diff options
124 files changed, 8572 insertions, 3210 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-samsung-laptop b/Documentation/ABI/testing/sysfs-driver-samsung-laptop new file mode 100644 index 000000000000..0a810231aad4 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-samsung-laptop | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | What: /sys/devices/platform/samsung/performance_level | ||
| 2 | Date: January 1, 2010 | ||
| 3 | KernelVersion: 2.6.33 | ||
| 4 | Contact: Greg Kroah-Hartman <gregkh@suse.de> | ||
| 5 | Description: Some Samsung laptops have different "performance levels" | ||
| 6 | that are can be modified by a function key, and by this | ||
| 7 | sysfs file. These values don't always make a whole lot | ||
| 8 | of sense, but some users like to modify them to keep | ||
| 9 | their fans quiet at all costs. Reading from this file | ||
| 10 | will show the current performance level. Writing to the | ||
| 11 | file can change this value. | ||
| 12 | Valid options: | ||
| 13 | "silent" | ||
| 14 | "normal" | ||
| 15 | "overclock" | ||
| 16 | Note that not all laptops support all of these options. | ||
| 17 | Specifically, not all support the "overclock" option, | ||
| 18 | and it's still unknown if this value even changes | ||
| 19 | anything, other than making the user feel a bit better. | ||
diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi new file mode 100644 index 000000000000..2e7df91620de --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | What: /sys/devices/platform/<platform>/cpufv | ||
| 2 | Date: Oct 2010 | ||
| 3 | KernelVersion: 2.6.37 | ||
| 4 | Contact: "Corentin Chary" <corentincj@iksaif.net> | ||
| 5 | Description: | ||
| 6 | Change CPU clock configuration (write-only). | ||
| 7 | There are three available clock configuration: | ||
| 8 | * 0 -> Super Performance Mode | ||
| 9 | * 1 -> High Performance Mode | ||
| 10 | * 2 -> Power Saving Mode | ||
| 11 | |||
| 12 | What: /sys/devices/platform/<platform>/camera | ||
| 13 | Date: Jan 2010 | ||
| 14 | KernelVersion: 2.6.39 | ||
| 15 | Contact: "Corentin Chary" <corentincj@iksaif.net> | ||
| 16 | Description: | ||
| 17 | Control the camera. 1 means on, 0 means off. | ||
| 18 | |||
| 19 | What: /sys/devices/platform/<platform>/cardr | ||
| 20 | Date: Jan 2010 | ||
| 21 | KernelVersion: 2.6.39 | ||
| 22 | Contact: "Corentin Chary" <corentincj@iksaif.net> | ||
| 23 | Description: | ||
| 24 | Control the card reader. 1 means on, 0 means off. | ||
| 25 | |||
| 26 | What: /sys/devices/platform/<platform>/touchpad | ||
| 27 | Date: Jan 2010 | ||
| 28 | KernelVersion: 2.6.39 | ||
| 29 | Contact: "Corentin Chary" <corentincj@iksaif.net> | ||
| 30 | Description: | ||
| 31 | Control the card touchpad. 1 means on, 0 means off. | ||
diff --git a/Documentation/ABI/testing/sysfs-platform-eeepc-wmi b/Documentation/ABI/testing/sysfs-platform-eeepc-wmi deleted file mode 100644 index e4b5fef5fadd..000000000000 --- a/Documentation/ABI/testing/sysfs-platform-eeepc-wmi +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | What: /sys/devices/platform/eeepc-wmi/cpufv | ||
| 2 | Date: Oct 2010 | ||
| 3 | KernelVersion: 2.6.37 | ||
| 4 | Contact: "Corentin Chary" <corentincj@iksaif.net> | ||
| 5 | Description: | ||
| 6 | Change CPU clock configuration (write-only). | ||
| 7 | There are three available clock configuration: | ||
| 8 | * 0 -> Super Performance Mode | ||
| 9 | * 1 -> High Performance Mode | ||
| 10 | * 2 -> Power Saving Mode | ||
diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt index 23ce7d350d1a..2bd4e82e5d9f 100644 --- a/Documentation/laptops/sony-laptop.txt +++ b/Documentation/laptops/sony-laptop.txt | |||
| @@ -14,7 +14,8 @@ Some models report hotkeys through the SNC or SPIC devices, such events are | |||
| 14 | reported both through the ACPI subsystem as acpi events and through the INPUT | 14 | reported both through the ACPI subsystem as acpi events and through the INPUT |
| 15 | subsystem. See the logs of acpid or /proc/acpi/event and | 15 | subsystem. See the logs of acpid or /proc/acpi/event and |
| 16 | /proc/bus/input/devices to find out what those events are and which input | 16 | /proc/bus/input/devices to find out what those events are and which input |
| 17 | devices are created by the driver. | 17 | devices are created by the driver. Additionally, loading the driver with the |
| 18 | debug option will report all events in the kernel log. | ||
| 18 | 19 | ||
| 19 | Backlight control: | 20 | Backlight control: |
| 20 | ------------------ | 21 | ------------------ |
| @@ -64,6 +65,16 @@ powers off the sound card, | |||
| 64 | # echo "1" > /sys/devices/platform/sony-laptop/audiopower | 65 | # echo "1" > /sys/devices/platform/sony-laptop/audiopower |
| 65 | powers on the sound card. | 66 | powers on the sound card. |
| 66 | 67 | ||
| 68 | |||
| 69 | RFkill control: | ||
| 70 | --------------- | ||
| 71 | More recent Vaio models expose a consistent set of ACPI methods to | ||
| 72 | control radio frequency emitting devices. If you are a lucky owner of | ||
| 73 | such a laptop you will find the necessary rfkill devices under | ||
| 74 | /sys/class/rfkill. Check those starting with sony-* in | ||
| 75 | # grep . /sys/class/rfkill/*/{state,name} | ||
| 76 | |||
| 77 | |||
| 67 | Development: | 78 | Development: |
| 68 | ------------ | 79 | ------------ |
| 69 | 80 | ||
| @@ -75,8 +86,21 @@ pass the option 'debug=1'. | |||
| 75 | REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS. | 86 | REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS. |
| 76 | 87 | ||
| 77 | In your kernel logs you will find the list of all ACPI methods | 88 | In your kernel logs you will find the list of all ACPI methods |
| 78 | the SNC device has on your laptop. You can see the GCDP/GCDP methods | 89 | the SNC device has on your laptop. |
| 79 | used to pwer on/off the CD drive, but there are others. | 90 | |
| 91 | * For new models you will see a long list of meaningless method names, | ||
| 92 | reading the DSDT table source should reveal that: | ||
| 93 | (1) the SNC device uses an internal capability lookup table | ||
| 94 | (2) SN00 is used to find values in the lookup table | ||
| 95 | (3) SN06 and SN07 are used to call into the real methods based on | ||
| 96 | offsets you can obtain iterating the table using SN00 | ||
| 97 | (4) SN02 used to enable events. | ||
| 98 | Some values in the capability lookup table are more or less known, see | ||
| 99 | the code for all sony_call_snc_handle calls, others are more obscure. | ||
| 100 | |||
| 101 | * For old models you can see the GCDP/GCDP methods used to pwer on/off | ||
| 102 | the CD drive, but there are others and they are usually different from | ||
| 103 | model to model. | ||
| 80 | 104 | ||
| 81 | I HAVE NO IDEA WHAT THOSE METHODS DO. | 105 | I HAVE NO IDEA WHAT THOSE METHODS DO. |
| 82 | 106 | ||
| @@ -108,9 +132,8 @@ Bugs/Limitations: | |||
| 108 | laptop, including permanent damage. | 132 | laptop, including permanent damage. |
| 109 | 133 | ||
| 110 | * The sony-laptop and sonypi drivers do not interact at all. In the | 134 | * The sony-laptop and sonypi drivers do not interact at all. In the |
| 111 | future, sonypi could use sony-laptop to do (part of) its business. | 135 | future, sonypi will be removed and replaced by sony-laptop. |
| 112 | 136 | ||
| 113 | * spicctrl, which is the userspace tool used to communicate with the | 137 | * spicctrl, which is the userspace tool used to communicate with the |
| 114 | sonypi driver (through /dev/sonypi) does not try to use the | 138 | sonypi driver (through /dev/sonypi) is deprecated as well since all |
| 115 | sony-laptop driver. In the future, spicctrl could try sonypi first, | 139 | its features are now available under the sysfs tree via sony-laptop. |
| 116 | and if it isn't present, try sony-laptop instead. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 8aa1cacddbcc..6b4b9cdec370 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -1157,14 +1157,14 @@ S: Maintained | |||
| 1157 | F: Documentation/hwmon/asc7621 | 1157 | F: Documentation/hwmon/asc7621 |
| 1158 | F: drivers/hwmon/asc7621.c | 1158 | F: drivers/hwmon/asc7621.c |
| 1159 | 1159 | ||
| 1160 | ASUS ACPI EXTRAS DRIVER | 1160 | ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS |
| 1161 | M: Corentin Chary <corentincj@iksaif.net> | 1161 | M: Corentin Chary <corentincj@iksaif.net> |
| 1162 | M: Karol Kozimor <sziwan@users.sourceforge.net> | ||
| 1163 | L: acpi4asus-user@lists.sourceforge.net | 1162 | L: acpi4asus-user@lists.sourceforge.net |
| 1164 | L: platform-driver-x86@vger.kernel.org | 1163 | L: platform-driver-x86@vger.kernel.org |
| 1165 | W: http://acpi4asus.sf.net | 1164 | W: http://acpi4asus.sf.net |
| 1166 | S: Maintained | 1165 | S: Maintained |
| 1167 | F: drivers/platform/x86/asus_acpi.c | 1166 | F: drivers/platform/x86/asus*.c |
| 1167 | F: drivers/platform/x86/eeepc*.c | ||
| 1168 | 1168 | ||
| 1169 | ASUS ASB100 HARDWARE MONITOR DRIVER | 1169 | ASUS ASB100 HARDWARE MONITOR DRIVER |
| 1170 | M: "Mark M. Hoffman" <mhoffman@lightlink.com> | 1170 | M: "Mark M. Hoffman" <mhoffman@lightlink.com> |
| @@ -1172,14 +1172,6 @@ L: lm-sensors@lm-sensors.org | |||
| 1172 | S: Maintained | 1172 | S: Maintained |
| 1173 | F: drivers/hwmon/asb100.c | 1173 | F: drivers/hwmon/asb100.c |
| 1174 | 1174 | ||
| 1175 | ASUS LAPTOP EXTRAS DRIVER | ||
| 1176 | M: Corentin Chary <corentincj@iksaif.net> | ||
| 1177 | L: acpi4asus-user@lists.sourceforge.net | ||
| 1178 | L: platform-driver-x86@vger.kernel.org | ||
| 1179 | W: http://acpi4asus.sf.net | ||
| 1180 | S: Maintained | ||
| 1181 | F: drivers/platform/x86/asus-laptop.c | ||
| 1182 | |||
| 1183 | ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API | 1175 | ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API |
| 1184 | M: Dan Williams <dan.j.williams@intel.com> | 1176 | M: Dan Williams <dan.j.williams@intel.com> |
| 1185 | W: http://sourceforge.net/projects/xscaleiop | 1177 | W: http://sourceforge.net/projects/xscaleiop |
| @@ -2414,22 +2406,6 @@ T: git git://git.alsa-project.org/alsa-kernel.git | |||
| 2414 | S: Maintained | 2406 | S: Maintained |
| 2415 | F: sound/usb/misc/ua101.c | 2407 | F: sound/usb/misc/ua101.c |
| 2416 | 2408 | ||
| 2417 | EEEPC LAPTOP EXTRAS DRIVER | ||
| 2418 | M: Corentin Chary <corentincj@iksaif.net> | ||
| 2419 | L: acpi4asus-user@lists.sourceforge.net | ||
| 2420 | L: platform-driver-x86@vger.kernel.org | ||
| 2421 | W: http://acpi4asus.sf.net | ||
| 2422 | S: Maintained | ||
| 2423 | F: drivers/platform/x86/eeepc-laptop.c | ||
| 2424 | |||
| 2425 | EEEPC WMI EXTRAS DRIVER | ||
| 2426 | M: Corentin Chary <corentincj@iksaif.net> | ||
| 2427 | L: acpi4asus-user@lists.sourceforge.net | ||
| 2428 | L: platform-driver-x86@vger.kernel.org | ||
| 2429 | W: http://acpi4asus.sf.net | ||
| 2430 | S: Maintained | ||
| 2431 | F: drivers/platform/x86/eeepc-wmi.c | ||
| 2432 | |||
| 2433 | EFIFB FRAMEBUFFER DRIVER | 2409 | EFIFB FRAMEBUFFER DRIVER |
| 2434 | L: linux-fbdev@vger.kernel.org | 2410 | L: linux-fbdev@vger.kernel.org |
| 2435 | M: Peter Jones <pjones@redhat.com> | 2411 | M: Peter Jones <pjones@redhat.com> |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 93d595a7477a..efe06e004714 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -2009,6 +2009,7 @@ menu "Power management options" | |||
| 2009 | source "kernel/power/Kconfig" | 2009 | source "kernel/power/Kconfig" |
| 2010 | 2010 | ||
| 2011 | config ARCH_SUSPEND_POSSIBLE | 2011 | config ARCH_SUSPEND_POSSIBLE |
| 2012 | depends on !ARCH_S5P64X0 && !ARCH_S5P6442 | ||
| 2012 | def_bool y | 2013 | def_bool y |
| 2013 | 2014 | ||
| 2014 | endmenu | 2015 | endmenu |
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index a021b5240bba..e849f67be47d 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig | |||
| @@ -20,6 +20,11 @@ config EXYNOS4_MCT | |||
| 20 | help | 20 | help |
| 21 | Use MCT (Multi Core Timer) as kernel timers | 21 | Use MCT (Multi Core Timer) as kernel timers |
| 22 | 22 | ||
| 23 | config EXYNOS4_DEV_AHCI | ||
| 24 | bool | ||
| 25 | help | ||
| 26 | Compile in platform device definitions for AHCI | ||
| 27 | |||
| 23 | config EXYNOS4_DEV_PD | 28 | config EXYNOS4_DEV_PD |
| 24 | bool | 29 | bool |
| 25 | help | 30 | help |
| @@ -134,9 +139,9 @@ config MACH_ARMLEX4210 | |||
| 134 | select S3C_DEV_HSMMC | 139 | select S3C_DEV_HSMMC |
| 135 | select S3C_DEV_HSMMC2 | 140 | select S3C_DEV_HSMMC2 |
| 136 | select S3C_DEV_HSMMC3 | 141 | select S3C_DEV_HSMMC3 |
| 142 | select EXYNOS4_DEV_AHCI | ||
| 137 | select EXYNOS4_DEV_SYSMMU | 143 | select EXYNOS4_DEV_SYSMMU |
| 138 | select EXYNOS4_SETUP_SDHCI | 144 | select EXYNOS4_SETUP_SDHCI |
| 139 | select SATA_AHCI_PLATFORM | ||
| 140 | help | 145 | help |
| 141 | Machine support for Samsung ARMLEX4210 based on EXYNOS4210 | 146 | Machine support for Samsung ARMLEX4210 based on EXYNOS4210 |
| 142 | 147 | ||
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile index b8f0e7d82d7e..9be104f63c0b 100644 --- a/arch/arm/mach-exynos4/Makefile +++ b/arch/arm/mach-exynos4/Makefile | |||
| @@ -39,6 +39,7 @@ obj-$(CONFIG_MACH_NURI) += mach-nuri.o | |||
| 39 | # device support | 39 | # device support |
| 40 | 40 | ||
| 41 | obj-y += dev-audio.o | 41 | obj-y += dev-audio.o |
| 42 | obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o | ||
| 42 | obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o | 43 | obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o |
| 43 | obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o | 44 | obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o |
| 44 | 45 | ||
| @@ -53,4 +54,3 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o | |||
| 53 | obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o | 54 | obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o |
| 54 | obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o | 55 | obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o |
| 55 | obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o | 56 | obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o |
| 56 | obj-$(CONFIG_SATA_AHCI_PLATFORM) += dev-ahci.o | ||
diff --git a/arch/arm/mach-exynos4/include/mach/debug-macro.S b/arch/arm/mach-exynos4/include/mach/debug-macro.S index 58bbd049a6c4..a442ef861167 100644 --- a/arch/arm/mach-exynos4/include/mach/debug-macro.S +++ b/arch/arm/mach-exynos4/include/mach/debug-macro.S | |||
| @@ -21,8 +21,8 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | .macro addruart, rp, rv | 23 | .macro addruart, rp, rv |
| 24 | ldreq \rp, = S3C_PA_UART | 24 | ldr \rp, = S3C_PA_UART |
| 25 | ldrne \rv, = S3C_VA_UART | 25 | ldr \rv, = S3C_VA_UART |
| 26 | #if CONFIG_DEBUG_S3C_UART != 0 | 26 | #if CONFIG_DEBUG_S3C_UART != 0 |
| 27 | add \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART) | 27 | add \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART) |
| 28 | add \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART) | 28 | add \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART) |
diff --git a/arch/arm/mach-exynos4/mach-smdkc210.c b/arch/arm/mach-exynos4/mach-smdkc210.c index 25a256818122..e645f7a955f0 100644 --- a/arch/arm/mach-exynos4/mach-smdkc210.c +++ b/arch/arm/mach-exynos4/mach-smdkc210.c | |||
| @@ -125,7 +125,7 @@ static struct resource smdkc210_smsc911x_resources[] = { | |||
| 125 | }; | 125 | }; |
| 126 | 126 | ||
| 127 | static struct smsc911x_platform_config smsc9215_config = { | 127 | static struct smsc911x_platform_config smsc9215_config = { |
| 128 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, | 128 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, |
| 129 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, | 129 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, |
| 130 | .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, | 130 | .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, |
| 131 | .phy_interface = PHY_INTERFACE_MODE_MII, | 131 | .phy_interface = PHY_INTERFACE_MODE_MII, |
diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c index 88e0275143be..152676471b67 100644 --- a/arch/arm/mach-exynos4/mach-smdkv310.c +++ b/arch/arm/mach-exynos4/mach-smdkv310.c | |||
| @@ -127,7 +127,7 @@ static struct resource smdkv310_smsc911x_resources[] = { | |||
| 127 | }; | 127 | }; |
| 128 | 128 | ||
| 129 | static struct smsc911x_platform_config smsc9215_config = { | 129 | static struct smsc911x_platform_config smsc9215_config = { |
| 130 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, | 130 | .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, |
| 131 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, | 131 | .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, |
| 132 | .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, | 132 | .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY, |
| 133 | .phy_interface = PHY_INTERFACE_MODE_MII, | 133 | .phy_interface = PHY_INTERFACE_MODE_MII, |
diff --git a/arch/arm/mach-mx5/mx51_efika.c b/arch/arm/mach-mx5/mx51_efika.c index 51a67fc7f0ef..868af8f435fa 100644 --- a/arch/arm/mach-mx5/mx51_efika.c +++ b/arch/arm/mach-mx5/mx51_efika.c | |||
| @@ -572,8 +572,10 @@ static struct mc13xxx_regulator_init_data mx51_efika_regulators[] = { | |||
| 572 | 572 | ||
| 573 | static struct mc13xxx_platform_data mx51_efika_mc13892_data = { | 573 | static struct mc13xxx_platform_data mx51_efika_mc13892_data = { |
| 574 | .flags = MC13XXX_USE_RTC | MC13XXX_USE_REGULATOR, | 574 | .flags = MC13XXX_USE_RTC | MC13XXX_USE_REGULATOR, |
| 575 | .num_regulators = ARRAY_SIZE(mx51_efika_regulators), | 575 | .regulators = { |
| 576 | .regulators = mx51_efika_regulators, | 576 | .num_regulators = ARRAY_SIZE(mx51_efika_regulators), |
| 577 | .regulators = mx51_efika_regulators, | ||
| 578 | }, | ||
| 577 | }; | 579 | }; |
| 578 | 580 | ||
| 579 | static struct spi_board_info mx51_efika_spi_board_info[] __initdata = { | 581 | static struct spi_board_info mx51_efika_spi_board_info[] __initdata = { |
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c index 389fa5c669de..bf0fd48cbd80 100644 --- a/arch/arm/mach-ns9xxx/irq.c +++ b/arch/arm/mach-ns9xxx/irq.c | |||
| @@ -31,17 +31,11 @@ static void ns9xxx_mask_irq(struct irq_data *d) | |||
| 31 | __raw_writel(ic, SYS_IC(prio / 4)); | 31 | __raw_writel(ic, SYS_IC(prio / 4)); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | static void ns9xxx_ack_irq(struct irq_data *d) | 34 | static void ns9xxx_eoi_irq(struct irq_data *d) |
| 35 | { | 35 | { |
| 36 | __raw_writel(0, SYS_ISRADDR); | 36 | __raw_writel(0, SYS_ISRADDR); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | static void ns9xxx_maskack_irq(struct irq_data *d) | ||
| 40 | { | ||
| 41 | ns9xxx_mask_irq(d); | ||
| 42 | ns9xxx_ack_irq(d); | ||
| 43 | } | ||
| 44 | |||
| 45 | static void ns9xxx_unmask_irq(struct irq_data *d) | 39 | static void ns9xxx_unmask_irq(struct irq_data *d) |
| 46 | { | 40 | { |
| 47 | /* XXX: better use cpp symbols */ | 41 | /* XXX: better use cpp symbols */ |
| @@ -52,56 +46,11 @@ static void ns9xxx_unmask_irq(struct irq_data *d) | |||
| 52 | } | 46 | } |
| 53 | 47 | ||
| 54 | static struct irq_chip ns9xxx_chip = { | 48 | static struct irq_chip ns9xxx_chip = { |
| 55 | .irq_ack = ns9xxx_ack_irq, | 49 | .irq_eoi = ns9xxx_eoi_irq, |
| 56 | .irq_mask = ns9xxx_mask_irq, | 50 | .irq_mask = ns9xxx_mask_irq, |
| 57 | .irq_mask_ack = ns9xxx_maskack_irq, | ||
| 58 | .irq_unmask = ns9xxx_unmask_irq, | 51 | .irq_unmask = ns9xxx_unmask_irq, |
| 59 | }; | 52 | }; |
| 60 | 53 | ||
| 61 | #if 0 | ||
| 62 | #define handle_irq handle_level_irq | ||
| 63 | #else | ||
| 64 | static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) | ||
| 65 | { | ||
| 66 | struct irqaction *action; | ||
| 67 | irqreturn_t action_ret; | ||
| 68 | |||
| 69 | raw_spin_lock(&desc->lock); | ||
| 70 | |||
| 71 | BUG_ON(desc->status & IRQ_INPROGRESS); | ||
| 72 | |||
| 73 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | ||
| 74 | kstat_incr_irqs_this_cpu(irq, desc); | ||
| 75 | |||
| 76 | action = desc->action; | ||
| 77 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) | ||
| 78 | goto out_mask; | ||
| 79 | |||
| 80 | desc->status |= IRQ_INPROGRESS; | ||
| 81 | raw_spin_unlock(&desc->lock); | ||
| 82 | |||
| 83 | action_ret = handle_IRQ_event(irq, action); | ||
| 84 | |||
| 85 | /* XXX: There is no direct way to access noirqdebug, so check | ||
| 86 | * unconditionally for spurious irqs... | ||
| 87 | * Maybe this function should go to kernel/irq/chip.c? */ | ||
| 88 | note_interrupt(irq, desc, action_ret); | ||
| 89 | |||
| 90 | raw_spin_lock(&desc->lock); | ||
| 91 | desc->status &= ~IRQ_INPROGRESS; | ||
| 92 | |||
| 93 | if (desc->status & IRQ_DISABLED) | ||
| 94 | out_mask: | ||
| 95 | desc->irq_data.chip->irq_mask(&desc->irq_data); | ||
| 96 | |||
| 97 | /* ack unconditionally to unmask lower prio irqs */ | ||
| 98 | desc->irq_data.chip->irq_ack(&desc->irq_data); | ||
| 99 | |||
| 100 | raw_spin_unlock(&desc->lock); | ||
| 101 | } | ||
| 102 | #define handle_irq handle_prio_irq | ||
| 103 | #endif | ||
| 104 | |||
| 105 | void __init ns9xxx_init_irq(void) | 54 | void __init ns9xxx_init_irq(void) |
| 106 | { | 55 | { |
| 107 | int i; | 56 | int i; |
| @@ -119,7 +68,8 @@ void __init ns9xxx_init_irq(void) | |||
| 119 | 68 | ||
| 120 | for (i = 0; i <= 31; ++i) { | 69 | for (i = 0; i <= 31; ++i) { |
| 121 | set_irq_chip(i, &ns9xxx_chip); | 70 | set_irq_chip(i, &ns9xxx_chip); |
| 122 | set_irq_handler(i, handle_irq); | 71 | set_irq_handler(i, handle_fasteoi_irq); |
| 123 | set_irq_flags(i, IRQF_VALID); | 72 | set_irq_flags(i, IRQF_VALID); |
| 73 | irq_set_status_flags(i, IRQ_LEVEL); | ||
| 124 | } | 74 | } |
| 125 | } | 75 | } |
diff --git a/arch/arm/mach-s5p64x0/cpu.c b/arch/arm/mach-s5p64x0/cpu.c index b8d02eb4cf30..a5c00952ea35 100644 --- a/arch/arm/mach-s5p64x0/cpu.c +++ b/arch/arm/mach-s5p64x0/cpu.c | |||
| @@ -119,7 +119,7 @@ void __init s5p6450_map_io(void) | |||
| 119 | s3c_adc_setname("s3c64xx-adc"); | 119 | s3c_adc_setname("s3c64xx-adc"); |
| 120 | 120 | ||
| 121 | iotable_init(s5p64x0_iodesc, ARRAY_SIZE(s5p64x0_iodesc)); | 121 | iotable_init(s5p64x0_iodesc, ARRAY_SIZE(s5p64x0_iodesc)); |
| 122 | iotable_init(s5p6450_iodesc, ARRAY_SIZE(s5p6440_iodesc)); | 122 | iotable_init(s5p6450_iodesc, ARRAY_SIZE(s5p6450_iodesc)); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | /* | 125 | /* |
diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h index 26710b35ef87..b9f9ec33384d 100644 --- a/arch/arm/mach-s5pv210/include/mach/irqs.h +++ b/arch/arm/mach-s5pv210/include/mach/irqs.h | |||
| @@ -99,9 +99,9 @@ | |||
| 99 | #define IRQ_TC IRQ_PENDN | 99 | #define IRQ_TC IRQ_PENDN |
| 100 | #define IRQ_KEYPAD S5P_IRQ_VIC2(25) | 100 | #define IRQ_KEYPAD S5P_IRQ_VIC2(25) |
| 101 | #define IRQ_CG S5P_IRQ_VIC2(26) | 101 | #define IRQ_CG S5P_IRQ_VIC2(26) |
| 102 | #define IRQ_SEC S5P_IRQ_VIC2(27) | 102 | #define IRQ_SSS_INT S5P_IRQ_VIC2(27) |
| 103 | #define IRQ_SECRX S5P_IRQ_VIC2(28) | 103 | #define IRQ_SSS_HASH S5P_IRQ_VIC2(28) |
| 104 | #define IRQ_SECTX S5P_IRQ_VIC2(29) | 104 | #define IRQ_PCM2 S5P_IRQ_VIC2(29) |
| 105 | #define IRQ_SDMIRQ S5P_IRQ_VIC2(30) | 105 | #define IRQ_SDMIRQ S5P_IRQ_VIC2(30) |
| 106 | #define IRQ_SDMFIQ S5P_IRQ_VIC2(31) | 106 | #define IRQ_SDMFIQ S5P_IRQ_VIC2(31) |
| 107 | 107 | ||
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c index bc08ac42e7cc..c6a9e86c2d5c 100644 --- a/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/arch/arm/mach-s5pv210/mach-smdkv210.c | |||
| @@ -44,7 +44,6 @@ | |||
| 44 | #include <plat/keypad.h> | 44 | #include <plat/keypad.h> |
| 45 | #include <plat/pm.h> | 45 | #include <plat/pm.h> |
| 46 | #include <plat/fb.h> | 46 | #include <plat/fb.h> |
| 47 | #include <plat/gpio-cfg.h> | ||
| 48 | #include <plat/s5p-time.h> | 47 | #include <plat/s5p-time.h> |
| 49 | 48 | ||
| 50 | /* Following are default values for UCON, ULCON and UFCON UART registers */ | 49 | /* Following are default values for UCON, ULCON and UFCON UART registers */ |
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 203b986280f5..58626013aa32 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig | |||
| @@ -23,6 +23,7 @@ menu "Ux500 target platform" | |||
| 23 | config MACH_U8500 | 23 | config MACH_U8500 |
| 24 | bool "U8500 Development platform" | 24 | bool "U8500 Development platform" |
| 25 | depends on UX500_SOC_DB8500 | 25 | depends on UX500_SOC_DB8500 |
| 26 | select TPS6105X | ||
| 26 | help | 27 | help |
| 27 | Include support for the mop500 development platform. | 28 | Include support for the mop500 development platform. |
| 28 | 29 | ||
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 875c91b2f8a4..9ed0f90cfe23 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c | |||
| @@ -13,6 +13,30 @@ | |||
| 13 | #include <linux/regulator/ab8500.h> | 13 | #include <linux/regulator/ab8500.h> |
| 14 | #include "board-mop500-regulators.h" | 14 | #include "board-mop500-regulators.h" |
| 15 | 15 | ||
| 16 | /* | ||
| 17 | * TPS61052 regulator | ||
| 18 | */ | ||
| 19 | static struct regulator_consumer_supply tps61052_vaudio_consumers[] = { | ||
| 20 | /* | ||
| 21 | * Boost converter supply to raise voltage on audio speaker, this | ||
| 22 | * is actually connected to three pins, VInVhfL (left amplifier) | ||
| 23 | * VInVhfR (right amplifier) and VIntDClassInt - all three must | ||
| 24 | * be connected to the same voltage. | ||
| 25 | */ | ||
| 26 | REGULATOR_SUPPLY("vintdclassint", "ab8500-codec.0"), | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct regulator_init_data tps61052_regulator = { | ||
| 30 | .constraints = { | ||
| 31 | .name = "vaudio-hf", | ||
| 32 | .min_uV = 4500000, | ||
| 33 | .max_uV = 4500000, | ||
| 34 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
| 35 | }, | ||
| 36 | .num_consumer_supplies = ARRAY_SIZE(tps61052_vaudio_consumers), | ||
| 37 | .consumer_supplies = tps61052_vaudio_consumers, | ||
| 38 | }; | ||
| 39 | |||
| 16 | static struct regulator_consumer_supply ab8500_vaux1_consumers[] = { | 40 | static struct regulator_consumer_supply ab8500_vaux1_consumers[] = { |
| 17 | /* External displays, connector on board 2v5 power supply */ | 41 | /* External displays, connector on board 2v5 power supply */ |
| 18 | REGULATOR_SUPPLY("vaux12v5", "mcde.0"), | 42 | REGULATOR_SUPPLY("vaux12v5", "mcde.0"), |
| @@ -62,6 +86,182 @@ static struct regulator_consumer_supply ab8500_vana_consumers[] = { | |||
| 62 | REGULATOR_SUPPLY("vsmps2", "mcde.0"), | 86 | REGULATOR_SUPPLY("vsmps2", "mcde.0"), |
| 63 | }; | 87 | }; |
| 64 | 88 | ||
| 89 | /* ab8500 regulator register initialization */ | ||
| 90 | struct ab8500_regulator_reg_init | ||
| 91 | ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { | ||
| 92 | /* | ||
| 93 | * VanaRequestCtrl = HP/LP depending on VxRequest | ||
| 94 | * VextSupply1RequestCtrl = HP/LP depending on VxRequest | ||
| 95 | */ | ||
| 96 | INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0x00), | ||
| 97 | /* | ||
| 98 | * VextSupply2RequestCtrl = HP/LP depending on VxRequest | ||
| 99 | * VextSupply3RequestCtrl = HP/LP depending on VxRequest | ||
| 100 | * Vaux1RequestCtrl = HP/LP depending on VxRequest | ||
| 101 | * Vaux2RequestCtrl = HP/LP depending on VxRequest | ||
| 102 | */ | ||
| 103 | INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0x00), | ||
| 104 | /* | ||
| 105 | * Vaux3RequestCtrl = HP/LP depending on VxRequest | ||
| 106 | * SwHPReq = Control through SWValid disabled | ||
| 107 | */ | ||
| 108 | INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x00), | ||
| 109 | /* | ||
| 110 | * VanaSysClkReq1HPValid = disabled | ||
| 111 | * Vaux1SysClkReq1HPValid = disabled | ||
| 112 | * Vaux2SysClkReq1HPValid = disabled | ||
| 113 | * Vaux3SysClkReq1HPValid = disabled | ||
| 114 | */ | ||
| 115 | INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0x00), | ||
| 116 | /* | ||
| 117 | * VextSupply1SysClkReq1HPValid = disabled | ||
| 118 | * VextSupply2SysClkReq1HPValid = disabled | ||
| 119 | * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled | ||
| 120 | */ | ||
| 121 | INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x40), | ||
| 122 | /* | ||
| 123 | * VanaHwHPReq1Valid = disabled | ||
| 124 | * Vaux1HwHPreq1Valid = disabled | ||
| 125 | * Vaux2HwHPReq1Valid = disabled | ||
| 126 | * Vaux3HwHPReqValid = disabled | ||
| 127 | */ | ||
| 128 | INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0x00), | ||
| 129 | /* | ||
| 130 | * VextSupply1HwHPReq1Valid = disabled | ||
| 131 | * VextSupply2HwHPReq1Valid = disabled | ||
| 132 | * VextSupply3HwHPReq1Valid = disabled | ||
| 133 | */ | ||
| 134 | INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x00), | ||
| 135 | /* | ||
| 136 | * VanaHwHPReq2Valid = disabled | ||
| 137 | * Vaux1HwHPReq2Valid = disabled | ||
| 138 | * Vaux2HwHPReq2Valid = disabled | ||
| 139 | * Vaux3HwHPReq2Valid = disabled | ||
| 140 | */ | ||
| 141 | INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0x00), | ||
| 142 | /* | ||
| 143 | * VextSupply1HwHPReq2Valid = disabled | ||
| 144 | * VextSupply2HwHPReq2Valid = disabled | ||
| 145 | * VextSupply3HwHPReq2Valid = HWReq2 controlled | ||
| 146 | */ | ||
| 147 | INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x04), | ||
| 148 | /* | ||
| 149 | * VanaSwHPReqValid = disabled | ||
| 150 | * Vaux1SwHPReqValid = disabled | ||
| 151 | */ | ||
| 152 | INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0x00), | ||
| 153 | /* | ||
| 154 | * Vaux2SwHPReqValid = disabled | ||
| 155 | * Vaux3SwHPReqValid = disabled | ||
| 156 | * VextSupply1SwHPReqValid = disabled | ||
| 157 | * VextSupply2SwHPReqValid = disabled | ||
| 158 | * VextSupply3SwHPReqValid = disabled | ||
| 159 | */ | ||
| 160 | INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x00), | ||
| 161 | /* | ||
| 162 | * SysClkReq2Valid1 = SysClkReq2 controlled | ||
| 163 | * SysClkReq3Valid1 = disabled | ||
| 164 | * SysClkReq4Valid1 = SysClkReq4 controlled | ||
| 165 | * SysClkReq5Valid1 = disabled | ||
| 166 | * SysClkReq6Valid1 = SysClkReq6 controlled | ||
| 167 | * SysClkReq7Valid1 = disabled | ||
| 168 | * SysClkReq8Valid1 = disabled | ||
| 169 | */ | ||
| 170 | INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0x2a), | ||
| 171 | /* | ||
| 172 | * SysClkReq2Valid2 = disabled | ||
| 173 | * SysClkReq3Valid2 = disabled | ||
| 174 | * SysClkReq4Valid2 = disabled | ||
| 175 | * SysClkReq5Valid2 = disabled | ||
| 176 | * SysClkReq6Valid2 = SysClkReq6 controlled | ||
| 177 | * SysClkReq7Valid2 = disabled | ||
| 178 | * SysClkReq8Valid2 = disabled | ||
| 179 | */ | ||
| 180 | INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0x20), | ||
| 181 | /* | ||
| 182 | * VTVoutEna = disabled | ||
| 183 | * Vintcore12Ena = disabled | ||
| 184 | * Vintcore12Sel = 1.25 V | ||
| 185 | * Vintcore12LP = inactive (HP) | ||
| 186 | * VTVoutLP = inactive (HP) | ||
| 187 | */ | ||
| 188 | INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0x10), | ||
| 189 | /* | ||
| 190 | * VaudioEna = disabled | ||
| 191 | * VdmicEna = disabled | ||
| 192 | * Vamic1Ena = disabled | ||
| 193 | * Vamic2Ena = disabled | ||
| 194 | */ | ||
| 195 | INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x00), | ||
| 196 | /* | ||
| 197 | * Vamic1_dzout = high-Z when Vamic1 is disabled | ||
| 198 | * Vamic2_dzout = high-Z when Vamic2 is disabled | ||
| 199 | */ | ||
| 200 | INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x00), | ||
| 201 | /* | ||
| 202 | * VPll = Hw controlled | ||
| 203 | * VanaRegu = force off | ||
| 204 | */ | ||
| 205 | INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x02), | ||
| 206 | /* | ||
| 207 | * VrefDDREna = disabled | ||
| 208 | * VrefDDRSleepMode = inactive (no pulldown) | ||
| 209 | */ | ||
| 210 | INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x00), | ||
| 211 | /* | ||
| 212 | * VextSupply1Regu = HW control | ||
| 213 | * VextSupply2Regu = HW control | ||
| 214 | * VextSupply3Regu = HW control | ||
| 215 | * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0 | ||
| 216 | * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0 | ||
| 217 | */ | ||
| 218 | INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0x2a), | ||
| 219 | /* | ||
| 220 | * Vaux1Regu = force HP | ||
| 221 | * Vaux2Regu = force off | ||
| 222 | */ | ||
| 223 | INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x01), | ||
| 224 | /* | ||
| 225 | * Vaux3regu = force off | ||
| 226 | */ | ||
| 227 | INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x00), | ||
| 228 | /* | ||
| 229 | * Vsmps1 = 1.15V | ||
| 230 | */ | ||
| 231 | INIT_REGULATOR_REGISTER(AB8500_VSMPS1SEL1, 0x24), | ||
| 232 | /* | ||
| 233 | * Vaux1Sel = 2.5 V | ||
| 234 | */ | ||
| 235 | INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x08), | ||
| 236 | /* | ||
| 237 | * Vaux2Sel = 2.9 V | ||
| 238 | */ | ||
| 239 | INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0d), | ||
| 240 | /* | ||
| 241 | * Vaux3Sel = 2.91 V | ||
| 242 | */ | ||
| 243 | INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07), | ||
| 244 | /* | ||
| 245 | * VextSupply12LP = disabled (no LP) | ||
| 246 | */ | ||
| 247 | INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x00), | ||
| 248 | /* | ||
| 249 | * Vaux1Disch = short discharge time | ||
| 250 | * Vaux2Disch = short discharge time | ||
| 251 | * Vaux3Disch = short discharge time | ||
| 252 | * Vintcore12Disch = short discharge time | ||
| 253 | * VTVoutDisch = short discharge time | ||
| 254 | * VaudioDisch = short discharge time | ||
| 255 | */ | ||
| 256 | INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0x00), | ||
| 257 | /* | ||
| 258 | * VanaDisch = short discharge time | ||
| 259 | * VdmicPullDownEna = pulldown disabled when Vdmic is disabled | ||
| 260 | * VdmicDisch = short discharge time | ||
| 261 | */ | ||
| 262 | INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x00), | ||
| 263 | }; | ||
| 264 | |||
| 65 | /* AB8500 regulators */ | 265 | /* AB8500 regulators */ |
| 66 | struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { | 266 | struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { |
| 67 | /* supplies to the display/camera */ | 267 | /* supplies to the display/camera */ |
| @@ -72,6 +272,7 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { | |||
| 72 | .max_uV = 2900000, | 272 | .max_uV = 2900000, |
| 73 | .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | | 273 | .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | |
| 74 | REGULATOR_CHANGE_STATUS, | 274 | REGULATOR_CHANGE_STATUS, |
| 275 | .boot_on = 1, /* must be on for display */ | ||
| 75 | }, | 276 | }, |
| 76 | .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers), | 277 | .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers), |
| 77 | .consumer_supplies = ab8500_vaux1_consumers, | 278 | .consumer_supplies = ab8500_vaux1_consumers, |
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h index f979b892e4fa..94992158d962 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.h +++ b/arch/arm/mach-ux500/board-mop500-regulators.h | |||
| @@ -17,5 +17,6 @@ | |||
| 17 | extern struct ab8500_regulator_reg_init | 17 | extern struct ab8500_regulator_reg_init |
| 18 | ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS]; | 18 | ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS]; |
| 19 | extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; | 19 | extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; |
| 20 | extern struct regulator_init_data tps61052_regulator; | ||
| 20 | 21 | ||
| 21 | #endif | 22 | #endif |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index d0076453d7ff..dc8746d7826e 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include <linux/mfd/ab8500.h> | 22 | #include <linux/mfd/ab8500.h> |
| 23 | #include <linux/regulator/ab8500.h> | 23 | #include <linux/regulator/ab8500.h> |
| 24 | #include <linux/mfd/tc3589x.h> | 24 | #include <linux/mfd/tc3589x.h> |
| 25 | #include <linux/mfd/tps6105x.h> | ||
| 26 | #include <linux/mfd/ab8500/gpio.h> | ||
| 25 | #include <linux/leds-lp5521.h> | 27 | #include <linux/leds-lp5521.h> |
| 26 | #include <linux/input.h> | 28 | #include <linux/input.h> |
| 27 | #include <linux/gpio_keys.h> | 29 | #include <linux/gpio_keys.h> |
| @@ -42,10 +44,35 @@ | |||
| 42 | #include "board-mop500.h" | 44 | #include "board-mop500.h" |
| 43 | #include "board-mop500-regulators.h" | 45 | #include "board-mop500-regulators.h" |
| 44 | 46 | ||
| 47 | static struct ab8500_gpio_platform_data ab8500_gpio_pdata = { | ||
| 48 | .gpio_base = MOP500_AB8500_GPIO(0), | ||
| 49 | .irq_base = MOP500_AB8500_VIR_GPIO_IRQ_BASE, | ||
| 50 | /* config_reg is the initial configuration of ab8500 pins. | ||
| 51 | * The pins can be configured as GPIO or alt functions based | ||
| 52 | * on value present in GpioSel1 to GpioSel6 and AlternatFunction | ||
| 53 | * register. This is the array of 7 configuration settings. | ||
| 54 | * One has to compile time decide these settings. Below is the | ||
| 55 | * explaination of these setting | ||
| 56 | * GpioSel1 = 0x00 => Pins GPIO1 to GPIO8 are not used as GPIO | ||
| 57 | * GpioSel2 = 0x1E => Pins GPIO10 to GPIO13 are configured as GPIO | ||
| 58 | * GpioSel3 = 0x80 => Pin GPIO24 is configured as GPIO | ||
| 59 | * GpioSel4 = 0x01 => Pin GPIo25 is configured as GPIO | ||
| 60 | * GpioSel5 = 0x7A => Pins GPIO34, GPIO36 to GPIO39 are conf as GPIO | ||
| 61 | * GpioSel6 = 0x00 => Pins GPIO41 & GPIo42 are not configured as GPIO | ||
| 62 | * AlternaFunction = 0x00 => If Pins GPIO10 to 13 are not configured | ||
| 63 | * as GPIO then this register selectes the alternate fucntions | ||
| 64 | */ | ||
| 65 | .config_reg = {0x00, 0x1E, 0x80, 0x01, | ||
| 66 | 0x7A, 0x00, 0x00}, | ||
| 67 | }; | ||
| 68 | |||
| 45 | static struct ab8500_platform_data ab8500_platdata = { | 69 | static struct ab8500_platform_data ab8500_platdata = { |
| 46 | .irq_base = MOP500_AB8500_IRQ_BASE, | 70 | .irq_base = MOP500_AB8500_IRQ_BASE, |
| 71 | .regulator_reg_init = ab8500_regulator_reg_init, | ||
| 72 | .num_regulator_reg_init = ARRAY_SIZE(ab8500_regulator_reg_init), | ||
| 47 | .regulator = ab8500_regulators, | 73 | .regulator = ab8500_regulators, |
| 48 | .num_regulator = ARRAY_SIZE(ab8500_regulators), | 74 | .num_regulator = ARRAY_SIZE(ab8500_regulators), |
| 75 | .gpio = &ab8500_gpio_pdata, | ||
| 49 | }; | 76 | }; |
| 50 | 77 | ||
| 51 | static struct resource ab8500_resources[] = { | 78 | static struct resource ab8500_resources[] = { |
| @@ -67,6 +94,15 @@ struct platform_device ab8500_device = { | |||
| 67 | }; | 94 | }; |
| 68 | 95 | ||
| 69 | /* | 96 | /* |
| 97 | * TPS61052 | ||
| 98 | */ | ||
| 99 | |||
| 100 | static struct tps6105x_platform_data mop500_tps61052_data = { | ||
| 101 | .mode = TPS6105X_MODE_VOLTAGE, | ||
| 102 | .regulator_data = &tps61052_regulator, | ||
| 103 | }; | ||
| 104 | |||
| 105 | /* | ||
| 70 | * TC35892 | 106 | * TC35892 |
| 71 | */ | 107 | */ |
| 72 | 108 | ||
| @@ -136,7 +172,7 @@ static struct lp5521_platform_data __initdata lp5521_sec_data = { | |||
| 136 | .clock_mode = LP5521_CLOCK_EXT, | 172 | .clock_mode = LP5521_CLOCK_EXT, |
| 137 | }; | 173 | }; |
| 138 | 174 | ||
| 139 | static struct i2c_board_info mop500_i2c0_devices[] = { | 175 | static struct i2c_board_info __initdata mop500_i2c0_devices[] = { |
| 140 | { | 176 | { |
| 141 | I2C_BOARD_INFO("tc3589x", 0x42), | 177 | I2C_BOARD_INFO("tc3589x", 0x42), |
| 142 | .irq = NOMADIK_GPIO_TO_IRQ(217), | 178 | .irq = NOMADIK_GPIO_TO_IRQ(217), |
| @@ -144,6 +180,14 @@ static struct i2c_board_info mop500_i2c0_devices[] = { | |||
| 144 | }, | 180 | }, |
| 145 | }; | 181 | }; |
| 146 | 182 | ||
| 183 | /* I2C0 devices only available prior to HREFv60 */ | ||
| 184 | static struct i2c_board_info __initdata mop500_i2c0_old_devices[] = { | ||
| 185 | { | ||
| 186 | I2C_BOARD_INFO("tps61052", 0x33), | ||
| 187 | .platform_data = &mop500_tps61052_data, | ||
| 188 | }, | ||
| 189 | }; | ||
| 190 | |||
| 147 | static struct i2c_board_info __initdata mop500_i2c2_devices[] = { | 191 | static struct i2c_board_info __initdata mop500_i2c2_devices[] = { |
| 148 | { | 192 | { |
| 149 | /* lp5521 LED driver, 1st device */ | 193 | /* lp5521 LED driver, 1st device */ |
| @@ -406,6 +450,9 @@ static void __init mop500_init_machine(void) | |||
| 406 | 450 | ||
| 407 | i2c_register_board_info(0, mop500_i2c0_devices, | 451 | i2c_register_board_info(0, mop500_i2c0_devices, |
| 408 | ARRAY_SIZE(mop500_i2c0_devices)); | 452 | ARRAY_SIZE(mop500_i2c0_devices)); |
| 453 | if (!machine_is_hrefv60()) | ||
| 454 | i2c_register_board_info(0, mop500_i2c0_old_devices, | ||
| 455 | ARRAY_SIZE(mop500_i2c0_old_devices)); | ||
| 409 | i2c_register_board_info(2, mop500_i2c2_devices, | 456 | i2c_register_board_info(2, mop500_i2c2_devices, |
| 410 | ARRAY_SIZE(mop500_i2c2_devices)); | 457 | ARRAY_SIZE(mop500_i2c2_devices)); |
| 411 | } | 458 | } |
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index 56722f4be71b..03a31cc9b084 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h | |||
| @@ -27,6 +27,10 @@ | |||
| 27 | #define GPIO_BU21013_CS MOP500_EGPIO(13) | 27 | #define GPIO_BU21013_CS MOP500_EGPIO(13) |
| 28 | #define GPIO_SDMMC_EN MOP500_EGPIO(17) | 28 | #define GPIO_SDMMC_EN MOP500_EGPIO(17) |
| 29 | #define GPIO_SDMMC_1V8_3V_SEL MOP500_EGPIO(18) | 29 | #define GPIO_SDMMC_1V8_3V_SEL MOP500_EGPIO(18) |
| 30 | #define MOP500_EGPIO_END MOP500_EGPIO(24) | ||
| 31 | |||
| 32 | /* GPIOs on the AB8500 mixed-signals circuit */ | ||
| 33 | #define MOP500_AB8500_GPIO(x) (MOP500_EGPIO_END + (x)) | ||
| 30 | 34 | ||
| 31 | struct i2c_board_info; | 35 | struct i2c_board_info; |
| 32 | 36 | ||
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h index 7cdeb2af0ebb..97ef55f84934 100644 --- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h +++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h | |||
| @@ -35,9 +35,20 @@ | |||
| 35 | #define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END | 35 | #define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END |
| 36 | #define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x)) | 36 | #define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x)) |
| 37 | 37 | ||
| 38 | #define MOP500_NR_IRQS MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS) | 38 | #define MOP500_STMPE1601_IRQ_END \ |
| 39 | MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS) | ||
| 39 | 40 | ||
| 40 | #define MOP500_IRQ_END MOP500_NR_IRQS | 41 | /* AB8500 virtual gpio IRQ */ |
| 42 | #define AB8500_VIR_GPIO_NR_IRQS 16 | ||
| 43 | |||
| 44 | #define MOP500_AB8500_VIR_GPIO_IRQ_BASE \ | ||
| 45 | MOP500_STMPE1601_IRQ_END | ||
| 46 | #define MOP500_AB8500_VIR_GPIO_IRQ_END \ | ||
| 47 | (MOP500_AB8500_VIR_GPIO_IRQ_BASE + AB8500_VIR_GPIO_NR_IRQS) | ||
| 48 | |||
| 49 | #define MOP500_NR_IRQS MOP500_AB8500_VIR_GPIO_IRQ_END | ||
| 50 | |||
| 51 | #define MOP500_IRQ_END MOP500_NR_IRQS | ||
| 41 | 52 | ||
| 42 | #if MOP500_IRQ_END > IRQ_BOARD_END | 53 | #if MOP500_IRQ_END > IRQ_BOARD_END |
| 43 | #undef IRQ_BOARD_END | 54 | #undef IRQ_BOARD_END |
diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c index c3bfe9b13acf..5cf5e721e6ca 100644 --- a/arch/arm/plat-s5p/cpu.c +++ b/arch/arm/plat-s5p/cpu.c | |||
| @@ -39,7 +39,7 @@ static const char name_exynos4210[] = "EXYNOS4210"; | |||
| 39 | static struct cpu_table cpu_ids[] __initdata = { | 39 | static struct cpu_table cpu_ids[] __initdata = { |
| 40 | { | 40 | { |
| 41 | .idcode = 0x56440100, | 41 | .idcode = 0x56440100, |
| 42 | .idmask = 0xffffff00, | 42 | .idmask = 0xfffff000, |
| 43 | .map_io = s5p6440_map_io, | 43 | .map_io = s5p6440_map_io, |
| 44 | .init_clocks = s5p6440_init_clocks, | 44 | .init_clocks = s5p6440_init_clocks, |
| 45 | .init_uarts = s5p6440_init_uarts, | 45 | .init_uarts = s5p6440_init_uarts, |
| @@ -47,7 +47,7 @@ static struct cpu_table cpu_ids[] __initdata = { | |||
| 47 | .name = name_s5p6440, | 47 | .name = name_s5p6440, |
| 48 | }, { | 48 | }, { |
| 49 | .idcode = 0x36442000, | 49 | .idcode = 0x36442000, |
| 50 | .idmask = 0xffffff00, | 50 | .idmask = 0xfffff000, |
| 51 | .map_io = s5p6442_map_io, | 51 | .map_io = s5p6442_map_io, |
| 52 | .init_clocks = s5p6442_init_clocks, | 52 | .init_clocks = s5p6442_init_clocks, |
| 53 | .init_uarts = s5p6442_init_uarts, | 53 | .init_uarts = s5p6442_init_uarts, |
| @@ -55,7 +55,7 @@ static struct cpu_table cpu_ids[] __initdata = { | |||
| 55 | .name = name_s5p6442, | 55 | .name = name_s5p6442, |
| 56 | }, { | 56 | }, { |
| 57 | .idcode = 0x36450000, | 57 | .idcode = 0x36450000, |
| 58 | .idmask = 0xffffff00, | 58 | .idmask = 0xfffff000, |
| 59 | .map_io = s5p6450_map_io, | 59 | .map_io = s5p6450_map_io, |
| 60 | .init_clocks = s5p6450_init_clocks, | 60 | .init_clocks = s5p6450_init_clocks, |
| 61 | .init_uarts = s5p6450_init_uarts, | 61 | .init_uarts = s5p6450_init_uarts, |
| @@ -79,7 +79,7 @@ static struct cpu_table cpu_ids[] __initdata = { | |||
| 79 | .name = name_s5pv210, | 79 | .name = name_s5pv210, |
| 80 | }, { | 80 | }, { |
| 81 | .idcode = 0x43210000, | 81 | .idcode = 0x43210000, |
| 82 | .idmask = 0xfffff000, | 82 | .idmask = 0xfffe0000, |
| 83 | .map_io = exynos4_map_io, | 83 | .map_io = exynos4_map_io, |
| 84 | .init_clocks = exynos4_init_clocks, | 84 | .init_clocks = exynos4_init_clocks, |
| 85 | .init_uarts = exynos4_init_uarts, | 85 | .init_uarts = exynos4_init_uarts, |
diff --git a/arch/arm/plat-samsung/init.c b/arch/arm/plat-samsung/init.c index 6790edfaca6f..79d10fca9090 100644 --- a/arch/arm/plat-samsung/init.c +++ b/arch/arm/plat-samsung/init.c | |||
| @@ -36,7 +36,7 @@ static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, | |||
| 36 | unsigned int count) | 36 | unsigned int count) |
| 37 | { | 37 | { |
| 38 | for (; count != 0; count--, tab++) { | 38 | for (; count != 0; count--, tab++) { |
| 39 | if ((idcode & tab->idmask) == tab->idcode) | 39 | if ((idcode & tab->idmask) == (tab->idcode & tab->idmask)) |
| 40 | return tab; | 40 | return tab; |
| 41 | } | 41 | } |
| 42 | 42 | ||
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 04a7fc5eaf46..617925ddd142 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
| @@ -296,8 +296,7 @@ config ETRAX_RTC | |||
| 296 | choice | 296 | choice |
| 297 | prompt "RTC chip" | 297 | prompt "RTC chip" |
| 298 | depends on ETRAX_RTC | 298 | depends on ETRAX_RTC |
| 299 | default ETRAX_PCF8563 if ETRAX_ARCH_V32 | 299 | default ETRAX_DS1302 |
| 300 | default ETRAX_DS1302 if ETRAX_ARCH_V10 | ||
| 301 | 300 | ||
| 302 | config ETRAX_DS1302 | 301 | config ETRAX_DS1302 |
| 303 | depends on ETRAX_ARCH_V10 | 302 | depends on ETRAX_ARCH_V10 |
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index ea69faba9b62..1391b731ad1c 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c | |||
| @@ -345,7 +345,7 @@ static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned | |||
| 345 | int ret; | 345 | int ret; |
| 346 | 346 | ||
| 347 | mutex_lock(&pcf8563_mutex); | 347 | mutex_lock(&pcf8563_mutex); |
| 348 | return pcf8563_ioctl(filp, cmd, arg); | 348 | ret = pcf8563_ioctl(filp, cmd, arg); |
| 349 | mutex_unlock(&pcf8563_mutex); | 349 | mutex_unlock(&pcf8563_mutex); |
| 350 | 350 | ||
| 351 | return ret; | 351 | return ret; |
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index b6be705c2a3e..e78fe49a9849 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c | |||
| @@ -537,7 +537,7 @@ void do_signal(int canrestart, struct pt_regs *regs) | |||
| 537 | RESTART_CRIS_SYS(regs); | 537 | RESTART_CRIS_SYS(regs); |
| 538 | } | 538 | } |
| 539 | if (regs->r10 == -ERESTART_RESTARTBLOCK) { | 539 | if (regs->r10 == -ERESTART_RESTARTBLOCK) { |
| 540 | regs->r10 = __NR_restart_syscall; | 540 | regs->r9 = __NR_restart_syscall; |
| 541 | regs->irp -= 2; | 541 | regs->irp -= 2; |
| 542 | } | 542 | } |
| 543 | } | 543 | } |
diff --git a/arch/cris/arch-v32/drivers/Makefile b/arch/cris/arch-v32/drivers/Makefile index e8c02437edaf..39aa3c117a86 100644 --- a/arch/cris/arch-v32/drivers/Makefile +++ b/arch/cris/arch-v32/drivers/Makefile | |||
| @@ -7,7 +7,6 @@ obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o | |||
| 7 | obj-$(CONFIG_ETRAXFS) += mach-fs/ | 7 | obj-$(CONFIG_ETRAXFS) += mach-fs/ |
| 8 | obj-$(CONFIG_CRIS_MACH_ARTPEC3) += mach-a3/ | 8 | obj-$(CONFIG_CRIS_MACH_ARTPEC3) += mach-a3/ |
| 9 | obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o | 9 | obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o |
| 10 | obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o | ||
| 11 | obj-$(CONFIG_ETRAX_I2C) += i2c.o | 10 | obj-$(CONFIG_ETRAX_I2C) += i2c.o |
| 12 | obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o | 11 | obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o |
| 13 | obj-$(CONFIG_PCI) += pci/ | 12 | obj-$(CONFIG_PCI) += pci/ |
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c deleted file mode 100644 index b6e4fc0aad42..000000000000 --- a/arch/cris/arch-v32/drivers/pcf8563.c +++ /dev/null | |||
| @@ -1,377 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * PCF8563 RTC | ||
| 3 | * | ||
| 4 | * From Phillips' datasheet: | ||
| 5 | * | ||
| 6 | * The PCF8563 is a CMOS real-time clock/calendar optimized for low power | ||
| 7 | * consumption. A programmable clock output, interrupt output and voltage | ||
| 8 | * low detector are also provided. All address and data are transferred | ||
| 9 | * serially via two-line bidirectional I2C-bus. Maximum bus speed is | ||
| 10 | * 400 kbits/s. The built-in word address register is incremented | ||
| 11 | * automatically after each written or read byte. | ||
| 12 | * | ||
| 13 | * Copyright (c) 2002-2007, Axis Communications AB | ||
| 14 | * All rights reserved. | ||
| 15 | * | ||
| 16 | * Author: Tobias Anderberg <tobiasa@axis.com>. | ||
| 17 | * | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/types.h> | ||
| 23 | #include <linux/sched.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/fs.h> | ||
| 26 | #include <linux/ioctl.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | #include <linux/bcd.h> | ||
| 29 | #include <linux/mutex.h> | ||
| 30 | |||
| 31 | #include <asm/uaccess.h> | ||
| 32 | #include <asm/system.h> | ||
| 33 | #include <asm/io.h> | ||
| 34 | #include <asm/rtc.h> | ||
| 35 | |||
| 36 | #include "i2c.h" | ||
| 37 | |||
| 38 | #define PCF8563_MAJOR 121 /* Local major number. */ | ||
| 39 | #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ | ||
| 40 | #define PCF8563_NAME "PCF8563" | ||
| 41 | #define DRIVER_VERSION "$Revision: 1.17 $" | ||
| 42 | |||
| 43 | /* Two simple wrapper macros, saves a few keystrokes. */ | ||
| 44 | #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) | ||
| 45 | #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) | ||
| 46 | |||
| 47 | static DEFINE_MUTEX(pcf8563_mutex); | ||
| 48 | static DEFINE_MUTEX(rtc_lock); /* Protect state etc */ | ||
| 49 | |||
| 50 | static const unsigned char days_in_month[] = | ||
| 51 | { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
| 52 | |||
| 53 | static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | ||
| 54 | |||
| 55 | /* Cache VL bit value read at driver init since writing the RTC_SECOND | ||
| 56 | * register clears the VL status. | ||
| 57 | */ | ||
| 58 | static int voltage_low; | ||
| 59 | |||
| 60 | static const struct file_operations pcf8563_fops = { | ||
| 61 | .owner = THIS_MODULE, | ||
| 62 | .unlocked_ioctl = pcf8563_unlocked_ioctl, | ||
| 63 | .llseek = noop_llseek, | ||
| 64 | }; | ||
| 65 | |||
| 66 | unsigned char | ||
| 67 | pcf8563_readreg(int reg) | ||
| 68 | { | ||
| 69 | unsigned char res = rtc_read(reg); | ||
| 70 | |||
| 71 | /* The PCF8563 does not return 0 for unimplemented bits. */ | ||
| 72 | switch (reg) { | ||
| 73 | case RTC_SECONDS: | ||
| 74 | case RTC_MINUTES: | ||
| 75 | res &= 0x7F; | ||
| 76 | break; | ||
| 77 | case RTC_HOURS: | ||
| 78 | case RTC_DAY_OF_MONTH: | ||
| 79 | res &= 0x3F; | ||
| 80 | break; | ||
| 81 | case RTC_WEEKDAY: | ||
| 82 | res &= 0x07; | ||
| 83 | break; | ||
| 84 | case RTC_MONTH: | ||
| 85 | res &= 0x1F; | ||
| 86 | break; | ||
| 87 | case RTC_CONTROL1: | ||
| 88 | res &= 0xA8; | ||
| 89 | break; | ||
| 90 | case RTC_CONTROL2: | ||
| 91 | res &= 0x1F; | ||
| 92 | break; | ||
| 93 | case RTC_CLOCKOUT_FREQ: | ||
| 94 | case RTC_TIMER_CONTROL: | ||
| 95 | res &= 0x83; | ||
| 96 | break; | ||
| 97 | } | ||
| 98 | return res; | ||
| 99 | } | ||
| 100 | |||
| 101 | void | ||
| 102 | pcf8563_writereg(int reg, unsigned char val) | ||
| 103 | { | ||
| 104 | rtc_write(reg, val); | ||
| 105 | } | ||
| 106 | |||
| 107 | void | ||
| 108 | get_rtc_time(struct rtc_time *tm) | ||
| 109 | { | ||
| 110 | tm->tm_sec = rtc_read(RTC_SECONDS); | ||
| 111 | tm->tm_min = rtc_read(RTC_MINUTES); | ||
| 112 | tm->tm_hour = rtc_read(RTC_HOURS); | ||
| 113 | tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); | ||
| 114 | tm->tm_wday = rtc_read(RTC_WEEKDAY); | ||
| 115 | tm->tm_mon = rtc_read(RTC_MONTH); | ||
| 116 | tm->tm_year = rtc_read(RTC_YEAR); | ||
| 117 | |||
| 118 | if (tm->tm_sec & 0x80) { | ||
| 119 | printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time " | ||
| 120 | "information is no longer guaranteed!\n", PCF8563_NAME); | ||
| 121 | } | ||
| 122 | |||
| 123 | tm->tm_year = bcd2bin(tm->tm_year) + | ||
| 124 | ((tm->tm_mon & 0x80) ? 100 : 0); | ||
| 125 | tm->tm_sec &= 0x7F; | ||
| 126 | tm->tm_min &= 0x7F; | ||
| 127 | tm->tm_hour &= 0x3F; | ||
| 128 | tm->tm_mday &= 0x3F; | ||
| 129 | tm->tm_wday &= 0x07; /* Not coded in BCD. */ | ||
| 130 | tm->tm_mon &= 0x1F; | ||
| 131 | |||
| 132 | tm->tm_sec = bcd2bin(tm->tm_sec); | ||
| 133 | tm->tm_min = bcd2bin(tm->tm_min); | ||
| 134 | tm->tm_hour = bcd2bin(tm->tm_hour); | ||
| 135 | tm->tm_mday = bcd2bin(tm->tm_mday); | ||
| 136 | tm->tm_mon = bcd2bin(tm->tm_mon); | ||
| 137 | tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */ | ||
| 138 | } | ||
| 139 | |||
| 140 | int __init | ||
| 141 | pcf8563_init(void) | ||
| 142 | { | ||
| 143 | static int res; | ||
| 144 | static int first = 1; | ||
| 145 | |||
| 146 | if (!first) | ||
| 147 | return res; | ||
| 148 | first = 0; | ||
| 149 | |||
| 150 | /* Initiate the i2c protocol. */ | ||
| 151 | res = i2c_init(); | ||
| 152 | if (res < 0) { | ||
| 153 | printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n"); | ||
| 154 | return res; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* | ||
| 158 | * First of all we need to reset the chip. This is done by | ||
| 159 | * clearing control1, control2 and clk freq and resetting | ||
| 160 | * all alarms. | ||
| 161 | */ | ||
| 162 | if (rtc_write(RTC_CONTROL1, 0x00) < 0) | ||
| 163 | goto err; | ||
| 164 | |||
| 165 | if (rtc_write(RTC_CONTROL2, 0x00) < 0) | ||
| 166 | goto err; | ||
| 167 | |||
| 168 | if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) | ||
| 169 | goto err; | ||
| 170 | |||
| 171 | if (rtc_write(RTC_TIMER_CONTROL, 0x03) < 0) | ||
| 172 | goto err; | ||
| 173 | |||
| 174 | /* Reset the alarms. */ | ||
| 175 | if (rtc_write(RTC_MINUTE_ALARM, 0x80) < 0) | ||
| 176 | goto err; | ||
| 177 | |||
| 178 | if (rtc_write(RTC_HOUR_ALARM, 0x80) < 0) | ||
| 179 | goto err; | ||
| 180 | |||
| 181 | if (rtc_write(RTC_DAY_ALARM, 0x80) < 0) | ||
| 182 | goto err; | ||
| 183 | |||
| 184 | if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0) | ||
| 185 | goto err; | ||
| 186 | |||
| 187 | /* Check for low voltage, and warn about it. */ | ||
| 188 | if (rtc_read(RTC_SECONDS) & 0x80) { | ||
| 189 | voltage_low = 1; | ||
| 190 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable " | ||
| 191 | "date/time information is no longer guaranteed!\n", | ||
| 192 | PCF8563_NAME); | ||
| 193 | } | ||
| 194 | |||
| 195 | return res; | ||
| 196 | |||
| 197 | err: | ||
| 198 | printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); | ||
| 199 | res = -1; | ||
| 200 | return res; | ||
| 201 | } | ||
| 202 | |||
| 203 | void __exit | ||
| 204 | pcf8563_exit(void) | ||
| 205 | { | ||
| 206 | unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME); | ||
| 207 | } | ||
| 208 | |||
| 209 | /* | ||
| 210 | * ioctl calls for this driver. Why return -ENOTTY upon error? Because | ||
| 211 | * POSIX says so! | ||
| 212 | */ | ||
| 213 | static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||
| 214 | { | ||
| 215 | /* Some sanity checks. */ | ||
| 216 | if (_IOC_TYPE(cmd) != RTC_MAGIC) | ||
| 217 | return -ENOTTY; | ||
| 218 | |||
| 219 | if (_IOC_NR(cmd) > RTC_MAX_IOCTL) | ||
| 220 | return -ENOTTY; | ||
| 221 | |||
| 222 | switch (cmd) { | ||
| 223 | case RTC_RD_TIME: | ||
| 224 | { | ||
| 225 | struct rtc_time tm; | ||
| 226 | |||
| 227 | mutex_lock(&rtc_lock); | ||
| 228 | memset(&tm, 0, sizeof tm); | ||
| 229 | get_rtc_time(&tm); | ||
| 230 | |||
| 231 | if (copy_to_user((struct rtc_time *) arg, &tm, | ||
| 232 | sizeof tm)) { | ||
| 233 | mutex_unlock(&rtc_lock); | ||
| 234 | return -EFAULT; | ||
| 235 | } | ||
| 236 | |||
| 237 | mutex_unlock(&rtc_lock); | ||
| 238 | |||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | case RTC_SET_TIME: | ||
| 242 | { | ||
| 243 | int leap; | ||
| 244 | int year; | ||
| 245 | int century; | ||
| 246 | struct rtc_time tm; | ||
| 247 | |||
| 248 | memset(&tm, 0, sizeof tm); | ||
| 249 | if (!capable(CAP_SYS_TIME)) | ||
| 250 | return -EPERM; | ||
| 251 | |||
| 252 | if (copy_from_user(&tm, (struct rtc_time *) arg, | ||
| 253 | sizeof tm)) | ||
| 254 | return -EFAULT; | ||
| 255 | |||
| 256 | /* Convert from struct tm to struct rtc_time. */ | ||
| 257 | tm.tm_year += 1900; | ||
| 258 | tm.tm_mon += 1; | ||
| 259 | |||
| 260 | /* | ||
| 261 | * Check if tm.tm_year is a leap year. A year is a leap | ||
| 262 | * year if it is divisible by 4 but not 100, except | ||
| 263 | * that years divisible by 400 _are_ leap years. | ||
| 264 | */ | ||
| 265 | year = tm.tm_year; | ||
| 266 | leap = (tm.tm_mon == 2) && | ||
| 267 | ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); | ||
| 268 | |||
| 269 | /* Perform some sanity checks. */ | ||
| 270 | if ((tm.tm_year < 1970) || | ||
| 271 | (tm.tm_mon > 12) || | ||
| 272 | (tm.tm_mday == 0) || | ||
| 273 | (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || | ||
| 274 | (tm.tm_wday >= 7) || | ||
| 275 | (tm.tm_hour >= 24) || | ||
| 276 | (tm.tm_min >= 60) || | ||
| 277 | (tm.tm_sec >= 60)) | ||
| 278 | return -EINVAL; | ||
| 279 | |||
| 280 | century = (tm.tm_year >= 2000) ? 0x80 : 0; | ||
| 281 | tm.tm_year = tm.tm_year % 100; | ||
| 282 | |||
| 283 | tm.tm_year = bin2bcd(tm.tm_year); | ||
| 284 | tm.tm_mon = bin2bcd(tm.tm_mon); | ||
| 285 | tm.tm_mday = bin2bcd(tm.tm_mday); | ||
| 286 | tm.tm_hour = bin2bcd(tm.tm_hour); | ||
| 287 | tm.tm_min = bin2bcd(tm.tm_min); | ||
| 288 | tm.tm_sec = bin2bcd(tm.tm_sec); | ||
| 289 | tm.tm_mon |= century; | ||
| 290 | |||
| 291 | mutex_lock(&rtc_lock); | ||
| 292 | |||
| 293 | rtc_write(RTC_YEAR, tm.tm_year); | ||
| 294 | rtc_write(RTC_MONTH, tm.tm_mon); | ||
| 295 | rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */ | ||
| 296 | rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); | ||
| 297 | rtc_write(RTC_HOURS, tm.tm_hour); | ||
| 298 | rtc_write(RTC_MINUTES, tm.tm_min); | ||
| 299 | rtc_write(RTC_SECONDS, tm.tm_sec); | ||
| 300 | |||
| 301 | mutex_unlock(&rtc_lock); | ||
| 302 | |||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | case RTC_VL_READ: | ||
| 306 | if (voltage_low) | ||
| 307 | printk(KERN_ERR "%s: RTC Voltage Low - " | ||
| 308 | "reliable date/time information is no " | ||
| 309 | "longer guaranteed!\n", PCF8563_NAME); | ||
| 310 | |||
| 311 | if (copy_to_user((int *) arg, &voltage_low, sizeof(int))) | ||
| 312 | return -EFAULT; | ||
| 313 | return 0; | ||
| 314 | |||
| 315 | case RTC_VL_CLR: | ||
| 316 | { | ||
| 317 | /* Clear the VL bit in the seconds register in case | ||
| 318 | * the time has not been set already (which would | ||
| 319 | * have cleared it). This does not really matter | ||
| 320 | * because of the cached voltage_low value but do it | ||
| 321 | * anyway for consistency. */ | ||
| 322 | |||
| 323 | int ret = rtc_read(RTC_SECONDS); | ||
| 324 | |||
| 325 | rtc_write(RTC_SECONDS, (ret & 0x7F)); | ||
| 326 | |||
| 327 | /* Clear the cached value. */ | ||
| 328 | voltage_low = 0; | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | default: | ||
| 333 | return -ENOTTY; | ||
| 334 | } | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||
| 340 | { | ||
| 341 | int ret; | ||
| 342 | |||
| 343 | mutex_lock(&pcf8563_mutex); | ||
| 344 | return pcf8563_ioctl(filp, cmd, arg); | ||
| 345 | mutex_unlock(&pcf8563_mutex); | ||
| 346 | |||
| 347 | return ret; | ||
| 348 | } | ||
| 349 | |||
| 350 | static int __init pcf8563_register(void) | ||
| 351 | { | ||
| 352 | if (pcf8563_init() < 0) { | ||
| 353 | printk(KERN_INFO "%s: Unable to initialize Real-Time Clock " | ||
| 354 | "Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); | ||
| 355 | return -1; | ||
| 356 | } | ||
| 357 | |||
| 358 | if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { | ||
| 359 | printk(KERN_INFO "%s: Unable to get major numer %d for RTC " | ||
| 360 | "device.\n", PCF8563_NAME, PCF8563_MAJOR); | ||
| 361 | return -1; | ||
| 362 | } | ||
| 363 | |||
| 364 | printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, | ||
| 365 | DRIVER_VERSION); | ||
| 366 | |||
| 367 | /* Check for low voltage, and warn about it. */ | ||
| 368 | if (voltage_low) { | ||
| 369 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time " | ||
| 370 | "information is no longer guaranteed!\n", PCF8563_NAME); | ||
| 371 | } | ||
| 372 | |||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | |||
| 376 | module_init(pcf8563_register); | ||
| 377 | module_exit(pcf8563_exit); | ||
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 48cd7d2e1b75..81239ebed83f 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig | |||
| @@ -9,6 +9,7 @@ config PPC_CELL_COMMON | |||
| 9 | select PPC_INDIRECT_IO | 9 | select PPC_INDIRECT_IO |
| 10 | select PPC_NATIVE | 10 | select PPC_NATIVE |
| 11 | select PPC_RTAS | 11 | select PPC_RTAS |
| 12 | select IRQ_EDGE_EOI_HANDLER | ||
| 12 | 13 | ||
| 13 | config PPC_CELL_NATIVE | 14 | config PPC_CELL_NATIVE |
| 14 | bool | 15 | bool |
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 624d26e72f1d..ec9fc7d82068 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
| @@ -235,54 +235,6 @@ static int iic_host_match(struct irq_host *h, struct device_node *node) | |||
| 235 | "IBM,CBEA-Internal-Interrupt-Controller"); | 235 | "IBM,CBEA-Internal-Interrupt-Controller"); |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | extern int noirqdebug; | ||
| 239 | |||
| 240 | static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) | ||
| 241 | { | ||
| 242 | struct irq_chip *chip = get_irq_desc_chip(desc); | ||
| 243 | |||
| 244 | raw_spin_lock(&desc->lock); | ||
| 245 | |||
| 246 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | ||
| 247 | |||
| 248 | /* | ||
| 249 | * If we're currently running this IRQ, or its disabled, | ||
| 250 | * we shouldn't process the IRQ. Mark it pending, handle | ||
| 251 | * the necessary masking and go out | ||
| 252 | */ | ||
| 253 | if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) || | ||
| 254 | !desc->action)) { | ||
| 255 | desc->status |= IRQ_PENDING; | ||
| 256 | goto out_eoi; | ||
| 257 | } | ||
| 258 | |||
| 259 | kstat_incr_irqs_this_cpu(irq, desc); | ||
| 260 | |||
| 261 | /* Mark the IRQ currently in progress.*/ | ||
| 262 | desc->status |= IRQ_INPROGRESS; | ||
| 263 | |||
| 264 | do { | ||
| 265 | struct irqaction *action = desc->action; | ||
| 266 | irqreturn_t action_ret; | ||
| 267 | |||
| 268 | if (unlikely(!action)) | ||
| 269 | goto out_eoi; | ||
| 270 | |||
| 271 | desc->status &= ~IRQ_PENDING; | ||
| 272 | raw_spin_unlock(&desc->lock); | ||
| 273 | action_ret = handle_IRQ_event(irq, action); | ||
| 274 | if (!noirqdebug) | ||
| 275 | note_interrupt(irq, desc, action_ret); | ||
| 276 | raw_spin_lock(&desc->lock); | ||
| 277 | |||
| 278 | } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING); | ||
| 279 | |||
| 280 | desc->status &= ~IRQ_INPROGRESS; | ||
| 281 | out_eoi: | ||
| 282 | chip->irq_eoi(&desc->irq_data); | ||
| 283 | raw_spin_unlock(&desc->lock); | ||
| 284 | } | ||
| 285 | |||
| 286 | static int iic_host_map(struct irq_host *h, unsigned int virq, | 238 | static int iic_host_map(struct irq_host *h, unsigned int virq, |
| 287 | irq_hw_number_t hw) | 239 | irq_hw_number_t hw) |
| 288 | { | 240 | { |
| @@ -295,7 +247,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq, | |||
| 295 | handle_iic_irq); | 247 | handle_iic_irq); |
| 296 | break; | 248 | break; |
| 297 | default: | 249 | default: |
| 298 | set_irq_chip_and_handler(virq, &iic_chip, handle_iic_irq); | 250 | set_irq_chip_and_handler(virq, &iic_chip, handle_edge_eoi_irq); |
| 299 | } | 251 | } |
| 300 | return 0; | 252 | return 0; |
| 301 | } | 253 | } |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d8d0cda2641d..d3743204a7e9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
| @@ -414,4 +414,9 @@ config GPIO_JANZ_TTL | |||
| 414 | This driver provides support for driving the pins in output | 414 | This driver provides support for driving the pins in output |
| 415 | mode only. Input mode is not supported. | 415 | mode only. Input mode is not supported. |
| 416 | 416 | ||
| 417 | config AB8500_GPIO | ||
| 418 | bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" | ||
| 419 | depends on AB8500_CORE | ||
| 420 | help | ||
| 421 | Select this to enable the AB8500 IC GPIO driver | ||
| 417 | endif | 422 | endif |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 3351cf87b0ed..becef5954356 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
| @@ -42,3 +42,4 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o | |||
| 42 | obj-$(CONFIG_GPIO_SX150X) += sx150x.o | 42 | obj-$(CONFIG_GPIO_SX150X) += sx150x.o |
| 43 | obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o | 43 | obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o |
| 44 | obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o | 44 | obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o |
| 45 | obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o | ||
diff --git a/drivers/gpio/ab8500-gpio.c b/drivers/gpio/ab8500-gpio.c new file mode 100644 index 000000000000..e7b834d054b7 --- /dev/null +++ b/drivers/gpio/ab8500-gpio.c | |||
| @@ -0,0 +1,522 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2011 | ||
| 3 | * | ||
| 4 | * Author: BIBEK BASU <bibek.basu@stericsson.com> | ||
| 5 | * License terms: GNU General Public License (GPL) version 2 | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/gpio.h> | ||
| 20 | #include <linux/irq.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/mfd/ab8500.h> | ||
| 23 | #include <linux/mfd/abx500.h> | ||
| 24 | #include <linux/mfd/ab8500/gpio.h> | ||
| 25 | |||
| 26 | /* | ||
| 27 | * GPIO registers offset | ||
| 28 | * Bank: 0x10 | ||
| 29 | */ | ||
| 30 | #define AB8500_GPIO_SEL1_REG 0x00 | ||
| 31 | #define AB8500_GPIO_SEL2_REG 0x01 | ||
| 32 | #define AB8500_GPIO_SEL3_REG 0x02 | ||
| 33 | #define AB8500_GPIO_SEL4_REG 0x03 | ||
| 34 | #define AB8500_GPIO_SEL5_REG 0x04 | ||
| 35 | #define AB8500_GPIO_SEL6_REG 0x05 | ||
| 36 | |||
| 37 | #define AB8500_GPIO_DIR1_REG 0x10 | ||
| 38 | #define AB8500_GPIO_DIR2_REG 0x11 | ||
| 39 | #define AB8500_GPIO_DIR3_REG 0x12 | ||
| 40 | #define AB8500_GPIO_DIR4_REG 0x13 | ||
| 41 | #define AB8500_GPIO_DIR5_REG 0x14 | ||
| 42 | #define AB8500_GPIO_DIR6_REG 0x15 | ||
| 43 | |||
| 44 | #define AB8500_GPIO_OUT1_REG 0x20 | ||
| 45 | #define AB8500_GPIO_OUT2_REG 0x21 | ||
| 46 | #define AB8500_GPIO_OUT3_REG 0x22 | ||
| 47 | #define AB8500_GPIO_OUT4_REG 0x23 | ||
| 48 | #define AB8500_GPIO_OUT5_REG 0x24 | ||
| 49 | #define AB8500_GPIO_OUT6_REG 0x25 | ||
| 50 | |||
| 51 | #define AB8500_GPIO_PUD1_REG 0x30 | ||
| 52 | #define AB8500_GPIO_PUD2_REG 0x31 | ||
| 53 | #define AB8500_GPIO_PUD3_REG 0x32 | ||
| 54 | #define AB8500_GPIO_PUD4_REG 0x33 | ||
| 55 | #define AB8500_GPIO_PUD5_REG 0x34 | ||
| 56 | #define AB8500_GPIO_PUD6_REG 0x35 | ||
| 57 | |||
| 58 | #define AB8500_GPIO_IN1_REG 0x40 | ||
| 59 | #define AB8500_GPIO_IN2_REG 0x41 | ||
| 60 | #define AB8500_GPIO_IN3_REG 0x42 | ||
| 61 | #define AB8500_GPIO_IN4_REG 0x43 | ||
| 62 | #define AB8500_GPIO_IN5_REG 0x44 | ||
| 63 | #define AB8500_GPIO_IN6_REG 0x45 | ||
| 64 | #define AB8500_GPIO_ALTFUN_REG 0x45 | ||
| 65 | #define ALTFUN_REG_INDEX 6 | ||
| 66 | #define AB8500_NUM_GPIO 42 | ||
| 67 | #define AB8500_NUM_VIR_GPIO_IRQ 16 | ||
| 68 | |||
| 69 | enum ab8500_gpio_action { | ||
| 70 | NONE, | ||
| 71 | STARTUP, | ||
| 72 | SHUTDOWN, | ||
| 73 | MASK, | ||
| 74 | UNMASK | ||
| 75 | }; | ||
| 76 | |||
| 77 | struct ab8500_gpio { | ||
| 78 | struct gpio_chip chip; | ||
| 79 | struct ab8500 *parent; | ||
| 80 | struct device *dev; | ||
| 81 | struct mutex lock; | ||
| 82 | u32 irq_base; | ||
| 83 | enum ab8500_gpio_action irq_action; | ||
| 84 | u16 rising; | ||
| 85 | u16 falling; | ||
| 86 | }; | ||
| 87 | /** | ||
| 88 | * to_ab8500_gpio() - get the pointer to ab8500_gpio | ||
| 89 | * @chip: Member of the structure ab8500_gpio | ||
| 90 | */ | ||
| 91 | static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip) | ||
| 92 | { | ||
| 93 | return container_of(chip, struct ab8500_gpio, chip); | ||
| 94 | } | ||
| 95 | |||
| 96 | static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg, | ||
| 97 | unsigned offset, int val) | ||
| 98 | { | ||
| 99 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
| 100 | u8 pos = offset % 8; | ||
| 101 | int ret; | ||
| 102 | |||
| 103 | reg = reg + (offset / 8); | ||
| 104 | ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev, | ||
| 105 | AB8500_MISC, reg, 1 << pos, val << pos); | ||
| 106 | if (ret < 0) | ||
| 107 | dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); | ||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | /** | ||
| 111 | * ab8500_gpio_get() - Get the particular GPIO value | ||
| 112 | * @chip: Gpio device | ||
| 113 | * @offset: GPIO number to read | ||
| 114 | */ | ||
| 115 | static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
| 116 | { | ||
| 117 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
| 118 | u8 mask = 1 << (offset % 8); | ||
| 119 | u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8); | ||
| 120 | int ret; | ||
| 121 | u8 data; | ||
| 122 | ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC, | ||
| 123 | reg, &data); | ||
| 124 | if (ret < 0) { | ||
| 125 | dev_err(ab8500_gpio->dev, "%s read failed\n", __func__); | ||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | return (data & mask) >> (offset % 8); | ||
| 129 | } | ||
| 130 | |||
| 131 | static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
| 132 | { | ||
| 133 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
| 134 | int ret; | ||
| 135 | /* Write the data */ | ||
| 136 | ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1); | ||
| 137 | if (ret < 0) | ||
| 138 | dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); | ||
| 139 | } | ||
| 140 | |||
| 141 | static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
| 142 | int val) | ||
| 143 | { | ||
| 144 | int ret; | ||
| 145 | /* set direction as output */ | ||
| 146 | ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1); | ||
| 147 | if (ret < 0) | ||
| 148 | return ret; | ||
| 149 | /* disable pull down */ | ||
| 150 | ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1); | ||
| 151 | if (ret < 0) | ||
| 152 | return ret; | ||
| 153 | /* set the output as 1 or 0 */ | ||
| 154 | return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); | ||
| 155 | |||
| 156 | } | ||
| 157 | |||
| 158 | static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
| 159 | { | ||
| 160 | /* set the register as input */ | ||
| 161 | return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0); | ||
| 162 | } | ||
| 163 | |||
| 164 | static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
| 165 | { | ||
| 166 | /* | ||
| 167 | * Only some GPIOs are interrupt capable, and they are | ||
| 168 | * organized in discontiguous clusters: | ||
| 169 | * | ||
| 170 | * GPIO6 to GPIO13 | ||
| 171 | * GPIO24 and GPIO25 | ||
| 172 | * GPIO36 to GPIO41 | ||
| 173 | */ | ||
| 174 | static struct ab8500_gpio_irq_cluster { | ||
| 175 | int start; | ||
| 176 | int end; | ||
| 177 | } clusters[] = { | ||
| 178 | {.start = 6, .end = 13}, | ||
| 179 | {.start = 24, .end = 25}, | ||
| 180 | {.start = 36, .end = 41}, | ||
| 181 | }; | ||
| 182 | struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); | ||
| 183 | int base = ab8500_gpio->irq_base; | ||
| 184 | int i; | ||
| 185 | |||
| 186 | for (i = 0; i < ARRAY_SIZE(clusters); i++) { | ||
| 187 | struct ab8500_gpio_irq_cluster *cluster = &clusters[i]; | ||
| 188 | |||
| 189 | if (offset >= cluster->start && offset <= cluster->end) | ||
| 190 | return base + offset - cluster->start; | ||
| 191 | |||
| 192 | /* Advance by the number of gpios in this cluster */ | ||
| 193 | base += cluster->end - cluster->start + 1; | ||
| 194 | } | ||
| 195 | |||
| 196 | return -EINVAL; | ||
| 197 | } | ||
| 198 | |||
| 199 | static struct gpio_chip ab8500gpio_chip = { | ||
| 200 | .label = "ab8500_gpio", | ||
| 201 | .owner = THIS_MODULE, | ||
| 202 | .direction_input = ab8500_gpio_direction_input, | ||
| 203 | .get = ab8500_gpio_get, | ||
| 204 | .direction_output = ab8500_gpio_direction_output, | ||
| 205 | .set = ab8500_gpio_set, | ||
| 206 | .to_irq = ab8500_gpio_to_irq, | ||
| 207 | }; | ||
| 208 | |||
| 209 | static unsigned int irq_to_rising(unsigned int irq) | ||
| 210 | { | ||
| 211 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 212 | int offset = irq - ab8500_gpio->irq_base; | ||
| 213 | int new_irq = offset + AB8500_INT_GPIO6R | ||
| 214 | + ab8500_gpio->parent->irq_base; | ||
| 215 | return new_irq; | ||
| 216 | } | ||
| 217 | |||
| 218 | static unsigned int irq_to_falling(unsigned int irq) | ||
| 219 | { | ||
| 220 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 221 | int offset = irq - ab8500_gpio->irq_base; | ||
| 222 | int new_irq = offset + AB8500_INT_GPIO6F | ||
| 223 | + ab8500_gpio->parent->irq_base; | ||
| 224 | return new_irq; | ||
| 225 | |||
| 226 | } | ||
| 227 | |||
| 228 | static unsigned int rising_to_irq(unsigned int irq, void *dev) | ||
| 229 | { | ||
| 230 | struct ab8500_gpio *ab8500_gpio = dev; | ||
| 231 | int offset = irq - AB8500_INT_GPIO6R | ||
| 232 | - ab8500_gpio->parent->irq_base ; | ||
| 233 | int new_irq = offset + ab8500_gpio->irq_base; | ||
| 234 | return new_irq; | ||
| 235 | } | ||
| 236 | |||
| 237 | static unsigned int falling_to_irq(unsigned int irq, void *dev) | ||
| 238 | { | ||
| 239 | struct ab8500_gpio *ab8500_gpio = dev; | ||
| 240 | int offset = irq - AB8500_INT_GPIO6F | ||
| 241 | - ab8500_gpio->parent->irq_base ; | ||
| 242 | int new_irq = offset + ab8500_gpio->irq_base; | ||
| 243 | return new_irq; | ||
| 244 | |||
| 245 | } | ||
| 246 | |||
| 247 | /* | ||
| 248 | * IRQ handler | ||
| 249 | */ | ||
| 250 | |||
| 251 | static irqreturn_t handle_rising(int irq, void *dev) | ||
| 252 | { | ||
| 253 | |||
| 254 | handle_nested_irq(rising_to_irq(irq , dev)); | ||
| 255 | return IRQ_HANDLED; | ||
| 256 | } | ||
| 257 | |||
| 258 | static irqreturn_t handle_falling(int irq, void *dev) | ||
| 259 | { | ||
| 260 | |||
| 261 | handle_nested_irq(falling_to_irq(irq, dev)); | ||
| 262 | return IRQ_HANDLED; | ||
| 263 | } | ||
| 264 | |||
| 265 | static void ab8500_gpio_irq_lock(unsigned int irq) | ||
| 266 | { | ||
| 267 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 268 | mutex_lock(&ab8500_gpio->lock); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void ab8500_gpio_irq_sync_unlock(unsigned int irq) | ||
| 272 | { | ||
| 273 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 274 | int offset = irq - ab8500_gpio->irq_base; | ||
| 275 | bool rising = ab8500_gpio->rising & BIT(offset); | ||
| 276 | bool falling = ab8500_gpio->falling & BIT(offset); | ||
| 277 | int ret; | ||
| 278 | |||
| 279 | switch (ab8500_gpio->irq_action) { | ||
| 280 | case STARTUP: | ||
| 281 | if (rising) | ||
| 282 | ret = request_threaded_irq(irq_to_rising(irq), | ||
| 283 | NULL, handle_rising, | ||
| 284 | IRQF_TRIGGER_RISING, | ||
| 285 | "ab8500-gpio-r", ab8500_gpio); | ||
| 286 | if (falling) | ||
| 287 | ret = request_threaded_irq(irq_to_falling(irq), | ||
| 288 | NULL, handle_falling, | ||
| 289 | IRQF_TRIGGER_FALLING, | ||
| 290 | "ab8500-gpio-f", ab8500_gpio); | ||
| 291 | break; | ||
| 292 | case SHUTDOWN: | ||
| 293 | if (rising) | ||
| 294 | free_irq(irq_to_rising(irq), ab8500_gpio); | ||
| 295 | if (falling) | ||
| 296 | free_irq(irq_to_falling(irq), ab8500_gpio); | ||
| 297 | break; | ||
| 298 | case MASK: | ||
| 299 | if (rising) | ||
| 300 | disable_irq(irq_to_rising(irq)); | ||
| 301 | if (falling) | ||
| 302 | disable_irq(irq_to_falling(irq)); | ||
| 303 | break; | ||
| 304 | case UNMASK: | ||
| 305 | if (rising) | ||
| 306 | enable_irq(irq_to_rising(irq)); | ||
| 307 | if (falling) | ||
| 308 | enable_irq(irq_to_falling(irq)); | ||
| 309 | break; | ||
| 310 | case NONE: | ||
| 311 | break; | ||
| 312 | } | ||
| 313 | ab8500_gpio->irq_action = NONE; | ||
| 314 | ab8500_gpio->rising &= ~(BIT(offset)); | ||
| 315 | ab8500_gpio->falling &= ~(BIT(offset)); | ||
| 316 | mutex_unlock(&ab8500_gpio->lock); | ||
| 317 | } | ||
| 318 | |||
| 319 | |||
| 320 | static void ab8500_gpio_irq_mask(unsigned int irq) | ||
| 321 | { | ||
| 322 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 323 | ab8500_gpio->irq_action = MASK; | ||
| 324 | } | ||
| 325 | |||
| 326 | static void ab8500_gpio_irq_unmask(unsigned int irq) | ||
| 327 | { | ||
| 328 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 329 | ab8500_gpio->irq_action = UNMASK; | ||
| 330 | } | ||
| 331 | |||
| 332 | static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) | ||
| 333 | { | ||
| 334 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 335 | int offset = irq - ab8500_gpio->irq_base; | ||
| 336 | |||
| 337 | if (type == IRQ_TYPE_EDGE_BOTH) { | ||
| 338 | ab8500_gpio->rising = BIT(offset); | ||
| 339 | ab8500_gpio->falling = BIT(offset); | ||
| 340 | } else if (type == IRQ_TYPE_EDGE_RISING) { | ||
| 341 | ab8500_gpio->rising = BIT(offset); | ||
| 342 | } else { | ||
| 343 | ab8500_gpio->falling = BIT(offset); | ||
| 344 | } | ||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | |||
| 348 | unsigned int ab8500_gpio_irq_startup(unsigned int irq) | ||
| 349 | { | ||
| 350 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 351 | ab8500_gpio->irq_action = STARTUP; | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 355 | void ab8500_gpio_irq_shutdown(unsigned int irq) | ||
| 356 | { | ||
| 357 | struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); | ||
| 358 | ab8500_gpio->irq_action = SHUTDOWN; | ||
| 359 | } | ||
| 360 | |||
| 361 | static struct irq_chip ab8500_gpio_irq_chip = { | ||
| 362 | .name = "ab8500-gpio", | ||
| 363 | .startup = ab8500_gpio_irq_startup, | ||
| 364 | .shutdown = ab8500_gpio_irq_shutdown, | ||
| 365 | .bus_lock = ab8500_gpio_irq_lock, | ||
| 366 | .bus_sync_unlock = ab8500_gpio_irq_sync_unlock, | ||
| 367 | .mask = ab8500_gpio_irq_mask, | ||
| 368 | .unmask = ab8500_gpio_irq_unmask, | ||
| 369 | .set_type = ab8500_gpio_irq_set_type, | ||
| 370 | }; | ||
| 371 | |||
| 372 | static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) | ||
| 373 | { | ||
| 374 | u32 base = ab8500_gpio->irq_base; | ||
| 375 | int irq; | ||
| 376 | |||
| 377 | for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) { | ||
| 378 | set_irq_chip_data(irq, ab8500_gpio); | ||
| 379 | set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip, | ||
| 380 | handle_simple_irq); | ||
| 381 | set_irq_nested_thread(irq, 1); | ||
| 382 | #ifdef CONFIG_ARM | ||
| 383 | set_irq_flags(irq, IRQF_VALID); | ||
| 384 | #else | ||
| 385 | set_irq_noprobe(irq); | ||
| 386 | #endif | ||
| 387 | } | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) | ||
| 393 | { | ||
| 394 | int base = ab8500_gpio->irq_base; | ||
| 395 | int irq; | ||
| 396 | |||
| 397 | for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) { | ||
| 398 | #ifdef CONFIG_ARM | ||
| 399 | set_irq_flags(irq, 0); | ||
| 400 | #endif | ||
| 401 | set_irq_chip_and_handler(irq, NULL, NULL); | ||
| 402 | set_irq_chip_data(irq, NULL); | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | static int __devinit ab8500_gpio_probe(struct platform_device *pdev) | ||
| 407 | { | ||
| 408 | struct ab8500_platform_data *ab8500_pdata = | ||
| 409 | dev_get_platdata(pdev->dev.parent); | ||
| 410 | struct ab8500_gpio_platform_data *pdata; | ||
| 411 | struct ab8500_gpio *ab8500_gpio; | ||
| 412 | int ret; | ||
| 413 | int i; | ||
| 414 | |||
| 415 | pdata = ab8500_pdata->gpio; | ||
| 416 | if (!pdata) { | ||
| 417 | dev_err(&pdev->dev, "gpio platform data missing\n"); | ||
| 418 | return -ENODEV; | ||
| 419 | } | ||
| 420 | |||
| 421 | ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL); | ||
| 422 | if (ab8500_gpio == NULL) { | ||
| 423 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
| 424 | return -ENOMEM; | ||
| 425 | } | ||
| 426 | ab8500_gpio->dev = &pdev->dev; | ||
| 427 | ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent); | ||
| 428 | ab8500_gpio->chip = ab8500gpio_chip; | ||
| 429 | ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO; | ||
| 430 | ab8500_gpio->chip.dev = &pdev->dev; | ||
| 431 | ab8500_gpio->chip.base = pdata->gpio_base; | ||
| 432 | ab8500_gpio->irq_base = pdata->irq_base; | ||
| 433 | /* initialize the lock */ | ||
| 434 | mutex_init(&ab8500_gpio->lock); | ||
| 435 | /* | ||
| 436 | * AB8500 core will handle and clear the IRQ | ||
| 437 | * configre GPIO based on config-reg value. | ||
| 438 | * These values are for selecting the PINs as | ||
| 439 | * GPIO or alternate function | ||
| 440 | */ | ||
| 441 | for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++) { | ||
| 442 | ret = abx500_set_register_interruptible(ab8500_gpio->dev, | ||
| 443 | AB8500_MISC, i, | ||
| 444 | pdata->config_reg[i]); | ||
| 445 | if (ret < 0) | ||
| 446 | goto out_free; | ||
| 447 | } | ||
| 448 | ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC, | ||
| 449 | AB8500_GPIO_ALTFUN_REG, | ||
| 450 | pdata->config_reg[ALTFUN_REG_INDEX]); | ||
| 451 | if (ret < 0) | ||
| 452 | goto out_free; | ||
| 453 | |||
| 454 | ret = ab8500_gpio_irq_init(ab8500_gpio); | ||
| 455 | if (ret) | ||
| 456 | goto out_free; | ||
| 457 | ret = gpiochip_add(&ab8500_gpio->chip); | ||
| 458 | if (ret) { | ||
| 459 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", | ||
| 460 | ret); | ||
| 461 | goto out_rem_irq; | ||
| 462 | } | ||
| 463 | platform_set_drvdata(pdev, ab8500_gpio); | ||
| 464 | return 0; | ||
| 465 | |||
| 466 | out_rem_irq: | ||
| 467 | ab8500_gpio_irq_remove(ab8500_gpio); | ||
| 468 | out_free: | ||
| 469 | mutex_destroy(&ab8500_gpio->lock); | ||
| 470 | kfree(ab8500_gpio); | ||
| 471 | return ret; | ||
| 472 | } | ||
| 473 | |||
| 474 | /* | ||
| 475 | * ab8500_gpio_remove() - remove Ab8500-gpio driver | ||
| 476 | * @pdev : Platform device registered | ||
| 477 | */ | ||
| 478 | static int __devexit ab8500_gpio_remove(struct platform_device *pdev) | ||
| 479 | { | ||
| 480 | struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev); | ||
| 481 | int ret; | ||
| 482 | |||
| 483 | ret = gpiochip_remove(&ab8500_gpio->chip); | ||
| 484 | if (ret < 0) { | ||
| 485 | dev_err(ab8500_gpio->dev, "unable to remove gpiochip:\ | ||
| 486 | %d\n", ret); | ||
| 487 | return ret; | ||
| 488 | } | ||
| 489 | |||
| 490 | platform_set_drvdata(pdev, NULL); | ||
| 491 | mutex_destroy(&ab8500_gpio->lock); | ||
| 492 | kfree(ab8500_gpio); | ||
| 493 | |||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | static struct platform_driver ab8500_gpio_driver = { | ||
| 498 | .driver = { | ||
| 499 | .name = "ab8500-gpio", | ||
| 500 | .owner = THIS_MODULE, | ||
| 501 | }, | ||
| 502 | .probe = ab8500_gpio_probe, | ||
| 503 | .remove = __devexit_p(ab8500_gpio_remove), | ||
| 504 | }; | ||
| 505 | |||
| 506 | static int __init ab8500_gpio_init(void) | ||
| 507 | { | ||
| 508 | return platform_driver_register(&ab8500_gpio_driver); | ||
| 509 | } | ||
| 510 | arch_initcall(ab8500_gpio_init); | ||
| 511 | |||
| 512 | static void __exit ab8500_gpio_exit(void) | ||
| 513 | { | ||
| 514 | platform_driver_unregister(&ab8500_gpio_driver); | ||
| 515 | } | ||
| 516 | module_exit(ab8500_gpio_exit); | ||
| 517 | |||
| 518 | MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>"); | ||
| 519 | MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins\ | ||
| 520 | to be used as GPIO"); | ||
| 521 | MODULE_ALIAS("AB8500 GPIO driver"); | ||
| 522 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 767406c95291..700d420a59ac 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <linux/swab.h> | 23 | #include <linux/swab.h> |
| 24 | #include "r592.h" | 24 | #include "r592.h" |
| 25 | 25 | ||
| 26 | static int enable_dma = 1; | 26 | static int r592_enable_dma = 1; |
| 27 | static int debug; | 27 | static int debug; |
| 28 | 28 | ||
| 29 | static const char *tpc_names[] = { | 29 | static const char *tpc_names[] = { |
| @@ -267,7 +267,7 @@ static void r592_stop_dma(struct r592_device *dev, int error) | |||
| 267 | /* Test if hardware supports DMA */ | 267 | /* Test if hardware supports DMA */ |
| 268 | static void r592_check_dma(struct r592_device *dev) | 268 | static void r592_check_dma(struct r592_device *dev) |
| 269 | { | 269 | { |
| 270 | dev->dma_capable = enable_dma && | 270 | dev->dma_capable = r592_enable_dma && |
| 271 | (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & | 271 | (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & |
| 272 | R592_FIFO_DMA_SETTINGS_CAP); | 272 | R592_FIFO_DMA_SETTINGS_CAP); |
| 273 | } | 273 | } |
| @@ -898,7 +898,7 @@ static void __exit r592_module_exit(void) | |||
| 898 | module_init(r592_module_init); | 898 | module_init(r592_module_init); |
| 899 | module_exit(r592_module_exit); | 899 | module_exit(r592_module_exit); |
| 900 | 900 | ||
| 901 | module_param(enable_dma, bool, S_IRUGO); | 901 | module_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO); |
| 902 | MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); | 902 | MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); |
| 903 | module_param(debug, int, S_IRUGO | S_IWUSR); | 903 | module_param(debug, int, S_IRUGO | S_IWUSR); |
| 904 | MODULE_PARM_DESC(debug, "Debug level (0-3)"); | 904 | MODULE_PARM_DESC(debug, "Debug level (0-3)"); |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 62e33e2258d4..67d01c938284 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
| @@ -362,6 +362,15 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) | |||
| 362 | } | 362 | } |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | static struct resource ab8500_gpio_resources[] = { | ||
| 366 | { | ||
| 367 | .name = "GPIO_INT6", | ||
| 368 | .start = AB8500_INT_GPIO6R, | ||
| 369 | .end = AB8500_INT_GPIO41F, | ||
| 370 | .flags = IORESOURCE_IRQ, | ||
| 371 | } | ||
| 372 | }; | ||
| 373 | |||
| 365 | static struct resource ab8500_gpadc_resources[] = { | 374 | static struct resource ab8500_gpadc_resources[] = { |
| 366 | { | 375 | { |
| 367 | .name = "HW_CONV_END", | 376 | .name = "HW_CONV_END", |
| @@ -596,6 +605,11 @@ static struct mfd_cell ab8500_devs[] = { | |||
| 596 | .name = "ab8500-regulator", | 605 | .name = "ab8500-regulator", |
| 597 | }, | 606 | }, |
| 598 | { | 607 | { |
| 608 | .name = "ab8500-gpio", | ||
| 609 | .num_resources = ARRAY_SIZE(ab8500_gpio_resources), | ||
| 610 | .resources = ab8500_gpio_resources, | ||
| 611 | }, | ||
| 612 | { | ||
| 599 | .name = "ab8500-gpadc", | 613 | .name = "ab8500-gpadc", |
| 600 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | 614 | .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), |
| 601 | .resources = ab8500_gpadc_resources, | 615 | .resources = ab8500_gpadc_resources, |
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c index 6820327adf4a..821e6b86afd2 100644 --- a/drivers/mfd/ab8500-i2c.c +++ b/drivers/mfd/ab8500-i2c.c | |||
| @@ -97,7 +97,7 @@ static void __exit ab8500_i2c_exit(void) | |||
| 97 | { | 97 | { |
| 98 | platform_driver_unregister(&ab8500_i2c_driver); | 98 | platform_driver_unregister(&ab8500_i2c_driver); |
| 99 | } | 99 | } |
| 100 | subsys_initcall(ab8500_i2c_init); | 100 | arch_initcall(ab8500_i2c_init); |
| 101 | module_exit(ab8500_i2c_exit); | 101 | module_exit(ab8500_i2c_exit); |
| 102 | 102 | ||
| 103 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); | 103 | MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com"); |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 222dfb737b11..2ee442c2a5db 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
| @@ -101,6 +101,19 @@ config DELL_WMI | |||
| 101 | To compile this driver as a module, choose M here: the module will | 101 | To compile this driver as a module, choose M here: the module will |
| 102 | be called dell-wmi. | 102 | be called dell-wmi. |
| 103 | 103 | ||
| 104 | config DELL_WMI_AIO | ||
| 105 | tristate "WMI Hotkeys for Dell All-In-One series" | ||
| 106 | depends on ACPI_WMI | ||
| 107 | depends on INPUT | ||
| 108 | select INPUT_SPARSEKMAP | ||
| 109 | ---help--- | ||
| 110 | Say Y here if you want to support WMI-based hotkeys on Dell | ||
| 111 | All-In-One machines. | ||
| 112 | |||
| 113 | To compile this driver as a module, choose M here: the module will | ||
| 114 | be called dell-wmi. | ||
| 115 | |||
| 116 | |||
| 104 | config FUJITSU_LAPTOP | 117 | config FUJITSU_LAPTOP |
| 105 | tristate "Fujitsu Laptop Extras" | 118 | tristate "Fujitsu Laptop Extras" |
| 106 | depends on ACPI | 119 | depends on ACPI |
| @@ -438,23 +451,53 @@ config EEEPC_LAPTOP | |||
| 438 | Bluetooth, backlight and allows powering on/off some other | 451 | Bluetooth, backlight and allows powering on/off some other |
| 439 | devices. | 452 | devices. |
| 440 | 453 | ||
| 441 | If you have an Eee PC laptop, say Y or M here. | 454 | If you have an Eee PC laptop, say Y or M here. If this driver |
| 455 | doesn't work on your Eee PC, try eeepc-wmi instead. | ||
| 442 | 456 | ||
| 443 | config EEEPC_WMI | 457 | config ASUS_WMI |
| 444 | tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" | 458 | tristate "ASUS WMI Driver (EXPERIMENTAL)" |
| 445 | depends on ACPI_WMI | 459 | depends on ACPI_WMI |
| 446 | depends on INPUT | 460 | depends on INPUT |
| 461 | depends on HWMON | ||
| 447 | depends on EXPERIMENTAL | 462 | depends on EXPERIMENTAL |
| 448 | depends on BACKLIGHT_CLASS_DEVICE | 463 | depends on BACKLIGHT_CLASS_DEVICE |
| 449 | depends on RFKILL || RFKILL = n | 464 | depends on RFKILL || RFKILL = n |
| 465 | depends on HOTPLUG_PCI | ||
| 450 | select INPUT_SPARSEKMAP | 466 | select INPUT_SPARSEKMAP |
| 451 | select LEDS_CLASS | 467 | select LEDS_CLASS |
| 452 | select NEW_LEDS | 468 | select NEW_LEDS |
| 453 | ---help--- | 469 | ---help--- |
| 454 | Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. | 470 | Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new |
| 471 | Asus Notebooks). | ||
| 455 | 472 | ||
| 456 | To compile this driver as a module, choose M here: the module will | 473 | To compile this driver as a module, choose M here: the module will |
| 457 | be called eeepc-wmi. | 474 | be called asus-wmi. |
| 475 | |||
| 476 | config ASUS_NB_WMI | ||
| 477 | tristate "Asus Notebook WMI Driver (EXPERIMENTAL)" | ||
| 478 | depends on ASUS_WMI | ||
| 479 | ---help--- | ||
| 480 | This is a driver for newer Asus notebooks. It adds extra features | ||
| 481 | like wireless radio and bluetooth control, leds, hotkeys, backlight... | ||
| 482 | |||
| 483 | For more informations, see | ||
| 484 | <file:Documentation/ABI/testing/sysfs-platform-asus-wmi> | ||
| 485 | |||
| 486 | If you have an ACPI-WMI compatible Asus Notebook, say Y or M | ||
| 487 | here. | ||
| 488 | |||
| 489 | config EEEPC_WMI | ||
| 490 | tristate "Eee PC WMI Driver (EXPERIMENTAL)" | ||
| 491 | depends on ASUS_WMI | ||
| 492 | ---help--- | ||
| 493 | This is a driver for newer Eee PC laptops. It adds extra features | ||
| 494 | like wireless radio and bluetooth control, leds, hotkeys, backlight... | ||
| 495 | |||
| 496 | For more informations, see | ||
| 497 | <file:Documentation/ABI/testing/sysfs-platform-asus-wmi> | ||
| 498 | |||
| 499 | If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M | ||
| 500 | here. | ||
| 458 | 501 | ||
| 459 | config ACPI_WMI | 502 | config ACPI_WMI |
| 460 | tristate "WMI" | 503 | tristate "WMI" |
| @@ -616,6 +659,21 @@ config GPIO_INTEL_PMIC | |||
| 616 | Say Y here to support GPIO via the SCU IPC interface | 659 | Say Y here to support GPIO via the SCU IPC interface |
| 617 | on Intel MID platforms. | 660 | on Intel MID platforms. |
| 618 | 661 | ||
| 662 | config INTEL_MID_POWER_BUTTON | ||
| 663 | tristate "power button driver for Intel MID platforms" | ||
| 664 | depends on INTEL_SCU_IPC && INPUT | ||
| 665 | help | ||
| 666 | This driver handles the power button on the Intel MID platforms. | ||
| 667 | |||
| 668 | If unsure, say N. | ||
| 669 | |||
| 670 | config INTEL_MFLD_THERMAL | ||
| 671 | tristate "Thermal driver for Intel Medfield platform" | ||
| 672 | depends on INTEL_SCU_IPC && THERMAL | ||
| 673 | help | ||
| 674 | Say Y here to enable thermal driver support for the Intel Medfield | ||
| 675 | platform. | ||
| 676 | |||
| 619 | config RAR_REGISTER | 677 | config RAR_REGISTER |
| 620 | bool "Restricted Access Region Register Driver" | 678 | bool "Restricted Access Region Register Driver" |
| 621 | depends on PCI && X86_MRST | 679 | depends on PCI && X86_MRST |
| @@ -672,4 +730,26 @@ config XO1_RFKILL | |||
| 672 | Support for enabling/disabling the WLAN interface on the OLPC XO-1 | 730 | Support for enabling/disabling the WLAN interface on the OLPC XO-1 |
| 673 | laptop. | 731 | laptop. |
| 674 | 732 | ||
| 733 | config XO15_EBOOK | ||
| 734 | tristate "OLPC XO-1.5 ebook switch" | ||
| 735 | depends on ACPI && INPUT | ||
| 736 | ---help--- | ||
| 737 | Support for the ebook switch on the OLPC XO-1.5 laptop. | ||
| 738 | |||
| 739 | This switch is triggered as the screen is rotated and folded down to | ||
| 740 | convert the device into ebook form. | ||
| 741 | |||
| 742 | config SAMSUNG_LAPTOP | ||
| 743 | tristate "Samsung Laptop driver" | ||
| 744 | depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 | ||
| 745 | ---help--- | ||
| 746 | This module implements a driver for a wide range of different | ||
| 747 | Samsung laptops. It offers control over the different | ||
| 748 | function keys, wireless LED, LCD backlight level, and | ||
| 749 | sometimes provides a "performance_control" sysfs file to allow | ||
| 750 | the performance level of the laptop to be changed. | ||
| 751 | |||
| 752 | To compile this driver as a module, choose M here: the module | ||
| 753 | will be called samsung-laptop. | ||
| 754 | |||
| 675 | endif # X86_PLATFORM_DEVICES | 755 | endif # X86_PLATFORM_DEVICES |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 299aefb3e74c..029e8861d086 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | # x86 Platform-Specific Drivers | 3 | # x86 Platform-Specific Drivers |
| 4 | # | 4 | # |
| 5 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o | 5 | obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o |
| 6 | obj-$(CONFIG_ASUS_WMI) += asus-wmi.o | ||
| 7 | obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o | ||
| 6 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o | 8 | obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o |
| 7 | obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o | 9 | obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o |
| 8 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o | 10 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o |
| @@ -10,6 +12,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o | |||
| 10 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o | 12 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o |
| 11 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o | 13 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o |
| 12 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o | 14 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o |
| 15 | obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o | ||
| 13 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o | 16 | obj-$(CONFIG_ACER_WMI) += acer-wmi.o |
| 14 | obj-$(CONFIG_ACERHDF) += acerhdf.o | 17 | obj-$(CONFIG_ACERHDF) += acerhdf.o |
| 15 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o | 18 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o |
| @@ -29,9 +32,13 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o | |||
| 29 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | 32 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o |
| 30 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o | 33 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o |
| 31 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o | 34 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o |
| 32 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o | 35 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o |
| 36 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | ||
| 33 | obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o | 37 | obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o |
| 34 | obj-$(CONFIG_INTEL_IPS) += intel_ips.o | 38 | obj-$(CONFIG_INTEL_IPS) += intel_ips.o |
| 35 | obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o | 39 | obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o |
| 36 | obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o | 40 | obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o |
| 41 | obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o | ||
| 37 | obj-$(CONFIG_IBM_RTL) += ibm_rtl.o | 42 | obj-$(CONFIG_IBM_RTL) += ibm_rtl.o |
| 43 | obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o | ||
| 44 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | ||
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c9784705f6ac..5ea6c3477d17 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 26 | |||
| 25 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
| 26 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 27 | #include <linux/init.h> | 29 | #include <linux/init.h> |
| @@ -46,12 +48,6 @@ MODULE_AUTHOR("Carlos Corbacho"); | |||
| 46 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); | 48 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); |
| 47 | MODULE_LICENSE("GPL"); | 49 | MODULE_LICENSE("GPL"); |
| 48 | 50 | ||
| 49 | #define ACER_LOGPREFIX "acer-wmi: " | ||
| 50 | #define ACER_ERR KERN_ERR ACER_LOGPREFIX | ||
| 51 | #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX | ||
| 52 | #define ACER_INFO KERN_INFO ACER_LOGPREFIX | ||
| 53 | #define ACER_WARNING KERN_WARNING ACER_LOGPREFIX | ||
| 54 | |||
| 55 | /* | 51 | /* |
| 56 | * Magic Number | 52 | * Magic Number |
| 57 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 | 53 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 |
| @@ -84,7 +80,7 @@ MODULE_LICENSE("GPL"); | |||
| 84 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" | 80 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" |
| 85 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" | 81 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" |
| 86 | #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" | 82 | #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" |
| 87 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" | 83 | #define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A" |
| 88 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" | 84 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" |
| 89 | 85 | ||
| 90 | /* | 86 | /* |
| @@ -93,7 +89,7 @@ MODULE_LICENSE("GPL"); | |||
| 93 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" | 89 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" |
| 94 | 90 | ||
| 95 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); | 91 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); |
| 96 | MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); | 92 | MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); |
| 97 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); | 93 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); |
| 98 | 94 | ||
| 99 | enum acer_wmi_event_ids { | 95 | enum acer_wmi_event_ids { |
| @@ -108,7 +104,7 @@ static const struct key_entry acer_wmi_keymap[] = { | |||
| 108 | {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ | 104 | {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ |
| 109 | {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ | 105 | {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ |
| 110 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ | 106 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ |
| 111 | {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ | 107 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */ |
| 112 | {KE_END, 0} | 108 | {KE_END, 0} |
| 113 | }; | 109 | }; |
| 114 | 110 | ||
| @@ -221,6 +217,7 @@ struct acer_debug { | |||
| 221 | static struct rfkill *wireless_rfkill; | 217 | static struct rfkill *wireless_rfkill; |
| 222 | static struct rfkill *bluetooth_rfkill; | 218 | static struct rfkill *bluetooth_rfkill; |
| 223 | static struct rfkill *threeg_rfkill; | 219 | static struct rfkill *threeg_rfkill; |
| 220 | static bool rfkill_inited; | ||
| 224 | 221 | ||
| 225 | /* Each low-level interface must define at least some of the following */ | 222 | /* Each low-level interface must define at least some of the following */ |
| 226 | struct wmi_interface { | 223 | struct wmi_interface { |
| @@ -845,7 +842,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy) | |||
| 845 | has_type_aa = true; | 842 | has_type_aa = true; |
| 846 | type_aa = (struct hotkey_function_type_aa *) header; | 843 | type_aa = (struct hotkey_function_type_aa *) header; |
| 847 | 844 | ||
| 848 | printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", | 845 | pr_info("Function bitmap for Communication Button: 0x%x\n", |
| 849 | type_aa->commun_func_bitmap); | 846 | type_aa->commun_func_bitmap); |
| 850 | 847 | ||
| 851 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) | 848 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) |
| @@ -991,6 +988,7 @@ static int __devinit acer_led_init(struct device *dev) | |||
| 991 | 988 | ||
| 992 | static void acer_led_exit(void) | 989 | static void acer_led_exit(void) |
| 993 | { | 990 | { |
| 991 | set_u32(LED_OFF, ACER_CAP_MAILLED); | ||
| 994 | led_classdev_unregister(&mail_led); | 992 | led_classdev_unregister(&mail_led); |
| 995 | } | 993 | } |
| 996 | 994 | ||
| @@ -1036,7 +1034,7 @@ static int __devinit acer_backlight_init(struct device *dev) | |||
| 1036 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, | 1034 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, |
| 1037 | &props); | 1035 | &props); |
| 1038 | if (IS_ERR(bd)) { | 1036 | if (IS_ERR(bd)) { |
| 1039 | printk(ACER_ERR "Could not register Acer backlight device\n"); | 1037 | pr_err("Could not register Acer backlight device\n"); |
| 1040 | acer_backlight_device = NULL; | 1038 | acer_backlight_device = NULL; |
| 1041 | return PTR_ERR(bd); | 1039 | return PTR_ERR(bd); |
| 1042 | } | 1040 | } |
| @@ -1083,8 +1081,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) | |||
| 1083 | return AE_ERROR; | 1081 | return AE_ERROR; |
| 1084 | } | 1082 | } |
| 1085 | if (obj->buffer.length != 8) { | 1083 | if (obj->buffer.length != 8) { |
| 1086 | printk(ACER_WARNING "Unknown buffer length %d\n", | 1084 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); |
| 1087 | obj->buffer.length); | ||
| 1088 | kfree(obj); | 1085 | kfree(obj); |
| 1089 | return AE_ERROR; | 1086 | return AE_ERROR; |
| 1090 | } | 1087 | } |
| @@ -1093,7 +1090,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) | |||
| 1093 | kfree(obj); | 1090 | kfree(obj); |
| 1094 | 1091 | ||
| 1095 | if (return_value.error_code || return_value.ec_return_value) | 1092 | if (return_value.error_code || return_value.ec_return_value) |
| 1096 | printk(ACER_WARNING "Get Device Status failed: " | 1093 | pr_warning("Get Device Status failed: " |
| 1097 | "0x%x - 0x%x\n", return_value.error_code, | 1094 | "0x%x - 0x%x\n", return_value.error_code, |
| 1098 | return_value.ec_return_value); | 1095 | return_value.ec_return_value); |
| 1099 | else | 1096 | else |
| @@ -1161,9 +1158,13 @@ static int acer_rfkill_set(void *data, bool blocked) | |||
| 1161 | { | 1158 | { |
| 1162 | acpi_status status; | 1159 | acpi_status status; |
| 1163 | u32 cap = (unsigned long)data; | 1160 | u32 cap = (unsigned long)data; |
| 1164 | status = set_u32(!blocked, cap); | 1161 | |
| 1165 | if (ACPI_FAILURE(status)) | 1162 | if (rfkill_inited) { |
| 1166 | return -ENODEV; | 1163 | status = set_u32(!blocked, cap); |
| 1164 | if (ACPI_FAILURE(status)) | ||
| 1165 | return -ENODEV; | ||
| 1166 | } | ||
| 1167 | |||
| 1167 | return 0; | 1168 | return 0; |
| 1168 | } | 1169 | } |
| 1169 | 1170 | ||
| @@ -1187,14 +1188,16 @@ static struct rfkill *acer_rfkill_register(struct device *dev, | |||
| 1187 | return ERR_PTR(-ENOMEM); | 1188 | return ERR_PTR(-ENOMEM); |
| 1188 | 1189 | ||
| 1189 | status = get_device_status(&state, cap); | 1190 | status = get_device_status(&state, cap); |
| 1190 | if (ACPI_SUCCESS(status)) | ||
| 1191 | rfkill_init_sw_state(rfkill_dev, !state); | ||
| 1192 | 1191 | ||
| 1193 | err = rfkill_register(rfkill_dev); | 1192 | err = rfkill_register(rfkill_dev); |
| 1194 | if (err) { | 1193 | if (err) { |
| 1195 | rfkill_destroy(rfkill_dev); | 1194 | rfkill_destroy(rfkill_dev); |
| 1196 | return ERR_PTR(err); | 1195 | return ERR_PTR(err); |
| 1197 | } | 1196 | } |
| 1197 | |||
| 1198 | if (ACPI_SUCCESS(status)) | ||
| 1199 | rfkill_set_sw_state(rfkill_dev, !state); | ||
| 1200 | |||
| 1198 | return rfkill_dev; | 1201 | return rfkill_dev; |
| 1199 | } | 1202 | } |
| 1200 | 1203 | ||
| @@ -1229,14 +1232,19 @@ static int acer_rfkill_init(struct device *dev) | |||
| 1229 | } | 1232 | } |
| 1230 | } | 1233 | } |
| 1231 | 1234 | ||
| 1232 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); | 1235 | rfkill_inited = true; |
| 1236 | |||
| 1237 | if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) | ||
| 1238 | schedule_delayed_work(&acer_rfkill_work, | ||
| 1239 | round_jiffies_relative(HZ)); | ||
| 1233 | 1240 | ||
| 1234 | return 0; | 1241 | return 0; |
| 1235 | } | 1242 | } |
| 1236 | 1243 | ||
| 1237 | static void acer_rfkill_exit(void) | 1244 | static void acer_rfkill_exit(void) |
| 1238 | { | 1245 | { |
| 1239 | cancel_delayed_work_sync(&acer_rfkill_work); | 1246 | if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) |
| 1247 | cancel_delayed_work_sync(&acer_rfkill_work); | ||
| 1240 | 1248 | ||
| 1241 | rfkill_unregister(wireless_rfkill); | 1249 | rfkill_unregister(wireless_rfkill); |
| 1242 | rfkill_destroy(wireless_rfkill); | 1250 | rfkill_destroy(wireless_rfkill); |
| @@ -1309,7 +1317,7 @@ static void acer_wmi_notify(u32 value, void *context) | |||
| 1309 | 1317 | ||
| 1310 | status = wmi_get_event_data(value, &response); | 1318 | status = wmi_get_event_data(value, &response); |
| 1311 | if (status != AE_OK) { | 1319 | if (status != AE_OK) { |
| 1312 | printk(ACER_WARNING "bad event status 0x%x\n", status); | 1320 | pr_warning("bad event status 0x%x\n", status); |
| 1313 | return; | 1321 | return; |
| 1314 | } | 1322 | } |
| 1315 | 1323 | ||
| @@ -1318,14 +1326,12 @@ static void acer_wmi_notify(u32 value, void *context) | |||
| 1318 | if (!obj) | 1326 | if (!obj) |
| 1319 | return; | 1327 | return; |
| 1320 | if (obj->type != ACPI_TYPE_BUFFER) { | 1328 | if (obj->type != ACPI_TYPE_BUFFER) { |
| 1321 | printk(ACER_WARNING "Unknown response received %d\n", | 1329 | pr_warning("Unknown response received %d\n", obj->type); |
| 1322 | obj->type); | ||
| 1323 | kfree(obj); | 1330 | kfree(obj); |
| 1324 | return; | 1331 | return; |
| 1325 | } | 1332 | } |
| 1326 | if (obj->buffer.length != 8) { | 1333 | if (obj->buffer.length != 8) { |
| 1327 | printk(ACER_WARNING "Unknown buffer length %d\n", | 1334 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); |
| 1328 | obj->buffer.length); | ||
| 1329 | kfree(obj); | 1335 | kfree(obj); |
| 1330 | return; | 1336 | return; |
| 1331 | } | 1337 | } |
| @@ -1335,13 +1341,26 @@ static void acer_wmi_notify(u32 value, void *context) | |||
| 1335 | 1341 | ||
| 1336 | switch (return_value.function) { | 1342 | switch (return_value.function) { |
| 1337 | case WMID_HOTKEY_EVENT: | 1343 | case WMID_HOTKEY_EVENT: |
| 1344 | if (return_value.device_state) { | ||
| 1345 | u16 device_state = return_value.device_state; | ||
| 1346 | pr_debug("deivces states: 0x%x\n", device_state); | ||
| 1347 | if (has_cap(ACER_CAP_WIRELESS)) | ||
| 1348 | rfkill_set_sw_state(wireless_rfkill, | ||
| 1349 | !(device_state & ACER_WMID3_GDS_WIRELESS)); | ||
| 1350 | if (has_cap(ACER_CAP_BLUETOOTH)) | ||
| 1351 | rfkill_set_sw_state(bluetooth_rfkill, | ||
| 1352 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); | ||
| 1353 | if (has_cap(ACER_CAP_THREEG)) | ||
| 1354 | rfkill_set_sw_state(threeg_rfkill, | ||
| 1355 | !(device_state & ACER_WMID3_GDS_THREEG)); | ||
| 1356 | } | ||
| 1338 | if (!sparse_keymap_report_event(acer_wmi_input_dev, | 1357 | if (!sparse_keymap_report_event(acer_wmi_input_dev, |
| 1339 | return_value.key_num, 1, true)) | 1358 | return_value.key_num, 1, true)) |
| 1340 | printk(ACER_WARNING "Unknown key number - 0x%x\n", | 1359 | pr_warning("Unknown key number - 0x%x\n", |
| 1341 | return_value.key_num); | 1360 | return_value.key_num); |
| 1342 | break; | 1361 | break; |
| 1343 | default: | 1362 | default: |
| 1344 | printk(ACER_WARNING "Unknown function number - %d - %d\n", | 1363 | pr_warning("Unknown function number - %d - %d\n", |
| 1345 | return_value.function, return_value.key_num); | 1364 | return_value.function, return_value.key_num); |
| 1346 | break; | 1365 | break; |
| 1347 | } | 1366 | } |
| @@ -1370,8 +1389,7 @@ wmid3_set_lm_mode(struct lm_input_params *params, | |||
| 1370 | return AE_ERROR; | 1389 | return AE_ERROR; |
| 1371 | } | 1390 | } |
| 1372 | if (obj->buffer.length != 4) { | 1391 | if (obj->buffer.length != 4) { |
| 1373 | printk(ACER_WARNING "Unknown buffer length %d\n", | 1392 | pr_warning("Unknown buffer length %d\n", obj->buffer.length); |
| 1374 | obj->buffer.length); | ||
| 1375 | kfree(obj); | 1393 | kfree(obj); |
| 1376 | return AE_ERROR; | 1394 | return AE_ERROR; |
| 1377 | } | 1395 | } |
| @@ -1396,11 +1414,11 @@ static int acer_wmi_enable_ec_raw(void) | |||
| 1396 | status = wmid3_set_lm_mode(¶ms, &return_value); | 1414 | status = wmid3_set_lm_mode(¶ms, &return_value); |
| 1397 | 1415 | ||
| 1398 | if (return_value.error_code || return_value.ec_return_value) | 1416 | if (return_value.error_code || return_value.ec_return_value) |
| 1399 | printk(ACER_WARNING "Enabling EC raw mode failed: " | 1417 | pr_warning("Enabling EC raw mode failed: " |
| 1400 | "0x%x - 0x%x\n", return_value.error_code, | 1418 | "0x%x - 0x%x\n", return_value.error_code, |
| 1401 | return_value.ec_return_value); | 1419 | return_value.ec_return_value); |
| 1402 | else | 1420 | else |
| 1403 | printk(ACER_INFO "Enabled EC raw mode"); | 1421 | pr_info("Enabled EC raw mode"); |
| 1404 | 1422 | ||
| 1405 | return status; | 1423 | return status; |
| 1406 | } | 1424 | } |
| @@ -1419,7 +1437,7 @@ static int acer_wmi_enable_lm(void) | |||
| 1419 | status = wmid3_set_lm_mode(¶ms, &return_value); | 1437 | status = wmid3_set_lm_mode(¶ms, &return_value); |
| 1420 | 1438 | ||
| 1421 | if (return_value.error_code || return_value.ec_return_value) | 1439 | if (return_value.error_code || return_value.ec_return_value) |
| 1422 | printk(ACER_WARNING "Enabling Launch Manager failed: " | 1440 | pr_warning("Enabling Launch Manager failed: " |
| 1423 | "0x%x - 0x%x\n", return_value.error_code, | 1441 | "0x%x - 0x%x\n", return_value.error_code, |
| 1424 | return_value.ec_return_value); | 1442 | return_value.ec_return_value); |
| 1425 | 1443 | ||
| @@ -1553,6 +1571,7 @@ pm_message_t state) | |||
| 1553 | 1571 | ||
| 1554 | if (has_cap(ACER_CAP_MAILLED)) { | 1572 | if (has_cap(ACER_CAP_MAILLED)) { |
| 1555 | get_u32(&value, ACER_CAP_MAILLED); | 1573 | get_u32(&value, ACER_CAP_MAILLED); |
| 1574 | set_u32(LED_OFF, ACER_CAP_MAILLED); | ||
| 1556 | data->mailled = value; | 1575 | data->mailled = value; |
| 1557 | } | 1576 | } |
| 1558 | 1577 | ||
| @@ -1580,6 +1599,17 @@ static int acer_platform_resume(struct platform_device *device) | |||
| 1580 | return 0; | 1599 | return 0; |
| 1581 | } | 1600 | } |
| 1582 | 1601 | ||
| 1602 | static void acer_platform_shutdown(struct platform_device *device) | ||
| 1603 | { | ||
| 1604 | struct acer_data *data = &interface->data; | ||
| 1605 | |||
| 1606 | if (!data) | ||
| 1607 | return; | ||
| 1608 | |||
| 1609 | if (has_cap(ACER_CAP_MAILLED)) | ||
| 1610 | set_u32(LED_OFF, ACER_CAP_MAILLED); | ||
| 1611 | } | ||
| 1612 | |||
| 1583 | static struct platform_driver acer_platform_driver = { | 1613 | static struct platform_driver acer_platform_driver = { |
| 1584 | .driver = { | 1614 | .driver = { |
| 1585 | .name = "acer-wmi", | 1615 | .name = "acer-wmi", |
| @@ -1589,6 +1619,7 @@ static struct platform_driver acer_platform_driver = { | |||
| 1589 | .remove = acer_platform_remove, | 1619 | .remove = acer_platform_remove, |
| 1590 | .suspend = acer_platform_suspend, | 1620 | .suspend = acer_platform_suspend, |
| 1591 | .resume = acer_platform_resume, | 1621 | .resume = acer_platform_resume, |
| 1622 | .shutdown = acer_platform_shutdown, | ||
| 1592 | }; | 1623 | }; |
| 1593 | 1624 | ||
| 1594 | static struct platform_device *acer_platform_device; | 1625 | static struct platform_device *acer_platform_device; |
| @@ -1636,7 +1667,7 @@ static int create_debugfs(void) | |||
| 1636 | { | 1667 | { |
| 1637 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); | 1668 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); |
| 1638 | if (!interface->debug.root) { | 1669 | if (!interface->debug.root) { |
| 1639 | printk(ACER_ERR "Failed to create debugfs directory"); | 1670 | pr_err("Failed to create debugfs directory"); |
| 1640 | return -ENOMEM; | 1671 | return -ENOMEM; |
| 1641 | } | 1672 | } |
| 1642 | 1673 | ||
| @@ -1657,11 +1688,10 @@ static int __init acer_wmi_init(void) | |||
| 1657 | { | 1688 | { |
| 1658 | int err; | 1689 | int err; |
| 1659 | 1690 | ||
| 1660 | printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); | 1691 | pr_info("Acer Laptop ACPI-WMI Extras\n"); |
| 1661 | 1692 | ||
| 1662 | if (dmi_check_system(acer_blacklist)) { | 1693 | if (dmi_check_system(acer_blacklist)) { |
| 1663 | printk(ACER_INFO "Blacklisted hardware detected - " | 1694 | pr_info("Blacklisted hardware detected - not loading\n"); |
| 1664 | "not loading\n"); | ||
| 1665 | return -ENODEV; | 1695 | return -ENODEV; |
| 1666 | } | 1696 | } |
| 1667 | 1697 | ||
| @@ -1678,12 +1708,11 @@ static int __init acer_wmi_init(void) | |||
| 1678 | 1708 | ||
| 1679 | if (wmi_has_guid(WMID_GUID2) && interface) { | 1709 | if (wmi_has_guid(WMID_GUID2) && interface) { |
| 1680 | if (ACPI_FAILURE(WMID_set_capabilities())) { | 1710 | if (ACPI_FAILURE(WMID_set_capabilities())) { |
| 1681 | printk(ACER_ERR "Unable to detect available WMID " | 1711 | pr_err("Unable to detect available WMID devices\n"); |
| 1682 | "devices\n"); | ||
| 1683 | return -ENODEV; | 1712 | return -ENODEV; |
| 1684 | } | 1713 | } |
| 1685 | } else if (!wmi_has_guid(WMID_GUID2) && interface) { | 1714 | } else if (!wmi_has_guid(WMID_GUID2) && interface) { |
| 1686 | printk(ACER_ERR "No WMID device detection method found\n"); | 1715 | pr_err("No WMID device detection method found\n"); |
| 1687 | return -ENODEV; | 1716 | return -ENODEV; |
| 1688 | } | 1717 | } |
| 1689 | 1718 | ||
| @@ -1691,8 +1720,7 @@ static int __init acer_wmi_init(void) | |||
| 1691 | interface = &AMW0_interface; | 1720 | interface = &AMW0_interface; |
| 1692 | 1721 | ||
| 1693 | if (ACPI_FAILURE(AMW0_set_capabilities())) { | 1722 | if (ACPI_FAILURE(AMW0_set_capabilities())) { |
| 1694 | printk(ACER_ERR "Unable to detect available AMW0 " | 1723 | pr_err("Unable to detect available AMW0 devices\n"); |
| 1695 | "devices\n"); | ||
| 1696 | return -ENODEV; | 1724 | return -ENODEV; |
| 1697 | } | 1725 | } |
| 1698 | } | 1726 | } |
| @@ -1701,8 +1729,7 @@ static int __init acer_wmi_init(void) | |||
| 1701 | AMW0_find_mailled(); | 1729 | AMW0_find_mailled(); |
| 1702 | 1730 | ||
| 1703 | if (!interface) { | 1731 | if (!interface) { |
| 1704 | printk(ACER_INFO "No or unsupported WMI interface, unable to " | 1732 | pr_err("No or unsupported WMI interface, unable to load\n"); |
| 1705 | "load\n"); | ||
| 1706 | return -ENODEV; | 1733 | return -ENODEV; |
| 1707 | } | 1734 | } |
| 1708 | 1735 | ||
| @@ -1710,22 +1737,22 @@ static int __init acer_wmi_init(void) | |||
| 1710 | 1737 | ||
| 1711 | if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { | 1738 | if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { |
| 1712 | interface->capability &= ~ACER_CAP_BRIGHTNESS; | 1739 | interface->capability &= ~ACER_CAP_BRIGHTNESS; |
| 1713 | printk(ACER_INFO "Brightness must be controlled by " | 1740 | pr_info("Brightness must be controlled by " |
| 1714 | "generic video driver\n"); | 1741 | "generic video driver\n"); |
| 1715 | } | 1742 | } |
| 1716 | 1743 | ||
| 1717 | if (wmi_has_guid(WMID_GUID3)) { | 1744 | if (wmi_has_guid(WMID_GUID3)) { |
| 1718 | if (ec_raw_mode) { | 1745 | if (ec_raw_mode) { |
| 1719 | if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { | 1746 | if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { |
| 1720 | printk(ACER_ERR "Cannot enable EC raw mode\n"); | 1747 | pr_err("Cannot enable EC raw mode\n"); |
| 1721 | return -ENODEV; | 1748 | return -ENODEV; |
| 1722 | } | 1749 | } |
| 1723 | } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { | 1750 | } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { |
| 1724 | printk(ACER_ERR "Cannot enable Launch Manager mode\n"); | 1751 | pr_err("Cannot enable Launch Manager mode\n"); |
| 1725 | return -ENODEV; | 1752 | return -ENODEV; |
| 1726 | } | 1753 | } |
| 1727 | } else if (ec_raw_mode) { | 1754 | } else if (ec_raw_mode) { |
| 1728 | printk(ACER_INFO "No WMID EC raw mode enable method\n"); | 1755 | pr_info("No WMID EC raw mode enable method\n"); |
| 1729 | } | 1756 | } |
| 1730 | 1757 | ||
| 1731 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) { | 1758 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) { |
| @@ -1736,7 +1763,7 @@ static int __init acer_wmi_init(void) | |||
| 1736 | 1763 | ||
| 1737 | err = platform_driver_register(&acer_platform_driver); | 1764 | err = platform_driver_register(&acer_platform_driver); |
| 1738 | if (err) { | 1765 | if (err) { |
| 1739 | printk(ACER_ERR "Unable to register platform driver.\n"); | 1766 | pr_err("Unable to register platform driver.\n"); |
| 1740 | goto error_platform_register; | 1767 | goto error_platform_register; |
| 1741 | } | 1768 | } |
| 1742 | 1769 | ||
| @@ -1791,7 +1818,7 @@ static void __exit acer_wmi_exit(void) | |||
| 1791 | platform_device_unregister(acer_platform_device); | 1818 | platform_device_unregister(acer_platform_device); |
| 1792 | platform_driver_unregister(&acer_platform_driver); | 1819 | platform_driver_unregister(&acer_platform_driver); |
| 1793 | 1820 | ||
| 1794 | printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); | 1821 | pr_info("Acer Laptop WMI Extras unloaded\n"); |
| 1795 | return; | 1822 | return; |
| 1796 | } | 1823 | } |
| 1797 | 1824 | ||
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 5a6f7d7575d6..c53b3ff7978a 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | * John Belmonte - ACPI code for Toshiba laptop was a good starting point. | 29 | * John Belmonte - ACPI code for Toshiba laptop was a good starting point. |
| 30 | * Eric Burghard - LED display support for W1N | 30 | * Eric Burghard - LED display support for W1N |
| 31 | * Josh Green - Light Sens support | 31 | * Josh Green - Light Sens support |
| 32 | * Thomas Tuttle - His first patch for led support was very helpfull | 32 | * Thomas Tuttle - His first patch for led support was very helpful |
| 33 | * Sam Lin - GPS support | 33 | * Sam Lin - GPS support |
| 34 | */ | 34 | */ |
| 35 | 35 | ||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <linux/input/sparse-keymap.h> | 50 | #include <linux/input/sparse-keymap.h> |
| 51 | #include <linux/rfkill.h> | 51 | #include <linux/rfkill.h> |
| 52 | #include <linux/slab.h> | 52 | #include <linux/slab.h> |
| 53 | #include <linux/dmi.h> | ||
| 53 | #include <acpi/acpi_drivers.h> | 54 | #include <acpi/acpi_drivers.h> |
| 54 | #include <acpi/acpi_bus.h> | 55 | #include <acpi/acpi_bus.h> |
| 55 | 56 | ||
| @@ -157,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " | |||
| 157 | #define METHOD_BRIGHTNESS_SET "SPLV" | 158 | #define METHOD_BRIGHTNESS_SET "SPLV" |
| 158 | #define METHOD_BRIGHTNESS_GET "GPLV" | 159 | #define METHOD_BRIGHTNESS_GET "GPLV" |
| 159 | 160 | ||
| 160 | /* Backlight */ | ||
| 161 | static acpi_handle lcd_switch_handle; | ||
| 162 | static char *lcd_switch_paths[] = { | ||
| 163 | "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ | ||
| 164 | "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ | ||
| 165 | "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ | ||
| 166 | "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ | ||
| 167 | "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ | ||
| 168 | "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ | ||
| 169 | "\\_SB.PCI0.PX40.Q10", /* S1x */ | ||
| 170 | "\\Q10"}; /* A2x, L2D, L3D, M2E */ | ||
| 171 | |||
| 172 | /* Display */ | 161 | /* Display */ |
| 173 | #define METHOD_SWITCH_DISPLAY "SDSP" | 162 | #define METHOD_SWITCH_DISPLAY "SDSP" |
| 174 | 163 | ||
| 175 | static acpi_handle display_get_handle; | ||
| 176 | static char *display_get_paths[] = { | ||
| 177 | /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ | ||
| 178 | "\\_SB.PCI0.P0P1.VGA.GETD", | ||
| 179 | /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ | ||
| 180 | "\\_SB.PCI0.P0P2.VGA.GETD", | ||
| 181 | /* A6V A6Q */ | ||
| 182 | "\\_SB.PCI0.P0P3.VGA.GETD", | ||
| 183 | /* A6T, A6M */ | ||
| 184 | "\\_SB.PCI0.P0PA.VGA.GETD", | ||
| 185 | /* L3C */ | ||
| 186 | "\\_SB.PCI0.PCI1.VGAC.NMAP", | ||
| 187 | /* Z96F */ | ||
| 188 | "\\_SB.PCI0.VGA.GETD", | ||
| 189 | /* A2D */ | ||
| 190 | "\\ACTD", | ||
| 191 | /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ | ||
| 192 | "\\ADVG", | ||
| 193 | /* P30 */ | ||
| 194 | "\\DNXT", | ||
| 195 | /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ | ||
| 196 | "\\INFB", | ||
| 197 | /* A3F A6F A3N A3L M6N W3N W6A */ | ||
| 198 | "\\SSTE"}; | ||
| 199 | |||
| 200 | #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ | 164 | #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ |
| 201 | #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ | 165 | #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ |
| 202 | 166 | ||
| @@ -246,7 +210,6 @@ struct asus_laptop { | |||
| 246 | 210 | ||
| 247 | int wireless_status; | 211 | int wireless_status; |
| 248 | bool have_rsts; | 212 | bool have_rsts; |
| 249 | int lcd_state; | ||
| 250 | 213 | ||
| 251 | struct rfkill *gps_rfkill; | 214 | struct rfkill *gps_rfkill; |
| 252 | 215 | ||
| @@ -559,48 +522,6 @@ error: | |||
| 559 | /* | 522 | /* |
| 560 | * Backlight device | 523 | * Backlight device |
| 561 | */ | 524 | */ |
| 562 | static int asus_lcd_status(struct asus_laptop *asus) | ||
| 563 | { | ||
| 564 | return asus->lcd_state; | ||
| 565 | } | ||
| 566 | |||
| 567 | static int asus_lcd_set(struct asus_laptop *asus, int value) | ||
| 568 | { | ||
| 569 | int lcd = 0; | ||
| 570 | acpi_status status = 0; | ||
| 571 | |||
| 572 | lcd = !!value; | ||
| 573 | |||
| 574 | if (lcd == asus_lcd_status(asus)) | ||
| 575 | return 0; | ||
| 576 | |||
| 577 | if (!lcd_switch_handle) | ||
| 578 | return -ENODEV; | ||
| 579 | |||
| 580 | status = acpi_evaluate_object(lcd_switch_handle, | ||
| 581 | NULL, NULL, NULL); | ||
| 582 | |||
| 583 | if (ACPI_FAILURE(status)) { | ||
| 584 | pr_warning("Error switching LCD\n"); | ||
| 585 | return -ENODEV; | ||
| 586 | } | ||
| 587 | |||
| 588 | asus->lcd_state = lcd; | ||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | static void lcd_blank(struct asus_laptop *asus, int blank) | ||
| 593 | { | ||
| 594 | struct backlight_device *bd = asus->backlight_device; | ||
| 595 | |||
| 596 | asus->lcd_state = (blank == FB_BLANK_UNBLANK); | ||
| 597 | |||
| 598 | if (bd) { | ||
| 599 | bd->props.power = blank; | ||
| 600 | backlight_update_status(bd); | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | static int asus_read_brightness(struct backlight_device *bd) | 525 | static int asus_read_brightness(struct backlight_device *bd) |
| 605 | { | 526 | { |
| 606 | struct asus_laptop *asus = bl_get_data(bd); | 527 | struct asus_laptop *asus = bl_get_data(bd); |
| @@ -628,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value) | |||
| 628 | 549 | ||
| 629 | static int update_bl_status(struct backlight_device *bd) | 550 | static int update_bl_status(struct backlight_device *bd) |
| 630 | { | 551 | { |
| 631 | struct asus_laptop *asus = bl_get_data(bd); | ||
| 632 | int rv; | ||
| 633 | int value = bd->props.brightness; | 552 | int value = bd->props.brightness; |
| 634 | 553 | ||
| 635 | rv = asus_set_brightness(bd, value); | 554 | return asus_set_brightness(bd, value); |
| 636 | if (rv) | ||
| 637 | return rv; | ||
| 638 | |||
| 639 | value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; | ||
| 640 | return asus_lcd_set(asus, value); | ||
| 641 | } | 555 | } |
| 642 | 556 | ||
| 643 | static const struct backlight_ops asusbl_ops = { | 557 | static const struct backlight_ops asusbl_ops = { |
| @@ -661,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus) | |||
| 661 | struct backlight_properties props; | 575 | struct backlight_properties props; |
| 662 | 576 | ||
| 663 | if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || | 577 | if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || |
| 664 | acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || | 578 | acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL)) |
| 665 | !lcd_switch_handle) | ||
| 666 | return 0; | 579 | return 0; |
| 667 | 580 | ||
| 668 | memset(&props, 0, sizeof(struct backlight_properties)); | 581 | memset(&props, 0, sizeof(struct backlight_properties)); |
| @@ -971,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value) | |||
| 971 | return; | 884 | return; |
| 972 | } | 885 | } |
| 973 | 886 | ||
| 974 | static int read_display(struct asus_laptop *asus) | ||
| 975 | { | ||
| 976 | unsigned long long value = 0; | ||
| 977 | acpi_status rv = AE_OK; | ||
| 978 | |||
| 979 | /* | ||
| 980 | * In most of the case, we know how to set the display, but sometime | ||
| 981 | * we can't read it | ||
| 982 | */ | ||
| 983 | if (display_get_handle) { | ||
| 984 | rv = acpi_evaluate_integer(display_get_handle, NULL, | ||
| 985 | NULL, &value); | ||
| 986 | if (ACPI_FAILURE(rv)) | ||
| 987 | pr_warning("Error reading display status\n"); | ||
| 988 | } | ||
| 989 | |||
| 990 | value &= 0x0F; /* needed for some models, shouldn't hurt others */ | ||
| 991 | |||
| 992 | return value; | ||
| 993 | } | ||
| 994 | |||
| 995 | /* | ||
| 996 | * Now, *this* one could be more user-friendly, but so far, no-one has | ||
| 997 | * complained. The significance of bits is the same as in store_disp() | ||
| 998 | */ | ||
| 999 | static ssize_t show_disp(struct device *dev, | ||
| 1000 | struct device_attribute *attr, char *buf) | ||
| 1001 | { | ||
| 1002 | struct asus_laptop *asus = dev_get_drvdata(dev); | ||
| 1003 | |||
| 1004 | if (!display_get_handle) | ||
| 1005 | return -ENODEV; | ||
| 1006 | return sprintf(buf, "%d\n", read_display(asus)); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | /* | 887 | /* |
| 1010 | * Experimental support for display switching. As of now: 1 should activate | 888 | * Experimental support for display switching. As of now: 1 should activate |
| 1011 | * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. | 889 | * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. |
| @@ -1247,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) | |||
| 1247 | struct asus_laptop *asus = acpi_driver_data(device); | 1125 | struct asus_laptop *asus = acpi_driver_data(device); |
| 1248 | u16 count; | 1126 | u16 count; |
| 1249 | 1127 | ||
| 1250 | /* | ||
| 1251 | * We need to tell the backlight device when the backlight power is | ||
| 1252 | * switched | ||
| 1253 | */ | ||
| 1254 | if (event == ATKD_LCD_ON) | ||
| 1255 | lcd_blank(asus, FB_BLANK_UNBLANK); | ||
| 1256 | else if (event == ATKD_LCD_OFF) | ||
| 1257 | lcd_blank(asus, FB_BLANK_POWERDOWN); | ||
| 1258 | |||
| 1259 | /* TODO Find a better way to handle events count. */ | 1128 | /* TODO Find a better way to handle events count. */ |
| 1260 | count = asus->event_count[event % 128]++; | 1129 | count = asus->event_count[event % 128]++; |
| 1261 | acpi_bus_generate_proc_event(asus->device, event, count); | 1130 | acpi_bus_generate_proc_event(asus->device, event, count); |
| @@ -1282,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, | |||
| 1282 | show_bluetooth, store_bluetooth); | 1151 | show_bluetooth, store_bluetooth); |
| 1283 | static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); | 1152 | static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); |
| 1284 | static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); | 1153 | static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); |
| 1285 | static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); | 1154 | static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp); |
| 1286 | static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); | 1155 | static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); |
| 1287 | static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); | 1156 | static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); |
| 1288 | static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); | 1157 | static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); |
| @@ -1393,26 +1262,6 @@ static struct platform_driver platform_driver = { | |||
| 1393 | } | 1262 | } |
| 1394 | }; | 1263 | }; |
| 1395 | 1264 | ||
| 1396 | static int asus_handle_init(char *name, acpi_handle * handle, | ||
| 1397 | char **paths, int num_paths) | ||
| 1398 | { | ||
| 1399 | int i; | ||
| 1400 | acpi_status status; | ||
| 1401 | |||
| 1402 | for (i = 0; i < num_paths; i++) { | ||
| 1403 | status = acpi_get_handle(NULL, paths[i], handle); | ||
| 1404 | if (ACPI_SUCCESS(status)) | ||
| 1405 | return 0; | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | *handle = NULL; | ||
| 1409 | return -ENODEV; | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | #define ASUS_HANDLE_INIT(object) \ | ||
| 1413 | asus_handle_init(#object, &object##_handle, object##_paths, \ | ||
| 1414 | ARRAY_SIZE(object##_paths)) | ||
| 1415 | |||
| 1416 | /* | 1265 | /* |
| 1417 | * This function is used to initialize the context with right values. In this | 1266 | * This function is used to initialize the context with right values. In this |
| 1418 | * method, we can make all the detection we want, and modify the asus_laptop | 1267 | * method, we can make all the detection we want, and modify the asus_laptop |
| @@ -1498,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus) | |||
| 1498 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) | 1347 | if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) |
| 1499 | asus->have_rsts = true; | 1348 | asus->have_rsts = true; |
| 1500 | 1349 | ||
| 1501 | /* Scheduled for removal */ | ||
| 1502 | ASUS_HANDLE_INIT(lcd_switch); | ||
| 1503 | ASUS_HANDLE_INIT(display_get); | ||
| 1504 | |||
| 1505 | kfree(model); | 1350 | kfree(model); |
| 1506 | 1351 | ||
| 1507 | return AE_OK; | 1352 | return AE_OK; |
| @@ -1553,10 +1398,23 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) | |||
| 1553 | asus_als_level(asus, asus->light_level); | 1398 | asus_als_level(asus, asus->light_level); |
| 1554 | } | 1399 | } |
| 1555 | 1400 | ||
| 1556 | asus->lcd_state = 1; /* LCD should be on when the module load */ | ||
| 1557 | return result; | 1401 | return result; |
| 1558 | } | 1402 | } |
| 1559 | 1403 | ||
| 1404 | static void __devinit asus_dmi_check(void) | ||
| 1405 | { | ||
| 1406 | const char *model; | ||
| 1407 | |||
| 1408 | model = dmi_get_system_info(DMI_PRODUCT_NAME); | ||
| 1409 | if (!model) | ||
| 1410 | return; | ||
| 1411 | |||
| 1412 | /* On L1400B WLED control the sound card, don't mess with it ... */ | ||
| 1413 | if (strncmp(model, "L1400B", 6) == 0) { | ||
| 1414 | wlan_status = -1; | ||
| 1415 | } | ||
| 1416 | } | ||
| 1417 | |||
| 1560 | static bool asus_device_present; | 1418 | static bool asus_device_present; |
| 1561 | 1419 | ||
| 1562 | static int __devinit asus_acpi_add(struct acpi_device *device) | 1420 | static int __devinit asus_acpi_add(struct acpi_device *device) |
| @@ -1575,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device) | |||
| 1575 | device->driver_data = asus; | 1433 | device->driver_data = asus; |
| 1576 | asus->device = device; | 1434 | asus->device = device; |
| 1577 | 1435 | ||
| 1436 | asus_dmi_check(); | ||
| 1437 | |||
| 1578 | result = asus_acpi_init(asus); | 1438 | result = asus_acpi_init(asus); |
| 1579 | if (result) | 1439 | if (result) |
| 1580 | goto fail_platform; | 1440 | goto fail_platform; |
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c new file mode 100644 index 000000000000..0580d99b0798 --- /dev/null +++ b/drivers/platform/x86/asus-nb-wmi.c | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | /* | ||
| 2 | * Asus Notebooks WMI hotkey driver | ||
| 3 | * | ||
| 4 | * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 22 | |||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/input.h> | ||
| 27 | #include <linux/input/sparse-keymap.h> | ||
| 28 | |||
| 29 | #include "asus-wmi.h" | ||
| 30 | |||
| 31 | #define ASUS_NB_WMI_FILE "asus-nb-wmi" | ||
| 32 | |||
| 33 | MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>"); | ||
| 34 | MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver"); | ||
| 35 | MODULE_LICENSE("GPL"); | ||
| 36 | |||
| 37 | #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" | ||
| 38 | |||
| 39 | MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); | ||
| 40 | |||
| 41 | static const struct key_entry asus_nb_wmi_keymap[] = { | ||
| 42 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, | ||
| 43 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, | ||
| 44 | { KE_KEY, 0x32, { KEY_MUTE } }, | ||
| 45 | { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */ | ||
| 46 | { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ | ||
| 47 | { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, | ||
| 48 | { KE_KEY, 0x41, { KEY_NEXTSONG } }, | ||
| 49 | { KE_KEY, 0x43, { KEY_STOPCD } }, | ||
| 50 | { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, | ||
| 51 | { KE_KEY, 0x4c, { KEY_MEDIA } }, | ||
| 52 | { KE_KEY, 0x50, { KEY_EMAIL } }, | ||
| 53 | { KE_KEY, 0x51, { KEY_WWW } }, | ||
| 54 | { KE_KEY, 0x55, { KEY_CALC } }, | ||
| 55 | { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ | ||
| 56 | { KE_KEY, 0x5D, { KEY_WLAN } }, | ||
| 57 | { KE_KEY, 0x5E, { KEY_WLAN } }, | ||
| 58 | { KE_KEY, 0x5F, { KEY_WLAN } }, | ||
| 59 | { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, | ||
| 60 | { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, | ||
| 61 | { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, | ||
| 62 | { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, | ||
| 63 | { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, | ||
| 64 | { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, | ||
| 65 | { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, | ||
| 66 | { KE_KEY, 0x82, { KEY_CAMERA } }, | ||
| 67 | { KE_KEY, 0x88, { KEY_RFKILL } }, | ||
| 68 | { KE_KEY, 0x8A, { KEY_PROG1 } }, | ||
| 69 | { KE_KEY, 0x95, { KEY_MEDIA } }, | ||
| 70 | { KE_KEY, 0x99, { KEY_PHONE } }, | ||
| 71 | { KE_KEY, 0xb5, { KEY_CALC } }, | ||
| 72 | { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, | ||
| 73 | { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, | ||
| 74 | { KE_END, 0}, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static struct asus_wmi_driver asus_nb_wmi_driver = { | ||
| 78 | .name = ASUS_NB_WMI_FILE, | ||
| 79 | .owner = THIS_MODULE, | ||
| 80 | .event_guid = ASUS_NB_WMI_EVENT_GUID, | ||
| 81 | .keymap = asus_nb_wmi_keymap, | ||
| 82 | .input_name = "Asus WMI hotkeys", | ||
| 83 | .input_phys = ASUS_NB_WMI_FILE "/input0", | ||
| 84 | }; | ||
| 85 | |||
| 86 | |||
| 87 | static int __init asus_nb_wmi_init(void) | ||
| 88 | { | ||
| 89 | return asus_wmi_register_driver(&asus_nb_wmi_driver); | ||
| 90 | } | ||
| 91 | |||
| 92 | static void __exit asus_nb_wmi_exit(void) | ||
| 93 | { | ||
| 94 | asus_wmi_unregister_driver(&asus_nb_wmi_driver); | ||
| 95 | } | ||
| 96 | |||
| 97 | module_init(asus_nb_wmi_init); | ||
| 98 | module_exit(asus_nb_wmi_exit); | ||
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c new file mode 100644 index 000000000000..efc776cb0c66 --- /dev/null +++ b/drivers/platform/x86/asus-wmi.c | |||
| @@ -0,0 +1,1656 @@ | |||
| 1 | /* | ||
| 2 | * Asus PC WMI hotkey driver | ||
| 3 | * | ||
| 4 | * Copyright(C) 2010 Intel Corporation. | ||
| 5 | * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> | ||
| 6 | * | ||
| 7 | * Portions based on wistron_btns.c: | ||
| 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | ||
| 9 | * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> | ||
| 10 | * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | */ | ||
| 26 | |||
| 27 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 28 | |||
| 29 | #include <linux/kernel.h> | ||
| 30 | #include <linux/module.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/types.h> | ||
| 33 | #include <linux/slab.h> | ||
| 34 | #include <linux/input.h> | ||
| 35 | #include <linux/input/sparse-keymap.h> | ||
| 36 | #include <linux/fb.h> | ||
| 37 | #include <linux/backlight.h> | ||
| 38 | #include <linux/leds.h> | ||
| 39 | #include <linux/rfkill.h> | ||
| 40 | #include <linux/pci.h> | ||
| 41 | #include <linux/pci_hotplug.h> | ||
| 42 | #include <linux/hwmon.h> | ||
| 43 | #include <linux/hwmon-sysfs.h> | ||
| 44 | #include <linux/debugfs.h> | ||
| 45 | #include <linux/seq_file.h> | ||
| 46 | #include <linux/platform_device.h> | ||
| 47 | #include <acpi/acpi_bus.h> | ||
| 48 | #include <acpi/acpi_drivers.h> | ||
| 49 | |||
| 50 | #include "asus-wmi.h" | ||
| 51 | |||
| 52 | MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>, " | ||
| 53 | "Yong Wang <yong.y.wang@intel.com>"); | ||
| 54 | MODULE_DESCRIPTION("Asus Generic WMI Driver"); | ||
| 55 | MODULE_LICENSE("GPL"); | ||
| 56 | |||
| 57 | #define to_platform_driver(drv) \ | ||
| 58 | (container_of((drv), struct platform_driver, driver)) | ||
| 59 | |||
| 60 | #define to_asus_wmi_driver(pdrv) \ | ||
| 61 | (container_of((pdrv), struct asus_wmi_driver, platform_driver)) | ||
| 62 | |||
| 63 | #define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" | ||
| 64 | |||
| 65 | #define NOTIFY_BRNUP_MIN 0x11 | ||
| 66 | #define NOTIFY_BRNUP_MAX 0x1f | ||
| 67 | #define NOTIFY_BRNDOWN_MIN 0x20 | ||
| 68 | #define NOTIFY_BRNDOWN_MAX 0x2e | ||
| 69 | |||
| 70 | /* WMI Methods */ | ||
| 71 | #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ | ||
| 72 | #define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */ | ||
| 73 | #define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */ | ||
| 74 | #define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */ | ||
| 75 | #define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */ | ||
| 76 | #define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */ | ||
| 77 | #define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */ | ||
| 78 | #define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */ | ||
| 79 | #define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */ | ||
| 80 | #define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */ | ||
| 81 | #define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */ | ||
| 82 | #define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */ | ||
| 83 | #define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/ | ||
| 84 | #define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */ | ||
| 85 | #define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */ | ||
| 86 | #define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */ | ||
| 87 | #define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */ | ||
| 88 | #define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */ | ||
| 89 | #define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */ | ||
| 90 | |||
| 91 | #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE | ||
| 92 | |||
| 93 | /* Wireless */ | ||
| 94 | #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 | ||
| 95 | #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 | ||
| 96 | #define ASUS_WMI_DEVID_WLAN 0x00010011 | ||
| 97 | #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 | ||
| 98 | #define ASUS_WMI_DEVID_GPS 0x00010015 | ||
| 99 | #define ASUS_WMI_DEVID_WIMAX 0x00010017 | ||
| 100 | #define ASUS_WMI_DEVID_WWAN3G 0x00010019 | ||
| 101 | #define ASUS_WMI_DEVID_UWB 0x00010021 | ||
| 102 | |||
| 103 | /* Leds */ | ||
| 104 | /* 0x000200XX and 0x000400XX */ | ||
| 105 | |||
| 106 | /* Backlight and Brightness */ | ||
| 107 | #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 | ||
| 108 | #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 | ||
| 109 | #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 | ||
| 110 | #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ | ||
| 111 | |||
| 112 | /* Misc */ | ||
| 113 | #define ASUS_WMI_DEVID_CAMERA 0x00060013 | ||
| 114 | |||
| 115 | /* Storage */ | ||
| 116 | #define ASUS_WMI_DEVID_CARDREADER 0x00080013 | ||
| 117 | |||
| 118 | /* Input */ | ||
| 119 | #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 | ||
| 120 | #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 | ||
| 121 | |||
| 122 | /* Fan, Thermal */ | ||
| 123 | #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 | ||
| 124 | #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 | ||
| 125 | |||
| 126 | /* Power */ | ||
| 127 | #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 | ||
| 128 | |||
| 129 | /* DSTS masks */ | ||
| 130 | #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 | ||
| 131 | #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 | ||
| 132 | #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 | ||
| 133 | #define ASUS_WMI_DSTS_USER_BIT 0x00020000 | ||
| 134 | #define ASUS_WMI_DSTS_BIOS_BIT 0x00040000 | ||
| 135 | #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF | ||
| 136 | #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 | ||
| 137 | |||
| 138 | struct bios_args { | ||
| 139 | u32 arg0; | ||
| 140 | u32 arg1; | ||
| 141 | } __packed; | ||
| 142 | |||
| 143 | /* | ||
| 144 | * <platform>/ - debugfs root directory | ||
| 145 | * dev_id - current dev_id | ||
| 146 | * ctrl_param - current ctrl_param | ||
| 147 | * method_id - current method_id | ||
| 148 | * devs - call DEVS(dev_id, ctrl_param) and print result | ||
| 149 | * dsts - call DSTS(dev_id) and print result | ||
| 150 | * call - call method_id(dev_id, ctrl_param) and print result | ||
| 151 | */ | ||
| 152 | struct asus_wmi_debug { | ||
| 153 | struct dentry *root; | ||
| 154 | u32 method_id; | ||
| 155 | u32 dev_id; | ||
| 156 | u32 ctrl_param; | ||
| 157 | }; | ||
| 158 | |||
| 159 | struct asus_rfkill { | ||
| 160 | struct asus_wmi *asus; | ||
| 161 | struct rfkill *rfkill; | ||
| 162 | u32 dev_id; | ||
| 163 | }; | ||
| 164 | |||
| 165 | struct asus_wmi { | ||
| 166 | int dsts_id; | ||
| 167 | int spec; | ||
| 168 | int sfun; | ||
| 169 | |||
| 170 | struct input_dev *inputdev; | ||
| 171 | struct backlight_device *backlight_device; | ||
| 172 | struct device *hwmon_device; | ||
| 173 | struct platform_device *platform_device; | ||
| 174 | |||
| 175 | struct led_classdev tpd_led; | ||
| 176 | int tpd_led_wk; | ||
| 177 | struct workqueue_struct *led_workqueue; | ||
| 178 | struct work_struct tpd_led_work; | ||
| 179 | |||
| 180 | struct asus_rfkill wlan; | ||
| 181 | struct asus_rfkill bluetooth; | ||
| 182 | struct asus_rfkill wimax; | ||
| 183 | struct asus_rfkill wwan3g; | ||
| 184 | |||
| 185 | struct hotplug_slot *hotplug_slot; | ||
| 186 | struct mutex hotplug_lock; | ||
| 187 | struct mutex wmi_lock; | ||
| 188 | struct workqueue_struct *hotplug_workqueue; | ||
| 189 | struct work_struct hotplug_work; | ||
| 190 | |||
| 191 | struct asus_wmi_debug debug; | ||
| 192 | |||
| 193 | struct asus_wmi_driver *driver; | ||
| 194 | }; | ||
| 195 | |||
| 196 | static int asus_wmi_input_init(struct asus_wmi *asus) | ||
| 197 | { | ||
| 198 | int err; | ||
| 199 | |||
| 200 | asus->inputdev = input_allocate_device(); | ||
| 201 | if (!asus->inputdev) | ||
| 202 | return -ENOMEM; | ||
| 203 | |||
| 204 | asus->inputdev->name = asus->driver->input_phys; | ||
| 205 | asus->inputdev->phys = asus->driver->input_name; | ||
| 206 | asus->inputdev->id.bustype = BUS_HOST; | ||
| 207 | asus->inputdev->dev.parent = &asus->platform_device->dev; | ||
| 208 | |||
| 209 | err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); | ||
| 210 | if (err) | ||
| 211 | goto err_free_dev; | ||
| 212 | |||
| 213 | err = input_register_device(asus->inputdev); | ||
| 214 | if (err) | ||
| 215 | goto err_free_keymap; | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | |||
| 219 | err_free_keymap: | ||
| 220 | sparse_keymap_free(asus->inputdev); | ||
| 221 | err_free_dev: | ||
| 222 | input_free_device(asus->inputdev); | ||
| 223 | return err; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void asus_wmi_input_exit(struct asus_wmi *asus) | ||
| 227 | { | ||
| 228 | if (asus->inputdev) { | ||
| 229 | sparse_keymap_free(asus->inputdev); | ||
| 230 | input_unregister_device(asus->inputdev); | ||
| 231 | } | ||
| 232 | |||
| 233 | asus->inputdev = NULL; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, | ||
| 237 | u32 *retval) | ||
| 238 | { | ||
| 239 | struct bios_args args = { | ||
| 240 | .arg0 = arg0, | ||
| 241 | .arg1 = arg1, | ||
| 242 | }; | ||
| 243 | struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; | ||
| 244 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 245 | acpi_status status; | ||
| 246 | union acpi_object *obj; | ||
| 247 | u32 tmp; | ||
| 248 | |||
| 249 | status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, | ||
| 250 | &input, &output); | ||
| 251 | |||
| 252 | if (ACPI_FAILURE(status)) | ||
| 253 | goto exit; | ||
| 254 | |||
| 255 | obj = (union acpi_object *)output.pointer; | ||
| 256 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
| 257 | tmp = (u32) obj->integer.value; | ||
| 258 | else | ||
| 259 | tmp = 0; | ||
| 260 | |||
| 261 | if (retval) | ||
| 262 | *retval = tmp; | ||
| 263 | |||
| 264 | kfree(obj); | ||
| 265 | |||
| 266 | exit: | ||
| 267 | if (ACPI_FAILURE(status)) | ||
| 268 | return -EIO; | ||
| 269 | |||
| 270 | if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) | ||
| 271 | return -ENODEV; | ||
| 272 | |||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) | ||
| 277 | { | ||
| 278 | return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); | ||
| 279 | } | ||
| 280 | |||
| 281 | static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, | ||
| 282 | u32 *retval) | ||
| 283 | { | ||
| 284 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, | ||
| 285 | ctrl_param, retval); | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Helper for special devices with magic return codes */ | ||
| 289 | static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, | ||
| 290 | u32 dev_id, u32 mask) | ||
| 291 | { | ||
| 292 | u32 retval = 0; | ||
| 293 | int err; | ||
| 294 | |||
| 295 | err = asus_wmi_get_devstate(asus, dev_id, &retval); | ||
| 296 | |||
| 297 | if (err < 0) | ||
| 298 | return err; | ||
| 299 | |||
| 300 | if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) | ||
| 301 | return -ENODEV; | ||
| 302 | |||
| 303 | if (mask == ASUS_WMI_DSTS_STATUS_BIT) { | ||
| 304 | if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT) | ||
| 305 | return -ENODEV; | ||
| 306 | } | ||
| 307 | |||
| 308 | return retval & mask; | ||
| 309 | } | ||
| 310 | |||
| 311 | static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) | ||
| 312 | { | ||
| 313 | return asus_wmi_get_devstate_bits(asus, dev_id, | ||
| 314 | ASUS_WMI_DSTS_STATUS_BIT); | ||
| 315 | } | ||
| 316 | |||
| 317 | /* | ||
| 318 | * LEDs | ||
| 319 | */ | ||
| 320 | /* | ||
| 321 | * These functions actually update the LED's, and are called from a | ||
| 322 | * workqueue. By doing this as separate work rather than when the LED | ||
| 323 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | ||
| 324 | * potentially bad time, such as a timer interrupt. | ||
| 325 | */ | ||
| 326 | static void tpd_led_update(struct work_struct *work) | ||
| 327 | { | ||
| 328 | int ctrl_param; | ||
| 329 | struct asus_wmi *asus; | ||
| 330 | |||
| 331 | asus = container_of(work, struct asus_wmi, tpd_led_work); | ||
| 332 | |||
| 333 | ctrl_param = asus->tpd_led_wk; | ||
| 334 | asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); | ||
| 335 | } | ||
| 336 | |||
| 337 | static void tpd_led_set(struct led_classdev *led_cdev, | ||
| 338 | enum led_brightness value) | ||
| 339 | { | ||
| 340 | struct asus_wmi *asus; | ||
| 341 | |||
| 342 | asus = container_of(led_cdev, struct asus_wmi, tpd_led); | ||
| 343 | |||
| 344 | asus->tpd_led_wk = !!value; | ||
| 345 | queue_work(asus->led_workqueue, &asus->tpd_led_work); | ||
| 346 | } | ||
| 347 | |||
| 348 | static int read_tpd_led_state(struct asus_wmi *asus) | ||
| 349 | { | ||
| 350 | return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); | ||
| 351 | } | ||
| 352 | |||
| 353 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) | ||
| 354 | { | ||
| 355 | struct asus_wmi *asus; | ||
| 356 | |||
| 357 | asus = container_of(led_cdev, struct asus_wmi, tpd_led); | ||
| 358 | |||
| 359 | return read_tpd_led_state(asus); | ||
| 360 | } | ||
| 361 | |||
| 362 | static int asus_wmi_led_init(struct asus_wmi *asus) | ||
| 363 | { | ||
| 364 | int rv; | ||
| 365 | |||
| 366 | if (read_tpd_led_state(asus) < 0) | ||
| 367 | return 0; | ||
| 368 | |||
| 369 | asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); | ||
| 370 | if (!asus->led_workqueue) | ||
| 371 | return -ENOMEM; | ||
| 372 | INIT_WORK(&asus->tpd_led_work, tpd_led_update); | ||
| 373 | |||
| 374 | asus->tpd_led.name = "asus::touchpad"; | ||
| 375 | asus->tpd_led.brightness_set = tpd_led_set; | ||
| 376 | asus->tpd_led.brightness_get = tpd_led_get; | ||
| 377 | asus->tpd_led.max_brightness = 1; | ||
| 378 | |||
| 379 | rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); | ||
| 380 | if (rv) { | ||
| 381 | destroy_workqueue(asus->led_workqueue); | ||
| 382 | return rv; | ||
| 383 | } | ||
| 384 | |||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | static void asus_wmi_led_exit(struct asus_wmi *asus) | ||
| 389 | { | ||
| 390 | if (asus->tpd_led.dev) | ||
| 391 | led_classdev_unregister(&asus->tpd_led); | ||
| 392 | if (asus->led_workqueue) | ||
| 393 | destroy_workqueue(asus->led_workqueue); | ||
| 394 | } | ||
| 395 | |||
| 396 | /* | ||
| 397 | * PCI hotplug (for wlan rfkill) | ||
| 398 | */ | ||
| 399 | static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) | ||
| 400 | { | ||
| 401 | int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
| 402 | |||
| 403 | if (result < 0) | ||
| 404 | return false; | ||
| 405 | return !result; | ||
| 406 | } | ||
| 407 | |||
| 408 | static void asus_rfkill_hotplug(struct asus_wmi *asus) | ||
| 409 | { | ||
| 410 | struct pci_dev *dev; | ||
| 411 | struct pci_bus *bus; | ||
| 412 | bool blocked; | ||
| 413 | bool absent; | ||
| 414 | u32 l; | ||
| 415 | |||
| 416 | mutex_lock(&asus->wmi_lock); | ||
| 417 | blocked = asus_wlan_rfkill_blocked(asus); | ||
| 418 | mutex_unlock(&asus->wmi_lock); | ||
| 419 | |||
| 420 | mutex_lock(&asus->hotplug_lock); | ||
| 421 | |||
| 422 | if (asus->wlan.rfkill) | ||
| 423 | rfkill_set_sw_state(asus->wlan.rfkill, blocked); | ||
| 424 | |||
| 425 | if (asus->hotplug_slot) { | ||
| 426 | bus = pci_find_bus(0, 1); | ||
| 427 | if (!bus) { | ||
| 428 | pr_warning("Unable to find PCI bus 1?\n"); | ||
| 429 | goto out_unlock; | ||
| 430 | } | ||
| 431 | |||
| 432 | if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { | ||
| 433 | pr_err("Unable to read PCI config space?\n"); | ||
| 434 | goto out_unlock; | ||
| 435 | } | ||
| 436 | absent = (l == 0xffffffff); | ||
| 437 | |||
| 438 | if (blocked != absent) { | ||
| 439 | pr_warning("BIOS says wireless lan is %s, " | ||
| 440 | "but the pci device is %s\n", | ||
| 441 | blocked ? "blocked" : "unblocked", | ||
| 442 | absent ? "absent" : "present"); | ||
| 443 | pr_warning("skipped wireless hotplug as probably " | ||
| 444 | "inappropriate for this model\n"); | ||
| 445 | goto out_unlock; | ||
| 446 | } | ||
| 447 | |||
| 448 | if (!blocked) { | ||
| 449 | dev = pci_get_slot(bus, 0); | ||
| 450 | if (dev) { | ||
| 451 | /* Device already present */ | ||
| 452 | pci_dev_put(dev); | ||
| 453 | goto out_unlock; | ||
| 454 | } | ||
| 455 | dev = pci_scan_single_device(bus, 0); | ||
| 456 | if (dev) { | ||
| 457 | pci_bus_assign_resources(bus); | ||
| 458 | if (pci_bus_add_device(dev)) | ||
| 459 | pr_err("Unable to hotplug wifi\n"); | ||
| 460 | } | ||
| 461 | } else { | ||
| 462 | dev = pci_get_slot(bus, 0); | ||
| 463 | if (dev) { | ||
| 464 | pci_remove_bus_device(dev); | ||
| 465 | pci_dev_put(dev); | ||
| 466 | } | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 470 | out_unlock: | ||
| 471 | mutex_unlock(&asus->hotplug_lock); | ||
| 472 | } | ||
| 473 | |||
| 474 | static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data) | ||
| 475 | { | ||
| 476 | struct asus_wmi *asus = data; | ||
| 477 | |||
| 478 | if (event != ACPI_NOTIFY_BUS_CHECK) | ||
| 479 | return; | ||
| 480 | |||
| 481 | /* | ||
| 482 | * We can't call directly asus_rfkill_hotplug because most | ||
| 483 | * of the time WMBC is still being executed and not reetrant. | ||
| 484 | * There is currently no way to tell ACPICA that we want this | ||
| 485 | * method to be serialized, we schedule a asus_rfkill_hotplug | ||
| 486 | * call later, in a safer context. | ||
| 487 | */ | ||
| 488 | queue_work(asus->hotplug_workqueue, &asus->hotplug_work); | ||
| 489 | } | ||
| 490 | |||
| 491 | static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node) | ||
| 492 | { | ||
| 493 | acpi_status status; | ||
| 494 | acpi_handle handle; | ||
| 495 | |||
| 496 | status = acpi_get_handle(NULL, node, &handle); | ||
| 497 | |||
| 498 | if (ACPI_SUCCESS(status)) { | ||
| 499 | status = acpi_install_notify_handler(handle, | ||
| 500 | ACPI_SYSTEM_NOTIFY, | ||
| 501 | asus_rfkill_notify, asus); | ||
| 502 | if (ACPI_FAILURE(status)) | ||
| 503 | pr_warning("Failed to register notify on %s\n", node); | ||
| 504 | } else | ||
| 505 | return -ENODEV; | ||
| 506 | |||
| 507 | return 0; | ||
| 508 | } | ||
| 509 | |||
| 510 | static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) | ||
| 511 | { | ||
| 512 | acpi_status status = AE_OK; | ||
| 513 | acpi_handle handle; | ||
| 514 | |||
| 515 | status = acpi_get_handle(NULL, node, &handle); | ||
| 516 | |||
| 517 | if (ACPI_SUCCESS(status)) { | ||
| 518 | status = acpi_remove_notify_handler(handle, | ||
| 519 | ACPI_SYSTEM_NOTIFY, | ||
| 520 | asus_rfkill_notify); | ||
| 521 | if (ACPI_FAILURE(status)) | ||
| 522 | pr_err("Error removing rfkill notify handler %s\n", | ||
| 523 | node); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, | ||
| 528 | u8 *value) | ||
| 529 | { | ||
| 530 | struct asus_wmi *asus = hotplug_slot->private; | ||
| 531 | int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
| 532 | |||
| 533 | if (result < 0) | ||
| 534 | return result; | ||
| 535 | |||
| 536 | *value = !!result; | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 540 | static void asus_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) | ||
| 541 | { | ||
| 542 | kfree(hotplug_slot->info); | ||
| 543 | kfree(hotplug_slot); | ||
| 544 | } | ||
| 545 | |||
| 546 | static struct hotplug_slot_ops asus_hotplug_slot_ops = { | ||
| 547 | .owner = THIS_MODULE, | ||
| 548 | .get_adapter_status = asus_get_adapter_status, | ||
| 549 | .get_power_status = asus_get_adapter_status, | ||
| 550 | }; | ||
| 551 | |||
| 552 | static void asus_hotplug_work(struct work_struct *work) | ||
| 553 | { | ||
| 554 | struct asus_wmi *asus; | ||
| 555 | |||
| 556 | asus = container_of(work, struct asus_wmi, hotplug_work); | ||
| 557 | asus_rfkill_hotplug(asus); | ||
| 558 | } | ||
| 559 | |||
| 560 | static int asus_setup_pci_hotplug(struct asus_wmi *asus) | ||
| 561 | { | ||
| 562 | int ret = -ENOMEM; | ||
| 563 | struct pci_bus *bus = pci_find_bus(0, 1); | ||
| 564 | |||
| 565 | if (!bus) { | ||
| 566 | pr_err("Unable to find wifi PCI bus\n"); | ||
| 567 | return -ENODEV; | ||
| 568 | } | ||
| 569 | |||
| 570 | asus->hotplug_workqueue = | ||
| 571 | create_singlethread_workqueue("hotplug_workqueue"); | ||
| 572 | if (!asus->hotplug_workqueue) | ||
| 573 | goto error_workqueue; | ||
| 574 | |||
| 575 | INIT_WORK(&asus->hotplug_work, asus_hotplug_work); | ||
| 576 | |||
| 577 | asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | ||
| 578 | if (!asus->hotplug_slot) | ||
| 579 | goto error_slot; | ||
| 580 | |||
| 581 | asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), | ||
| 582 | GFP_KERNEL); | ||
| 583 | if (!asus->hotplug_slot->info) | ||
| 584 | goto error_info; | ||
| 585 | |||
| 586 | asus->hotplug_slot->private = asus; | ||
| 587 | asus->hotplug_slot->release = &asus_cleanup_pci_hotplug; | ||
| 588 | asus->hotplug_slot->ops = &asus_hotplug_slot_ops; | ||
| 589 | asus_get_adapter_status(asus->hotplug_slot, | ||
| 590 | &asus->hotplug_slot->info->adapter_status); | ||
| 591 | |||
| 592 | ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi"); | ||
| 593 | if (ret) { | ||
| 594 | pr_err("Unable to register hotplug slot - %d\n", ret); | ||
| 595 | goto error_register; | ||
| 596 | } | ||
| 597 | |||
| 598 | return 0; | ||
| 599 | |||
| 600 | error_register: | ||
| 601 | kfree(asus->hotplug_slot->info); | ||
| 602 | error_info: | ||
| 603 | kfree(asus->hotplug_slot); | ||
| 604 | asus->hotplug_slot = NULL; | ||
| 605 | error_slot: | ||
| 606 | destroy_workqueue(asus->hotplug_workqueue); | ||
| 607 | error_workqueue: | ||
| 608 | return ret; | ||
| 609 | } | ||
| 610 | |||
| 611 | /* | ||
| 612 | * Rfkill devices | ||
| 613 | */ | ||
| 614 | static int asus_rfkill_set(void *data, bool blocked) | ||
| 615 | { | ||
| 616 | struct asus_rfkill *priv = data; | ||
| 617 | u32 ctrl_param = !blocked; | ||
| 618 | |||
| 619 | return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); | ||
| 620 | } | ||
| 621 | |||
| 622 | static void asus_rfkill_query(struct rfkill *rfkill, void *data) | ||
| 623 | { | ||
| 624 | struct asus_rfkill *priv = data; | ||
| 625 | int result; | ||
| 626 | |||
| 627 | result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); | ||
| 628 | |||
| 629 | if (result < 0) | ||
| 630 | return; | ||
| 631 | |||
| 632 | rfkill_set_sw_state(priv->rfkill, !result); | ||
| 633 | } | ||
| 634 | |||
| 635 | static int asus_rfkill_wlan_set(void *data, bool blocked) | ||
| 636 | { | ||
| 637 | struct asus_rfkill *priv = data; | ||
| 638 | struct asus_wmi *asus = priv->asus; | ||
| 639 | int ret; | ||
| 640 | |||
| 641 | /* | ||
| 642 | * This handler is enabled only if hotplug is enabled. | ||
| 643 | * In this case, the asus_wmi_set_devstate() will | ||
| 644 | * trigger a wmi notification and we need to wait | ||
| 645 | * this call to finish before being able to call | ||
| 646 | * any wmi method | ||
| 647 | */ | ||
| 648 | mutex_lock(&asus->wmi_lock); | ||
| 649 | ret = asus_rfkill_set(data, blocked); | ||
| 650 | mutex_unlock(&asus->wmi_lock); | ||
| 651 | return ret; | ||
| 652 | } | ||
| 653 | |||
| 654 | static const struct rfkill_ops asus_rfkill_wlan_ops = { | ||
| 655 | .set_block = asus_rfkill_wlan_set, | ||
| 656 | .query = asus_rfkill_query, | ||
| 657 | }; | ||
| 658 | |||
| 659 | static const struct rfkill_ops asus_rfkill_ops = { | ||
| 660 | .set_block = asus_rfkill_set, | ||
| 661 | .query = asus_rfkill_query, | ||
| 662 | }; | ||
| 663 | |||
| 664 | static int asus_new_rfkill(struct asus_wmi *asus, | ||
| 665 | struct asus_rfkill *arfkill, | ||
| 666 | const char *name, enum rfkill_type type, int dev_id) | ||
| 667 | { | ||
| 668 | int result = asus_wmi_get_devstate_simple(asus, dev_id); | ||
| 669 | struct rfkill **rfkill = &arfkill->rfkill; | ||
| 670 | |||
| 671 | if (result < 0) | ||
| 672 | return result; | ||
| 673 | |||
| 674 | arfkill->dev_id = dev_id; | ||
| 675 | arfkill->asus = asus; | ||
| 676 | |||
| 677 | if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) | ||
| 678 | *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, | ||
| 679 | &asus_rfkill_wlan_ops, arfkill); | ||
| 680 | else | ||
| 681 | *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, | ||
| 682 | &asus_rfkill_ops, arfkill); | ||
| 683 | |||
| 684 | if (!*rfkill) | ||
| 685 | return -EINVAL; | ||
| 686 | |||
| 687 | rfkill_init_sw_state(*rfkill, !result); | ||
| 688 | result = rfkill_register(*rfkill); | ||
| 689 | if (result) { | ||
| 690 | rfkill_destroy(*rfkill); | ||
| 691 | *rfkill = NULL; | ||
| 692 | return result; | ||
| 693 | } | ||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | static void asus_wmi_rfkill_exit(struct asus_wmi *asus) | ||
| 698 | { | ||
| 699 | asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); | ||
| 700 | asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); | ||
| 701 | asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); | ||
| 702 | if (asus->wlan.rfkill) { | ||
| 703 | rfkill_unregister(asus->wlan.rfkill); | ||
| 704 | rfkill_destroy(asus->wlan.rfkill); | ||
| 705 | asus->wlan.rfkill = NULL; | ||
| 706 | } | ||
| 707 | /* | ||
| 708 | * Refresh pci hotplug in case the rfkill state was changed after | ||
| 709 | * asus_unregister_rfkill_notifier() | ||
| 710 | */ | ||
| 711 | asus_rfkill_hotplug(asus); | ||
| 712 | if (asus->hotplug_slot) | ||
| 713 | pci_hp_deregister(asus->hotplug_slot); | ||
| 714 | if (asus->hotplug_workqueue) | ||
| 715 | destroy_workqueue(asus->hotplug_workqueue); | ||
| 716 | |||
| 717 | if (asus->bluetooth.rfkill) { | ||
| 718 | rfkill_unregister(asus->bluetooth.rfkill); | ||
| 719 | rfkill_destroy(asus->bluetooth.rfkill); | ||
| 720 | asus->bluetooth.rfkill = NULL; | ||
| 721 | } | ||
| 722 | if (asus->wimax.rfkill) { | ||
| 723 | rfkill_unregister(asus->wimax.rfkill); | ||
| 724 | rfkill_destroy(asus->wimax.rfkill); | ||
| 725 | asus->wimax.rfkill = NULL; | ||
| 726 | } | ||
| 727 | if (asus->wwan3g.rfkill) { | ||
| 728 | rfkill_unregister(asus->wwan3g.rfkill); | ||
| 729 | rfkill_destroy(asus->wwan3g.rfkill); | ||
| 730 | asus->wwan3g.rfkill = NULL; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 734 | static int asus_wmi_rfkill_init(struct asus_wmi *asus) | ||
| 735 | { | ||
| 736 | int result = 0; | ||
| 737 | |||
| 738 | mutex_init(&asus->hotplug_lock); | ||
| 739 | mutex_init(&asus->wmi_lock); | ||
| 740 | |||
| 741 | result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan", | ||
| 742 | RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN); | ||
| 743 | |||
| 744 | if (result && result != -ENODEV) | ||
| 745 | goto exit; | ||
| 746 | |||
| 747 | result = asus_new_rfkill(asus, &asus->bluetooth, | ||
| 748 | "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
| 749 | ASUS_WMI_DEVID_BLUETOOTH); | ||
| 750 | |||
| 751 | if (result && result != -ENODEV) | ||
| 752 | goto exit; | ||
| 753 | |||
| 754 | result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax", | ||
| 755 | RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX); | ||
| 756 | |||
| 757 | if (result && result != -ENODEV) | ||
| 758 | goto exit; | ||
| 759 | |||
| 760 | result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g", | ||
| 761 | RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G); | ||
| 762 | |||
| 763 | if (result && result != -ENODEV) | ||
| 764 | goto exit; | ||
| 765 | |||
| 766 | if (!asus->driver->hotplug_wireless) | ||
| 767 | goto exit; | ||
| 768 | |||
| 769 | result = asus_setup_pci_hotplug(asus); | ||
| 770 | /* | ||
| 771 | * If we get -EBUSY then something else is handling the PCI hotplug - | ||
| 772 | * don't fail in this case | ||
| 773 | */ | ||
| 774 | if (result == -EBUSY) | ||
| 775 | result = 0; | ||
| 776 | |||
| 777 | asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); | ||
| 778 | asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); | ||
| 779 | asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); | ||
| 780 | /* | ||
| 781 | * Refresh pci hotplug in case the rfkill state was changed during | ||
| 782 | * setup. | ||
| 783 | */ | ||
| 784 | asus_rfkill_hotplug(asus); | ||
| 785 | |||
| 786 | exit: | ||
| 787 | if (result && result != -ENODEV) | ||
| 788 | asus_wmi_rfkill_exit(asus); | ||
| 789 | |||
| 790 | if (result == -ENODEV) | ||
| 791 | result = 0; | ||
| 792 | |||
| 793 | return result; | ||
| 794 | } | ||
| 795 | |||
| 796 | /* | ||
| 797 | * Hwmon device | ||
| 798 | */ | ||
| 799 | static ssize_t asus_hwmon_pwm1(struct device *dev, | ||
| 800 | struct device_attribute *attr, | ||
| 801 | char *buf) | ||
| 802 | { | ||
| 803 | struct asus_wmi *asus = dev_get_drvdata(dev); | ||
| 804 | u32 value; | ||
| 805 | int err; | ||
| 806 | |||
| 807 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); | ||
| 808 | |||
| 809 | if (err < 0) | ||
| 810 | return err; | ||
| 811 | |||
| 812 | value |= 0xFF; | ||
| 813 | |||
| 814 | if (value == 1) /* Low Speed */ | ||
| 815 | value = 85; | ||
| 816 | else if (value == 2) | ||
| 817 | value = 170; | ||
| 818 | else if (value == 3) | ||
| 819 | value = 255; | ||
| 820 | else if (value != 0) { | ||
| 821 | pr_err("Unknown fan speed %#x", value); | ||
| 822 | value = -1; | ||
| 823 | } | ||
| 824 | |||
| 825 | return sprintf(buf, "%d\n", value); | ||
| 826 | } | ||
| 827 | |||
| 828 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); | ||
| 829 | |||
| 830 | static ssize_t | ||
| 831 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | ||
| 832 | { | ||
| 833 | return sprintf(buf, "asus\n"); | ||
| 834 | } | ||
| 835 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | ||
| 836 | |||
| 837 | static struct attribute *hwmon_attributes[] = { | ||
| 838 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
| 839 | &sensor_dev_attr_name.dev_attr.attr, | ||
| 840 | NULL | ||
| 841 | }; | ||
| 842 | |||
| 843 | static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, | ||
| 844 | struct attribute *attr, int idx) | ||
| 845 | { | ||
| 846 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 847 | struct platform_device *pdev = to_platform_device(dev->parent); | ||
| 848 | struct asus_wmi *asus = platform_get_drvdata(pdev); | ||
| 849 | bool ok = true; | ||
| 850 | int dev_id = -1; | ||
| 851 | u32 value = ASUS_WMI_UNSUPPORTED_METHOD; | ||
| 852 | |||
| 853 | if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) | ||
| 854 | dev_id = ASUS_WMI_DEVID_FAN_CTRL; | ||
| 855 | |||
| 856 | if (dev_id != -1) { | ||
| 857 | int err = asus_wmi_get_devstate(asus, dev_id, &value); | ||
| 858 | |||
| 859 | if (err < 0) | ||
| 860 | return err; | ||
| 861 | } | ||
| 862 | |||
| 863 | if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { | ||
| 864 | /* | ||
| 865 | * We need to find a better way, probably using sfun, | ||
| 866 | * bits or spec ... | ||
| 867 | * Currently we disable it if: | ||
| 868 | * - ASUS_WMI_UNSUPPORTED_METHOD is returned | ||
| 869 | * - reverved bits are non-zero | ||
| 870 | * - sfun and presence bit are not set | ||
| 871 | */ | ||
| 872 | if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 | ||
| 873 | || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) | ||
| 874 | ok = false; | ||
| 875 | } | ||
| 876 | |||
| 877 | return ok ? attr->mode : 0; | ||
| 878 | } | ||
| 879 | |||
| 880 | static struct attribute_group hwmon_attribute_group = { | ||
| 881 | .is_visible = asus_hwmon_sysfs_is_visible, | ||
| 882 | .attrs = hwmon_attributes | ||
| 883 | }; | ||
| 884 | |||
| 885 | static void asus_wmi_hwmon_exit(struct asus_wmi *asus) | ||
| 886 | { | ||
| 887 | struct device *hwmon; | ||
| 888 | |||
| 889 | hwmon = asus->hwmon_device; | ||
| 890 | if (!hwmon) | ||
| 891 | return; | ||
| 892 | sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group); | ||
| 893 | hwmon_device_unregister(hwmon); | ||
| 894 | asus->hwmon_device = NULL; | ||
| 895 | } | ||
| 896 | |||
| 897 | static int asus_wmi_hwmon_init(struct asus_wmi *asus) | ||
| 898 | { | ||
| 899 | struct device *hwmon; | ||
| 900 | int result; | ||
| 901 | |||
| 902 | hwmon = hwmon_device_register(&asus->platform_device->dev); | ||
| 903 | if (IS_ERR(hwmon)) { | ||
| 904 | pr_err("Could not register asus hwmon device\n"); | ||
| 905 | return PTR_ERR(hwmon); | ||
| 906 | } | ||
| 907 | asus->hwmon_device = hwmon; | ||
| 908 | result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); | ||
| 909 | if (result) | ||
| 910 | asus_wmi_hwmon_exit(asus); | ||
| 911 | return result; | ||
| 912 | } | ||
| 913 | |||
| 914 | /* | ||
| 915 | * Backlight | ||
| 916 | */ | ||
| 917 | static int read_backlight_power(struct asus_wmi *asus) | ||
| 918 | { | ||
| 919 | int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); | ||
| 920 | |||
| 921 | if (ret < 0) | ||
| 922 | return ret; | ||
| 923 | |||
| 924 | return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; | ||
| 925 | } | ||
| 926 | |||
| 927 | static int read_brightness_max(struct asus_wmi *asus) | ||
| 928 | { | ||
| 929 | u32 retval; | ||
| 930 | int err; | ||
| 931 | |||
| 932 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); | ||
| 933 | |||
| 934 | if (err < 0) | ||
| 935 | return err; | ||
| 936 | |||
| 937 | retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK; | ||
| 938 | retval >>= 8; | ||
| 939 | |||
| 940 | if (!retval) | ||
| 941 | return -ENODEV; | ||
| 942 | |||
| 943 | return retval; | ||
| 944 | } | ||
| 945 | |||
| 946 | static int read_brightness(struct backlight_device *bd) | ||
| 947 | { | ||
| 948 | struct asus_wmi *asus = bl_get_data(bd); | ||
| 949 | u32 retval; | ||
| 950 | int err; | ||
| 951 | |||
| 952 | err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); | ||
| 953 | |||
| 954 | if (err < 0) | ||
| 955 | return err; | ||
| 956 | |||
| 957 | return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; | ||
| 958 | } | ||
| 959 | |||
| 960 | static int update_bl_status(struct backlight_device *bd) | ||
| 961 | { | ||
| 962 | struct asus_wmi *asus = bl_get_data(bd); | ||
| 963 | u32 ctrl_param; | ||
| 964 | int power, err; | ||
| 965 | |||
| 966 | ctrl_param = bd->props.brightness; | ||
| 967 | |||
| 968 | err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, | ||
| 969 | ctrl_param, NULL); | ||
| 970 | |||
| 971 | if (err < 0) | ||
| 972 | return err; | ||
| 973 | |||
| 974 | power = read_backlight_power(asus); | ||
| 975 | if (power != -ENODEV && bd->props.power != power) { | ||
| 976 | ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); | ||
| 977 | err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, | ||
| 978 | ctrl_param, NULL); | ||
| 979 | } | ||
| 980 | return err; | ||
| 981 | } | ||
| 982 | |||
| 983 | static const struct backlight_ops asus_wmi_bl_ops = { | ||
| 984 | .get_brightness = read_brightness, | ||
| 985 | .update_status = update_bl_status, | ||
| 986 | }; | ||
| 987 | |||
| 988 | static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code) | ||
| 989 | { | ||
| 990 | struct backlight_device *bd = asus->backlight_device; | ||
| 991 | int old = bd->props.brightness; | ||
| 992 | int new = old; | ||
| 993 | |||
| 994 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
| 995 | new = code - NOTIFY_BRNUP_MIN + 1; | ||
| 996 | else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) | ||
| 997 | new = code - NOTIFY_BRNDOWN_MIN; | ||
| 998 | |||
| 999 | bd->props.brightness = new; | ||
| 1000 | backlight_update_status(bd); | ||
| 1001 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); | ||
| 1002 | |||
| 1003 | return old; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | static int asus_wmi_backlight_init(struct asus_wmi *asus) | ||
| 1007 | { | ||
| 1008 | struct backlight_device *bd; | ||
| 1009 | struct backlight_properties props; | ||
| 1010 | int max; | ||
| 1011 | int power; | ||
| 1012 | |||
| 1013 | max = read_brightness_max(asus); | ||
| 1014 | |||
| 1015 | if (max == -ENODEV) | ||
| 1016 | max = 0; | ||
| 1017 | else if (max < 0) | ||
| 1018 | return max; | ||
| 1019 | |||
| 1020 | power = read_backlight_power(asus); | ||
| 1021 | |||
| 1022 | if (power == -ENODEV) | ||
| 1023 | power = FB_BLANK_UNBLANK; | ||
| 1024 | else if (power < 0) | ||
| 1025 | return power; | ||
| 1026 | |||
| 1027 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 1028 | props.max_brightness = max; | ||
| 1029 | bd = backlight_device_register(asus->driver->name, | ||
| 1030 | &asus->platform_device->dev, asus, | ||
| 1031 | &asus_wmi_bl_ops, &props); | ||
| 1032 | if (IS_ERR(bd)) { | ||
| 1033 | pr_err("Could not register backlight device\n"); | ||
| 1034 | return PTR_ERR(bd); | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | asus->backlight_device = bd; | ||
| 1038 | |||
| 1039 | bd->props.brightness = read_brightness(bd); | ||
| 1040 | bd->props.power = power; | ||
| 1041 | backlight_update_status(bd); | ||
| 1042 | |||
| 1043 | return 0; | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | static void asus_wmi_backlight_exit(struct asus_wmi *asus) | ||
| 1047 | { | ||
| 1048 | if (asus->backlight_device) | ||
| 1049 | backlight_device_unregister(asus->backlight_device); | ||
| 1050 | |||
| 1051 | asus->backlight_device = NULL; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | static void asus_wmi_notify(u32 value, void *context) | ||
| 1055 | { | ||
| 1056 | struct asus_wmi *asus = context; | ||
| 1057 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1058 | union acpi_object *obj; | ||
| 1059 | acpi_status status; | ||
| 1060 | int code; | ||
| 1061 | int orig_code; | ||
| 1062 | |||
| 1063 | status = wmi_get_event_data(value, &response); | ||
| 1064 | if (status != AE_OK) { | ||
| 1065 | pr_err("bad event status 0x%x\n", status); | ||
| 1066 | return; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | obj = (union acpi_object *)response.pointer; | ||
| 1070 | |||
| 1071 | if (!obj || obj->type != ACPI_TYPE_INTEGER) | ||
| 1072 | goto exit; | ||
| 1073 | |||
| 1074 | code = obj->integer.value; | ||
| 1075 | orig_code = code; | ||
| 1076 | |||
| 1077 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
| 1078 | code = NOTIFY_BRNUP_MIN; | ||
| 1079 | else if (code >= NOTIFY_BRNDOWN_MIN && | ||
| 1080 | code <= NOTIFY_BRNDOWN_MAX) | ||
| 1081 | code = NOTIFY_BRNDOWN_MIN; | ||
| 1082 | |||
| 1083 | if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { | ||
| 1084 | if (!acpi_video_backlight_support()) | ||
| 1085 | asus_wmi_backlight_notify(asus, orig_code); | ||
| 1086 | } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) | ||
| 1087 | pr_info("Unknown key %x pressed\n", code); | ||
| 1088 | |||
| 1089 | exit: | ||
| 1090 | kfree(obj); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* | ||
| 1094 | * Sys helpers | ||
| 1095 | */ | ||
| 1096 | static int parse_arg(const char *buf, unsigned long count, int *val) | ||
| 1097 | { | ||
| 1098 | if (!count) | ||
| 1099 | return 0; | ||
| 1100 | if (sscanf(buf, "%i", val) != 1) | ||
| 1101 | return -EINVAL; | ||
| 1102 | return count; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, | ||
| 1106 | const char *buf, size_t count) | ||
| 1107 | { | ||
| 1108 | u32 retval; | ||
| 1109 | int rv, err, value; | ||
| 1110 | |||
| 1111 | value = asus_wmi_get_devstate_simple(asus, devid); | ||
| 1112 | if (value == -ENODEV) /* Check device presence */ | ||
| 1113 | return value; | ||
| 1114 | |||
| 1115 | rv = parse_arg(buf, count, &value); | ||
| 1116 | err = asus_wmi_set_devstate(devid, value, &retval); | ||
| 1117 | |||
| 1118 | if (err < 0) | ||
| 1119 | return err; | ||
| 1120 | |||
| 1121 | return rv; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) | ||
| 1125 | { | ||
| 1126 | int value = asus_wmi_get_devstate_simple(asus, devid); | ||
| 1127 | |||
| 1128 | if (value < 0) | ||
| 1129 | return value; | ||
| 1130 | |||
| 1131 | return sprintf(buf, "%d\n", value); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | #define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ | ||
| 1135 | static ssize_t show_##_name(struct device *dev, \ | ||
| 1136 | struct device_attribute *attr, \ | ||
| 1137 | char *buf) \ | ||
| 1138 | { \ | ||
| 1139 | struct asus_wmi *asus = dev_get_drvdata(dev); \ | ||
| 1140 | \ | ||
| 1141 | return show_sys_wmi(asus, _cm, buf); \ | ||
| 1142 | } \ | ||
| 1143 | static ssize_t store_##_name(struct device *dev, \ | ||
| 1144 | struct device_attribute *attr, \ | ||
| 1145 | const char *buf, size_t count) \ | ||
| 1146 | { \ | ||
| 1147 | struct asus_wmi *asus = dev_get_drvdata(dev); \ | ||
| 1148 | \ | ||
| 1149 | return store_sys_wmi(asus, _cm, buf, count); \ | ||
| 1150 | } \ | ||
| 1151 | static struct device_attribute dev_attr_##_name = { \ | ||
| 1152 | .attr = { \ | ||
| 1153 | .name = __stringify(_name), \ | ||
| 1154 | .mode = _mode }, \ | ||
| 1155 | .show = show_##_name, \ | ||
| 1156 | .store = store_##_name, \ | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); | ||
| 1160 | ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); | ||
| 1161 | ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); | ||
| 1162 | |||
| 1163 | static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, | ||
| 1164 | const char *buf, size_t count) | ||
| 1165 | { | ||
| 1166 | int value; | ||
| 1167 | |||
| 1168 | if (!count || sscanf(buf, "%i", &value) != 1) | ||
| 1169 | return -EINVAL; | ||
| 1170 | if (value < 0 || value > 2) | ||
| 1171 | return -EINVAL; | ||
| 1172 | |||
| 1173 | return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); | ||
| 1177 | |||
| 1178 | static struct attribute *platform_attributes[] = { | ||
| 1179 | &dev_attr_cpufv.attr, | ||
| 1180 | &dev_attr_camera.attr, | ||
| 1181 | &dev_attr_cardr.attr, | ||
| 1182 | &dev_attr_touchpad.attr, | ||
| 1183 | NULL | ||
| 1184 | }; | ||
| 1185 | |||
| 1186 | static mode_t asus_sysfs_is_visible(struct kobject *kobj, | ||
| 1187 | struct attribute *attr, int idx) | ||
| 1188 | { | ||
| 1189 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 1190 | struct platform_device *pdev = to_platform_device(dev); | ||
| 1191 | struct asus_wmi *asus = platform_get_drvdata(pdev); | ||
| 1192 | bool ok = true; | ||
| 1193 | int devid = -1; | ||
| 1194 | |||
| 1195 | if (attr == &dev_attr_camera.attr) | ||
| 1196 | devid = ASUS_WMI_DEVID_CAMERA; | ||
| 1197 | else if (attr == &dev_attr_cardr.attr) | ||
| 1198 | devid = ASUS_WMI_DEVID_CARDREADER; | ||
| 1199 | else if (attr == &dev_attr_touchpad.attr) | ||
| 1200 | devid = ASUS_WMI_DEVID_TOUCHPAD; | ||
| 1201 | |||
| 1202 | if (devid != -1) | ||
| 1203 | ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); | ||
| 1204 | |||
| 1205 | return ok ? attr->mode : 0; | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | static struct attribute_group platform_attribute_group = { | ||
| 1209 | .is_visible = asus_sysfs_is_visible, | ||
| 1210 | .attrs = platform_attributes | ||
| 1211 | }; | ||
| 1212 | |||
| 1213 | static void asus_wmi_sysfs_exit(struct platform_device *device) | ||
| 1214 | { | ||
| 1215 | sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | static int asus_wmi_sysfs_init(struct platform_device *device) | ||
| 1219 | { | ||
| 1220 | return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | /* | ||
| 1224 | * Platform device | ||
| 1225 | */ | ||
| 1226 | static int __init asus_wmi_platform_init(struct asus_wmi *asus) | ||
| 1227 | { | ||
| 1228 | int rv; | ||
| 1229 | |||
| 1230 | /* INIT enable hotkeys on some models */ | ||
| 1231 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv)) | ||
| 1232 | pr_info("Initialization: %#x", rv); | ||
| 1233 | |||
| 1234 | /* We don't know yet what to do with this version... */ | ||
| 1235 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { | ||
| 1236 | pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); | ||
| 1237 | asus->spec = rv; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | /* | ||
| 1241 | * The SFUN method probably allows the original driver to get the list | ||
| 1242 | * of features supported by a given model. For now, 0x0100 or 0x0800 | ||
| 1243 | * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. | ||
| 1244 | * The significance of others is yet to be found. | ||
| 1245 | */ | ||
| 1246 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) { | ||
| 1247 | pr_info("SFUN value: %#x", rv); | ||
| 1248 | asus->sfun = rv; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | /* | ||
| 1252 | * Eee PC and Notebooks seems to have different method_id for DSTS, | ||
| 1253 | * but it may also be related to the BIOS's SPEC. | ||
| 1254 | * Note, on most Eeepc, there is no way to check if a method exist | ||
| 1255 | * or note, while on notebooks, they returns 0xFFFFFFFE on failure, | ||
| 1256 | * but once again, SPEC may probably be used for that kind of things. | ||
| 1257 | */ | ||
| 1258 | if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) | ||
| 1259 | asus->dsts_id = ASUS_WMI_METHODID_DSTS; | ||
| 1260 | else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) | ||
| 1261 | asus->dsts_id = ASUS_WMI_METHODID_DSTS2; | ||
| 1262 | |||
| 1263 | if (!asus->dsts_id) { | ||
| 1264 | pr_err("Can't find DSTS"); | ||
| 1265 | return -ENODEV; | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | return asus_wmi_sysfs_init(asus->platform_device); | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | static void asus_wmi_platform_exit(struct asus_wmi *asus) | ||
| 1272 | { | ||
| 1273 | asus_wmi_sysfs_exit(asus->platform_device); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | /* | ||
| 1277 | * debugfs | ||
| 1278 | */ | ||
| 1279 | struct asus_wmi_debugfs_node { | ||
| 1280 | struct asus_wmi *asus; | ||
| 1281 | char *name; | ||
| 1282 | int (*show) (struct seq_file *m, void *data); | ||
| 1283 | }; | ||
| 1284 | |||
| 1285 | static int show_dsts(struct seq_file *m, void *data) | ||
| 1286 | { | ||
| 1287 | struct asus_wmi *asus = m->private; | ||
| 1288 | int err; | ||
| 1289 | u32 retval = -1; | ||
| 1290 | |||
| 1291 | err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); | ||
| 1292 | |||
| 1293 | if (err < 0) | ||
| 1294 | return err; | ||
| 1295 | |||
| 1296 | seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval); | ||
| 1297 | |||
| 1298 | return 0; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | static int show_devs(struct seq_file *m, void *data) | ||
| 1302 | { | ||
| 1303 | struct asus_wmi *asus = m->private; | ||
| 1304 | int err; | ||
| 1305 | u32 retval = -1; | ||
| 1306 | |||
| 1307 | err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, | ||
| 1308 | &retval); | ||
| 1309 | |||
| 1310 | if (err < 0) | ||
| 1311 | return err; | ||
| 1312 | |||
| 1313 | seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id, | ||
| 1314 | asus->debug.ctrl_param, retval); | ||
| 1315 | |||
| 1316 | return 0; | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | static int show_call(struct seq_file *m, void *data) | ||
| 1320 | { | ||
| 1321 | struct asus_wmi *asus = m->private; | ||
| 1322 | struct bios_args args = { | ||
| 1323 | .arg0 = asus->debug.dev_id, | ||
| 1324 | .arg1 = asus->debug.ctrl_param, | ||
| 1325 | }; | ||
| 1326 | struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; | ||
| 1327 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1328 | union acpi_object *obj; | ||
| 1329 | acpi_status status; | ||
| 1330 | |||
| 1331 | status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, | ||
| 1332 | 1, asus->debug.method_id, | ||
| 1333 | &input, &output); | ||
| 1334 | |||
| 1335 | if (ACPI_FAILURE(status)) | ||
| 1336 | return -EIO; | ||
| 1337 | |||
| 1338 | obj = (union acpi_object *)output.pointer; | ||
| 1339 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
| 1340 | seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id, | ||
| 1341 | asus->debug.dev_id, asus->debug.ctrl_param, | ||
| 1342 | (u32) obj->integer.value); | ||
| 1343 | else | ||
| 1344 | seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, | ||
| 1345 | asus->debug.dev_id, asus->debug.ctrl_param, | ||
| 1346 | obj ? obj->type : -1); | ||
| 1347 | |||
| 1348 | kfree(obj); | ||
| 1349 | |||
| 1350 | return 0; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { | ||
| 1354 | {NULL, "devs", show_devs}, | ||
| 1355 | {NULL, "dsts", show_dsts}, | ||
| 1356 | {NULL, "call", show_call}, | ||
| 1357 | }; | ||
| 1358 | |||
| 1359 | static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) | ||
| 1360 | { | ||
| 1361 | struct asus_wmi_debugfs_node *node = inode->i_private; | ||
| 1362 | |||
| 1363 | return single_open(file, node->show, node->asus); | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | static const struct file_operations asus_wmi_debugfs_io_ops = { | ||
| 1367 | .owner = THIS_MODULE, | ||
| 1368 | .open = asus_wmi_debugfs_open, | ||
| 1369 | .read = seq_read, | ||
| 1370 | .llseek = seq_lseek, | ||
| 1371 | .release = single_release, | ||
| 1372 | }; | ||
| 1373 | |||
| 1374 | static void asus_wmi_debugfs_exit(struct asus_wmi *asus) | ||
| 1375 | { | ||
| 1376 | debugfs_remove_recursive(asus->debug.root); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | static int asus_wmi_debugfs_init(struct asus_wmi *asus) | ||
| 1380 | { | ||
| 1381 | struct dentry *dent; | ||
| 1382 | int i; | ||
| 1383 | |||
| 1384 | asus->debug.root = debugfs_create_dir(asus->driver->name, NULL); | ||
| 1385 | if (!asus->debug.root) { | ||
| 1386 | pr_err("failed to create debugfs directory"); | ||
| 1387 | goto error_debugfs; | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, | ||
| 1391 | asus->debug.root, &asus->debug.method_id); | ||
| 1392 | if (!dent) | ||
| 1393 | goto error_debugfs; | ||
| 1394 | |||
| 1395 | dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, | ||
| 1396 | asus->debug.root, &asus->debug.dev_id); | ||
| 1397 | if (!dent) | ||
| 1398 | goto error_debugfs; | ||
| 1399 | |||
| 1400 | dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, | ||
| 1401 | asus->debug.root, &asus->debug.ctrl_param); | ||
| 1402 | if (!dent) | ||
| 1403 | goto error_debugfs; | ||
| 1404 | |||
| 1405 | for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) { | ||
| 1406 | struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i]; | ||
| 1407 | |||
| 1408 | node->asus = asus; | ||
| 1409 | dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, | ||
| 1410 | asus->debug.root, node, | ||
| 1411 | &asus_wmi_debugfs_io_ops); | ||
| 1412 | if (!dent) { | ||
| 1413 | pr_err("failed to create debug file: %s\n", node->name); | ||
| 1414 | goto error_debugfs; | ||
| 1415 | } | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | return 0; | ||
| 1419 | |||
| 1420 | error_debugfs: | ||
| 1421 | asus_wmi_debugfs_exit(asus); | ||
| 1422 | return -ENOMEM; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | /* | ||
| 1426 | * WMI Driver | ||
| 1427 | */ | ||
| 1428 | static int asus_wmi_add(struct platform_device *pdev) | ||
| 1429 | { | ||
| 1430 | struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); | ||
| 1431 | struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); | ||
| 1432 | struct asus_wmi *asus; | ||
| 1433 | acpi_status status; | ||
| 1434 | int err; | ||
| 1435 | |||
| 1436 | asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL); | ||
| 1437 | if (!asus) | ||
| 1438 | return -ENOMEM; | ||
| 1439 | |||
| 1440 | asus->driver = wdrv; | ||
| 1441 | asus->platform_device = pdev; | ||
| 1442 | wdrv->platform_device = pdev; | ||
| 1443 | platform_set_drvdata(asus->platform_device, asus); | ||
| 1444 | |||
| 1445 | if (wdrv->quirks) | ||
| 1446 | wdrv->quirks(asus->driver); | ||
| 1447 | |||
| 1448 | err = asus_wmi_platform_init(asus); | ||
| 1449 | if (err) | ||
| 1450 | goto fail_platform; | ||
| 1451 | |||
| 1452 | err = asus_wmi_input_init(asus); | ||
| 1453 | if (err) | ||
| 1454 | goto fail_input; | ||
| 1455 | |||
| 1456 | err = asus_wmi_hwmon_init(asus); | ||
| 1457 | if (err) | ||
| 1458 | goto fail_hwmon; | ||
| 1459 | |||
| 1460 | err = asus_wmi_led_init(asus); | ||
| 1461 | if (err) | ||
| 1462 | goto fail_leds; | ||
| 1463 | |||
| 1464 | err = asus_wmi_rfkill_init(asus); | ||
| 1465 | if (err) | ||
| 1466 | goto fail_rfkill; | ||
| 1467 | |||
| 1468 | if (!acpi_video_backlight_support()) { | ||
| 1469 | err = asus_wmi_backlight_init(asus); | ||
| 1470 | if (err && err != -ENODEV) | ||
| 1471 | goto fail_backlight; | ||
| 1472 | } else | ||
| 1473 | pr_info("Backlight controlled by ACPI video driver\n"); | ||
| 1474 | |||
| 1475 | status = wmi_install_notify_handler(asus->driver->event_guid, | ||
| 1476 | asus_wmi_notify, asus); | ||
| 1477 | if (ACPI_FAILURE(status)) { | ||
| 1478 | pr_err("Unable to register notify handler - %d\n", status); | ||
| 1479 | err = -ENODEV; | ||
| 1480 | goto fail_wmi_handler; | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | err = asus_wmi_debugfs_init(asus); | ||
| 1484 | if (err) | ||
| 1485 | goto fail_debugfs; | ||
| 1486 | |||
| 1487 | return 0; | ||
| 1488 | |||
| 1489 | fail_debugfs: | ||
| 1490 | wmi_remove_notify_handler(asus->driver->event_guid); | ||
| 1491 | fail_wmi_handler: | ||
| 1492 | asus_wmi_backlight_exit(asus); | ||
| 1493 | fail_backlight: | ||
| 1494 | asus_wmi_rfkill_exit(asus); | ||
| 1495 | fail_rfkill: | ||
| 1496 | asus_wmi_led_exit(asus); | ||
| 1497 | fail_leds: | ||
| 1498 | asus_wmi_hwmon_exit(asus); | ||
| 1499 | fail_hwmon: | ||
| 1500 | asus_wmi_input_exit(asus); | ||
| 1501 | fail_input: | ||
| 1502 | asus_wmi_platform_exit(asus); | ||
| 1503 | fail_platform: | ||
| 1504 | kfree(asus); | ||
| 1505 | return err; | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | static int asus_wmi_remove(struct platform_device *device) | ||
| 1509 | { | ||
| 1510 | struct asus_wmi *asus; | ||
| 1511 | |||
| 1512 | asus = platform_get_drvdata(device); | ||
| 1513 | wmi_remove_notify_handler(asus->driver->event_guid); | ||
| 1514 | asus_wmi_backlight_exit(asus); | ||
| 1515 | asus_wmi_input_exit(asus); | ||
| 1516 | asus_wmi_hwmon_exit(asus); | ||
| 1517 | asus_wmi_led_exit(asus); | ||
| 1518 | asus_wmi_rfkill_exit(asus); | ||
| 1519 | asus_wmi_debugfs_exit(asus); | ||
| 1520 | asus_wmi_platform_exit(asus); | ||
| 1521 | |||
| 1522 | kfree(asus); | ||
| 1523 | return 0; | ||
| 1524 | } | ||
| 1525 | |||
| 1526 | /* | ||
| 1527 | * Platform driver - hibernate/resume callbacks | ||
| 1528 | */ | ||
| 1529 | static int asus_hotk_thaw(struct device *device) | ||
| 1530 | { | ||
| 1531 | struct asus_wmi *asus = dev_get_drvdata(device); | ||
| 1532 | |||
| 1533 | if (asus->wlan.rfkill) { | ||
| 1534 | bool wlan; | ||
| 1535 | |||
| 1536 | /* | ||
| 1537 | * Work around bios bug - acpi _PTS turns off the wireless led | ||
| 1538 | * during suspend. Normally it restores it on resume, but | ||
| 1539 | * we should kick it ourselves in case hibernation is aborted. | ||
| 1540 | */ | ||
| 1541 | wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); | ||
| 1542 | asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | return 0; | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | static int asus_hotk_restore(struct device *device) | ||
| 1549 | { | ||
| 1550 | struct asus_wmi *asus = dev_get_drvdata(device); | ||
| 1551 | int bl; | ||
| 1552 | |||
| 1553 | /* Refresh both wlan rfkill state and pci hotplug */ | ||
| 1554 | if (asus->wlan.rfkill) | ||
| 1555 | asus_rfkill_hotplug(asus); | ||
| 1556 | |||
| 1557 | if (asus->bluetooth.rfkill) { | ||
| 1558 | bl = !asus_wmi_get_devstate_simple(asus, | ||
| 1559 | ASUS_WMI_DEVID_BLUETOOTH); | ||
| 1560 | rfkill_set_sw_state(asus->bluetooth.rfkill, bl); | ||
| 1561 | } | ||
| 1562 | if (asus->wimax.rfkill) { | ||
| 1563 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); | ||
| 1564 | rfkill_set_sw_state(asus->wimax.rfkill, bl); | ||
| 1565 | } | ||
| 1566 | if (asus->wwan3g.rfkill) { | ||
| 1567 | bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); | ||
| 1568 | rfkill_set_sw_state(asus->wwan3g.rfkill, bl); | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | return 0; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | static const struct dev_pm_ops asus_pm_ops = { | ||
| 1575 | .thaw = asus_hotk_thaw, | ||
| 1576 | .restore = asus_hotk_restore, | ||
| 1577 | }; | ||
| 1578 | |||
| 1579 | static int asus_wmi_probe(struct platform_device *pdev) | ||
| 1580 | { | ||
| 1581 | struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); | ||
| 1582 | struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); | ||
| 1583 | int ret; | ||
| 1584 | |||
| 1585 | if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { | ||
| 1586 | pr_warning("Management GUID not found\n"); | ||
| 1587 | return -ENODEV; | ||
| 1588 | } | ||
| 1589 | |||
| 1590 | if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) { | ||
| 1591 | pr_warning("Event GUID not found\n"); | ||
| 1592 | return -ENODEV; | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | if (wdrv->probe) { | ||
| 1596 | ret = wdrv->probe(pdev); | ||
| 1597 | if (ret) | ||
| 1598 | return ret; | ||
| 1599 | } | ||
| 1600 | |||
| 1601 | return asus_wmi_add(pdev); | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | static bool used; | ||
| 1605 | |||
| 1606 | int asus_wmi_register_driver(struct asus_wmi_driver *driver) | ||
| 1607 | { | ||
| 1608 | struct platform_driver *platform_driver; | ||
| 1609 | struct platform_device *platform_device; | ||
| 1610 | |||
| 1611 | if (used) | ||
| 1612 | return -EBUSY; | ||
| 1613 | |||
| 1614 | platform_driver = &driver->platform_driver; | ||
| 1615 | platform_driver->remove = asus_wmi_remove; | ||
| 1616 | platform_driver->driver.owner = driver->owner; | ||
| 1617 | platform_driver->driver.name = driver->name; | ||
| 1618 | platform_driver->driver.pm = &asus_pm_ops; | ||
| 1619 | |||
| 1620 | platform_device = platform_create_bundle(platform_driver, | ||
| 1621 | asus_wmi_probe, | ||
| 1622 | NULL, 0, NULL, 0); | ||
| 1623 | if (IS_ERR(platform_device)) | ||
| 1624 | return PTR_ERR(platform_device); | ||
| 1625 | |||
| 1626 | used = true; | ||
| 1627 | return 0; | ||
| 1628 | } | ||
| 1629 | EXPORT_SYMBOL_GPL(asus_wmi_register_driver); | ||
| 1630 | |||
| 1631 | void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) | ||
| 1632 | { | ||
| 1633 | platform_device_unregister(driver->platform_device); | ||
| 1634 | platform_driver_unregister(&driver->platform_driver); | ||
| 1635 | used = false; | ||
| 1636 | } | ||
| 1637 | EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); | ||
| 1638 | |||
| 1639 | static int __init asus_wmi_init(void) | ||
| 1640 | { | ||
| 1641 | if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { | ||
| 1642 | pr_info("Asus Management GUID not found"); | ||
| 1643 | return -ENODEV; | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | pr_info("ASUS WMI generic driver loaded"); | ||
| 1647 | return 0; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | static void __exit asus_wmi_exit(void) | ||
| 1651 | { | ||
| 1652 | pr_info("ASUS WMI generic driver unloaded"); | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | module_init(asus_wmi_init); | ||
| 1656 | module_exit(asus_wmi_exit); | ||
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h new file mode 100644 index 000000000000..c044522c8766 --- /dev/null +++ b/drivers/platform/x86/asus-wmi.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Asus PC WMI hotkey driver | ||
| 3 | * | ||
| 4 | * Copyright(C) 2010 Intel Corporation. | ||
| 5 | * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> | ||
| 6 | * | ||
| 7 | * Portions based on wistron_btns.c: | ||
| 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | ||
| 9 | * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> | ||
| 10 | * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _ASUS_WMI_H_ | ||
| 28 | #define _ASUS_WMI_H_ | ||
| 29 | |||
| 30 | #include <linux/platform_device.h> | ||
| 31 | |||
| 32 | struct module; | ||
| 33 | struct key_entry; | ||
| 34 | struct asus_wmi; | ||
| 35 | |||
| 36 | struct asus_wmi_driver { | ||
| 37 | bool hotplug_wireless; | ||
| 38 | |||
| 39 | const char *name; | ||
| 40 | struct module *owner; | ||
| 41 | |||
| 42 | const char *event_guid; | ||
| 43 | |||
| 44 | const struct key_entry *keymap; | ||
| 45 | const char *input_name; | ||
| 46 | const char *input_phys; | ||
| 47 | |||
| 48 | int (*probe) (struct platform_device *device); | ||
| 49 | void (*quirks) (struct asus_wmi_driver *driver); | ||
| 50 | |||
| 51 | struct platform_driver platform_driver; | ||
| 52 | struct platform_device *platform_device; | ||
| 53 | }; | ||
| 54 | |||
| 55 | int asus_wmi_register_driver(struct asus_wmi_driver *driver); | ||
| 56 | void asus_wmi_unregister_driver(struct asus_wmi_driver *driver); | ||
| 57 | |||
| 58 | #endif /* !_ASUS_WMI_H_ */ | ||
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index eb95878fa583..c16a27641ced 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c | |||
| @@ -201,7 +201,7 @@ static bool extra_features; | |||
| 201 | * into 0x4F and read a few bytes from the output, like so: | 201 | * into 0x4F and read a few bytes from the output, like so: |
| 202 | * u8 writeData = 0x33; | 202 | * u8 writeData = 0x33; |
| 203 | * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); | 203 | * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); |
| 204 | * That address is labled "fan1 table information" in the service manual. | 204 | * That address is labelled "fan1 table information" in the service manual. |
| 205 | * It should be clear which value in 'buffer' changes). This seems to be | 205 | * It should be clear which value in 'buffer' changes). This seems to be |
| 206 | * related to fan speed. It isn't a proper 'realtime' fan speed value | 206 | * related to fan speed. It isn't a proper 'realtime' fan speed value |
| 207 | * though, because physically stopping or speeding up the fan doesn't | 207 | * though, because physically stopping or speeding up the fan doesn't |
| @@ -275,7 +275,7 @@ static int set_backlight_level(int level) | |||
| 275 | 275 | ||
| 276 | ec_write(BACKLIGHT_LEVEL_ADDR, level); | 276 | ec_write(BACKLIGHT_LEVEL_ADDR, level); |
| 277 | 277 | ||
| 278 | return 1; | 278 | return 0; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | static int get_backlight_level(void) | 281 | static int get_backlight_level(void) |
| @@ -763,7 +763,7 @@ static int dmi_check_cb(const struct dmi_system_id *id) | |||
| 763 | printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", | 763 | printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", |
| 764 | id->ident); | 764 | id->ident); |
| 765 | extra_features = false; | 765 | extra_features = false; |
| 766 | return 0; | 766 | return 1; |
| 767 | } | 767 | } |
| 768 | 768 | ||
| 769 | static int dmi_check_cb_extra(const struct dmi_system_id *id) | 769 | static int dmi_check_cb_extra(const struct dmi_system_id *id) |
| @@ -772,7 +772,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id) | |||
| 772 | "enabling extra features\n", | 772 | "enabling extra features\n", |
| 773 | id->ident); | 773 | id->ident); |
| 774 | extra_features = true; | 774 | extra_features = true; |
| 775 | return 0; | 775 | return 1; |
| 776 | } | 776 | } |
| 777 | 777 | ||
| 778 | static struct dmi_system_id __initdata compal_dmi_table[] = { | 778 | static struct dmi_system_id __initdata compal_dmi_table[] = { |
diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c new file mode 100644 index 000000000000..0ed84573ae1f --- /dev/null +++ b/drivers/platform/x86/dell-wmi-aio.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* | ||
| 2 | * WMI hotkeys support for Dell All-In-One series | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | */ | ||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/types.h> | ||
| 24 | #include <linux/input.h> | ||
| 25 | #include <linux/input/sparse-keymap.h> | ||
| 26 | #include <acpi/acpi_drivers.h> | ||
| 27 | #include <linux/acpi.h> | ||
| 28 | #include <linux/string.h> | ||
| 29 | |||
| 30 | MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series"); | ||
| 31 | MODULE_LICENSE("GPL"); | ||
| 32 | |||
| 33 | #define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4" | ||
| 34 | #define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8" | ||
| 35 | |||
| 36 | static const char *dell_wmi_aio_guids[] = { | ||
| 37 | EVENT_GUID1, | ||
| 38 | EVENT_GUID2, | ||
| 39 | NULL | ||
| 40 | }; | ||
| 41 | |||
| 42 | MODULE_ALIAS("wmi:"EVENT_GUID1); | ||
| 43 | MODULE_ALIAS("wmi:"EVENT_GUID2); | ||
| 44 | |||
| 45 | static const struct key_entry dell_wmi_aio_keymap[] = { | ||
| 46 | { KE_KEY, 0xc0, { KEY_VOLUMEUP } }, | ||
| 47 | { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } }, | ||
| 48 | { KE_END, 0 } | ||
| 49 | }; | ||
| 50 | |||
| 51 | static struct input_dev *dell_wmi_aio_input_dev; | ||
| 52 | |||
| 53 | static void dell_wmi_aio_notify(u32 value, void *context) | ||
| 54 | { | ||
| 55 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 56 | union acpi_object *obj; | ||
| 57 | acpi_status status; | ||
| 58 | |||
| 59 | status = wmi_get_event_data(value, &response); | ||
| 60 | if (status != AE_OK) { | ||
| 61 | pr_info("bad event status 0x%x\n", status); | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | |||
| 65 | obj = (union acpi_object *)response.pointer; | ||
| 66 | if (obj) { | ||
| 67 | unsigned int scancode; | ||
| 68 | |||
| 69 | switch (obj->type) { | ||
| 70 | case ACPI_TYPE_INTEGER: | ||
| 71 | /* Most All-In-One correctly return integer scancode */ | ||
| 72 | scancode = obj->integer.value; | ||
| 73 | sparse_keymap_report_event(dell_wmi_aio_input_dev, | ||
| 74 | scancode, 1, true); | ||
| 75 | break; | ||
| 76 | case ACPI_TYPE_BUFFER: | ||
| 77 | /* Broken machines return the scancode in a buffer */ | ||
| 78 | if (obj->buffer.pointer && obj->buffer.length > 0) { | ||
| 79 | scancode = obj->buffer.pointer[0]; | ||
| 80 | sparse_keymap_report_event( | ||
| 81 | dell_wmi_aio_input_dev, | ||
| 82 | scancode, 1, true); | ||
| 83 | } | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | kfree(obj); | ||
| 88 | } | ||
| 89 | |||
| 90 | static int __init dell_wmi_aio_input_setup(void) | ||
| 91 | { | ||
| 92 | int err; | ||
| 93 | |||
| 94 | dell_wmi_aio_input_dev = input_allocate_device(); | ||
| 95 | |||
| 96 | if (!dell_wmi_aio_input_dev) | ||
| 97 | return -ENOMEM; | ||
| 98 | |||
| 99 | dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys"; | ||
| 100 | dell_wmi_aio_input_dev->phys = "wmi/input0"; | ||
| 101 | dell_wmi_aio_input_dev->id.bustype = BUS_HOST; | ||
| 102 | |||
| 103 | err = sparse_keymap_setup(dell_wmi_aio_input_dev, | ||
| 104 | dell_wmi_aio_keymap, NULL); | ||
| 105 | if (err) { | ||
| 106 | pr_err("Unable to setup input device keymap\n"); | ||
| 107 | goto err_free_dev; | ||
| 108 | } | ||
| 109 | err = input_register_device(dell_wmi_aio_input_dev); | ||
| 110 | if (err) { | ||
| 111 | pr_info("Unable to register input device\n"); | ||
| 112 | goto err_free_keymap; | ||
| 113 | } | ||
| 114 | return 0; | ||
| 115 | |||
| 116 | err_free_keymap: | ||
| 117 | sparse_keymap_free(dell_wmi_aio_input_dev); | ||
| 118 | err_free_dev: | ||
| 119 | input_free_device(dell_wmi_aio_input_dev); | ||
| 120 | return err; | ||
| 121 | } | ||
| 122 | |||
| 123 | static const char *dell_wmi_aio_find(void) | ||
| 124 | { | ||
| 125 | int i; | ||
| 126 | |||
| 127 | for (i = 0; dell_wmi_aio_guids[i] != NULL; i++) | ||
| 128 | if (wmi_has_guid(dell_wmi_aio_guids[i])) | ||
| 129 | return dell_wmi_aio_guids[i]; | ||
| 130 | |||
| 131 | return NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int __init dell_wmi_aio_init(void) | ||
| 135 | { | ||
| 136 | int err; | ||
| 137 | const char *guid; | ||
| 138 | |||
| 139 | guid = dell_wmi_aio_find(); | ||
| 140 | if (!guid) { | ||
| 141 | pr_warning("No known WMI GUID found\n"); | ||
| 142 | return -ENXIO; | ||
| 143 | } | ||
| 144 | |||
| 145 | err = dell_wmi_aio_input_setup(); | ||
| 146 | if (err) | ||
| 147 | return err; | ||
| 148 | |||
| 149 | err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL); | ||
| 150 | if (err) { | ||
| 151 | pr_err("Unable to register notify handler - %d\n", err); | ||
| 152 | sparse_keymap_free(dell_wmi_aio_input_dev); | ||
| 153 | input_unregister_device(dell_wmi_aio_input_dev); | ||
| 154 | return err; | ||
| 155 | } | ||
| 156 | |||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | static void __exit dell_wmi_aio_exit(void) | ||
| 161 | { | ||
| 162 | const char *guid; | ||
| 163 | |||
| 164 | guid = dell_wmi_aio_find(); | ||
| 165 | wmi_remove_notify_handler(guid); | ||
| 166 | sparse_keymap_free(dell_wmi_aio_input_dev); | ||
| 167 | input_unregister_device(dell_wmi_aio_input_dev); | ||
| 168 | } | ||
| 169 | |||
| 170 | module_init(dell_wmi_aio_init); | ||
| 171 | module_exit(dell_wmi_aio_exit); | ||
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6605beac0d0e..5f2dd386152b 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
| @@ -1322,7 +1322,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) | |||
| 1322 | { | 1322 | { |
| 1323 | int dummy; | 1323 | int dummy; |
| 1324 | 1324 | ||
| 1325 | /* Some BIOSes do not report cm although it is avaliable. | 1325 | /* Some BIOSes do not report cm although it is available. |
| 1326 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | 1326 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ |
| 1327 | if (!(eeepc->cm_supported & (1 << cm)) | 1327 | if (!(eeepc->cm_supported & (1 << cm)) |
| 1328 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { | 1328 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { |
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 4d38f98aa976..0ddc434fb93b 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Eee PC WMI hotkey driver | 2 | * Eee PC WMI hotkey driver |
| 3 | * | 3 | * |
| 4 | * Copyright(C) 2010 Intel Corporation. | 4 | * Copyright(C) 2010 Intel Corporation. |
| 5 | * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> | 5 | * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> |
| 6 | * | 6 | * |
| 7 | * Portions based on wistron_btns.c: | 7 | * Portions based on wistron_btns.c: |
| 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> |
| @@ -29,841 +29,57 @@ | |||
| 29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 32 | #include <linux/types.h> | ||
| 33 | #include <linux/slab.h> | ||
| 34 | #include <linux/input.h> | 32 | #include <linux/input.h> |
| 35 | #include <linux/input/sparse-keymap.h> | 33 | #include <linux/input/sparse-keymap.h> |
| 36 | #include <linux/fb.h> | 34 | #include <linux/dmi.h> |
| 37 | #include <linux/backlight.h> | ||
| 38 | #include <linux/leds.h> | ||
| 39 | #include <linux/rfkill.h> | ||
| 40 | #include <linux/debugfs.h> | ||
| 41 | #include <linux/seq_file.h> | ||
| 42 | #include <linux/platform_device.h> | ||
| 43 | #include <acpi/acpi_bus.h> | 35 | #include <acpi/acpi_bus.h> |
| 44 | #include <acpi/acpi_drivers.h> | 36 | |
| 37 | #include "asus-wmi.h" | ||
| 45 | 38 | ||
| 46 | #define EEEPC_WMI_FILE "eeepc-wmi" | 39 | #define EEEPC_WMI_FILE "eeepc-wmi" |
| 47 | 40 | ||
| 48 | MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); | 41 | MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>"); |
| 49 | MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); | 42 | MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); |
| 50 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
| 51 | 44 | ||
| 52 | #define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ | 45 | #define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ |
| 53 | 46 | ||
| 54 | #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" | 47 | #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" |
| 55 | #define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" | ||
| 56 | 48 | ||
| 57 | MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); | 49 | MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); |
| 58 | MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); | ||
| 59 | |||
| 60 | #define NOTIFY_BRNUP_MIN 0x11 | ||
| 61 | #define NOTIFY_BRNUP_MAX 0x1f | ||
| 62 | #define NOTIFY_BRNDOWN_MIN 0x20 | ||
| 63 | #define NOTIFY_BRNDOWN_MAX 0x2e | ||
| 64 | 50 | ||
| 65 | #define EEEPC_WMI_METHODID_DEVS 0x53564544 | 51 | static bool hotplug_wireless; |
| 66 | #define EEEPC_WMI_METHODID_DSTS 0x53544344 | ||
| 67 | #define EEEPC_WMI_METHODID_CFVS 0x53564643 | ||
| 68 | 52 | ||
| 69 | #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 | 53 | module_param(hotplug_wireless, bool, 0444); |
| 70 | #define EEEPC_WMI_DEVID_TPDLED 0x00100011 | 54 | MODULE_PARM_DESC(hotplug_wireless, |
| 71 | #define EEEPC_WMI_DEVID_WLAN 0x00010011 | 55 | "Enable hotplug for wireless device. " |
| 72 | #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 | 56 | "If your laptop needs that, please report to " |
| 73 | #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 | 57 | "acpi4asus-user@lists.sourceforge.net."); |
| 74 | 58 | ||
| 75 | static const struct key_entry eeepc_wmi_keymap[] = { | 59 | static const struct key_entry eeepc_wmi_keymap[] = { |
| 76 | /* Sleep already handled via generic ACPI code */ | 60 | /* Sleep already handled via generic ACPI code */ |
| 77 | { KE_KEY, 0x5d, { KEY_WLAN } }, | ||
| 78 | { KE_KEY, 0x32, { KEY_MUTE } }, | ||
| 79 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, | ||
| 80 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, | 61 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, |
| 81 | { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, | 62 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, |
| 82 | { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, | 63 | { KE_KEY, 0x32, { KEY_MUTE } }, |
| 64 | { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ | ||
| 65 | { KE_KEY, 0x5d, { KEY_WLAN } }, | ||
| 66 | { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */ | ||
| 67 | { KE_KEY, 0x82, { KEY_CAMERA } }, | ||
| 68 | { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, | ||
| 69 | { KE_KEY, 0x88, { KEY_WLAN } }, | ||
| 83 | { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, | 70 | { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, |
| 84 | { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ | 71 | { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ |
| 85 | { KE_KEY, 0xe1, { KEY_F14 } }, | 72 | { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ |
| 86 | { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, | 73 | { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, |
| 87 | { KE_KEY, 0xe0, { KEY_PROG1 } }, | 74 | { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, |
| 88 | { KE_KEY, 0x5c, { KEY_F15 } }, | 75 | { KE_KEY, 0xec, { KEY_CAMERA_UP } }, |
| 76 | { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, | ||
| 77 | { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, | ||
| 78 | { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, | ||
| 89 | { KE_END, 0}, | 79 | { KE_END, 0}, |
| 90 | }; | 80 | }; |
| 91 | 81 | ||
| 92 | struct bios_args { | 82 | static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level, |
| 93 | u32 dev_id; | ||
| 94 | u32 ctrl_param; | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* | ||
| 98 | * eeepc-wmi/ - debugfs root directory | ||
| 99 | * dev_id - current dev_id | ||
| 100 | * ctrl_param - current ctrl_param | ||
| 101 | * devs - call DEVS(dev_id, ctrl_param) and print result | ||
| 102 | * dsts - call DSTS(dev_id) and print result | ||
| 103 | */ | ||
| 104 | struct eeepc_wmi_debug { | ||
| 105 | struct dentry *root; | ||
| 106 | u32 dev_id; | ||
| 107 | u32 ctrl_param; | ||
| 108 | }; | ||
| 109 | |||
| 110 | struct eeepc_wmi { | ||
| 111 | struct input_dev *inputdev; | ||
| 112 | struct backlight_device *backlight_device; | ||
| 113 | struct platform_device *platform_device; | ||
| 114 | |||
| 115 | struct led_classdev tpd_led; | ||
| 116 | int tpd_led_wk; | ||
| 117 | struct workqueue_struct *led_workqueue; | ||
| 118 | struct work_struct tpd_led_work; | ||
| 119 | |||
| 120 | struct rfkill *wlan_rfkill; | ||
| 121 | struct rfkill *bluetooth_rfkill; | ||
| 122 | struct rfkill *wwan3g_rfkill; | ||
| 123 | |||
| 124 | struct eeepc_wmi_debug debug; | ||
| 125 | }; | ||
| 126 | |||
| 127 | /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ | ||
| 128 | static struct platform_device *platform_device; | ||
| 129 | |||
| 130 | static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) | ||
| 131 | { | ||
| 132 | int err; | ||
| 133 | |||
| 134 | eeepc->inputdev = input_allocate_device(); | ||
| 135 | if (!eeepc->inputdev) | ||
| 136 | return -ENOMEM; | ||
| 137 | |||
| 138 | eeepc->inputdev->name = "Eee PC WMI hotkeys"; | ||
| 139 | eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; | ||
| 140 | eeepc->inputdev->id.bustype = BUS_HOST; | ||
| 141 | eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; | ||
| 142 | |||
| 143 | err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); | ||
| 144 | if (err) | ||
| 145 | goto err_free_dev; | ||
| 146 | |||
| 147 | err = input_register_device(eeepc->inputdev); | ||
| 148 | if (err) | ||
| 149 | goto err_free_keymap; | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | |||
| 153 | err_free_keymap: | ||
| 154 | sparse_keymap_free(eeepc->inputdev); | ||
| 155 | err_free_dev: | ||
| 156 | input_free_device(eeepc->inputdev); | ||
| 157 | return err; | ||
| 158 | } | ||
| 159 | |||
| 160 | static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) | ||
| 161 | { | ||
| 162 | if (eeepc->inputdev) { | ||
| 163 | sparse_keymap_free(eeepc->inputdev); | ||
| 164 | input_unregister_device(eeepc->inputdev); | ||
| 165 | } | ||
| 166 | |||
| 167 | eeepc->inputdev = NULL; | ||
| 168 | } | ||
| 169 | |||
| 170 | static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) | ||
| 171 | { | ||
| 172 | struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; | ||
| 173 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 174 | union acpi_object *obj; | ||
| 175 | acpi_status status; | ||
| 176 | u32 tmp; | ||
| 177 | |||
| 178 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, | ||
| 179 | 1, EEEPC_WMI_METHODID_DSTS, &input, &output); | ||
| 180 | |||
| 181 | if (ACPI_FAILURE(status)) | ||
| 182 | return status; | ||
| 183 | |||
| 184 | obj = (union acpi_object *)output.pointer; | ||
| 185 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
| 186 | tmp = (u32)obj->integer.value; | ||
| 187 | else | ||
| 188 | tmp = 0; | ||
| 189 | |||
| 190 | if (retval) | ||
| 191 | *retval = tmp; | ||
| 192 | |||
| 193 | kfree(obj); | ||
| 194 | |||
| 195 | return status; | ||
| 196 | |||
| 197 | } | ||
| 198 | |||
| 199 | static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, | ||
| 200 | u32 *retval) | ||
| 201 | { | ||
| 202 | struct bios_args args = { | ||
| 203 | .dev_id = dev_id, | ||
| 204 | .ctrl_param = ctrl_param, | ||
| 205 | }; | ||
| 206 | struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; | ||
| 207 | acpi_status status; | ||
| 208 | |||
| 209 | if (!retval) { | ||
| 210 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, | ||
| 211 | EEEPC_WMI_METHODID_DEVS, | ||
| 212 | &input, NULL); | ||
| 213 | } else { | ||
| 214 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 215 | union acpi_object *obj; | ||
| 216 | u32 tmp; | ||
| 217 | |||
| 218 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, | ||
| 219 | EEEPC_WMI_METHODID_DEVS, | ||
| 220 | &input, &output); | ||
| 221 | |||
| 222 | if (ACPI_FAILURE(status)) | ||
| 223 | return status; | ||
| 224 | |||
| 225 | obj = (union acpi_object *)output.pointer; | ||
| 226 | if (obj && obj->type == ACPI_TYPE_INTEGER) | ||
| 227 | tmp = (u32)obj->integer.value; | ||
| 228 | else | ||
| 229 | tmp = 0; | ||
| 230 | |||
| 231 | *retval = tmp; | ||
| 232 | |||
| 233 | kfree(obj); | ||
| 234 | } | ||
| 235 | |||
| 236 | return status; | ||
| 237 | } | ||
| 238 | |||
| 239 | /* | ||
| 240 | * LEDs | ||
| 241 | */ | ||
| 242 | /* | ||
| 243 | * These functions actually update the LED's, and are called from a | ||
| 244 | * workqueue. By doing this as separate work rather than when the LED | ||
| 245 | * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a | ||
| 246 | * potentially bad time, such as a timer interrupt. | ||
| 247 | */ | ||
| 248 | static void tpd_led_update(struct work_struct *work) | ||
| 249 | { | ||
| 250 | int ctrl_param; | ||
| 251 | struct eeepc_wmi *eeepc; | ||
| 252 | |||
| 253 | eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); | ||
| 254 | |||
| 255 | ctrl_param = eeepc->tpd_led_wk; | ||
| 256 | eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL); | ||
| 257 | } | ||
| 258 | |||
| 259 | static void tpd_led_set(struct led_classdev *led_cdev, | ||
| 260 | enum led_brightness value) | ||
| 261 | { | ||
| 262 | struct eeepc_wmi *eeepc; | ||
| 263 | |||
| 264 | eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); | ||
| 265 | |||
| 266 | eeepc->tpd_led_wk = !!value; | ||
| 267 | queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); | ||
| 268 | } | ||
| 269 | |||
| 270 | static int read_tpd_state(struct eeepc_wmi *eeepc) | ||
| 271 | { | ||
| 272 | u32 retval; | ||
| 273 | acpi_status status; | ||
| 274 | |||
| 275 | status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval); | ||
| 276 | |||
| 277 | if (ACPI_FAILURE(status)) | ||
| 278 | return -1; | ||
| 279 | else if (!retval || retval == 0x00060000) | ||
| 280 | /* | ||
| 281 | * if touchpad led is present, DSTS will set some bits, | ||
| 282 | * usually 0x00020000. | ||
| 283 | * 0x00060000 means that the device is not supported | ||
| 284 | */ | ||
| 285 | return -ENODEV; | ||
| 286 | else | ||
| 287 | /* Status is stored in the first bit */ | ||
| 288 | return retval & 0x1; | ||
| 289 | } | ||
| 290 | |||
| 291 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) | ||
| 292 | { | ||
| 293 | struct eeepc_wmi *eeepc; | ||
| 294 | |||
| 295 | eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); | ||
| 296 | |||
| 297 | return read_tpd_state(eeepc); | ||
| 298 | } | ||
| 299 | |||
| 300 | static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) | ||
| 301 | { | ||
| 302 | int rv; | ||
| 303 | |||
| 304 | if (read_tpd_state(eeepc) < 0) | ||
| 305 | return 0; | ||
| 306 | |||
| 307 | eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); | ||
| 308 | if (!eeepc->led_workqueue) | ||
| 309 | return -ENOMEM; | ||
| 310 | INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); | ||
| 311 | |||
| 312 | eeepc->tpd_led.name = "eeepc::touchpad"; | ||
| 313 | eeepc->tpd_led.brightness_set = tpd_led_set; | ||
| 314 | eeepc->tpd_led.brightness_get = tpd_led_get; | ||
| 315 | eeepc->tpd_led.max_brightness = 1; | ||
| 316 | |||
| 317 | rv = led_classdev_register(&eeepc->platform_device->dev, | ||
| 318 | &eeepc->tpd_led); | ||
| 319 | if (rv) { | ||
| 320 | destroy_workqueue(eeepc->led_workqueue); | ||
| 321 | return rv; | ||
| 322 | } | ||
| 323 | |||
| 324 | return 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) | ||
| 328 | { | ||
| 329 | if (eeepc->tpd_led.dev) | ||
| 330 | led_classdev_unregister(&eeepc->tpd_led); | ||
| 331 | if (eeepc->led_workqueue) | ||
| 332 | destroy_workqueue(eeepc->led_workqueue); | ||
| 333 | } | ||
| 334 | |||
| 335 | /* | ||
| 336 | * Rfkill devices | ||
| 337 | */ | ||
| 338 | static int eeepc_rfkill_set(void *data, bool blocked) | ||
| 339 | { | ||
| 340 | int dev_id = (unsigned long)data; | ||
| 341 | u32 ctrl_param = !blocked; | ||
| 342 | |||
| 343 | return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); | ||
| 344 | } | ||
| 345 | |||
| 346 | static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) | ||
| 347 | { | ||
| 348 | int dev_id = (unsigned long)data; | ||
| 349 | u32 retval; | ||
| 350 | acpi_status status; | ||
| 351 | |||
| 352 | status = eeepc_wmi_get_devstate(dev_id, &retval); | ||
| 353 | |||
| 354 | if (ACPI_FAILURE(status)) | ||
| 355 | return ; | ||
| 356 | |||
| 357 | rfkill_set_sw_state(rfkill, !(retval & 0x1)); | ||
| 358 | } | ||
| 359 | |||
| 360 | static const struct rfkill_ops eeepc_rfkill_ops = { | ||
| 361 | .set_block = eeepc_rfkill_set, | ||
| 362 | .query = eeepc_rfkill_query, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, | ||
| 366 | struct rfkill **rfkill, | ||
| 367 | const char *name, | ||
| 368 | enum rfkill_type type, int dev_id) | ||
| 369 | { | ||
| 370 | int result; | ||
| 371 | u32 retval; | ||
| 372 | acpi_status status; | ||
| 373 | |||
| 374 | status = eeepc_wmi_get_devstate(dev_id, &retval); | ||
| 375 | |||
| 376 | if (ACPI_FAILURE(status)) | ||
| 377 | return -1; | ||
| 378 | |||
| 379 | /* If the device is present, DSTS will always set some bits | ||
| 380 | * 0x00070000 - 1110000000000000000 - device supported | ||
| 381 | * 0x00060000 - 1100000000000000000 - not supported | ||
| 382 | * 0x00020000 - 0100000000000000000 - device supported | ||
| 383 | * 0x00010000 - 0010000000000000000 - not supported / special mode ? | ||
| 384 | */ | ||
| 385 | if (!retval || retval == 0x00060000) | ||
| 386 | return -ENODEV; | ||
| 387 | |||
| 388 | *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, | ||
| 389 | &eeepc_rfkill_ops, (void *)(long)dev_id); | ||
| 390 | |||
| 391 | if (!*rfkill) | ||
| 392 | return -EINVAL; | ||
| 393 | |||
| 394 | rfkill_init_sw_state(*rfkill, !(retval & 0x1)); | ||
| 395 | result = rfkill_register(*rfkill); | ||
| 396 | if (result) { | ||
| 397 | rfkill_destroy(*rfkill); | ||
| 398 | *rfkill = NULL; | ||
| 399 | return result; | ||
| 400 | } | ||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | |||
| 404 | static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) | ||
| 405 | { | ||
| 406 | if (eeepc->wlan_rfkill) { | ||
| 407 | rfkill_unregister(eeepc->wlan_rfkill); | ||
| 408 | rfkill_destroy(eeepc->wlan_rfkill); | ||
| 409 | eeepc->wlan_rfkill = NULL; | ||
| 410 | } | ||
| 411 | if (eeepc->bluetooth_rfkill) { | ||
| 412 | rfkill_unregister(eeepc->bluetooth_rfkill); | ||
| 413 | rfkill_destroy(eeepc->bluetooth_rfkill); | ||
| 414 | eeepc->bluetooth_rfkill = NULL; | ||
| 415 | } | ||
| 416 | if (eeepc->wwan3g_rfkill) { | ||
| 417 | rfkill_unregister(eeepc->wwan3g_rfkill); | ||
| 418 | rfkill_destroy(eeepc->wwan3g_rfkill); | ||
| 419 | eeepc->wwan3g_rfkill = NULL; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) | ||
| 424 | { | ||
| 425 | int result = 0; | ||
| 426 | |||
| 427 | result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, | ||
| 428 | "eeepc-wlan", RFKILL_TYPE_WLAN, | ||
| 429 | EEEPC_WMI_DEVID_WLAN); | ||
| 430 | |||
| 431 | if (result && result != -ENODEV) | ||
| 432 | goto exit; | ||
| 433 | |||
| 434 | result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, | ||
| 435 | "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
| 436 | EEEPC_WMI_DEVID_BLUETOOTH); | ||
| 437 | |||
| 438 | if (result && result != -ENODEV) | ||
| 439 | goto exit; | ||
| 440 | |||
| 441 | result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, | ||
| 442 | "eeepc-wwan3g", RFKILL_TYPE_WWAN, | ||
| 443 | EEEPC_WMI_DEVID_WWAN3G); | ||
| 444 | |||
| 445 | if (result && result != -ENODEV) | ||
| 446 | goto exit; | ||
| 447 | |||
| 448 | exit: | ||
| 449 | if (result && result != -ENODEV) | ||
| 450 | eeepc_wmi_rfkill_exit(eeepc); | ||
| 451 | |||
| 452 | if (result == -ENODEV) | ||
| 453 | result = 0; | ||
| 454 | |||
| 455 | return result; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* | ||
| 459 | * Backlight | ||
| 460 | */ | ||
| 461 | static int read_brightness(struct backlight_device *bd) | ||
| 462 | { | ||
| 463 | u32 retval; | ||
| 464 | acpi_status status; | ||
| 465 | |||
| 466 | status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval); | ||
| 467 | |||
| 468 | if (ACPI_FAILURE(status)) | ||
| 469 | return -1; | ||
| 470 | else | ||
| 471 | return retval & 0xFF; | ||
| 472 | } | ||
| 473 | |||
| 474 | static int update_bl_status(struct backlight_device *bd) | ||
| 475 | { | ||
| 476 | |||
| 477 | u32 ctrl_param; | ||
| 478 | acpi_status status; | ||
| 479 | |||
| 480 | ctrl_param = bd->props.brightness; | ||
| 481 | |||
| 482 | status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, | ||
| 483 | ctrl_param, NULL); | ||
| 484 | |||
| 485 | if (ACPI_FAILURE(status)) | ||
| 486 | return -1; | ||
| 487 | else | ||
| 488 | return 0; | ||
| 489 | } | ||
| 490 | |||
| 491 | static const struct backlight_ops eeepc_wmi_bl_ops = { | ||
| 492 | .get_brightness = read_brightness, | ||
| 493 | .update_status = update_bl_status, | ||
| 494 | }; | ||
| 495 | |||
| 496 | static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) | ||
| 497 | { | ||
| 498 | struct backlight_device *bd = eeepc->backlight_device; | ||
| 499 | int old = bd->props.brightness; | ||
| 500 | int new = old; | ||
| 501 | |||
| 502 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
| 503 | new = code - NOTIFY_BRNUP_MIN + 1; | ||
| 504 | else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) | ||
| 505 | new = code - NOTIFY_BRNDOWN_MIN; | ||
| 506 | |||
| 507 | bd->props.brightness = new; | ||
| 508 | backlight_update_status(bd); | ||
| 509 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); | ||
| 510 | |||
| 511 | return old; | ||
| 512 | } | ||
| 513 | |||
| 514 | static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) | ||
| 515 | { | ||
| 516 | struct backlight_device *bd; | ||
| 517 | struct backlight_properties props; | ||
| 518 | |||
| 519 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 520 | props.max_brightness = 15; | ||
| 521 | bd = backlight_device_register(EEEPC_WMI_FILE, | ||
| 522 | &eeepc->platform_device->dev, eeepc, | ||
| 523 | &eeepc_wmi_bl_ops, &props); | ||
| 524 | if (IS_ERR(bd)) { | ||
| 525 | pr_err("Could not register backlight device\n"); | ||
| 526 | return PTR_ERR(bd); | ||
| 527 | } | ||
| 528 | |||
| 529 | eeepc->backlight_device = bd; | ||
| 530 | |||
| 531 | bd->props.brightness = read_brightness(bd); | ||
| 532 | bd->props.power = FB_BLANK_UNBLANK; | ||
| 533 | backlight_update_status(bd); | ||
| 534 | |||
| 535 | return 0; | ||
| 536 | } | ||
| 537 | |||
| 538 | static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) | ||
| 539 | { | ||
| 540 | if (eeepc->backlight_device) | ||
| 541 | backlight_device_unregister(eeepc->backlight_device); | ||
| 542 | |||
| 543 | eeepc->backlight_device = NULL; | ||
| 544 | } | ||
| 545 | |||
| 546 | static void eeepc_wmi_notify(u32 value, void *context) | ||
| 547 | { | ||
| 548 | struct eeepc_wmi *eeepc = context; | ||
| 549 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 550 | union acpi_object *obj; | ||
| 551 | acpi_status status; | ||
| 552 | int code; | ||
| 553 | int orig_code; | ||
| 554 | |||
| 555 | status = wmi_get_event_data(value, &response); | ||
| 556 | if (status != AE_OK) { | ||
| 557 | pr_err("bad event status 0x%x\n", status); | ||
| 558 | return; | ||
| 559 | } | ||
| 560 | |||
| 561 | obj = (union acpi_object *)response.pointer; | ||
| 562 | |||
| 563 | if (obj && obj->type == ACPI_TYPE_INTEGER) { | ||
| 564 | code = obj->integer.value; | ||
| 565 | orig_code = code; | ||
| 566 | |||
| 567 | if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) | ||
| 568 | code = NOTIFY_BRNUP_MIN; | ||
| 569 | else if (code >= NOTIFY_BRNDOWN_MIN && | ||
| 570 | code <= NOTIFY_BRNDOWN_MAX) | ||
| 571 | code = NOTIFY_BRNDOWN_MIN; | ||
| 572 | |||
| 573 | if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { | ||
| 574 | if (!acpi_video_backlight_support()) | ||
| 575 | eeepc_wmi_backlight_notify(eeepc, orig_code); | ||
| 576 | } | ||
| 577 | |||
| 578 | if (!sparse_keymap_report_event(eeepc->inputdev, | ||
| 579 | code, 1, true)) | ||
| 580 | pr_info("Unknown key %x pressed\n", code); | ||
| 581 | } | ||
| 582 | |||
| 583 | kfree(obj); | ||
| 584 | } | ||
| 585 | |||
| 586 | static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, | ||
| 587 | const char *buf, size_t count) | ||
| 588 | { | ||
| 589 | int value; | ||
| 590 | struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; | ||
| 591 | acpi_status status; | ||
| 592 | |||
| 593 | if (!count || sscanf(buf, "%i", &value) != 1) | ||
| 594 | return -EINVAL; | ||
| 595 | if (value < 0 || value > 2) | ||
| 596 | return -EINVAL; | ||
| 597 | |||
| 598 | status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, | ||
| 599 | 1, EEEPC_WMI_METHODID_CFVS, &input, NULL); | ||
| 600 | |||
| 601 | if (ACPI_FAILURE(status)) | ||
| 602 | return -EIO; | ||
| 603 | else | ||
| 604 | return count; | ||
| 605 | } | ||
| 606 | |||
| 607 | static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); | ||
| 608 | |||
| 609 | static struct attribute *platform_attributes[] = { | ||
| 610 | &dev_attr_cpufv.attr, | ||
| 611 | NULL | ||
| 612 | }; | ||
| 613 | |||
| 614 | static struct attribute_group platform_attribute_group = { | ||
| 615 | .attrs = platform_attributes | ||
| 616 | }; | ||
| 617 | |||
| 618 | static void eeepc_wmi_sysfs_exit(struct platform_device *device) | ||
| 619 | { | ||
| 620 | sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); | ||
| 621 | } | ||
| 622 | |||
| 623 | static int eeepc_wmi_sysfs_init(struct platform_device *device) | ||
| 624 | { | ||
| 625 | return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); | ||
| 626 | } | ||
| 627 | |||
| 628 | /* | ||
| 629 | * Platform device | ||
| 630 | */ | ||
| 631 | static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) | ||
| 632 | { | ||
| 633 | int err; | ||
| 634 | |||
| 635 | eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); | ||
| 636 | if (!eeepc->platform_device) | ||
| 637 | return -ENOMEM; | ||
| 638 | platform_set_drvdata(eeepc->platform_device, eeepc); | ||
| 639 | |||
| 640 | err = platform_device_add(eeepc->platform_device); | ||
| 641 | if (err) | ||
| 642 | goto fail_platform_device; | ||
| 643 | |||
| 644 | err = eeepc_wmi_sysfs_init(eeepc->platform_device); | ||
| 645 | if (err) | ||
| 646 | goto fail_sysfs; | ||
| 647 | return 0; | ||
| 648 | |||
| 649 | fail_sysfs: | ||
| 650 | platform_device_del(eeepc->platform_device); | ||
| 651 | fail_platform_device: | ||
| 652 | platform_device_put(eeepc->platform_device); | ||
| 653 | return err; | ||
| 654 | } | ||
| 655 | |||
| 656 | static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) | ||
| 657 | { | ||
| 658 | eeepc_wmi_sysfs_exit(eeepc->platform_device); | ||
| 659 | platform_device_unregister(eeepc->platform_device); | ||
| 660 | } | ||
| 661 | |||
| 662 | /* | ||
| 663 | * debugfs | ||
| 664 | */ | ||
| 665 | struct eeepc_wmi_debugfs_node { | ||
| 666 | struct eeepc_wmi *eeepc; | ||
| 667 | char *name; | ||
| 668 | int (*show)(struct seq_file *m, void *data); | ||
| 669 | }; | ||
| 670 | |||
| 671 | static int show_dsts(struct seq_file *m, void *data) | ||
| 672 | { | ||
| 673 | struct eeepc_wmi *eeepc = m->private; | ||
| 674 | acpi_status status; | ||
| 675 | u32 retval = -1; | ||
| 676 | |||
| 677 | status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); | ||
| 678 | |||
| 679 | if (ACPI_FAILURE(status)) | ||
| 680 | return -EIO; | ||
| 681 | |||
| 682 | seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); | ||
| 683 | |||
| 684 | return 0; | ||
| 685 | } | ||
| 686 | |||
| 687 | static int show_devs(struct seq_file *m, void *data) | ||
| 688 | { | ||
| 689 | struct eeepc_wmi *eeepc = m->private; | ||
| 690 | acpi_status status; | ||
| 691 | u32 retval = -1; | ||
| 692 | |||
| 693 | status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, | ||
| 694 | eeepc->debug.ctrl_param, &retval); | ||
| 695 | if (ACPI_FAILURE(status)) | ||
| 696 | return -EIO; | ||
| 697 | |||
| 698 | seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, | ||
| 699 | eeepc->debug.ctrl_param, retval); | ||
| 700 | |||
| 701 | return 0; | ||
| 702 | } | ||
| 703 | |||
| 704 | static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { | ||
| 705 | { NULL, "devs", show_devs }, | ||
| 706 | { NULL, "dsts", show_dsts }, | ||
| 707 | }; | ||
| 708 | |||
| 709 | static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) | ||
| 710 | { | ||
| 711 | struct eeepc_wmi_debugfs_node *node = inode->i_private; | ||
| 712 | |||
| 713 | return single_open(file, node->show, node->eeepc); | ||
| 714 | } | ||
| 715 | |||
| 716 | static const struct file_operations eeepc_wmi_debugfs_io_ops = { | ||
| 717 | .owner = THIS_MODULE, | ||
| 718 | .open = eeepc_wmi_debugfs_open, | ||
| 719 | .read = seq_read, | ||
| 720 | .llseek = seq_lseek, | ||
| 721 | .release = single_release, | ||
| 722 | }; | ||
| 723 | |||
| 724 | static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) | ||
| 725 | { | ||
| 726 | debugfs_remove_recursive(eeepc->debug.root); | ||
| 727 | } | ||
| 728 | |||
| 729 | static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) | ||
| 730 | { | ||
| 731 | struct dentry *dent; | ||
| 732 | int i; | ||
| 733 | |||
| 734 | eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); | ||
| 735 | if (!eeepc->debug.root) { | ||
| 736 | pr_err("failed to create debugfs directory"); | ||
| 737 | goto error_debugfs; | ||
| 738 | } | ||
| 739 | |||
| 740 | dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, | ||
| 741 | eeepc->debug.root, &eeepc->debug.dev_id); | ||
| 742 | if (!dent) | ||
| 743 | goto error_debugfs; | ||
| 744 | |||
| 745 | dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, | ||
| 746 | eeepc->debug.root, &eeepc->debug.ctrl_param); | ||
| 747 | if (!dent) | ||
| 748 | goto error_debugfs; | ||
| 749 | |||
| 750 | for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { | ||
| 751 | struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; | ||
| 752 | |||
| 753 | node->eeepc = eeepc; | ||
| 754 | dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, | ||
| 755 | eeepc->debug.root, node, | ||
| 756 | &eeepc_wmi_debugfs_io_ops); | ||
| 757 | if (!dent) { | ||
| 758 | pr_err("failed to create debug file: %s\n", node->name); | ||
| 759 | goto error_debugfs; | ||
| 760 | } | ||
| 761 | } | ||
| 762 | |||
| 763 | return 0; | ||
| 764 | |||
| 765 | error_debugfs: | ||
| 766 | eeepc_wmi_debugfs_exit(eeepc); | ||
| 767 | return -ENOMEM; | ||
| 768 | } | ||
| 769 | |||
| 770 | /* | ||
| 771 | * WMI Driver | ||
| 772 | */ | ||
| 773 | static struct platform_device * __init eeepc_wmi_add(void) | ||
| 774 | { | ||
| 775 | struct eeepc_wmi *eeepc; | ||
| 776 | acpi_status status; | ||
| 777 | int err; | ||
| 778 | |||
| 779 | eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); | ||
| 780 | if (!eeepc) | ||
| 781 | return ERR_PTR(-ENOMEM); | ||
| 782 | |||
| 783 | /* | ||
| 784 | * Register the platform device first. It is used as a parent for the | ||
| 785 | * sub-devices below. | ||
| 786 | */ | ||
| 787 | err = eeepc_wmi_platform_init(eeepc); | ||
| 788 | if (err) | ||
| 789 | goto fail_platform; | ||
| 790 | |||
| 791 | err = eeepc_wmi_input_init(eeepc); | ||
| 792 | if (err) | ||
| 793 | goto fail_input; | ||
| 794 | |||
| 795 | err = eeepc_wmi_led_init(eeepc); | ||
| 796 | if (err) | ||
| 797 | goto fail_leds; | ||
| 798 | |||
| 799 | err = eeepc_wmi_rfkill_init(eeepc); | ||
| 800 | if (err) | ||
| 801 | goto fail_rfkill; | ||
| 802 | |||
| 803 | if (!acpi_video_backlight_support()) { | ||
| 804 | err = eeepc_wmi_backlight_init(eeepc); | ||
| 805 | if (err) | ||
| 806 | goto fail_backlight; | ||
| 807 | } else | ||
| 808 | pr_info("Backlight controlled by ACPI video driver\n"); | ||
| 809 | |||
| 810 | status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, | ||
| 811 | eeepc_wmi_notify, eeepc); | ||
| 812 | if (ACPI_FAILURE(status)) { | ||
| 813 | pr_err("Unable to register notify handler - %d\n", | ||
| 814 | status); | ||
| 815 | err = -ENODEV; | ||
| 816 | goto fail_wmi_handler; | ||
| 817 | } | ||
| 818 | |||
| 819 | err = eeepc_wmi_debugfs_init(eeepc); | ||
| 820 | if (err) | ||
| 821 | goto fail_debugfs; | ||
| 822 | |||
| 823 | return eeepc->platform_device; | ||
| 824 | |||
| 825 | fail_debugfs: | ||
| 826 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); | ||
| 827 | fail_wmi_handler: | ||
| 828 | eeepc_wmi_backlight_exit(eeepc); | ||
| 829 | fail_backlight: | ||
| 830 | eeepc_wmi_rfkill_exit(eeepc); | ||
| 831 | fail_rfkill: | ||
| 832 | eeepc_wmi_led_exit(eeepc); | ||
| 833 | fail_leds: | ||
| 834 | eeepc_wmi_input_exit(eeepc); | ||
| 835 | fail_input: | ||
| 836 | eeepc_wmi_platform_exit(eeepc); | ||
| 837 | fail_platform: | ||
| 838 | kfree(eeepc); | ||
| 839 | return ERR_PTR(err); | ||
| 840 | } | ||
| 841 | |||
| 842 | static int eeepc_wmi_remove(struct platform_device *device) | ||
| 843 | { | ||
| 844 | struct eeepc_wmi *eeepc; | ||
| 845 | |||
| 846 | eeepc = platform_get_drvdata(device); | ||
| 847 | wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); | ||
| 848 | eeepc_wmi_backlight_exit(eeepc); | ||
| 849 | eeepc_wmi_input_exit(eeepc); | ||
| 850 | eeepc_wmi_led_exit(eeepc); | ||
| 851 | eeepc_wmi_rfkill_exit(eeepc); | ||
| 852 | eeepc_wmi_debugfs_exit(eeepc); | ||
| 853 | eeepc_wmi_platform_exit(eeepc); | ||
| 854 | |||
| 855 | kfree(eeepc); | ||
| 856 | return 0; | ||
| 857 | } | ||
| 858 | |||
| 859 | static struct platform_driver platform_driver = { | ||
| 860 | .driver = { | ||
| 861 | .name = EEEPC_WMI_FILE, | ||
| 862 | .owner = THIS_MODULE, | ||
| 863 | }, | ||
| 864 | }; | ||
| 865 | |||
| 866 | static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, | ||
| 867 | void *context, void **retval) | 83 | void *context, void **retval) |
| 868 | { | 84 | { |
| 869 | pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); | 85 | pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); |
| @@ -871,7 +87,7 @@ static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, | |||
| 871 | return AE_CTRL_TERMINATE; | 87 | return AE_CTRL_TERMINATE; |
| 872 | } | 88 | } |
| 873 | 89 | ||
| 874 | static int __init eeepc_wmi_check_atkd(void) | 90 | static int eeepc_wmi_check_atkd(void) |
| 875 | { | 91 | { |
| 876 | acpi_status status; | 92 | acpi_status status; |
| 877 | bool found = false; | 93 | bool found = false; |
| @@ -884,16 +100,8 @@ static int __init eeepc_wmi_check_atkd(void) | |||
| 884 | return -1; | 100 | return -1; |
| 885 | } | 101 | } |
| 886 | 102 | ||
| 887 | static int __init eeepc_wmi_init(void) | 103 | static int eeepc_wmi_probe(struct platform_device *pdev) |
| 888 | { | 104 | { |
| 889 | int err; | ||
| 890 | |||
| 891 | if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || | ||
| 892 | !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { | ||
| 893 | pr_warning("No known WMI GUID found\n"); | ||
| 894 | return -ENODEV; | ||
| 895 | } | ||
| 896 | |||
| 897 | if (eeepc_wmi_check_atkd()) { | 105 | if (eeepc_wmi_check_atkd()) { |
| 898 | pr_warning("WMI device present, but legacy ATKD device is also " | 106 | pr_warning("WMI device present, but legacy ATKD device is also " |
| 899 | "present and enabled."); | 107 | "present and enabled."); |
| @@ -901,33 +109,59 @@ static int __init eeepc_wmi_init(void) | |||
| 901 | "acpi_osi=\"!Windows 2009\""); | 109 | "acpi_osi=\"!Windows 2009\""); |
| 902 | pr_warning("Can't load eeepc-wmi, use default acpi_osi " | 110 | pr_warning("Can't load eeepc-wmi, use default acpi_osi " |
| 903 | "(preferred) or eeepc-laptop"); | 111 | "(preferred) or eeepc-laptop"); |
| 904 | return -ENODEV; | 112 | return -EBUSY; |
| 905 | } | 113 | } |
| 114 | return 0; | ||
| 115 | } | ||
| 906 | 116 | ||
| 907 | platform_device = eeepc_wmi_add(); | 117 | static void eeepc_dmi_check(struct asus_wmi_driver *driver) |
| 908 | if (IS_ERR(platform_device)) { | 118 | { |
| 909 | err = PTR_ERR(platform_device); | 119 | const char *model; |
| 910 | goto fail_eeepc_wmi; | 120 | |
| 911 | } | 121 | model = dmi_get_system_info(DMI_PRODUCT_NAME); |
| 122 | if (!model) | ||
| 123 | return; | ||
| 912 | 124 | ||
| 913 | err = platform_driver_register(&platform_driver); | 125 | /* |
| 914 | if (err) { | 126 | * Whitelist for wlan hotplug |
| 915 | pr_warning("Unable to register platform driver\n"); | 127 | * |
| 916 | goto fail_platform_driver; | 128 | * Asus 1000H needs the current hotplug code to handle |
| 129 | * Fn+F2 correctly. We may add other Asus here later, but | ||
| 130 | * it seems that most of the laptops supported by asus-wmi | ||
| 131 | * don't need to be on this list | ||
| 132 | */ | ||
| 133 | if (strcmp(model, "1000H") == 0) { | ||
| 134 | driver->hotplug_wireless = true; | ||
| 135 | pr_info("wlan hotplug enabled\n"); | ||
| 917 | } | 136 | } |
| 137 | } | ||
| 138 | |||
| 139 | static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) | ||
| 140 | { | ||
| 141 | driver->hotplug_wireless = hotplug_wireless; | ||
| 142 | eeepc_dmi_check(driver); | ||
| 143 | } | ||
| 144 | |||
| 145 | static struct asus_wmi_driver asus_wmi_driver = { | ||
| 146 | .name = EEEPC_WMI_FILE, | ||
| 147 | .owner = THIS_MODULE, | ||
| 148 | .event_guid = EEEPC_WMI_EVENT_GUID, | ||
| 149 | .keymap = eeepc_wmi_keymap, | ||
| 150 | .input_name = "Eee PC WMI hotkeys", | ||
| 151 | .input_phys = EEEPC_WMI_FILE "/input0", | ||
| 152 | .probe = eeepc_wmi_probe, | ||
| 153 | .quirks = eeepc_wmi_quirks, | ||
| 154 | }; | ||
| 918 | 155 | ||
| 919 | return 0; | ||
| 920 | 156 | ||
| 921 | fail_platform_driver: | 157 | static int __init eeepc_wmi_init(void) |
| 922 | eeepc_wmi_remove(platform_device); | 158 | { |
| 923 | fail_eeepc_wmi: | 159 | return asus_wmi_register_driver(&asus_wmi_driver); |
| 924 | return err; | ||
| 925 | } | 160 | } |
| 926 | 161 | ||
| 927 | static void __exit eeepc_wmi_exit(void) | 162 | static void __exit eeepc_wmi_exit(void) |
| 928 | { | 163 | { |
| 929 | eeepc_wmi_remove(platform_device); | 164 | asus_wmi_unregister_driver(&asus_wmi_driver); |
| 930 | platform_driver_unregister(&platform_driver); | ||
| 931 | } | 165 | } |
| 932 | 166 | ||
| 933 | module_init(eeepc_wmi_init); | 167 | module_init(eeepc_wmi_init); |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 9e05af9c41cb..1bc4a7539ba9 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * HP WMI hotkeys | 2 | * HP WMI hotkeys |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2008 Red Hat <mjg@redhat.com> | 4 | * Copyright (C) 2008 Red Hat <mjg@redhat.com> |
| 5 | * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi> | ||
| 5 | * | 6 | * |
| 6 | * Portions based on wistron_btns.c: | 7 | * Portions based on wistron_btns.c: |
| 7 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> | 8 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> |
| @@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
| 51 | #define HPWMI_HARDWARE_QUERY 0x4 | 52 | #define HPWMI_HARDWARE_QUERY 0x4 |
| 52 | #define HPWMI_WIRELESS_QUERY 0x5 | 53 | #define HPWMI_WIRELESS_QUERY 0x5 |
| 53 | #define HPWMI_HOTKEY_QUERY 0xc | 54 | #define HPWMI_HOTKEY_QUERY 0xc |
| 55 | #define HPWMI_WIRELESS2_QUERY 0x1b | ||
| 54 | 56 | ||
| 55 | #define PREFIX "HP WMI: " | 57 | #define PREFIX "HP WMI: " |
| 56 | #define UNIMP "Unimplemented " | 58 | #define UNIMP "Unimplemented " |
| @@ -86,7 +88,46 @@ struct bios_args { | |||
| 86 | struct bios_return { | 88 | struct bios_return { |
| 87 | u32 sigpass; | 89 | u32 sigpass; |
| 88 | u32 return_code; | 90 | u32 return_code; |
| 89 | u32 value; | 91 | }; |
| 92 | |||
| 93 | enum hp_return_value { | ||
| 94 | HPWMI_RET_WRONG_SIGNATURE = 0x02, | ||
| 95 | HPWMI_RET_UNKNOWN_COMMAND = 0x03, | ||
| 96 | HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, | ||
| 97 | HPWMI_RET_INVALID_PARAMETERS = 0x05, | ||
| 98 | }; | ||
| 99 | |||
| 100 | enum hp_wireless2_bits { | ||
| 101 | HPWMI_POWER_STATE = 0x01, | ||
| 102 | HPWMI_POWER_SOFT = 0x02, | ||
| 103 | HPWMI_POWER_BIOS = 0x04, | ||
| 104 | HPWMI_POWER_HARD = 0x08, | ||
| 105 | }; | ||
| 106 | |||
| 107 | #define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \ | ||
| 108 | != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) | ||
| 109 | #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) | ||
| 110 | |||
| 111 | struct bios_rfkill2_device_state { | ||
| 112 | u8 radio_type; | ||
| 113 | u8 bus_type; | ||
| 114 | u16 vendor_id; | ||
| 115 | u16 product_id; | ||
| 116 | u16 subsys_vendor_id; | ||
| 117 | u16 subsys_product_id; | ||
| 118 | u8 rfkill_id; | ||
| 119 | u8 power; | ||
| 120 | u8 unknown[4]; | ||
| 121 | }; | ||
| 122 | |||
| 123 | /* 7 devices fit into the 128 byte buffer */ | ||
| 124 | #define HPWMI_MAX_RFKILL2_DEVICES 7 | ||
| 125 | |||
| 126 | struct bios_rfkill2_state { | ||
| 127 | u8 unknown[7]; | ||
| 128 | u8 count; | ||
| 129 | u8 pad[8]; | ||
| 130 | struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; | ||
| 90 | }; | 131 | }; |
| 91 | 132 | ||
| 92 | static const struct key_entry hp_wmi_keymap[] = { | 133 | static const struct key_entry hp_wmi_keymap[] = { |
| @@ -108,6 +149,15 @@ static struct rfkill *wifi_rfkill; | |||
| 108 | static struct rfkill *bluetooth_rfkill; | 149 | static struct rfkill *bluetooth_rfkill; |
| 109 | static struct rfkill *wwan_rfkill; | 150 | static struct rfkill *wwan_rfkill; |
| 110 | 151 | ||
| 152 | struct rfkill2_device { | ||
| 153 | u8 id; | ||
| 154 | int num; | ||
| 155 | struct rfkill *rfkill; | ||
| 156 | }; | ||
| 157 | |||
| 158 | static int rfkill2_count; | ||
| 159 | static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; | ||
| 160 | |||
| 111 | static const struct dev_pm_ops hp_wmi_pm_ops = { | 161 | static const struct dev_pm_ops hp_wmi_pm_ops = { |
| 112 | .resume = hp_wmi_resume_handler, | 162 | .resume = hp_wmi_resume_handler, |
| 113 | .restore = hp_wmi_resume_handler, | 163 | .restore = hp_wmi_resume_handler, |
| @@ -129,7 +179,8 @@ static struct platform_driver hp_wmi_driver = { | |||
| 129 | * query: The commandtype -> What should be queried | 179 | * query: The commandtype -> What should be queried |
| 130 | * write: The command -> 0 read, 1 write, 3 ODM specific | 180 | * write: The command -> 0 read, 1 write, 3 ODM specific |
| 131 | * buffer: Buffer used as input and/or output | 181 | * buffer: Buffer used as input and/or output |
| 132 | * buffersize: Size of buffer | 182 | * insize: Size of input buffer |
| 183 | * outsize: Size of output buffer | ||
| 133 | * | 184 | * |
| 134 | * returns zero on success | 185 | * returns zero on success |
| 135 | * an HP WMI query specific error code (which is positive) | 186 | * an HP WMI query specific error code (which is positive) |
| @@ -140,25 +191,29 @@ static struct platform_driver hp_wmi_driver = { | |||
| 140 | * size. E.g. Battery info query (0x7) is defined to have 1 byte input | 191 | * size. E.g. Battery info query (0x7) is defined to have 1 byte input |
| 141 | * and 128 byte output. The caller would do: | 192 | * and 128 byte output. The caller would do: |
| 142 | * buffer = kzalloc(128, GFP_KERNEL); | 193 | * buffer = kzalloc(128, GFP_KERNEL); |
| 143 | * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) | 194 | * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) |
| 144 | */ | 195 | */ |
| 145 | static int hp_wmi_perform_query(int query, int write, u32 *buffer, | 196 | static int hp_wmi_perform_query(int query, int write, void *buffer, |
| 146 | int buffersize) | 197 | int insize, int outsize) |
| 147 | { | 198 | { |
| 148 | struct bios_return bios_return; | 199 | struct bios_return *bios_return; |
| 149 | acpi_status status; | 200 | int actual_outsize; |
| 150 | union acpi_object *obj; | 201 | union acpi_object *obj; |
| 151 | struct bios_args args = { | 202 | struct bios_args args = { |
| 152 | .signature = 0x55434553, | 203 | .signature = 0x55434553, |
| 153 | .command = write ? 0x2 : 0x1, | 204 | .command = write ? 0x2 : 0x1, |
| 154 | .commandtype = query, | 205 | .commandtype = query, |
| 155 | .datasize = buffersize, | 206 | .datasize = insize, |
| 156 | .data = *buffer, | 207 | .data = 0, |
| 157 | }; | 208 | }; |
| 158 | struct acpi_buffer input = { sizeof(struct bios_args), &args }; | 209 | struct acpi_buffer input = { sizeof(struct bios_args), &args }; |
| 159 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | 210 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 160 | 211 | ||
| 161 | status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); | 212 | if (WARN_ON(insize > sizeof(args.data))) |
| 213 | return -EINVAL; | ||
| 214 | memcpy(&args.data, buffer, insize); | ||
| 215 | |||
| 216 | wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); | ||
| 162 | 217 | ||
| 163 | obj = output.pointer; | 218 | obj = output.pointer; |
| 164 | 219 | ||
| @@ -169,10 +224,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, | |||
| 169 | return -EINVAL; | 224 | return -EINVAL; |
| 170 | } | 225 | } |
| 171 | 226 | ||
| 172 | bios_return = *((struct bios_return *)obj->buffer.pointer); | 227 | bios_return = (struct bios_return *)obj->buffer.pointer; |
| 173 | 228 | ||
| 174 | memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); | 229 | if (bios_return->return_code) { |
| 230 | if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE) | ||
| 231 | printk(KERN_WARNING PREFIX "query 0x%x returned " | ||
| 232 | "error 0x%x\n", | ||
| 233 | query, bios_return->return_code); | ||
| 234 | kfree(obj); | ||
| 235 | return bios_return->return_code; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (!outsize) { | ||
| 239 | /* ignore output data */ | ||
| 240 | kfree(obj); | ||
| 241 | return 0; | ||
| 242 | } | ||
| 175 | 243 | ||
| 244 | actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); | ||
| 245 | memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); | ||
| 246 | memset(buffer + actual_outsize, 0, outsize - actual_outsize); | ||
| 176 | kfree(obj); | 247 | kfree(obj); |
| 177 | return 0; | 248 | return 0; |
| 178 | } | 249 | } |
| @@ -181,7 +252,7 @@ static int hp_wmi_display_state(void) | |||
| 181 | { | 252 | { |
| 182 | int state = 0; | 253 | int state = 0; |
| 183 | int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, | 254 | int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, |
| 184 | sizeof(state)); | 255 | sizeof(state), sizeof(state)); |
| 185 | if (ret) | 256 | if (ret) |
| 186 | return -EINVAL; | 257 | return -EINVAL; |
| 187 | return state; | 258 | return state; |
| @@ -191,7 +262,7 @@ static int hp_wmi_hddtemp_state(void) | |||
| 191 | { | 262 | { |
| 192 | int state = 0; | 263 | int state = 0; |
| 193 | int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, | 264 | int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, |
| 194 | sizeof(state)); | 265 | sizeof(state), sizeof(state)); |
| 195 | if (ret) | 266 | if (ret) |
| 196 | return -EINVAL; | 267 | return -EINVAL; |
| 197 | return state; | 268 | return state; |
| @@ -201,7 +272,7 @@ static int hp_wmi_als_state(void) | |||
| 201 | { | 272 | { |
| 202 | int state = 0; | 273 | int state = 0; |
| 203 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, | 274 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, |
| 204 | sizeof(state)); | 275 | sizeof(state), sizeof(state)); |
| 205 | if (ret) | 276 | if (ret) |
| 206 | return -EINVAL; | 277 | return -EINVAL; |
| 207 | return state; | 278 | return state; |
| @@ -211,7 +282,7 @@ static int hp_wmi_dock_state(void) | |||
| 211 | { | 282 | { |
| 212 | int state = 0; | 283 | int state = 0; |
| 213 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, | 284 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, |
| 214 | sizeof(state)); | 285 | sizeof(state), sizeof(state)); |
| 215 | 286 | ||
| 216 | if (ret) | 287 | if (ret) |
| 217 | return -EINVAL; | 288 | return -EINVAL; |
| @@ -223,7 +294,7 @@ static int hp_wmi_tablet_state(void) | |||
| 223 | { | 294 | { |
| 224 | int state = 0; | 295 | int state = 0; |
| 225 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, | 296 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, |
| 226 | sizeof(state)); | 297 | sizeof(state), sizeof(state)); |
| 227 | if (ret) | 298 | if (ret) |
| 228 | return ret; | 299 | return ret; |
| 229 | 300 | ||
| @@ -237,7 +308,7 @@ static int hp_wmi_set_block(void *data, bool blocked) | |||
| 237 | int ret; | 308 | int ret; |
| 238 | 309 | ||
| 239 | ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, | 310 | ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, |
| 240 | &query, sizeof(query)); | 311 | &query, sizeof(query), 0); |
| 241 | if (ret) | 312 | if (ret) |
| 242 | return -EINVAL; | 313 | return -EINVAL; |
| 243 | return 0; | 314 | return 0; |
| @@ -252,7 +323,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) | |||
| 252 | int wireless = 0; | 323 | int wireless = 0; |
| 253 | int mask; | 324 | int mask; |
| 254 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, | 325 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, |
| 255 | &wireless, sizeof(wireless)); | 326 | &wireless, sizeof(wireless), |
| 327 | sizeof(wireless)); | ||
| 256 | /* TBD: Pass error */ | 328 | /* TBD: Pass error */ |
| 257 | 329 | ||
| 258 | mask = 0x200 << (r * 8); | 330 | mask = 0x200 << (r * 8); |
| @@ -268,7 +340,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) | |||
| 268 | int wireless = 0; | 340 | int wireless = 0; |
| 269 | int mask; | 341 | int mask; |
| 270 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, | 342 | hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, |
| 271 | &wireless, sizeof(wireless)); | 343 | &wireless, sizeof(wireless), |
| 344 | sizeof(wireless)); | ||
| 272 | /* TBD: Pass error */ | 345 | /* TBD: Pass error */ |
| 273 | 346 | ||
| 274 | mask = 0x800 << (r * 8); | 347 | mask = 0x800 << (r * 8); |
| @@ -279,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) | |||
| 279 | return true; | 352 | return true; |
| 280 | } | 353 | } |
| 281 | 354 | ||
| 355 | static int hp_wmi_rfkill2_set_block(void *data, bool blocked) | ||
| 356 | { | ||
| 357 | int rfkill_id = (int)(long)data; | ||
| 358 | char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; | ||
| 359 | |||
| 360 | if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, | ||
| 361 | buffer, sizeof(buffer), 0)) | ||
| 362 | return -EINVAL; | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | static const struct rfkill_ops hp_wmi_rfkill2_ops = { | ||
| 367 | .set_block = hp_wmi_rfkill2_set_block, | ||
| 368 | }; | ||
| 369 | |||
| 370 | static int hp_wmi_rfkill2_refresh(void) | ||
| 371 | { | ||
| 372 | int err, i; | ||
| 373 | struct bios_rfkill2_state state; | ||
| 374 | |||
| 375 | err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, | ||
| 376 | 0, sizeof(state)); | ||
| 377 | if (err) | ||
| 378 | return err; | ||
| 379 | |||
| 380 | for (i = 0; i < rfkill2_count; i++) { | ||
| 381 | int num = rfkill2[i].num; | ||
| 382 | struct bios_rfkill2_device_state *devstate; | ||
| 383 | devstate = &state.device[num]; | ||
| 384 | |||
| 385 | if (num >= state.count || | ||
| 386 | devstate->rfkill_id != rfkill2[i].id) { | ||
| 387 | printk(KERN_WARNING PREFIX "power configuration of " | ||
| 388 | "the wireless devices unexpectedly changed\n"); | ||
| 389 | continue; | ||
| 390 | } | ||
| 391 | |||
| 392 | rfkill_set_states(rfkill2[i].rfkill, | ||
| 393 | IS_SWBLOCKED(devstate->power), | ||
| 394 | IS_HWBLOCKED(devstate->power)); | ||
| 395 | } | ||
| 396 | |||
| 397 | return 0; | ||
| 398 | } | ||
| 399 | |||
| 282 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, | 400 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, |
| 283 | char *buf) | 401 | char *buf) |
| 284 | { | 402 | { |
| @@ -329,7 +447,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, | |||
| 329 | { | 447 | { |
| 330 | u32 tmp = simple_strtoul(buf, NULL, 10); | 448 | u32 tmp = simple_strtoul(buf, NULL, 10); |
| 331 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, | 449 | int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, |
| 332 | sizeof(tmp)); | 450 | sizeof(tmp), sizeof(tmp)); |
| 333 | if (ret) | 451 | if (ret) |
| 334 | return -EINVAL; | 452 | return -EINVAL; |
| 335 | 453 | ||
| @@ -402,6 +520,7 @@ static void hp_wmi_notify(u32 value, void *context) | |||
| 402 | case HPWMI_BEZEL_BUTTON: | 520 | case HPWMI_BEZEL_BUTTON: |
| 403 | ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, | 521 | ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, |
| 404 | &key_code, | 522 | &key_code, |
| 523 | sizeof(key_code), | ||
| 405 | sizeof(key_code)); | 524 | sizeof(key_code)); |
| 406 | if (ret) | 525 | if (ret) |
| 407 | break; | 526 | break; |
| @@ -412,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context) | |||
| 412 | key_code); | 531 | key_code); |
| 413 | break; | 532 | break; |
| 414 | case HPWMI_WIRELESS: | 533 | case HPWMI_WIRELESS: |
| 534 | if (rfkill2_count) { | ||
| 535 | hp_wmi_rfkill2_refresh(); | ||
| 536 | break; | ||
| 537 | } | ||
| 538 | |||
| 415 | if (wifi_rfkill) | 539 | if (wifi_rfkill) |
| 416 | rfkill_set_states(wifi_rfkill, | 540 | rfkill_set_states(wifi_rfkill, |
| 417 | hp_wmi_get_sw_state(HPWMI_WIFI), | 541 | hp_wmi_get_sw_state(HPWMI_WIFI), |
| @@ -502,32 +626,16 @@ static void cleanup_sysfs(struct platform_device *device) | |||
| 502 | device_remove_file(&device->dev, &dev_attr_tablet); | 626 | device_remove_file(&device->dev, &dev_attr_tablet); |
| 503 | } | 627 | } |
| 504 | 628 | ||
| 505 | static int __devinit hp_wmi_bios_setup(struct platform_device *device) | 629 | static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) |
| 506 | { | 630 | { |
| 507 | int err; | 631 | int err; |
| 508 | int wireless = 0; | 632 | int wireless = 0; |
| 509 | 633 | ||
| 510 | err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, | 634 | err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, |
| 511 | sizeof(wireless)); | 635 | sizeof(wireless), sizeof(wireless)); |
| 512 | if (err) | 636 | if (err) |
| 513 | return err; | 637 | return err; |
| 514 | 638 | ||
| 515 | err = device_create_file(&device->dev, &dev_attr_display); | ||
| 516 | if (err) | ||
| 517 | goto add_sysfs_error; | ||
| 518 | err = device_create_file(&device->dev, &dev_attr_hddtemp); | ||
| 519 | if (err) | ||
| 520 | goto add_sysfs_error; | ||
| 521 | err = device_create_file(&device->dev, &dev_attr_als); | ||
| 522 | if (err) | ||
| 523 | goto add_sysfs_error; | ||
| 524 | err = device_create_file(&device->dev, &dev_attr_dock); | ||
| 525 | if (err) | ||
| 526 | goto add_sysfs_error; | ||
| 527 | err = device_create_file(&device->dev, &dev_attr_tablet); | ||
| 528 | if (err) | ||
| 529 | goto add_sysfs_error; | ||
| 530 | |||
| 531 | if (wireless & 0x1) { | 639 | if (wireless & 0x1) { |
| 532 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, | 640 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
| 533 | RFKILL_TYPE_WLAN, | 641 | RFKILL_TYPE_WLAN, |
| @@ -573,14 +681,131 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) | |||
| 573 | return 0; | 681 | return 0; |
| 574 | register_wwan_err: | 682 | register_wwan_err: |
| 575 | rfkill_destroy(wwan_rfkill); | 683 | rfkill_destroy(wwan_rfkill); |
| 684 | wwan_rfkill = NULL; | ||
| 576 | if (bluetooth_rfkill) | 685 | if (bluetooth_rfkill) |
| 577 | rfkill_unregister(bluetooth_rfkill); | 686 | rfkill_unregister(bluetooth_rfkill); |
| 578 | register_bluetooth_error: | 687 | register_bluetooth_error: |
| 579 | rfkill_destroy(bluetooth_rfkill); | 688 | rfkill_destroy(bluetooth_rfkill); |
| 689 | bluetooth_rfkill = NULL; | ||
| 580 | if (wifi_rfkill) | 690 | if (wifi_rfkill) |
| 581 | rfkill_unregister(wifi_rfkill); | 691 | rfkill_unregister(wifi_rfkill); |
| 582 | register_wifi_error: | 692 | register_wifi_error: |
| 583 | rfkill_destroy(wifi_rfkill); | 693 | rfkill_destroy(wifi_rfkill); |
| 694 | wifi_rfkill = NULL; | ||
| 695 | return err; | ||
| 696 | } | ||
| 697 | |||
| 698 | static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device) | ||
| 699 | { | ||
| 700 | int err, i; | ||
| 701 | struct bios_rfkill2_state state; | ||
| 702 | err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, | ||
| 703 | 0, sizeof(state)); | ||
| 704 | if (err) | ||
| 705 | return err; | ||
| 706 | |||
| 707 | if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { | ||
| 708 | printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n"); | ||
| 709 | return -EINVAL; | ||
| 710 | } | ||
| 711 | |||
| 712 | for (i = 0; i < state.count; i++) { | ||
| 713 | struct rfkill *rfkill; | ||
| 714 | enum rfkill_type type; | ||
| 715 | char *name; | ||
| 716 | switch (state.device[i].radio_type) { | ||
| 717 | case HPWMI_WIFI: | ||
| 718 | type = RFKILL_TYPE_WLAN; | ||
| 719 | name = "hp-wifi"; | ||
| 720 | break; | ||
| 721 | case HPWMI_BLUETOOTH: | ||
| 722 | type = RFKILL_TYPE_BLUETOOTH; | ||
| 723 | name = "hp-bluetooth"; | ||
| 724 | break; | ||
| 725 | case HPWMI_WWAN: | ||
| 726 | type = RFKILL_TYPE_WWAN; | ||
| 727 | name = "hp-wwan"; | ||
| 728 | break; | ||
| 729 | default: | ||
| 730 | printk(KERN_WARNING PREFIX "unknown device type 0x%x\n", | ||
| 731 | state.device[i].radio_type); | ||
| 732 | continue; | ||
| 733 | } | ||
| 734 | |||
| 735 | if (!state.device[i].vendor_id) { | ||
| 736 | printk(KERN_WARNING PREFIX "zero device %d while %d " | ||
| 737 | "reported\n", i, state.count); | ||
| 738 | continue; | ||
| 739 | } | ||
| 740 | |||
| 741 | rfkill = rfkill_alloc(name, &device->dev, type, | ||
| 742 | &hp_wmi_rfkill2_ops, (void *)(long)i); | ||
| 743 | if (!rfkill) { | ||
| 744 | err = -ENOMEM; | ||
| 745 | goto fail; | ||
| 746 | } | ||
| 747 | |||
| 748 | rfkill2[rfkill2_count].id = state.device[i].rfkill_id; | ||
| 749 | rfkill2[rfkill2_count].num = i; | ||
| 750 | rfkill2[rfkill2_count].rfkill = rfkill; | ||
| 751 | |||
| 752 | rfkill_init_sw_state(rfkill, | ||
| 753 | IS_SWBLOCKED(state.device[i].power)); | ||
| 754 | rfkill_set_hw_state(rfkill, | ||
| 755 | IS_HWBLOCKED(state.device[i].power)); | ||
| 756 | |||
| 757 | if (!(state.device[i].power & HPWMI_POWER_BIOS)) | ||
| 758 | printk(KERN_INFO PREFIX "device %s blocked by BIOS\n", | ||
| 759 | name); | ||
| 760 | |||
| 761 | err = rfkill_register(rfkill); | ||
| 762 | if (err) { | ||
| 763 | rfkill_destroy(rfkill); | ||
| 764 | goto fail; | ||
| 765 | } | ||
| 766 | |||
| 767 | rfkill2_count++; | ||
| 768 | } | ||
| 769 | |||
| 770 | return 0; | ||
| 771 | fail: | ||
| 772 | for (; rfkill2_count > 0; rfkill2_count--) { | ||
| 773 | rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); | ||
| 774 | rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); | ||
| 775 | } | ||
| 776 | return err; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int __devinit hp_wmi_bios_setup(struct platform_device *device) | ||
| 780 | { | ||
| 781 | int err; | ||
| 782 | |||
| 783 | /* clear detected rfkill devices */ | ||
| 784 | wifi_rfkill = NULL; | ||
| 785 | bluetooth_rfkill = NULL; | ||
| 786 | wwan_rfkill = NULL; | ||
| 787 | rfkill2_count = 0; | ||
| 788 | |||
| 789 | if (hp_wmi_rfkill_setup(device)) | ||
| 790 | hp_wmi_rfkill2_setup(device); | ||
| 791 | |||
| 792 | err = device_create_file(&device->dev, &dev_attr_display); | ||
| 793 | if (err) | ||
| 794 | goto add_sysfs_error; | ||
| 795 | err = device_create_file(&device->dev, &dev_attr_hddtemp); | ||
| 796 | if (err) | ||
| 797 | goto add_sysfs_error; | ||
| 798 | err = device_create_file(&device->dev, &dev_attr_als); | ||
| 799 | if (err) | ||
| 800 | goto add_sysfs_error; | ||
| 801 | err = device_create_file(&device->dev, &dev_attr_dock); | ||
| 802 | if (err) | ||
| 803 | goto add_sysfs_error; | ||
| 804 | err = device_create_file(&device->dev, &dev_attr_tablet); | ||
| 805 | if (err) | ||
| 806 | goto add_sysfs_error; | ||
| 807 | return 0; | ||
| 808 | |||
| 584 | add_sysfs_error: | 809 | add_sysfs_error: |
| 585 | cleanup_sysfs(device); | 810 | cleanup_sysfs(device); |
| 586 | return err; | 811 | return err; |
| @@ -588,8 +813,14 @@ add_sysfs_error: | |||
| 588 | 813 | ||
| 589 | static int __exit hp_wmi_bios_remove(struct platform_device *device) | 814 | static int __exit hp_wmi_bios_remove(struct platform_device *device) |
| 590 | { | 815 | { |
| 816 | int i; | ||
| 591 | cleanup_sysfs(device); | 817 | cleanup_sysfs(device); |
| 592 | 818 | ||
| 819 | for (i = 0; i < rfkill2_count; i++) { | ||
| 820 | rfkill_unregister(rfkill2[i].rfkill); | ||
| 821 | rfkill_destroy(rfkill2[i].rfkill); | ||
| 822 | } | ||
| 823 | |||
| 593 | if (wifi_rfkill) { | 824 | if (wifi_rfkill) { |
| 594 | rfkill_unregister(wifi_rfkill); | 825 | rfkill_unregister(wifi_rfkill); |
| 595 | rfkill_destroy(wifi_rfkill); | 826 | rfkill_destroy(wifi_rfkill); |
| @@ -622,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device) | |||
| 622 | input_sync(hp_wmi_input_dev); | 853 | input_sync(hp_wmi_input_dev); |
| 623 | } | 854 | } |
| 624 | 855 | ||
| 856 | if (rfkill2_count) | ||
| 857 | hp_wmi_rfkill2_refresh(); | ||
| 858 | |||
| 625 | if (wifi_rfkill) | 859 | if (wifi_rfkill) |
| 626 | rfkill_set_states(wifi_rfkill, | 860 | rfkill_set_states(wifi_rfkill, |
| 627 | hp_wmi_get_sw_state(HPWMI_WIFI), | 861 | hp_wmi_get_sw_state(HPWMI_WIFI), |
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 114d95247cdf..21b101899bae 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
| @@ -459,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) | |||
| 459 | if (test_bit(vpc_bit, &vpc1)) { | 459 | if (test_bit(vpc_bit, &vpc1)) { |
| 460 | if (vpc_bit == 9) | 460 | if (vpc_bit == 9) |
| 461 | ideapad_sync_rfk_state(adevice); | 461 | ideapad_sync_rfk_state(adevice); |
| 462 | else if (vpc_bit == 4) | ||
| 463 | read_ec_data(handle, 0x12, &vpc2); | ||
| 462 | else | 464 | else |
| 463 | ideapad_input_report(priv, vpc_bit); | 465 | ideapad_input_report(priv, vpc_bit); |
| 464 | } | 466 | } |
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 1294a39373ba..85c8ad43c0c5 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c | |||
| @@ -1111,7 +1111,7 @@ static int ips_monitor(void *data) | |||
| 1111 | last_msecs = jiffies_to_msecs(jiffies); | 1111 | last_msecs = jiffies_to_msecs(jiffies); |
| 1112 | expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); | 1112 | expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); |
| 1113 | 1113 | ||
| 1114 | __set_current_state(TASK_UNINTERRUPTIBLE); | 1114 | __set_current_state(TASK_INTERRUPTIBLE); |
| 1115 | mod_timer(&timer, expire); | 1115 | mod_timer(&timer, expire); |
| 1116 | schedule(); | 1116 | schedule(); |
| 1117 | 1117 | ||
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c new file mode 100644 index 000000000000..213e79ba68d5 --- /dev/null +++ b/drivers/platform/x86/intel_mid_powerbtn.c | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | /* | ||
| 2 | * Power button driver for Medfield. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Intel Corp | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; version 2 of the License. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License along | ||
| 16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 17 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/platform_device.h> | ||
| 25 | #include <linux/input.h> | ||
| 26 | #include <asm/intel_scu_ipc.h> | ||
| 27 | |||
| 28 | #define DRIVER_NAME "msic_power_btn" | ||
| 29 | |||
| 30 | #define MSIC_IRQ_STAT 0x02 | ||
| 31 | #define MSIC_IRQ_PB (1 << 0) | ||
| 32 | #define MSIC_PB_CONFIG 0x3e | ||
| 33 | #define MSIC_PB_STATUS 0x3f | ||
| 34 | #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ | ||
| 35 | |||
| 36 | struct mfld_pb_priv { | ||
| 37 | struct input_dev *input; | ||
| 38 | unsigned int irq; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static irqreturn_t mfld_pb_isr(int irq, void *dev_id) | ||
| 42 | { | ||
| 43 | struct mfld_pb_priv *priv = dev_id; | ||
| 44 | int ret; | ||
| 45 | u8 pbstat; | ||
| 46 | |||
| 47 | ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); | ||
| 48 | if (ret < 0) | ||
| 49 | return IRQ_HANDLED; | ||
| 50 | |||
| 51 | input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL)); | ||
| 52 | input_sync(priv->input); | ||
| 53 | |||
| 54 | return IRQ_HANDLED; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int __devinit mfld_pb_probe(struct platform_device *pdev) | ||
| 58 | { | ||
| 59 | struct mfld_pb_priv *priv; | ||
| 60 | struct input_dev *input; | ||
| 61 | int irq; | ||
| 62 | int error; | ||
| 63 | |||
| 64 | irq = platform_get_irq(pdev, 0); | ||
| 65 | if (irq < 0) | ||
| 66 | return -EINVAL; | ||
| 67 | |||
| 68 | priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL); | ||
| 69 | input = input_allocate_device(); | ||
| 70 | if (!priv || !input) { | ||
| 71 | error = -ENOMEM; | ||
| 72 | goto err_free_mem; | ||
| 73 | } | ||
| 74 | |||
| 75 | priv->input = input; | ||
| 76 | priv->irq = irq; | ||
| 77 | |||
| 78 | input->name = pdev->name; | ||
| 79 | input->phys = "power-button/input0"; | ||
| 80 | input->id.bustype = BUS_HOST; | ||
| 81 | input->dev.parent = &pdev->dev; | ||
| 82 | |||
| 83 | input_set_capability(input, EV_KEY, KEY_POWER); | ||
| 84 | |||
| 85 | error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr, | ||
| 86 | 0, DRIVER_NAME, priv); | ||
| 87 | if (error) { | ||
| 88 | dev_err(&pdev->dev, | ||
| 89 | "unable to request irq %d for mfld power button\n", | ||
| 90 | irq); | ||
| 91 | goto err_free_mem; | ||
| 92 | } | ||
| 93 | |||
| 94 | error = input_register_device(input); | ||
| 95 | if (error) { | ||
| 96 | dev_err(&pdev->dev, | ||
| 97 | "unable to register input dev, error %d\n", error); | ||
| 98 | goto err_free_irq; | ||
| 99 | } | ||
| 100 | |||
| 101 | platform_set_drvdata(pdev, priv); | ||
| 102 | return 0; | ||
| 103 | |||
| 104 | err_free_irq: | ||
| 105 | free_irq(priv->irq, priv); | ||
| 106 | err_free_mem: | ||
| 107 | input_free_device(input); | ||
| 108 | kfree(priv); | ||
| 109 | return error; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int __devexit mfld_pb_remove(struct platform_device *pdev) | ||
| 113 | { | ||
| 114 | struct mfld_pb_priv *priv = platform_get_drvdata(pdev); | ||
| 115 | |||
| 116 | free_irq(priv->irq, priv); | ||
| 117 | input_unregister_device(priv->input); | ||
| 118 | kfree(priv); | ||
| 119 | |||
| 120 | platform_set_drvdata(pdev, NULL); | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static struct platform_driver mfld_pb_driver = { | ||
| 125 | .driver = { | ||
| 126 | .name = DRIVER_NAME, | ||
| 127 | .owner = THIS_MODULE, | ||
| 128 | }, | ||
| 129 | .probe = mfld_pb_probe, | ||
| 130 | .remove = __devexit_p(mfld_pb_remove), | ||
| 131 | }; | ||
| 132 | |||
| 133 | static int __init mfld_pb_init(void) | ||
| 134 | { | ||
| 135 | return platform_driver_register(&mfld_pb_driver); | ||
| 136 | } | ||
| 137 | module_init(mfld_pb_init); | ||
| 138 | |||
| 139 | static void __exit mfld_pb_exit(void) | ||
| 140 | { | ||
| 141 | platform_driver_unregister(&mfld_pb_driver); | ||
| 142 | } | ||
| 143 | module_exit(mfld_pb_exit); | ||
| 144 | |||
| 145 | MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>"); | ||
| 146 | MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); | ||
| 147 | MODULE_LICENSE("GPL v2"); | ||
| 148 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c new file mode 100644 index 000000000000..6c12db503161 --- /dev/null +++ b/drivers/platform/x86/intel_mid_thermal.c | |||
| @@ -0,0 +1,576 @@ | |||
| 1 | /* | ||
| 2 | * intel_mid_thermal.c - Intel MID platform thermal driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Intel Corporation | ||
| 5 | * | ||
| 6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 19 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
| 20 | * | ||
| 21 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 22 | * Author: Durgadoss R <durgadoss.r@intel.com> | ||
| 23 | */ | ||
| 24 | |||
| 25 | #define pr_fmt(fmt) "intel_mid_thermal: " fmt | ||
| 26 | |||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/err.h> | ||
| 30 | #include <linux/param.h> | ||
| 31 | #include <linux/device.h> | ||
| 32 | #include <linux/platform_device.h> | ||
| 33 | #include <linux/slab.h> | ||
| 34 | #include <linux/pm.h> | ||
| 35 | #include <linux/thermal.h> | ||
| 36 | |||
| 37 | #include <asm/intel_scu_ipc.h> | ||
| 38 | |||
| 39 | /* Number of thermal sensors */ | ||
| 40 | #define MSIC_THERMAL_SENSORS 4 | ||
| 41 | |||
| 42 | /* ADC1 - thermal registers */ | ||
| 43 | #define MSIC_THERM_ADC1CNTL1 0x1C0 | ||
| 44 | #define MSIC_ADC_ENBL 0x10 | ||
| 45 | #define MSIC_ADC_START 0x08 | ||
| 46 | |||
| 47 | #define MSIC_THERM_ADC1CNTL3 0x1C2 | ||
| 48 | #define MSIC_ADCTHERM_ENBL 0x04 | ||
| 49 | #define MSIC_ADCRRDATA_ENBL 0x05 | ||
| 50 | #define MSIC_CHANL_MASK_VAL 0x0F | ||
| 51 | |||
| 52 | #define MSIC_STOPBIT_MASK 16 | ||
| 53 | #define MSIC_ADCTHERM_MASK 4 | ||
| 54 | #define ADC_CHANLS_MAX 15 /* Number of ADC channels */ | ||
| 55 | #define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS) | ||
| 56 | |||
| 57 | /* ADC channel code values */ | ||
| 58 | #define SKIN_SENSOR0_CODE 0x08 | ||
| 59 | #define SKIN_SENSOR1_CODE 0x09 | ||
| 60 | #define SYS_SENSOR_CODE 0x0A | ||
| 61 | #define MSIC_DIE_SENSOR_CODE 0x03 | ||
| 62 | |||
| 63 | #define SKIN_THERM_SENSOR0 0 | ||
| 64 | #define SKIN_THERM_SENSOR1 1 | ||
| 65 | #define SYS_THERM_SENSOR2 2 | ||
| 66 | #define MSIC_DIE_THERM_SENSOR3 3 | ||
| 67 | |||
| 68 | /* ADC code range */ | ||
| 69 | #define ADC_MAX 977 | ||
| 70 | #define ADC_MIN 162 | ||
| 71 | #define ADC_VAL0C 887 | ||
| 72 | #define ADC_VAL20C 720 | ||
| 73 | #define ADC_VAL40C 508 | ||
| 74 | #define ADC_VAL60C 315 | ||
| 75 | |||
| 76 | /* ADC base addresses */ | ||
| 77 | #define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ | ||
| 78 | #define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ | ||
| 79 | |||
| 80 | /* MSIC die attributes */ | ||
| 81 | #define MSIC_DIE_ADC_MIN 488 | ||
| 82 | #define MSIC_DIE_ADC_MAX 1004 | ||
| 83 | |||
| 84 | /* This holds the address of the first free ADC channel, | ||
| 85 | * among the 15 channels | ||
| 86 | */ | ||
| 87 | static int channel_index; | ||
| 88 | |||
| 89 | struct platform_info { | ||
| 90 | struct platform_device *pdev; | ||
| 91 | struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS]; | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct thermal_device_info { | ||
| 95 | unsigned int chnl_addr; | ||
| 96 | int direct; | ||
| 97 | /* This holds the current temperature in millidegree celsius */ | ||
| 98 | long curr_temp; | ||
| 99 | }; | ||
| 100 | |||
| 101 | /** | ||
| 102 | * to_msic_die_temp - converts adc_val to msic_die temperature | ||
| 103 | * @adc_val: ADC value to be converted | ||
| 104 | * | ||
| 105 | * Can sleep | ||
| 106 | */ | ||
| 107 | static int to_msic_die_temp(uint16_t adc_val) | ||
| 108 | { | ||
| 109 | return (368 * (adc_val) / 1000) - 220; | ||
| 110 | } | ||
| 111 | |||
| 112 | /** | ||
| 113 | * is_valid_adc - checks whether the adc code is within the defined range | ||
| 114 | * @min: minimum value for the sensor | ||
| 115 | * @max: maximum value for the sensor | ||
| 116 | * | ||
| 117 | * Can sleep | ||
| 118 | */ | ||
| 119 | static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max) | ||
| 120 | { | ||
| 121 | return (adc_val >= min) && (adc_val <= max); | ||
| 122 | } | ||
| 123 | |||
| 124 | /** | ||
| 125 | * adc_to_temp - converts the ADC code to temperature in C | ||
| 126 | * @direct: true if ths channel is direct index | ||
| 127 | * @adc_val: the adc_val that needs to be converted | ||
| 128 | * @tp: temperature return value | ||
| 129 | * | ||
| 130 | * Linear approximation is used to covert the skin adc value into temperature. | ||
| 131 | * This technique is used to avoid very long look-up table to get | ||
| 132 | * the appropriate temp value from ADC value. | ||
| 133 | * The adc code vs sensor temp curve is split into five parts | ||
| 134 | * to achieve very close approximate temp value with less than | ||
| 135 | * 0.5C error | ||
| 136 | */ | ||
| 137 | static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp) | ||
| 138 | { | ||
| 139 | int temp; | ||
| 140 | |||
| 141 | /* Direct conversion for die temperature */ | ||
| 142 | if (direct) { | ||
| 143 | if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) { | ||
| 144 | *tp = to_msic_die_temp(adc_val) * 1000; | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | return -ERANGE; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX)) | ||
| 151 | return -ERANGE; | ||
| 152 | |||
| 153 | /* Linear approximation for skin temperature */ | ||
| 154 | if (adc_val > ADC_VAL0C) | ||
| 155 | temp = 177 - (adc_val/5); | ||
| 156 | else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C)) | ||
| 157 | temp = 111 - (adc_val/8); | ||
| 158 | else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C)) | ||
| 159 | temp = 92 - (adc_val/10); | ||
| 160 | else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C)) | ||
| 161 | temp = 91 - (adc_val/10); | ||
| 162 | else | ||
| 163 | temp = 112 - (adc_val/6); | ||
| 164 | |||
| 165 | /* Convert temperature in celsius to milli degree celsius */ | ||
| 166 | *tp = temp * 1000; | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * mid_read_temp - read sensors for temperature | ||
| 172 | * @temp: holds the current temperature for the sensor after reading | ||
| 173 | * | ||
| 174 | * reads the adc_code from the channel and converts it to real | ||
| 175 | * temperature. The converted value is stored in temp. | ||
| 176 | * | ||
| 177 | * Can sleep | ||
| 178 | */ | ||
| 179 | static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) | ||
| 180 | { | ||
| 181 | struct thermal_device_info *td_info = tzd->devdata; | ||
| 182 | uint16_t adc_val, addr; | ||
| 183 | uint8_t data = 0; | ||
| 184 | int ret; | ||
| 185 | unsigned long curr_temp; | ||
| 186 | |||
| 187 | |||
| 188 | addr = td_info->chnl_addr; | ||
| 189 | |||
| 190 | /* Enable the msic for conversion before reading */ | ||
| 191 | ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); | ||
| 192 | if (ret) | ||
| 193 | return ret; | ||
| 194 | |||
| 195 | /* Re-toggle the RRDATARD bit (temporary workaround) */ | ||
| 196 | ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); | ||
| 197 | if (ret) | ||
| 198 | return ret; | ||
| 199 | |||
| 200 | /* Read the higher bits of data */ | ||
| 201 | ret = intel_scu_ipc_ioread8(addr, &data); | ||
| 202 | if (ret) | ||
| 203 | return ret; | ||
| 204 | |||
| 205 | /* Shift bits to accomodate the lower two data bits */ | ||
| 206 | adc_val = (data << 2); | ||
| 207 | addr++; | ||
| 208 | |||
| 209 | ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ | ||
| 210 | if (ret) | ||
| 211 | return ret; | ||
| 212 | |||
| 213 | /* Adding lower two bits to the higher bits */ | ||
| 214 | data &= 03; | ||
| 215 | adc_val += data; | ||
| 216 | |||
| 217 | /* Convert ADC value to temperature */ | ||
| 218 | ret = adc_to_temp(td_info->direct, adc_val, &curr_temp); | ||
| 219 | if (ret == 0) | ||
| 220 | *temp = td_info->curr_temp = curr_temp; | ||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | |||
| 224 | /** | ||
| 225 | * configure_adc - enables/disables the ADC for conversion | ||
| 226 | * @val: zero: disables the ADC non-zero:enables the ADC | ||
| 227 | * | ||
| 228 | * Enable/Disable the ADC depending on the argument | ||
| 229 | * | ||
| 230 | * Can sleep | ||
| 231 | */ | ||
| 232 | static int configure_adc(int val) | ||
| 233 | { | ||
| 234 | int ret; | ||
| 235 | uint8_t data; | ||
| 236 | |||
| 237 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); | ||
| 238 | if (ret) | ||
| 239 | return ret; | ||
| 240 | |||
| 241 | if (val) { | ||
| 242 | /* Enable and start the ADC */ | ||
| 243 | data |= (MSIC_ADC_ENBL | MSIC_ADC_START); | ||
| 244 | } else { | ||
| 245 | /* Just stop the ADC */ | ||
| 246 | data &= (~MSIC_ADC_START); | ||
| 247 | } | ||
| 248 | |||
| 249 | return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); | ||
| 250 | } | ||
| 251 | |||
| 252 | /** | ||
| 253 | * set_up_therm_channel - enable thermal channel for conversion | ||
| 254 | * @base_addr: index of free msic ADC channel | ||
| 255 | * | ||
| 256 | * Enable all the three channels for conversion | ||
| 257 | * | ||
| 258 | * Can sleep | ||
| 259 | */ | ||
| 260 | static int set_up_therm_channel(u16 base_addr) | ||
| 261 | { | ||
| 262 | int ret; | ||
| 263 | |||
| 264 | /* Enable all the sensor channels */ | ||
| 265 | ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE); | ||
| 266 | if (ret) | ||
| 267 | return ret; | ||
| 268 | |||
| 269 | ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE); | ||
| 270 | if (ret) | ||
| 271 | return ret; | ||
| 272 | |||
| 273 | ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE); | ||
| 274 | if (ret) | ||
| 275 | return ret; | ||
| 276 | |||
| 277 | /* Since this is the last channel, set the stop bit | ||
| 278 | to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ | ||
| 279 | ret = intel_scu_ipc_iowrite8(base_addr + 3, | ||
| 280 | (MSIC_DIE_SENSOR_CODE | 0x10)); | ||
| 281 | if (ret) | ||
| 282 | return ret; | ||
| 283 | |||
| 284 | /* Enable ADC and start it */ | ||
| 285 | return configure_adc(1); | ||
| 286 | } | ||
| 287 | |||
| 288 | /** | ||
| 289 | * reset_stopbit - sets the stop bit to 0 on the given channel | ||
| 290 | * @addr: address of the channel | ||
| 291 | * | ||
| 292 | * Can sleep | ||
| 293 | */ | ||
| 294 | static int reset_stopbit(uint16_t addr) | ||
| 295 | { | ||
| 296 | int ret; | ||
| 297 | uint8_t data; | ||
| 298 | ret = intel_scu_ipc_ioread8(addr, &data); | ||
| 299 | if (ret) | ||
| 300 | return ret; | ||
| 301 | /* Set the stop bit to zero */ | ||
| 302 | return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); | ||
| 303 | } | ||
| 304 | |||
| 305 | /** | ||
| 306 | * find_free_channel - finds an empty channel for conversion | ||
| 307 | * | ||
| 308 | * If the ADC is not enabled then start using 0th channel | ||
| 309 | * itself. Otherwise find an empty channel by looking for a | ||
| 310 | * channel in which the stopbit is set to 1. returns the index | ||
| 311 | * of the first free channel if succeeds or an error code. | ||
| 312 | * | ||
| 313 | * Context: can sleep | ||
| 314 | * | ||
| 315 | * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc | ||
| 316 | * code. | ||
| 317 | */ | ||
| 318 | static int find_free_channel(void) | ||
| 319 | { | ||
| 320 | int ret; | ||
| 321 | int i; | ||
| 322 | uint8_t data; | ||
| 323 | |||
| 324 | /* check whether ADC is enabled */ | ||
| 325 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); | ||
| 326 | if (ret) | ||
| 327 | return ret; | ||
| 328 | |||
| 329 | if ((data & MSIC_ADC_ENBL) == 0) | ||
| 330 | return 0; | ||
| 331 | |||
| 332 | /* ADC is already enabled; Looking for an empty channel */ | ||
| 333 | for (i = 0; i < ADC_CHANLS_MAX; i++) { | ||
| 334 | ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); | ||
| 335 | if (ret) | ||
| 336 | return ret; | ||
| 337 | |||
| 338 | if (data & MSIC_STOPBIT_MASK) { | ||
| 339 | ret = i; | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | } | ||
| 343 | return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * mid_initialize_adc - initializing the ADC | ||
| 348 | * @dev: our device structure | ||
| 349 | * | ||
| 350 | * Initialize the ADC for reading thermistor values. Can sleep. | ||
| 351 | */ | ||
| 352 | static int mid_initialize_adc(struct device *dev) | ||
| 353 | { | ||
| 354 | u8 data; | ||
| 355 | u16 base_addr; | ||
| 356 | int ret; | ||
| 357 | |||
| 358 | /* | ||
| 359 | * Ensure that adctherm is disabled before we | ||
| 360 | * initialize the ADC | ||
| 361 | */ | ||
| 362 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); | ||
| 363 | if (ret) | ||
| 364 | return ret; | ||
| 365 | |||
| 366 | if (data & MSIC_ADCTHERM_MASK) | ||
| 367 | dev_warn(dev, "ADCTHERM already set"); | ||
| 368 | |||
| 369 | /* Index of the first channel in which the stop bit is set */ | ||
| 370 | channel_index = find_free_channel(); | ||
| 371 | if (channel_index < 0) { | ||
| 372 | dev_err(dev, "No free ADC channels"); | ||
| 373 | return channel_index; | ||
| 374 | } | ||
| 375 | |||
| 376 | base_addr = ADC_CHNL_START_ADDR + channel_index; | ||
| 377 | |||
| 378 | if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { | ||
| 379 | /* Reset stop bit for channels other than 0 and 12 */ | ||
| 380 | ret = reset_stopbit(base_addr); | ||
| 381 | if (ret) | ||
| 382 | return ret; | ||
| 383 | |||
| 384 | /* Index of the first free channel */ | ||
| 385 | base_addr++; | ||
| 386 | channel_index++; | ||
| 387 | } | ||
| 388 | |||
| 389 | ret = set_up_therm_channel(base_addr); | ||
| 390 | if (ret) { | ||
| 391 | dev_err(dev, "unable to enable ADC"); | ||
| 392 | return ret; | ||
| 393 | } | ||
| 394 | dev_dbg(dev, "ADC initialization successful"); | ||
| 395 | return ret; | ||
| 396 | } | ||
| 397 | |||
| 398 | /** | ||
| 399 | * initialize_sensor - sets default temp and timer ranges | ||
| 400 | * @index: index of the sensor | ||
| 401 | * | ||
| 402 | * Context: can sleep | ||
| 403 | */ | ||
| 404 | static struct thermal_device_info *initialize_sensor(int index) | ||
| 405 | { | ||
| 406 | struct thermal_device_info *td_info = | ||
| 407 | kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL); | ||
| 408 | |||
| 409 | if (!td_info) | ||
| 410 | return NULL; | ||
| 411 | |||
| 412 | /* Set the base addr of the channel for this sensor */ | ||
| 413 | td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index); | ||
| 414 | /* Sensor 3 is direct conversion */ | ||
| 415 | if (index == 3) | ||
| 416 | td_info->direct = 1; | ||
| 417 | return td_info; | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 421 | * mid_thermal_resume - resume routine | ||
| 422 | * @pdev: platform device structure | ||
| 423 | * | ||
| 424 | * mid thermal resume: re-initializes the adc. Can sleep. | ||
| 425 | */ | ||
| 426 | static int mid_thermal_resume(struct platform_device *pdev) | ||
| 427 | { | ||
| 428 | return mid_initialize_adc(&pdev->dev); | ||
| 429 | } | ||
| 430 | |||
| 431 | /** | ||
| 432 | * mid_thermal_suspend - suspend routine | ||
| 433 | * @pdev: platform device structure | ||
| 434 | * | ||
| 435 | * mid thermal suspend implements the suspend functionality | ||
| 436 | * by stopping the ADC. Can sleep. | ||
| 437 | */ | ||
| 438 | static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg) | ||
| 439 | { | ||
| 440 | /* | ||
| 441 | * This just stops the ADC and does not disable it. | ||
| 442 | * temporary workaround until we have a generic ADC driver. | ||
| 443 | * If 0 is passed, it disables the ADC. | ||
| 444 | */ | ||
| 445 | return configure_adc(0); | ||
| 446 | } | ||
| 447 | |||
| 448 | /** | ||
| 449 | * read_curr_temp - reads the current temperature and stores in temp | ||
| 450 | * @temp: holds the current temperature value after reading | ||
| 451 | * | ||
| 452 | * Can sleep | ||
| 453 | */ | ||
| 454 | static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp) | ||
| 455 | { | ||
| 456 | WARN_ON(tzd == NULL); | ||
| 457 | return mid_read_temp(tzd, temp); | ||
| 458 | } | ||
| 459 | |||
| 460 | /* Can't be const */ | ||
| 461 | static struct thermal_zone_device_ops tzd_ops = { | ||
| 462 | .get_temp = read_curr_temp, | ||
| 463 | }; | ||
| 464 | |||
| 465 | |||
| 466 | /** | ||
| 467 | * mid_thermal_probe - mfld thermal initialize | ||
| 468 | * @pdev: platform device structure | ||
| 469 | * | ||
| 470 | * mid thermal probe initializes the hardware and registers | ||
| 471 | * all the sensors with the generic thermal framework. Can sleep. | ||
| 472 | */ | ||
| 473 | static int mid_thermal_probe(struct platform_device *pdev) | ||
| 474 | { | ||
| 475 | static char *name[MSIC_THERMAL_SENSORS] = { | ||
| 476 | "skin0", "skin1", "sys", "msicdie" | ||
| 477 | }; | ||
| 478 | |||
| 479 | int ret; | ||
| 480 | int i; | ||
| 481 | struct platform_info *pinfo; | ||
| 482 | |||
| 483 | pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL); | ||
| 484 | if (!pinfo) | ||
| 485 | return -ENOMEM; | ||
| 486 | |||
| 487 | /* Initializing the hardware */ | ||
| 488 | ret = mid_initialize_adc(&pdev->dev); | ||
| 489 | if (ret) { | ||
| 490 | dev_err(&pdev->dev, "ADC init failed"); | ||
| 491 | kfree(pinfo); | ||
| 492 | return ret; | ||
| 493 | } | ||
| 494 | |||
| 495 | /* Register each sensor with the generic thermal framework*/ | ||
| 496 | for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { | ||
| 497 | pinfo->tzd[i] = thermal_zone_device_register(name[i], | ||
| 498 | 0, initialize_sensor(i), | ||
| 499 | &tzd_ops, 0, 0, 0, 0); | ||
| 500 | if (IS_ERR(pinfo->tzd[i])) | ||
| 501 | goto reg_fail; | ||
| 502 | } | ||
| 503 | |||
| 504 | pinfo->pdev = pdev; | ||
| 505 | platform_set_drvdata(pdev, pinfo); | ||
| 506 | return 0; | ||
| 507 | |||
| 508 | reg_fail: | ||
| 509 | ret = PTR_ERR(pinfo->tzd[i]); | ||
| 510 | while (--i >= 0) | ||
| 511 | thermal_zone_device_unregister(pinfo->tzd[i]); | ||
| 512 | configure_adc(0); | ||
| 513 | kfree(pinfo); | ||
| 514 | return ret; | ||
| 515 | } | ||
| 516 | |||
| 517 | /** | ||
| 518 | * mid_thermal_remove - mfld thermal finalize | ||
| 519 | * @dev: platform device structure | ||
| 520 | * | ||
| 521 | * MLFD thermal remove unregisters all the sensors from the generic | ||
| 522 | * thermal framework. Can sleep. | ||
| 523 | */ | ||
| 524 | static int mid_thermal_remove(struct platform_device *pdev) | ||
| 525 | { | ||
| 526 | int i; | ||
| 527 | struct platform_info *pinfo = platform_get_drvdata(pdev); | ||
| 528 | |||
| 529 | for (i = 0; i < MSIC_THERMAL_SENSORS; i++) | ||
| 530 | thermal_zone_device_unregister(pinfo->tzd[i]); | ||
| 531 | |||
| 532 | platform_set_drvdata(pdev, NULL); | ||
| 533 | |||
| 534 | /* Stop the ADC */ | ||
| 535 | return configure_adc(0); | ||
| 536 | } | ||
| 537 | |||
| 538 | /********************************************************************* | ||
| 539 | * Driver initialisation and finalization | ||
| 540 | *********************************************************************/ | ||
| 541 | |||
| 542 | #define DRIVER_NAME "msic_sensor" | ||
| 543 | |||
| 544 | static const struct platform_device_id therm_id_table[] = { | ||
| 545 | { DRIVER_NAME, 1 }, | ||
| 546 | { } | ||
| 547 | }; | ||
| 548 | |||
| 549 | static struct platform_driver mid_thermal_driver = { | ||
| 550 | .driver = { | ||
| 551 | .name = DRIVER_NAME, | ||
| 552 | .owner = THIS_MODULE, | ||
| 553 | }, | ||
| 554 | .probe = mid_thermal_probe, | ||
| 555 | .suspend = mid_thermal_suspend, | ||
| 556 | .resume = mid_thermal_resume, | ||
| 557 | .remove = __devexit_p(mid_thermal_remove), | ||
| 558 | .id_table = therm_id_table, | ||
| 559 | }; | ||
| 560 | |||
| 561 | static int __init mid_thermal_module_init(void) | ||
| 562 | { | ||
| 563 | return platform_driver_register(&mid_thermal_driver); | ||
| 564 | } | ||
| 565 | |||
| 566 | static void __exit mid_thermal_module_exit(void) | ||
| 567 | { | ||
| 568 | platform_driver_unregister(&mid_thermal_driver); | ||
| 569 | } | ||
| 570 | |||
| 571 | module_init(mid_thermal_module_init); | ||
| 572 | module_exit(mid_thermal_module_exit); | ||
| 573 | |||
| 574 | MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>"); | ||
| 575 | MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver"); | ||
| 576 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index 2b11a33325e6..bde47e9080cd 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c | |||
| @@ -485,7 +485,7 @@ EXPORT_SYMBOL(rar_lock); | |||
| 485 | * | 485 | * |
| 486 | * The register_rar function is to used by other device drivers | 486 | * The register_rar function is to used by other device drivers |
| 487 | * to ensure that this driver is ready. As we cannot be sure of | 487 | * to ensure that this driver is ready. As we cannot be sure of |
| 488 | * the compile/execute order of drivers in ther kernel, it is | 488 | * the compile/execute order of drivers in the kernel, it is |
| 489 | * best to give this driver a callback function to call when | 489 | * best to give this driver a callback function to call when |
| 490 | * it is ready to give out addresses. The callback function | 490 | * it is ready to give out addresses. The callback function |
| 491 | * would have those steps that continue the initialization of | 491 | * would have those steps that continue the initialization of |
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index a91d510a798b..940accbe28d3 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | * as published by the Free Software Foundation; version 2 | 9 | * as published by the Free Software Foundation; version 2 |
| 10 | * of the License. | 10 | * of the License. |
| 11 | * | 11 | * |
| 12 | * SCU runing in ARC processor communicates with other entity running in IA | 12 | * SCU running in ARC processor communicates with other entity running in IA |
| 13 | * core through IPC mechanism which in turn messaging between IA core ad SCU. | 13 | * core through IPC mechanism which in turn messaging between IA core ad SCU. |
| 14 | * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and | 14 | * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and |
| 15 | * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with | 15 | * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with |
diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 142d38579314..23fb2afda00b 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c | |||
| @@ -51,6 +51,8 @@ | |||
| 51 | * laptop as MSI S270. YMMV. | 51 | * laptop as MSI S270. YMMV. |
| 52 | */ | 52 | */ |
| 53 | 53 | ||
| 54 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 55 | |||
| 54 | #include <linux/module.h> | 56 | #include <linux/module.h> |
| 55 | #include <linux/kernel.h> | 57 | #include <linux/kernel.h> |
| 56 | #include <linux/init.h> | 58 | #include <linux/init.h> |
| @@ -60,6 +62,8 @@ | |||
| 60 | #include <linux/platform_device.h> | 62 | #include <linux/platform_device.h> |
| 61 | #include <linux/rfkill.h> | 63 | #include <linux/rfkill.h> |
| 62 | #include <linux/i8042.h> | 64 | #include <linux/i8042.h> |
| 65 | #include <linux/input.h> | ||
| 66 | #include <linux/input/sparse-keymap.h> | ||
| 63 | 67 | ||
| 64 | #define MSI_DRIVER_VERSION "0.5" | 68 | #define MSI_DRIVER_VERSION "0.5" |
| 65 | 69 | ||
| @@ -78,6 +82,9 @@ | |||
| 78 | #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d | 82 | #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d |
| 79 | #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) | 83 | #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) |
| 80 | 84 | ||
| 85 | #define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4 | ||
| 86 | #define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4) | ||
| 87 | |||
| 81 | static int msi_laptop_resume(struct platform_device *device); | 88 | static int msi_laptop_resume(struct platform_device *device); |
| 82 | 89 | ||
| 83 | #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f | 90 | #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f |
| @@ -90,6 +97,14 @@ static int auto_brightness; | |||
| 90 | module_param(auto_brightness, int, 0); | 97 | module_param(auto_brightness, int, 0); |
| 91 | MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); | 98 | MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); |
| 92 | 99 | ||
| 100 | static const struct key_entry msi_laptop_keymap[] = { | ||
| 101 | {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */ | ||
| 102 | {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */ | ||
| 103 | {KE_END, 0} | ||
| 104 | }; | ||
| 105 | |||
| 106 | static struct input_dev *msi_laptop_input_dev; | ||
| 107 | |||
| 93 | static bool old_ec_model; | 108 | static bool old_ec_model; |
| 94 | static int wlan_s, bluetooth_s, threeg_s; | 109 | static int wlan_s, bluetooth_s, threeg_s; |
| 95 | static int threeg_exists; | 110 | static int threeg_exists; |
| @@ -432,8 +447,7 @@ static struct platform_device *msipf_device; | |||
| 432 | 447 | ||
| 433 | static int dmi_check_cb(const struct dmi_system_id *id) | 448 | static int dmi_check_cb(const struct dmi_system_id *id) |
| 434 | { | 449 | { |
| 435 | printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", | 450 | pr_info("Identified laptop model '%s'.\n", id->ident); |
| 436 | id->ident); | ||
| 437 | return 1; | 451 | return 1; |
| 438 | } | 452 | } |
| 439 | 453 | ||
| @@ -605,6 +619,21 @@ static void msi_update_rfkill(struct work_struct *ignored) | |||
| 605 | } | 619 | } |
| 606 | static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); | 620 | static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); |
| 607 | 621 | ||
| 622 | static void msi_send_touchpad_key(struct work_struct *ignored) | ||
| 623 | { | ||
| 624 | u8 rdata; | ||
| 625 | int result; | ||
| 626 | |||
| 627 | result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata); | ||
| 628 | if (result < 0) | ||
| 629 | return; | ||
| 630 | |||
| 631 | sparse_keymap_report_event(msi_laptop_input_dev, | ||
| 632 | (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? | ||
| 633 | KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); | ||
| 634 | } | ||
| 635 | static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); | ||
| 636 | |||
| 608 | static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, | 637 | static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, |
| 609 | struct serio *port) | 638 | struct serio *port) |
| 610 | { | 639 | { |
| @@ -613,12 +642,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, | |||
| 613 | if (str & 0x20) | 642 | if (str & 0x20) |
| 614 | return false; | 643 | return false; |
| 615 | 644 | ||
| 616 | /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ | 645 | /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/ |
| 617 | if (unlikely(data == 0xe0)) { | 646 | if (unlikely(data == 0xe0)) { |
| 618 | extended = true; | 647 | extended = true; |
| 619 | return false; | 648 | return false; |
| 620 | } else if (unlikely(extended)) { | 649 | } else if (unlikely(extended)) { |
| 650 | extended = false; | ||
| 621 | switch (data) { | 651 | switch (data) { |
| 652 | case 0xE4: | ||
| 653 | schedule_delayed_work(&msi_touchpad_work, | ||
| 654 | round_jiffies_relative(0.5 * HZ)); | ||
| 655 | break; | ||
| 622 | case 0x54: | 656 | case 0x54: |
| 623 | case 0x62: | 657 | case 0x62: |
| 624 | case 0x76: | 658 | case 0x76: |
| @@ -626,7 +660,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, | |||
| 626 | round_jiffies_relative(0.5 * HZ)); | 660 | round_jiffies_relative(0.5 * HZ)); |
| 627 | break; | 661 | break; |
| 628 | } | 662 | } |
| 629 | extended = false; | ||
| 630 | } | 663 | } |
| 631 | 664 | ||
| 632 | return false; | 665 | return false; |
| @@ -731,6 +764,42 @@ static int msi_laptop_resume(struct platform_device *device) | |||
| 731 | return 0; | 764 | return 0; |
| 732 | } | 765 | } |
| 733 | 766 | ||
| 767 | static int __init msi_laptop_input_setup(void) | ||
| 768 | { | ||
| 769 | int err; | ||
| 770 | |||
| 771 | msi_laptop_input_dev = input_allocate_device(); | ||
| 772 | if (!msi_laptop_input_dev) | ||
| 773 | return -ENOMEM; | ||
| 774 | |||
| 775 | msi_laptop_input_dev->name = "MSI Laptop hotkeys"; | ||
| 776 | msi_laptop_input_dev->phys = "msi-laptop/input0"; | ||
| 777 | msi_laptop_input_dev->id.bustype = BUS_HOST; | ||
| 778 | |||
| 779 | err = sparse_keymap_setup(msi_laptop_input_dev, | ||
| 780 | msi_laptop_keymap, NULL); | ||
| 781 | if (err) | ||
| 782 | goto err_free_dev; | ||
| 783 | |||
| 784 | err = input_register_device(msi_laptop_input_dev); | ||
| 785 | if (err) | ||
| 786 | goto err_free_keymap; | ||
| 787 | |||
| 788 | return 0; | ||
| 789 | |||
| 790 | err_free_keymap: | ||
| 791 | sparse_keymap_free(msi_laptop_input_dev); | ||
| 792 | err_free_dev: | ||
| 793 | input_free_device(msi_laptop_input_dev); | ||
| 794 | return err; | ||
| 795 | } | ||
| 796 | |||
| 797 | static void msi_laptop_input_destroy(void) | ||
| 798 | { | ||
| 799 | sparse_keymap_free(msi_laptop_input_dev); | ||
| 800 | input_unregister_device(msi_laptop_input_dev); | ||
| 801 | } | ||
| 802 | |||
| 734 | static int load_scm_model_init(struct platform_device *sdev) | 803 | static int load_scm_model_init(struct platform_device *sdev) |
| 735 | { | 804 | { |
| 736 | u8 data; | 805 | u8 data; |
| @@ -759,16 +828,23 @@ static int load_scm_model_init(struct platform_device *sdev) | |||
| 759 | if (result < 0) | 828 | if (result < 0) |
| 760 | goto fail_rfkill; | 829 | goto fail_rfkill; |
| 761 | 830 | ||
| 831 | /* setup input device */ | ||
| 832 | result = msi_laptop_input_setup(); | ||
| 833 | if (result) | ||
| 834 | goto fail_input; | ||
| 835 | |||
| 762 | result = i8042_install_filter(msi_laptop_i8042_filter); | 836 | result = i8042_install_filter(msi_laptop_i8042_filter); |
| 763 | if (result) { | 837 | if (result) { |
| 764 | printk(KERN_ERR | 838 | pr_err("Unable to install key filter\n"); |
| 765 | "msi-laptop: Unable to install key filter\n"); | ||
| 766 | goto fail_filter; | 839 | goto fail_filter; |
| 767 | } | 840 | } |
| 768 | 841 | ||
| 769 | return 0; | 842 | return 0; |
| 770 | 843 | ||
| 771 | fail_filter: | 844 | fail_filter: |
| 845 | msi_laptop_input_destroy(); | ||
| 846 | |||
| 847 | fail_input: | ||
| 772 | rfkill_cleanup(); | 848 | rfkill_cleanup(); |
| 773 | 849 | ||
| 774 | fail_rfkill: | 850 | fail_rfkill: |
| @@ -799,7 +875,7 @@ static int __init msi_init(void) | |||
| 799 | /* Register backlight stuff */ | 875 | /* Register backlight stuff */ |
| 800 | 876 | ||
| 801 | if (acpi_video_backlight_support()) { | 877 | if (acpi_video_backlight_support()) { |
| 802 | printk(KERN_INFO "MSI: Brightness ignored, must be controlled " | 878 | pr_info("Brightness ignored, must be controlled " |
| 803 | "by ACPI video driver\n"); | 879 | "by ACPI video driver\n"); |
| 804 | } else { | 880 | } else { |
| 805 | struct backlight_properties props; | 881 | struct backlight_properties props; |
| @@ -854,7 +930,7 @@ static int __init msi_init(void) | |||
| 854 | if (auto_brightness != 2) | 930 | if (auto_brightness != 2) |
| 855 | set_auto_brightness(auto_brightness); | 931 | set_auto_brightness(auto_brightness); |
| 856 | 932 | ||
| 857 | printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); | 933 | pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n"); |
| 858 | 934 | ||
| 859 | return 0; | 935 | return 0; |
| 860 | 936 | ||
| @@ -886,6 +962,7 @@ static void __exit msi_cleanup(void) | |||
| 886 | { | 962 | { |
| 887 | if (load_scm_model) { | 963 | if (load_scm_model) { |
| 888 | i8042_remove_filter(msi_laptop_i8042_filter); | 964 | i8042_remove_filter(msi_laptop_i8042_filter); |
| 965 | msi_laptop_input_destroy(); | ||
| 889 | cancel_delayed_work_sync(&msi_rfkill_work); | 966 | cancel_delayed_work_sync(&msi_rfkill_work); |
| 890 | rfkill_cleanup(); | 967 | rfkill_cleanup(); |
| 891 | } | 968 | } |
| @@ -901,7 +978,7 @@ static void __exit msi_cleanup(void) | |||
| 901 | if (auto_brightness != 2) | 978 | if (auto_brightness != 2) |
| 902 | set_auto_brightness(1); | 979 | set_auto_brightness(1); |
| 903 | 980 | ||
| 904 | printk(KERN_INFO "msi-laptop: driver unloaded.\n"); | 981 | pr_info("driver unloaded.\n"); |
| 905 | } | 982 | } |
| 906 | 983 | ||
| 907 | module_init(msi_init); | 984 | module_init(msi_init); |
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c new file mode 100644 index 000000000000..de434c6dc2d6 --- /dev/null +++ b/drivers/platform/x86/samsung-laptop.c | |||
| @@ -0,0 +1,832 @@ | |||
| 1 | /* | ||
| 2 | * Samsung Laptop driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) | ||
| 5 | * Copyright (C) 2009,2011 Novell Inc. | ||
| 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 | */ | ||
| 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/pci.h> | ||
| 19 | #include <linux/backlight.h> | ||
| 20 | #include <linux/fb.h> | ||
| 21 | #include <linux/dmi.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/rfkill.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * This driver is needed because a number of Samsung laptops do not hook | ||
| 27 | * their control settings through ACPI. So we have to poke around in the | ||
| 28 | * BIOS to do things like brightness values, and "special" key controls. | ||
| 29 | */ | ||
| 30 | |||
| 31 | /* | ||
| 32 | * We have 0 - 8 as valid brightness levels. The specs say that level 0 should | ||
| 33 | * be reserved by the BIOS (which really doesn't make much sense), we tell | ||
| 34 | * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 | ||
| 35 | */ | ||
| 36 | #define MAX_BRIGHT 0x07 | ||
| 37 | |||
| 38 | |||
| 39 | #define SABI_IFACE_MAIN 0x00 | ||
| 40 | #define SABI_IFACE_SUB 0x02 | ||
| 41 | #define SABI_IFACE_COMPLETE 0x04 | ||
| 42 | #define SABI_IFACE_DATA 0x05 | ||
| 43 | |||
| 44 | /* Structure to get data back to the calling function */ | ||
| 45 | struct sabi_retval { | ||
| 46 | u8 retval[20]; | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct sabi_header_offsets { | ||
| 50 | u8 port; | ||
| 51 | u8 re_mem; | ||
| 52 | u8 iface_func; | ||
| 53 | u8 en_mem; | ||
| 54 | u8 data_offset; | ||
| 55 | u8 data_segment; | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct sabi_commands { | ||
| 59 | /* | ||
| 60 | * Brightness is 0 - 8, as described above. | ||
| 61 | * Value 0 is for the BIOS to use | ||
| 62 | */ | ||
| 63 | u8 get_brightness; | ||
| 64 | u8 set_brightness; | ||
| 65 | |||
| 66 | /* | ||
| 67 | * first byte: | ||
| 68 | * 0x00 - wireless is off | ||
| 69 | * 0x01 - wireless is on | ||
| 70 | * second byte: | ||
| 71 | * 0x02 - 3G is off | ||
| 72 | * 0x03 - 3G is on | ||
| 73 | * TODO, verify 3G is correct, that doesn't seem right... | ||
| 74 | */ | ||
| 75 | u8 get_wireless_button; | ||
| 76 | u8 set_wireless_button; | ||
| 77 | |||
| 78 | /* 0 is off, 1 is on */ | ||
| 79 | u8 get_backlight; | ||
| 80 | u8 set_backlight; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * 0x80 or 0x00 - no action | ||
| 84 | * 0x81 - recovery key pressed | ||
| 85 | */ | ||
| 86 | u8 get_recovery_mode; | ||
| 87 | u8 set_recovery_mode; | ||
| 88 | |||
| 89 | /* | ||
| 90 | * on seclinux: 0 is low, 1 is high, | ||
| 91 | * on swsmi: 0 is normal, 1 is silent, 2 is turbo | ||
| 92 | */ | ||
| 93 | u8 get_performance_level; | ||
| 94 | u8 set_performance_level; | ||
| 95 | |||
| 96 | /* | ||
| 97 | * Tell the BIOS that Linux is running on this machine. | ||
| 98 | * 81 is on, 80 is off | ||
| 99 | */ | ||
| 100 | u8 set_linux; | ||
| 101 | }; | ||
| 102 | |||
| 103 | struct sabi_performance_level { | ||
| 104 | const char *name; | ||
| 105 | u8 value; | ||
| 106 | }; | ||
| 107 | |||
| 108 | struct sabi_config { | ||
| 109 | const char *test_string; | ||
| 110 | u16 main_function; | ||
| 111 | const struct sabi_header_offsets header_offsets; | ||
| 112 | const struct sabi_commands commands; | ||
| 113 | const struct sabi_performance_level performance_levels[4]; | ||
| 114 | u8 min_brightness; | ||
| 115 | u8 max_brightness; | ||
| 116 | }; | ||
| 117 | |||
| 118 | static const struct sabi_config sabi_configs[] = { | ||
| 119 | { | ||
| 120 | .test_string = "SECLINUX", | ||
| 121 | |||
| 122 | .main_function = 0x4c49, | ||
| 123 | |||
| 124 | .header_offsets = { | ||
| 125 | .port = 0x00, | ||
| 126 | .re_mem = 0x02, | ||
| 127 | .iface_func = 0x03, | ||
| 128 | .en_mem = 0x04, | ||
| 129 | .data_offset = 0x05, | ||
| 130 | .data_segment = 0x07, | ||
| 131 | }, | ||
| 132 | |||
| 133 | .commands = { | ||
| 134 | .get_brightness = 0x00, | ||
| 135 | .set_brightness = 0x01, | ||
| 136 | |||
| 137 | .get_wireless_button = 0x02, | ||
| 138 | .set_wireless_button = 0x03, | ||
| 139 | |||
| 140 | .get_backlight = 0x04, | ||
| 141 | .set_backlight = 0x05, | ||
| 142 | |||
| 143 | .get_recovery_mode = 0x06, | ||
| 144 | .set_recovery_mode = 0x07, | ||
| 145 | |||
| 146 | .get_performance_level = 0x08, | ||
| 147 | .set_performance_level = 0x09, | ||
| 148 | |||
| 149 | .set_linux = 0x0a, | ||
| 150 | }, | ||
| 151 | |||
| 152 | .performance_levels = { | ||
| 153 | { | ||
| 154 | .name = "silent", | ||
| 155 | .value = 0, | ||
| 156 | }, | ||
| 157 | { | ||
| 158 | .name = "normal", | ||
| 159 | .value = 1, | ||
| 160 | }, | ||
| 161 | { }, | ||
| 162 | }, | ||
| 163 | .min_brightness = 1, | ||
| 164 | .max_brightness = 8, | ||
| 165 | }, | ||
| 166 | { | ||
| 167 | .test_string = "SwSmi@", | ||
| 168 | |||
| 169 | .main_function = 0x5843, | ||
| 170 | |||
| 171 | .header_offsets = { | ||
| 172 | .port = 0x00, | ||
| 173 | .re_mem = 0x04, | ||
| 174 | .iface_func = 0x02, | ||
| 175 | .en_mem = 0x03, | ||
| 176 | .data_offset = 0x05, | ||
| 177 | .data_segment = 0x07, | ||
| 178 | }, | ||
| 179 | |||
| 180 | .commands = { | ||
| 181 | .get_brightness = 0x10, | ||
| 182 | .set_brightness = 0x11, | ||
| 183 | |||
| 184 | .get_wireless_button = 0x12, | ||
| 185 | .set_wireless_button = 0x13, | ||
| 186 | |||
| 187 | .get_backlight = 0x2d, | ||
| 188 | .set_backlight = 0x2e, | ||
| 189 | |||
| 190 | .get_recovery_mode = 0xff, | ||
| 191 | .set_recovery_mode = 0xff, | ||
| 192 | |||
| 193 | .get_performance_level = 0x31, | ||
| 194 | .set_performance_level = 0x32, | ||
| 195 | |||
| 196 | .set_linux = 0xff, | ||
| 197 | }, | ||
| 198 | |||
| 199 | .performance_levels = { | ||
| 200 | { | ||
| 201 | .name = "normal", | ||
| 202 | .value = 0, | ||
| 203 | }, | ||
| 204 | { | ||
| 205 | .name = "silent", | ||
| 206 | .value = 1, | ||
| 207 | }, | ||
| 208 | { | ||
| 209 | .name = "overclock", | ||
| 210 | .value = 2, | ||
| 211 | }, | ||
| 212 | { }, | ||
| 213 | }, | ||
| 214 | .min_brightness = 0, | ||
| 215 | .max_brightness = 8, | ||
| 216 | }, | ||
| 217 | { }, | ||
| 218 | }; | ||
| 219 | |||
| 220 | static const struct sabi_config *sabi_config; | ||
| 221 | |||
| 222 | static void __iomem *sabi; | ||
| 223 | static void __iomem *sabi_iface; | ||
| 224 | static void __iomem *f0000_segment; | ||
| 225 | static struct backlight_device *backlight_device; | ||
| 226 | static struct mutex sabi_mutex; | ||
| 227 | static struct platform_device *sdev; | ||
| 228 | static struct rfkill *rfk; | ||
| 229 | |||
| 230 | static int force; | ||
| 231 | module_param(force, bool, 0); | ||
| 232 | MODULE_PARM_DESC(force, | ||
| 233 | "Disable the DMI check and forces the driver to be loaded"); | ||
| 234 | |||
| 235 | static int debug; | ||
| 236 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 237 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
| 238 | |||
| 239 | static int sabi_get_command(u8 command, struct sabi_retval *sretval) | ||
| 240 | { | ||
| 241 | int retval = 0; | ||
| 242 | u16 port = readw(sabi + sabi_config->header_offsets.port); | ||
| 243 | u8 complete, iface_data; | ||
| 244 | |||
| 245 | mutex_lock(&sabi_mutex); | ||
| 246 | |||
| 247 | /* enable memory to be able to write to it */ | ||
| 248 | outb(readb(sabi + sabi_config->header_offsets.en_mem), port); | ||
| 249 | |||
| 250 | /* write out the command */ | ||
| 251 | writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); | ||
| 252 | writew(command, sabi_iface + SABI_IFACE_SUB); | ||
| 253 | writeb(0, sabi_iface + SABI_IFACE_COMPLETE); | ||
| 254 | outb(readb(sabi + sabi_config->header_offsets.iface_func), port); | ||
| 255 | |||
| 256 | /* write protect memory to make it safe */ | ||
| 257 | outb(readb(sabi + sabi_config->header_offsets.re_mem), port); | ||
| 258 | |||
| 259 | /* see if the command actually succeeded */ | ||
| 260 | complete = readb(sabi_iface + SABI_IFACE_COMPLETE); | ||
| 261 | iface_data = readb(sabi_iface + SABI_IFACE_DATA); | ||
| 262 | if (complete != 0xaa || iface_data == 0xff) { | ||
| 263 | pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", | ||
| 264 | command, complete, iface_data); | ||
| 265 | retval = -EINVAL; | ||
| 266 | goto exit; | ||
| 267 | } | ||
| 268 | /* | ||
| 269 | * Save off the data into a structure so the caller use it. | ||
| 270 | * Right now we only want the first 4 bytes, | ||
| 271 | * There are commands that need more, but not for the ones we | ||
| 272 | * currently care about. | ||
| 273 | */ | ||
| 274 | sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); | ||
| 275 | sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); | ||
| 276 | sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); | ||
| 277 | sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); | ||
| 278 | |||
| 279 | exit: | ||
| 280 | mutex_unlock(&sabi_mutex); | ||
| 281 | return retval; | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | static int sabi_set_command(u8 command, u8 data) | ||
| 286 | { | ||
| 287 | int retval = 0; | ||
| 288 | u16 port = readw(sabi + sabi_config->header_offsets.port); | ||
| 289 | u8 complete, iface_data; | ||
| 290 | |||
| 291 | mutex_lock(&sabi_mutex); | ||
| 292 | |||
| 293 | /* enable memory to be able to write to it */ | ||
| 294 | outb(readb(sabi + sabi_config->header_offsets.en_mem), port); | ||
| 295 | |||
| 296 | /* write out the command */ | ||
| 297 | writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); | ||
| 298 | writew(command, sabi_iface + SABI_IFACE_SUB); | ||
| 299 | writeb(0, sabi_iface + SABI_IFACE_COMPLETE); | ||
| 300 | writeb(data, sabi_iface + SABI_IFACE_DATA); | ||
| 301 | outb(readb(sabi + sabi_config->header_offsets.iface_func), port); | ||
| 302 | |||
| 303 | /* write protect memory to make it safe */ | ||
| 304 | outb(readb(sabi + sabi_config->header_offsets.re_mem), port); | ||
| 305 | |||
| 306 | /* see if the command actually succeeded */ | ||
| 307 | complete = readb(sabi_iface + SABI_IFACE_COMPLETE); | ||
| 308 | iface_data = readb(sabi_iface + SABI_IFACE_DATA); | ||
| 309 | if (complete != 0xaa || iface_data == 0xff) { | ||
| 310 | pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", | ||
| 311 | command, complete, iface_data); | ||
| 312 | retval = -EINVAL; | ||
| 313 | } | ||
| 314 | |||
| 315 | mutex_unlock(&sabi_mutex); | ||
| 316 | return retval; | ||
| 317 | } | ||
| 318 | |||
| 319 | static void test_backlight(void) | ||
| 320 | { | ||
| 321 | struct sabi_retval sretval; | ||
| 322 | |||
| 323 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
| 324 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
| 325 | |||
| 326 | sabi_set_command(sabi_config->commands.set_backlight, 0); | ||
| 327 | printk(KERN_DEBUG "backlight should be off\n"); | ||
| 328 | |||
| 329 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
| 330 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
| 331 | |||
| 332 | msleep(1000); | ||
| 333 | |||
| 334 | sabi_set_command(sabi_config->commands.set_backlight, 1); | ||
| 335 | printk(KERN_DEBUG "backlight should be on\n"); | ||
| 336 | |||
| 337 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
| 338 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
| 339 | } | ||
| 340 | |||
| 341 | static void test_wireless(void) | ||
| 342 | { | ||
| 343 | struct sabi_retval sretval; | ||
| 344 | |||
| 345 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
| 346 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
| 347 | |||
| 348 | sabi_set_command(sabi_config->commands.set_wireless_button, 0); | ||
| 349 | printk(KERN_DEBUG "wireless led should be off\n"); | ||
| 350 | |||
| 351 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
| 352 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
| 353 | |||
| 354 | msleep(1000); | ||
| 355 | |||
| 356 | sabi_set_command(sabi_config->commands.set_wireless_button, 1); | ||
| 357 | printk(KERN_DEBUG "wireless led should be on\n"); | ||
| 358 | |||
| 359 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
| 360 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
| 361 | } | ||
| 362 | |||
| 363 | static u8 read_brightness(void) | ||
| 364 | { | ||
| 365 | struct sabi_retval sretval; | ||
| 366 | int user_brightness = 0; | ||
| 367 | int retval; | ||
| 368 | |||
| 369 | retval = sabi_get_command(sabi_config->commands.get_brightness, | ||
| 370 | &sretval); | ||
| 371 | if (!retval) { | ||
| 372 | user_brightness = sretval.retval[0]; | ||
| 373 | if (user_brightness != 0) | ||
| 374 | user_brightness -= sabi_config->min_brightness; | ||
| 375 | } | ||
| 376 | return user_brightness; | ||
| 377 | } | ||
| 378 | |||
| 379 | static void set_brightness(u8 user_brightness) | ||
| 380 | { | ||
| 381 | u8 user_level = user_brightness - sabi_config->min_brightness; | ||
| 382 | |||
| 383 | sabi_set_command(sabi_config->commands.set_brightness, user_level); | ||
| 384 | } | ||
| 385 | |||
| 386 | static int get_brightness(struct backlight_device *bd) | ||
| 387 | { | ||
| 388 | return (int)read_brightness(); | ||
| 389 | } | ||
| 390 | |||
| 391 | static int update_status(struct backlight_device *bd) | ||
| 392 | { | ||
| 393 | set_brightness(bd->props.brightness); | ||
| 394 | |||
| 395 | if (bd->props.power == FB_BLANK_UNBLANK) | ||
| 396 | sabi_set_command(sabi_config->commands.set_backlight, 1); | ||
| 397 | else | ||
| 398 | sabi_set_command(sabi_config->commands.set_backlight, 0); | ||
| 399 | return 0; | ||
| 400 | } | ||
| 401 | |||
| 402 | static const struct backlight_ops backlight_ops = { | ||
| 403 | .get_brightness = get_brightness, | ||
| 404 | .update_status = update_status, | ||
| 405 | }; | ||
| 406 | |||
| 407 | static int rfkill_set(void *data, bool blocked) | ||
| 408 | { | ||
| 409 | /* Do something with blocked...*/ | ||
| 410 | /* | ||
| 411 | * blocked == false is on | ||
| 412 | * blocked == true is off | ||
| 413 | */ | ||
| 414 | if (blocked) | ||
| 415 | sabi_set_command(sabi_config->commands.set_wireless_button, 0); | ||
| 416 | else | ||
| 417 | sabi_set_command(sabi_config->commands.set_wireless_button, 1); | ||
| 418 | |||
| 419 | return 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | static struct rfkill_ops rfkill_ops = { | ||
| 423 | .set_block = rfkill_set, | ||
| 424 | }; | ||
| 425 | |||
| 426 | static int init_wireless(struct platform_device *sdev) | ||
| 427 | { | ||
| 428 | int retval; | ||
| 429 | |||
| 430 | rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, | ||
| 431 | &rfkill_ops, NULL); | ||
| 432 | if (!rfk) | ||
| 433 | return -ENOMEM; | ||
| 434 | |||
| 435 | retval = rfkill_register(rfk); | ||
| 436 | if (retval) { | ||
| 437 | rfkill_destroy(rfk); | ||
| 438 | return -ENODEV; | ||
| 439 | } | ||
| 440 | |||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 444 | static void destroy_wireless(void) | ||
| 445 | { | ||
| 446 | rfkill_unregister(rfk); | ||
| 447 | rfkill_destroy(rfk); | ||
| 448 | } | ||
| 449 | |||
| 450 | static ssize_t get_performance_level(struct device *dev, | ||
| 451 | struct device_attribute *attr, char *buf) | ||
| 452 | { | ||
| 453 | struct sabi_retval sretval; | ||
| 454 | int retval; | ||
| 455 | int i; | ||
| 456 | |||
| 457 | /* Read the state */ | ||
| 458 | retval = sabi_get_command(sabi_config->commands.get_performance_level, | ||
| 459 | &sretval); | ||
| 460 | if (retval) | ||
| 461 | return retval; | ||
| 462 | |||
| 463 | /* The logic is backwards, yeah, lots of fun... */ | ||
| 464 | for (i = 0; sabi_config->performance_levels[i].name; ++i) { | ||
| 465 | if (sretval.retval[0] == sabi_config->performance_levels[i].value) | ||
| 466 | return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); | ||
| 467 | } | ||
| 468 | return sprintf(buf, "%s\n", "unknown"); | ||
| 469 | } | ||
| 470 | |||
| 471 | static ssize_t set_performance_level(struct device *dev, | ||
| 472 | struct device_attribute *attr, const char *buf, | ||
| 473 | size_t count) | ||
| 474 | { | ||
| 475 | if (count >= 1) { | ||
| 476 | int i; | ||
| 477 | for (i = 0; sabi_config->performance_levels[i].name; ++i) { | ||
| 478 | const struct sabi_performance_level *level = | ||
| 479 | &sabi_config->performance_levels[i]; | ||
| 480 | if (!strncasecmp(level->name, buf, strlen(level->name))) { | ||
| 481 | sabi_set_command(sabi_config->commands.set_performance_level, | ||
| 482 | level->value); | ||
| 483 | break; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | if (!sabi_config->performance_levels[i].name) | ||
| 487 | return -EINVAL; | ||
| 488 | } | ||
| 489 | return count; | ||
| 490 | } | ||
| 491 | static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, | ||
| 492 | get_performance_level, set_performance_level); | ||
| 493 | |||
| 494 | |||
| 495 | static int __init dmi_check_cb(const struct dmi_system_id *id) | ||
| 496 | { | ||
| 497 | pr_info("found laptop model '%s'\n", | ||
| 498 | id->ident); | ||
| 499 | return 1; | ||
| 500 | } | ||
| 501 | |||
| 502 | static struct dmi_system_id __initdata samsung_dmi_table[] = { | ||
| 503 | { | ||
| 504 | .ident = "N128", | ||
| 505 | .matches = { | ||
| 506 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 507 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 508 | DMI_MATCH(DMI_PRODUCT_NAME, "N128"), | ||
| 509 | DMI_MATCH(DMI_BOARD_NAME, "N128"), | ||
| 510 | }, | ||
| 511 | .callback = dmi_check_cb, | ||
| 512 | }, | ||
| 513 | { | ||
| 514 | .ident = "N130", | ||
| 515 | .matches = { | ||
| 516 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 517 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 518 | DMI_MATCH(DMI_PRODUCT_NAME, "N130"), | ||
| 519 | DMI_MATCH(DMI_BOARD_NAME, "N130"), | ||
| 520 | }, | ||
| 521 | .callback = dmi_check_cb, | ||
| 522 | }, | ||
| 523 | { | ||
| 524 | .ident = "X125", | ||
| 525 | .matches = { | ||
| 526 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 527 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 528 | DMI_MATCH(DMI_PRODUCT_NAME, "X125"), | ||
| 529 | DMI_MATCH(DMI_BOARD_NAME, "X125"), | ||
| 530 | }, | ||
| 531 | .callback = dmi_check_cb, | ||
| 532 | }, | ||
| 533 | { | ||
| 534 | .ident = "X120/X170", | ||
| 535 | .matches = { | ||
| 536 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 537 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 538 | DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), | ||
| 539 | DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), | ||
| 540 | }, | ||
| 541 | .callback = dmi_check_cb, | ||
| 542 | }, | ||
| 543 | { | ||
| 544 | .ident = "NC10", | ||
| 545 | .matches = { | ||
| 546 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 547 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 548 | DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), | ||
| 549 | DMI_MATCH(DMI_BOARD_NAME, "NC10"), | ||
| 550 | }, | ||
| 551 | .callback = dmi_check_cb, | ||
| 552 | }, | ||
| 553 | { | ||
| 554 | .ident = "NP-Q45", | ||
| 555 | .matches = { | ||
| 556 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 557 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 558 | DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), | ||
| 559 | DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), | ||
| 560 | }, | ||
| 561 | .callback = dmi_check_cb, | ||
| 562 | }, | ||
| 563 | { | ||
| 564 | .ident = "X360", | ||
| 565 | .matches = { | ||
| 566 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 567 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 568 | DMI_MATCH(DMI_PRODUCT_NAME, "X360"), | ||
| 569 | DMI_MATCH(DMI_BOARD_NAME, "X360"), | ||
| 570 | }, | ||
| 571 | .callback = dmi_check_cb, | ||
| 572 | }, | ||
| 573 | { | ||
| 574 | .ident = "R518", | ||
| 575 | .matches = { | ||
| 576 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 577 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 578 | DMI_MATCH(DMI_PRODUCT_NAME, "R518"), | ||
| 579 | DMI_MATCH(DMI_BOARD_NAME, "R518"), | ||
| 580 | }, | ||
| 581 | .callback = dmi_check_cb, | ||
| 582 | }, | ||
| 583 | { | ||
| 584 | .ident = "R519/R719", | ||
| 585 | .matches = { | ||
| 586 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 587 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 588 | DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), | ||
| 589 | DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), | ||
| 590 | }, | ||
| 591 | .callback = dmi_check_cb, | ||
| 592 | }, | ||
| 593 | { | ||
| 594 | .ident = "N150/N210/N220", | ||
| 595 | .matches = { | ||
| 596 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 597 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 598 | DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), | ||
| 599 | DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), | ||
| 600 | }, | ||
| 601 | .callback = dmi_check_cb, | ||
| 602 | }, | ||
| 603 | { | ||
| 604 | .ident = "N150P/N210P/N220P", | ||
| 605 | .matches = { | ||
| 606 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 607 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 608 | DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), | ||
| 609 | DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), | ||
| 610 | }, | ||
| 611 | .callback = dmi_check_cb, | ||
| 612 | }, | ||
| 613 | { | ||
| 614 | .ident = "R530/R730", | ||
| 615 | .matches = { | ||
| 616 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 617 | DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), | ||
| 618 | DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), | ||
| 619 | }, | ||
| 620 | .callback = dmi_check_cb, | ||
| 621 | }, | ||
| 622 | { | ||
| 623 | .ident = "NF110/NF210/NF310", | ||
| 624 | .matches = { | ||
| 625 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 626 | DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), | ||
| 627 | DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), | ||
| 628 | }, | ||
| 629 | .callback = dmi_check_cb, | ||
| 630 | }, | ||
| 631 | { | ||
| 632 | .ident = "N145P/N250P/N260P", | ||
| 633 | .matches = { | ||
| 634 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 635 | DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), | ||
| 636 | DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), | ||
| 637 | }, | ||
| 638 | .callback = dmi_check_cb, | ||
| 639 | }, | ||
| 640 | { | ||
| 641 | .ident = "R70/R71", | ||
| 642 | .matches = { | ||
| 643 | DMI_MATCH(DMI_SYS_VENDOR, | ||
| 644 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 645 | DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), | ||
| 646 | DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), | ||
| 647 | }, | ||
| 648 | .callback = dmi_check_cb, | ||
| 649 | }, | ||
| 650 | { | ||
| 651 | .ident = "P460", | ||
| 652 | .matches = { | ||
| 653 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
| 654 | DMI_MATCH(DMI_PRODUCT_NAME, "P460"), | ||
| 655 | DMI_MATCH(DMI_BOARD_NAME, "P460"), | ||
| 656 | }, | ||
| 657 | .callback = dmi_check_cb, | ||
| 658 | }, | ||
| 659 | { }, | ||
| 660 | }; | ||
| 661 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | ||
| 662 | |||
| 663 | static int find_signature(void __iomem *memcheck, const char *testStr) | ||
| 664 | { | ||
| 665 | int i = 0; | ||
| 666 | int loca; | ||
| 667 | |||
| 668 | for (loca = 0; loca < 0xffff; loca++) { | ||
| 669 | char temp = readb(memcheck + loca); | ||
| 670 | |||
| 671 | if (temp == testStr[i]) { | ||
| 672 | if (i == strlen(testStr)-1) | ||
| 673 | break; | ||
| 674 | ++i; | ||
| 675 | } else { | ||
| 676 | i = 0; | ||
| 677 | } | ||
| 678 | } | ||
| 679 | return loca; | ||
| 680 | } | ||
| 681 | |||
| 682 | static int __init samsung_init(void) | ||
| 683 | { | ||
| 684 | struct backlight_properties props; | ||
| 685 | struct sabi_retval sretval; | ||
| 686 | unsigned int ifaceP; | ||
| 687 | int i; | ||
| 688 | int loca; | ||
| 689 | int retval; | ||
| 690 | |||
| 691 | mutex_init(&sabi_mutex); | ||
| 692 | |||
| 693 | if (!force && !dmi_check_system(samsung_dmi_table)) | ||
| 694 | return -ENODEV; | ||
| 695 | |||
| 696 | f0000_segment = ioremap_nocache(0xf0000, 0xffff); | ||
| 697 | if (!f0000_segment) { | ||
| 698 | pr_err("Can't map the segment at 0xf0000\n"); | ||
| 699 | return -EINVAL; | ||
| 700 | } | ||
| 701 | |||
| 702 | /* Try to find one of the signatures in memory to find the header */ | ||
| 703 | for (i = 0; sabi_configs[i].test_string != 0; ++i) { | ||
| 704 | sabi_config = &sabi_configs[i]; | ||
| 705 | loca = find_signature(f0000_segment, sabi_config->test_string); | ||
| 706 | if (loca != 0xffff) | ||
| 707 | break; | ||
| 708 | } | ||
| 709 | |||
| 710 | if (loca == 0xffff) { | ||
| 711 | pr_err("This computer does not support SABI\n"); | ||
| 712 | goto error_no_signature; | ||
| 713 | } | ||
| 714 | |||
| 715 | /* point to the SMI port Number */ | ||
| 716 | loca += 1; | ||
| 717 | sabi = (f0000_segment + loca); | ||
| 718 | |||
| 719 | if (debug) { | ||
| 720 | printk(KERN_DEBUG "This computer supports SABI==%x\n", | ||
| 721 | loca + 0xf0000 - 6); | ||
| 722 | printk(KERN_DEBUG "SABI header:\n"); | ||
| 723 | printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", | ||
| 724 | readw(sabi + sabi_config->header_offsets.port)); | ||
| 725 | printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", | ||
| 726 | readb(sabi + sabi_config->header_offsets.iface_func)); | ||
| 727 | printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", | ||
| 728 | readb(sabi + sabi_config->header_offsets.en_mem)); | ||
| 729 | printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", | ||
| 730 | readb(sabi + sabi_config->header_offsets.re_mem)); | ||
| 731 | printk(KERN_DEBUG " SABI data offset = 0x%04x\n", | ||
| 732 | readw(sabi + sabi_config->header_offsets.data_offset)); | ||
| 733 | printk(KERN_DEBUG " SABI data segment = 0x%04x\n", | ||
| 734 | readw(sabi + sabi_config->header_offsets.data_segment)); | ||
| 735 | } | ||
| 736 | |||
| 737 | /* Get a pointer to the SABI Interface */ | ||
| 738 | ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; | ||
| 739 | ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; | ||
| 740 | sabi_iface = ioremap_nocache(ifaceP, 16); | ||
| 741 | if (!sabi_iface) { | ||
| 742 | pr_err("Can't remap %x\n", ifaceP); | ||
| 743 | goto exit; | ||
| 744 | } | ||
| 745 | if (debug) { | ||
| 746 | printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); | ||
| 747 | printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); | ||
| 748 | |||
| 749 | test_backlight(); | ||
| 750 | test_wireless(); | ||
| 751 | |||
| 752 | retval = sabi_get_command(sabi_config->commands.get_brightness, | ||
| 753 | &sretval); | ||
| 754 | printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); | ||
| 755 | } | ||
| 756 | |||
| 757 | /* Turn on "Linux" mode in the BIOS */ | ||
| 758 | if (sabi_config->commands.set_linux != 0xff) { | ||
| 759 | retval = sabi_set_command(sabi_config->commands.set_linux, | ||
| 760 | 0x81); | ||
| 761 | if (retval) { | ||
| 762 | pr_warn("Linux mode was not set!\n"); | ||
| 763 | goto error_no_platform; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | |||
| 767 | /* knock up a platform device to hang stuff off of */ | ||
| 768 | sdev = platform_device_register_simple("samsung", -1, NULL, 0); | ||
| 769 | if (IS_ERR(sdev)) | ||
| 770 | goto error_no_platform; | ||
| 771 | |||
| 772 | /* create a backlight device to talk to this one */ | ||
| 773 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 774 | props.max_brightness = sabi_config->max_brightness; | ||
| 775 | backlight_device = backlight_device_register("samsung", &sdev->dev, | ||
| 776 | NULL, &backlight_ops, | ||
| 777 | &props); | ||
| 778 | if (IS_ERR(backlight_device)) | ||
| 779 | goto error_no_backlight; | ||
| 780 | |||
| 781 | backlight_device->props.brightness = read_brightness(); | ||
| 782 | backlight_device->props.power = FB_BLANK_UNBLANK; | ||
| 783 | backlight_update_status(backlight_device); | ||
| 784 | |||
| 785 | retval = init_wireless(sdev); | ||
| 786 | if (retval) | ||
| 787 | goto error_no_rfk; | ||
| 788 | |||
| 789 | retval = device_create_file(&sdev->dev, &dev_attr_performance_level); | ||
| 790 | if (retval) | ||
| 791 | goto error_file_create; | ||
| 792 | |||
| 793 | exit: | ||
| 794 | return 0; | ||
| 795 | |||
| 796 | error_file_create: | ||
| 797 | destroy_wireless(); | ||
| 798 | |||
| 799 | error_no_rfk: | ||
| 800 | backlight_device_unregister(backlight_device); | ||
| 801 | |||
| 802 | error_no_backlight: | ||
| 803 | platform_device_unregister(sdev); | ||
| 804 | |||
| 805 | error_no_platform: | ||
| 806 | iounmap(sabi_iface); | ||
| 807 | |||
| 808 | error_no_signature: | ||
| 809 | iounmap(f0000_segment); | ||
| 810 | return -EINVAL; | ||
| 811 | } | ||
| 812 | |||
| 813 | static void __exit samsung_exit(void) | ||
| 814 | { | ||
| 815 | /* Turn off "Linux" mode in the BIOS */ | ||
| 816 | if (sabi_config->commands.set_linux != 0xff) | ||
| 817 | sabi_set_command(sabi_config->commands.set_linux, 0x80); | ||
| 818 | |||
| 819 | device_remove_file(&sdev->dev, &dev_attr_performance_level); | ||
| 820 | backlight_device_unregister(backlight_device); | ||
| 821 | destroy_wireless(); | ||
| 822 | iounmap(sabi_iface); | ||
| 823 | iounmap(f0000_segment); | ||
| 824 | platform_device_unregister(sdev); | ||
| 825 | } | ||
| 826 | |||
| 827 | module_init(samsung_init); | ||
| 828 | module_exit(samsung_exit); | ||
| 829 | |||
| 830 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); | ||
| 831 | MODULE_DESCRIPTION("Samsung Backlight driver"); | ||
| 832 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 13d8d63bcca9..e642f5f29504 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
| @@ -71,8 +71,9 @@ | |||
| 71 | #endif | 71 | #endif |
| 72 | 72 | ||
| 73 | #define DRV_PFX "sony-laptop: " | 73 | #define DRV_PFX "sony-laptop: " |
| 74 | #define dprintk(msg...) do { \ | 74 | #define dprintk(msg...) do { \ |
| 75 | if (debug) printk(KERN_WARNING DRV_PFX msg); \ | 75 | if (debug) \ |
| 76 | pr_warn(DRV_PFX msg); \ | ||
| 76 | } while (0) | 77 | } while (0) |
| 77 | 78 | ||
| 78 | #define SONY_LAPTOP_DRIVER_VERSION "0.6" | 79 | #define SONY_LAPTOP_DRIVER_VERSION "0.6" |
| @@ -124,6 +125,19 @@ MODULE_PARM_DESC(minor, | |||
| 124 | "default is -1 (automatic)"); | 125 | "default is -1 (automatic)"); |
| 125 | #endif | 126 | #endif |
| 126 | 127 | ||
| 128 | static int kbd_backlight; /* = 1 */ | ||
| 129 | module_param(kbd_backlight, int, 0444); | ||
| 130 | MODULE_PARM_DESC(kbd_backlight, | ||
| 131 | "set this to 0 to disable keyboard backlight, " | ||
| 132 | "1 to enable it (default: 0)"); | ||
| 133 | |||
| 134 | static int kbd_backlight_timeout; /* = 0 */ | ||
| 135 | module_param(kbd_backlight_timeout, int, 0444); | ||
| 136 | MODULE_PARM_DESC(kbd_backlight_timeout, | ||
| 137 | "set this to 0 to set the default 10 seconds timeout, " | ||
| 138 | "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " | ||
| 139 | "(default: 0)"); | ||
| 140 | |||
| 127 | enum sony_nc_rfkill { | 141 | enum sony_nc_rfkill { |
| 128 | SONY_WIFI, | 142 | SONY_WIFI, |
| 129 | SONY_BLUETOOTH, | 143 | SONY_BLUETOOTH, |
| @@ -402,7 +416,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) | |||
| 402 | error = kfifo_alloc(&sony_laptop_input.fifo, | 416 | error = kfifo_alloc(&sony_laptop_input.fifo, |
| 403 | SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); | 417 | SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); |
| 404 | if (error) { | 418 | if (error) { |
| 405 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 419 | pr_err(DRV_PFX "kfifo_alloc failed\n"); |
| 406 | goto err_dec_users; | 420 | goto err_dec_users; |
| 407 | } | 421 | } |
| 408 | 422 | ||
| @@ -591,7 +605,7 @@ struct sony_nc_value { | |||
| 591 | int value; /* current setting */ | 605 | int value; /* current setting */ |
| 592 | int valid; /* Has ever been set */ | 606 | int valid; /* Has ever been set */ |
| 593 | int debug; /* active only in debug mode ? */ | 607 | int debug; /* active only in debug mode ? */ |
| 594 | struct device_attribute devattr; /* sysfs atribute */ | 608 | struct device_attribute devattr; /* sysfs attribute */ |
| 595 | }; | 609 | }; |
| 596 | 610 | ||
| 597 | #define SNC_HANDLE_NAMES(_name, _values...) \ | 611 | #define SNC_HANDLE_NAMES(_name, _values...) \ |
| @@ -686,7 +700,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) | |||
| 686 | return 0; | 700 | return 0; |
| 687 | } | 701 | } |
| 688 | 702 | ||
| 689 | printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); | 703 | pr_warn(DRV_PFX "acpi_callreadfunc failed\n"); |
| 690 | 704 | ||
| 691 | return -1; | 705 | return -1; |
| 692 | } | 706 | } |
| @@ -712,7 +726,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | |||
| 712 | if (status == AE_OK) { | 726 | if (status == AE_OK) { |
| 713 | if (result != NULL) { | 727 | if (result != NULL) { |
| 714 | if (out_obj.type != ACPI_TYPE_INTEGER) { | 728 | if (out_obj.type != ACPI_TYPE_INTEGER) { |
| 715 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " | 729 | pr_warn(DRV_PFX "acpi_evaluate_object bad " |
| 716 | "return type\n"); | 730 | "return type\n"); |
| 717 | return -1; | 731 | return -1; |
| 718 | } | 732 | } |
| @@ -721,34 +735,103 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | |||
| 721 | return 0; | 735 | return 0; |
| 722 | } | 736 | } |
| 723 | 737 | ||
| 724 | printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); | 738 | pr_warn(DRV_PFX "acpi_evaluate_object failed\n"); |
| 725 | 739 | ||
| 726 | return -1; | 740 | return -1; |
| 727 | } | 741 | } |
| 728 | 742 | ||
| 729 | static int sony_find_snc_handle(int handle) | 743 | struct sony_nc_handles { |
| 744 | u16 cap[0x10]; | ||
| 745 | struct device_attribute devattr; | ||
| 746 | }; | ||
| 747 | |||
| 748 | static struct sony_nc_handles *handles; | ||
| 749 | |||
| 750 | static ssize_t sony_nc_handles_show(struct device *dev, | ||
| 751 | struct device_attribute *attr, char *buffer) | ||
| 752 | { | ||
| 753 | ssize_t len = 0; | ||
| 754 | int i; | ||
| 755 | |||
| 756 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
| 757 | len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ", | ||
| 758 | handles->cap[i]); | ||
| 759 | } | ||
| 760 | len += snprintf(buffer + len, PAGE_SIZE - len, "\n"); | ||
| 761 | |||
| 762 | return len; | ||
| 763 | } | ||
| 764 | |||
| 765 | static int sony_nc_handles_setup(struct platform_device *pd) | ||
| 730 | { | 766 | { |
| 731 | int i; | 767 | int i; |
| 732 | int result; | 768 | int result; |
| 733 | 769 | ||
| 734 | for (i = 0x20; i < 0x30; i++) { | 770 | handles = kzalloc(sizeof(*handles), GFP_KERNEL); |
| 735 | acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); | 771 | if (!handles) |
| 736 | if (result == handle) | 772 | return -ENOMEM; |
| 737 | return i-0x20; | 773 | |
| 774 | sysfs_attr_init(&handles->devattr.attr); | ||
| 775 | handles->devattr.attr.name = "handles"; | ||
| 776 | handles->devattr.attr.mode = S_IRUGO; | ||
| 777 | handles->devattr.show = sony_nc_handles_show; | ||
| 778 | |||
| 779 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
| 780 | if (!acpi_callsetfunc(sony_nc_acpi_handle, | ||
| 781 | "SN00", i + 0x20, &result)) { | ||
| 782 | dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", | ||
| 783 | result, i); | ||
| 784 | handles->cap[i] = result; | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | /* allow reading capabilities via sysfs */ | ||
| 789 | if (device_create_file(&pd->dev, &handles->devattr)) { | ||
| 790 | kfree(handles); | ||
| 791 | handles = NULL; | ||
| 792 | return -1; | ||
| 793 | } | ||
| 794 | |||
| 795 | return 0; | ||
| 796 | } | ||
| 797 | |||
| 798 | static int sony_nc_handles_cleanup(struct platform_device *pd) | ||
| 799 | { | ||
| 800 | if (handles) { | ||
| 801 | device_remove_file(&pd->dev, &handles->devattr); | ||
| 802 | kfree(handles); | ||
| 803 | handles = NULL; | ||
| 738 | } | 804 | } |
| 805 | return 0; | ||
| 806 | } | ||
| 739 | 807 | ||
| 808 | static int sony_find_snc_handle(int handle) | ||
| 809 | { | ||
| 810 | int i; | ||
| 811 | for (i = 0; i < 0x10; i++) { | ||
| 812 | if (handles->cap[i] == handle) { | ||
| 813 | dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", | ||
| 814 | handle, i); | ||
| 815 | return i; | ||
| 816 | } | ||
| 817 | } | ||
| 818 | dprintk("handle 0x%.4x not found\n", handle); | ||
| 740 | return -1; | 819 | return -1; |
| 741 | } | 820 | } |
| 742 | 821 | ||
| 743 | static int sony_call_snc_handle(int handle, int argument, int *result) | 822 | static int sony_call_snc_handle(int handle, int argument, int *result) |
| 744 | { | 823 | { |
| 824 | int ret = 0; | ||
| 745 | int offset = sony_find_snc_handle(handle); | 825 | int offset = sony_find_snc_handle(handle); |
| 746 | 826 | ||
| 747 | if (offset < 0) | 827 | if (offset < 0) |
| 748 | return -1; | 828 | return -1; |
| 749 | 829 | ||
| 750 | return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, | 830 | ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, |
| 751 | result); | 831 | result); |
| 832 | dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, | ||
| 833 | *result); | ||
| 834 | return ret; | ||
| 752 | } | 835 | } |
| 753 | 836 | ||
| 754 | /* | 837 | /* |
| @@ -857,11 +940,39 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) | |||
| 857 | return value - 1; | 940 | return value - 1; |
| 858 | } | 941 | } |
| 859 | 942 | ||
| 860 | static struct backlight_device *sony_backlight_device; | 943 | static int sony_nc_get_brightness_ng(struct backlight_device *bd) |
| 944 | { | ||
| 945 | int result; | ||
| 946 | int *handle = (int *)bl_get_data(bd); | ||
| 947 | |||
| 948 | sony_call_snc_handle(*handle, 0x0200, &result); | ||
| 949 | |||
| 950 | return result & 0xff; | ||
| 951 | } | ||
| 952 | |||
| 953 | static int sony_nc_update_status_ng(struct backlight_device *bd) | ||
| 954 | { | ||
| 955 | int value, result; | ||
| 956 | int *handle = (int *)bl_get_data(bd); | ||
| 957 | |||
| 958 | value = bd->props.brightness; | ||
| 959 | sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); | ||
| 960 | |||
| 961 | return sony_nc_get_brightness_ng(bd); | ||
| 962 | } | ||
| 963 | |||
| 861 | static const struct backlight_ops sony_backlight_ops = { | 964 | static const struct backlight_ops sony_backlight_ops = { |
| 965 | .options = BL_CORE_SUSPENDRESUME, | ||
| 862 | .update_status = sony_backlight_update_status, | 966 | .update_status = sony_backlight_update_status, |
| 863 | .get_brightness = sony_backlight_get_brightness, | 967 | .get_brightness = sony_backlight_get_brightness, |
| 864 | }; | 968 | }; |
| 969 | static const struct backlight_ops sony_backlight_ng_ops = { | ||
| 970 | .options = BL_CORE_SUSPENDRESUME, | ||
| 971 | .update_status = sony_nc_update_status_ng, | ||
| 972 | .get_brightness = sony_nc_get_brightness_ng, | ||
| 973 | }; | ||
| 974 | static int backlight_ng_handle; | ||
| 975 | static struct backlight_device *sony_backlight_device; | ||
| 865 | 976 | ||
| 866 | /* | 977 | /* |
| 867 | * New SNC-only Vaios event mapping to driver known keys | 978 | * New SNC-only Vaios event mapping to driver known keys |
| @@ -972,7 +1083,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) | |||
| 972 | } | 1083 | } |
| 973 | 1084 | ||
| 974 | if (!key_event->data) | 1085 | if (!key_event->data) |
| 975 | printk(KERN_INFO DRV_PFX | 1086 | pr_info(DRV_PFX |
| 976 | "Unknown event: 0x%x 0x%x\n", | 1087 | "Unknown event: 0x%x 0x%x\n", |
| 977 | key_handle, | 1088 | key_handle, |
| 978 | ev); | 1089 | ev); |
| @@ -996,7 +1107,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | |||
| 996 | struct acpi_device_info *info; | 1107 | struct acpi_device_info *info; |
| 997 | 1108 | ||
| 998 | if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { | 1109 | if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { |
| 999 | printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", | 1110 | pr_warn(DRV_PFX "method: name: %4.4s, args %X\n", |
| 1000 | (char *)&info->name, info->param_count); | 1111 | (char *)&info->name, info->param_count); |
| 1001 | 1112 | ||
| 1002 | kfree(info); | 1113 | kfree(info); |
| @@ -1037,7 +1148,7 @@ static int sony_nc_resume(struct acpi_device *device) | |||
| 1037 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, | 1148 | ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, |
| 1038 | item->value, NULL); | 1149 | item->value, NULL); |
| 1039 | if (ret < 0) { | 1150 | if (ret < 0) { |
| 1040 | printk("%s: %d\n", __func__, ret); | 1151 | pr_err(DRV_PFX "%s: %d\n", __func__, ret); |
| 1041 | break; | 1152 | break; |
| 1042 | } | 1153 | } |
| 1043 | } | 1154 | } |
| @@ -1054,11 +1165,6 @@ static int sony_nc_resume(struct acpi_device *device) | |||
| 1054 | sony_nc_function_setup(device); | 1165 | sony_nc_function_setup(device); |
| 1055 | } | 1166 | } |
| 1056 | 1167 | ||
| 1057 | /* set the last requested brightness level */ | ||
| 1058 | if (sony_backlight_device && | ||
| 1059 | sony_backlight_update_status(sony_backlight_device) < 0) | ||
| 1060 | printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); | ||
| 1061 | |||
| 1062 | /* re-read rfkill state */ | 1168 | /* re-read rfkill state */ |
| 1063 | sony_nc_rfkill_update(); | 1169 | sony_nc_rfkill_update(); |
| 1064 | 1170 | ||
| @@ -1206,12 +1312,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device) | |||
| 1206 | 1312 | ||
| 1207 | device_enum = (union acpi_object *) buffer.pointer; | 1313 | device_enum = (union acpi_object *) buffer.pointer; |
| 1208 | if (!device_enum) { | 1314 | if (!device_enum) { |
| 1209 | pr_err("Invalid SN06 return object\n"); | 1315 | pr_err(DRV_PFX "No SN06 return object."); |
| 1210 | goto out_no_enum; | 1316 | goto out_no_enum; |
| 1211 | } | 1317 | } |
| 1212 | if (device_enum->type != ACPI_TYPE_BUFFER) { | 1318 | if (device_enum->type != ACPI_TYPE_BUFFER) { |
| 1213 | pr_err("Invalid SN06 return object type 0x%.2x\n", | 1319 | pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n", |
| 1214 | device_enum->type); | 1320 | device_enum->type); |
| 1215 | goto out_no_enum; | 1321 | goto out_no_enum; |
| 1216 | } | 1322 | } |
| 1217 | 1323 | ||
| @@ -1245,6 +1351,209 @@ out_no_enum: | |||
| 1245 | return; | 1351 | return; |
| 1246 | } | 1352 | } |
| 1247 | 1353 | ||
| 1354 | /* Keyboard backlight feature */ | ||
| 1355 | #define KBDBL_HANDLER 0x137 | ||
| 1356 | #define KBDBL_PRESENT 0xB00 | ||
| 1357 | #define SET_MODE 0xC00 | ||
| 1358 | #define SET_TIMEOUT 0xE00 | ||
| 1359 | |||
| 1360 | struct kbd_backlight { | ||
| 1361 | int mode; | ||
| 1362 | int timeout; | ||
| 1363 | struct device_attribute mode_attr; | ||
| 1364 | struct device_attribute timeout_attr; | ||
| 1365 | }; | ||
| 1366 | |||
| 1367 | static struct kbd_backlight *kbdbl_handle; | ||
| 1368 | |||
| 1369 | static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) | ||
| 1370 | { | ||
| 1371 | int result; | ||
| 1372 | |||
| 1373 | if (value > 1) | ||
| 1374 | return -EINVAL; | ||
| 1375 | |||
| 1376 | if (sony_call_snc_handle(KBDBL_HANDLER, | ||
| 1377 | (value << 0x10) | SET_MODE, &result)) | ||
| 1378 | return -EIO; | ||
| 1379 | |||
| 1380 | kbdbl_handle->mode = value; | ||
| 1381 | |||
| 1382 | return 0; | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, | ||
| 1386 | struct device_attribute *attr, | ||
| 1387 | const char *buffer, size_t count) | ||
| 1388 | { | ||
| 1389 | int ret = 0; | ||
| 1390 | unsigned long value; | ||
| 1391 | |||
| 1392 | if (count > 31) | ||
| 1393 | return -EINVAL; | ||
| 1394 | |||
| 1395 | if (strict_strtoul(buffer, 10, &value)) | ||
| 1396 | return -EINVAL; | ||
| 1397 | |||
| 1398 | ret = __sony_nc_kbd_backlight_mode_set(value); | ||
| 1399 | if (ret < 0) | ||
| 1400 | return ret; | ||
| 1401 | |||
| 1402 | return count; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, | ||
| 1406 | struct device_attribute *attr, char *buffer) | ||
| 1407 | { | ||
| 1408 | ssize_t count = 0; | ||
| 1409 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); | ||
| 1410 | return count; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | static int __sony_nc_kbd_backlight_timeout_set(u8 value) | ||
| 1414 | { | ||
| 1415 | int result; | ||
| 1416 | |||
| 1417 | if (value > 3) | ||
| 1418 | return -EINVAL; | ||
| 1419 | |||
| 1420 | if (sony_call_snc_handle(KBDBL_HANDLER, | ||
| 1421 | (value << 0x10) | SET_TIMEOUT, &result)) | ||
| 1422 | return -EIO; | ||
| 1423 | |||
| 1424 | kbdbl_handle->timeout = value; | ||
| 1425 | |||
| 1426 | return 0; | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, | ||
| 1430 | struct device_attribute *attr, | ||
| 1431 | const char *buffer, size_t count) | ||
| 1432 | { | ||
| 1433 | int ret = 0; | ||
| 1434 | unsigned long value; | ||
| 1435 | |||
| 1436 | if (count > 31) | ||
| 1437 | return -EINVAL; | ||
| 1438 | |||
| 1439 | if (strict_strtoul(buffer, 10, &value)) | ||
| 1440 | return -EINVAL; | ||
| 1441 | |||
| 1442 | ret = __sony_nc_kbd_backlight_timeout_set(value); | ||
| 1443 | if (ret < 0) | ||
| 1444 | return ret; | ||
| 1445 | |||
| 1446 | return count; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, | ||
| 1450 | struct device_attribute *attr, char *buffer) | ||
| 1451 | { | ||
| 1452 | ssize_t count = 0; | ||
| 1453 | count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); | ||
| 1454 | return count; | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd) | ||
| 1458 | { | ||
| 1459 | int result; | ||
| 1460 | |||
| 1461 | if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) | ||
| 1462 | return 0; | ||
| 1463 | if (!(result & 0x02)) | ||
| 1464 | return 0; | ||
| 1465 | |||
| 1466 | kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); | ||
| 1467 | if (!kbdbl_handle) | ||
| 1468 | return -ENOMEM; | ||
| 1469 | |||
| 1470 | sysfs_attr_init(&kbdbl_handle->mode_attr.attr); | ||
| 1471 | kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; | ||
| 1472 | kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
| 1473 | kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; | ||
| 1474 | kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; | ||
| 1475 | |||
| 1476 | sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); | ||
| 1477 | kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; | ||
| 1478 | kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; | ||
| 1479 | kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; | ||
| 1480 | kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; | ||
| 1481 | |||
| 1482 | if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) | ||
| 1483 | goto outkzalloc; | ||
| 1484 | |||
| 1485 | if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) | ||
| 1486 | goto outmode; | ||
| 1487 | |||
| 1488 | __sony_nc_kbd_backlight_mode_set(kbd_backlight); | ||
| 1489 | __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout); | ||
| 1490 | |||
| 1491 | return 0; | ||
| 1492 | |||
| 1493 | outmode: | ||
| 1494 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | ||
| 1495 | outkzalloc: | ||
| 1496 | kfree(kbdbl_handle); | ||
| 1497 | kbdbl_handle = NULL; | ||
| 1498 | return -1; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | ||
| 1502 | { | ||
| 1503 | if (kbdbl_handle) { | ||
| 1504 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | ||
| 1505 | device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); | ||
| 1506 | kfree(kbdbl_handle); | ||
| 1507 | } | ||
| 1508 | return 0; | ||
| 1509 | } | ||
| 1510 | |||
| 1511 | static void sony_nc_backlight_setup(void) | ||
| 1512 | { | ||
| 1513 | acpi_handle unused; | ||
| 1514 | int max_brightness = 0; | ||
| 1515 | const struct backlight_ops *ops = NULL; | ||
| 1516 | struct backlight_properties props; | ||
| 1517 | |||
| 1518 | if (sony_find_snc_handle(0x12f) != -1) { | ||
| 1519 | backlight_ng_handle = 0x12f; | ||
| 1520 | ops = &sony_backlight_ng_ops; | ||
| 1521 | max_brightness = 0xff; | ||
| 1522 | |||
| 1523 | } else if (sony_find_snc_handle(0x137) != -1) { | ||
| 1524 | backlight_ng_handle = 0x137; | ||
| 1525 | ops = &sony_backlight_ng_ops; | ||
| 1526 | max_brightness = 0xff; | ||
| 1527 | |||
| 1528 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | ||
| 1529 | &unused))) { | ||
| 1530 | ops = &sony_backlight_ops; | ||
| 1531 | max_brightness = SONY_MAX_BRIGHTNESS - 1; | ||
| 1532 | |||
| 1533 | } else | ||
| 1534 | return; | ||
| 1535 | |||
| 1536 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 1537 | props.type = BACKLIGHT_PLATFORM; | ||
| 1538 | props.max_brightness = max_brightness; | ||
| 1539 | sony_backlight_device = backlight_device_register("sony", NULL, | ||
| 1540 | &backlight_ng_handle, | ||
| 1541 | ops, &props); | ||
| 1542 | |||
| 1543 | if (IS_ERR(sony_backlight_device)) { | ||
| 1544 | pr_warning(DRV_PFX "unable to register backlight device\n"); | ||
| 1545 | sony_backlight_device = NULL; | ||
| 1546 | } else | ||
| 1547 | sony_backlight_device->props.brightness = | ||
| 1548 | ops->get_brightness(sony_backlight_device); | ||
| 1549 | } | ||
| 1550 | |||
| 1551 | static void sony_nc_backlight_cleanup(void) | ||
| 1552 | { | ||
| 1553 | if (sony_backlight_device) | ||
| 1554 | backlight_device_unregister(sony_backlight_device); | ||
| 1555 | } | ||
| 1556 | |||
| 1248 | static int sony_nc_add(struct acpi_device *device) | 1557 | static int sony_nc_add(struct acpi_device *device) |
| 1249 | { | 1558 | { |
| 1250 | acpi_status status; | 1559 | acpi_status status; |
| @@ -1252,8 +1561,8 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1252 | acpi_handle handle; | 1561 | acpi_handle handle; |
| 1253 | struct sony_nc_value *item; | 1562 | struct sony_nc_value *item; |
| 1254 | 1563 | ||
| 1255 | printk(KERN_INFO DRV_PFX "%s v%s.\n", | 1564 | pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME, |
| 1256 | SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); | 1565 | SONY_LAPTOP_DRIVER_VERSION); |
| 1257 | 1566 | ||
| 1258 | sony_nc_acpi_device = device; | 1567 | sony_nc_acpi_device = device; |
| 1259 | strcpy(acpi_device_class(device), "sony/hotkey"); | 1568 | strcpy(acpi_device_class(device), "sony/hotkey"); |
| @@ -1269,13 +1578,18 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1269 | goto outwalk; | 1578 | goto outwalk; |
| 1270 | } | 1579 | } |
| 1271 | 1580 | ||
| 1581 | result = sony_pf_add(); | ||
| 1582 | if (result) | ||
| 1583 | goto outpresent; | ||
| 1584 | |||
| 1272 | if (debug) { | 1585 | if (debug) { |
| 1273 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, | 1586 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, |
| 1274 | 1, sony_walk_callback, NULL, NULL, NULL); | 1587 | sony_nc_acpi_handle, 1, sony_walk_callback, |
| 1588 | NULL, NULL, NULL); | ||
| 1275 | if (ACPI_FAILURE(status)) { | 1589 | if (ACPI_FAILURE(status)) { |
| 1276 | printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); | 1590 | pr_warn(DRV_PFX "unable to walk acpi resources\n"); |
| 1277 | result = -ENODEV; | 1591 | result = -ENODEV; |
| 1278 | goto outwalk; | 1592 | goto outpresent; |
| 1279 | } | 1593 | } |
| 1280 | } | 1594 | } |
| 1281 | 1595 | ||
| @@ -1288,6 +1602,12 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1288 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", | 1602 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", |
| 1289 | &handle))) { | 1603 | &handle))) { |
| 1290 | dprintk("Doing SNC setup\n"); | 1604 | dprintk("Doing SNC setup\n"); |
| 1605 | result = sony_nc_handles_setup(sony_pf_device); | ||
| 1606 | if (result) | ||
| 1607 | goto outpresent; | ||
| 1608 | result = sony_nc_kbd_backlight_setup(sony_pf_device); | ||
| 1609 | if (result) | ||
| 1610 | goto outsnc; | ||
| 1291 | sony_nc_function_setup(device); | 1611 | sony_nc_function_setup(device); |
| 1292 | sony_nc_rfkill_setup(device); | 1612 | sony_nc_rfkill_setup(device); |
| 1293 | } | 1613 | } |
| @@ -1295,40 +1615,17 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1295 | /* setup input devices and helper fifo */ | 1615 | /* setup input devices and helper fifo */ |
| 1296 | result = sony_laptop_setup_input(device); | 1616 | result = sony_laptop_setup_input(device); |
| 1297 | if (result) { | 1617 | if (result) { |
| 1298 | printk(KERN_ERR DRV_PFX | 1618 | pr_err(DRV_PFX "Unable to create input devices.\n"); |
| 1299 | "Unable to create input devices.\n"); | 1619 | goto outkbdbacklight; |
| 1300 | goto outwalk; | ||
| 1301 | } | 1620 | } |
| 1302 | 1621 | ||
| 1303 | if (acpi_video_backlight_support()) { | 1622 | if (acpi_video_backlight_support()) { |
| 1304 | printk(KERN_INFO DRV_PFX "brightness ignored, must be " | 1623 | pr_info(DRV_PFX "brightness ignored, must be " |
| 1305 | "controlled by ACPI video driver\n"); | 1624 | "controlled by ACPI video driver\n"); |
| 1306 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | 1625 | } else { |
| 1307 | &handle))) { | 1626 | sony_nc_backlight_setup(); |
| 1308 | struct backlight_properties props; | ||
| 1309 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
| 1310 | props.type = BACKLIGHT_PLATFORM; | ||
| 1311 | props.max_brightness = SONY_MAX_BRIGHTNESS - 1; | ||
| 1312 | sony_backlight_device = backlight_device_register("sony", NULL, | ||
| 1313 | NULL, | ||
| 1314 | &sony_backlight_ops, | ||
| 1315 | &props); | ||
| 1316 | |||
| 1317 | if (IS_ERR(sony_backlight_device)) { | ||
| 1318 | printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); | ||
| 1319 | sony_backlight_device = NULL; | ||
| 1320 | } else { | ||
| 1321 | sony_backlight_device->props.brightness = | ||
| 1322 | sony_backlight_get_brightness | ||
| 1323 | (sony_backlight_device); | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | } | 1627 | } |
| 1327 | 1628 | ||
| 1328 | result = sony_pf_add(); | ||
| 1329 | if (result) | ||
| 1330 | goto outbacklight; | ||
| 1331 | |||
| 1332 | /* create sony_pf sysfs attributes related to the SNC device */ | 1629 | /* create sony_pf sysfs attributes related to the SNC device */ |
| 1333 | for (item = sony_nc_values; item->name; ++item) { | 1630 | for (item = sony_nc_values; item->name; ++item) { |
| 1334 | 1631 | ||
| @@ -1374,14 +1671,19 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 1374 | for (item = sony_nc_values; item->name; ++item) { | 1671 | for (item = sony_nc_values; item->name; ++item) { |
| 1375 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1672 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
| 1376 | } | 1673 | } |
| 1377 | sony_pf_remove(); | 1674 | sony_nc_backlight_cleanup(); |
| 1378 | |||
| 1379 | outbacklight: | ||
| 1380 | if (sony_backlight_device) | ||
| 1381 | backlight_device_unregister(sony_backlight_device); | ||
| 1382 | 1675 | ||
| 1383 | sony_laptop_remove_input(); | 1676 | sony_laptop_remove_input(); |
| 1384 | 1677 | ||
| 1678 | outkbdbacklight: | ||
| 1679 | sony_nc_kbd_backlight_cleanup(sony_pf_device); | ||
| 1680 | |||
| 1681 | outsnc: | ||
| 1682 | sony_nc_handles_cleanup(sony_pf_device); | ||
| 1683 | |||
| 1684 | outpresent: | ||
| 1685 | sony_pf_remove(); | ||
| 1686 | |||
| 1385 | outwalk: | 1687 | outwalk: |
| 1386 | sony_nc_rfkill_cleanup(); | 1688 | sony_nc_rfkill_cleanup(); |
| 1387 | return result; | 1689 | return result; |
| @@ -1391,8 +1693,7 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
| 1391 | { | 1693 | { |
| 1392 | struct sony_nc_value *item; | 1694 | struct sony_nc_value *item; |
| 1393 | 1695 | ||
| 1394 | if (sony_backlight_device) | 1696 | sony_nc_backlight_cleanup(); |
| 1395 | backlight_device_unregister(sony_backlight_device); | ||
| 1396 | 1697 | ||
| 1397 | sony_nc_acpi_device = NULL; | 1698 | sony_nc_acpi_device = NULL; |
| 1398 | 1699 | ||
| @@ -1400,6 +1701,8 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
| 1400 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1701 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
| 1401 | } | 1702 | } |
| 1402 | 1703 | ||
| 1704 | sony_nc_kbd_backlight_cleanup(sony_pf_device); | ||
| 1705 | sony_nc_handles_cleanup(sony_pf_device); | ||
| 1403 | sony_pf_remove(); | 1706 | sony_pf_remove(); |
| 1404 | sony_laptop_remove_input(); | 1707 | sony_laptop_remove_input(); |
| 1405 | sony_nc_rfkill_cleanup(); | 1708 | sony_nc_rfkill_cleanup(); |
| @@ -1438,7 +1741,6 @@ static struct acpi_driver sony_nc_driver = { | |||
| 1438 | #define SONYPI_DEVICE_TYPE1 0x00000001 | 1741 | #define SONYPI_DEVICE_TYPE1 0x00000001 |
| 1439 | #define SONYPI_DEVICE_TYPE2 0x00000002 | 1742 | #define SONYPI_DEVICE_TYPE2 0x00000002 |
| 1440 | #define SONYPI_DEVICE_TYPE3 0x00000004 | 1743 | #define SONYPI_DEVICE_TYPE3 0x00000004 |
| 1441 | #define SONYPI_DEVICE_TYPE4 0x00000008 | ||
| 1442 | 1744 | ||
| 1443 | #define SONYPI_TYPE1_OFFSET 0x04 | 1745 | #define SONYPI_TYPE1_OFFSET 0x04 |
| 1444 | #define SONYPI_TYPE2_OFFSET 0x12 | 1746 | #define SONYPI_TYPE2_OFFSET 0x12 |
| @@ -1584,8 +1886,8 @@ static struct sonypi_event sonypi_blueev[] = { | |||
| 1584 | 1886 | ||
| 1585 | /* The set of possible wireless events */ | 1887 | /* The set of possible wireless events */ |
| 1586 | static struct sonypi_event sonypi_wlessev[] = { | 1888 | static struct sonypi_event sonypi_wlessev[] = { |
| 1587 | { 0x59, SONYPI_EVENT_WIRELESS_ON }, | 1889 | { 0x59, SONYPI_EVENT_IGNORE }, |
| 1588 | { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, | 1890 | { 0x5a, SONYPI_EVENT_IGNORE }, |
| 1589 | { 0, 0 } | 1891 | { 0, 0 } |
| 1590 | }; | 1892 | }; |
| 1591 | 1893 | ||
| @@ -1842,7 +2144,7 @@ out: | |||
| 1842 | if (pcidev) | 2144 | if (pcidev) |
| 1843 | pci_dev_put(pcidev); | 2145 | pci_dev_put(pcidev); |
| 1844 | 2146 | ||
| 1845 | printk(KERN_INFO DRV_PFX "detected Type%d model\n", | 2147 | pr_info(DRV_PFX "detected Type%d model\n", |
| 1846 | dev->model == SONYPI_DEVICE_TYPE1 ? 1 : | 2148 | dev->model == SONYPI_DEVICE_TYPE1 ? 1 : |
| 1847 | dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); | 2149 | dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); |
| 1848 | } | 2150 | } |
| @@ -1890,7 +2192,7 @@ static int __sony_pic_camera_ready(void) | |||
| 1890 | static int __sony_pic_camera_off(void) | 2192 | static int __sony_pic_camera_off(void) |
| 1891 | { | 2193 | { |
| 1892 | if (!camera) { | 2194 | if (!camera) { |
| 1893 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); | 2195 | pr_warn(DRV_PFX "camera control not enabled\n"); |
| 1894 | return -ENODEV; | 2196 | return -ENODEV; |
| 1895 | } | 2197 | } |
| 1896 | 2198 | ||
| @@ -1910,7 +2212,7 @@ static int __sony_pic_camera_on(void) | |||
| 1910 | int i, j, x; | 2212 | int i, j, x; |
| 1911 | 2213 | ||
| 1912 | if (!camera) { | 2214 | if (!camera) { |
| 1913 | printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); | 2215 | pr_warn(DRV_PFX "camera control not enabled\n"); |
| 1914 | return -ENODEV; | 2216 | return -ENODEV; |
| 1915 | } | 2217 | } |
| 1916 | 2218 | ||
| @@ -1933,7 +2235,7 @@ static int __sony_pic_camera_on(void) | |||
| 1933 | } | 2235 | } |
| 1934 | 2236 | ||
| 1935 | if (j == 0) { | 2237 | if (j == 0) { |
| 1936 | printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); | 2238 | pr_warn(DRV_PFX "failed to power on camera\n"); |
| 1937 | return -ENODEV; | 2239 | return -ENODEV; |
| 1938 | } | 2240 | } |
| 1939 | 2241 | ||
| @@ -1989,7 +2291,7 @@ int sony_pic_camera_command(int command, u8 value) | |||
| 1989 | ITERATIONS_SHORT); | 2291 | ITERATIONS_SHORT); |
| 1990 | break; | 2292 | break; |
| 1991 | default: | 2293 | default: |
| 1992 | printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", | 2294 | pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n", |
| 1993 | command); | 2295 | command); |
| 1994 | break; | 2296 | break; |
| 1995 | } | 2297 | } |
| @@ -2396,7 +2698,7 @@ static int sonypi_compat_init(void) | |||
| 2396 | error = | 2698 | error = |
| 2397 | kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); | 2699 | kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); |
| 2398 | if (error) { | 2700 | if (error) { |
| 2399 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 2701 | pr_err(DRV_PFX "kfifo_alloc failed\n"); |
| 2400 | return error; | 2702 | return error; |
| 2401 | } | 2703 | } |
| 2402 | 2704 | ||
| @@ -2406,11 +2708,11 @@ static int sonypi_compat_init(void) | |||
| 2406 | sonypi_misc_device.minor = minor; | 2708 | sonypi_misc_device.minor = minor; |
| 2407 | error = misc_register(&sonypi_misc_device); | 2709 | error = misc_register(&sonypi_misc_device); |
| 2408 | if (error) { | 2710 | if (error) { |
| 2409 | printk(KERN_ERR DRV_PFX "misc_register failed\n"); | 2711 | pr_err(DRV_PFX "misc_register failed\n"); |
| 2410 | goto err_free_kfifo; | 2712 | goto err_free_kfifo; |
| 2411 | } | 2713 | } |
| 2412 | if (minor == -1) | 2714 | if (minor == -1) |
| 2413 | printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", | 2715 | pr_info(DRV_PFX "device allocated minor is %d\n", |
| 2414 | sonypi_misc_device.minor); | 2716 | sonypi_misc_device.minor); |
| 2415 | 2717 | ||
| 2416 | return 0; | 2718 | return 0; |
| @@ -2470,8 +2772,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
| 2470 | } | 2772 | } |
| 2471 | for (i = 0; i < p->interrupt_count; i++) { | 2773 | for (i = 0; i < p->interrupt_count; i++) { |
| 2472 | if (!p->interrupts[i]) { | 2774 | if (!p->interrupts[i]) { |
| 2473 | printk(KERN_WARNING DRV_PFX | 2775 | pr_warn(DRV_PFX "Invalid IRQ %d\n", |
| 2474 | "Invalid IRQ %d\n", | ||
| 2475 | p->interrupts[i]); | 2776 | p->interrupts[i]); |
| 2476 | continue; | 2777 | continue; |
| 2477 | } | 2778 | } |
| @@ -2510,7 +2811,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
| 2510 | ioport->io2.address_length); | 2811 | ioport->io2.address_length); |
| 2511 | } | 2812 | } |
| 2512 | else { | 2813 | else { |
| 2513 | printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); | 2814 | pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); |
| 2514 | return AE_ERROR; | 2815 | return AE_ERROR; |
| 2515 | } | 2816 | } |
| 2516 | return AE_OK; | 2817 | return AE_OK; |
| @@ -2538,7 +2839,7 @@ static int sony_pic_possible_resources(struct acpi_device *device) | |||
| 2538 | dprintk("Evaluating _STA\n"); | 2839 | dprintk("Evaluating _STA\n"); |
| 2539 | result = acpi_bus_get_status(device); | 2840 | result = acpi_bus_get_status(device); |
| 2540 | if (result) { | 2841 | if (result) { |
| 2541 | printk(KERN_WARNING DRV_PFX "Unable to read status\n"); | 2842 | pr_warn(DRV_PFX "Unable to read status\n"); |
| 2542 | goto end; | 2843 | goto end; |
| 2543 | } | 2844 | } |
| 2544 | 2845 | ||
| @@ -2554,8 +2855,7 @@ static int sony_pic_possible_resources(struct acpi_device *device) | |||
| 2554 | status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, | 2855 | status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, |
| 2555 | sony_pic_read_possible_resource, &spic_dev); | 2856 | sony_pic_read_possible_resource, &spic_dev); |
| 2556 | if (ACPI_FAILURE(status)) { | 2857 | if (ACPI_FAILURE(status)) { |
| 2557 | printk(KERN_WARNING DRV_PFX | 2858 | pr_warn(DRV_PFX "Failure evaluating %s\n", |
| 2558 | "Failure evaluating %s\n", | ||
| 2559 | METHOD_NAME__PRS); | 2859 | METHOD_NAME__PRS); |
| 2560 | result = -ENODEV; | 2860 | result = -ENODEV; |
| 2561 | } | 2861 | } |
| @@ -2669,7 +2969,7 @@ static int sony_pic_enable(struct acpi_device *device, | |||
| 2669 | 2969 | ||
| 2670 | /* check for total failure */ | 2970 | /* check for total failure */ |
| 2671 | if (ACPI_FAILURE(status)) { | 2971 | if (ACPI_FAILURE(status)) { |
| 2672 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); | 2972 | pr_err(DRV_PFX "Error evaluating _SRS\n"); |
| 2673 | result = -ENODEV; | 2973 | result = -ENODEV; |
| 2674 | goto end; | 2974 | goto end; |
| 2675 | } | 2975 | } |
| @@ -2725,6 +3025,9 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) | |||
| 2725 | if (ev == dev->event_types[i].events[j].data) { | 3025 | if (ev == dev->event_types[i].events[j].data) { |
| 2726 | device_event = | 3026 | device_event = |
| 2727 | dev->event_types[i].events[j].event; | 3027 | dev->event_types[i].events[j].event; |
| 3028 | /* some events may require ignoring */ | ||
| 3029 | if (!device_event) | ||
| 3030 | return IRQ_HANDLED; | ||
| 2728 | goto found; | 3031 | goto found; |
| 2729 | } | 3032 | } |
| 2730 | } | 3033 | } |
| @@ -2744,7 +3047,6 @@ found: | |||
| 2744 | sony_laptop_report_input_event(device_event); | 3047 | sony_laptop_report_input_event(device_event); |
| 2745 | acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); | 3048 | acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); |
| 2746 | sonypi_compat_report_event(device_event); | 3049 | sonypi_compat_report_event(device_event); |
| 2747 | |||
| 2748 | return IRQ_HANDLED; | 3050 | return IRQ_HANDLED; |
| 2749 | } | 3051 | } |
| 2750 | 3052 | ||
| @@ -2759,7 +3061,7 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
| 2759 | struct sony_pic_irq *irq, *tmp_irq; | 3061 | struct sony_pic_irq *irq, *tmp_irq; |
| 2760 | 3062 | ||
| 2761 | if (sony_pic_disable(device)) { | 3063 | if (sony_pic_disable(device)) { |
| 2762 | printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); | 3064 | pr_err(DRV_PFX "Couldn't disable device.\n"); |
| 2763 | return -ENXIO; | 3065 | return -ENXIO; |
| 2764 | } | 3066 | } |
| 2765 | 3067 | ||
| @@ -2799,8 +3101,8 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2799 | struct sony_pic_ioport *io, *tmp_io; | 3101 | struct sony_pic_ioport *io, *tmp_io; |
| 2800 | struct sony_pic_irq *irq, *tmp_irq; | 3102 | struct sony_pic_irq *irq, *tmp_irq; |
| 2801 | 3103 | ||
| 2802 | printk(KERN_INFO DRV_PFX "%s v%s.\n", | 3104 | pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME, |
| 2803 | SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); | 3105 | SONY_LAPTOP_DRIVER_VERSION); |
| 2804 | 3106 | ||
| 2805 | spic_dev.acpi_dev = device; | 3107 | spic_dev.acpi_dev = device; |
| 2806 | strcpy(acpi_device_class(device), "sony/hotkey"); | 3108 | strcpy(acpi_device_class(device), "sony/hotkey"); |
| @@ -2810,16 +3112,14 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2810 | /* read _PRS resources */ | 3112 | /* read _PRS resources */ |
| 2811 | result = sony_pic_possible_resources(device); | 3113 | result = sony_pic_possible_resources(device); |
| 2812 | if (result) { | 3114 | if (result) { |
| 2813 | printk(KERN_ERR DRV_PFX | 3115 | pr_err(DRV_PFX "Unable to read possible resources.\n"); |
| 2814 | "Unable to read possible resources.\n"); | ||
| 2815 | goto err_free_resources; | 3116 | goto err_free_resources; |
| 2816 | } | 3117 | } |
| 2817 | 3118 | ||
| 2818 | /* setup input devices and helper fifo */ | 3119 | /* setup input devices and helper fifo */ |
| 2819 | result = sony_laptop_setup_input(device); | 3120 | result = sony_laptop_setup_input(device); |
| 2820 | if (result) { | 3121 | if (result) { |
| 2821 | printk(KERN_ERR DRV_PFX | 3122 | pr_err(DRV_PFX "Unable to create input devices.\n"); |
| 2822 | "Unable to create input devices.\n"); | ||
| 2823 | goto err_free_resources; | 3123 | goto err_free_resources; |
| 2824 | } | 3124 | } |
| 2825 | 3125 | ||
| @@ -2829,7 +3129,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2829 | /* request io port */ | 3129 | /* request io port */ |
| 2830 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { | 3130 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { |
| 2831 | if (request_region(io->io1.minimum, io->io1.address_length, | 3131 | if (request_region(io->io1.minimum, io->io1.address_length, |
| 2832 | "Sony Programable I/O Device")) { | 3132 | "Sony Programmable I/O Device")) { |
| 2833 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", | 3133 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", |
| 2834 | io->io1.minimum, io->io1.maximum, | 3134 | io->io1.minimum, io->io1.maximum, |
| 2835 | io->io1.address_length); | 3135 | io->io1.address_length); |
| @@ -2837,7 +3137,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2837 | if (io->io2.minimum) { | 3137 | if (io->io2.minimum) { |
| 2838 | if (request_region(io->io2.minimum, | 3138 | if (request_region(io->io2.minimum, |
| 2839 | io->io2.address_length, | 3139 | io->io2.address_length, |
| 2840 | "Sony Programable I/O Device")) { | 3140 | "Sony Programmable I/O Device")) { |
| 2841 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", | 3141 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", |
| 2842 | io->io2.minimum, io->io2.maximum, | 3142 | io->io2.minimum, io->io2.maximum, |
| 2843 | io->io2.address_length); | 3143 | io->io2.address_length); |
| @@ -2860,7 +3160,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2860 | } | 3160 | } |
| 2861 | } | 3161 | } |
| 2862 | if (!spic_dev.cur_ioport) { | 3162 | if (!spic_dev.cur_ioport) { |
| 2863 | printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); | 3163 | pr_err(DRV_PFX "Failed to request_region.\n"); |
| 2864 | result = -ENODEV; | 3164 | result = -ENODEV; |
| 2865 | goto err_remove_compat; | 3165 | goto err_remove_compat; |
| 2866 | } | 3166 | } |
| @@ -2880,7 +3180,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2880 | } | 3180 | } |
| 2881 | } | 3181 | } |
| 2882 | if (!spic_dev.cur_irq) { | 3182 | if (!spic_dev.cur_irq) { |
| 2883 | printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); | 3183 | pr_err(DRV_PFX "Failed to request_irq.\n"); |
| 2884 | result = -ENODEV; | 3184 | result = -ENODEV; |
| 2885 | goto err_release_region; | 3185 | goto err_release_region; |
| 2886 | } | 3186 | } |
| @@ -2888,7 +3188,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 2888 | /* set resource status _SRS */ | 3188 | /* set resource status _SRS */ |
| 2889 | result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); | 3189 | result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); |
| 2890 | if (result) { | 3190 | if (result) { |
| 2891 | printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); | 3191 | pr_err(DRV_PFX "Couldn't enable device.\n"); |
| 2892 | goto err_free_irq; | 3192 | goto err_free_irq; |
| 2893 | } | 3193 | } |
| 2894 | 3194 | ||
| @@ -2997,8 +3297,7 @@ static int __init sony_laptop_init(void) | |||
| 2997 | if (!no_spic && dmi_check_system(sonypi_dmi_table)) { | 3297 | if (!no_spic && dmi_check_system(sonypi_dmi_table)) { |
| 2998 | result = acpi_bus_register_driver(&sony_pic_driver); | 3298 | result = acpi_bus_register_driver(&sony_pic_driver); |
| 2999 | if (result) { | 3299 | if (result) { |
| 3000 | printk(KERN_ERR DRV_PFX | 3300 | pr_err(DRV_PFX "Unable to register SPIC driver."); |
| 3001 | "Unable to register SPIC driver."); | ||
| 3002 | goto out; | 3301 | goto out; |
| 3003 | } | 3302 | } |
| 3004 | spic_drv_registered = 1; | 3303 | spic_drv_registered = 1; |
| @@ -3006,7 +3305,7 @@ static int __init sony_laptop_init(void) | |||
| 3006 | 3305 | ||
| 3007 | result = acpi_bus_register_driver(&sony_nc_driver); | 3306 | result = acpi_bus_register_driver(&sony_nc_driver); |
| 3008 | if (result) { | 3307 | if (result) { |
| 3009 | printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); | 3308 | pr_err(DRV_PFX "Unable to register SNC driver."); |
| 3010 | goto out_unregister_pic; | 3309 | goto out_unregister_pic; |
| 3011 | } | 3310 | } |
| 3012 | 3311 | ||
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 947bdcaa0ce9..a08561f5349e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -2407,7 +2407,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, | |||
| 2407 | * This code is supposed to duplicate the IBM firmware behaviour: | 2407 | * This code is supposed to duplicate the IBM firmware behaviour: |
| 2408 | * - Pressing MUTE issues mute hotkey message, even when already mute | 2408 | * - Pressing MUTE issues mute hotkey message, even when already mute |
| 2409 | * - Pressing Volume up/down issues volume up/down hotkey messages, | 2409 | * - Pressing Volume up/down issues volume up/down hotkey messages, |
| 2410 | * even when already at maximum or minumum volume | 2410 | * even when already at maximum or minimum volume |
| 2411 | * - The act of unmuting issues volume up/down notification, | 2411 | * - The act of unmuting issues volume up/down notification, |
| 2412 | * depending which key was used to unmute | 2412 | * depending which key was used to unmute |
| 2413 | * | 2413 | * |
| @@ -2990,7 +2990,7 @@ static void tpacpi_send_radiosw_update(void) | |||
| 2990 | * rfkill input events, or we will race the rfkill core input | 2990 | * rfkill input events, or we will race the rfkill core input |
| 2991 | * handler. | 2991 | * handler. |
| 2992 | * | 2992 | * |
| 2993 | * tpacpi_inputdev_send_mutex works as a syncronization point | 2993 | * tpacpi_inputdev_send_mutex works as a synchronization point |
| 2994 | * for the above. | 2994 | * for the above. |
| 2995 | * | 2995 | * |
| 2996 | * We optimize to avoid numerous calls to hotkey_get_wlsw. | 2996 | * We optimize to avoid numerous calls to hotkey_get_wlsw. |
diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c new file mode 100644 index 000000000000..c1372ed9d2e9 --- /dev/null +++ b/drivers/platform/x86/xo15-ebook.c | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | /* | ||
| 2 | * OLPC XO-1.5 ebook switch driver | ||
| 3 | * (based on generic ACPI button driver) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2009 Paul Fox <pgf@laptop.org> | ||
| 6 | * Copyright (C) 2010 One Laptop per Child | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
| 11 | * your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/input.h> | ||
| 19 | #include <acpi/acpi_bus.h> | ||
| 20 | #include <acpi/acpi_drivers.h> | ||
| 21 | |||
| 22 | #define MODULE_NAME "xo15-ebook" | ||
| 23 | #define PREFIX MODULE_NAME ": " | ||
| 24 | |||
| 25 | #define XO15_EBOOK_CLASS MODULE_NAME | ||
| 26 | #define XO15_EBOOK_TYPE_UNKNOWN 0x00 | ||
| 27 | #define XO15_EBOOK_NOTIFY_STATUS 0x80 | ||
| 28 | |||
| 29 | #define XO15_EBOOK_SUBCLASS "ebook" | ||
| 30 | #define XO15_EBOOK_HID "XO15EBK" | ||
| 31 | #define XO15_EBOOK_DEVICE_NAME "EBook Switch" | ||
| 32 | |||
| 33 | ACPI_MODULE_NAME(MODULE_NAME); | ||
| 34 | |||
| 35 | MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver"); | ||
| 36 | MODULE_LICENSE("GPL"); | ||
| 37 | |||
| 38 | static const struct acpi_device_id ebook_device_ids[] = { | ||
| 39 | { XO15_EBOOK_HID, 0 }, | ||
| 40 | { "", 0 }, | ||
| 41 | }; | ||
| 42 | MODULE_DEVICE_TABLE(acpi, ebook_device_ids); | ||
| 43 | |||
| 44 | struct ebook_switch { | ||
| 45 | struct input_dev *input; | ||
| 46 | char phys[32]; /* for input device */ | ||
| 47 | }; | ||
| 48 | |||
| 49 | static int ebook_send_state(struct acpi_device *device) | ||
| 50 | { | ||
| 51 | struct ebook_switch *button = acpi_driver_data(device); | ||
| 52 | unsigned long long state; | ||
| 53 | acpi_status status; | ||
| 54 | |||
| 55 | status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state); | ||
| 56 | if (ACPI_FAILURE(status)) | ||
| 57 | return -EIO; | ||
| 58 | |||
| 59 | /* input layer checks if event is redundant */ | ||
| 60 | input_report_switch(button->input, SW_TABLET_MODE, !state); | ||
| 61 | input_sync(button->input); | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static void ebook_switch_notify(struct acpi_device *device, u32 event) | ||
| 66 | { | ||
| 67 | switch (event) { | ||
| 68 | case ACPI_FIXED_HARDWARE_EVENT: | ||
| 69 | case XO15_EBOOK_NOTIFY_STATUS: | ||
| 70 | ebook_send_state(device); | ||
| 71 | break; | ||
| 72 | default: | ||
| 73 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
| 74 | "Unsupported event [0x%x]\n", event)); | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | static int ebook_switch_resume(struct acpi_device *device) | ||
| 80 | { | ||
| 81 | return ebook_send_state(device); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int ebook_switch_add(struct acpi_device *device) | ||
| 85 | { | ||
| 86 | struct ebook_switch *button; | ||
| 87 | struct input_dev *input; | ||
| 88 | const char *hid = acpi_device_hid(device); | ||
| 89 | char *name, *class; | ||
| 90 | int error; | ||
| 91 | |||
| 92 | button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL); | ||
| 93 | if (!button) | ||
| 94 | return -ENOMEM; | ||
| 95 | |||
| 96 | device->driver_data = button; | ||
| 97 | |||
| 98 | button->input = input = input_allocate_device(); | ||
| 99 | if (!input) { | ||
| 100 | error = -ENOMEM; | ||
| 101 | goto err_free_button; | ||
| 102 | } | ||
| 103 | |||
| 104 | name = acpi_device_name(device); | ||
| 105 | class = acpi_device_class(device); | ||
| 106 | |||
| 107 | if (strcmp(hid, XO15_EBOOK_HID)) { | ||
| 108 | printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); | ||
| 109 | error = -ENODEV; | ||
| 110 | goto err_free_input; | ||
| 111 | } | ||
| 112 | |||
| 113 | strcpy(name, XO15_EBOOK_DEVICE_NAME); | ||
| 114 | sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); | ||
| 115 | |||
| 116 | snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); | ||
| 117 | |||
| 118 | input->name = name; | ||
| 119 | input->phys = button->phys; | ||
| 120 | input->id.bustype = BUS_HOST; | ||
| 121 | input->dev.parent = &device->dev; | ||
| 122 | |||
| 123 | input->evbit[0] = BIT_MASK(EV_SW); | ||
| 124 | set_bit(SW_TABLET_MODE, input->swbit); | ||
| 125 | |||
| 126 | error = input_register_device(input); | ||
| 127 | if (error) | ||
| 128 | goto err_free_input; | ||
| 129 | |||
| 130 | ebook_send_state(device); | ||
| 131 | |||
| 132 | if (device->wakeup.flags.valid) { | ||
| 133 | /* Button's GPE is run-wake GPE */ | ||
| 134 | acpi_enable_gpe(device->wakeup.gpe_device, | ||
| 135 | device->wakeup.gpe_number); | ||
| 136 | device_set_wakeup_enable(&device->dev, true); | ||
| 137 | } | ||
| 138 | |||
| 139 | return 0; | ||
| 140 | |||
| 141 | err_free_input: | ||
| 142 | input_free_device(input); | ||
| 143 | err_free_button: | ||
| 144 | kfree(button); | ||
| 145 | return error; | ||
| 146 | } | ||
| 147 | |||
| 148 | static int ebook_switch_remove(struct acpi_device *device, int type) | ||
| 149 | { | ||
| 150 | struct ebook_switch *button = acpi_driver_data(device); | ||
| 151 | |||
| 152 | input_unregister_device(button->input); | ||
| 153 | kfree(button); | ||
| 154 | return 0; | ||
| 155 | } | ||
| 156 | |||
| 157 | static struct acpi_driver xo15_ebook_driver = { | ||
| 158 | .name = MODULE_NAME, | ||
| 159 | .class = XO15_EBOOK_CLASS, | ||
| 160 | .ids = ebook_device_ids, | ||
| 161 | .ops = { | ||
| 162 | .add = ebook_switch_add, | ||
| 163 | .resume = ebook_switch_resume, | ||
| 164 | .remove = ebook_switch_remove, | ||
| 165 | .notify = ebook_switch_notify, | ||
| 166 | }, | ||
| 167 | }; | ||
| 168 | |||
| 169 | static int __init xo15_ebook_init(void) | ||
| 170 | { | ||
| 171 | return acpi_bus_register_driver(&xo15_ebook_driver); | ||
| 172 | } | ||
| 173 | |||
| 174 | static void __exit xo15_ebook_exit(void) | ||
| 175 | { | ||
| 176 | acpi_bus_unregister_driver(&xo15_ebook_driver); | ||
| 177 | } | ||
| 178 | |||
| 179 | module_init(xo15_ebook_init); | ||
| 180 | module_exit(xo15_ebook_exit); | ||
diff --git a/drivers/vlynq/vlynq.c b/drivers/vlynq/vlynq.c index f885c868a04d..aa250cebecd2 100644 --- a/drivers/vlynq/vlynq.c +++ b/drivers/vlynq/vlynq.c | |||
| @@ -135,40 +135,40 @@ static void vlynq_reset(struct vlynq_device *dev) | |||
| 135 | msleep(5); | 135 | msleep(5); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | static void vlynq_irq_unmask(unsigned int irq) | 138 | static void vlynq_irq_unmask(struct irq_data *d) |
| 139 | { | 139 | { |
| 140 | u32 val; | 140 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
| 141 | struct vlynq_device *dev = get_irq_chip_data(irq); | ||
| 142 | int virq; | 141 | int virq; |
| 142 | u32 val; | ||
| 143 | 143 | ||
| 144 | BUG_ON(!dev); | 144 | BUG_ON(!dev); |
| 145 | virq = irq - dev->irq_start; | 145 | virq = d->irq - dev->irq_start; |
| 146 | val = readl(&dev->remote->int_device[virq >> 2]); | 146 | val = readl(&dev->remote->int_device[virq >> 2]); |
| 147 | val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); | 147 | val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); |
| 148 | writel(val, &dev->remote->int_device[virq >> 2]); | 148 | writel(val, &dev->remote->int_device[virq >> 2]); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | static void vlynq_irq_mask(unsigned int irq) | 151 | static void vlynq_irq_mask(struct irq_data *d) |
| 152 | { | 152 | { |
| 153 | u32 val; | 153 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
| 154 | struct vlynq_device *dev = get_irq_chip_data(irq); | ||
| 155 | int virq; | 154 | int virq; |
| 155 | u32 val; | ||
| 156 | 156 | ||
| 157 | BUG_ON(!dev); | 157 | BUG_ON(!dev); |
| 158 | virq = irq - dev->irq_start; | 158 | virq = d->irq - dev->irq_start; |
| 159 | val = readl(&dev->remote->int_device[virq >> 2]); | 159 | val = readl(&dev->remote->int_device[virq >> 2]); |
| 160 | val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); | 160 | val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); |
| 161 | writel(val, &dev->remote->int_device[virq >> 2]); | 161 | writel(val, &dev->remote->int_device[virq >> 2]); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) | 164 | static int vlynq_irq_type(struct irq_data *d, unsigned int flow_type) |
| 165 | { | 165 | { |
| 166 | u32 val; | 166 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
| 167 | struct vlynq_device *dev = get_irq_chip_data(irq); | ||
| 168 | int virq; | 167 | int virq; |
| 168 | u32 val; | ||
| 169 | 169 | ||
| 170 | BUG_ON(!dev); | 170 | BUG_ON(!dev); |
| 171 | virq = irq - dev->irq_start; | 171 | virq = d->irq - dev->irq_start; |
| 172 | val = readl(&dev->remote->int_device[virq >> 2]); | 172 | val = readl(&dev->remote->int_device[virq >> 2]); |
| 173 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { | 173 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { |
| 174 | case IRQ_TYPE_EDGE_RISING: | 174 | case IRQ_TYPE_EDGE_RISING: |
| @@ -192,10 +192,9 @@ static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) | |||
| 192 | return 0; | 192 | return 0; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | static void vlynq_local_ack(unsigned int irq) | 195 | static void vlynq_local_ack(struct irq_data *d) |
| 196 | { | 196 | { |
| 197 | struct vlynq_device *dev = get_irq_chip_data(irq); | 197 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
| 198 | |||
| 199 | u32 status = readl(&dev->local->status); | 198 | u32 status = readl(&dev->local->status); |
| 200 | 199 | ||
| 201 | pr_debug("%s: local status: 0x%08x\n", | 200 | pr_debug("%s: local status: 0x%08x\n", |
| @@ -203,10 +202,9 @@ static void vlynq_local_ack(unsigned int irq) | |||
| 203 | writel(status, &dev->local->status); | 202 | writel(status, &dev->local->status); |
| 204 | } | 203 | } |
| 205 | 204 | ||
| 206 | static void vlynq_remote_ack(unsigned int irq) | 205 | static void vlynq_remote_ack(struct irq_data *d) |
| 207 | { | 206 | { |
| 208 | struct vlynq_device *dev = get_irq_chip_data(irq); | 207 | struct vlynq_device *dev = irq_data_get_irq_chip_data(d); |
| 209 | |||
| 210 | u32 status = readl(&dev->remote->status); | 208 | u32 status = readl(&dev->remote->status); |
| 211 | 209 | ||
| 212 | pr_debug("%s: remote status: 0x%08x\n", | 210 | pr_debug("%s: remote status: 0x%08x\n", |
| @@ -238,23 +236,23 @@ static irqreturn_t vlynq_irq(int irq, void *dev_id) | |||
| 238 | 236 | ||
| 239 | static struct irq_chip vlynq_irq_chip = { | 237 | static struct irq_chip vlynq_irq_chip = { |
| 240 | .name = "vlynq", | 238 | .name = "vlynq", |
| 241 | .unmask = vlynq_irq_unmask, | 239 | .irq_unmask = vlynq_irq_unmask, |
| 242 | .mask = vlynq_irq_mask, | 240 | .irq_mask = vlynq_irq_mask, |
| 243 | .set_type = vlynq_irq_type, | 241 | .irq_set_type = vlynq_irq_type, |
| 244 | }; | 242 | }; |
| 245 | 243 | ||
| 246 | static struct irq_chip vlynq_local_chip = { | 244 | static struct irq_chip vlynq_local_chip = { |
| 247 | .name = "vlynq local error", | 245 | .name = "vlynq local error", |
| 248 | .unmask = vlynq_irq_unmask, | 246 | .irq_unmask = vlynq_irq_unmask, |
| 249 | .mask = vlynq_irq_mask, | 247 | .irq_mask = vlynq_irq_mask, |
| 250 | .ack = vlynq_local_ack, | 248 | .irq_ack = vlynq_local_ack, |
| 251 | }; | 249 | }; |
| 252 | 250 | ||
| 253 | static struct irq_chip vlynq_remote_chip = { | 251 | static struct irq_chip vlynq_remote_chip = { |
| 254 | .name = "vlynq local error", | 252 | .name = "vlynq local error", |
| 255 | .unmask = vlynq_irq_unmask, | 253 | .irq_unmask = vlynq_irq_unmask, |
| 256 | .mask = vlynq_irq_mask, | 254 | .irq_mask = vlynq_irq_mask, |
| 257 | .ack = vlynq_remote_ack, | 255 | .irq_ack = vlynq_remote_ack, |
| 258 | }; | 256 | }; |
| 259 | 257 | ||
| 260 | static int vlynq_setup_irq(struct vlynq_device *dev) | 258 | static int vlynq_setup_irq(struct vlynq_device *dev) |
| @@ -291,17 +289,17 @@ static int vlynq_setup_irq(struct vlynq_device *dev) | |||
| 291 | for (i = dev->irq_start; i <= dev->irq_end; i++) { | 289 | for (i = dev->irq_start; i <= dev->irq_end; i++) { |
| 292 | virq = i - dev->irq_start; | 290 | virq = i - dev->irq_start; |
| 293 | if (virq == dev->local_irq) { | 291 | if (virq == dev->local_irq) { |
| 294 | set_irq_chip_and_handler(i, &vlynq_local_chip, | 292 | irq_set_chip_and_handler(i, &vlynq_local_chip, |
| 295 | handle_level_irq); | 293 | handle_level_irq); |
| 296 | set_irq_chip_data(i, dev); | 294 | irq_set_chip_data(i, dev); |
| 297 | } else if (virq == dev->remote_irq) { | 295 | } else if (virq == dev->remote_irq) { |
| 298 | set_irq_chip_and_handler(i, &vlynq_remote_chip, | 296 | irq_set_chip_and_handler(i, &vlynq_remote_chip, |
| 299 | handle_level_irq); | 297 | handle_level_irq); |
| 300 | set_irq_chip_data(i, dev); | 298 | irq_set_chip_data(i, dev); |
| 301 | } else { | 299 | } else { |
| 302 | set_irq_chip_and_handler(i, &vlynq_irq_chip, | 300 | irq_set_chip_and_handler(i, &vlynq_irq_chip, |
| 303 | handle_simple_irq); | 301 | handle_simple_irq); |
| 304 | set_irq_chip_data(i, dev); | 302 | irq_set_chip_data(i, dev); |
| 305 | writel(0, &dev->remote->int_device[virq >> 2]); | 303 | writel(0, &dev->remote->int_device[virq >> 2]); |
| 306 | } | 304 | } |
| 307 | } | 305 | } |
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index ccc991c542df..57c3bb2884ce 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
| @@ -136,9 +136,8 @@ struct btrfs_inode { | |||
| 136 | * items we think we'll end up using, and reserved_extents is the number | 136 | * items we think we'll end up using, and reserved_extents is the number |
| 137 | * of extent items we've reserved metadata for. | 137 | * of extent items we've reserved metadata for. |
| 138 | */ | 138 | */ |
| 139 | spinlock_t accounting_lock; | ||
| 140 | atomic_t outstanding_extents; | 139 | atomic_t outstanding_extents; |
| 141 | int reserved_extents; | 140 | atomic_t reserved_extents; |
| 142 | 141 | ||
| 143 | /* | 142 | /* |
| 144 | * ordered_data_close is set by truncate when a file that used | 143 | * ordered_data_close is set by truncate when a file that used |
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 4d2110eafe29..41d1d7c70e29 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
| @@ -340,6 +340,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, | |||
| 340 | 340 | ||
| 341 | WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1)); | 341 | WARN_ON(start & ((u64)PAGE_CACHE_SIZE - 1)); |
| 342 | cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS); | 342 | cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS); |
| 343 | if (!cb) | ||
| 344 | return -ENOMEM; | ||
| 343 | atomic_set(&cb->pending_bios, 0); | 345 | atomic_set(&cb->pending_bios, 0); |
| 344 | cb->errors = 0; | 346 | cb->errors = 0; |
| 345 | cb->inode = inode; | 347 | cb->inode = inode; |
| @@ -354,6 +356,10 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, | |||
| 354 | bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; | 356 | bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; |
| 355 | 357 | ||
| 356 | bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); | 358 | bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); |
| 359 | if(!bio) { | ||
| 360 | kfree(cb); | ||
| 361 | return -ENOMEM; | ||
| 362 | } | ||
| 357 | bio->bi_private = cb; | 363 | bio->bi_private = cb; |
| 358 | bio->bi_end_io = end_compressed_bio_write; | 364 | bio->bi_end_io = end_compressed_bio_write; |
| 359 | atomic_inc(&cb->pending_bios); | 365 | atomic_inc(&cb->pending_bios); |
| @@ -657,8 +663,9 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | |||
| 657 | atomic_inc(&cb->pending_bios); | 663 | atomic_inc(&cb->pending_bios); |
| 658 | 664 | ||
| 659 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { | 665 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { |
| 660 | btrfs_lookup_bio_sums(root, inode, comp_bio, | 666 | ret = btrfs_lookup_bio_sums(root, inode, |
| 661 | sums); | 667 | comp_bio, sums); |
| 668 | BUG_ON(ret); | ||
| 662 | } | 669 | } |
| 663 | sums += (comp_bio->bi_size + root->sectorsize - 1) / | 670 | sums += (comp_bio->bi_size + root->sectorsize - 1) / |
| 664 | root->sectorsize; | 671 | root->sectorsize; |
| @@ -683,8 +690,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | |||
| 683 | ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0); | 690 | ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0); |
| 684 | BUG_ON(ret); | 691 | BUG_ON(ret); |
| 685 | 692 | ||
| 686 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) | 693 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { |
| 687 | btrfs_lookup_bio_sums(root, inode, comp_bio, sums); | 694 | ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums); |
| 695 | BUG_ON(ret); | ||
| 696 | } | ||
| 688 | 697 | ||
| 689 | ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); | 698 | ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); |
| 690 | BUG_ON(ret); | 699 | BUG_ON(ret); |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index b5baff0dccfe..84d7ca1fe0ba 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -147,10 +147,11 @@ noinline void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | |||
| 147 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root) | 147 | struct extent_buffer *btrfs_root_node(struct btrfs_root *root) |
| 148 | { | 148 | { |
| 149 | struct extent_buffer *eb; | 149 | struct extent_buffer *eb; |
| 150 | spin_lock(&root->node_lock); | 150 | |
| 151 | eb = root->node; | 151 | rcu_read_lock(); |
| 152 | eb = rcu_dereference(root->node); | ||
| 152 | extent_buffer_get(eb); | 153 | extent_buffer_get(eb); |
| 153 | spin_unlock(&root->node_lock); | 154 | rcu_read_unlock(); |
| 154 | return eb; | 155 | return eb; |
| 155 | } | 156 | } |
| 156 | 157 | ||
| @@ -165,14 +166,8 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root) | |||
| 165 | while (1) { | 166 | while (1) { |
| 166 | eb = btrfs_root_node(root); | 167 | eb = btrfs_root_node(root); |
| 167 | btrfs_tree_lock(eb); | 168 | btrfs_tree_lock(eb); |
| 168 | 169 | if (eb == root->node) | |
| 169 | spin_lock(&root->node_lock); | ||
| 170 | if (eb == root->node) { | ||
| 171 | spin_unlock(&root->node_lock); | ||
| 172 | break; | 170 | break; |
| 173 | } | ||
| 174 | spin_unlock(&root->node_lock); | ||
| 175 | |||
| 176 | btrfs_tree_unlock(eb); | 171 | btrfs_tree_unlock(eb); |
| 177 | free_extent_buffer(eb); | 172 | free_extent_buffer(eb); |
| 178 | } | 173 | } |
| @@ -458,10 +453,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
| 458 | else | 453 | else |
| 459 | parent_start = 0; | 454 | parent_start = 0; |
| 460 | 455 | ||
| 461 | spin_lock(&root->node_lock); | ||
| 462 | root->node = cow; | ||
| 463 | extent_buffer_get(cow); | 456 | extent_buffer_get(cow); |
| 464 | spin_unlock(&root->node_lock); | 457 | rcu_assign_pointer(root->node, cow); |
| 465 | 458 | ||
| 466 | btrfs_free_tree_block(trans, root, buf, parent_start, | 459 | btrfs_free_tree_block(trans, root, buf, parent_start, |
| 467 | last_ref); | 460 | last_ref); |
| @@ -542,6 +535,9 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
| 542 | 535 | ||
| 543 | ret = __btrfs_cow_block(trans, root, buf, parent, | 536 | ret = __btrfs_cow_block(trans, root, buf, parent, |
| 544 | parent_slot, cow_ret, search_start, 0); | 537 | parent_slot, cow_ret, search_start, 0); |
| 538 | |||
| 539 | trace_btrfs_cow_block(root, buf, *cow_ret); | ||
| 540 | |||
| 545 | return ret; | 541 | return ret; |
| 546 | } | 542 | } |
| 547 | 543 | ||
| @@ -686,6 +682,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, | |||
| 686 | if (!cur) { | 682 | if (!cur) { |
| 687 | cur = read_tree_block(root, blocknr, | 683 | cur = read_tree_block(root, blocknr, |
| 688 | blocksize, gen); | 684 | blocksize, gen); |
| 685 | if (!cur) | ||
| 686 | return -EIO; | ||
| 689 | } else if (!uptodate) { | 687 | } else if (!uptodate) { |
| 690 | btrfs_read_buffer(cur, gen); | 688 | btrfs_read_buffer(cur, gen); |
| 691 | } | 689 | } |
| @@ -732,122 +730,6 @@ static inline unsigned int leaf_data_end(struct btrfs_root *root, | |||
| 732 | return btrfs_item_offset_nr(leaf, nr - 1); | 730 | return btrfs_item_offset_nr(leaf, nr - 1); |
| 733 | } | 731 | } |
| 734 | 732 | ||
| 735 | /* | ||
| 736 | * extra debugging checks to make sure all the items in a key are | ||
| 737 | * well formed and in the proper order | ||
| 738 | */ | ||
| 739 | static int check_node(struct btrfs_root *root, struct btrfs_path *path, | ||
| 740 | int level) | ||
| 741 | { | ||
| 742 | struct extent_buffer *parent = NULL; | ||
| 743 | struct extent_buffer *node = path->nodes[level]; | ||
| 744 | struct btrfs_disk_key parent_key; | ||
| 745 | struct btrfs_disk_key node_key; | ||
| 746 | int parent_slot; | ||
| 747 | int slot; | ||
| 748 | struct btrfs_key cpukey; | ||
| 749 | u32 nritems = btrfs_header_nritems(node); | ||
| 750 | |||
| 751 | if (path->nodes[level + 1]) | ||
| 752 | parent = path->nodes[level + 1]; | ||
| 753 | |||
| 754 | slot = path->slots[level]; | ||
| 755 | BUG_ON(nritems == 0); | ||
| 756 | if (parent) { | ||
| 757 | parent_slot = path->slots[level + 1]; | ||
| 758 | btrfs_node_key(parent, &parent_key, parent_slot); | ||
| 759 | btrfs_node_key(node, &node_key, 0); | ||
| 760 | BUG_ON(memcmp(&parent_key, &node_key, | ||
| 761 | sizeof(struct btrfs_disk_key))); | ||
| 762 | BUG_ON(btrfs_node_blockptr(parent, parent_slot) != | ||
| 763 | btrfs_header_bytenr(node)); | ||
| 764 | } | ||
| 765 | BUG_ON(nritems > BTRFS_NODEPTRS_PER_BLOCK(root)); | ||
| 766 | if (slot != 0) { | ||
| 767 | btrfs_node_key_to_cpu(node, &cpukey, slot - 1); | ||
| 768 | btrfs_node_key(node, &node_key, slot); | ||
| 769 | BUG_ON(comp_keys(&node_key, &cpukey) <= 0); | ||
| 770 | } | ||
| 771 | if (slot < nritems - 1) { | ||
| 772 | btrfs_node_key_to_cpu(node, &cpukey, slot + 1); | ||
| 773 | btrfs_node_key(node, &node_key, slot); | ||
| 774 | BUG_ON(comp_keys(&node_key, &cpukey) >= 0); | ||
| 775 | } | ||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | /* | ||
| 780 | * extra checking to make sure all the items in a leaf are | ||
| 781 | * well formed and in the proper order | ||
| 782 | */ | ||
| 783 | static int check_leaf(struct btrfs_root *root, struct btrfs_path *path, | ||
| 784 | int level) | ||
| 785 | { | ||
| 786 | struct extent_buffer *leaf = path->nodes[level]; | ||
| 787 | struct extent_buffer *parent = NULL; | ||
| 788 | int parent_slot; | ||
| 789 | struct btrfs_key cpukey; | ||
| 790 | struct btrfs_disk_key parent_key; | ||
| 791 | struct btrfs_disk_key leaf_key; | ||
| 792 | int slot = path->slots[0]; | ||
| 793 | |||
| 794 | u32 nritems = btrfs_header_nritems(leaf); | ||
| 795 | |||
| 796 | if (path->nodes[level + 1]) | ||
| 797 | parent = path->nodes[level + 1]; | ||
| 798 | |||
| 799 | if (nritems == 0) | ||
| 800 | return 0; | ||
| 801 | |||
| 802 | if (parent) { | ||
| 803 | parent_slot = path->slots[level + 1]; | ||
| 804 | btrfs_node_key(parent, &parent_key, parent_slot); | ||
| 805 | btrfs_item_key(leaf, &leaf_key, 0); | ||
| 806 | |||
| 807 | BUG_ON(memcmp(&parent_key, &leaf_key, | ||
| 808 | sizeof(struct btrfs_disk_key))); | ||
| 809 | BUG_ON(btrfs_node_blockptr(parent, parent_slot) != | ||
| 810 | btrfs_header_bytenr(leaf)); | ||
| 811 | } | ||
| 812 | if (slot != 0 && slot < nritems - 1) { | ||
| 813 | btrfs_item_key(leaf, &leaf_key, slot); | ||
| 814 | btrfs_item_key_to_cpu(leaf, &cpukey, slot - 1); | ||
| 815 | if (comp_keys(&leaf_key, &cpukey) <= 0) { | ||
| 816 | btrfs_print_leaf(root, leaf); | ||
| 817 | printk(KERN_CRIT "slot %d offset bad key\n", slot); | ||
| 818 | BUG_ON(1); | ||
| 819 | } | ||
| 820 | if (btrfs_item_offset_nr(leaf, slot - 1) != | ||
| 821 | btrfs_item_end_nr(leaf, slot)) { | ||
| 822 | btrfs_print_leaf(root, leaf); | ||
| 823 | printk(KERN_CRIT "slot %d offset bad\n", slot); | ||
| 824 | BUG_ON(1); | ||
| 825 | } | ||
| 826 | } | ||
| 827 | if (slot < nritems - 1) { | ||
| 828 | btrfs_item_key(leaf, &leaf_key, slot); | ||
| 829 | btrfs_item_key_to_cpu(leaf, &cpukey, slot + 1); | ||
| 830 | BUG_ON(comp_keys(&leaf_key, &cpukey) >= 0); | ||
| 831 | if (btrfs_item_offset_nr(leaf, slot) != | ||
| 832 | btrfs_item_end_nr(leaf, slot + 1)) { | ||
| 833 | btrfs_print_leaf(root, leaf); | ||
| 834 | printk(KERN_CRIT "slot %d offset bad\n", slot); | ||
| 835 | BUG_ON(1); | ||
| 836 | } | ||
| 837 | } | ||
| 838 | BUG_ON(btrfs_item_offset_nr(leaf, 0) + | ||
| 839 | btrfs_item_size_nr(leaf, 0) != BTRFS_LEAF_DATA_SIZE(root)); | ||
| 840 | return 0; | ||
| 841 | } | ||
| 842 | |||
| 843 | static noinline int check_block(struct btrfs_root *root, | ||
| 844 | struct btrfs_path *path, int level) | ||
| 845 | { | ||
| 846 | return 0; | ||
| 847 | if (level == 0) | ||
| 848 | return check_leaf(root, path, level); | ||
| 849 | return check_node(root, path, level); | ||
| 850 | } | ||
| 851 | 733 | ||
| 852 | /* | 734 | /* |
| 853 | * search for key in the extent_buffer. The items start at offset p, | 735 | * search for key in the extent_buffer. The items start at offset p, |
| @@ -1046,9 +928,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
| 1046 | goto enospc; | 928 | goto enospc; |
| 1047 | } | 929 | } |
| 1048 | 930 | ||
| 1049 | spin_lock(&root->node_lock); | 931 | rcu_assign_pointer(root->node, child); |
| 1050 | root->node = child; | ||
| 1051 | spin_unlock(&root->node_lock); | ||
| 1052 | 932 | ||
| 1053 | add_root_to_dirty_list(root); | 933 | add_root_to_dirty_list(root); |
| 1054 | btrfs_tree_unlock(child); | 934 | btrfs_tree_unlock(child); |
| @@ -1188,7 +1068,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
| 1188 | } | 1068 | } |
| 1189 | } | 1069 | } |
| 1190 | /* double check we haven't messed things up */ | 1070 | /* double check we haven't messed things up */ |
| 1191 | check_block(root, path, level); | ||
| 1192 | if (orig_ptr != | 1071 | if (orig_ptr != |
| 1193 | btrfs_node_blockptr(path->nodes[level], path->slots[level])) | 1072 | btrfs_node_blockptr(path->nodes[level], path->slots[level])) |
| 1194 | BUG(); | 1073 | BUG(); |
| @@ -1798,12 +1677,6 @@ cow_done: | |||
| 1798 | if (!cow) | 1677 | if (!cow) |
| 1799 | btrfs_unlock_up_safe(p, level + 1); | 1678 | btrfs_unlock_up_safe(p, level + 1); |
| 1800 | 1679 | ||
| 1801 | ret = check_block(root, p, level); | ||
| 1802 | if (ret) { | ||
| 1803 | ret = -1; | ||
| 1804 | goto done; | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | ret = bin_search(b, key, level, &slot); | 1680 | ret = bin_search(b, key, level, &slot); |
| 1808 | 1681 | ||
| 1809 | if (level != 0) { | 1682 | if (level != 0) { |
| @@ -2130,10 +2003,8 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, | |||
| 2130 | 2003 | ||
| 2131 | btrfs_mark_buffer_dirty(c); | 2004 | btrfs_mark_buffer_dirty(c); |
| 2132 | 2005 | ||
| 2133 | spin_lock(&root->node_lock); | ||
| 2134 | old = root->node; | 2006 | old = root->node; |
| 2135 | root->node = c; | 2007 | rcu_assign_pointer(root->node, c); |
| 2136 | spin_unlock(&root->node_lock); | ||
| 2137 | 2008 | ||
| 2138 | /* the super has an extra ref to root->node */ | 2009 | /* the super has an extra ref to root->node */ |
| 2139 | free_extent_buffer(old); | 2010 | free_extent_buffer(old); |
| @@ -3840,7 +3711,8 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 3840 | unsigned long ptr; | 3711 | unsigned long ptr; |
| 3841 | 3712 | ||
| 3842 | path = btrfs_alloc_path(); | 3713 | path = btrfs_alloc_path(); |
| 3843 | BUG_ON(!path); | 3714 | if (!path) |
| 3715 | return -ENOMEM; | ||
| 3844 | ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); | 3716 | ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); |
| 3845 | if (!ret) { | 3717 | if (!ret) { |
| 3846 | leaf = path->nodes[0]; | 3718 | leaf = path->nodes[0]; |
| @@ -4217,6 +4089,7 @@ find_next_key: | |||
| 4217 | } | 4089 | } |
| 4218 | btrfs_set_path_blocking(path); | 4090 | btrfs_set_path_blocking(path); |
| 4219 | cur = read_node_slot(root, cur, slot); | 4091 | cur = read_node_slot(root, cur, slot); |
| 4092 | BUG_ON(!cur); | ||
| 4220 | 4093 | ||
| 4221 | btrfs_tree_lock(cur); | 4094 | btrfs_tree_lock(cur); |
| 4222 | 4095 | ||
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7f78cc78fdd0..d47ce8307854 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/wait.h> | 28 | #include <linux/wait.h> |
| 29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | #include <linux/kobject.h> | 30 | #include <linux/kobject.h> |
| 31 | #include <trace/events/btrfs.h> | ||
| 31 | #include <asm/kmap_types.h> | 32 | #include <asm/kmap_types.h> |
| 32 | #include "extent_io.h" | 33 | #include "extent_io.h" |
| 33 | #include "extent_map.h" | 34 | #include "extent_map.h" |
| @@ -40,6 +41,7 @@ extern struct kmem_cache *btrfs_trans_handle_cachep; | |||
| 40 | extern struct kmem_cache *btrfs_transaction_cachep; | 41 | extern struct kmem_cache *btrfs_transaction_cachep; |
| 41 | extern struct kmem_cache *btrfs_bit_radix_cachep; | 42 | extern struct kmem_cache *btrfs_bit_radix_cachep; |
| 42 | extern struct kmem_cache *btrfs_path_cachep; | 43 | extern struct kmem_cache *btrfs_path_cachep; |
| 44 | extern struct kmem_cache *btrfs_free_space_cachep; | ||
| 43 | struct btrfs_ordered_sum; | 45 | struct btrfs_ordered_sum; |
| 44 | 46 | ||
| 45 | #define BTRFS_MAGIC "_BHRfS_M" | 47 | #define BTRFS_MAGIC "_BHRfS_M" |
| @@ -782,9 +784,6 @@ struct btrfs_free_cluster { | |||
| 782 | /* first extent starting offset */ | 784 | /* first extent starting offset */ |
| 783 | u64 window_start; | 785 | u64 window_start; |
| 784 | 786 | ||
| 785 | /* if this cluster simply points at a bitmap in the block group */ | ||
| 786 | bool points_to_bitmap; | ||
| 787 | |||
| 788 | struct btrfs_block_group_cache *block_group; | 787 | struct btrfs_block_group_cache *block_group; |
| 789 | /* | 788 | /* |
| 790 | * when a cluster is allocated from a block group, we put the | 789 | * when a cluster is allocated from a block group, we put the |
| @@ -1283,6 +1282,7 @@ struct btrfs_root { | |||
| 1283 | #define BTRFS_INODE_NODUMP (1 << 8) | 1282 | #define BTRFS_INODE_NODUMP (1 << 8) |
| 1284 | #define BTRFS_INODE_NOATIME (1 << 9) | 1283 | #define BTRFS_INODE_NOATIME (1 << 9) |
| 1285 | #define BTRFS_INODE_DIRSYNC (1 << 10) | 1284 | #define BTRFS_INODE_DIRSYNC (1 << 10) |
| 1285 | #define BTRFS_INODE_COMPRESS (1 << 11) | ||
| 1286 | 1286 | ||
| 1287 | /* some macros to generate set/get funcs for the struct fields. This | 1287 | /* some macros to generate set/get funcs for the struct fields. This |
| 1288 | * assumes there is a lefoo_to_cpu for every type, so lets make a simple | 1288 | * assumes there is a lefoo_to_cpu for every type, so lets make a simple |
| @@ -2157,6 +2157,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, | |||
| 2157 | u64 root_objectid, u64 owner, u64 offset); | 2157 | u64 root_objectid, u64 owner, u64 offset); |
| 2158 | 2158 | ||
| 2159 | int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); | 2159 | int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len); |
| 2160 | int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache, | ||
| 2161 | u64 num_bytes, int reserve, int sinfo); | ||
| 2160 | int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, | 2162 | int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, |
| 2161 | struct btrfs_root *root); | 2163 | struct btrfs_root *root); |
| 2162 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | 2164 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, |
| @@ -2227,10 +2229,12 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); | |||
| 2227 | int btrfs_error_unpin_extent_range(struct btrfs_root *root, | 2229 | int btrfs_error_unpin_extent_range(struct btrfs_root *root, |
| 2228 | u64 start, u64 end); | 2230 | u64 start, u64 end); |
| 2229 | int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, | 2231 | int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, |
| 2230 | u64 num_bytes); | 2232 | u64 num_bytes, u64 *actual_bytes); |
| 2231 | int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, | 2233 | int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, |
| 2232 | struct btrfs_root *root, u64 type); | 2234 | struct btrfs_root *root, u64 type); |
| 2235 | int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range); | ||
| 2233 | 2236 | ||
| 2237 | int btrfs_init_space_info(struct btrfs_fs_info *fs_info); | ||
| 2234 | /* ctree.c */ | 2238 | /* ctree.c */ |
| 2235 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | 2239 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, |
| 2236 | int level, int *slot); | 2240 | int level, int *slot); |
| @@ -2392,6 +2396,9 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, | |||
| 2392 | struct btrfs_path *path, u64 dir, | 2396 | struct btrfs_path *path, u64 dir, |
| 2393 | const char *name, u16 name_len, | 2397 | const char *name, u16 name_len, |
| 2394 | int mod); | 2398 | int mod); |
| 2399 | int verify_dir_item(struct btrfs_root *root, | ||
| 2400 | struct extent_buffer *leaf, | ||
| 2401 | struct btrfs_dir_item *dir_item); | ||
| 2395 | 2402 | ||
| 2396 | /* orphan.c */ | 2403 | /* orphan.c */ |
| 2397 | int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, | 2404 | int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, |
| @@ -2528,7 +2535,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, | |||
| 2528 | struct inode *inode); | 2535 | struct inode *inode); |
| 2529 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); | 2536 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); |
| 2530 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); | 2537 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); |
| 2531 | void btrfs_orphan_cleanup(struct btrfs_root *root); | 2538 | int btrfs_orphan_cleanup(struct btrfs_root *root); |
| 2532 | void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans, | 2539 | void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans, |
| 2533 | struct btrfs_pending_snapshot *pending, | 2540 | struct btrfs_pending_snapshot *pending, |
| 2534 | u64 *bytes_to_reserve); | 2541 | u64 *bytes_to_reserve); |
| @@ -2536,7 +2543,7 @@ void btrfs_orphan_post_snapshot(struct btrfs_trans_handle *trans, | |||
| 2536 | struct btrfs_pending_snapshot *pending); | 2543 | struct btrfs_pending_snapshot *pending); |
| 2537 | void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, | 2544 | void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, |
| 2538 | struct btrfs_root *root); | 2545 | struct btrfs_root *root); |
| 2539 | int btrfs_cont_expand(struct inode *inode, loff_t size); | 2546 | int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size); |
| 2540 | int btrfs_invalidate_inodes(struct btrfs_root *root); | 2547 | int btrfs_invalidate_inodes(struct btrfs_root *root); |
| 2541 | void btrfs_add_delayed_iput(struct inode *inode); | 2548 | void btrfs_add_delayed_iput(struct inode *inode); |
| 2542 | void btrfs_run_delayed_iputs(struct btrfs_root *root); | 2549 | void btrfs_run_delayed_iputs(struct btrfs_root *root); |
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index e807b143b857..bce28f653899 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c | |||
| @@ -483,6 +483,8 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans, | |||
| 483 | INIT_LIST_HEAD(&head_ref->cluster); | 483 | INIT_LIST_HEAD(&head_ref->cluster); |
| 484 | mutex_init(&head_ref->mutex); | 484 | mutex_init(&head_ref->mutex); |
| 485 | 485 | ||
| 486 | trace_btrfs_delayed_ref_head(ref, head_ref, action); | ||
| 487 | |||
| 486 | existing = tree_insert(&delayed_refs->root, &ref->rb_node); | 488 | existing = tree_insert(&delayed_refs->root, &ref->rb_node); |
| 487 | 489 | ||
| 488 | if (existing) { | 490 | if (existing) { |
| @@ -537,6 +539,8 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans, | |||
| 537 | } | 539 | } |
| 538 | full_ref->level = level; | 540 | full_ref->level = level; |
| 539 | 541 | ||
| 542 | trace_btrfs_delayed_tree_ref(ref, full_ref, action); | ||
| 543 | |||
| 540 | existing = tree_insert(&delayed_refs->root, &ref->rb_node); | 544 | existing = tree_insert(&delayed_refs->root, &ref->rb_node); |
| 541 | 545 | ||
| 542 | if (existing) { | 546 | if (existing) { |
| @@ -591,6 +595,8 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans, | |||
| 591 | full_ref->objectid = owner; | 595 | full_ref->objectid = owner; |
| 592 | full_ref->offset = offset; | 596 | full_ref->offset = offset; |
| 593 | 597 | ||
| 598 | trace_btrfs_delayed_data_ref(ref, full_ref, action); | ||
| 599 | |||
| 594 | existing = tree_insert(&delayed_refs->root, &ref->rb_node); | 600 | existing = tree_insert(&delayed_refs->root, &ref->rb_node); |
| 595 | 601 | ||
| 596 | if (existing) { | 602 | if (existing) { |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index f0cad5ae5be7..c62f02f6ae69 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
| @@ -151,7 +151,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 151 | ret = PTR_ERR(dir_item); | 151 | ret = PTR_ERR(dir_item); |
| 152 | if (ret == -EEXIST) | 152 | if (ret == -EEXIST) |
| 153 | goto second_insert; | 153 | goto second_insert; |
| 154 | goto out; | 154 | goto out_free; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | leaf = path->nodes[0]; | 157 | leaf = path->nodes[0]; |
| @@ -170,7 +170,7 @@ second_insert: | |||
| 170 | /* FIXME, use some real flag for selecting the extra index */ | 170 | /* FIXME, use some real flag for selecting the extra index */ |
| 171 | if (root == root->fs_info->tree_root) { | 171 | if (root == root->fs_info->tree_root) { |
| 172 | ret = 0; | 172 | ret = 0; |
| 173 | goto out; | 173 | goto out_free; |
| 174 | } | 174 | } |
| 175 | btrfs_release_path(root, path); | 175 | btrfs_release_path(root, path); |
| 176 | 176 | ||
| @@ -180,7 +180,7 @@ second_insert: | |||
| 180 | name, name_len); | 180 | name, name_len); |
| 181 | if (IS_ERR(dir_item)) { | 181 | if (IS_ERR(dir_item)) { |
| 182 | ret2 = PTR_ERR(dir_item); | 182 | ret2 = PTR_ERR(dir_item); |
| 183 | goto out; | 183 | goto out_free; |
| 184 | } | 184 | } |
| 185 | leaf = path->nodes[0]; | 185 | leaf = path->nodes[0]; |
| 186 | btrfs_cpu_key_to_disk(&disk_key, location); | 186 | btrfs_cpu_key_to_disk(&disk_key, location); |
| @@ -192,7 +192,9 @@ second_insert: | |||
| 192 | name_ptr = (unsigned long)(dir_item + 1); | 192 | name_ptr = (unsigned long)(dir_item + 1); |
| 193 | write_extent_buffer(leaf, name, name_ptr, name_len); | 193 | write_extent_buffer(leaf, name, name_ptr, name_len); |
| 194 | btrfs_mark_buffer_dirty(leaf); | 194 | btrfs_mark_buffer_dirty(leaf); |
| 195 | out: | 195 | |
| 196 | out_free: | ||
| 197 | |||
| 196 | btrfs_free_path(path); | 198 | btrfs_free_path(path); |
| 197 | if (ret) | 199 | if (ret) |
| 198 | return ret; | 200 | return ret; |
| @@ -377,6 +379,9 @@ struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, | |||
| 377 | 379 | ||
| 378 | leaf = path->nodes[0]; | 380 | leaf = path->nodes[0]; |
| 379 | dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); | 381 | dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); |
| 382 | if (verify_dir_item(root, leaf, dir_item)) | ||
| 383 | return NULL; | ||
| 384 | |||
| 380 | total_len = btrfs_item_size_nr(leaf, path->slots[0]); | 385 | total_len = btrfs_item_size_nr(leaf, path->slots[0]); |
| 381 | while (cur < total_len) { | 386 | while (cur < total_len) { |
| 382 | this_len = sizeof(*dir_item) + | 387 | this_len = sizeof(*dir_item) + |
| @@ -429,3 +434,35 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, | |||
| 429 | } | 434 | } |
| 430 | return ret; | 435 | return ret; |
| 431 | } | 436 | } |
| 437 | |||
| 438 | int verify_dir_item(struct btrfs_root *root, | ||
| 439 | struct extent_buffer *leaf, | ||
| 440 | struct btrfs_dir_item *dir_item) | ||
| 441 | { | ||
| 442 | u16 namelen = BTRFS_NAME_LEN; | ||
| 443 | u8 type = btrfs_dir_type(leaf, dir_item); | ||
| 444 | |||
| 445 | if (type >= BTRFS_FT_MAX) { | ||
| 446 | printk(KERN_CRIT "btrfs: invalid dir item type: %d\n", | ||
| 447 | (int)type); | ||
| 448 | return 1; | ||
| 449 | } | ||
| 450 | |||
| 451 | if (type == BTRFS_FT_XATTR) | ||
| 452 | namelen = XATTR_NAME_MAX; | ||
| 453 | |||
| 454 | if (btrfs_dir_name_len(leaf, dir_item) > namelen) { | ||
| 455 | printk(KERN_CRIT "btrfS: invalid dir item name len: %u\n", | ||
| 456 | (unsigned)btrfs_dir_data_len(leaf, dir_item)); | ||
| 457 | return 1; | ||
| 458 | } | ||
| 459 | |||
| 460 | /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */ | ||
| 461 | if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) { | ||
| 462 | printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n", | ||
| 463 | (unsigned)btrfs_dir_data_len(leaf, dir_item)); | ||
| 464 | return 1; | ||
| 465 | } | ||
| 466 | |||
| 467 | return 0; | ||
| 468 | } | ||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 830d261d0e6b..d7a7315bd031 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/crc32c.h> | 29 | #include <linux/crc32c.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/migrate.h> | 31 | #include <linux/migrate.h> |
| 32 | #include <asm/unaligned.h> | ||
| 32 | #include "compat.h" | 33 | #include "compat.h" |
| 33 | #include "ctree.h" | 34 | #include "ctree.h" |
| 34 | #include "disk-io.h" | 35 | #include "disk-io.h" |
| @@ -198,7 +199,7 @@ u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) | |||
| 198 | 199 | ||
| 199 | void btrfs_csum_final(u32 crc, char *result) | 200 | void btrfs_csum_final(u32 crc, char *result) |
| 200 | { | 201 | { |
| 201 | *(__le32 *)result = ~cpu_to_le32(crc); | 202 | put_unaligned_le32(~crc, result); |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 204 | /* | 205 | /* |
| @@ -323,6 +324,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
| 323 | int num_copies = 0; | 324 | int num_copies = 0; |
| 324 | int mirror_num = 0; | 325 | int mirror_num = 0; |
| 325 | 326 | ||
| 327 | clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); | ||
| 326 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; | 328 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; |
| 327 | while (1) { | 329 | while (1) { |
| 328 | ret = read_extent_buffer_pages(io_tree, eb, start, 1, | 330 | ret = read_extent_buffer_pages(io_tree, eb, start, 1, |
| @@ -331,6 +333,14 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
| 331 | !verify_parent_transid(io_tree, eb, parent_transid)) | 333 | !verify_parent_transid(io_tree, eb, parent_transid)) |
| 332 | return ret; | 334 | return ret; |
| 333 | 335 | ||
| 336 | /* | ||
| 337 | * This buffer's crc is fine, but its contents are corrupted, so | ||
| 338 | * there is no reason to read the other copies, they won't be | ||
| 339 | * any less wrong. | ||
| 340 | */ | ||
| 341 | if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) | ||
| 342 | return ret; | ||
| 343 | |||
| 334 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, | 344 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, |
| 335 | eb->start, eb->len); | 345 | eb->start, eb->len); |
| 336 | if (num_copies == 1) | 346 | if (num_copies == 1) |
| @@ -419,6 +429,73 @@ static int check_tree_block_fsid(struct btrfs_root *root, | |||
| 419 | return ret; | 429 | return ret; |
| 420 | } | 430 | } |
| 421 | 431 | ||
| 432 | #define CORRUPT(reason, eb, root, slot) \ | ||
| 433 | printk(KERN_CRIT "btrfs: corrupt leaf, %s: block=%llu," \ | ||
| 434 | "root=%llu, slot=%d\n", reason, \ | ||
| 435 | (unsigned long long)btrfs_header_bytenr(eb), \ | ||
| 436 | (unsigned long long)root->objectid, slot) | ||
| 437 | |||
| 438 | static noinline int check_leaf(struct btrfs_root *root, | ||
| 439 | struct extent_buffer *leaf) | ||
| 440 | { | ||
| 441 | struct btrfs_key key; | ||
| 442 | struct btrfs_key leaf_key; | ||
| 443 | u32 nritems = btrfs_header_nritems(leaf); | ||
| 444 | int slot; | ||
| 445 | |||
| 446 | if (nritems == 0) | ||
| 447 | return 0; | ||
| 448 | |||
| 449 | /* Check the 0 item */ | ||
| 450 | if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != | ||
| 451 | BTRFS_LEAF_DATA_SIZE(root)) { | ||
| 452 | CORRUPT("invalid item offset size pair", leaf, root, 0); | ||
| 453 | return -EIO; | ||
| 454 | } | ||
| 455 | |||
| 456 | /* | ||
| 457 | * Check to make sure each items keys are in the correct order and their | ||
| 458 | * offsets make sense. We only have to loop through nritems-1 because | ||
| 459 | * we check the current slot against the next slot, which verifies the | ||
| 460 | * next slot's offset+size makes sense and that the current's slot | ||
| 461 | * offset is correct. | ||
| 462 | */ | ||
| 463 | for (slot = 0; slot < nritems - 1; slot++) { | ||
| 464 | btrfs_item_key_to_cpu(leaf, &leaf_key, slot); | ||
| 465 | btrfs_item_key_to_cpu(leaf, &key, slot + 1); | ||
| 466 | |||
| 467 | /* Make sure the keys are in the right order */ | ||
| 468 | if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) { | ||
| 469 | CORRUPT("bad key order", leaf, root, slot); | ||
| 470 | return -EIO; | ||
| 471 | } | ||
| 472 | |||
| 473 | /* | ||
| 474 | * Make sure the offset and ends are right, remember that the | ||
| 475 | * item data starts at the end of the leaf and grows towards the | ||
| 476 | * front. | ||
| 477 | */ | ||
| 478 | if (btrfs_item_offset_nr(leaf, slot) != | ||
| 479 | btrfs_item_end_nr(leaf, slot + 1)) { | ||
| 480 | CORRUPT("slot offset bad", leaf, root, slot); | ||
| 481 | return -EIO; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* | ||
| 485 | * Check to make sure that we don't point outside of the leaf, | ||
| 486 | * just incase all the items are consistent to eachother, but | ||
| 487 | * all point outside of the leaf. | ||
| 488 | */ | ||
| 489 | if (btrfs_item_end_nr(leaf, slot) > | ||
| 490 | BTRFS_LEAF_DATA_SIZE(root)) { | ||
| 491 | CORRUPT("slot end outside of leaf", leaf, root, slot); | ||
| 492 | return -EIO; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | return 0; | ||
| 497 | } | ||
| 498 | |||
| 422 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 499 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
| 423 | void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level) | 500 | void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level) |
| 424 | { | 501 | { |
| @@ -485,8 +562,20 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
| 485 | btrfs_set_buffer_lockdep_class(eb, found_level); | 562 | btrfs_set_buffer_lockdep_class(eb, found_level); |
| 486 | 563 | ||
| 487 | ret = csum_tree_block(root, eb, 1); | 564 | ret = csum_tree_block(root, eb, 1); |
| 488 | if (ret) | 565 | if (ret) { |
| 489 | ret = -EIO; | 566 | ret = -EIO; |
| 567 | goto err; | ||
| 568 | } | ||
| 569 | |||
| 570 | /* | ||
| 571 | * If this is a leaf block and it is corrupt, set the corrupt bit so | ||
| 572 | * that we don't try and read the other copies of this block, just | ||
| 573 | * return -EIO. | ||
| 574 | */ | ||
| 575 | if (found_level == 0 && check_leaf(root, eb)) { | ||
| 576 | set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); | ||
| 577 | ret = -EIO; | ||
| 578 | } | ||
| 490 | 579 | ||
| 491 | end = min_t(u64, eb->len, PAGE_CACHE_SIZE); | 580 | end = min_t(u64, eb->len, PAGE_CACHE_SIZE); |
| 492 | end = eb->start + end - 1; | 581 | end = eb->start + end - 1; |
| @@ -1159,7 +1248,10 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, | |||
| 1159 | root, fs_info, location->objectid); | 1248 | root, fs_info, location->objectid); |
| 1160 | 1249 | ||
| 1161 | path = btrfs_alloc_path(); | 1250 | path = btrfs_alloc_path(); |
| 1162 | BUG_ON(!path); | 1251 | if (!path) { |
| 1252 | kfree(root); | ||
| 1253 | return ERR_PTR(-ENOMEM); | ||
| 1254 | } | ||
| 1163 | ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); | 1255 | ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); |
| 1164 | if (ret == 0) { | 1256 | if (ret == 0) { |
| 1165 | l = path->nodes[0]; | 1257 | l = path->nodes[0]; |
| @@ -1553,6 +1645,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1553 | goto fail_bdi; | 1645 | goto fail_bdi; |
| 1554 | } | 1646 | } |
| 1555 | 1647 | ||
| 1648 | fs_info->btree_inode->i_mapping->flags &= ~__GFP_FS; | ||
| 1649 | |||
| 1556 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); | 1650 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); |
| 1557 | INIT_LIST_HEAD(&fs_info->trans_list); | 1651 | INIT_LIST_HEAD(&fs_info->trans_list); |
| 1558 | INIT_LIST_HEAD(&fs_info->dead_roots); | 1652 | INIT_LIST_HEAD(&fs_info->dead_roots); |
| @@ -1683,6 +1777,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1683 | 1777 | ||
| 1684 | btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); | 1778 | btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); |
| 1685 | 1779 | ||
| 1780 | /* | ||
| 1781 | * In the long term, we'll store the compression type in the super | ||
| 1782 | * block, and it'll be used for per file compression control. | ||
| 1783 | */ | ||
| 1784 | fs_info->compress_type = BTRFS_COMPRESS_ZLIB; | ||
| 1785 | |||
| 1686 | ret = btrfs_parse_options(tree_root, options); | 1786 | ret = btrfs_parse_options(tree_root, options); |
| 1687 | if (ret) { | 1787 | if (ret) { |
| 1688 | err = ret; | 1788 | err = ret; |
| @@ -1888,6 +1988,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1888 | fs_info->metadata_alloc_profile = (u64)-1; | 1988 | fs_info->metadata_alloc_profile = (u64)-1; |
| 1889 | fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; | 1989 | fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; |
| 1890 | 1990 | ||
| 1991 | ret = btrfs_init_space_info(fs_info); | ||
| 1992 | if (ret) { | ||
| 1993 | printk(KERN_ERR "Failed to initial space info: %d\n", ret); | ||
| 1994 | goto fail_block_groups; | ||
| 1995 | } | ||
| 1996 | |||
| 1891 | ret = btrfs_read_block_groups(extent_root); | 1997 | ret = btrfs_read_block_groups(extent_root); |
| 1892 | if (ret) { | 1998 | if (ret) { |
| 1893 | printk(KERN_ERR "Failed to read block groups: %d\n", ret); | 1999 | printk(KERN_ERR "Failed to read block groups: %d\n", ret); |
| @@ -1979,9 +2085,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1979 | 2085 | ||
| 1980 | if (!(sb->s_flags & MS_RDONLY)) { | 2086 | if (!(sb->s_flags & MS_RDONLY)) { |
| 1981 | down_read(&fs_info->cleanup_work_sem); | 2087 | down_read(&fs_info->cleanup_work_sem); |
| 1982 | btrfs_orphan_cleanup(fs_info->fs_root); | 2088 | err = btrfs_orphan_cleanup(fs_info->fs_root); |
| 1983 | btrfs_orphan_cleanup(fs_info->tree_root); | 2089 | if (!err) |
| 2090 | err = btrfs_orphan_cleanup(fs_info->tree_root); | ||
| 1984 | up_read(&fs_info->cleanup_work_sem); | 2091 | up_read(&fs_info->cleanup_work_sem); |
| 2092 | if (err) { | ||
| 2093 | close_ctree(tree_root); | ||
| 2094 | return ERR_PTR(err); | ||
| 2095 | } | ||
| 1985 | } | 2096 | } |
| 1986 | 2097 | ||
| 1987 | return tree_root; | 2098 | return tree_root; |
| @@ -2356,8 +2467,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) | |||
| 2356 | 2467 | ||
| 2357 | root_objectid = gang[ret - 1]->root_key.objectid + 1; | 2468 | root_objectid = gang[ret - 1]->root_key.objectid + 1; |
| 2358 | for (i = 0; i < ret; i++) { | 2469 | for (i = 0; i < ret; i++) { |
| 2470 | int err; | ||
| 2471 | |||
| 2359 | root_objectid = gang[i]->root_key.objectid; | 2472 | root_objectid = gang[i]->root_key.objectid; |
| 2360 | btrfs_orphan_cleanup(gang[i]); | 2473 | err = btrfs_orphan_cleanup(gang[i]); |
| 2474 | if (err) | ||
| 2475 | return err; | ||
| 2361 | } | 2476 | } |
| 2362 | root_objectid++; | 2477 | root_objectid++; |
| 2363 | } | 2478 | } |
| @@ -2868,7 +2983,10 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root, | |||
| 2868 | break; | 2983 | break; |
| 2869 | 2984 | ||
| 2870 | /* opt_discard */ | 2985 | /* opt_discard */ |
| 2871 | ret = btrfs_error_discard_extent(root, start, end + 1 - start); | 2986 | if (btrfs_test_opt(root, DISCARD)) |
| 2987 | ret = btrfs_error_discard_extent(root, start, | ||
| 2988 | end + 1 - start, | ||
| 2989 | NULL); | ||
| 2872 | 2990 | ||
| 2873 | clear_extent_dirty(unpin, start, end, GFP_NOFS); | 2991 | clear_extent_dirty(unpin, start, end, GFP_NOFS); |
| 2874 | btrfs_error_unpin_extent_range(root, start, end); | 2992 | btrfs_error_unpin_extent_range(root, start, end); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7b3089b5c2df..f619c3cb13b7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -36,8 +36,6 @@ | |||
| 36 | static int update_block_group(struct btrfs_trans_handle *trans, | 36 | static int update_block_group(struct btrfs_trans_handle *trans, |
| 37 | struct btrfs_root *root, | 37 | struct btrfs_root *root, |
| 38 | u64 bytenr, u64 num_bytes, int alloc); | 38 | u64 bytenr, u64 num_bytes, int alloc); |
| 39 | static int update_reserved_bytes(struct btrfs_block_group_cache *cache, | ||
| 40 | u64 num_bytes, int reserve, int sinfo); | ||
| 41 | static int __btrfs_free_extent(struct btrfs_trans_handle *trans, | 39 | static int __btrfs_free_extent(struct btrfs_trans_handle *trans, |
| 42 | struct btrfs_root *root, | 40 | struct btrfs_root *root, |
| 43 | u64 bytenr, u64 num_bytes, u64 parent, | 41 | u64 bytenr, u64 num_bytes, u64 parent, |
| @@ -442,7 +440,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, | |||
| 442 | * allocate blocks for the tree root we can't do the fast caching since | 440 | * allocate blocks for the tree root we can't do the fast caching since |
| 443 | * we likely hold important locks. | 441 | * we likely hold important locks. |
| 444 | */ | 442 | */ |
| 445 | if (!trans->transaction->in_commit && | 443 | if (trans && (!trans->transaction->in_commit) && |
| 446 | (root && root != root->fs_info->tree_root)) { | 444 | (root && root != root->fs_info->tree_root)) { |
| 447 | spin_lock(&cache->lock); | 445 | spin_lock(&cache->lock); |
| 448 | if (cache->cached != BTRFS_CACHE_NO) { | 446 | if (cache->cached != BTRFS_CACHE_NO) { |
| @@ -471,7 +469,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, | |||
| 471 | if (load_cache_only) | 469 | if (load_cache_only) |
| 472 | return 0; | 470 | return 0; |
| 473 | 471 | ||
| 474 | caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL); | 472 | caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS); |
| 475 | BUG_ON(!caching_ctl); | 473 | BUG_ON(!caching_ctl); |
| 476 | 474 | ||
| 477 | INIT_LIST_HEAD(&caching_ctl->list); | 475 | INIT_LIST_HEAD(&caching_ctl->list); |
| @@ -1740,39 +1738,45 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans, | |||
| 1740 | return ret; | 1738 | return ret; |
| 1741 | } | 1739 | } |
| 1742 | 1740 | ||
| 1743 | static void btrfs_issue_discard(struct block_device *bdev, | 1741 | static int btrfs_issue_discard(struct block_device *bdev, |
| 1744 | u64 start, u64 len) | 1742 | u64 start, u64 len) |
| 1745 | { | 1743 | { |
| 1746 | blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL, 0); | 1744 | return blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0); |
| 1747 | } | 1745 | } |
| 1748 | 1746 | ||
| 1749 | static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, | 1747 | static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, |
| 1750 | u64 num_bytes) | 1748 | u64 num_bytes, u64 *actual_bytes) |
| 1751 | { | 1749 | { |
| 1752 | int ret; | 1750 | int ret; |
| 1753 | u64 map_length = num_bytes; | 1751 | u64 discarded_bytes = 0; |
| 1754 | struct btrfs_multi_bio *multi = NULL; | 1752 | struct btrfs_multi_bio *multi = NULL; |
| 1755 | 1753 | ||
| 1756 | if (!btrfs_test_opt(root, DISCARD)) | ||
| 1757 | return 0; | ||
| 1758 | 1754 | ||
| 1759 | /* Tell the block device(s) that the sectors can be discarded */ | 1755 | /* Tell the block device(s) that the sectors can be discarded */ |
| 1760 | ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, | 1756 | ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD, |
| 1761 | bytenr, &map_length, &multi, 0); | 1757 | bytenr, &num_bytes, &multi, 0); |
| 1762 | if (!ret) { | 1758 | if (!ret) { |
| 1763 | struct btrfs_bio_stripe *stripe = multi->stripes; | 1759 | struct btrfs_bio_stripe *stripe = multi->stripes; |
| 1764 | int i; | 1760 | int i; |
| 1765 | 1761 | ||
| 1766 | if (map_length > num_bytes) | ||
| 1767 | map_length = num_bytes; | ||
| 1768 | 1762 | ||
| 1769 | for (i = 0; i < multi->num_stripes; i++, stripe++) { | 1763 | for (i = 0; i < multi->num_stripes; i++, stripe++) { |
| 1770 | btrfs_issue_discard(stripe->dev->bdev, | 1764 | ret = btrfs_issue_discard(stripe->dev->bdev, |
| 1771 | stripe->physical, | 1765 | stripe->physical, |
| 1772 | map_length); | 1766 | stripe->length); |
| 1767 | if (!ret) | ||
| 1768 | discarded_bytes += stripe->length; | ||
| 1769 | else if (ret != -EOPNOTSUPP) | ||
| 1770 | break; | ||
| 1773 | } | 1771 | } |
| 1774 | kfree(multi); | 1772 | kfree(multi); |
| 1775 | } | 1773 | } |
| 1774 | if (discarded_bytes && ret == -EOPNOTSUPP) | ||
| 1775 | ret = 0; | ||
| 1776 | |||
| 1777 | if (actual_bytes) | ||
| 1778 | *actual_bytes = discarded_bytes; | ||
| 1779 | |||
| 1776 | 1780 | ||
| 1777 | return ret; | 1781 | return ret; |
| 1778 | } | 1782 | } |
| @@ -3996,6 +4000,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) | |||
| 3996 | struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv; | 4000 | struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv; |
| 3997 | u64 to_reserve; | 4001 | u64 to_reserve; |
| 3998 | int nr_extents; | 4002 | int nr_extents; |
| 4003 | int reserved_extents; | ||
| 3999 | int ret; | 4004 | int ret; |
| 4000 | 4005 | ||
| 4001 | if (btrfs_transaction_in_commit(root->fs_info)) | 4006 | if (btrfs_transaction_in_commit(root->fs_info)) |
| @@ -4003,25 +4008,24 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) | |||
| 4003 | 4008 | ||
| 4004 | num_bytes = ALIGN(num_bytes, root->sectorsize); | 4009 | num_bytes = ALIGN(num_bytes, root->sectorsize); |
| 4005 | 4010 | ||
| 4006 | spin_lock(&BTRFS_I(inode)->accounting_lock); | ||
| 4007 | nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1; | 4011 | nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1; |
| 4008 | if (nr_extents > BTRFS_I(inode)->reserved_extents) { | 4012 | reserved_extents = atomic_read(&BTRFS_I(inode)->reserved_extents); |
| 4009 | nr_extents -= BTRFS_I(inode)->reserved_extents; | 4013 | |
| 4014 | if (nr_extents > reserved_extents) { | ||
| 4015 | nr_extents -= reserved_extents; | ||
| 4010 | to_reserve = calc_trans_metadata_size(root, nr_extents); | 4016 | to_reserve = calc_trans_metadata_size(root, nr_extents); |
| 4011 | } else { | 4017 | } else { |
| 4012 | nr_extents = 0; | 4018 | nr_extents = 0; |
| 4013 | to_reserve = 0; | 4019 | to_reserve = 0; |
| 4014 | } | 4020 | } |
| 4015 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | 4021 | |
| 4016 | to_reserve += calc_csum_metadata_size(inode, num_bytes); | 4022 | to_reserve += calc_csum_metadata_size(inode, num_bytes); |
| 4017 | ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1); | 4023 | ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1); |
| 4018 | if (ret) | 4024 | if (ret) |
| 4019 | return ret; | 4025 | return ret; |
| 4020 | 4026 | ||
| 4021 | spin_lock(&BTRFS_I(inode)->accounting_lock); | 4027 | atomic_add(nr_extents, &BTRFS_I(inode)->reserved_extents); |
| 4022 | BTRFS_I(inode)->reserved_extents += nr_extents; | ||
| 4023 | atomic_inc(&BTRFS_I(inode)->outstanding_extents); | 4028 | atomic_inc(&BTRFS_I(inode)->outstanding_extents); |
| 4024 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | ||
| 4025 | 4029 | ||
| 4026 | block_rsv_add_bytes(block_rsv, to_reserve, 1); | 4030 | block_rsv_add_bytes(block_rsv, to_reserve, 1); |
| 4027 | 4031 | ||
| @@ -4036,20 +4040,30 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes) | |||
| 4036 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4040 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 4037 | u64 to_free; | 4041 | u64 to_free; |
| 4038 | int nr_extents; | 4042 | int nr_extents; |
| 4043 | int reserved_extents; | ||
| 4039 | 4044 | ||
| 4040 | num_bytes = ALIGN(num_bytes, root->sectorsize); | 4045 | num_bytes = ALIGN(num_bytes, root->sectorsize); |
| 4041 | atomic_dec(&BTRFS_I(inode)->outstanding_extents); | 4046 | atomic_dec(&BTRFS_I(inode)->outstanding_extents); |
| 4042 | WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0); | 4047 | WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0); |
| 4043 | 4048 | ||
| 4044 | spin_lock(&BTRFS_I(inode)->accounting_lock); | 4049 | reserved_extents = atomic_read(&BTRFS_I(inode)->reserved_extents); |
| 4045 | nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents); | 4050 | do { |
| 4046 | if (nr_extents < BTRFS_I(inode)->reserved_extents) { | 4051 | int old, new; |
| 4047 | nr_extents = BTRFS_I(inode)->reserved_extents - nr_extents; | 4052 | |
| 4048 | BTRFS_I(inode)->reserved_extents -= nr_extents; | 4053 | nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents); |
| 4049 | } else { | 4054 | if (nr_extents >= reserved_extents) { |
| 4050 | nr_extents = 0; | 4055 | nr_extents = 0; |
| 4051 | } | 4056 | break; |
| 4052 | spin_unlock(&BTRFS_I(inode)->accounting_lock); | 4057 | } |
| 4058 | old = reserved_extents; | ||
| 4059 | nr_extents = reserved_extents - nr_extents; | ||
| 4060 | new = reserved_extents - nr_extents; | ||
| 4061 | old = atomic_cmpxchg(&BTRFS_I(inode)->reserved_extents, | ||
| 4062 | reserved_extents, new); | ||
| 4063 | if (likely(old == reserved_extents)) | ||
| 4064 | break; | ||
| 4065 | reserved_extents = old; | ||
| 4066 | } while (1); | ||
| 4053 | 4067 | ||
| 4054 | to_free = calc_csum_metadata_size(inode, num_bytes); | 4068 | to_free = calc_csum_metadata_size(inode, num_bytes); |
| 4055 | if (nr_extents > 0) | 4069 | if (nr_extents > 0) |
| @@ -4223,8 +4237,8 @@ int btrfs_pin_extent(struct btrfs_root *root, | |||
| 4223 | * update size of reserved extents. this function may return -EAGAIN | 4237 | * update size of reserved extents. this function may return -EAGAIN |
| 4224 | * if 'reserve' is true or 'sinfo' is false. | 4238 | * if 'reserve' is true or 'sinfo' is false. |
| 4225 | */ | 4239 | */ |
| 4226 | static int update_reserved_bytes(struct btrfs_block_group_cache *cache, | 4240 | int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache, |
| 4227 | u64 num_bytes, int reserve, int sinfo) | 4241 | u64 num_bytes, int reserve, int sinfo) |
| 4228 | { | 4242 | { |
| 4229 | int ret = 0; | 4243 | int ret = 0; |
| 4230 | if (sinfo) { | 4244 | if (sinfo) { |
| @@ -4363,7 +4377,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | |||
| 4363 | if (ret) | 4377 | if (ret) |
| 4364 | break; | 4378 | break; |
| 4365 | 4379 | ||
| 4366 | ret = btrfs_discard_extent(root, start, end + 1 - start); | 4380 | if (btrfs_test_opt(root, DISCARD)) |
| 4381 | ret = btrfs_discard_extent(root, start, | ||
| 4382 | end + 1 - start, NULL); | ||
| 4367 | 4383 | ||
| 4368 | clear_extent_dirty(unpin, start, end, GFP_NOFS); | 4384 | clear_extent_dirty(unpin, start, end, GFP_NOFS); |
| 4369 | unpin_extent_range(root, start, end); | 4385 | unpin_extent_range(root, start, end); |
| @@ -4704,10 +4720,10 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, | |||
| 4704 | WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)); | 4720 | WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)); |
| 4705 | 4721 | ||
| 4706 | btrfs_add_free_space(cache, buf->start, buf->len); | 4722 | btrfs_add_free_space(cache, buf->start, buf->len); |
| 4707 | ret = update_reserved_bytes(cache, buf->len, 0, 0); | 4723 | ret = btrfs_update_reserved_bytes(cache, buf->len, 0, 0); |
| 4708 | if (ret == -EAGAIN) { | 4724 | if (ret == -EAGAIN) { |
| 4709 | /* block group became read-only */ | 4725 | /* block group became read-only */ |
| 4710 | update_reserved_bytes(cache, buf->len, 0, 1); | 4726 | btrfs_update_reserved_bytes(cache, buf->len, 0, 1); |
| 4711 | goto out; | 4727 | goto out; |
| 4712 | } | 4728 | } |
| 4713 | 4729 | ||
| @@ -4744,6 +4760,11 @@ pin: | |||
| 4744 | } | 4760 | } |
| 4745 | } | 4761 | } |
| 4746 | out: | 4762 | out: |
| 4763 | /* | ||
| 4764 | * Deleting the buffer, clear the corrupt flag since it doesn't matter | ||
| 4765 | * anymore. | ||
| 4766 | */ | ||
| 4767 | clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags); | ||
| 4747 | btrfs_put_block_group(cache); | 4768 | btrfs_put_block_group(cache); |
| 4748 | } | 4769 | } |
| 4749 | 4770 | ||
| @@ -5191,7 +5212,7 @@ checks: | |||
| 5191 | search_start - offset); | 5212 | search_start - offset); |
| 5192 | BUG_ON(offset > search_start); | 5213 | BUG_ON(offset > search_start); |
| 5193 | 5214 | ||
| 5194 | ret = update_reserved_bytes(block_group, num_bytes, 1, | 5215 | ret = btrfs_update_reserved_bytes(block_group, num_bytes, 1, |
| 5195 | (data & BTRFS_BLOCK_GROUP_DATA)); | 5216 | (data & BTRFS_BLOCK_GROUP_DATA)); |
| 5196 | if (ret == -EAGAIN) { | 5217 | if (ret == -EAGAIN) { |
| 5197 | btrfs_add_free_space(block_group, offset, num_bytes); | 5218 | btrfs_add_free_space(block_group, offset, num_bytes); |
| @@ -5397,6 +5418,8 @@ again: | |||
| 5397 | dump_space_info(sinfo, num_bytes, 1); | 5418 | dump_space_info(sinfo, num_bytes, 1); |
| 5398 | } | 5419 | } |
| 5399 | 5420 | ||
| 5421 | trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset); | ||
| 5422 | |||
| 5400 | return ret; | 5423 | return ret; |
| 5401 | } | 5424 | } |
| 5402 | 5425 | ||
| @@ -5412,12 +5435,15 @@ int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) | |||
| 5412 | return -ENOSPC; | 5435 | return -ENOSPC; |
| 5413 | } | 5436 | } |
| 5414 | 5437 | ||
| 5415 | ret = btrfs_discard_extent(root, start, len); | 5438 | if (btrfs_test_opt(root, DISCARD)) |
| 5439 | ret = btrfs_discard_extent(root, start, len, NULL); | ||
| 5416 | 5440 | ||
| 5417 | btrfs_add_free_space(cache, start, len); | 5441 | btrfs_add_free_space(cache, start, len); |
| 5418 | update_reserved_bytes(cache, len, 0, 1); | 5442 | btrfs_update_reserved_bytes(cache, len, 0, 1); |
| 5419 | btrfs_put_block_group(cache); | 5443 | btrfs_put_block_group(cache); |
| 5420 | 5444 | ||
| 5445 | trace_btrfs_reserved_extent_free(root, start, len); | ||
| 5446 | |||
| 5421 | return ret; | 5447 | return ret; |
| 5422 | } | 5448 | } |
| 5423 | 5449 | ||
| @@ -5444,7 +5470,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
| 5444 | size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type); | 5470 | size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type); |
| 5445 | 5471 | ||
| 5446 | path = btrfs_alloc_path(); | 5472 | path = btrfs_alloc_path(); |
| 5447 | BUG_ON(!path); | 5473 | if (!path) |
| 5474 | return -ENOMEM; | ||
| 5448 | 5475 | ||
| 5449 | path->leave_spinning = 1; | 5476 | path->leave_spinning = 1; |
| 5450 | ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, | 5477 | ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, |
| @@ -5614,7 +5641,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
| 5614 | put_caching_control(caching_ctl); | 5641 | put_caching_control(caching_ctl); |
| 5615 | } | 5642 | } |
| 5616 | 5643 | ||
| 5617 | ret = update_reserved_bytes(block_group, ins->offset, 1, 1); | 5644 | ret = btrfs_update_reserved_bytes(block_group, ins->offset, 1, 1); |
| 5618 | BUG_ON(ret); | 5645 | BUG_ON(ret); |
| 5619 | btrfs_put_block_group(block_group); | 5646 | btrfs_put_block_group(block_group); |
| 5620 | ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, | 5647 | ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, |
| @@ -6047,6 +6074,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, | |||
| 6047 | if (reada && level == 1) | 6074 | if (reada && level == 1) |
| 6048 | reada_walk_down(trans, root, wc, path); | 6075 | reada_walk_down(trans, root, wc, path); |
| 6049 | next = read_tree_block(root, bytenr, blocksize, generation); | 6076 | next = read_tree_block(root, bytenr, blocksize, generation); |
| 6077 | if (!next) | ||
| 6078 | return -EIO; | ||
| 6050 | btrfs_tree_lock(next); | 6079 | btrfs_tree_lock(next); |
| 6051 | btrfs_set_lock_blocking(next); | 6080 | btrfs_set_lock_blocking(next); |
| 6052 | } | 6081 | } |
| @@ -6438,10 +6467,14 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | |||
| 6438 | BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); | 6467 | BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); |
| 6439 | 6468 | ||
| 6440 | path = btrfs_alloc_path(); | 6469 | path = btrfs_alloc_path(); |
| 6441 | BUG_ON(!path); | 6470 | if (!path) |
| 6471 | return -ENOMEM; | ||
| 6442 | 6472 | ||
| 6443 | wc = kzalloc(sizeof(*wc), GFP_NOFS); | 6473 | wc = kzalloc(sizeof(*wc), GFP_NOFS); |
| 6444 | BUG_ON(!wc); | 6474 | if (!wc) { |
| 6475 | btrfs_free_path(path); | ||
| 6476 | return -ENOMEM; | ||
| 6477 | } | ||
| 6445 | 6478 | ||
| 6446 | btrfs_assert_tree_locked(parent); | 6479 | btrfs_assert_tree_locked(parent); |
| 6447 | parent_level = btrfs_header_level(parent); | 6480 | parent_level = btrfs_header_level(parent); |
| @@ -6899,7 +6932,11 @@ static noinline int get_new_locations(struct inode *reloc_inode, | |||
| 6899 | } | 6932 | } |
| 6900 | 6933 | ||
| 6901 | path = btrfs_alloc_path(); | 6934 | path = btrfs_alloc_path(); |
| 6902 | BUG_ON(!path); | 6935 | if (!path) { |
| 6936 | if (exts != *extents) | ||
| 6937 | kfree(exts); | ||
| 6938 | return -ENOMEM; | ||
| 6939 | } | ||
| 6903 | 6940 | ||
| 6904 | cur_pos = extent_key->objectid - offset; | 6941 | cur_pos = extent_key->objectid - offset; |
| 6905 | last_byte = extent_key->objectid + extent_key->offset; | 6942 | last_byte = extent_key->objectid + extent_key->offset; |
| @@ -6941,6 +6978,10 @@ static noinline int get_new_locations(struct inode *reloc_inode, | |||
| 6941 | struct disk_extent *old = exts; | 6978 | struct disk_extent *old = exts; |
| 6942 | max *= 2; | 6979 | max *= 2; |
| 6943 | exts = kzalloc(sizeof(*exts) * max, GFP_NOFS); | 6980 | exts = kzalloc(sizeof(*exts) * max, GFP_NOFS); |
| 6981 | if (!exts) { | ||
| 6982 | ret = -ENOMEM; | ||
| 6983 | goto out; | ||
| 6984 | } | ||
| 6944 | memcpy(exts, old, sizeof(*exts) * nr); | 6985 | memcpy(exts, old, sizeof(*exts) * nr); |
| 6945 | if (old != *extents) | 6986 | if (old != *extents) |
| 6946 | kfree(old); | 6987 | kfree(old); |
| @@ -7423,7 +7464,8 @@ static noinline int replace_extents_in_leaf(struct btrfs_trans_handle *trans, | |||
| 7423 | int ret; | 7464 | int ret; |
| 7424 | 7465 | ||
| 7425 | new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS); | 7466 | new_extent = kmalloc(sizeof(*new_extent), GFP_NOFS); |
| 7426 | BUG_ON(!new_extent); | 7467 | if (!new_extent) |
| 7468 | return -ENOMEM; | ||
| 7427 | 7469 | ||
| 7428 | ref = btrfs_lookup_leaf_ref(root, leaf->start); | 7470 | ref = btrfs_lookup_leaf_ref(root, leaf->start); |
| 7429 | BUG_ON(!ref); | 7471 | BUG_ON(!ref); |
| @@ -7609,7 +7651,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root) | |||
| 7609 | 7651 | ||
| 7610 | reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location); | 7652 | reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location); |
| 7611 | BUG_ON(!reloc_root); | 7653 | BUG_ON(!reloc_root); |
| 7612 | btrfs_orphan_cleanup(reloc_root); | 7654 | ret = btrfs_orphan_cleanup(reloc_root); |
| 7655 | BUG_ON(ret); | ||
| 7613 | return 0; | 7656 | return 0; |
| 7614 | } | 7657 | } |
| 7615 | 7658 | ||
| @@ -7627,7 +7670,8 @@ static noinline int init_reloc_tree(struct btrfs_trans_handle *trans, | |||
| 7627 | return 0; | 7670 | return 0; |
| 7628 | 7671 | ||
| 7629 | root_item = kmalloc(sizeof(*root_item), GFP_NOFS); | 7672 | root_item = kmalloc(sizeof(*root_item), GFP_NOFS); |
| 7630 | BUG_ON(!root_item); | 7673 | if (!root_item) |
| 7674 | return -ENOMEM; | ||
| 7631 | 7675 | ||
| 7632 | ret = btrfs_copy_root(trans, root, root->commit_root, | 7676 | ret = btrfs_copy_root(trans, root, root->commit_root, |
| 7633 | &eb, BTRFS_TREE_RELOC_OBJECTID); | 7677 | &eb, BTRFS_TREE_RELOC_OBJECTID); |
| @@ -7653,7 +7697,7 @@ static noinline int init_reloc_tree(struct btrfs_trans_handle *trans, | |||
| 7653 | 7697 | ||
| 7654 | reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root, | 7698 | reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root, |
| 7655 | &root_key); | 7699 | &root_key); |
| 7656 | BUG_ON(!reloc_root); | 7700 | BUG_ON(IS_ERR(reloc_root)); |
| 7657 | reloc_root->last_trans = trans->transid; | 7701 | reloc_root->last_trans = trans->transid; |
| 7658 | reloc_root->commit_root = NULL; | 7702 | reloc_root->commit_root = NULL; |
| 7659 | reloc_root->ref_tree = &root->fs_info->reloc_ref_tree; | 7703 | reloc_root->ref_tree = &root->fs_info->reloc_ref_tree; |
| @@ -7906,6 +7950,10 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root, | |||
| 7906 | 7950 | ||
| 7907 | eb = read_tree_block(found_root, block_start, | 7951 | eb = read_tree_block(found_root, block_start, |
| 7908 | block_size, 0); | 7952 | block_size, 0); |
| 7953 | if (!eb) { | ||
| 7954 | ret = -EIO; | ||
| 7955 | goto out; | ||
| 7956 | } | ||
| 7909 | btrfs_tree_lock(eb); | 7957 | btrfs_tree_lock(eb); |
| 7910 | BUG_ON(level != btrfs_header_level(eb)); | 7958 | BUG_ON(level != btrfs_header_level(eb)); |
| 7911 | 7959 | ||
| @@ -8621,6 +8669,12 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
| 8621 | BUG_ON(!block_group); | 8669 | BUG_ON(!block_group); |
| 8622 | BUG_ON(!block_group->ro); | 8670 | BUG_ON(!block_group->ro); |
| 8623 | 8671 | ||
| 8672 | /* | ||
| 8673 | * Free the reserved super bytes from this block group before | ||
| 8674 | * remove it. | ||
| 8675 | */ | ||
| 8676 | free_excluded_extents(root, block_group); | ||
| 8677 | |||
| 8624 | memcpy(&key, &block_group->key, sizeof(key)); | 8678 | memcpy(&key, &block_group->key, sizeof(key)); |
| 8625 | if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | | 8679 | if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | |
| 8626 | BTRFS_BLOCK_GROUP_RAID1 | | 8680 | BTRFS_BLOCK_GROUP_RAID1 | |
| @@ -8724,13 +8778,84 @@ out: | |||
| 8724 | return ret; | 8778 | return ret; |
| 8725 | } | 8779 | } |
| 8726 | 8780 | ||
| 8781 | int btrfs_init_space_info(struct btrfs_fs_info *fs_info) | ||
| 8782 | { | ||
| 8783 | struct btrfs_space_info *space_info; | ||
| 8784 | int ret; | ||
| 8785 | |||
| 8786 | ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM, 0, 0, | ||
| 8787 | &space_info); | ||
| 8788 | if (ret) | ||
| 8789 | return ret; | ||
| 8790 | |||
| 8791 | ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA, 0, 0, | ||
| 8792 | &space_info); | ||
| 8793 | if (ret) | ||
| 8794 | return ret; | ||
| 8795 | |||
| 8796 | ret = update_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA, 0, 0, | ||
| 8797 | &space_info); | ||
| 8798 | if (ret) | ||
| 8799 | return ret; | ||
| 8800 | |||
| 8801 | return ret; | ||
| 8802 | } | ||
| 8803 | |||
| 8727 | int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) | 8804 | int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) |
| 8728 | { | 8805 | { |
| 8729 | return unpin_extent_range(root, start, end); | 8806 | return unpin_extent_range(root, start, end); |
| 8730 | } | 8807 | } |
| 8731 | 8808 | ||
| 8732 | int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, | 8809 | int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, |
| 8733 | u64 num_bytes) | 8810 | u64 num_bytes, u64 *actual_bytes) |
| 8811 | { | ||
| 8812 | return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes); | ||
| 8813 | } | ||
| 8814 | |||
| 8815 | int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) | ||
| 8734 | { | 8816 | { |
| 8735 | return btrfs_discard_extent(root, bytenr, num_bytes); | 8817 | struct btrfs_fs_info *fs_info = root->fs_info; |
| 8818 | struct btrfs_block_group_cache *cache = NULL; | ||
| 8819 | u64 group_trimmed; | ||
| 8820 | u64 start; | ||
| 8821 | u64 end; | ||
| 8822 | u64 trimmed = 0; | ||
| 8823 | int ret = 0; | ||
| 8824 | |||
| 8825 | cache = btrfs_lookup_block_group(fs_info, range->start); | ||
| 8826 | |||
| 8827 | while (cache) { | ||
| 8828 | if (cache->key.objectid >= (range->start + range->len)) { | ||
| 8829 | btrfs_put_block_group(cache); | ||
| 8830 | break; | ||
| 8831 | } | ||
| 8832 | |||
| 8833 | start = max(range->start, cache->key.objectid); | ||
| 8834 | end = min(range->start + range->len, | ||
| 8835 | cache->key.objectid + cache->key.offset); | ||
| 8836 | |||
| 8837 | if (end - start >= range->minlen) { | ||
| 8838 | if (!block_group_cache_done(cache)) { | ||
| 8839 | ret = cache_block_group(cache, NULL, root, 0); | ||
| 8840 | if (!ret) | ||
| 8841 | wait_block_group_cache_done(cache); | ||
| 8842 | } | ||
| 8843 | ret = btrfs_trim_block_group(cache, | ||
| 8844 | &group_trimmed, | ||
| 8845 | start, | ||
| 8846 | end, | ||
| 8847 | range->minlen); | ||
| 8848 | |||
| 8849 | trimmed += group_trimmed; | ||
| 8850 | if (ret) { | ||
| 8851 | btrfs_put_block_group(cache); | ||
| 8852 | break; | ||
| 8853 | } | ||
| 8854 | } | ||
| 8855 | |||
| 8856 | cache = next_block_group(fs_info->tree_root, cache); | ||
| 8857 | } | ||
| 8858 | |||
| 8859 | range->len = trimmed; | ||
| 8860 | return ret; | ||
| 8736 | } | 8861 | } |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index b5b92824a271..20ddb28602a8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -2192,6 +2192,8 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
| 2192 | else | 2192 | else |
| 2193 | write_flags = WRITE; | 2193 | write_flags = WRITE; |
| 2194 | 2194 | ||
| 2195 | trace___extent_writepage(page, inode, wbc); | ||
| 2196 | |||
| 2195 | WARN_ON(!PageLocked(page)); | 2197 | WARN_ON(!PageLocked(page)); |
| 2196 | pg_offset = i_size & (PAGE_CACHE_SIZE - 1); | 2198 | pg_offset = i_size & (PAGE_CACHE_SIZE - 1); |
| 2197 | if (page->index > end_index || | 2199 | if (page->index > end_index || |
| @@ -3690,6 +3692,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
| 3690 | "wanted %lu %lu\n", (unsigned long long)eb->start, | 3692 | "wanted %lu %lu\n", (unsigned long long)eb->start, |
| 3691 | eb->len, start, min_len); | 3693 | eb->len, start, min_len); |
| 3692 | WARN_ON(1); | 3694 | WARN_ON(1); |
| 3695 | return -EINVAL; | ||
| 3693 | } | 3696 | } |
| 3694 | 3697 | ||
| 3695 | p = extent_buffer_page(eb, i); | 3698 | p = extent_buffer_page(eb, i); |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 9318dfefd59c..f62c5442835d 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #define EXTENT_BUFFER_UPTODATE 0 | 31 | #define EXTENT_BUFFER_UPTODATE 0 |
| 32 | #define EXTENT_BUFFER_BLOCKING 1 | 32 | #define EXTENT_BUFFER_BLOCKING 1 |
| 33 | #define EXTENT_BUFFER_DIRTY 2 | 33 | #define EXTENT_BUFFER_DIRTY 2 |
| 34 | #define EXTENT_BUFFER_CORRUPT 3 | ||
| 34 | 35 | ||
| 35 | /* these are flags for extent_clear_unlock_delalloc */ | 36 | /* these are flags for extent_clear_unlock_delalloc */ |
| 36 | #define EXTENT_CLEAR_UNLOCK_PAGE 0x1 | 37 | #define EXTENT_CLEAR_UNLOCK_PAGE 0x1 |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 4f19a3e1bf32..a6a9d4e8b491 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
| @@ -48,7 +48,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, | |||
| 48 | struct extent_buffer *leaf; | 48 | struct extent_buffer *leaf; |
| 49 | 49 | ||
| 50 | path = btrfs_alloc_path(); | 50 | path = btrfs_alloc_path(); |
| 51 | BUG_ON(!path); | 51 | if (!path) |
| 52 | return -ENOMEM; | ||
| 52 | file_key.objectid = objectid; | 53 | file_key.objectid = objectid; |
| 53 | file_key.offset = pos; | 54 | file_key.offset = pos; |
| 54 | btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); | 55 | btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); |
| @@ -169,6 +170,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, | |||
| 169 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 170 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
| 170 | 171 | ||
| 171 | path = btrfs_alloc_path(); | 172 | path = btrfs_alloc_path(); |
| 173 | if (!path) | ||
| 174 | return -ENOMEM; | ||
| 172 | if (bio->bi_size > PAGE_CACHE_SIZE * 8) | 175 | if (bio->bi_size > PAGE_CACHE_SIZE * 8) |
| 173 | path->reada = 2; | 176 | path->reada = 2; |
| 174 | 177 | ||
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index f447b783bb84..656bc0a892b1 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
| @@ -45,14 +45,14 @@ | |||
| 45 | * and be replaced with calls into generic code. | 45 | * and be replaced with calls into generic code. |
| 46 | */ | 46 | */ |
| 47 | static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, | 47 | static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, |
| 48 | int write_bytes, | 48 | size_t write_bytes, |
| 49 | struct page **prepared_pages, | 49 | struct page **prepared_pages, |
| 50 | struct iov_iter *i) | 50 | struct iov_iter *i) |
| 51 | { | 51 | { |
| 52 | size_t copied = 0; | 52 | size_t copied = 0; |
| 53 | size_t total_copied = 0; | ||
| 53 | int pg = 0; | 54 | int pg = 0; |
| 54 | int offset = pos & (PAGE_CACHE_SIZE - 1); | 55 | int offset = pos & (PAGE_CACHE_SIZE - 1); |
| 55 | int total_copied = 0; | ||
| 56 | 56 | ||
| 57 | while (write_bytes > 0) { | 57 | while (write_bytes > 0) { |
| 58 | size_t count = min_t(size_t, | 58 | size_t count = min_t(size_t, |
| @@ -88,9 +88,8 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, | |||
| 88 | total_copied += copied; | 88 | total_copied += copied; |
| 89 | 89 | ||
| 90 | /* Return to btrfs_file_aio_write to fault page */ | 90 | /* Return to btrfs_file_aio_write to fault page */ |
| 91 | if (unlikely(copied == 0)) { | 91 | if (unlikely(copied == 0)) |
| 92 | break; | 92 | break; |
| 93 | } | ||
| 94 | 93 | ||
| 95 | if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { | 94 | if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { |
| 96 | offset += copied; | 95 | offset += copied; |
| @@ -109,8 +108,6 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) | |||
| 109 | { | 108 | { |
| 110 | size_t i; | 109 | size_t i; |
| 111 | for (i = 0; i < num_pages; i++) { | 110 | for (i = 0; i < num_pages; i++) { |
| 112 | if (!pages[i]) | ||
| 113 | break; | ||
| 114 | /* page checked is some magic around finding pages that | 111 | /* page checked is some magic around finding pages that |
| 115 | * have been modified without going through btrfs_set_page_dirty | 112 | * have been modified without going through btrfs_set_page_dirty |
| 116 | * clear it here | 113 | * clear it here |
| @@ -130,13 +127,12 @@ static noinline void btrfs_drop_pages(struct page **pages, size_t num_pages) | |||
| 130 | * this also makes the decision about creating an inline extent vs | 127 | * this also makes the decision about creating an inline extent vs |
| 131 | * doing real data extents, marking pages dirty and delalloc as required. | 128 | * doing real data extents, marking pages dirty and delalloc as required. |
| 132 | */ | 129 | */ |
| 133 | static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, | 130 | static noinline int dirty_and_release_pages(struct btrfs_root *root, |
| 134 | struct btrfs_root *root, | 131 | struct file *file, |
| 135 | struct file *file, | 132 | struct page **pages, |
| 136 | struct page **pages, | 133 | size_t num_pages, |
| 137 | size_t num_pages, | 134 | loff_t pos, |
| 138 | loff_t pos, | 135 | size_t write_bytes) |
| 139 | size_t write_bytes) | ||
| 140 | { | 136 | { |
| 141 | int err = 0; | 137 | int err = 0; |
| 142 | int i; | 138 | int i; |
| @@ -154,7 +150,8 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
| 154 | end_of_last_block = start_pos + num_bytes - 1; | 150 | end_of_last_block = start_pos + num_bytes - 1; |
| 155 | err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, | 151 | err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, |
| 156 | NULL); | 152 | NULL); |
| 157 | BUG_ON(err); | 153 | if (err) |
| 154 | return err; | ||
| 158 | 155 | ||
| 159 | for (i = 0; i < num_pages; i++) { | 156 | for (i = 0; i < num_pages; i++) { |
| 160 | struct page *p = pages[i]; | 157 | struct page *p = pages[i]; |
| @@ -162,13 +159,14 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
| 162 | ClearPageChecked(p); | 159 | ClearPageChecked(p); |
| 163 | set_page_dirty(p); | 160 | set_page_dirty(p); |
| 164 | } | 161 | } |
| 165 | if (end_pos > isize) { | 162 | |
| 163 | /* | ||
| 164 | * we've only changed i_size in ram, and we haven't updated | ||
| 165 | * the disk i_size. There is no need to log the inode | ||
| 166 | * at this time. | ||
| 167 | */ | ||
| 168 | if (end_pos > isize) | ||
| 166 | i_size_write(inode, end_pos); | 169 | i_size_write(inode, end_pos); |
| 167 | /* we've only changed i_size in ram, and we haven't updated | ||
| 168 | * the disk i_size. There is no need to log the inode | ||
| 169 | * at this time. | ||
| 170 | */ | ||
| 171 | } | ||
| 172 | return 0; | 170 | return 0; |
| 173 | } | 171 | } |
| 174 | 172 | ||
| @@ -610,6 +608,8 @@ again: | |||
| 610 | key.offset = split; | 608 | key.offset = split; |
| 611 | 609 | ||
| 612 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 610 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
| 611 | if (ret < 0) | ||
| 612 | goto out; | ||
| 613 | if (ret > 0 && path->slots[0] > 0) | 613 | if (ret > 0 && path->slots[0] > 0) |
| 614 | path->slots[0]--; | 614 | path->slots[0]--; |
| 615 | 615 | ||
| @@ -819,12 +819,11 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, | |||
| 819 | last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT; | 819 | last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT; |
| 820 | 820 | ||
| 821 | if (start_pos > inode->i_size) { | 821 | if (start_pos > inode->i_size) { |
| 822 | err = btrfs_cont_expand(inode, start_pos); | 822 | err = btrfs_cont_expand(inode, i_size_read(inode), start_pos); |
| 823 | if (err) | 823 | if (err) |
| 824 | return err; | 824 | return err; |
| 825 | } | 825 | } |
| 826 | 826 | ||
| 827 | memset(pages, 0, num_pages * sizeof(struct page *)); | ||
| 828 | again: | 827 | again: |
| 829 | for (i = 0; i < num_pages; i++) { | 828 | for (i = 0; i < num_pages; i++) { |
| 830 | pages[i] = grab_cache_page(inode->i_mapping, index + i); | 829 | pages[i] = grab_cache_page(inode->i_mapping, index + i); |
| @@ -896,156 +895,71 @@ fail: | |||
| 896 | 895 | ||
| 897 | } | 896 | } |
| 898 | 897 | ||
| 899 | static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | 898 | static noinline ssize_t __btrfs_buffered_write(struct file *file, |
| 900 | const struct iovec *iov, | 899 | struct iov_iter *i, |
| 901 | unsigned long nr_segs, loff_t pos) | 900 | loff_t pos) |
| 902 | { | 901 | { |
| 903 | struct file *file = iocb->ki_filp; | ||
| 904 | struct inode *inode = fdentry(file)->d_inode; | 902 | struct inode *inode = fdentry(file)->d_inode; |
| 905 | struct btrfs_root *root = BTRFS_I(inode)->root; | 903 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 906 | struct page **pages = NULL; | 904 | struct page **pages = NULL; |
| 907 | struct iov_iter i; | ||
| 908 | loff_t *ppos = &iocb->ki_pos; | ||
| 909 | loff_t start_pos; | ||
| 910 | ssize_t num_written = 0; | ||
| 911 | ssize_t err = 0; | ||
| 912 | size_t count; | ||
| 913 | size_t ocount; | ||
| 914 | int ret = 0; | ||
| 915 | int nrptrs; | ||
| 916 | unsigned long first_index; | 905 | unsigned long first_index; |
| 917 | unsigned long last_index; | 906 | unsigned long last_index; |
| 918 | int will_write; | 907 | size_t num_written = 0; |
| 919 | int buffered = 0; | 908 | int nrptrs; |
| 920 | int copied = 0; | 909 | int ret; |
| 921 | int dirty_pages = 0; | ||
| 922 | |||
| 923 | will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) || | ||
| 924 | (file->f_flags & O_DIRECT)); | ||
| 925 | |||
| 926 | start_pos = pos; | ||
| 927 | |||
| 928 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | ||
| 929 | |||
| 930 | mutex_lock(&inode->i_mutex); | ||
| 931 | |||
| 932 | err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); | ||
| 933 | if (err) | ||
| 934 | goto out; | ||
| 935 | count = ocount; | ||
| 936 | |||
| 937 | current->backing_dev_info = inode->i_mapping->backing_dev_info; | ||
| 938 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); | ||
| 939 | if (err) | ||
| 940 | goto out; | ||
| 941 | |||
| 942 | if (count == 0) | ||
| 943 | goto out; | ||
| 944 | |||
| 945 | err = file_remove_suid(file); | ||
| 946 | if (err) | ||
| 947 | goto out; | ||
| 948 | |||
| 949 | /* | ||
| 950 | * If BTRFS flips readonly due to some impossible error | ||
| 951 | * (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR), | ||
| 952 | * although we have opened a file as writable, we have | ||
| 953 | * to stop this write operation to ensure FS consistency. | ||
| 954 | */ | ||
| 955 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
| 956 | err = -EROFS; | ||
| 957 | goto out; | ||
| 958 | } | ||
| 959 | |||
| 960 | file_update_time(file); | ||
| 961 | BTRFS_I(inode)->sequence++; | ||
| 962 | |||
| 963 | if (unlikely(file->f_flags & O_DIRECT)) { | ||
| 964 | num_written = generic_file_direct_write(iocb, iov, &nr_segs, | ||
| 965 | pos, ppos, count, | ||
| 966 | ocount); | ||
| 967 | /* | ||
| 968 | * the generic O_DIRECT will update in-memory i_size after the | ||
| 969 | * DIOs are done. But our endio handlers that update the on | ||
| 970 | * disk i_size never update past the in memory i_size. So we | ||
| 971 | * need one more update here to catch any additions to the | ||
| 972 | * file | ||
| 973 | */ | ||
| 974 | if (inode->i_size != BTRFS_I(inode)->disk_i_size) { | ||
| 975 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); | ||
| 976 | mark_inode_dirty(inode); | ||
| 977 | } | ||
| 978 | |||
| 979 | if (num_written < 0) { | ||
| 980 | ret = num_written; | ||
| 981 | num_written = 0; | ||
| 982 | goto out; | ||
| 983 | } else if (num_written == count) { | ||
| 984 | /* pick up pos changes done by the generic code */ | ||
| 985 | pos = *ppos; | ||
| 986 | goto out; | ||
| 987 | } | ||
| 988 | /* | ||
| 989 | * We are going to do buffered for the rest of the range, so we | ||
| 990 | * need to make sure to invalidate the buffered pages when we're | ||
| 991 | * done. | ||
| 992 | */ | ||
| 993 | buffered = 1; | ||
| 994 | pos += num_written; | ||
| 995 | } | ||
| 996 | 910 | ||
| 997 | iov_iter_init(&i, iov, nr_segs, count, num_written); | 911 | nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) / |
| 998 | nrptrs = min((iov_iter_count(&i) + PAGE_CACHE_SIZE - 1) / | ||
| 999 | PAGE_CACHE_SIZE, PAGE_CACHE_SIZE / | 912 | PAGE_CACHE_SIZE, PAGE_CACHE_SIZE / |
| 1000 | (sizeof(struct page *))); | 913 | (sizeof(struct page *))); |
| 1001 | pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL); | 914 | pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL); |
| 1002 | if (!pages) { | 915 | if (!pages) |
| 1003 | ret = -ENOMEM; | 916 | return -ENOMEM; |
| 1004 | goto out; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /* generic_write_checks can change our pos */ | ||
| 1008 | start_pos = pos; | ||
| 1009 | 917 | ||
| 1010 | first_index = pos >> PAGE_CACHE_SHIFT; | 918 | first_index = pos >> PAGE_CACHE_SHIFT; |
| 1011 | last_index = (pos + iov_iter_count(&i)) >> PAGE_CACHE_SHIFT; | 919 | last_index = (pos + iov_iter_count(i)) >> PAGE_CACHE_SHIFT; |
| 1012 | 920 | ||
| 1013 | while (iov_iter_count(&i) > 0) { | 921 | while (iov_iter_count(i) > 0) { |
| 1014 | size_t offset = pos & (PAGE_CACHE_SIZE - 1); | 922 | size_t offset = pos & (PAGE_CACHE_SIZE - 1); |
| 1015 | size_t write_bytes = min(iov_iter_count(&i), | 923 | size_t write_bytes = min(iov_iter_count(i), |
| 1016 | nrptrs * (size_t)PAGE_CACHE_SIZE - | 924 | nrptrs * (size_t)PAGE_CACHE_SIZE - |
| 1017 | offset); | 925 | offset); |
| 1018 | size_t num_pages = (write_bytes + offset + | 926 | size_t num_pages = (write_bytes + offset + |
| 1019 | PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 927 | PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 928 | size_t dirty_pages; | ||
| 929 | size_t copied; | ||
| 1020 | 930 | ||
| 1021 | WARN_ON(num_pages > nrptrs); | 931 | WARN_ON(num_pages > nrptrs); |
| 1022 | memset(pages, 0, sizeof(struct page *) * nrptrs); | ||
| 1023 | 932 | ||
| 1024 | /* | 933 | /* |
| 1025 | * Fault pages before locking them in prepare_pages | 934 | * Fault pages before locking them in prepare_pages |
| 1026 | * to avoid recursive lock | 935 | * to avoid recursive lock |
| 1027 | */ | 936 | */ |
| 1028 | if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) { | 937 | if (unlikely(iov_iter_fault_in_readable(i, write_bytes))) { |
| 1029 | ret = -EFAULT; | 938 | ret = -EFAULT; |
| 1030 | goto out; | 939 | break; |
| 1031 | } | 940 | } |
| 1032 | 941 | ||
| 1033 | ret = btrfs_delalloc_reserve_space(inode, | 942 | ret = btrfs_delalloc_reserve_space(inode, |
| 1034 | num_pages << PAGE_CACHE_SHIFT); | 943 | num_pages << PAGE_CACHE_SHIFT); |
| 1035 | if (ret) | 944 | if (ret) |
| 1036 | goto out; | 945 | break; |
| 1037 | 946 | ||
| 947 | /* | ||
| 948 | * This is going to setup the pages array with the number of | ||
| 949 | * pages we want, so we don't really need to worry about the | ||
| 950 | * contents of pages from loop to loop | ||
| 951 | */ | ||
| 1038 | ret = prepare_pages(root, file, pages, num_pages, | 952 | ret = prepare_pages(root, file, pages, num_pages, |
| 1039 | pos, first_index, last_index, | 953 | pos, first_index, last_index, |
| 1040 | write_bytes); | 954 | write_bytes); |
| 1041 | if (ret) { | 955 | if (ret) { |
| 1042 | btrfs_delalloc_release_space(inode, | 956 | btrfs_delalloc_release_space(inode, |
| 1043 | num_pages << PAGE_CACHE_SHIFT); | 957 | num_pages << PAGE_CACHE_SHIFT); |
| 1044 | goto out; | 958 | break; |
| 1045 | } | 959 | } |
| 1046 | 960 | ||
| 1047 | copied = btrfs_copy_from_user(pos, num_pages, | 961 | copied = btrfs_copy_from_user(pos, num_pages, |
| 1048 | write_bytes, pages, &i); | 962 | write_bytes, pages, i); |
| 1049 | 963 | ||
| 1050 | /* | 964 | /* |
| 1051 | * if we have trouble faulting in the pages, fall | 965 | * if we have trouble faulting in the pages, fall |
| @@ -1061,6 +975,13 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
| 1061 | PAGE_CACHE_SIZE - 1) >> | 975 | PAGE_CACHE_SIZE - 1) >> |
| 1062 | PAGE_CACHE_SHIFT; | 976 | PAGE_CACHE_SHIFT; |
| 1063 | 977 | ||
| 978 | /* | ||
| 979 | * If we had a short copy we need to release the excess delaloc | ||
| 980 | * bytes we reserved. We need to increment outstanding_extents | ||
| 981 | * because btrfs_delalloc_release_space will decrement it, but | ||
| 982 | * we still have an outstanding extent for the chunk we actually | ||
| 983 | * managed to copy. | ||
| 984 | */ | ||
| 1064 | if (num_pages > dirty_pages) { | 985 | if (num_pages > dirty_pages) { |
| 1065 | if (copied > 0) | 986 | if (copied > 0) |
| 1066 | atomic_inc( | 987 | atomic_inc( |
| @@ -1071,39 +992,157 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
| 1071 | } | 992 | } |
| 1072 | 993 | ||
| 1073 | if (copied > 0) { | 994 | if (copied > 0) { |
| 1074 | dirty_and_release_pages(NULL, root, file, pages, | 995 | ret = dirty_and_release_pages(root, file, pages, |
| 1075 | dirty_pages, pos, copied); | 996 | dirty_pages, pos, |
| 997 | copied); | ||
| 998 | if (ret) { | ||
| 999 | btrfs_delalloc_release_space(inode, | ||
| 1000 | dirty_pages << PAGE_CACHE_SHIFT); | ||
| 1001 | btrfs_drop_pages(pages, num_pages); | ||
| 1002 | break; | ||
| 1003 | } | ||
| 1076 | } | 1004 | } |
| 1077 | 1005 | ||
| 1078 | btrfs_drop_pages(pages, num_pages); | 1006 | btrfs_drop_pages(pages, num_pages); |
| 1079 | 1007 | ||
| 1080 | if (copied > 0) { | 1008 | cond_resched(); |
| 1081 | if (will_write) { | 1009 | |
| 1082 | filemap_fdatawrite_range(inode->i_mapping, pos, | 1010 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, |
| 1083 | pos + copied - 1); | 1011 | dirty_pages); |
| 1084 | } else { | 1012 | if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) |
| 1085 | balance_dirty_pages_ratelimited_nr( | 1013 | btrfs_btree_balance_dirty(root, 1); |
| 1086 | inode->i_mapping, | 1014 | btrfs_throttle(root); |
| 1087 | dirty_pages); | ||
| 1088 | if (dirty_pages < | ||
| 1089 | (root->leafsize >> PAGE_CACHE_SHIFT) + 1) | ||
| 1090 | btrfs_btree_balance_dirty(root, 1); | ||
| 1091 | btrfs_throttle(root); | ||
| 1092 | } | ||
| 1093 | } | ||
| 1094 | 1015 | ||
| 1095 | pos += copied; | 1016 | pos += copied; |
| 1096 | num_written += copied; | 1017 | num_written += copied; |
| 1018 | } | ||
| 1097 | 1019 | ||
| 1098 | cond_resched(); | 1020 | kfree(pages); |
| 1021 | |||
| 1022 | return num_written ? num_written : ret; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static ssize_t __btrfs_direct_write(struct kiocb *iocb, | ||
| 1026 | const struct iovec *iov, | ||
| 1027 | unsigned long nr_segs, loff_t pos, | ||
| 1028 | loff_t *ppos, size_t count, size_t ocount) | ||
| 1029 | { | ||
| 1030 | struct file *file = iocb->ki_filp; | ||
| 1031 | struct inode *inode = fdentry(file)->d_inode; | ||
| 1032 | struct iov_iter i; | ||
| 1033 | ssize_t written; | ||
| 1034 | ssize_t written_buffered; | ||
| 1035 | loff_t endbyte; | ||
| 1036 | int err; | ||
| 1037 | |||
| 1038 | written = generic_file_direct_write(iocb, iov, &nr_segs, pos, ppos, | ||
| 1039 | count, ocount); | ||
| 1040 | |||
| 1041 | /* | ||
| 1042 | * the generic O_DIRECT will update in-memory i_size after the | ||
| 1043 | * DIOs are done. But our endio handlers that update the on | ||
| 1044 | * disk i_size never update past the in memory i_size. So we | ||
| 1045 | * need one more update here to catch any additions to the | ||
| 1046 | * file | ||
| 1047 | */ | ||
| 1048 | if (inode->i_size != BTRFS_I(inode)->disk_i_size) { | ||
| 1049 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); | ||
| 1050 | mark_inode_dirty(inode); | ||
| 1099 | } | 1051 | } |
| 1052 | |||
| 1053 | if (written < 0 || written == count) | ||
| 1054 | return written; | ||
| 1055 | |||
| 1056 | pos += written; | ||
| 1057 | count -= written; | ||
| 1058 | iov_iter_init(&i, iov, nr_segs, count, written); | ||
| 1059 | written_buffered = __btrfs_buffered_write(file, &i, pos); | ||
| 1060 | if (written_buffered < 0) { | ||
| 1061 | err = written_buffered; | ||
| 1062 | goto out; | ||
| 1063 | } | ||
| 1064 | endbyte = pos + written_buffered - 1; | ||
| 1065 | err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte); | ||
| 1066 | if (err) | ||
| 1067 | goto out; | ||
| 1068 | written += written_buffered; | ||
| 1069 | *ppos = pos + written_buffered; | ||
| 1070 | invalidate_mapping_pages(file->f_mapping, pos >> PAGE_CACHE_SHIFT, | ||
| 1071 | endbyte >> PAGE_CACHE_SHIFT); | ||
| 1100 | out: | 1072 | out: |
| 1101 | mutex_unlock(&inode->i_mutex); | 1073 | return written ? written : err; |
| 1102 | if (ret) | 1074 | } |
| 1103 | err = ret; | ||
| 1104 | 1075 | ||
| 1105 | kfree(pages); | 1076 | static ssize_t btrfs_file_aio_write(struct kiocb *iocb, |
| 1106 | *ppos = pos; | 1077 | const struct iovec *iov, |
| 1078 | unsigned long nr_segs, loff_t pos) | ||
| 1079 | { | ||
| 1080 | struct file *file = iocb->ki_filp; | ||
| 1081 | struct inode *inode = fdentry(file)->d_inode; | ||
| 1082 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
| 1083 | loff_t *ppos = &iocb->ki_pos; | ||
| 1084 | ssize_t num_written = 0; | ||
| 1085 | ssize_t err = 0; | ||
| 1086 | size_t count, ocount; | ||
| 1087 | |||
| 1088 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | ||
| 1089 | |||
| 1090 | mutex_lock(&inode->i_mutex); | ||
| 1091 | |||
| 1092 | err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); | ||
| 1093 | if (err) { | ||
| 1094 | mutex_unlock(&inode->i_mutex); | ||
| 1095 | goto out; | ||
| 1096 | } | ||
| 1097 | count = ocount; | ||
| 1098 | |||
| 1099 | current->backing_dev_info = inode->i_mapping->backing_dev_info; | ||
| 1100 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); | ||
| 1101 | if (err) { | ||
| 1102 | mutex_unlock(&inode->i_mutex); | ||
| 1103 | goto out; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | if (count == 0) { | ||
| 1107 | mutex_unlock(&inode->i_mutex); | ||
| 1108 | goto out; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | err = file_remove_suid(file); | ||
| 1112 | if (err) { | ||
| 1113 | mutex_unlock(&inode->i_mutex); | ||
| 1114 | goto out; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | /* | ||
| 1118 | * If BTRFS flips readonly due to some impossible error | ||
| 1119 | * (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR), | ||
| 1120 | * although we have opened a file as writable, we have | ||
| 1121 | * to stop this write operation to ensure FS consistency. | ||
| 1122 | */ | ||
| 1123 | if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { | ||
| 1124 | mutex_unlock(&inode->i_mutex); | ||
| 1125 | err = -EROFS; | ||
| 1126 | goto out; | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | file_update_time(file); | ||
| 1130 | BTRFS_I(inode)->sequence++; | ||
| 1131 | |||
| 1132 | if (unlikely(file->f_flags & O_DIRECT)) { | ||
| 1133 | num_written = __btrfs_direct_write(iocb, iov, nr_segs, | ||
| 1134 | pos, ppos, count, ocount); | ||
| 1135 | } else { | ||
| 1136 | struct iov_iter i; | ||
| 1137 | |||
| 1138 | iov_iter_init(&i, iov, nr_segs, count, num_written); | ||
| 1139 | |||
| 1140 | num_written = __btrfs_buffered_write(file, &i, pos); | ||
| 1141 | if (num_written > 0) | ||
| 1142 | *ppos = pos + num_written; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | mutex_unlock(&inode->i_mutex); | ||
| 1107 | 1146 | ||
| 1108 | /* | 1147 | /* |
| 1109 | * we want to make sure fsync finds this change | 1148 | * we want to make sure fsync finds this change |
| @@ -1118,43 +1157,12 @@ out: | |||
| 1118 | * one running right now. | 1157 | * one running right now. |
| 1119 | */ | 1158 | */ |
| 1120 | BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; | 1159 | BTRFS_I(inode)->last_trans = root->fs_info->generation + 1; |
| 1121 | 1160 | if (num_written > 0 || num_written == -EIOCBQUEUED) { | |
| 1122 | if (num_written > 0 && will_write) { | 1161 | err = generic_write_sync(file, pos, num_written); |
| 1123 | struct btrfs_trans_handle *trans; | 1162 | if (err < 0 && num_written > 0) |
| 1124 | |||
| 1125 | err = btrfs_wait_ordered_range(inode, start_pos, num_written); | ||
| 1126 | if (err) | ||
| 1127 | num_written = err; | 1163 | num_written = err; |
| 1128 | |||
| 1129 | if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { | ||
| 1130 | trans = btrfs_start_transaction(root, 0); | ||
| 1131 | if (IS_ERR(trans)) { | ||
| 1132 | num_written = PTR_ERR(trans); | ||
| 1133 | goto done; | ||
| 1134 | } | ||
| 1135 | mutex_lock(&inode->i_mutex); | ||
| 1136 | ret = btrfs_log_dentry_safe(trans, root, | ||
| 1137 | file->f_dentry); | ||
| 1138 | mutex_unlock(&inode->i_mutex); | ||
| 1139 | if (ret == 0) { | ||
| 1140 | ret = btrfs_sync_log(trans, root); | ||
| 1141 | if (ret == 0) | ||
| 1142 | btrfs_end_transaction(trans, root); | ||
| 1143 | else | ||
| 1144 | btrfs_commit_transaction(trans, root); | ||
| 1145 | } else if (ret != BTRFS_NO_LOG_SYNC) { | ||
| 1146 | btrfs_commit_transaction(trans, root); | ||
| 1147 | } else { | ||
| 1148 | btrfs_end_transaction(trans, root); | ||
| 1149 | } | ||
| 1150 | } | ||
| 1151 | if (file->f_flags & O_DIRECT && buffered) { | ||
| 1152 | invalidate_mapping_pages(inode->i_mapping, | ||
| 1153 | start_pos >> PAGE_CACHE_SHIFT, | ||
| 1154 | (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT); | ||
| 1155 | } | ||
| 1156 | } | 1164 | } |
| 1157 | done: | 1165 | out: |
| 1158 | current->backing_dev_info = NULL; | 1166 | current->backing_dev_info = NULL; |
| 1159 | return num_written ? num_written : err; | 1167 | return num_written ? num_written : err; |
| 1160 | } | 1168 | } |
| @@ -1197,6 +1205,7 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
| 1197 | int ret = 0; | 1205 | int ret = 0; |
| 1198 | struct btrfs_trans_handle *trans; | 1206 | struct btrfs_trans_handle *trans; |
| 1199 | 1207 | ||
| 1208 | trace_btrfs_sync_file(file, datasync); | ||
| 1200 | 1209 | ||
| 1201 | /* we wait first, since the writeback may change the inode */ | 1210 | /* we wait first, since the writeback may change the inode */ |
| 1202 | root->log_batch++; | 1211 | root->log_batch++; |
| @@ -1324,7 +1333,8 @@ static long btrfs_fallocate(struct file *file, int mode, | |||
| 1324 | goto out; | 1333 | goto out; |
| 1325 | 1334 | ||
| 1326 | if (alloc_start > inode->i_size) { | 1335 | if (alloc_start > inode->i_size) { |
| 1327 | ret = btrfs_cont_expand(inode, alloc_start); | 1336 | ret = btrfs_cont_expand(inode, i_size_read(inode), |
| 1337 | alloc_start); | ||
| 1328 | if (ret) | 1338 | if (ret) |
| 1329 | goto out; | 1339 | goto out; |
| 1330 | } | 1340 | } |
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index a0390657451b..0037427d8a9d 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
| @@ -393,7 +393,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, | |||
| 393 | break; | 393 | break; |
| 394 | 394 | ||
| 395 | need_loop = 1; | 395 | need_loop = 1; |
| 396 | e = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS); | 396 | e = kmem_cache_zalloc(btrfs_free_space_cachep, |
| 397 | GFP_NOFS); | ||
| 397 | if (!e) { | 398 | if (!e) { |
| 398 | kunmap(page); | 399 | kunmap(page); |
| 399 | unlock_page(page); | 400 | unlock_page(page); |
| @@ -405,7 +406,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, | |||
| 405 | e->bytes = le64_to_cpu(entry->bytes); | 406 | e->bytes = le64_to_cpu(entry->bytes); |
| 406 | if (!e->bytes) { | 407 | if (!e->bytes) { |
| 407 | kunmap(page); | 408 | kunmap(page); |
| 408 | kfree(e); | 409 | kmem_cache_free(btrfs_free_space_cachep, e); |
| 409 | unlock_page(page); | 410 | unlock_page(page); |
| 410 | page_cache_release(page); | 411 | page_cache_release(page); |
| 411 | goto free_cache; | 412 | goto free_cache; |
| @@ -420,7 +421,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, | |||
| 420 | e->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS); | 421 | e->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS); |
| 421 | if (!e->bitmap) { | 422 | if (!e->bitmap) { |
| 422 | kunmap(page); | 423 | kunmap(page); |
| 423 | kfree(e); | 424 | kmem_cache_free( |
| 425 | btrfs_free_space_cachep, e); | ||
| 424 | unlock_page(page); | 426 | unlock_page(page); |
| 425 | page_cache_release(page); | 427 | page_cache_release(page); |
| 426 | goto free_cache; | 428 | goto free_cache; |
| @@ -1187,7 +1189,7 @@ static void free_bitmap(struct btrfs_block_group_cache *block_group, | |||
| 1187 | { | 1189 | { |
| 1188 | unlink_free_space(block_group, bitmap_info); | 1190 | unlink_free_space(block_group, bitmap_info); |
| 1189 | kfree(bitmap_info->bitmap); | 1191 | kfree(bitmap_info->bitmap); |
| 1190 | kfree(bitmap_info); | 1192 | kmem_cache_free(btrfs_free_space_cachep, bitmap_info); |
| 1191 | block_group->total_bitmaps--; | 1193 | block_group->total_bitmaps--; |
| 1192 | recalculate_thresholds(block_group); | 1194 | recalculate_thresholds(block_group); |
| 1193 | } | 1195 | } |
| @@ -1285,9 +1287,22 @@ static int insert_into_bitmap(struct btrfs_block_group_cache *block_group, | |||
| 1285 | * If we are below the extents threshold then we can add this as an | 1287 | * If we are below the extents threshold then we can add this as an |
| 1286 | * extent, and don't have to deal with the bitmap | 1288 | * extent, and don't have to deal with the bitmap |
| 1287 | */ | 1289 | */ |
| 1288 | if (block_group->free_extents < block_group->extents_thresh && | 1290 | if (block_group->free_extents < block_group->extents_thresh) { |
| 1289 | info->bytes > block_group->sectorsize * 4) | 1291 | /* |
| 1290 | return 0; | 1292 | * If this block group has some small extents we don't want to |
| 1293 | * use up all of our free slots in the cache with them, we want | ||
| 1294 | * to reserve them to larger extents, however if we have plent | ||
| 1295 | * of cache left then go ahead an dadd them, no sense in adding | ||
| 1296 | * the overhead of a bitmap if we don't have to. | ||
| 1297 | */ | ||
| 1298 | if (info->bytes <= block_group->sectorsize * 4) { | ||
| 1299 | if (block_group->free_extents * 2 <= | ||
| 1300 | block_group->extents_thresh) | ||
| 1301 | return 0; | ||
| 1302 | } else { | ||
| 1303 | return 0; | ||
| 1304 | } | ||
| 1305 | } | ||
| 1291 | 1306 | ||
| 1292 | /* | 1307 | /* |
| 1293 | * some block groups are so tiny they can't be enveloped by a bitmap, so | 1308 | * some block groups are so tiny they can't be enveloped by a bitmap, so |
| @@ -1342,8 +1357,8 @@ new_bitmap: | |||
| 1342 | 1357 | ||
| 1343 | /* no pre-allocated info, allocate a new one */ | 1358 | /* no pre-allocated info, allocate a new one */ |
| 1344 | if (!info) { | 1359 | if (!info) { |
| 1345 | info = kzalloc(sizeof(struct btrfs_free_space), | 1360 | info = kmem_cache_zalloc(btrfs_free_space_cachep, |
| 1346 | GFP_NOFS); | 1361 | GFP_NOFS); |
| 1347 | if (!info) { | 1362 | if (!info) { |
| 1348 | spin_lock(&block_group->tree_lock); | 1363 | spin_lock(&block_group->tree_lock); |
| 1349 | ret = -ENOMEM; | 1364 | ret = -ENOMEM; |
| @@ -1365,7 +1380,7 @@ out: | |||
| 1365 | if (info) { | 1380 | if (info) { |
| 1366 | if (info->bitmap) | 1381 | if (info->bitmap) |
| 1367 | kfree(info->bitmap); | 1382 | kfree(info->bitmap); |
| 1368 | kfree(info); | 1383 | kmem_cache_free(btrfs_free_space_cachep, info); |
| 1369 | } | 1384 | } |
| 1370 | 1385 | ||
| 1371 | return ret; | 1386 | return ret; |
| @@ -1398,7 +1413,7 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group, | |||
| 1398 | else | 1413 | else |
| 1399 | __unlink_free_space(block_group, right_info); | 1414 | __unlink_free_space(block_group, right_info); |
| 1400 | info->bytes += right_info->bytes; | 1415 | info->bytes += right_info->bytes; |
| 1401 | kfree(right_info); | 1416 | kmem_cache_free(btrfs_free_space_cachep, right_info); |
| 1402 | merged = true; | 1417 | merged = true; |
| 1403 | } | 1418 | } |
| 1404 | 1419 | ||
| @@ -1410,7 +1425,7 @@ bool try_merge_free_space(struct btrfs_block_group_cache *block_group, | |||
| 1410 | __unlink_free_space(block_group, left_info); | 1425 | __unlink_free_space(block_group, left_info); |
| 1411 | info->offset = left_info->offset; | 1426 | info->offset = left_info->offset; |
| 1412 | info->bytes += left_info->bytes; | 1427 | info->bytes += left_info->bytes; |
| 1413 | kfree(left_info); | 1428 | kmem_cache_free(btrfs_free_space_cachep, left_info); |
| 1414 | merged = true; | 1429 | merged = true; |
| 1415 | } | 1430 | } |
| 1416 | 1431 | ||
| @@ -1423,7 +1438,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | |||
| 1423 | struct btrfs_free_space *info; | 1438 | struct btrfs_free_space *info; |
| 1424 | int ret = 0; | 1439 | int ret = 0; |
| 1425 | 1440 | ||
| 1426 | info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS); | 1441 | info = kmem_cache_zalloc(btrfs_free_space_cachep, GFP_NOFS); |
| 1427 | if (!info) | 1442 | if (!info) |
| 1428 | return -ENOMEM; | 1443 | return -ENOMEM; |
| 1429 | 1444 | ||
| @@ -1450,7 +1465,7 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | |||
| 1450 | link: | 1465 | link: |
| 1451 | ret = link_free_space(block_group, info); | 1466 | ret = link_free_space(block_group, info); |
| 1452 | if (ret) | 1467 | if (ret) |
| 1453 | kfree(info); | 1468 | kmem_cache_free(btrfs_free_space_cachep, info); |
| 1454 | out: | 1469 | out: |
| 1455 | spin_unlock(&block_group->tree_lock); | 1470 | spin_unlock(&block_group->tree_lock); |
| 1456 | 1471 | ||
| @@ -1520,7 +1535,7 @@ again: | |||
| 1520 | kfree(info->bitmap); | 1535 | kfree(info->bitmap); |
| 1521 | block_group->total_bitmaps--; | 1536 | block_group->total_bitmaps--; |
| 1522 | } | 1537 | } |
| 1523 | kfree(info); | 1538 | kmem_cache_free(btrfs_free_space_cachep, info); |
| 1524 | goto out_lock; | 1539 | goto out_lock; |
| 1525 | } | 1540 | } |
| 1526 | 1541 | ||
| @@ -1556,7 +1571,7 @@ again: | |||
| 1556 | /* the hole we're creating ends at the end | 1571 | /* the hole we're creating ends at the end |
| 1557 | * of the info struct, just free the info | 1572 | * of the info struct, just free the info |
| 1558 | */ | 1573 | */ |
| 1559 | kfree(info); | 1574 | kmem_cache_free(btrfs_free_space_cachep, info); |
| 1560 | } | 1575 | } |
| 1561 | spin_unlock(&block_group->tree_lock); | 1576 | spin_unlock(&block_group->tree_lock); |
| 1562 | 1577 | ||
| @@ -1629,30 +1644,28 @@ __btrfs_return_cluster_to_free_space( | |||
| 1629 | { | 1644 | { |
| 1630 | struct btrfs_free_space *entry; | 1645 | struct btrfs_free_space *entry; |
| 1631 | struct rb_node *node; | 1646 | struct rb_node *node; |
| 1632 | bool bitmap; | ||
| 1633 | 1647 | ||
| 1634 | spin_lock(&cluster->lock); | 1648 | spin_lock(&cluster->lock); |
| 1635 | if (cluster->block_group != block_group) | 1649 | if (cluster->block_group != block_group) |
| 1636 | goto out; | 1650 | goto out; |
| 1637 | 1651 | ||
| 1638 | bitmap = cluster->points_to_bitmap; | ||
| 1639 | cluster->block_group = NULL; | 1652 | cluster->block_group = NULL; |
| 1640 | cluster->window_start = 0; | 1653 | cluster->window_start = 0; |
| 1641 | list_del_init(&cluster->block_group_list); | 1654 | list_del_init(&cluster->block_group_list); |
| 1642 | cluster->points_to_bitmap = false; | ||
| 1643 | |||
| 1644 | if (bitmap) | ||
| 1645 | goto out; | ||
| 1646 | 1655 | ||
| 1647 | node = rb_first(&cluster->root); | 1656 | node = rb_first(&cluster->root); |
| 1648 | while (node) { | 1657 | while (node) { |
| 1658 | bool bitmap; | ||
| 1659 | |||
| 1649 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | 1660 | entry = rb_entry(node, struct btrfs_free_space, offset_index); |
| 1650 | node = rb_next(&entry->offset_index); | 1661 | node = rb_next(&entry->offset_index); |
| 1651 | rb_erase(&entry->offset_index, &cluster->root); | 1662 | rb_erase(&entry->offset_index, &cluster->root); |
| 1652 | BUG_ON(entry->bitmap); | 1663 | |
| 1653 | try_merge_free_space(block_group, entry, false); | 1664 | bitmap = (entry->bitmap != NULL); |
| 1665 | if (!bitmap) | ||
| 1666 | try_merge_free_space(block_group, entry, false); | ||
| 1654 | tree_insert_offset(&block_group->free_space_offset, | 1667 | tree_insert_offset(&block_group->free_space_offset, |
| 1655 | entry->offset, &entry->offset_index, 0); | 1668 | entry->offset, &entry->offset_index, bitmap); |
| 1656 | } | 1669 | } |
| 1657 | cluster->root = RB_ROOT; | 1670 | cluster->root = RB_ROOT; |
| 1658 | 1671 | ||
| @@ -1689,7 +1702,7 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group) | |||
| 1689 | unlink_free_space(block_group, info); | 1702 | unlink_free_space(block_group, info); |
| 1690 | if (info->bitmap) | 1703 | if (info->bitmap) |
| 1691 | kfree(info->bitmap); | 1704 | kfree(info->bitmap); |
| 1692 | kfree(info); | 1705 | kmem_cache_free(btrfs_free_space_cachep, info); |
| 1693 | if (need_resched()) { | 1706 | if (need_resched()) { |
| 1694 | spin_unlock(&block_group->tree_lock); | 1707 | spin_unlock(&block_group->tree_lock); |
| 1695 | cond_resched(); | 1708 | cond_resched(); |
| @@ -1722,7 +1735,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, | |||
| 1722 | entry->offset += bytes; | 1735 | entry->offset += bytes; |
| 1723 | entry->bytes -= bytes; | 1736 | entry->bytes -= bytes; |
| 1724 | if (!entry->bytes) | 1737 | if (!entry->bytes) |
| 1725 | kfree(entry); | 1738 | kmem_cache_free(btrfs_free_space_cachep, entry); |
| 1726 | else | 1739 | else |
| 1727 | link_free_space(block_group, entry); | 1740 | link_free_space(block_group, entry); |
| 1728 | } | 1741 | } |
| @@ -1775,50 +1788,24 @@ int btrfs_return_cluster_to_free_space( | |||
| 1775 | 1788 | ||
| 1776 | static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, | 1789 | static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, |
| 1777 | struct btrfs_free_cluster *cluster, | 1790 | struct btrfs_free_cluster *cluster, |
| 1791 | struct btrfs_free_space *entry, | ||
| 1778 | u64 bytes, u64 min_start) | 1792 | u64 bytes, u64 min_start) |
| 1779 | { | 1793 | { |
| 1780 | struct btrfs_free_space *entry; | ||
| 1781 | int err; | 1794 | int err; |
| 1782 | u64 search_start = cluster->window_start; | 1795 | u64 search_start = cluster->window_start; |
| 1783 | u64 search_bytes = bytes; | 1796 | u64 search_bytes = bytes; |
| 1784 | u64 ret = 0; | 1797 | u64 ret = 0; |
| 1785 | 1798 | ||
| 1786 | spin_lock(&block_group->tree_lock); | ||
| 1787 | spin_lock(&cluster->lock); | ||
| 1788 | |||
| 1789 | if (!cluster->points_to_bitmap) | ||
| 1790 | goto out; | ||
| 1791 | |||
| 1792 | if (cluster->block_group != block_group) | ||
| 1793 | goto out; | ||
| 1794 | |||
| 1795 | /* | ||
| 1796 | * search_start is the beginning of the bitmap, but at some point it may | ||
| 1797 | * be a good idea to point to the actual start of the free area in the | ||
| 1798 | * bitmap, so do the offset_to_bitmap trick anyway, and set bitmap_only | ||
| 1799 | * to 1 to make sure we get the bitmap entry | ||
| 1800 | */ | ||
| 1801 | entry = tree_search_offset(block_group, | ||
| 1802 | offset_to_bitmap(block_group, search_start), | ||
| 1803 | 1, 0); | ||
| 1804 | if (!entry || !entry->bitmap) | ||
| 1805 | goto out; | ||
| 1806 | |||
| 1807 | search_start = min_start; | 1799 | search_start = min_start; |
| 1808 | search_bytes = bytes; | 1800 | search_bytes = bytes; |
| 1809 | 1801 | ||
| 1810 | err = search_bitmap(block_group, entry, &search_start, | 1802 | err = search_bitmap(block_group, entry, &search_start, |
| 1811 | &search_bytes); | 1803 | &search_bytes); |
| 1812 | if (err) | 1804 | if (err) |
| 1813 | goto out; | 1805 | return 0; |
| 1814 | 1806 | ||
| 1815 | ret = search_start; | 1807 | ret = search_start; |
| 1816 | bitmap_clear_bits(block_group, entry, ret, bytes); | 1808 | bitmap_clear_bits(block_group, entry, ret, bytes); |
| 1817 | if (entry->bytes == 0) | ||
| 1818 | free_bitmap(block_group, entry); | ||
| 1819 | out: | ||
| 1820 | spin_unlock(&cluster->lock); | ||
| 1821 | spin_unlock(&block_group->tree_lock); | ||
| 1822 | 1809 | ||
| 1823 | return ret; | 1810 | return ret; |
| 1824 | } | 1811 | } |
| @@ -1836,10 +1823,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, | |||
| 1836 | struct rb_node *node; | 1823 | struct rb_node *node; |
| 1837 | u64 ret = 0; | 1824 | u64 ret = 0; |
| 1838 | 1825 | ||
| 1839 | if (cluster->points_to_bitmap) | ||
| 1840 | return btrfs_alloc_from_bitmap(block_group, cluster, bytes, | ||
| 1841 | min_start); | ||
| 1842 | |||
| 1843 | spin_lock(&cluster->lock); | 1826 | spin_lock(&cluster->lock); |
| 1844 | if (bytes > cluster->max_size) | 1827 | if (bytes > cluster->max_size) |
| 1845 | goto out; | 1828 | goto out; |
| @@ -1852,9 +1835,9 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, | |||
| 1852 | goto out; | 1835 | goto out; |
| 1853 | 1836 | ||
| 1854 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | 1837 | entry = rb_entry(node, struct btrfs_free_space, offset_index); |
| 1855 | |||
| 1856 | while(1) { | 1838 | while(1) { |
| 1857 | if (entry->bytes < bytes || entry->offset < min_start) { | 1839 | if (entry->bytes < bytes || |
| 1840 | (!entry->bitmap && entry->offset < min_start)) { | ||
| 1858 | struct rb_node *node; | 1841 | struct rb_node *node; |
| 1859 | 1842 | ||
| 1860 | node = rb_next(&entry->offset_index); | 1843 | node = rb_next(&entry->offset_index); |
| @@ -1864,10 +1847,27 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, | |||
| 1864 | offset_index); | 1847 | offset_index); |
| 1865 | continue; | 1848 | continue; |
| 1866 | } | 1849 | } |
| 1867 | ret = entry->offset; | ||
| 1868 | 1850 | ||
| 1869 | entry->offset += bytes; | 1851 | if (entry->bitmap) { |
| 1870 | entry->bytes -= bytes; | 1852 | ret = btrfs_alloc_from_bitmap(block_group, |
| 1853 | cluster, entry, bytes, | ||
| 1854 | min_start); | ||
| 1855 | if (ret == 0) { | ||
| 1856 | struct rb_node *node; | ||
| 1857 | node = rb_next(&entry->offset_index); | ||
| 1858 | if (!node) | ||
| 1859 | break; | ||
| 1860 | entry = rb_entry(node, struct btrfs_free_space, | ||
| 1861 | offset_index); | ||
| 1862 | continue; | ||
| 1863 | } | ||
| 1864 | } else { | ||
| 1865 | |||
| 1866 | ret = entry->offset; | ||
| 1867 | |||
| 1868 | entry->offset += bytes; | ||
| 1869 | entry->bytes -= bytes; | ||
| 1870 | } | ||
| 1871 | 1871 | ||
| 1872 | if (entry->bytes == 0) | 1872 | if (entry->bytes == 0) |
| 1873 | rb_erase(&entry->offset_index, &cluster->root); | 1873 | rb_erase(&entry->offset_index, &cluster->root); |
| @@ -1884,7 +1884,12 @@ out: | |||
| 1884 | block_group->free_space -= bytes; | 1884 | block_group->free_space -= bytes; |
| 1885 | if (entry->bytes == 0) { | 1885 | if (entry->bytes == 0) { |
| 1886 | block_group->free_extents--; | 1886 | block_group->free_extents--; |
| 1887 | kfree(entry); | 1887 | if (entry->bitmap) { |
| 1888 | kfree(entry->bitmap); | ||
| 1889 | block_group->total_bitmaps--; | ||
| 1890 | recalculate_thresholds(block_group); | ||
| 1891 | } | ||
| 1892 | kmem_cache_free(btrfs_free_space_cachep, entry); | ||
| 1888 | } | 1893 | } |
| 1889 | 1894 | ||
| 1890 | spin_unlock(&block_group->tree_lock); | 1895 | spin_unlock(&block_group->tree_lock); |
| @@ -1904,12 +1909,13 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group, | |||
| 1904 | unsigned long found_bits; | 1909 | unsigned long found_bits; |
| 1905 | unsigned long start = 0; | 1910 | unsigned long start = 0; |
| 1906 | unsigned long total_found = 0; | 1911 | unsigned long total_found = 0; |
| 1912 | int ret; | ||
| 1907 | bool found = false; | 1913 | bool found = false; |
| 1908 | 1914 | ||
| 1909 | i = offset_to_bit(entry->offset, block_group->sectorsize, | 1915 | i = offset_to_bit(entry->offset, block_group->sectorsize, |
| 1910 | max_t(u64, offset, entry->offset)); | 1916 | max_t(u64, offset, entry->offset)); |
| 1911 | search_bits = bytes_to_bits(min_bytes, block_group->sectorsize); | 1917 | search_bits = bytes_to_bits(bytes, block_group->sectorsize); |
| 1912 | total_bits = bytes_to_bits(bytes, block_group->sectorsize); | 1918 | total_bits = bytes_to_bits(min_bytes, block_group->sectorsize); |
| 1913 | 1919 | ||
| 1914 | again: | 1920 | again: |
| 1915 | found_bits = 0; | 1921 | found_bits = 0; |
| @@ -1926,7 +1932,7 @@ again: | |||
| 1926 | } | 1932 | } |
| 1927 | 1933 | ||
| 1928 | if (!found_bits) | 1934 | if (!found_bits) |
| 1929 | return -1; | 1935 | return -ENOSPC; |
| 1930 | 1936 | ||
| 1931 | if (!found) { | 1937 | if (!found) { |
| 1932 | start = i; | 1938 | start = i; |
| @@ -1950,189 +1956,208 @@ again: | |||
| 1950 | 1956 | ||
| 1951 | cluster->window_start = start * block_group->sectorsize + | 1957 | cluster->window_start = start * block_group->sectorsize + |
| 1952 | entry->offset; | 1958 | entry->offset; |
| 1953 | cluster->points_to_bitmap = true; | 1959 | rb_erase(&entry->offset_index, &block_group->free_space_offset); |
| 1960 | ret = tree_insert_offset(&cluster->root, entry->offset, | ||
| 1961 | &entry->offset_index, 1); | ||
| 1962 | BUG_ON(ret); | ||
| 1954 | 1963 | ||
| 1955 | return 0; | 1964 | return 0; |
| 1956 | } | 1965 | } |
| 1957 | 1966 | ||
| 1958 | /* | 1967 | /* |
| 1959 | * here we try to find a cluster of blocks in a block group. The goal | 1968 | * This searches the block group for just extents to fill the cluster with. |
| 1960 | * is to find at least bytes free and up to empty_size + bytes free. | ||
| 1961 | * We might not find them all in one contiguous area. | ||
| 1962 | * | ||
| 1963 | * returns zero and sets up cluster if things worked out, otherwise | ||
| 1964 | * it returns -enospc | ||
| 1965 | */ | 1969 | */ |
| 1966 | int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, | 1970 | static int setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, |
| 1967 | struct btrfs_root *root, | 1971 | struct btrfs_free_cluster *cluster, |
| 1968 | struct btrfs_block_group_cache *block_group, | 1972 | u64 offset, u64 bytes, u64 min_bytes) |
| 1969 | struct btrfs_free_cluster *cluster, | ||
| 1970 | u64 offset, u64 bytes, u64 empty_size) | ||
| 1971 | { | 1973 | { |
| 1974 | struct btrfs_free_space *first = NULL; | ||
| 1972 | struct btrfs_free_space *entry = NULL; | 1975 | struct btrfs_free_space *entry = NULL; |
| 1976 | struct btrfs_free_space *prev = NULL; | ||
| 1977 | struct btrfs_free_space *last; | ||
| 1973 | struct rb_node *node; | 1978 | struct rb_node *node; |
| 1974 | struct btrfs_free_space *next; | ||
| 1975 | struct btrfs_free_space *last = NULL; | ||
| 1976 | u64 min_bytes; | ||
| 1977 | u64 window_start; | 1979 | u64 window_start; |
| 1978 | u64 window_free; | 1980 | u64 window_free; |
| 1979 | u64 max_extent = 0; | 1981 | u64 max_extent; |
| 1980 | bool found_bitmap = false; | 1982 | u64 max_gap = 128 * 1024; |
| 1981 | int ret; | ||
| 1982 | 1983 | ||
| 1983 | /* for metadata, allow allocates with more holes */ | 1984 | entry = tree_search_offset(block_group, offset, 0, 1); |
| 1984 | if (btrfs_test_opt(root, SSD_SPREAD)) { | 1985 | if (!entry) |
| 1985 | min_bytes = bytes + empty_size; | 1986 | return -ENOSPC; |
| 1986 | } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) { | ||
| 1987 | /* | ||
| 1988 | * we want to do larger allocations when we are | ||
| 1989 | * flushing out the delayed refs, it helps prevent | ||
| 1990 | * making more work as we go along. | ||
| 1991 | */ | ||
| 1992 | if (trans->transaction->delayed_refs.flushing) | ||
| 1993 | min_bytes = max(bytes, (bytes + empty_size) >> 1); | ||
| 1994 | else | ||
| 1995 | min_bytes = max(bytes, (bytes + empty_size) >> 4); | ||
| 1996 | } else | ||
| 1997 | min_bytes = max(bytes, (bytes + empty_size) >> 2); | ||
| 1998 | |||
| 1999 | spin_lock(&block_group->tree_lock); | ||
| 2000 | spin_lock(&cluster->lock); | ||
| 2001 | |||
| 2002 | /* someone already found a cluster, hooray */ | ||
| 2003 | if (cluster->block_group) { | ||
| 2004 | ret = 0; | ||
| 2005 | goto out; | ||
| 2006 | } | ||
| 2007 | again: | ||
| 2008 | entry = tree_search_offset(block_group, offset, found_bitmap, 1); | ||
| 2009 | if (!entry) { | ||
| 2010 | ret = -ENOSPC; | ||
| 2011 | goto out; | ||
| 2012 | } | ||
| 2013 | 1987 | ||
| 2014 | /* | 1988 | /* |
| 2015 | * If found_bitmap is true, we exhausted our search for extent entries, | 1989 | * We don't want bitmaps, so just move along until we find a normal |
| 2016 | * and we just want to search all of the bitmaps that we can find, and | 1990 | * extent entry. |
| 2017 | * ignore any extent entries we find. | ||
| 2018 | */ | 1991 | */ |
| 2019 | while (entry->bitmap || found_bitmap || | 1992 | while (entry->bitmap) { |
| 2020 | (!entry->bitmap && entry->bytes < min_bytes)) { | 1993 | node = rb_next(&entry->offset_index); |
| 2021 | struct rb_node *node = rb_next(&entry->offset_index); | 1994 | if (!node) |
| 2022 | 1995 | return -ENOSPC; | |
| 2023 | if (entry->bitmap && entry->bytes > bytes + empty_size) { | ||
| 2024 | ret = btrfs_bitmap_cluster(block_group, entry, cluster, | ||
| 2025 | offset, bytes + empty_size, | ||
| 2026 | min_bytes); | ||
| 2027 | if (!ret) | ||
| 2028 | goto got_it; | ||
| 2029 | } | ||
| 2030 | |||
| 2031 | if (!node) { | ||
| 2032 | ret = -ENOSPC; | ||
| 2033 | goto out; | ||
| 2034 | } | ||
| 2035 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | 1996 | entry = rb_entry(node, struct btrfs_free_space, offset_index); |
| 2036 | } | 1997 | } |
| 2037 | 1998 | ||
| 2038 | /* | ||
| 2039 | * We already searched all the extent entries from the passed in offset | ||
| 2040 | * to the end and didn't find enough space for the cluster, and we also | ||
| 2041 | * didn't find any bitmaps that met our criteria, just go ahead and exit | ||
| 2042 | */ | ||
| 2043 | if (found_bitmap) { | ||
| 2044 | ret = -ENOSPC; | ||
| 2045 | goto out; | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | cluster->points_to_bitmap = false; | ||
| 2049 | window_start = entry->offset; | 1999 | window_start = entry->offset; |
| 2050 | window_free = entry->bytes; | 2000 | window_free = entry->bytes; |
| 2051 | last = entry; | ||
| 2052 | max_extent = entry->bytes; | 2001 | max_extent = entry->bytes; |
| 2002 | first = entry; | ||
| 2003 | last = entry; | ||
| 2004 | prev = entry; | ||
| 2053 | 2005 | ||
| 2054 | while (1) { | 2006 | while (window_free <= min_bytes) { |
| 2055 | /* out window is just right, lets fill it */ | 2007 | node = rb_next(&entry->offset_index); |
| 2056 | if (window_free >= bytes + empty_size) | 2008 | if (!node) |
| 2057 | break; | 2009 | return -ENOSPC; |
| 2058 | 2010 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | |
| 2059 | node = rb_next(&last->offset_index); | ||
| 2060 | if (!node) { | ||
| 2061 | if (found_bitmap) | ||
| 2062 | goto again; | ||
| 2063 | ret = -ENOSPC; | ||
| 2064 | goto out; | ||
| 2065 | } | ||
| 2066 | next = rb_entry(node, struct btrfs_free_space, offset_index); | ||
| 2067 | 2011 | ||
| 2068 | /* | 2012 | if (entry->bitmap) |
| 2069 | * we found a bitmap, so if this search doesn't result in a | ||
| 2070 | * cluster, we know to go and search again for the bitmaps and | ||
| 2071 | * start looking for space there | ||
| 2072 | */ | ||
| 2073 | if (next->bitmap) { | ||
| 2074 | if (!found_bitmap) | ||
| 2075 | offset = next->offset; | ||
| 2076 | found_bitmap = true; | ||
| 2077 | last = next; | ||
| 2078 | continue; | 2013 | continue; |
| 2079 | } | ||
| 2080 | |||
| 2081 | /* | 2014 | /* |
| 2082 | * we haven't filled the empty size and the window is | 2015 | * we haven't filled the empty size and the window is |
| 2083 | * very large. reset and try again | 2016 | * very large. reset and try again |
| 2084 | */ | 2017 | */ |
| 2085 | if (next->offset - (last->offset + last->bytes) > 128 * 1024 || | 2018 | if (entry->offset - (prev->offset + prev->bytes) > max_gap || |
| 2086 | next->offset - window_start > (bytes + empty_size) * 2) { | 2019 | entry->offset - window_start > (min_bytes * 2)) { |
| 2087 | entry = next; | 2020 | first = entry; |
| 2088 | window_start = entry->offset; | 2021 | window_start = entry->offset; |
| 2089 | window_free = entry->bytes; | 2022 | window_free = entry->bytes; |
| 2090 | last = entry; | 2023 | last = entry; |
| 2091 | max_extent = entry->bytes; | 2024 | max_extent = entry->bytes; |
| 2092 | } else { | 2025 | } else { |
| 2093 | last = next; | 2026 | last = entry; |
| 2094 | window_free += next->bytes; | 2027 | window_free += entry->bytes; |
| 2095 | if (entry->bytes > max_extent) | 2028 | if (entry->bytes > max_extent) |
| 2096 | max_extent = entry->bytes; | 2029 | max_extent = entry->bytes; |
| 2097 | } | 2030 | } |
| 2031 | prev = entry; | ||
| 2098 | } | 2032 | } |
| 2099 | 2033 | ||
| 2100 | cluster->window_start = entry->offset; | 2034 | cluster->window_start = first->offset; |
| 2035 | |||
| 2036 | node = &first->offset_index; | ||
| 2101 | 2037 | ||
| 2102 | /* | 2038 | /* |
| 2103 | * now we've found our entries, pull them out of the free space | 2039 | * now we've found our entries, pull them out of the free space |
| 2104 | * cache and put them into the cluster rbtree | 2040 | * cache and put them into the cluster rbtree |
| 2105 | * | ||
| 2106 | * The cluster includes an rbtree, but only uses the offset index | ||
| 2107 | * of each free space cache entry. | ||
| 2108 | */ | 2041 | */ |
| 2109 | while (1) { | 2042 | do { |
| 2043 | int ret; | ||
| 2044 | |||
| 2045 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | ||
| 2110 | node = rb_next(&entry->offset_index); | 2046 | node = rb_next(&entry->offset_index); |
| 2111 | if (entry->bitmap && node) { | 2047 | if (entry->bitmap) |
| 2112 | entry = rb_entry(node, struct btrfs_free_space, | ||
| 2113 | offset_index); | ||
| 2114 | continue; | 2048 | continue; |
| 2115 | } else if (entry->bitmap && !node) { | ||
| 2116 | break; | ||
| 2117 | } | ||
| 2118 | 2049 | ||
| 2119 | rb_erase(&entry->offset_index, &block_group->free_space_offset); | 2050 | rb_erase(&entry->offset_index, &block_group->free_space_offset); |
| 2120 | ret = tree_insert_offset(&cluster->root, entry->offset, | 2051 | ret = tree_insert_offset(&cluster->root, entry->offset, |
| 2121 | &entry->offset_index, 0); | 2052 | &entry->offset_index, 0); |
| 2122 | BUG_ON(ret); | 2053 | BUG_ON(ret); |
| 2054 | } while (node && entry != last); | ||
| 2123 | 2055 | ||
| 2124 | if (!node || entry == last) | 2056 | cluster->max_size = max_extent; |
| 2125 | break; | 2057 | |
| 2058 | return 0; | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | /* | ||
| 2062 | * This specifically looks for bitmaps that may work in the cluster, we assume | ||
| 2063 | * that we have already failed to find extents that will work. | ||
| 2064 | */ | ||
| 2065 | static int setup_cluster_bitmap(struct btrfs_block_group_cache *block_group, | ||
| 2066 | struct btrfs_free_cluster *cluster, | ||
| 2067 | u64 offset, u64 bytes, u64 min_bytes) | ||
| 2068 | { | ||
| 2069 | struct btrfs_free_space *entry; | ||
| 2070 | struct rb_node *node; | ||
| 2071 | int ret = -ENOSPC; | ||
| 2072 | |||
| 2073 | if (block_group->total_bitmaps == 0) | ||
| 2074 | return -ENOSPC; | ||
| 2126 | 2075 | ||
| 2076 | entry = tree_search_offset(block_group, | ||
| 2077 | offset_to_bitmap(block_group, offset), | ||
| 2078 | 0, 1); | ||
| 2079 | if (!entry) | ||
| 2080 | return -ENOSPC; | ||
| 2081 | |||
| 2082 | node = &entry->offset_index; | ||
| 2083 | do { | ||
| 2127 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | 2084 | entry = rb_entry(node, struct btrfs_free_space, offset_index); |
| 2085 | node = rb_next(&entry->offset_index); | ||
| 2086 | if (!entry->bitmap) | ||
| 2087 | continue; | ||
| 2088 | if (entry->bytes < min_bytes) | ||
| 2089 | continue; | ||
| 2090 | ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset, | ||
| 2091 | bytes, min_bytes); | ||
| 2092 | } while (ret && node); | ||
| 2093 | |||
| 2094 | return ret; | ||
| 2095 | } | ||
| 2096 | |||
| 2097 | /* | ||
| 2098 | * here we try to find a cluster of blocks in a block group. The goal | ||
| 2099 | * is to find at least bytes free and up to empty_size + bytes free. | ||
| 2100 | * We might not find them all in one contiguous area. | ||
| 2101 | * | ||
| 2102 | * returns zero and sets up cluster if things worked out, otherwise | ||
| 2103 | * it returns -enospc | ||
| 2104 | */ | ||
| 2105 | int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, | ||
| 2106 | struct btrfs_root *root, | ||
| 2107 | struct btrfs_block_group_cache *block_group, | ||
| 2108 | struct btrfs_free_cluster *cluster, | ||
| 2109 | u64 offset, u64 bytes, u64 empty_size) | ||
| 2110 | { | ||
| 2111 | u64 min_bytes; | ||
| 2112 | int ret; | ||
| 2113 | |||
| 2114 | /* for metadata, allow allocates with more holes */ | ||
| 2115 | if (btrfs_test_opt(root, SSD_SPREAD)) { | ||
| 2116 | min_bytes = bytes + empty_size; | ||
| 2117 | } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) { | ||
| 2118 | /* | ||
| 2119 | * we want to do larger allocations when we are | ||
| 2120 | * flushing out the delayed refs, it helps prevent | ||
| 2121 | * making more work as we go along. | ||
| 2122 | */ | ||
| 2123 | if (trans->transaction->delayed_refs.flushing) | ||
| 2124 | min_bytes = max(bytes, (bytes + empty_size) >> 1); | ||
| 2125 | else | ||
| 2126 | min_bytes = max(bytes, (bytes + empty_size) >> 4); | ||
| 2127 | } else | ||
| 2128 | min_bytes = max(bytes, (bytes + empty_size) >> 2); | ||
| 2129 | |||
| 2130 | spin_lock(&block_group->tree_lock); | ||
| 2131 | |||
| 2132 | /* | ||
| 2133 | * If we know we don't have enough space to make a cluster don't even | ||
| 2134 | * bother doing all the work to try and find one. | ||
| 2135 | */ | ||
| 2136 | if (block_group->free_space < min_bytes) { | ||
| 2137 | spin_unlock(&block_group->tree_lock); | ||
| 2138 | return -ENOSPC; | ||
| 2128 | } | 2139 | } |
| 2129 | 2140 | ||
| 2130 | cluster->max_size = max_extent; | 2141 | spin_lock(&cluster->lock); |
| 2131 | got_it: | 2142 | |
| 2132 | ret = 0; | 2143 | /* someone already found a cluster, hooray */ |
| 2133 | atomic_inc(&block_group->count); | 2144 | if (cluster->block_group) { |
| 2134 | list_add_tail(&cluster->block_group_list, &block_group->cluster_list); | 2145 | ret = 0; |
| 2135 | cluster->block_group = block_group; | 2146 | goto out; |
| 2147 | } | ||
| 2148 | |||
| 2149 | ret = setup_cluster_no_bitmap(block_group, cluster, offset, bytes, | ||
| 2150 | min_bytes); | ||
| 2151 | if (ret) | ||
| 2152 | ret = setup_cluster_bitmap(block_group, cluster, offset, | ||
| 2153 | bytes, min_bytes); | ||
| 2154 | |||
| 2155 | if (!ret) { | ||
| 2156 | atomic_inc(&block_group->count); | ||
| 2157 | list_add_tail(&cluster->block_group_list, | ||
| 2158 | &block_group->cluster_list); | ||
| 2159 | cluster->block_group = block_group; | ||
| 2160 | } | ||
| 2136 | out: | 2161 | out: |
| 2137 | spin_unlock(&cluster->lock); | 2162 | spin_unlock(&cluster->lock); |
| 2138 | spin_unlock(&block_group->tree_lock); | 2163 | spin_unlock(&block_group->tree_lock); |
| @@ -2149,8 +2174,99 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) | |||
| 2149 | spin_lock_init(&cluster->refill_lock); | 2174 | spin_lock_init(&cluster->refill_lock); |
| 2150 | cluster->root = RB_ROOT; | 2175 | cluster->root = RB_ROOT; |
| 2151 | cluster->max_size = 0; | 2176 | cluster->max_size = 0; |
| 2152 | cluster->points_to_bitmap = false; | ||
| 2153 | INIT_LIST_HEAD(&cluster->block_group_list); | 2177 | INIT_LIST_HEAD(&cluster->block_group_list); |
| 2154 | cluster->block_group = NULL; | 2178 | cluster->block_group = NULL; |
| 2155 | } | 2179 | } |
| 2156 | 2180 | ||
| 2181 | int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, | ||
| 2182 | u64 *trimmed, u64 start, u64 end, u64 minlen) | ||
| 2183 | { | ||
| 2184 | struct btrfs_free_space *entry = NULL; | ||
| 2185 | struct btrfs_fs_info *fs_info = block_group->fs_info; | ||
| 2186 | u64 bytes = 0; | ||
| 2187 | u64 actually_trimmed; | ||
| 2188 | int ret = 0; | ||
| 2189 | |||
| 2190 | *trimmed = 0; | ||
| 2191 | |||
| 2192 | while (start < end) { | ||
| 2193 | spin_lock(&block_group->tree_lock); | ||
| 2194 | |||
| 2195 | if (block_group->free_space < minlen) { | ||
| 2196 | spin_unlock(&block_group->tree_lock); | ||
| 2197 | break; | ||
| 2198 | } | ||
| 2199 | |||
| 2200 | entry = tree_search_offset(block_group, start, 0, 1); | ||
| 2201 | if (!entry) | ||
| 2202 | entry = tree_search_offset(block_group, | ||
| 2203 | offset_to_bitmap(block_group, | ||
| 2204 | start), | ||
| 2205 | 1, 1); | ||
| 2206 | |||
| 2207 | if (!entry || entry->offset >= end) { | ||
| 2208 | spin_unlock(&block_group->tree_lock); | ||
| 2209 | break; | ||
| 2210 | } | ||
| 2211 | |||
| 2212 | if (entry->bitmap) { | ||
| 2213 | ret = search_bitmap(block_group, entry, &start, &bytes); | ||
| 2214 | if (!ret) { | ||
| 2215 | if (start >= end) { | ||
| 2216 | spin_unlock(&block_group->tree_lock); | ||
| 2217 | break; | ||
| 2218 | } | ||
| 2219 | bytes = min(bytes, end - start); | ||
| 2220 | bitmap_clear_bits(block_group, entry, | ||
| 2221 | start, bytes); | ||
| 2222 | if (entry->bytes == 0) | ||
| 2223 | free_bitmap(block_group, entry); | ||
| 2224 | } else { | ||
| 2225 | start = entry->offset + BITS_PER_BITMAP * | ||
| 2226 | block_group->sectorsize; | ||
| 2227 | spin_unlock(&block_group->tree_lock); | ||
| 2228 | ret = 0; | ||
| 2229 | continue; | ||
| 2230 | } | ||
| 2231 | } else { | ||
| 2232 | start = entry->offset; | ||
| 2233 | bytes = min(entry->bytes, end - start); | ||
| 2234 | unlink_free_space(block_group, entry); | ||
| 2235 | kfree(entry); | ||
| 2236 | } | ||
| 2237 | |||
| 2238 | spin_unlock(&block_group->tree_lock); | ||
| 2239 | |||
| 2240 | if (bytes >= minlen) { | ||
| 2241 | int update_ret; | ||
| 2242 | update_ret = btrfs_update_reserved_bytes(block_group, | ||
| 2243 | bytes, 1, 1); | ||
| 2244 | |||
| 2245 | ret = btrfs_error_discard_extent(fs_info->extent_root, | ||
| 2246 | start, | ||
| 2247 | bytes, | ||
| 2248 | &actually_trimmed); | ||
| 2249 | |||
| 2250 | btrfs_add_free_space(block_group, | ||
| 2251 | start, bytes); | ||
| 2252 | if (!update_ret) | ||
| 2253 | btrfs_update_reserved_bytes(block_group, | ||
| 2254 | bytes, 0, 1); | ||
| 2255 | |||
| 2256 | if (ret) | ||
| 2257 | break; | ||
| 2258 | *trimmed += actually_trimmed; | ||
| 2259 | } | ||
| 2260 | start += bytes; | ||
| 2261 | bytes = 0; | ||
| 2262 | |||
| 2263 | if (fatal_signal_pending(current)) { | ||
| 2264 | ret = -ERESTARTSYS; | ||
| 2265 | break; | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | cond_resched(); | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | return ret; | ||
| 2272 | } | ||
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h index e49ca5c321b5..65c3b935289f 100644 --- a/fs/btrfs/free-space-cache.h +++ b/fs/btrfs/free-space-cache.h | |||
| @@ -68,4 +68,6 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, | |||
| 68 | int btrfs_return_cluster_to_free_space( | 68 | int btrfs_return_cluster_to_free_space( |
| 69 | struct btrfs_block_group_cache *block_group, | 69 | struct btrfs_block_group_cache *block_group, |
| 70 | struct btrfs_free_cluster *cluster); | 70 | struct btrfs_free_cluster *cluster); |
| 71 | int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, | ||
| 72 | u64 *trimmed, u64 start, u64 end, u64 minlen); | ||
| 71 | #endif | 73 | #endif |
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index c56eb5909172..c05a08f4c411 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c | |||
| @@ -30,7 +30,8 @@ int btrfs_find_highest_inode(struct btrfs_root *root, u64 *objectid) | |||
| 30 | int slot; | 30 | int slot; |
| 31 | 31 | ||
| 32 | path = btrfs_alloc_path(); | 32 | path = btrfs_alloc_path(); |
| 33 | BUG_ON(!path); | 33 | if (!path) |
| 34 | return -ENOMEM; | ||
| 34 | 35 | ||
| 35 | search_key.objectid = BTRFS_LAST_FREE_OBJECTID; | 36 | search_key.objectid = BTRFS_LAST_FREE_OBJECTID; |
| 36 | search_key.type = -1; | 37 | search_key.type = -1; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 119520bdb9a5..93c28a1d6bdc 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include "tree-log.h" | 50 | #include "tree-log.h" |
| 51 | #include "compression.h" | 51 | #include "compression.h" |
| 52 | #include "locking.h" | 52 | #include "locking.h" |
| 53 | #include "free-space-cache.h" | ||
| 53 | 54 | ||
| 54 | struct btrfs_iget_args { | 55 | struct btrfs_iget_args { |
| 55 | u64 ino; | 56 | u64 ino; |
| @@ -70,6 +71,7 @@ static struct kmem_cache *btrfs_inode_cachep; | |||
| 70 | struct kmem_cache *btrfs_trans_handle_cachep; | 71 | struct kmem_cache *btrfs_trans_handle_cachep; |
| 71 | struct kmem_cache *btrfs_transaction_cachep; | 72 | struct kmem_cache *btrfs_transaction_cachep; |
| 72 | struct kmem_cache *btrfs_path_cachep; | 73 | struct kmem_cache *btrfs_path_cachep; |
| 74 | struct kmem_cache *btrfs_free_space_cachep; | ||
| 73 | 75 | ||
| 74 | #define S_SHIFT 12 | 76 | #define S_SHIFT 12 |
| 75 | static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { | 77 | static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { |
| @@ -82,7 +84,8 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { | |||
| 82 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, | 84 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, |
| 83 | }; | 85 | }; |
| 84 | 86 | ||
| 85 | static void btrfs_truncate(struct inode *inode); | 87 | static int btrfs_setsize(struct inode *inode, loff_t newsize); |
| 88 | static int btrfs_truncate(struct inode *inode); | ||
| 86 | static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end); | 89 | static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end); |
| 87 | static noinline int cow_file_range(struct inode *inode, | 90 | static noinline int cow_file_range(struct inode *inode, |
| 88 | struct page *locked_page, | 91 | struct page *locked_page, |
| @@ -288,6 +291,7 @@ static noinline int add_async_extent(struct async_cow *cow, | |||
| 288 | struct async_extent *async_extent; | 291 | struct async_extent *async_extent; |
| 289 | 292 | ||
| 290 | async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS); | 293 | async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS); |
| 294 | BUG_ON(!async_extent); | ||
| 291 | async_extent->start = start; | 295 | async_extent->start = start; |
| 292 | async_extent->ram_size = ram_size; | 296 | async_extent->ram_size = ram_size; |
| 293 | async_extent->compressed_size = compressed_size; | 297 | async_extent->compressed_size = compressed_size; |
| @@ -382,9 +386,11 @@ again: | |||
| 382 | */ | 386 | */ |
| 383 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) && | 387 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) && |
| 384 | (btrfs_test_opt(root, COMPRESS) || | 388 | (btrfs_test_opt(root, COMPRESS) || |
| 385 | (BTRFS_I(inode)->force_compress))) { | 389 | (BTRFS_I(inode)->force_compress) || |
| 390 | (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS))) { | ||
| 386 | WARN_ON(pages); | 391 | WARN_ON(pages); |
| 387 | pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); | 392 | pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); |
| 393 | BUG_ON(!pages); | ||
| 388 | 394 | ||
| 389 | if (BTRFS_I(inode)->force_compress) | 395 | if (BTRFS_I(inode)->force_compress) |
| 390 | compress_type = BTRFS_I(inode)->force_compress; | 396 | compress_type = BTRFS_I(inode)->force_compress; |
| @@ -1254,7 +1260,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, | |||
| 1254 | ret = run_delalloc_nocow(inode, locked_page, start, end, | 1260 | ret = run_delalloc_nocow(inode, locked_page, start, end, |
| 1255 | page_started, 0, nr_written); | 1261 | page_started, 0, nr_written); |
| 1256 | else if (!btrfs_test_opt(root, COMPRESS) && | 1262 | else if (!btrfs_test_opt(root, COMPRESS) && |
| 1257 | !(BTRFS_I(inode)->force_compress)) | 1263 | !(BTRFS_I(inode)->force_compress) && |
| 1264 | !(BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS)) | ||
| 1258 | ret = cow_file_range(inode, locked_page, start, end, | 1265 | ret = cow_file_range(inode, locked_page, start, end, |
| 1259 | page_started, nr_written, 1); | 1266 | page_started, nr_written, 1); |
| 1260 | else | 1267 | else |
| @@ -1461,8 +1468,11 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
| 1461 | if (bio_flags & EXTENT_BIO_COMPRESSED) { | 1468 | if (bio_flags & EXTENT_BIO_COMPRESSED) { |
| 1462 | return btrfs_submit_compressed_read(inode, bio, | 1469 | return btrfs_submit_compressed_read(inode, bio, |
| 1463 | mirror_num, bio_flags); | 1470 | mirror_num, bio_flags); |
| 1464 | } else if (!skip_sum) | 1471 | } else if (!skip_sum) { |
| 1465 | btrfs_lookup_bio_sums(root, inode, bio, NULL); | 1472 | ret = btrfs_lookup_bio_sums(root, inode, bio, NULL); |
| 1473 | if (ret) | ||
| 1474 | return ret; | ||
| 1475 | } | ||
| 1466 | goto mapit; | 1476 | goto mapit; |
| 1467 | } else if (!skip_sum) { | 1477 | } else if (!skip_sum) { |
| 1468 | /* csum items have already been cloned */ | 1478 | /* csum items have already been cloned */ |
| @@ -1785,6 +1795,8 @@ out: | |||
| 1785 | static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, | 1795 | static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, |
| 1786 | struct extent_state *state, int uptodate) | 1796 | struct extent_state *state, int uptodate) |
| 1787 | { | 1797 | { |
| 1798 | trace_btrfs_writepage_end_io_hook(page, start, end, uptodate); | ||
| 1799 | |||
| 1788 | ClearPagePrivate2(page); | 1800 | ClearPagePrivate2(page); |
| 1789 | return btrfs_finish_ordered_io(page->mapping->host, start, end); | 1801 | return btrfs_finish_ordered_io(page->mapping->host, start, end); |
| 1790 | } | 1802 | } |
| @@ -1895,10 +1907,10 @@ static int btrfs_io_failed_hook(struct bio *failed_bio, | |||
| 1895 | else | 1907 | else |
| 1896 | rw = READ; | 1908 | rw = READ; |
| 1897 | 1909 | ||
| 1898 | BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio, | 1910 | ret = BTRFS_I(inode)->io_tree.ops->submit_bio_hook(inode, rw, bio, |
| 1899 | failrec->last_mirror, | 1911 | failrec->last_mirror, |
| 1900 | failrec->bio_flags, 0); | 1912 | failrec->bio_flags, 0); |
| 1901 | return 0; | 1913 | return ret; |
| 1902 | } | 1914 | } |
| 1903 | 1915 | ||
| 1904 | /* | 1916 | /* |
| @@ -2282,7 +2294,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode) | |||
| 2282 | * this cleans up any orphans that may be left on the list from the last use | 2294 | * this cleans up any orphans that may be left on the list from the last use |
| 2283 | * of this root. | 2295 | * of this root. |
| 2284 | */ | 2296 | */ |
| 2285 | void btrfs_orphan_cleanup(struct btrfs_root *root) | 2297 | int btrfs_orphan_cleanup(struct btrfs_root *root) |
| 2286 | { | 2298 | { |
| 2287 | struct btrfs_path *path; | 2299 | struct btrfs_path *path; |
| 2288 | struct extent_buffer *leaf; | 2300 | struct extent_buffer *leaf; |
| @@ -2292,10 +2304,13 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2292 | int ret = 0, nr_unlink = 0, nr_truncate = 0; | 2304 | int ret = 0, nr_unlink = 0, nr_truncate = 0; |
| 2293 | 2305 | ||
| 2294 | if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED)) | 2306 | if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED)) |
| 2295 | return; | 2307 | return 0; |
| 2296 | 2308 | ||
| 2297 | path = btrfs_alloc_path(); | 2309 | path = btrfs_alloc_path(); |
| 2298 | BUG_ON(!path); | 2310 | if (!path) { |
| 2311 | ret = -ENOMEM; | ||
| 2312 | goto out; | ||
| 2313 | } | ||
| 2299 | path->reada = -1; | 2314 | path->reada = -1; |
| 2300 | 2315 | ||
| 2301 | key.objectid = BTRFS_ORPHAN_OBJECTID; | 2316 | key.objectid = BTRFS_ORPHAN_OBJECTID; |
| @@ -2304,11 +2319,8 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2304 | 2319 | ||
| 2305 | while (1) { | 2320 | while (1) { |
| 2306 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 2321 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
| 2307 | if (ret < 0) { | 2322 | if (ret < 0) |
| 2308 | printk(KERN_ERR "Error searching slot for orphan: %d" | 2323 | goto out; |
| 2309 | "\n", ret); | ||
| 2310 | break; | ||
| 2311 | } | ||
| 2312 | 2324 | ||
| 2313 | /* | 2325 | /* |
| 2314 | * if ret == 0 means we found what we were searching for, which | 2326 | * if ret == 0 means we found what we were searching for, which |
| @@ -2316,6 +2328,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2316 | * find the key and see if we have stuff that matches | 2328 | * find the key and see if we have stuff that matches |
| 2317 | */ | 2329 | */ |
| 2318 | if (ret > 0) { | 2330 | if (ret > 0) { |
| 2331 | ret = 0; | ||
| 2319 | if (path->slots[0] == 0) | 2332 | if (path->slots[0] == 0) |
| 2320 | break; | 2333 | break; |
| 2321 | path->slots[0]--; | 2334 | path->slots[0]--; |
| @@ -2343,7 +2356,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2343 | found_key.type = BTRFS_INODE_ITEM_KEY; | 2356 | found_key.type = BTRFS_INODE_ITEM_KEY; |
| 2344 | found_key.offset = 0; | 2357 | found_key.offset = 0; |
| 2345 | inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); | 2358 | inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); |
| 2346 | BUG_ON(IS_ERR(inode)); | 2359 | if (IS_ERR(inode)) { |
| 2360 | ret = PTR_ERR(inode); | ||
| 2361 | goto out; | ||
| 2362 | } | ||
| 2347 | 2363 | ||
| 2348 | /* | 2364 | /* |
| 2349 | * add this inode to the orphan list so btrfs_orphan_del does | 2365 | * add this inode to the orphan list so btrfs_orphan_del does |
| @@ -2361,7 +2377,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2361 | */ | 2377 | */ |
| 2362 | if (is_bad_inode(inode)) { | 2378 | if (is_bad_inode(inode)) { |
| 2363 | trans = btrfs_start_transaction(root, 0); | 2379 | trans = btrfs_start_transaction(root, 0); |
| 2364 | BUG_ON(IS_ERR(trans)); | 2380 | if (IS_ERR(trans)) { |
| 2381 | ret = PTR_ERR(trans); | ||
| 2382 | goto out; | ||
| 2383 | } | ||
| 2365 | btrfs_orphan_del(trans, inode); | 2384 | btrfs_orphan_del(trans, inode); |
| 2366 | btrfs_end_transaction(trans, root); | 2385 | btrfs_end_transaction(trans, root); |
| 2367 | iput(inode); | 2386 | iput(inode); |
| @@ -2370,17 +2389,22 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2370 | 2389 | ||
| 2371 | /* if we have links, this was a truncate, lets do that */ | 2390 | /* if we have links, this was a truncate, lets do that */ |
| 2372 | if (inode->i_nlink) { | 2391 | if (inode->i_nlink) { |
| 2392 | if (!S_ISREG(inode->i_mode)) { | ||
| 2393 | WARN_ON(1); | ||
| 2394 | iput(inode); | ||
| 2395 | continue; | ||
| 2396 | } | ||
| 2373 | nr_truncate++; | 2397 | nr_truncate++; |
| 2374 | btrfs_truncate(inode); | 2398 | ret = btrfs_truncate(inode); |
| 2375 | } else { | 2399 | } else { |
| 2376 | nr_unlink++; | 2400 | nr_unlink++; |
| 2377 | } | 2401 | } |
| 2378 | 2402 | ||
| 2379 | /* this will do delete_inode and everything for us */ | 2403 | /* this will do delete_inode and everything for us */ |
| 2380 | iput(inode); | 2404 | iput(inode); |
| 2405 | if (ret) | ||
| 2406 | goto out; | ||
| 2381 | } | 2407 | } |
| 2382 | btrfs_free_path(path); | ||
| 2383 | |||
| 2384 | root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; | 2408 | root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; |
| 2385 | 2409 | ||
| 2386 | if (root->orphan_block_rsv) | 2410 | if (root->orphan_block_rsv) |
| @@ -2389,14 +2413,20 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
| 2389 | 2413 | ||
| 2390 | if (root->orphan_block_rsv || root->orphan_item_inserted) { | 2414 | if (root->orphan_block_rsv || root->orphan_item_inserted) { |
| 2391 | trans = btrfs_join_transaction(root, 1); | 2415 | trans = btrfs_join_transaction(root, 1); |
| 2392 | BUG_ON(IS_ERR(trans)); | 2416 | if (!IS_ERR(trans)) |
| 2393 | btrfs_end_transaction(trans, root); | 2417 | btrfs_end_transaction(trans, root); |
| 2394 | } | 2418 | } |
| 2395 | 2419 | ||
| 2396 | if (nr_unlink) | 2420 | if (nr_unlink) |
| 2397 | printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink); | 2421 | printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink); |
| 2398 | if (nr_truncate) | 2422 | if (nr_truncate) |
| 2399 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); | 2423 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); |
| 2424 | |||
| 2425 | out: | ||
| 2426 | if (ret) | ||
| 2427 | printk(KERN_CRIT "btrfs: could not do orphan cleanup %d\n", ret); | ||
| 2428 | btrfs_free_path(path); | ||
| 2429 | return ret; | ||
| 2400 | } | 2430 | } |
| 2401 | 2431 | ||
| 2402 | /* | 2432 | /* |
| @@ -2507,6 +2537,8 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
| 2507 | BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); | 2537 | BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); |
| 2508 | 2538 | ||
| 2509 | alloc_group_block = btrfs_inode_block_group(leaf, inode_item); | 2539 | alloc_group_block = btrfs_inode_block_group(leaf, inode_item); |
| 2540 | if (location.objectid == BTRFS_FREE_SPACE_OBJECTID) | ||
| 2541 | inode->i_mapping->flags &= ~__GFP_FS; | ||
| 2510 | 2542 | ||
| 2511 | /* | 2543 | /* |
| 2512 | * try to precache a NULL acl entry for files that don't have | 2544 | * try to precache a NULL acl entry for files that don't have |
| @@ -2635,10 +2667,10 @@ failed: | |||
| 2635 | * recovery code. It remove a link in a directory with a given name, and | 2667 | * recovery code. It remove a link in a directory with a given name, and |
| 2636 | * also drops the back refs in the inode to the directory | 2668 | * also drops the back refs in the inode to the directory |
| 2637 | */ | 2669 | */ |
| 2638 | int btrfs_unlink_inode(struct btrfs_trans_handle *trans, | 2670 | static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, |
| 2639 | struct btrfs_root *root, | 2671 | struct btrfs_root *root, |
| 2640 | struct inode *dir, struct inode *inode, | 2672 | struct inode *dir, struct inode *inode, |
| 2641 | const char *name, int name_len) | 2673 | const char *name, int name_len) |
| 2642 | { | 2674 | { |
| 2643 | struct btrfs_path *path; | 2675 | struct btrfs_path *path; |
| 2644 | int ret = 0; | 2676 | int ret = 0; |
| @@ -2710,12 +2742,25 @@ err: | |||
| 2710 | btrfs_i_size_write(dir, dir->i_size - name_len * 2); | 2742 | btrfs_i_size_write(dir, dir->i_size - name_len * 2); |
| 2711 | inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME; | 2743 | inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME; |
| 2712 | btrfs_update_inode(trans, root, dir); | 2744 | btrfs_update_inode(trans, root, dir); |
| 2713 | btrfs_drop_nlink(inode); | ||
| 2714 | ret = btrfs_update_inode(trans, root, inode); | ||
| 2715 | out: | 2745 | out: |
| 2716 | return ret; | 2746 | return ret; |
| 2717 | } | 2747 | } |
| 2718 | 2748 | ||
| 2749 | int btrfs_unlink_inode(struct btrfs_trans_handle *trans, | ||
| 2750 | struct btrfs_root *root, | ||
| 2751 | struct inode *dir, struct inode *inode, | ||
| 2752 | const char *name, int name_len) | ||
| 2753 | { | ||
| 2754 | int ret; | ||
| 2755 | ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len); | ||
| 2756 | if (!ret) { | ||
| 2757 | btrfs_drop_nlink(inode); | ||
| 2758 | ret = btrfs_update_inode(trans, root, inode); | ||
| 2759 | } | ||
| 2760 | return ret; | ||
| 2761 | } | ||
| 2762 | |||
| 2763 | |||
| 2719 | /* helper to check if there is any shared block in the path */ | 2764 | /* helper to check if there is any shared block in the path */ |
| 2720 | static int check_path_shared(struct btrfs_root *root, | 2765 | static int check_path_shared(struct btrfs_root *root, |
| 2721 | struct btrfs_path *path) | 2766 | struct btrfs_path *path) |
| @@ -3537,7 +3582,13 @@ out: | |||
| 3537 | return ret; | 3582 | return ret; |
| 3538 | } | 3583 | } |
| 3539 | 3584 | ||
| 3540 | int btrfs_cont_expand(struct inode *inode, loff_t size) | 3585 | /* |
| 3586 | * This function puts in dummy file extents for the area we're creating a hole | ||
| 3587 | * for. So if we are truncating this file to a larger size we need to insert | ||
| 3588 | * these file extents so that btrfs_get_extent will return a EXTENT_MAP_HOLE for | ||
| 3589 | * the range between oldsize and size | ||
| 3590 | */ | ||
| 3591 | int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | ||
| 3541 | { | 3592 | { |
| 3542 | struct btrfs_trans_handle *trans; | 3593 | struct btrfs_trans_handle *trans; |
| 3543 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3594 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| @@ -3545,7 +3596,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) | |||
| 3545 | struct extent_map *em = NULL; | 3596 | struct extent_map *em = NULL; |
| 3546 | struct extent_state *cached_state = NULL; | 3597 | struct extent_state *cached_state = NULL; |
| 3547 | u64 mask = root->sectorsize - 1; | 3598 | u64 mask = root->sectorsize - 1; |
| 3548 | u64 hole_start = (inode->i_size + mask) & ~mask; | 3599 | u64 hole_start = (oldsize + mask) & ~mask; |
| 3549 | u64 block_end = (size + mask) & ~mask; | 3600 | u64 block_end = (size + mask) & ~mask; |
| 3550 | u64 last_byte; | 3601 | u64 last_byte; |
| 3551 | u64 cur_offset; | 3602 | u64 cur_offset; |
| @@ -3590,13 +3641,15 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) | |||
| 3590 | err = btrfs_drop_extents(trans, inode, cur_offset, | 3641 | err = btrfs_drop_extents(trans, inode, cur_offset, |
| 3591 | cur_offset + hole_size, | 3642 | cur_offset + hole_size, |
| 3592 | &hint_byte, 1); | 3643 | &hint_byte, 1); |
| 3593 | BUG_ON(err); | 3644 | if (err) |
| 3645 | break; | ||
| 3594 | 3646 | ||
| 3595 | err = btrfs_insert_file_extent(trans, root, | 3647 | err = btrfs_insert_file_extent(trans, root, |
| 3596 | inode->i_ino, cur_offset, 0, | 3648 | inode->i_ino, cur_offset, 0, |
| 3597 | 0, hole_size, 0, hole_size, | 3649 | 0, hole_size, 0, hole_size, |
| 3598 | 0, 0, 0); | 3650 | 0, 0, 0); |
| 3599 | BUG_ON(err); | 3651 | if (err) |
| 3652 | break; | ||
| 3600 | 3653 | ||
| 3601 | btrfs_drop_extent_cache(inode, hole_start, | 3654 | btrfs_drop_extent_cache(inode, hole_start, |
| 3602 | last_byte - 1, 0); | 3655 | last_byte - 1, 0); |
| @@ -3616,81 +3669,41 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) | |||
| 3616 | return err; | 3669 | return err; |
| 3617 | } | 3670 | } |
| 3618 | 3671 | ||
| 3619 | static int btrfs_setattr_size(struct inode *inode, struct iattr *attr) | 3672 | static int btrfs_setsize(struct inode *inode, loff_t newsize) |
| 3620 | { | 3673 | { |
| 3621 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3674 | loff_t oldsize = i_size_read(inode); |
| 3622 | struct btrfs_trans_handle *trans; | ||
| 3623 | unsigned long nr; | ||
| 3624 | int ret; | 3675 | int ret; |
| 3625 | 3676 | ||
| 3626 | if (attr->ia_size == inode->i_size) | 3677 | if (newsize == oldsize) |
| 3627 | return 0; | 3678 | return 0; |
| 3628 | 3679 | ||
| 3629 | if (attr->ia_size > inode->i_size) { | 3680 | if (newsize > oldsize) { |
| 3630 | unsigned long limit; | 3681 | i_size_write(inode, newsize); |
| 3631 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | 3682 | btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); |
| 3632 | if (attr->ia_size > inode->i_sb->s_maxbytes) | 3683 | truncate_pagecache(inode, oldsize, newsize); |
| 3633 | return -EFBIG; | 3684 | ret = btrfs_cont_expand(inode, oldsize, newsize); |
| 3634 | if (limit != RLIM_INFINITY && attr->ia_size > limit) { | ||
| 3635 | send_sig(SIGXFSZ, current, 0); | ||
| 3636 | return -EFBIG; | ||
| 3637 | } | ||
| 3638 | } | ||
| 3639 | |||
| 3640 | trans = btrfs_start_transaction(root, 5); | ||
| 3641 | if (IS_ERR(trans)) | ||
| 3642 | return PTR_ERR(trans); | ||
| 3643 | |||
| 3644 | btrfs_set_trans_block_group(trans, inode); | ||
| 3645 | |||
| 3646 | ret = btrfs_orphan_add(trans, inode); | ||
| 3647 | BUG_ON(ret); | ||
| 3648 | |||
| 3649 | nr = trans->blocks_used; | ||
| 3650 | btrfs_end_transaction(trans, root); | ||
| 3651 | btrfs_btree_balance_dirty(root, nr); | ||
| 3652 | |||
| 3653 | if (attr->ia_size > inode->i_size) { | ||
| 3654 | ret = btrfs_cont_expand(inode, attr->ia_size); | ||
| 3655 | if (ret) { | 3685 | if (ret) { |
| 3656 | btrfs_truncate(inode); | 3686 | btrfs_setsize(inode, oldsize); |
| 3657 | return ret; | 3687 | return ret; |
| 3658 | } | 3688 | } |
| 3659 | 3689 | ||
| 3660 | i_size_write(inode, attr->ia_size); | 3690 | mark_inode_dirty(inode); |
| 3661 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); | 3691 | } else { |
| 3662 | 3692 | ||
| 3663 | trans = btrfs_start_transaction(root, 0); | 3693 | /* |
| 3664 | BUG_ON(IS_ERR(trans)); | 3694 | * We're truncating a file that used to have good data down to |
| 3665 | btrfs_set_trans_block_group(trans, inode); | 3695 | * zero. Make sure it gets into the ordered flush list so that |
| 3666 | trans->block_rsv = root->orphan_block_rsv; | 3696 | * any new writes get down to disk quickly. |
| 3667 | BUG_ON(!trans->block_rsv); | 3697 | */ |
| 3698 | if (newsize == 0) | ||
| 3699 | BTRFS_I(inode)->ordered_data_close = 1; | ||
| 3668 | 3700 | ||
| 3669 | ret = btrfs_update_inode(trans, root, inode); | 3701 | /* we don't support swapfiles, so vmtruncate shouldn't fail */ |
| 3670 | BUG_ON(ret); | 3702 | truncate_setsize(inode, newsize); |
| 3671 | if (inode->i_nlink > 0) { | 3703 | ret = btrfs_truncate(inode); |
| 3672 | ret = btrfs_orphan_del(trans, inode); | ||
| 3673 | BUG_ON(ret); | ||
| 3674 | } | ||
| 3675 | nr = trans->blocks_used; | ||
| 3676 | btrfs_end_transaction(trans, root); | ||
| 3677 | btrfs_btree_balance_dirty(root, nr); | ||
| 3678 | return 0; | ||
| 3679 | } | 3704 | } |
| 3680 | 3705 | ||
| 3681 | /* | 3706 | return ret; |
| 3682 | * We're truncating a file that used to have good data down to | ||
| 3683 | * zero. Make sure it gets into the ordered flush list so that | ||
| 3684 | * any new writes get down to disk quickly. | ||
| 3685 | */ | ||
| 3686 | if (attr->ia_size == 0) | ||
| 3687 | BTRFS_I(inode)->ordered_data_close = 1; | ||
| 3688 | |||
| 3689 | /* we don't support swapfiles, so vmtruncate shouldn't fail */ | ||
| 3690 | ret = vmtruncate(inode, attr->ia_size); | ||
| 3691 | BUG_ON(ret); | ||
| 3692 | |||
| 3693 | return 0; | ||
| 3694 | } | 3707 | } |
| 3695 | 3708 | ||
| 3696 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | 3709 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) |
| @@ -3707,7 +3720,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 3707 | return err; | 3720 | return err; |
| 3708 | 3721 | ||
| 3709 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { | 3722 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { |
| 3710 | err = btrfs_setattr_size(inode, attr); | 3723 | err = btrfs_setsize(inode, attr->ia_size); |
| 3711 | if (err) | 3724 | if (err) |
| 3712 | return err; | 3725 | return err; |
| 3713 | } | 3726 | } |
| @@ -3730,6 +3743,8 @@ void btrfs_evict_inode(struct inode *inode) | |||
| 3730 | unsigned long nr; | 3743 | unsigned long nr; |
| 3731 | int ret; | 3744 | int ret; |
| 3732 | 3745 | ||
| 3746 | trace_btrfs_inode_evict(inode); | ||
| 3747 | |||
| 3733 | truncate_inode_pages(&inode->i_data, 0); | 3748 | truncate_inode_pages(&inode->i_data, 0); |
| 3734 | if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 || | 3749 | if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 || |
| 3735 | root == root->fs_info->tree_root)) | 3750 | root == root->fs_info->tree_root)) |
| @@ -4072,7 +4087,6 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, | |||
| 4072 | BTRFS_I(inode)->root = root; | 4087 | BTRFS_I(inode)->root = root; |
| 4073 | memcpy(&BTRFS_I(inode)->location, location, sizeof(*location)); | 4088 | memcpy(&BTRFS_I(inode)->location, location, sizeof(*location)); |
| 4074 | btrfs_read_locked_inode(inode); | 4089 | btrfs_read_locked_inode(inode); |
| 4075 | |||
| 4076 | inode_tree_add(inode); | 4090 | inode_tree_add(inode); |
| 4077 | unlock_new_inode(inode); | 4091 | unlock_new_inode(inode); |
| 4078 | if (new) | 4092 | if (new) |
| @@ -4147,8 +4161,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
| 4147 | if (!IS_ERR(inode) && root != sub_root) { | 4161 | if (!IS_ERR(inode) && root != sub_root) { |
| 4148 | down_read(&root->fs_info->cleanup_work_sem); | 4162 | down_read(&root->fs_info->cleanup_work_sem); |
| 4149 | if (!(inode->i_sb->s_flags & MS_RDONLY)) | 4163 | if (!(inode->i_sb->s_flags & MS_RDONLY)) |
| 4150 | btrfs_orphan_cleanup(sub_root); | 4164 | ret = btrfs_orphan_cleanup(sub_root); |
| 4151 | up_read(&root->fs_info->cleanup_work_sem); | 4165 | up_read(&root->fs_info->cleanup_work_sem); |
| 4166 | if (ret) | ||
| 4167 | inode = ERR_PTR(ret); | ||
| 4152 | } | 4168 | } |
| 4153 | 4169 | ||
| 4154 | return inode; | 4170 | return inode; |
| @@ -4282,6 +4298,9 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
| 4282 | while (di_cur < di_total) { | 4298 | while (di_cur < di_total) { |
| 4283 | struct btrfs_key location; | 4299 | struct btrfs_key location; |
| 4284 | 4300 | ||
| 4301 | if (verify_dir_item(root, leaf, di)) | ||
| 4302 | break; | ||
| 4303 | |||
| 4285 | name_len = btrfs_dir_name_len(leaf, di); | 4304 | name_len = btrfs_dir_name_len(leaf, di); |
| 4286 | if (name_len <= sizeof(tmp_name)) { | 4305 | if (name_len <= sizeof(tmp_name)) { |
| 4287 | name_ptr = tmp_name; | 4306 | name_ptr = tmp_name; |
| @@ -4517,6 +4536,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
| 4517 | return ERR_PTR(-ENOMEM); | 4536 | return ERR_PTR(-ENOMEM); |
| 4518 | 4537 | ||
| 4519 | if (dir) { | 4538 | if (dir) { |
| 4539 | trace_btrfs_inode_request(dir); | ||
| 4540 | |||
| 4520 | ret = btrfs_set_inode_index(dir, index); | 4541 | ret = btrfs_set_inode_index(dir, index); |
| 4521 | if (ret) { | 4542 | if (ret) { |
| 4522 | iput(inode); | 4543 | iput(inode); |
| @@ -4585,12 +4606,16 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
| 4585 | if ((mode & S_IFREG)) { | 4606 | if ((mode & S_IFREG)) { |
| 4586 | if (btrfs_test_opt(root, NODATASUM)) | 4607 | if (btrfs_test_opt(root, NODATASUM)) |
| 4587 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | 4608 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; |
| 4588 | if (btrfs_test_opt(root, NODATACOW)) | 4609 | if (btrfs_test_opt(root, NODATACOW) || |
| 4610 | (BTRFS_I(dir)->flags & BTRFS_INODE_NODATACOW)) | ||
| 4589 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | 4611 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; |
| 4590 | } | 4612 | } |
| 4591 | 4613 | ||
| 4592 | insert_inode_hash(inode); | 4614 | insert_inode_hash(inode); |
| 4593 | inode_tree_add(inode); | 4615 | inode_tree_add(inode); |
| 4616 | |||
| 4617 | trace_btrfs_inode_new(inode); | ||
| 4618 | |||
| 4594 | return inode; | 4619 | return inode; |
| 4595 | fail: | 4620 | fail: |
| 4596 | if (dir) | 4621 | if (dir) |
| @@ -4809,7 +4834,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 4809 | 4834 | ||
| 4810 | /* do not allow sys_link's with other subvols of the same device */ | 4835 | /* do not allow sys_link's with other subvols of the same device */ |
| 4811 | if (root->objectid != BTRFS_I(inode)->root->objectid) | 4836 | if (root->objectid != BTRFS_I(inode)->root->objectid) |
| 4812 | return -EPERM; | 4837 | return -EXDEV; |
| 4838 | |||
| 4839 | if (inode->i_nlink == ~0U) | ||
| 4840 | return -EMLINK; | ||
| 4813 | 4841 | ||
| 4814 | btrfs_inc_nlink(inode); | 4842 | btrfs_inc_nlink(inode); |
| 4815 | inode->i_ctime = CURRENT_TIME; | 4843 | inode->i_ctime = CURRENT_TIME; |
| @@ -5265,6 +5293,9 @@ insert: | |||
| 5265 | } | 5293 | } |
| 5266 | write_unlock(&em_tree->lock); | 5294 | write_unlock(&em_tree->lock); |
| 5267 | out: | 5295 | out: |
| 5296 | |||
| 5297 | trace_btrfs_get_extent(root, em); | ||
| 5298 | |||
| 5268 | if (path) | 5299 | if (path) |
| 5269 | btrfs_free_path(path); | 5300 | btrfs_free_path(path); |
| 5270 | if (trans) { | 5301 | if (trans) { |
| @@ -5748,6 +5779,10 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) | |||
| 5748 | 5779 | ||
| 5749 | kfree(dip->csums); | 5780 | kfree(dip->csums); |
| 5750 | kfree(dip); | 5781 | kfree(dip); |
| 5782 | |||
| 5783 | /* If we had a csum failure make sure to clear the uptodate flag */ | ||
| 5784 | if (err) | ||
| 5785 | clear_bit(BIO_UPTODATE, &bio->bi_flags); | ||
| 5751 | dio_end_io(bio, err); | 5786 | dio_end_io(bio, err); |
| 5752 | } | 5787 | } |
| 5753 | 5788 | ||
| @@ -5849,6 +5884,10 @@ out_done: | |||
| 5849 | 5884 | ||
| 5850 | kfree(dip->csums); | 5885 | kfree(dip->csums); |
| 5851 | kfree(dip); | 5886 | kfree(dip); |
| 5887 | |||
| 5888 | /* If we had an error make sure to clear the uptodate flag */ | ||
| 5889 | if (err) | ||
| 5890 | clear_bit(BIO_UPTODATE, &bio->bi_flags); | ||
| 5852 | dio_end_io(bio, err); | 5891 | dio_end_io(bio, err); |
| 5853 | } | 5892 | } |
| 5854 | 5893 | ||
| @@ -5922,9 +5961,12 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | |||
| 5922 | __btrfs_submit_bio_start_direct_io, | 5961 | __btrfs_submit_bio_start_direct_io, |
| 5923 | __btrfs_submit_bio_done); | 5962 | __btrfs_submit_bio_done); |
| 5924 | goto err; | 5963 | goto err; |
| 5925 | } else if (!skip_sum) | 5964 | } else if (!skip_sum) { |
| 5926 | btrfs_lookup_bio_sums_dio(root, inode, bio, | 5965 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, |
| 5927 | file_offset, csums); | 5966 | file_offset, csums); |
| 5967 | if (ret) | ||
| 5968 | goto err; | ||
| 5969 | } | ||
| 5928 | 5970 | ||
| 5929 | ret = btrfs_map_bio(root, rw, bio, 0, 1); | 5971 | ret = btrfs_map_bio(root, rw, bio, 0, 1); |
| 5930 | err: | 5972 | err: |
| @@ -5948,6 +5990,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
| 5948 | int nr_pages = 0; | 5990 | int nr_pages = 0; |
| 5949 | u32 *csums = dip->csums; | 5991 | u32 *csums = dip->csums; |
| 5950 | int ret = 0; | 5992 | int ret = 0; |
| 5993 | int write = rw & REQ_WRITE; | ||
| 5951 | 5994 | ||
| 5952 | bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); | 5995 | bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); |
| 5953 | if (!bio) | 5996 | if (!bio) |
| @@ -5984,7 +6027,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
| 5984 | goto out_err; | 6027 | goto out_err; |
| 5985 | } | 6028 | } |
| 5986 | 6029 | ||
| 5987 | if (!skip_sum) | 6030 | /* Write's use the ordered csums */ |
| 6031 | if (!write && !skip_sum) | ||
| 5988 | csums = csums + nr_pages; | 6032 | csums = csums + nr_pages; |
| 5989 | start_sector += submit_len >> 9; | 6033 | start_sector += submit_len >> 9; |
| 5990 | file_offset += submit_len; | 6034 | file_offset += submit_len; |
| @@ -6052,7 +6096,8 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | |||
| 6052 | } | 6096 | } |
| 6053 | dip->csums = NULL; | 6097 | dip->csums = NULL; |
| 6054 | 6098 | ||
| 6055 | if (!skip_sum) { | 6099 | /* Write's use the ordered csum stuff, so we don't need dip->csums */ |
| 6100 | if (!write && !skip_sum) { | ||
| 6056 | dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS); | 6101 | dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS); |
| 6057 | if (!dip->csums) { | 6102 | if (!dip->csums) { |
| 6058 | kfree(dip); | 6103 | kfree(dip); |
| @@ -6474,28 +6519,42 @@ out: | |||
| 6474 | return ret; | 6519 | return ret; |
| 6475 | } | 6520 | } |
| 6476 | 6521 | ||
| 6477 | static void btrfs_truncate(struct inode *inode) | 6522 | static int btrfs_truncate(struct inode *inode) |
| 6478 | { | 6523 | { |
| 6479 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6524 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 6480 | int ret; | 6525 | int ret; |
| 6526 | int err = 0; | ||
| 6481 | struct btrfs_trans_handle *trans; | 6527 | struct btrfs_trans_handle *trans; |
| 6482 | unsigned long nr; | 6528 | unsigned long nr; |
| 6483 | u64 mask = root->sectorsize - 1; | 6529 | u64 mask = root->sectorsize - 1; |
| 6484 | 6530 | ||
| 6485 | if (!S_ISREG(inode->i_mode)) { | ||
| 6486 | WARN_ON(1); | ||
| 6487 | return; | ||
| 6488 | } | ||
| 6489 | |||
| 6490 | ret = btrfs_truncate_page(inode->i_mapping, inode->i_size); | 6531 | ret = btrfs_truncate_page(inode->i_mapping, inode->i_size); |
| 6491 | if (ret) | 6532 | if (ret) |
| 6492 | return; | 6533 | return ret; |
| 6493 | 6534 | ||
| 6494 | btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); | 6535 | btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); |
| 6495 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); | 6536 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); |
| 6496 | 6537 | ||
| 6538 | trans = btrfs_start_transaction(root, 5); | ||
| 6539 | if (IS_ERR(trans)) | ||
| 6540 | return PTR_ERR(trans); | ||
| 6541 | |||
| 6542 | btrfs_set_trans_block_group(trans, inode); | ||
| 6543 | |||
| 6544 | ret = btrfs_orphan_add(trans, inode); | ||
| 6545 | if (ret) { | ||
| 6546 | btrfs_end_transaction(trans, root); | ||
| 6547 | return ret; | ||
| 6548 | } | ||
| 6549 | |||
| 6550 | nr = trans->blocks_used; | ||
| 6551 | btrfs_end_transaction(trans, root); | ||
| 6552 | btrfs_btree_balance_dirty(root, nr); | ||
| 6553 | |||
| 6554 | /* Now start a transaction for the truncate */ | ||
| 6497 | trans = btrfs_start_transaction(root, 0); | 6555 | trans = btrfs_start_transaction(root, 0); |
| 6498 | BUG_ON(IS_ERR(trans)); | 6556 | if (IS_ERR(trans)) |
| 6557 | return PTR_ERR(trans); | ||
| 6499 | btrfs_set_trans_block_group(trans, inode); | 6558 | btrfs_set_trans_block_group(trans, inode); |
| 6500 | trans->block_rsv = root->orphan_block_rsv; | 6559 | trans->block_rsv = root->orphan_block_rsv; |
| 6501 | 6560 | ||
| @@ -6522,29 +6581,38 @@ static void btrfs_truncate(struct inode *inode) | |||
| 6522 | while (1) { | 6581 | while (1) { |
| 6523 | if (!trans) { | 6582 | if (!trans) { |
| 6524 | trans = btrfs_start_transaction(root, 0); | 6583 | trans = btrfs_start_transaction(root, 0); |
| 6525 | BUG_ON(IS_ERR(trans)); | 6584 | if (IS_ERR(trans)) |
| 6585 | return PTR_ERR(trans); | ||
| 6526 | btrfs_set_trans_block_group(trans, inode); | 6586 | btrfs_set_trans_block_group(trans, inode); |
| 6527 | trans->block_rsv = root->orphan_block_rsv; | 6587 | trans->block_rsv = root->orphan_block_rsv; |
| 6528 | } | 6588 | } |
| 6529 | 6589 | ||
| 6530 | ret = btrfs_block_rsv_check(trans, root, | 6590 | ret = btrfs_block_rsv_check(trans, root, |
| 6531 | root->orphan_block_rsv, 0, 5); | 6591 | root->orphan_block_rsv, 0, 5); |
| 6532 | if (ret) { | 6592 | if (ret == -EAGAIN) { |
| 6533 | BUG_ON(ret != -EAGAIN); | ||
| 6534 | ret = btrfs_commit_transaction(trans, root); | 6593 | ret = btrfs_commit_transaction(trans, root); |
| 6535 | BUG_ON(ret); | 6594 | if (ret) |
| 6595 | return ret; | ||
| 6536 | trans = NULL; | 6596 | trans = NULL; |
| 6537 | continue; | 6597 | continue; |
| 6598 | } else if (ret) { | ||
| 6599 | err = ret; | ||
| 6600 | break; | ||
| 6538 | } | 6601 | } |
| 6539 | 6602 | ||
| 6540 | ret = btrfs_truncate_inode_items(trans, root, inode, | 6603 | ret = btrfs_truncate_inode_items(trans, root, inode, |
| 6541 | inode->i_size, | 6604 | inode->i_size, |
| 6542 | BTRFS_EXTENT_DATA_KEY); | 6605 | BTRFS_EXTENT_DATA_KEY); |
| 6543 | if (ret != -EAGAIN) | 6606 | if (ret != -EAGAIN) { |
| 6607 | err = ret; | ||
| 6544 | break; | 6608 | break; |
| 6609 | } | ||
| 6545 | 6610 | ||
| 6546 | ret = btrfs_update_inode(trans, root, inode); | 6611 | ret = btrfs_update_inode(trans, root, inode); |
| 6547 | BUG_ON(ret); | 6612 | if (ret) { |
| 6613 | err = ret; | ||
| 6614 | break; | ||
| 6615 | } | ||
| 6548 | 6616 | ||
| 6549 | nr = trans->blocks_used; | 6617 | nr = trans->blocks_used; |
| 6550 | btrfs_end_transaction(trans, root); | 6618 | btrfs_end_transaction(trans, root); |
| @@ -6554,16 +6622,27 @@ static void btrfs_truncate(struct inode *inode) | |||
| 6554 | 6622 | ||
| 6555 | if (ret == 0 && inode->i_nlink > 0) { | 6623 | if (ret == 0 && inode->i_nlink > 0) { |
| 6556 | ret = btrfs_orphan_del(trans, inode); | 6624 | ret = btrfs_orphan_del(trans, inode); |
| 6557 | BUG_ON(ret); | 6625 | if (ret) |
| 6626 | err = ret; | ||
| 6627 | } else if (ret && inode->i_nlink > 0) { | ||
| 6628 | /* | ||
| 6629 | * Failed to do the truncate, remove us from the in memory | ||
| 6630 | * orphan list. | ||
| 6631 | */ | ||
| 6632 | ret = btrfs_orphan_del(NULL, inode); | ||
| 6558 | } | 6633 | } |
| 6559 | 6634 | ||
| 6560 | ret = btrfs_update_inode(trans, root, inode); | 6635 | ret = btrfs_update_inode(trans, root, inode); |
| 6561 | BUG_ON(ret); | 6636 | if (ret && !err) |
| 6637 | err = ret; | ||
| 6562 | 6638 | ||
| 6563 | nr = trans->blocks_used; | 6639 | nr = trans->blocks_used; |
| 6564 | ret = btrfs_end_transaction_throttle(trans, root); | 6640 | ret = btrfs_end_transaction_throttle(trans, root); |
| 6565 | BUG_ON(ret); | 6641 | if (ret && !err) |
| 6642 | err = ret; | ||
| 6566 | btrfs_btree_balance_dirty(root, nr); | 6643 | btrfs_btree_balance_dirty(root, nr); |
| 6644 | |||
| 6645 | return err; | ||
| 6567 | } | 6646 | } |
| 6568 | 6647 | ||
| 6569 | /* | 6648 | /* |
| @@ -6630,9 +6709,8 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
| 6630 | ei->index_cnt = (u64)-1; | 6709 | ei->index_cnt = (u64)-1; |
| 6631 | ei->last_unlink_trans = 0; | 6710 | ei->last_unlink_trans = 0; |
| 6632 | 6711 | ||
| 6633 | spin_lock_init(&ei->accounting_lock); | ||
| 6634 | atomic_set(&ei->outstanding_extents, 0); | 6712 | atomic_set(&ei->outstanding_extents, 0); |
| 6635 | ei->reserved_extents = 0; | 6713 | atomic_set(&ei->reserved_extents, 0); |
| 6636 | 6714 | ||
| 6637 | ei->ordered_data_close = 0; | 6715 | ei->ordered_data_close = 0; |
| 6638 | ei->orphan_meta_reserved = 0; | 6716 | ei->orphan_meta_reserved = 0; |
| @@ -6668,7 +6746,7 @@ void btrfs_destroy_inode(struct inode *inode) | |||
| 6668 | WARN_ON(!list_empty(&inode->i_dentry)); | 6746 | WARN_ON(!list_empty(&inode->i_dentry)); |
| 6669 | WARN_ON(inode->i_data.nrpages); | 6747 | WARN_ON(inode->i_data.nrpages); |
| 6670 | WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents)); | 6748 | WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents)); |
| 6671 | WARN_ON(BTRFS_I(inode)->reserved_extents); | 6749 | WARN_ON(atomic_read(&BTRFS_I(inode)->reserved_extents)); |
| 6672 | 6750 | ||
| 6673 | /* | 6751 | /* |
| 6674 | * This can happen where we create an inode, but somebody else also | 6752 | * This can happen where we create an inode, but somebody else also |
| @@ -6760,6 +6838,8 @@ void btrfs_destroy_cachep(void) | |||
| 6760 | kmem_cache_destroy(btrfs_transaction_cachep); | 6838 | kmem_cache_destroy(btrfs_transaction_cachep); |
| 6761 | if (btrfs_path_cachep) | 6839 | if (btrfs_path_cachep) |
| 6762 | kmem_cache_destroy(btrfs_path_cachep); | 6840 | kmem_cache_destroy(btrfs_path_cachep); |
| 6841 | if (btrfs_free_space_cachep) | ||
| 6842 | kmem_cache_destroy(btrfs_free_space_cachep); | ||
| 6763 | } | 6843 | } |
| 6764 | 6844 | ||
| 6765 | int btrfs_init_cachep(void) | 6845 | int btrfs_init_cachep(void) |
| @@ -6788,6 +6868,12 @@ int btrfs_init_cachep(void) | |||
| 6788 | if (!btrfs_path_cachep) | 6868 | if (!btrfs_path_cachep) |
| 6789 | goto fail; | 6869 | goto fail; |
| 6790 | 6870 | ||
| 6871 | btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space_cache", | ||
| 6872 | sizeof(struct btrfs_free_space), 0, | ||
| 6873 | SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL); | ||
| 6874 | if (!btrfs_free_space_cachep) | ||
| 6875 | goto fail; | ||
| 6876 | |||
| 6791 | return 0; | 6877 | return 0; |
| 6792 | fail: | 6878 | fail: |
| 6793 | btrfs_destroy_cachep(); | 6879 | btrfs_destroy_cachep(); |
| @@ -6806,6 +6892,26 @@ static int btrfs_getattr(struct vfsmount *mnt, | |||
| 6806 | return 0; | 6892 | return 0; |
| 6807 | } | 6893 | } |
| 6808 | 6894 | ||
| 6895 | /* | ||
| 6896 | * If a file is moved, it will inherit the cow and compression flags of the new | ||
| 6897 | * directory. | ||
| 6898 | */ | ||
| 6899 | static void fixup_inode_flags(struct inode *dir, struct inode *inode) | ||
| 6900 | { | ||
| 6901 | struct btrfs_inode *b_dir = BTRFS_I(dir); | ||
| 6902 | struct btrfs_inode *b_inode = BTRFS_I(inode); | ||
| 6903 | |||
| 6904 | if (b_dir->flags & BTRFS_INODE_NODATACOW) | ||
| 6905 | b_inode->flags |= BTRFS_INODE_NODATACOW; | ||
| 6906 | else | ||
| 6907 | b_inode->flags &= ~BTRFS_INODE_NODATACOW; | ||
| 6908 | |||
| 6909 | if (b_dir->flags & BTRFS_INODE_COMPRESS) | ||
| 6910 | b_inode->flags |= BTRFS_INODE_COMPRESS; | ||
| 6911 | else | ||
| 6912 | b_inode->flags &= ~BTRFS_INODE_COMPRESS; | ||
| 6913 | } | ||
| 6914 | |||
| 6809 | static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 6915 | static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
| 6810 | struct inode *new_dir, struct dentry *new_dentry) | 6916 | struct inode *new_dir, struct dentry *new_dentry) |
| 6811 | { | 6917 | { |
| @@ -6908,11 +7014,12 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 6908 | old_dentry->d_name.name, | 7014 | old_dentry->d_name.name, |
| 6909 | old_dentry->d_name.len); | 7015 | old_dentry->d_name.len); |
| 6910 | } else { | 7016 | } else { |
| 6911 | btrfs_inc_nlink(old_dentry->d_inode); | 7017 | ret = __btrfs_unlink_inode(trans, root, old_dir, |
| 6912 | ret = btrfs_unlink_inode(trans, root, old_dir, | 7018 | old_dentry->d_inode, |
| 6913 | old_dentry->d_inode, | 7019 | old_dentry->d_name.name, |
| 6914 | old_dentry->d_name.name, | 7020 | old_dentry->d_name.len); |
| 6915 | old_dentry->d_name.len); | 7021 | if (!ret) |
| 7022 | ret = btrfs_update_inode(trans, root, old_inode); | ||
| 6916 | } | 7023 | } |
| 6917 | BUG_ON(ret); | 7024 | BUG_ON(ret); |
| 6918 | 7025 | ||
| @@ -6939,6 +7046,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 6939 | } | 7046 | } |
| 6940 | } | 7047 | } |
| 6941 | 7048 | ||
| 7049 | fixup_inode_flags(new_dir, old_inode); | ||
| 7050 | |||
| 6942 | ret = btrfs_add_link(trans, new_dir, old_inode, | 7051 | ret = btrfs_add_link(trans, new_dir, old_inode, |
| 6943 | new_dentry->d_name.name, | 7052 | new_dentry->d_name.name, |
| 6944 | new_dentry->d_name.len, 0, index); | 7053 | new_dentry->d_name.len, 0, index); |
| @@ -7355,7 +7464,6 @@ static const struct address_space_operations btrfs_symlink_aops = { | |||
| 7355 | }; | 7464 | }; |
| 7356 | 7465 | ||
| 7357 | static const struct inode_operations btrfs_file_inode_operations = { | 7466 | static const struct inode_operations btrfs_file_inode_operations = { |
| 7358 | .truncate = btrfs_truncate, | ||
| 7359 | .getattr = btrfs_getattr, | 7467 | .getattr = btrfs_getattr, |
| 7360 | .setattr = btrfs_setattr, | 7468 | .setattr = btrfs_setattr, |
| 7361 | .setxattr = btrfs_setxattr, | 7469 | .setxattr = btrfs_setxattr, |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d1bace3df9b6..7c07fe26b7cf 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/xattr.h> | 40 | #include <linux/xattr.h> |
| 41 | #include <linux/vmalloc.h> | 41 | #include <linux/vmalloc.h> |
| 42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
| 43 | #include <linux/blkdev.h> | ||
| 43 | #include "compat.h" | 44 | #include "compat.h" |
| 44 | #include "ctree.h" | 45 | #include "ctree.h" |
| 45 | #include "disk-io.h" | 46 | #include "disk-io.h" |
| @@ -138,6 +139,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg) | |||
| 138 | return 0; | 139 | return 0; |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 142 | static int check_flags(unsigned int flags) | ||
| 143 | { | ||
| 144 | if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ | ||
| 145 | FS_NOATIME_FL | FS_NODUMP_FL | \ | ||
| 146 | FS_SYNC_FL | FS_DIRSYNC_FL | \ | ||
| 147 | FS_NOCOMP_FL | FS_COMPR_FL | \ | ||
| 148 | FS_NOCOW_FL | FS_COW_FL)) | ||
| 149 | return -EOPNOTSUPP; | ||
| 150 | |||
| 151 | if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) | ||
| 152 | return -EINVAL; | ||
| 153 | |||
| 154 | if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL)) | ||
| 155 | return -EINVAL; | ||
| 156 | |||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 141 | static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | 160 | static int btrfs_ioctl_setflags(struct file *file, void __user *arg) |
| 142 | { | 161 | { |
| 143 | struct inode *inode = file->f_path.dentry->d_inode; | 162 | struct inode *inode = file->f_path.dentry->d_inode; |
| @@ -153,10 +172,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
| 153 | if (copy_from_user(&flags, arg, sizeof(flags))) | 172 | if (copy_from_user(&flags, arg, sizeof(flags))) |
| 154 | return -EFAULT; | 173 | return -EFAULT; |
| 155 | 174 | ||
| 156 | if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ | 175 | ret = check_flags(flags); |
| 157 | FS_NOATIME_FL | FS_NODUMP_FL | \ | 176 | if (ret) |
| 158 | FS_SYNC_FL | FS_DIRSYNC_FL)) | 177 | return ret; |
| 159 | return -EOPNOTSUPP; | ||
| 160 | 178 | ||
| 161 | if (!inode_owner_or_capable(inode)) | 179 | if (!inode_owner_or_capable(inode)) |
| 162 | return -EACCES; | 180 | return -EACCES; |
| @@ -201,6 +219,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
| 201 | else | 219 | else |
| 202 | ip->flags &= ~BTRFS_INODE_DIRSYNC; | 220 | ip->flags &= ~BTRFS_INODE_DIRSYNC; |
| 203 | 221 | ||
| 222 | /* | ||
| 223 | * The COMPRESS flag can only be changed by users, while the NOCOMPRESS | ||
| 224 | * flag may be changed automatically if compression code won't make | ||
| 225 | * things smaller. | ||
| 226 | */ | ||
| 227 | if (flags & FS_NOCOMP_FL) { | ||
| 228 | ip->flags &= ~BTRFS_INODE_COMPRESS; | ||
| 229 | ip->flags |= BTRFS_INODE_NOCOMPRESS; | ||
| 230 | } else if (flags & FS_COMPR_FL) { | ||
| 231 | ip->flags |= BTRFS_INODE_COMPRESS; | ||
| 232 | ip->flags &= ~BTRFS_INODE_NOCOMPRESS; | ||
| 233 | } | ||
| 234 | if (flags & FS_NOCOW_FL) | ||
| 235 | ip->flags |= BTRFS_INODE_NODATACOW; | ||
| 236 | else if (flags & FS_COW_FL) | ||
| 237 | ip->flags &= ~BTRFS_INODE_NODATACOW; | ||
| 204 | 238 | ||
| 205 | trans = btrfs_join_transaction(root, 1); | 239 | trans = btrfs_join_transaction(root, 1); |
| 206 | BUG_ON(IS_ERR(trans)); | 240 | BUG_ON(IS_ERR(trans)); |
| @@ -213,9 +247,11 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
| 213 | btrfs_end_transaction(trans, root); | 247 | btrfs_end_transaction(trans, root); |
| 214 | 248 | ||
| 215 | mnt_drop_write(file->f_path.mnt); | 249 | mnt_drop_write(file->f_path.mnt); |
| 250 | |||
| 251 | ret = 0; | ||
| 216 | out_unlock: | 252 | out_unlock: |
| 217 | mutex_unlock(&inode->i_mutex); | 253 | mutex_unlock(&inode->i_mutex); |
| 218 | return 0; | 254 | return ret; |
| 219 | } | 255 | } |
| 220 | 256 | ||
| 221 | static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | 257 | static int btrfs_ioctl_getversion(struct file *file, int __user *arg) |
| @@ -225,6 +261,49 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | |||
| 225 | return put_user(inode->i_generation, arg); | 261 | return put_user(inode->i_generation, arg); |
| 226 | } | 262 | } |
| 227 | 263 | ||
| 264 | static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | ||
| 265 | { | ||
| 266 | struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info; | ||
| 267 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
| 268 | struct btrfs_device *device; | ||
| 269 | struct request_queue *q; | ||
| 270 | struct fstrim_range range; | ||
| 271 | u64 minlen = ULLONG_MAX; | ||
| 272 | u64 num_devices = 0; | ||
| 273 | int ret; | ||
| 274 | |||
| 275 | if (!capable(CAP_SYS_ADMIN)) | ||
| 276 | return -EPERM; | ||
| 277 | |||
| 278 | mutex_lock(&fs_info->fs_devices->device_list_mutex); | ||
| 279 | list_for_each_entry(device, &fs_info->fs_devices->devices, dev_list) { | ||
| 280 | if (!device->bdev) | ||
| 281 | continue; | ||
| 282 | q = bdev_get_queue(device->bdev); | ||
| 283 | if (blk_queue_discard(q)) { | ||
| 284 | num_devices++; | ||
| 285 | minlen = min((u64)q->limits.discard_granularity, | ||
| 286 | minlen); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | mutex_unlock(&fs_info->fs_devices->device_list_mutex); | ||
| 290 | if (!num_devices) | ||
| 291 | return -EOPNOTSUPP; | ||
| 292 | |||
| 293 | if (copy_from_user(&range, arg, sizeof(range))) | ||
| 294 | return -EFAULT; | ||
| 295 | |||
| 296 | range.minlen = max(range.minlen, minlen); | ||
| 297 | ret = btrfs_trim_fs(root, &range); | ||
| 298 | if (ret < 0) | ||
| 299 | return ret; | ||
| 300 | |||
| 301 | if (copy_to_user(arg, &range, sizeof(range))) | ||
| 302 | return -EFAULT; | ||
| 303 | |||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 228 | static noinline int create_subvol(struct btrfs_root *root, | 307 | static noinline int create_subvol(struct btrfs_root *root, |
| 229 | struct dentry *dentry, | 308 | struct dentry *dentry, |
| 230 | char *name, int namelen, | 309 | char *name, int namelen, |
| @@ -409,7 +488,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
| 409 | if (ret) | 488 | if (ret) |
| 410 | goto fail; | 489 | goto fail; |
| 411 | 490 | ||
| 412 | btrfs_orphan_cleanup(pending_snapshot->snap); | 491 | ret = btrfs_orphan_cleanup(pending_snapshot->snap); |
| 492 | if (ret) | ||
| 493 | goto fail; | ||
| 413 | 494 | ||
| 414 | parent = dget_parent(dentry); | 495 | parent = dget_parent(dentry); |
| 415 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); | 496 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); |
| @@ -2348,12 +2429,15 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp | |||
| 2348 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; | 2429 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; |
| 2349 | struct btrfs_trans_handle *trans; | 2430 | struct btrfs_trans_handle *trans; |
| 2350 | u64 transid; | 2431 | u64 transid; |
| 2432 | int ret; | ||
| 2351 | 2433 | ||
| 2352 | trans = btrfs_start_transaction(root, 0); | 2434 | trans = btrfs_start_transaction(root, 0); |
| 2353 | if (IS_ERR(trans)) | 2435 | if (IS_ERR(trans)) |
| 2354 | return PTR_ERR(trans); | 2436 | return PTR_ERR(trans); |
| 2355 | transid = trans->transid; | 2437 | transid = trans->transid; |
| 2356 | btrfs_commit_transaction_async(trans, root, 0); | 2438 | ret = btrfs_commit_transaction_async(trans, root, 0); |
| 2439 | if (ret) | ||
| 2440 | return ret; | ||
| 2357 | 2441 | ||
| 2358 | if (argp) | 2442 | if (argp) |
| 2359 | if (copy_to_user(argp, &transid, sizeof(transid))) | 2443 | if (copy_to_user(argp, &transid, sizeof(transid))) |
| @@ -2388,6 +2472,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 2388 | return btrfs_ioctl_setflags(file, argp); | 2472 | return btrfs_ioctl_setflags(file, argp); |
| 2389 | case FS_IOC_GETVERSION: | 2473 | case FS_IOC_GETVERSION: |
| 2390 | return btrfs_ioctl_getversion(file, argp); | 2474 | return btrfs_ioctl_getversion(file, argp); |
| 2475 | case FITRIM: | ||
| 2476 | return btrfs_ioctl_fitrim(file, argp); | ||
| 2391 | case BTRFS_IOC_SNAP_CREATE: | 2477 | case BTRFS_IOC_SNAP_CREATE: |
| 2392 | return btrfs_ioctl_snap_create(file, argp, 0); | 2478 | return btrfs_ioctl_snap_create(file, argp, 0); |
| 2393 | case BTRFS_IOC_SNAP_CREATE_V2: | 2479 | case BTRFS_IOC_SNAP_CREATE_V2: |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 083a55477375..a1c940425307 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
| @@ -202,6 +202,8 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
| 202 | INIT_LIST_HEAD(&entry->list); | 202 | INIT_LIST_HEAD(&entry->list); |
| 203 | INIT_LIST_HEAD(&entry->root_extent_list); | 203 | INIT_LIST_HEAD(&entry->root_extent_list); |
| 204 | 204 | ||
| 205 | trace_btrfs_ordered_extent_add(inode, entry); | ||
| 206 | |||
| 205 | spin_lock(&tree->lock); | 207 | spin_lock(&tree->lock); |
| 206 | node = tree_insert(&tree->tree, file_offset, | 208 | node = tree_insert(&tree->tree, file_offset, |
| 207 | &entry->rb_node); | 209 | &entry->rb_node); |
| @@ -387,6 +389,8 @@ int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry) | |||
| 387 | struct list_head *cur; | 389 | struct list_head *cur; |
| 388 | struct btrfs_ordered_sum *sum; | 390 | struct btrfs_ordered_sum *sum; |
| 389 | 391 | ||
| 392 | trace_btrfs_ordered_extent_put(entry->inode, entry); | ||
| 393 | |||
| 390 | if (atomic_dec_and_test(&entry->refs)) { | 394 | if (atomic_dec_and_test(&entry->refs)) { |
| 391 | while (!list_empty(&entry->list)) { | 395 | while (!list_empty(&entry->list)) { |
| 392 | cur = entry->list.next; | 396 | cur = entry->list.next; |
| @@ -420,6 +424,8 @@ static int __btrfs_remove_ordered_extent(struct inode *inode, | |||
| 420 | spin_lock(&root->fs_info->ordered_extent_lock); | 424 | spin_lock(&root->fs_info->ordered_extent_lock); |
| 421 | list_del_init(&entry->root_extent_list); | 425 | list_del_init(&entry->root_extent_list); |
| 422 | 426 | ||
| 427 | trace_btrfs_ordered_extent_remove(inode, entry); | ||
| 428 | |||
| 423 | /* | 429 | /* |
| 424 | * we have no more ordered extents for this inode and | 430 | * we have no more ordered extents for this inode and |
| 425 | * no dirty pages. We can safely remove it from the | 431 | * no dirty pages. We can safely remove it from the |
| @@ -585,6 +591,8 @@ void btrfs_start_ordered_extent(struct inode *inode, | |||
| 585 | u64 start = entry->file_offset; | 591 | u64 start = entry->file_offset; |
| 586 | u64 end = start + entry->len - 1; | 592 | u64 end = start + entry->len - 1; |
| 587 | 593 | ||
| 594 | trace_btrfs_ordered_extent_start(inode, entry); | ||
| 595 | |||
| 588 | /* | 596 | /* |
| 589 | * pages in the range can be dirty, clean or writeback. We | 597 | * pages in the range can be dirty, clean or writeback. We |
| 590 | * start IO on any dirty ones so the wait doesn't stall waiting | 598 | * start IO on any dirty ones so the wait doesn't stall waiting |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 31ade5802ae8..58250e09eb05 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
| @@ -1724,6 +1724,7 @@ again: | |||
| 1724 | 1724 | ||
| 1725 | eb = read_tree_block(dest, old_bytenr, blocksize, | 1725 | eb = read_tree_block(dest, old_bytenr, blocksize, |
| 1726 | old_ptr_gen); | 1726 | old_ptr_gen); |
| 1727 | BUG_ON(!eb); | ||
| 1727 | btrfs_tree_lock(eb); | 1728 | btrfs_tree_lock(eb); |
| 1728 | if (cow) { | 1729 | if (cow) { |
| 1729 | ret = btrfs_cow_block(trans, dest, eb, parent, | 1730 | ret = btrfs_cow_block(trans, dest, eb, parent, |
| @@ -2513,6 +2514,10 @@ static int do_relocation(struct btrfs_trans_handle *trans, | |||
| 2513 | blocksize = btrfs_level_size(root, node->level); | 2514 | blocksize = btrfs_level_size(root, node->level); |
| 2514 | generation = btrfs_node_ptr_generation(upper->eb, slot); | 2515 | generation = btrfs_node_ptr_generation(upper->eb, slot); |
| 2515 | eb = read_tree_block(root, bytenr, blocksize, generation); | 2516 | eb = read_tree_block(root, bytenr, blocksize, generation); |
| 2517 | if (!eb) { | ||
| 2518 | err = -EIO; | ||
| 2519 | goto next; | ||
| 2520 | } | ||
| 2516 | btrfs_tree_lock(eb); | 2521 | btrfs_tree_lock(eb); |
| 2517 | btrfs_set_lock_blocking(eb); | 2522 | btrfs_set_lock_blocking(eb); |
| 2518 | 2523 | ||
| @@ -2670,6 +2675,7 @@ static int get_tree_block_key(struct reloc_control *rc, | |||
| 2670 | BUG_ON(block->key_ready); | 2675 | BUG_ON(block->key_ready); |
| 2671 | eb = read_tree_block(rc->extent_root, block->bytenr, | 2676 | eb = read_tree_block(rc->extent_root, block->bytenr, |
| 2672 | block->key.objectid, block->key.offset); | 2677 | block->key.objectid, block->key.offset); |
| 2678 | BUG_ON(!eb); | ||
| 2673 | WARN_ON(btrfs_header_level(eb) != block->level); | 2679 | WARN_ON(btrfs_header_level(eb) != block->level); |
| 2674 | if (block->level == 0) | 2680 | if (block->level == 0) |
| 2675 | btrfs_item_key_to_cpu(eb, &block->key, 0); | 2681 | btrfs_item_key_to_cpu(eb, &block->key, 0); |
| @@ -4209,7 +4215,7 @@ out: | |||
| 4209 | if (IS_ERR(fs_root)) | 4215 | if (IS_ERR(fs_root)) |
| 4210 | err = PTR_ERR(fs_root); | 4216 | err = PTR_ERR(fs_root); |
| 4211 | else | 4217 | else |
| 4212 | btrfs_orphan_cleanup(fs_root); | 4218 | err = btrfs_orphan_cleanup(fs_root); |
| 4213 | } | 4219 | } |
| 4214 | return err; | 4220 | return err; |
| 4215 | } | 4221 | } |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 6a1086e83ffc..29b2d7c930eb 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
| @@ -88,7 +88,8 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | |||
| 88 | search_key.offset = (u64)-1; | 88 | search_key.offset = (u64)-1; |
| 89 | 89 | ||
| 90 | path = btrfs_alloc_path(); | 90 | path = btrfs_alloc_path(); |
| 91 | BUG_ON(!path); | 91 | if (!path) |
| 92 | return -ENOMEM; | ||
| 92 | ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); | 93 | ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); |
| 93 | if (ret < 0) | 94 | if (ret < 0) |
| 94 | goto out; | 95 | goto out; |
| @@ -332,7 +333,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
| 332 | struct extent_buffer *leaf; | 333 | struct extent_buffer *leaf; |
| 333 | 334 | ||
| 334 | path = btrfs_alloc_path(); | 335 | path = btrfs_alloc_path(); |
| 335 | BUG_ON(!path); | 336 | if (!path) |
| 337 | return -ENOMEM; | ||
| 336 | ret = btrfs_search_slot(trans, root, key, path, -1, 1); | 338 | ret = btrfs_search_slot(trans, root, key, path, -1, 1); |
| 337 | if (ret < 0) | 339 | if (ret < 0) |
| 338 | goto out; | 340 | goto out; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index d39a9895d932..2edfc039f098 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -52,6 +52,9 @@ | |||
| 52 | #include "export.h" | 52 | #include "export.h" |
| 53 | #include "compression.h" | 53 | #include "compression.h" |
| 54 | 54 | ||
| 55 | #define CREATE_TRACE_POINTS | ||
| 56 | #include <trace/events/btrfs.h> | ||
| 57 | |||
| 55 | static const struct super_operations btrfs_super_ops; | 58 | static const struct super_operations btrfs_super_ops; |
| 56 | 59 | ||
| 57 | static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno, | 60 | static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno, |
| @@ -620,6 +623,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait) | |||
| 620 | struct btrfs_root *root = btrfs_sb(sb); | 623 | struct btrfs_root *root = btrfs_sb(sb); |
| 621 | int ret; | 624 | int ret; |
| 622 | 625 | ||
| 626 | trace_btrfs_sync_fs(wait); | ||
| 627 | |||
| 623 | if (!wait) { | 628 | if (!wait) { |
| 624 | filemap_flush(root->fs_info->btree_inode->i_mapping); | 629 | filemap_flush(root->fs_info->btree_inode->i_mapping); |
| 625 | return 0; | 630 | return 0; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 3d73c8d93bbb..ce48eb59d615 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -57,7 +57,8 @@ static noinline int join_transaction(struct btrfs_root *root) | |||
| 57 | if (!cur_trans) { | 57 | if (!cur_trans) { |
| 58 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, | 58 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, |
| 59 | GFP_NOFS); | 59 | GFP_NOFS); |
| 60 | BUG_ON(!cur_trans); | 60 | if (!cur_trans) |
| 61 | return -ENOMEM; | ||
| 61 | root->fs_info->generation++; | 62 | root->fs_info->generation++; |
| 62 | cur_trans->num_writers = 1; | 63 | cur_trans->num_writers = 1; |
| 63 | cur_trans->num_joined = 0; | 64 | cur_trans->num_joined = 0; |
| @@ -195,7 +196,11 @@ again: | |||
| 195 | wait_current_trans(root); | 196 | wait_current_trans(root); |
| 196 | 197 | ||
| 197 | ret = join_transaction(root); | 198 | ret = join_transaction(root); |
| 198 | BUG_ON(ret); | 199 | if (ret < 0) { |
| 200 | if (type != TRANS_JOIN_NOLOCK) | ||
| 201 | mutex_unlock(&root->fs_info->trans_mutex); | ||
| 202 | return ERR_PTR(ret); | ||
| 203 | } | ||
| 199 | 204 | ||
| 200 | cur_trans = root->fs_info->running_transaction; | 205 | cur_trans = root->fs_info->running_transaction; |
| 201 | cur_trans->use_count++; | 206 | cur_trans->use_count++; |
| @@ -1156,7 +1161,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
| 1156 | struct btrfs_transaction *cur_trans; | 1161 | struct btrfs_transaction *cur_trans; |
| 1157 | 1162 | ||
| 1158 | ac = kmalloc(sizeof(*ac), GFP_NOFS); | 1163 | ac = kmalloc(sizeof(*ac), GFP_NOFS); |
| 1159 | BUG_ON(!ac); | 1164 | if (!ac) |
| 1165 | return -ENOMEM; | ||
| 1160 | 1166 | ||
| 1161 | INIT_DELAYED_WORK(&ac->work, do_async_commit); | 1167 | INIT_DELAYED_WORK(&ac->work, do_async_commit); |
| 1162 | ac->root = root; | 1168 | ac->root = root; |
| @@ -1389,6 +1395,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
| 1389 | put_transaction(cur_trans); | 1395 | put_transaction(cur_trans); |
| 1390 | put_transaction(cur_trans); | 1396 | put_transaction(cur_trans); |
| 1391 | 1397 | ||
| 1398 | trace_btrfs_transaction_commit(root); | ||
| 1399 | |||
| 1392 | mutex_unlock(&root->fs_info->trans_mutex); | 1400 | mutex_unlock(&root->fs_info->trans_mutex); |
| 1393 | 1401 | ||
| 1394 | if (current->journal_info == trans) | 1402 | if (current->journal_info == trans) |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a4bbb854dfd2..c50271ad3157 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -799,12 +799,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
| 799 | struct inode *dir; | 799 | struct inode *dir; |
| 800 | int ret; | 800 | int ret; |
| 801 | struct btrfs_inode_ref *ref; | 801 | struct btrfs_inode_ref *ref; |
| 802 | struct btrfs_dir_item *di; | ||
| 803 | struct inode *inode; | 802 | struct inode *inode; |
| 804 | char *name; | 803 | char *name; |
| 805 | int namelen; | 804 | int namelen; |
| 806 | unsigned long ref_ptr; | 805 | unsigned long ref_ptr; |
| 807 | unsigned long ref_end; | 806 | unsigned long ref_end; |
| 807 | int search_done = 0; | ||
| 808 | 808 | ||
| 809 | /* | 809 | /* |
| 810 | * it is possible that we didn't log all the parent directories | 810 | * it is possible that we didn't log all the parent directories |
| @@ -845,7 +845,10 @@ again: | |||
| 845 | * existing back reference, and we don't want to create | 845 | * existing back reference, and we don't want to create |
| 846 | * dangling pointers in the directory. | 846 | * dangling pointers in the directory. |
| 847 | */ | 847 | */ |
| 848 | conflict_again: | 848 | |
| 849 | if (search_done) | ||
| 850 | goto insert; | ||
| 851 | |||
| 849 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | 852 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); |
| 850 | if (ret == 0) { | 853 | if (ret == 0) { |
| 851 | char *victim_name; | 854 | char *victim_name; |
| @@ -886,37 +889,21 @@ conflict_again: | |||
| 886 | ret = btrfs_unlink_inode(trans, root, dir, | 889 | ret = btrfs_unlink_inode(trans, root, dir, |
| 887 | inode, victim_name, | 890 | inode, victim_name, |
| 888 | victim_name_len); | 891 | victim_name_len); |
| 889 | kfree(victim_name); | ||
| 890 | btrfs_release_path(root, path); | ||
| 891 | goto conflict_again; | ||
| 892 | } | 892 | } |
| 893 | kfree(victim_name); | 893 | kfree(victim_name); |
| 894 | ptr = (unsigned long)(victim_ref + 1) + victim_name_len; | 894 | ptr = (unsigned long)(victim_ref + 1) + victim_name_len; |
| 895 | } | 895 | } |
| 896 | BUG_ON(ret); | 896 | BUG_ON(ret); |
| 897 | } | ||
| 898 | btrfs_release_path(root, path); | ||
| 899 | |||
| 900 | /* look for a conflicting sequence number */ | ||
| 901 | di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino, | ||
| 902 | btrfs_inode_ref_index(eb, ref), | ||
| 903 | name, namelen, 0); | ||
| 904 | if (di && !IS_ERR(di)) { | ||
| 905 | ret = drop_one_dir_item(trans, root, path, dir, di); | ||
| 906 | BUG_ON(ret); | ||
| 907 | } | ||
| 908 | btrfs_release_path(root, path); | ||
| 909 | 897 | ||
| 910 | 898 | /* | |
| 911 | /* look for a conflicting name */ | 899 | * NOTE: we have searched root tree and checked the |
| 912 | di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino, | 900 | * coresponding ref, it does not need to check again. |
| 913 | name, namelen, 0); | 901 | */ |
| 914 | if (di && !IS_ERR(di)) { | 902 | search_done = 1; |
| 915 | ret = drop_one_dir_item(trans, root, path, dir, di); | ||
| 916 | BUG_ON(ret); | ||
| 917 | } | 903 | } |
| 918 | btrfs_release_path(root, path); | 904 | btrfs_release_path(root, path); |
| 919 | 905 | ||
| 906 | insert: | ||
| 920 | /* insert our name */ | 907 | /* insert our name */ |
| 921 | ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, | 908 | ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, |
| 922 | btrfs_inode_ref_index(eb, ref)); | 909 | btrfs_inode_ref_index(eb, ref)); |
| @@ -1286,6 +1273,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, | |||
| 1286 | ptr_end = ptr + item_size; | 1273 | ptr_end = ptr + item_size; |
| 1287 | while (ptr < ptr_end) { | 1274 | while (ptr < ptr_end) { |
| 1288 | di = (struct btrfs_dir_item *)ptr; | 1275 | di = (struct btrfs_dir_item *)ptr; |
| 1276 | if (verify_dir_item(root, eb, di)) | ||
| 1277 | return -EIO; | ||
| 1289 | name_len = btrfs_dir_name_len(eb, di); | 1278 | name_len = btrfs_dir_name_len(eb, di); |
| 1290 | ret = replay_one_name(trans, root, path, eb, di, key); | 1279 | ret = replay_one_name(trans, root, path, eb, di, key); |
| 1291 | BUG_ON(ret); | 1280 | BUG_ON(ret); |
| @@ -1412,6 +1401,11 @@ again: | |||
| 1412 | ptr_end = ptr + item_size; | 1401 | ptr_end = ptr + item_size; |
| 1413 | while (ptr < ptr_end) { | 1402 | while (ptr < ptr_end) { |
| 1414 | di = (struct btrfs_dir_item *)ptr; | 1403 | di = (struct btrfs_dir_item *)ptr; |
| 1404 | if (verify_dir_item(root, eb, di)) { | ||
| 1405 | ret = -EIO; | ||
| 1406 | goto out; | ||
| 1407 | } | ||
| 1408 | |||
| 1415 | name_len = btrfs_dir_name_len(eb, di); | 1409 | name_len = btrfs_dir_name_len(eb, di); |
| 1416 | name = kmalloc(name_len, GFP_NOFS); | 1410 | name = kmalloc(name_len, GFP_NOFS); |
| 1417 | if (!name) { | 1411 | if (!name) { |
| @@ -1821,7 +1815,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, | |||
| 1821 | int orig_level; | 1815 | int orig_level; |
| 1822 | 1816 | ||
| 1823 | path = btrfs_alloc_path(); | 1817 | path = btrfs_alloc_path(); |
| 1824 | BUG_ON(!path); | 1818 | if (!path) |
| 1819 | return -ENOMEM; | ||
| 1825 | 1820 | ||
| 1826 | level = btrfs_header_level(log->node); | 1821 | level = btrfs_header_level(log->node); |
| 1827 | orig_level = level; | 1822 | orig_level = level; |
| @@ -3107,9 +3102,11 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
| 3107 | .stage = 0, | 3102 | .stage = 0, |
| 3108 | }; | 3103 | }; |
| 3109 | 3104 | ||
| 3110 | fs_info->log_root_recovering = 1; | ||
| 3111 | path = btrfs_alloc_path(); | 3105 | path = btrfs_alloc_path(); |
| 3112 | BUG_ON(!path); | 3106 | if (!path) |
| 3107 | return -ENOMEM; | ||
| 3108 | |||
| 3109 | fs_info->log_root_recovering = 1; | ||
| 3113 | 3110 | ||
| 3114 | trans = btrfs_start_transaction(fs_info->tree_root, 0); | 3111 | trans = btrfs_start_transaction(fs_info->tree_root, 0); |
| 3115 | BUG_ON(IS_ERR(trans)); | 3112 | BUG_ON(IS_ERR(trans)); |
| @@ -3117,7 +3114,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
| 3117 | wc.trans = trans; | 3114 | wc.trans = trans; |
| 3118 | wc.pin = 1; | 3115 | wc.pin = 1; |
| 3119 | 3116 | ||
| 3120 | walk_log_tree(trans, log_root_tree, &wc); | 3117 | ret = walk_log_tree(trans, log_root_tree, &wc); |
| 3118 | BUG_ON(ret); | ||
| 3121 | 3119 | ||
| 3122 | again: | 3120 | again: |
| 3123 | key.objectid = BTRFS_TREE_LOG_OBJECTID; | 3121 | key.objectid = BTRFS_TREE_LOG_OBJECTID; |
| @@ -3141,8 +3139,7 @@ again: | |||
| 3141 | 3139 | ||
| 3142 | log = btrfs_read_fs_root_no_radix(log_root_tree, | 3140 | log = btrfs_read_fs_root_no_radix(log_root_tree, |
| 3143 | &found_key); | 3141 | &found_key); |
| 3144 | BUG_ON(!log); | 3142 | BUG_ON(IS_ERR(log)); |
| 3145 | |||
| 3146 | 3143 | ||
| 3147 | tmp_key.objectid = found_key.offset; | 3144 | tmp_key.objectid = found_key.offset; |
| 3148 | tmp_key.type = BTRFS_ROOT_ITEM_KEY; | 3145 | tmp_key.type = BTRFS_ROOT_ITEM_KEY; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9d554e8e6583..309a57b9fc85 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -33,17 +33,6 @@ | |||
| 33 | #include "volumes.h" | 33 | #include "volumes.h" |
| 34 | #include "async-thread.h" | 34 | #include "async-thread.h" |
| 35 | 35 | ||
| 36 | struct map_lookup { | ||
| 37 | u64 type; | ||
| 38 | int io_align; | ||
| 39 | int io_width; | ||
| 40 | int stripe_len; | ||
| 41 | int sector_size; | ||
| 42 | int num_stripes; | ||
| 43 | int sub_stripes; | ||
| 44 | struct btrfs_bio_stripe stripes[]; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int init_first_rw_device(struct btrfs_trans_handle *trans, | 36 | static int init_first_rw_device(struct btrfs_trans_handle *trans, |
| 48 | struct btrfs_root *root, | 37 | struct btrfs_root *root, |
| 49 | struct btrfs_device *device); | 38 | struct btrfs_device *device); |
| @@ -1879,6 +1868,8 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, | |||
| 1879 | 1868 | ||
| 1880 | BUG_ON(ret); | 1869 | BUG_ON(ret); |
| 1881 | 1870 | ||
| 1871 | trace_btrfs_chunk_free(root, map, chunk_offset, em->len); | ||
| 1872 | |||
| 1882 | if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { | 1873 | if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { |
| 1883 | ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset); | 1874 | ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset); |
| 1884 | BUG_ON(ret); | 1875 | BUG_ON(ret); |
| @@ -2606,6 +2597,8 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
| 2606 | *num_bytes = chunk_bytes_by_type(type, calc_size, | 2597 | *num_bytes = chunk_bytes_by_type(type, calc_size, |
| 2607 | map->num_stripes, sub_stripes); | 2598 | map->num_stripes, sub_stripes); |
| 2608 | 2599 | ||
| 2600 | trace_btrfs_chunk_alloc(info->chunk_root, map, start, *num_bytes); | ||
| 2601 | |||
| 2609 | em = alloc_extent_map(GFP_NOFS); | 2602 | em = alloc_extent_map(GFP_NOFS); |
| 2610 | if (!em) { | 2603 | if (!em) { |
| 2611 | ret = -ENOMEM; | 2604 | ret = -ENOMEM; |
| @@ -2714,6 +2707,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, | |||
| 2714 | item_size); | 2707 | item_size); |
| 2715 | BUG_ON(ret); | 2708 | BUG_ON(ret); |
| 2716 | } | 2709 | } |
| 2710 | |||
| 2717 | kfree(chunk); | 2711 | kfree(chunk); |
| 2718 | return 0; | 2712 | return 0; |
| 2719 | } | 2713 | } |
| @@ -2918,7 +2912,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
| 2918 | struct extent_map_tree *em_tree = &map_tree->map_tree; | 2912 | struct extent_map_tree *em_tree = &map_tree->map_tree; |
| 2919 | u64 offset; | 2913 | u64 offset; |
| 2920 | u64 stripe_offset; | 2914 | u64 stripe_offset; |
| 2915 | u64 stripe_end_offset; | ||
| 2921 | u64 stripe_nr; | 2916 | u64 stripe_nr; |
| 2917 | u64 stripe_nr_orig; | ||
| 2918 | u64 stripe_nr_end; | ||
| 2922 | int stripes_allocated = 8; | 2919 | int stripes_allocated = 8; |
| 2923 | int stripes_required = 1; | 2920 | int stripes_required = 1; |
| 2924 | int stripe_index; | 2921 | int stripe_index; |
| @@ -2927,7 +2924,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
| 2927 | int max_errors = 0; | 2924 | int max_errors = 0; |
| 2928 | struct btrfs_multi_bio *multi = NULL; | 2925 | struct btrfs_multi_bio *multi = NULL; |
| 2929 | 2926 | ||
| 2930 | if (multi_ret && !(rw & REQ_WRITE)) | 2927 | if (multi_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) |
| 2931 | stripes_allocated = 1; | 2928 | stripes_allocated = 1; |
| 2932 | again: | 2929 | again: |
| 2933 | if (multi_ret) { | 2930 | if (multi_ret) { |
| @@ -2968,7 +2965,15 @@ again: | |||
| 2968 | max_errors = 1; | 2965 | max_errors = 1; |
| 2969 | } | 2966 | } |
| 2970 | } | 2967 | } |
| 2971 | if (multi_ret && (rw & REQ_WRITE) && | 2968 | if (rw & REQ_DISCARD) { |
| 2969 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | | ||
| 2970 | BTRFS_BLOCK_GROUP_RAID1 | | ||
| 2971 | BTRFS_BLOCK_GROUP_DUP | | ||
| 2972 | BTRFS_BLOCK_GROUP_RAID10)) { | ||
| 2973 | stripes_required = map->num_stripes; | ||
| 2974 | } | ||
| 2975 | } | ||
| 2976 | if (multi_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && | ||
| 2972 | stripes_allocated < stripes_required) { | 2977 | stripes_allocated < stripes_required) { |
| 2973 | stripes_allocated = map->num_stripes; | 2978 | stripes_allocated = map->num_stripes; |
| 2974 | free_extent_map(em); | 2979 | free_extent_map(em); |
| @@ -2988,12 +2993,15 @@ again: | |||
| 2988 | /* stripe_offset is the offset of this block in its stripe*/ | 2993 | /* stripe_offset is the offset of this block in its stripe*/ |
| 2989 | stripe_offset = offset - stripe_offset; | 2994 | stripe_offset = offset - stripe_offset; |
| 2990 | 2995 | ||
| 2991 | if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | | 2996 | if (rw & REQ_DISCARD) |
| 2992 | BTRFS_BLOCK_GROUP_RAID10 | | 2997 | *length = min_t(u64, em->len - offset, *length); |
| 2993 | BTRFS_BLOCK_GROUP_DUP)) { | 2998 | else if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | |
| 2999 | BTRFS_BLOCK_GROUP_RAID1 | | ||
| 3000 | BTRFS_BLOCK_GROUP_RAID10 | | ||
| 3001 | BTRFS_BLOCK_GROUP_DUP)) { | ||
| 2994 | /* we limit the length of each bio to what fits in a stripe */ | 3002 | /* we limit the length of each bio to what fits in a stripe */ |
| 2995 | *length = min_t(u64, em->len - offset, | 3003 | *length = min_t(u64, em->len - offset, |
| 2996 | map->stripe_len - stripe_offset); | 3004 | map->stripe_len - stripe_offset); |
| 2997 | } else { | 3005 | } else { |
| 2998 | *length = em->len - offset; | 3006 | *length = em->len - offset; |
| 2999 | } | 3007 | } |
| @@ -3003,8 +3011,19 @@ again: | |||
| 3003 | 3011 | ||
| 3004 | num_stripes = 1; | 3012 | num_stripes = 1; |
| 3005 | stripe_index = 0; | 3013 | stripe_index = 0; |
| 3006 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | 3014 | stripe_nr_orig = stripe_nr; |
| 3007 | if (rw & REQ_WRITE) | 3015 | stripe_nr_end = (offset + *length + map->stripe_len - 1) & |
| 3016 | (~(map->stripe_len - 1)); | ||
| 3017 | do_div(stripe_nr_end, map->stripe_len); | ||
| 3018 | stripe_end_offset = stripe_nr_end * map->stripe_len - | ||
| 3019 | (offset + *length); | ||
| 3020 | if (map->type & BTRFS_BLOCK_GROUP_RAID0) { | ||
| 3021 | if (rw & REQ_DISCARD) | ||
| 3022 | num_stripes = min_t(u64, map->num_stripes, | ||
| 3023 | stripe_nr_end - stripe_nr_orig); | ||
| 3024 | stripe_index = do_div(stripe_nr, map->num_stripes); | ||
| 3025 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | ||
| 3026 | if (rw & (REQ_WRITE | REQ_DISCARD)) | ||
| 3008 | num_stripes = map->num_stripes; | 3027 | num_stripes = map->num_stripes; |
| 3009 | else if (mirror_num) | 3028 | else if (mirror_num) |
| 3010 | stripe_index = mirror_num - 1; | 3029 | stripe_index = mirror_num - 1; |
| @@ -3015,7 +3034,7 @@ again: | |||
| 3015 | } | 3034 | } |
| 3016 | 3035 | ||
| 3017 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { | 3036 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { |
| 3018 | if (rw & REQ_WRITE) | 3037 | if (rw & (REQ_WRITE | REQ_DISCARD)) |
| 3019 | num_stripes = map->num_stripes; | 3038 | num_stripes = map->num_stripes; |
| 3020 | else if (mirror_num) | 3039 | else if (mirror_num) |
| 3021 | stripe_index = mirror_num - 1; | 3040 | stripe_index = mirror_num - 1; |
| @@ -3028,6 +3047,10 @@ again: | |||
| 3028 | 3047 | ||
| 3029 | if (rw & REQ_WRITE) | 3048 | if (rw & REQ_WRITE) |
| 3030 | num_stripes = map->sub_stripes; | 3049 | num_stripes = map->sub_stripes; |
| 3050 | else if (rw & REQ_DISCARD) | ||
| 3051 | num_stripes = min_t(u64, map->sub_stripes * | ||
| 3052 | (stripe_nr_end - stripe_nr_orig), | ||
| 3053 | map->num_stripes); | ||
| 3031 | else if (mirror_num) | 3054 | else if (mirror_num) |
| 3032 | stripe_index += mirror_num - 1; | 3055 | stripe_index += mirror_num - 1; |
| 3033 | else { | 3056 | else { |
| @@ -3045,12 +3068,101 @@ again: | |||
| 3045 | } | 3068 | } |
| 3046 | BUG_ON(stripe_index >= map->num_stripes); | 3069 | BUG_ON(stripe_index >= map->num_stripes); |
| 3047 | 3070 | ||
| 3048 | for (i = 0; i < num_stripes; i++) { | 3071 | if (rw & REQ_DISCARD) { |
| 3049 | multi->stripes[i].physical = | 3072 | for (i = 0; i < num_stripes; i++) { |
| 3050 | map->stripes[stripe_index].physical + | 3073 | multi->stripes[i].physical = |
| 3051 | stripe_offset + stripe_nr * map->stripe_len; | 3074 | map->stripes[stripe_index].physical + |
| 3052 | multi->stripes[i].dev = map->stripes[stripe_index].dev; | 3075 | stripe_offset + stripe_nr * map->stripe_len; |
| 3053 | stripe_index++; | 3076 | multi->stripes[i].dev = map->stripes[stripe_index].dev; |
| 3077 | |||
| 3078 | if (map->type & BTRFS_BLOCK_GROUP_RAID0) { | ||
| 3079 | u64 stripes; | ||
| 3080 | u32 last_stripe = 0; | ||
| 3081 | int j; | ||
| 3082 | |||
| 3083 | div_u64_rem(stripe_nr_end - 1, | ||
| 3084 | map->num_stripes, | ||
| 3085 | &last_stripe); | ||
| 3086 | |||
| 3087 | for (j = 0; j < map->num_stripes; j++) { | ||
| 3088 | u32 test; | ||
| 3089 | |||
| 3090 | div_u64_rem(stripe_nr_end - 1 - j, | ||
| 3091 | map->num_stripes, &test); | ||
| 3092 | if (test == stripe_index) | ||
| 3093 | break; | ||
| 3094 | } | ||
| 3095 | stripes = stripe_nr_end - 1 - j; | ||
| 3096 | do_div(stripes, map->num_stripes); | ||
| 3097 | multi->stripes[i].length = map->stripe_len * | ||
| 3098 | (stripes - stripe_nr + 1); | ||
| 3099 | |||
| 3100 | if (i == 0) { | ||
| 3101 | multi->stripes[i].length -= | ||
| 3102 | stripe_offset; | ||
| 3103 | stripe_offset = 0; | ||
| 3104 | } | ||
| 3105 | if (stripe_index == last_stripe) | ||
| 3106 | multi->stripes[i].length -= | ||
| 3107 | stripe_end_offset; | ||
| 3108 | } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { | ||
| 3109 | u64 stripes; | ||
| 3110 | int j; | ||
| 3111 | int factor = map->num_stripes / | ||
| 3112 | map->sub_stripes; | ||
| 3113 | u32 last_stripe = 0; | ||
| 3114 | |||
| 3115 | div_u64_rem(stripe_nr_end - 1, | ||
| 3116 | factor, &last_stripe); | ||
| 3117 | last_stripe *= map->sub_stripes; | ||
| 3118 | |||
| 3119 | for (j = 0; j < factor; j++) { | ||
| 3120 | u32 test; | ||
| 3121 | |||
| 3122 | div_u64_rem(stripe_nr_end - 1 - j, | ||
| 3123 | factor, &test); | ||
| 3124 | |||
| 3125 | if (test == | ||
| 3126 | stripe_index / map->sub_stripes) | ||
| 3127 | break; | ||
| 3128 | } | ||
| 3129 | stripes = stripe_nr_end - 1 - j; | ||
| 3130 | do_div(stripes, factor); | ||
| 3131 | multi->stripes[i].length = map->stripe_len * | ||
| 3132 | (stripes - stripe_nr + 1); | ||
| 3133 | |||
| 3134 | if (i < map->sub_stripes) { | ||
| 3135 | multi->stripes[i].length -= | ||
| 3136 | stripe_offset; | ||
| 3137 | if (i == map->sub_stripes - 1) | ||
| 3138 | stripe_offset = 0; | ||
| 3139 | } | ||
| 3140 | if (stripe_index >= last_stripe && | ||
| 3141 | stripe_index <= (last_stripe + | ||
| 3142 | map->sub_stripes - 1)) { | ||
| 3143 | multi->stripes[i].length -= | ||
| 3144 | stripe_end_offset; | ||
| 3145 | } | ||
| 3146 | } else | ||
| 3147 | multi->stripes[i].length = *length; | ||
| 3148 | |||
| 3149 | stripe_index++; | ||
| 3150 | if (stripe_index == map->num_stripes) { | ||
| 3151 | /* This could only happen for RAID0/10 */ | ||
| 3152 | stripe_index = 0; | ||
| 3153 | stripe_nr++; | ||
| 3154 | } | ||
| 3155 | } | ||
| 3156 | } else { | ||
| 3157 | for (i = 0; i < num_stripes; i++) { | ||
| 3158 | multi->stripes[i].physical = | ||
| 3159 | map->stripes[stripe_index].physical + | ||
| 3160 | stripe_offset + | ||
| 3161 | stripe_nr * map->stripe_len; | ||
| 3162 | multi->stripes[i].dev = | ||
| 3163 | map->stripes[stripe_index].dev; | ||
| 3164 | stripe_index++; | ||
| 3165 | } | ||
| 3054 | } | 3166 | } |
| 3055 | if (multi_ret) { | 3167 | if (multi_ret) { |
| 3056 | *multi_ret = multi; | 3168 | *multi_ret = multi; |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 7fb59d45fe8c..cc2eadaf7a27 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
| @@ -126,6 +126,7 @@ struct btrfs_fs_devices { | |||
| 126 | struct btrfs_bio_stripe { | 126 | struct btrfs_bio_stripe { |
| 127 | struct btrfs_device *dev; | 127 | struct btrfs_device *dev; |
| 128 | u64 physical; | 128 | u64 physical; |
| 129 | u64 length; /* only used for discard mappings */ | ||
| 129 | }; | 130 | }; |
| 130 | 131 | ||
| 131 | struct btrfs_multi_bio { | 132 | struct btrfs_multi_bio { |
| @@ -145,6 +146,17 @@ struct btrfs_device_info { | |||
| 145 | u64 max_avail; | 146 | u64 max_avail; |
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| 149 | struct map_lookup { | ||
| 150 | u64 type; | ||
| 151 | int io_align; | ||
| 152 | int io_width; | ||
| 153 | int stripe_len; | ||
| 154 | int sector_size; | ||
| 155 | int num_stripes; | ||
| 156 | int sub_stripes; | ||
| 157 | struct btrfs_bio_stripe stripes[]; | ||
| 158 | }; | ||
| 159 | |||
| 148 | /* Used to sort the devices by max_avail(descending sort) */ | 160 | /* Used to sort the devices by max_avail(descending sort) */ |
| 149 | int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2); | 161 | int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2); |
| 150 | 162 | ||
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index d779cefcfd7d..a5303b871b13 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c | |||
| @@ -242,6 +242,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
| 242 | break; | 242 | break; |
| 243 | 243 | ||
| 244 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); | 244 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); |
| 245 | if (verify_dir_item(root, leaf, di)) | ||
| 246 | continue; | ||
| 245 | 247 | ||
| 246 | name_len = btrfs_dir_name_len(leaf, di); | 248 | name_len = btrfs_dir_name_len(leaf, di); |
| 247 | total_size += name_len + 1; | 249 | total_size += name_len + 1; |
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index bfd8b680e648..d2a70a4561f9 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
| @@ -266,7 +266,6 @@ void ecryptfs_destroy_mount_crypt_stat( | |||
| 266 | &mount_crypt_stat->global_auth_tok_list, | 266 | &mount_crypt_stat->global_auth_tok_list, |
| 267 | mount_crypt_stat_list) { | 267 | mount_crypt_stat_list) { |
| 268 | list_del(&auth_tok->mount_crypt_stat_list); | 268 | list_del(&auth_tok->mount_crypt_stat_list); |
| 269 | mount_crypt_stat->num_global_auth_toks--; | ||
| 270 | if (auth_tok->global_auth_tok_key | 269 | if (auth_tok->global_auth_tok_key |
| 271 | && !(auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID)) | 270 | && !(auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID)) |
| 272 | key_put(auth_tok->global_auth_tok_key); | 271 | key_put(auth_tok->global_auth_tok_key); |
| @@ -1389,6 +1388,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) | |||
| 1389 | rc = -ENOMEM; | 1388 | rc = -ENOMEM; |
| 1390 | goto out; | 1389 | goto out; |
| 1391 | } | 1390 | } |
| 1391 | /* Zeroed page ensures the in-header unencrypted i_size is set to 0 */ | ||
| 1392 | rc = ecryptfs_write_headers_virt(virt, virt_len, &size, crypt_stat, | 1392 | rc = ecryptfs_write_headers_virt(virt, virt_len, &size, crypt_stat, |
| 1393 | ecryptfs_dentry); | 1393 | ecryptfs_dentry); |
| 1394 | if (unlikely(rc)) { | 1394 | if (unlikely(rc)) { |
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index e00753496e3e..bd3cafd0949d 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h | |||
| @@ -233,7 +233,7 @@ ecryptfs_get_key_payload_data(struct key *key) | |||
| 233 | 233 | ||
| 234 | struct ecryptfs_key_sig { | 234 | struct ecryptfs_key_sig { |
| 235 | struct list_head crypt_stat_list; | 235 | struct list_head crypt_stat_list; |
| 236 | char keysig[ECRYPTFS_SIG_SIZE_HEX]; | 236 | char keysig[ECRYPTFS_SIG_SIZE_HEX + 1]; |
| 237 | }; | 237 | }; |
| 238 | 238 | ||
| 239 | struct ecryptfs_filename { | 239 | struct ecryptfs_filename { |
| @@ -257,19 +257,18 @@ struct ecryptfs_filename { | |||
| 257 | struct ecryptfs_crypt_stat { | 257 | struct ecryptfs_crypt_stat { |
| 258 | #define ECRYPTFS_STRUCT_INITIALIZED 0x00000001 | 258 | #define ECRYPTFS_STRUCT_INITIALIZED 0x00000001 |
| 259 | #define ECRYPTFS_POLICY_APPLIED 0x00000002 | 259 | #define ECRYPTFS_POLICY_APPLIED 0x00000002 |
| 260 | #define ECRYPTFS_NEW_FILE 0x00000004 | 260 | #define ECRYPTFS_ENCRYPTED 0x00000004 |
| 261 | #define ECRYPTFS_ENCRYPTED 0x00000008 | 261 | #define ECRYPTFS_SECURITY_WARNING 0x00000008 |
| 262 | #define ECRYPTFS_SECURITY_WARNING 0x00000010 | 262 | #define ECRYPTFS_ENABLE_HMAC 0x00000010 |
| 263 | #define ECRYPTFS_ENABLE_HMAC 0x00000020 | 263 | #define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000020 |
| 264 | #define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040 | 264 | #define ECRYPTFS_KEY_VALID 0x00000040 |
| 265 | #define ECRYPTFS_KEY_VALID 0x00000080 | 265 | #define ECRYPTFS_METADATA_IN_XATTR 0x00000080 |
| 266 | #define ECRYPTFS_METADATA_IN_XATTR 0x00000100 | 266 | #define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000100 |
| 267 | #define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200 | 267 | #define ECRYPTFS_KEY_SET 0x00000200 |
| 268 | #define ECRYPTFS_KEY_SET 0x00000400 | 268 | #define ECRYPTFS_ENCRYPT_FILENAMES 0x00000400 |
| 269 | #define ECRYPTFS_ENCRYPT_FILENAMES 0x00000800 | 269 | #define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00000800 |
| 270 | #define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00001000 | 270 | #define ECRYPTFS_ENCFN_USE_FEK 0x00001000 |
| 271 | #define ECRYPTFS_ENCFN_USE_FEK 0x00002000 | 271 | #define ECRYPTFS_UNLINK_SIGS 0x00002000 |
| 272 | #define ECRYPTFS_UNLINK_SIGS 0x00004000 | ||
| 273 | u32 flags; | 272 | u32 flags; |
| 274 | unsigned int file_version; | 273 | unsigned int file_version; |
| 275 | size_t iv_bytes; | 274 | size_t iv_bytes; |
| @@ -297,7 +296,6 @@ struct ecryptfs_inode_info { | |||
| 297 | struct inode vfs_inode; | 296 | struct inode vfs_inode; |
| 298 | struct inode *wii_inode; | 297 | struct inode *wii_inode; |
| 299 | struct file *lower_file; | 298 | struct file *lower_file; |
| 300 | struct mutex lower_file_mutex; | ||
| 301 | struct ecryptfs_crypt_stat crypt_stat; | 299 | struct ecryptfs_crypt_stat crypt_stat; |
| 302 | }; | 300 | }; |
| 303 | 301 | ||
| @@ -333,7 +331,6 @@ struct ecryptfs_global_auth_tok { | |||
| 333 | u32 flags; | 331 | u32 flags; |
| 334 | struct list_head mount_crypt_stat_list; | 332 | struct list_head mount_crypt_stat_list; |
| 335 | struct key *global_auth_tok_key; | 333 | struct key *global_auth_tok_key; |
| 336 | struct ecryptfs_auth_tok *global_auth_tok; | ||
| 337 | unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; | 334 | unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; |
| 338 | }; | 335 | }; |
| 339 | 336 | ||
| @@ -380,7 +377,6 @@ struct ecryptfs_mount_crypt_stat { | |||
| 380 | u32 flags; | 377 | u32 flags; |
| 381 | struct list_head global_auth_tok_list; | 378 | struct list_head global_auth_tok_list; |
| 382 | struct mutex global_auth_tok_list_mutex; | 379 | struct mutex global_auth_tok_list_mutex; |
| 383 | size_t num_global_auth_toks; | ||
| 384 | size_t global_default_cipher_key_size; | 380 | size_t global_default_cipher_key_size; |
| 385 | size_t global_default_fn_cipher_key_bytes; | 381 | size_t global_default_fn_cipher_key_bytes; |
| 386 | unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE | 382 | unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE |
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 7d1050e254f9..cedc913d11ba 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
| @@ -273,7 +273,14 @@ static int ecryptfs_release(struct inode *inode, struct file *file) | |||
| 273 | static int | 273 | static int |
| 274 | ecryptfs_fsync(struct file *file, int datasync) | 274 | ecryptfs_fsync(struct file *file, int datasync) |
| 275 | { | 275 | { |
| 276 | return vfs_fsync(ecryptfs_file_to_lower(file), datasync); | 276 | int rc = 0; |
| 277 | |||
| 278 | rc = generic_file_fsync(file, datasync); | ||
| 279 | if (rc) | ||
| 280 | goto out; | ||
| 281 | rc = vfs_fsync(ecryptfs_file_to_lower(file), datasync); | ||
| 282 | out: | ||
| 283 | return rc; | ||
| 277 | } | 284 | } |
| 278 | 285 | ||
| 279 | static int ecryptfs_fasync(int fd, struct file *file, int flag) | 286 | static int ecryptfs_fasync(int fd, struct file *file, int flag) |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index b592938a84bc..f99051b7adab 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -143,26 +143,6 @@ out: | |||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
| 146 | * grow_file | ||
| 147 | * @ecryptfs_dentry: the eCryptfs dentry | ||
| 148 | * | ||
| 149 | * This is the code which will grow the file to its correct size. | ||
| 150 | */ | ||
| 151 | static int grow_file(struct dentry *ecryptfs_dentry) | ||
| 152 | { | ||
| 153 | struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode; | ||
| 154 | char zero_virt[] = { 0x00 }; | ||
| 155 | int rc = 0; | ||
| 156 | |||
| 157 | rc = ecryptfs_write(ecryptfs_inode, zero_virt, 0, 1); | ||
| 158 | i_size_write(ecryptfs_inode, 0); | ||
| 159 | rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); | ||
| 160 | ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat.flags |= | ||
| 161 | ECRYPTFS_NEW_FILE; | ||
| 162 | return rc; | ||
| 163 | } | ||
| 164 | |||
| 165 | /** | ||
| 166 | * ecryptfs_initialize_file | 146 | * ecryptfs_initialize_file |
| 167 | * | 147 | * |
| 168 | * Cause the file to be changed from a basic empty file to an ecryptfs | 148 | * Cause the file to be changed from a basic empty file to an ecryptfs |
| @@ -181,7 +161,6 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) | |||
| 181 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | 161 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); |
| 182 | goto out; | 162 | goto out; |
| 183 | } | 163 | } |
| 184 | crypt_stat->flags |= ECRYPTFS_NEW_FILE; | ||
| 185 | ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); | 164 | ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); |
| 186 | rc = ecryptfs_new_file_context(ecryptfs_dentry); | 165 | rc = ecryptfs_new_file_context(ecryptfs_dentry); |
| 187 | if (rc) { | 166 | if (rc) { |
| @@ -202,9 +181,6 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) | |||
| 202 | printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); | 181 | printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); |
| 203 | goto out; | 182 | goto out; |
| 204 | } | 183 | } |
| 205 | rc = grow_file(ecryptfs_dentry); | ||
| 206 | if (rc) | ||
| 207 | printk(KERN_ERR "Error growing file; rc = [%d]\n", rc); | ||
| 208 | out: | 184 | out: |
| 209 | return rc; | 185 | return rc; |
| 210 | } | 186 | } |
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index c1436cff6f2d..03e609c45012 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c | |||
| @@ -65,6 +65,24 @@ static int process_request_key_err(long err_code) | |||
| 65 | return rc; | 65 | return rc; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | static int process_find_global_auth_tok_for_sig_err(int err_code) | ||
| 69 | { | ||
| 70 | int rc = err_code; | ||
| 71 | |||
| 72 | switch (err_code) { | ||
| 73 | case -ENOENT: | ||
| 74 | ecryptfs_printk(KERN_WARNING, "Missing auth tok\n"); | ||
| 75 | break; | ||
| 76 | case -EINVAL: | ||
| 77 | ecryptfs_printk(KERN_WARNING, "Invalid auth tok\n"); | ||
| 78 | break; | ||
| 79 | default: | ||
| 80 | rc = process_request_key_err(err_code); | ||
| 81 | break; | ||
| 82 | } | ||
| 83 | return rc; | ||
| 84 | } | ||
| 85 | |||
| 68 | /** | 86 | /** |
| 69 | * ecryptfs_parse_packet_length | 87 | * ecryptfs_parse_packet_length |
| 70 | * @data: Pointer to memory containing length at offset | 88 | * @data: Pointer to memory containing length at offset |
| @@ -403,27 +421,120 @@ out: | |||
| 403 | return rc; | 421 | return rc; |
| 404 | } | 422 | } |
| 405 | 423 | ||
| 424 | /** | ||
| 425 | * ecryptfs_verify_version | ||
| 426 | * @version: The version number to confirm | ||
| 427 | * | ||
| 428 | * Returns zero on good version; non-zero otherwise | ||
| 429 | */ | ||
| 430 | static int ecryptfs_verify_version(u16 version) | ||
| 431 | { | ||
| 432 | int rc = 0; | ||
| 433 | unsigned char major; | ||
| 434 | unsigned char minor; | ||
| 435 | |||
| 436 | major = ((version >> 8) & 0xFF); | ||
| 437 | minor = (version & 0xFF); | ||
| 438 | if (major != ECRYPTFS_VERSION_MAJOR) { | ||
| 439 | ecryptfs_printk(KERN_ERR, "Major version number mismatch. " | ||
| 440 | "Expected [%d]; got [%d]\n", | ||
| 441 | ECRYPTFS_VERSION_MAJOR, major); | ||
| 442 | rc = -EINVAL; | ||
| 443 | goto out; | ||
| 444 | } | ||
| 445 | if (minor != ECRYPTFS_VERSION_MINOR) { | ||
| 446 | ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " | ||
| 447 | "Expected [%d]; got [%d]\n", | ||
| 448 | ECRYPTFS_VERSION_MINOR, minor); | ||
| 449 | rc = -EINVAL; | ||
| 450 | goto out; | ||
| 451 | } | ||
| 452 | out: | ||
| 453 | return rc; | ||
| 454 | } | ||
| 455 | |||
| 456 | /** | ||
| 457 | * ecryptfs_verify_auth_tok_from_key | ||
| 458 | * @auth_tok_key: key containing the authentication token | ||
| 459 | * @auth_tok: authentication token | ||
| 460 | * | ||
| 461 | * Returns zero on valid auth tok; -EINVAL otherwise | ||
| 462 | */ | ||
| 463 | static int | ||
| 464 | ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key, | ||
| 465 | struct ecryptfs_auth_tok **auth_tok) | ||
| 466 | { | ||
| 467 | int rc = 0; | ||
| 468 | |||
| 469 | (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key); | ||
| 470 | if (ecryptfs_verify_version((*auth_tok)->version)) { | ||
| 471 | printk(KERN_ERR "Data structure version mismatch. Userspace " | ||
| 472 | "tools must match eCryptfs kernel module with major " | ||
| 473 | "version [%d] and minor version [%d]\n", | ||
| 474 | ECRYPTFS_VERSION_MAJOR, ECRYPTFS_VERSION_MINOR); | ||
| 475 | rc = -EINVAL; | ||
| 476 | goto out; | ||
| 477 | } | ||
| 478 | if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD | ||
| 479 | && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { | ||
| 480 | printk(KERN_ERR "Invalid auth_tok structure " | ||
| 481 | "returned from key query\n"); | ||
| 482 | rc = -EINVAL; | ||
| 483 | goto out; | ||
| 484 | } | ||
| 485 | out: | ||
| 486 | return rc; | ||
| 487 | } | ||
| 488 | |||
| 406 | static int | 489 | static int |
| 407 | ecryptfs_find_global_auth_tok_for_sig( | 490 | ecryptfs_find_global_auth_tok_for_sig( |
| 408 | struct ecryptfs_global_auth_tok **global_auth_tok, | 491 | struct key **auth_tok_key, |
| 492 | struct ecryptfs_auth_tok **auth_tok, | ||
| 409 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig) | 493 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig) |
| 410 | { | 494 | { |
| 411 | struct ecryptfs_global_auth_tok *walker; | 495 | struct ecryptfs_global_auth_tok *walker; |
| 412 | int rc = 0; | 496 | int rc = 0; |
| 413 | 497 | ||
| 414 | (*global_auth_tok) = NULL; | 498 | (*auth_tok_key) = NULL; |
| 499 | (*auth_tok) = NULL; | ||
| 415 | mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); | 500 | mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); |
| 416 | list_for_each_entry(walker, | 501 | list_for_each_entry(walker, |
| 417 | &mount_crypt_stat->global_auth_tok_list, | 502 | &mount_crypt_stat->global_auth_tok_list, |
| 418 | mount_crypt_stat_list) { | 503 | mount_crypt_stat_list) { |
| 419 | if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX) == 0) { | 504 | if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX)) |
| 420 | rc = key_validate(walker->global_auth_tok_key); | 505 | continue; |
| 421 | if (!rc) | 506 | |
| 422 | (*global_auth_tok) = walker; | 507 | if (walker->flags & ECRYPTFS_AUTH_TOK_INVALID) { |
| 508 | rc = -EINVAL; | ||
| 423 | goto out; | 509 | goto out; |
| 424 | } | 510 | } |
| 511 | |||
| 512 | rc = key_validate(walker->global_auth_tok_key); | ||
| 513 | if (rc) { | ||
| 514 | if (rc == -EKEYEXPIRED) | ||
| 515 | goto out; | ||
| 516 | goto out_invalid_auth_tok; | ||
| 517 | } | ||
| 518 | |||
| 519 | down_write(&(walker->global_auth_tok_key->sem)); | ||
| 520 | rc = ecryptfs_verify_auth_tok_from_key( | ||
| 521 | walker->global_auth_tok_key, auth_tok); | ||
| 522 | if (rc) | ||
| 523 | goto out_invalid_auth_tok_unlock; | ||
| 524 | |||
| 525 | (*auth_tok_key) = walker->global_auth_tok_key; | ||
| 526 | key_get(*auth_tok_key); | ||
| 527 | goto out; | ||
| 425 | } | 528 | } |
| 426 | rc = -EINVAL; | 529 | rc = -ENOENT; |
| 530 | goto out; | ||
| 531 | out_invalid_auth_tok_unlock: | ||
| 532 | up_write(&(walker->global_auth_tok_key->sem)); | ||
| 533 | out_invalid_auth_tok: | ||
| 534 | printk(KERN_WARNING "Invalidating auth tok with sig = [%s]\n", sig); | ||
| 535 | walker->flags |= ECRYPTFS_AUTH_TOK_INVALID; | ||
| 536 | key_put(walker->global_auth_tok_key); | ||
| 537 | walker->global_auth_tok_key = NULL; | ||
| 427 | out: | 538 | out: |
| 428 | mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); | 539 | mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); |
| 429 | return rc; | 540 | return rc; |
| @@ -451,14 +562,11 @@ ecryptfs_find_auth_tok_for_sig( | |||
| 451 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat, | 562 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat, |
| 452 | char *sig) | 563 | char *sig) |
| 453 | { | 564 | { |
| 454 | struct ecryptfs_global_auth_tok *global_auth_tok; | ||
| 455 | int rc = 0; | 565 | int rc = 0; |
| 456 | 566 | ||
| 457 | (*auth_tok_key) = NULL; | 567 | rc = ecryptfs_find_global_auth_tok_for_sig(auth_tok_key, auth_tok, |
| 458 | (*auth_tok) = NULL; | 568 | mount_crypt_stat, sig); |
| 459 | if (ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, | 569 | if (rc == -ENOENT) { |
| 460 | mount_crypt_stat, sig)) { | ||
| 461 | |||
| 462 | /* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the | 570 | /* if the flag ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY is set in the |
| 463 | * mount_crypt_stat structure, we prevent to use auth toks that | 571 | * mount_crypt_stat structure, we prevent to use auth toks that |
| 464 | * are not inserted through the ecryptfs_add_global_auth_tok | 572 | * are not inserted through the ecryptfs_add_global_auth_tok |
| @@ -470,8 +578,7 @@ ecryptfs_find_auth_tok_for_sig( | |||
| 470 | 578 | ||
| 471 | rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok, | 579 | rc = ecryptfs_keyring_auth_tok_for_sig(auth_tok_key, auth_tok, |
| 472 | sig); | 580 | sig); |
| 473 | } else | 581 | } |
| 474 | (*auth_tok) = global_auth_tok->global_auth_tok; | ||
| 475 | return rc; | 582 | return rc; |
| 476 | } | 583 | } |
| 477 | 584 | ||
| @@ -531,6 +638,16 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, | |||
| 531 | } | 638 | } |
| 532 | s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 639 | s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 533 | (*packet_size) = 0; | 640 | (*packet_size) = 0; |
| 641 | rc = ecryptfs_find_auth_tok_for_sig( | ||
| 642 | &auth_tok_key, | ||
| 643 | &s->auth_tok, mount_crypt_stat, | ||
| 644 | mount_crypt_stat->global_default_fnek_sig); | ||
| 645 | if (rc) { | ||
| 646 | printk(KERN_ERR "%s: Error attempting to find auth tok for " | ||
| 647 | "fnek sig [%s]; rc = [%d]\n", __func__, | ||
| 648 | mount_crypt_stat->global_default_fnek_sig, rc); | ||
| 649 | goto out; | ||
| 650 | } | ||
| 534 | rc = ecryptfs_get_tfm_and_mutex_for_cipher_name( | 651 | rc = ecryptfs_get_tfm_and_mutex_for_cipher_name( |
| 535 | &s->desc.tfm, | 652 | &s->desc.tfm, |
| 536 | &s->tfm_mutex, mount_crypt_stat->global_default_fn_cipher_name); | 653 | &s->tfm_mutex, mount_crypt_stat->global_default_fn_cipher_name); |
| @@ -616,16 +733,6 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, | |||
| 616 | goto out_free_unlock; | 733 | goto out_free_unlock; |
| 617 | } | 734 | } |
| 618 | dest[s->i++] = s->cipher_code; | 735 | dest[s->i++] = s->cipher_code; |
| 619 | rc = ecryptfs_find_auth_tok_for_sig( | ||
| 620 | &auth_tok_key, | ||
| 621 | &s->auth_tok, mount_crypt_stat, | ||
| 622 | mount_crypt_stat->global_default_fnek_sig); | ||
| 623 | if (rc) { | ||
| 624 | printk(KERN_ERR "%s: Error attempting to find auth tok for " | ||
| 625 | "fnek sig [%s]; rc = [%d]\n", __func__, | ||
| 626 | mount_crypt_stat->global_default_fnek_sig, rc); | ||
| 627 | goto out_free_unlock; | ||
| 628 | } | ||
| 629 | /* TODO: Support other key modules than passphrase for | 736 | /* TODO: Support other key modules than passphrase for |
| 630 | * filename encryption */ | 737 | * filename encryption */ |
| 631 | if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) { | 738 | if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) { |
| @@ -765,8 +872,10 @@ out_free_unlock: | |||
| 765 | out_unlock: | 872 | out_unlock: |
| 766 | mutex_unlock(s->tfm_mutex); | 873 | mutex_unlock(s->tfm_mutex); |
| 767 | out: | 874 | out: |
| 768 | if (auth_tok_key) | 875 | if (auth_tok_key) { |
| 876 | up_write(&(auth_tok_key->sem)); | ||
| 769 | key_put(auth_tok_key); | 877 | key_put(auth_tok_key); |
| 878 | } | ||
| 770 | kfree(s); | 879 | kfree(s); |
| 771 | return rc; | 880 | return rc; |
| 772 | } | 881 | } |
| @@ -879,6 +988,15 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, | |||
| 879 | __func__, s->cipher_code); | 988 | __func__, s->cipher_code); |
| 880 | goto out; | 989 | goto out; |
| 881 | } | 990 | } |
| 991 | rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key, | ||
| 992 | &s->auth_tok, mount_crypt_stat, | ||
| 993 | s->fnek_sig_hex); | ||
| 994 | if (rc) { | ||
| 995 | printk(KERN_ERR "%s: Error attempting to find auth tok for " | ||
| 996 | "fnek sig [%s]; rc = [%d]\n", __func__, s->fnek_sig_hex, | ||
| 997 | rc); | ||
| 998 | goto out; | ||
| 999 | } | ||
| 882 | rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&s->desc.tfm, | 1000 | rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&s->desc.tfm, |
| 883 | &s->tfm_mutex, | 1001 | &s->tfm_mutex, |
| 884 | s->cipher_string); | 1002 | s->cipher_string); |
| @@ -925,15 +1043,6 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, | |||
| 925 | * >= ECRYPTFS_MAX_IV_BYTES. */ | 1043 | * >= ECRYPTFS_MAX_IV_BYTES. */ |
| 926 | memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES); | 1044 | memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES); |
| 927 | s->desc.info = s->iv; | 1045 | s->desc.info = s->iv; |
| 928 | rc = ecryptfs_find_auth_tok_for_sig(&auth_tok_key, | ||
| 929 | &s->auth_tok, mount_crypt_stat, | ||
| 930 | s->fnek_sig_hex); | ||
| 931 | if (rc) { | ||
| 932 | printk(KERN_ERR "%s: Error attempting to find auth tok for " | ||
| 933 | "fnek sig [%s]; rc = [%d]\n", __func__, s->fnek_sig_hex, | ||
| 934 | rc); | ||
| 935 | goto out_free_unlock; | ||
| 936 | } | ||
| 937 | /* TODO: Support other key modules than passphrase for | 1046 | /* TODO: Support other key modules than passphrase for |
| 938 | * filename encryption */ | 1047 | * filename encryption */ |
| 939 | if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) { | 1048 | if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) { |
| @@ -1002,8 +1111,10 @@ out: | |||
| 1002 | (*filename_size) = 0; | 1111 | (*filename_size) = 0; |
| 1003 | (*filename) = NULL; | 1112 | (*filename) = NULL; |
| 1004 | } | 1113 | } |
| 1005 | if (auth_tok_key) | 1114 | if (auth_tok_key) { |
| 1115 | up_write(&(auth_tok_key->sem)); | ||
| 1006 | key_put(auth_tok_key); | 1116 | key_put(auth_tok_key); |
| 1117 | } | ||
| 1007 | kfree(s); | 1118 | kfree(s); |
| 1008 | return rc; | 1119 | return rc; |
| 1009 | } | 1120 | } |
| @@ -1520,38 +1631,6 @@ out: | |||
| 1520 | return rc; | 1631 | return rc; |
| 1521 | } | 1632 | } |
| 1522 | 1633 | ||
| 1523 | /** | ||
| 1524 | * ecryptfs_verify_version | ||
| 1525 | * @version: The version number to confirm | ||
| 1526 | * | ||
| 1527 | * Returns zero on good version; non-zero otherwise | ||
| 1528 | */ | ||
| 1529 | static int ecryptfs_verify_version(u16 version) | ||
| 1530 | { | ||
| 1531 | int rc = 0; | ||
| 1532 | unsigned char major; | ||
| 1533 | unsigned char minor; | ||
| 1534 | |||
| 1535 | major = ((version >> 8) & 0xFF); | ||
| 1536 | minor = (version & 0xFF); | ||
| 1537 | if (major != ECRYPTFS_VERSION_MAJOR) { | ||
| 1538 | ecryptfs_printk(KERN_ERR, "Major version number mismatch. " | ||
| 1539 | "Expected [%d]; got [%d]\n", | ||
| 1540 | ECRYPTFS_VERSION_MAJOR, major); | ||
| 1541 | rc = -EINVAL; | ||
| 1542 | goto out; | ||
| 1543 | } | ||
| 1544 | if (minor != ECRYPTFS_VERSION_MINOR) { | ||
| 1545 | ecryptfs_printk(KERN_ERR, "Minor version number mismatch. " | ||
| 1546 | "Expected [%d]; got [%d]\n", | ||
| 1547 | ECRYPTFS_VERSION_MINOR, minor); | ||
| 1548 | rc = -EINVAL; | ||
| 1549 | goto out; | ||
| 1550 | } | ||
| 1551 | out: | ||
| 1552 | return rc; | ||
| 1553 | } | ||
| 1554 | |||
| 1555 | int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, | 1634 | int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, |
| 1556 | struct ecryptfs_auth_tok **auth_tok, | 1635 | struct ecryptfs_auth_tok **auth_tok, |
| 1557 | char *sig) | 1636 | char *sig) |
| @@ -1563,31 +1642,16 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, | |||
| 1563 | printk(KERN_ERR "Could not find key with description: [%s]\n", | 1642 | printk(KERN_ERR "Could not find key with description: [%s]\n", |
| 1564 | sig); | 1643 | sig); |
| 1565 | rc = process_request_key_err(PTR_ERR(*auth_tok_key)); | 1644 | rc = process_request_key_err(PTR_ERR(*auth_tok_key)); |
| 1645 | (*auth_tok_key) = NULL; | ||
| 1566 | goto out; | 1646 | goto out; |
| 1567 | } | 1647 | } |
| 1568 | (*auth_tok) = ecryptfs_get_key_payload_data(*auth_tok_key); | 1648 | down_write(&(*auth_tok_key)->sem); |
| 1569 | if (ecryptfs_verify_version((*auth_tok)->version)) { | 1649 | rc = ecryptfs_verify_auth_tok_from_key(*auth_tok_key, auth_tok); |
| 1570 | printk(KERN_ERR | ||
| 1571 | "Data structure version mismatch. " | ||
| 1572 | "Userspace tools must match eCryptfs " | ||
| 1573 | "kernel module with major version [%d] " | ||
| 1574 | "and minor version [%d]\n", | ||
| 1575 | ECRYPTFS_VERSION_MAJOR, | ||
| 1576 | ECRYPTFS_VERSION_MINOR); | ||
| 1577 | rc = -EINVAL; | ||
| 1578 | goto out_release_key; | ||
| 1579 | } | ||
| 1580 | if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD | ||
| 1581 | && (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) { | ||
| 1582 | printk(KERN_ERR "Invalid auth_tok structure " | ||
| 1583 | "returned from key query\n"); | ||
| 1584 | rc = -EINVAL; | ||
| 1585 | goto out_release_key; | ||
| 1586 | } | ||
| 1587 | out_release_key: | ||
| 1588 | if (rc) { | 1650 | if (rc) { |
| 1651 | up_write(&(*auth_tok_key)->sem); | ||
| 1589 | key_put(*auth_tok_key); | 1652 | key_put(*auth_tok_key); |
| 1590 | (*auth_tok_key) = NULL; | 1653 | (*auth_tok_key) = NULL; |
| 1654 | goto out; | ||
| 1591 | } | 1655 | } |
| 1592 | out: | 1656 | out: |
| 1593 | return rc; | 1657 | return rc; |
| @@ -1809,6 +1873,7 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, | |||
| 1809 | find_next_matching_auth_tok: | 1873 | find_next_matching_auth_tok: |
| 1810 | found_auth_tok = 0; | 1874 | found_auth_tok = 0; |
| 1811 | if (auth_tok_key) { | 1875 | if (auth_tok_key) { |
| 1876 | up_write(&(auth_tok_key->sem)); | ||
| 1812 | key_put(auth_tok_key); | 1877 | key_put(auth_tok_key); |
| 1813 | auth_tok_key = NULL; | 1878 | auth_tok_key = NULL; |
| 1814 | } | 1879 | } |
| @@ -1895,8 +1960,10 @@ found_matching_auth_tok: | |||
| 1895 | out_wipe_list: | 1960 | out_wipe_list: |
| 1896 | wipe_auth_tok_list(&auth_tok_list); | 1961 | wipe_auth_tok_list(&auth_tok_list); |
| 1897 | out: | 1962 | out: |
| 1898 | if (auth_tok_key) | 1963 | if (auth_tok_key) { |
| 1964 | up_write(&(auth_tok_key->sem)); | ||
| 1899 | key_put(auth_tok_key); | 1965 | key_put(auth_tok_key); |
| 1966 | } | ||
| 1900 | return rc; | 1967 | return rc; |
| 1901 | } | 1968 | } |
| 1902 | 1969 | ||
| @@ -2324,7 +2391,7 @@ ecryptfs_generate_key_packet_set(char *dest_base, | |||
| 2324 | size_t max) | 2391 | size_t max) |
| 2325 | { | 2392 | { |
| 2326 | struct ecryptfs_auth_tok *auth_tok; | 2393 | struct ecryptfs_auth_tok *auth_tok; |
| 2327 | struct ecryptfs_global_auth_tok *global_auth_tok; | 2394 | struct key *auth_tok_key = NULL; |
| 2328 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = | 2395 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat = |
| 2329 | &ecryptfs_superblock_to_private( | 2396 | &ecryptfs_superblock_to_private( |
| 2330 | ecryptfs_dentry->d_sb)->mount_crypt_stat; | 2397 | ecryptfs_dentry->d_sb)->mount_crypt_stat; |
| @@ -2343,21 +2410,16 @@ ecryptfs_generate_key_packet_set(char *dest_base, | |||
| 2343 | list_for_each_entry(key_sig, &crypt_stat->keysig_list, | 2410 | list_for_each_entry(key_sig, &crypt_stat->keysig_list, |
| 2344 | crypt_stat_list) { | 2411 | crypt_stat_list) { |
| 2345 | memset(key_rec, 0, sizeof(*key_rec)); | 2412 | memset(key_rec, 0, sizeof(*key_rec)); |
| 2346 | rc = ecryptfs_find_global_auth_tok_for_sig(&global_auth_tok, | 2413 | rc = ecryptfs_find_global_auth_tok_for_sig(&auth_tok_key, |
| 2414 | &auth_tok, | ||
| 2347 | mount_crypt_stat, | 2415 | mount_crypt_stat, |
| 2348 | key_sig->keysig); | 2416 | key_sig->keysig); |
| 2349 | if (rc) { | 2417 | if (rc) { |
| 2350 | printk(KERN_ERR "Error attempting to get the global " | 2418 | printk(KERN_WARNING "Unable to retrieve auth tok with " |
| 2351 | "auth_tok; rc = [%d]\n", rc); | 2419 | "sig = [%s]\n", key_sig->keysig); |
| 2420 | rc = process_find_global_auth_tok_for_sig_err(rc); | ||
| 2352 | goto out_free; | 2421 | goto out_free; |
| 2353 | } | 2422 | } |
| 2354 | if (global_auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID) { | ||
| 2355 | printk(KERN_WARNING | ||
| 2356 | "Skipping invalid auth tok with sig = [%s]\n", | ||
| 2357 | global_auth_tok->sig); | ||
| 2358 | continue; | ||
| 2359 | } | ||
| 2360 | auth_tok = global_auth_tok->global_auth_tok; | ||
| 2361 | if (auth_tok->token_type == ECRYPTFS_PASSWORD) { | 2423 | if (auth_tok->token_type == ECRYPTFS_PASSWORD) { |
| 2362 | rc = write_tag_3_packet((dest_base + (*len)), | 2424 | rc = write_tag_3_packet((dest_base + (*len)), |
| 2363 | &max, auth_tok, | 2425 | &max, auth_tok, |
| @@ -2395,6 +2457,9 @@ ecryptfs_generate_key_packet_set(char *dest_base, | |||
| 2395 | rc = -EINVAL; | 2457 | rc = -EINVAL; |
| 2396 | goto out_free; | 2458 | goto out_free; |
| 2397 | } | 2459 | } |
| 2460 | up_write(&(auth_tok_key->sem)); | ||
| 2461 | key_put(auth_tok_key); | ||
| 2462 | auth_tok_key = NULL; | ||
| 2398 | } | 2463 | } |
| 2399 | if (likely(max > 0)) { | 2464 | if (likely(max > 0)) { |
| 2400 | dest_base[(*len)] = 0x00; | 2465 | dest_base[(*len)] = 0x00; |
| @@ -2407,6 +2472,11 @@ out_free: | |||
| 2407 | out: | 2472 | out: |
| 2408 | if (rc) | 2473 | if (rc) |
| 2409 | (*len) = 0; | 2474 | (*len) = 0; |
| 2475 | if (auth_tok_key) { | ||
| 2476 | up_write(&(auth_tok_key->sem)); | ||
| 2477 | key_put(auth_tok_key); | ||
| 2478 | } | ||
| 2479 | |||
| 2410 | mutex_unlock(&crypt_stat->keysig_list_mutex); | 2480 | mutex_unlock(&crypt_stat->keysig_list_mutex); |
| 2411 | return rc; | 2481 | return rc; |
| 2412 | } | 2482 | } |
| @@ -2424,6 +2494,7 @@ int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig) | |||
| 2424 | return -ENOMEM; | 2494 | return -ENOMEM; |
| 2425 | } | 2495 | } |
| 2426 | memcpy(new_key_sig->keysig, sig, ECRYPTFS_SIG_SIZE_HEX); | 2496 | memcpy(new_key_sig->keysig, sig, ECRYPTFS_SIG_SIZE_HEX); |
| 2497 | new_key_sig->keysig[ECRYPTFS_SIG_SIZE_HEX] = '\0'; | ||
| 2427 | /* Caller must hold keysig_list_mutex */ | 2498 | /* Caller must hold keysig_list_mutex */ |
| 2428 | list_add(&new_key_sig->crypt_stat_list, &crypt_stat->keysig_list); | 2499 | list_add(&new_key_sig->crypt_stat_list, &crypt_stat->keysig_list); |
| 2429 | 2500 | ||
| @@ -2453,7 +2524,6 @@ ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat, | |||
| 2453 | mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); | 2524 | mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); |
| 2454 | list_add(&new_auth_tok->mount_crypt_stat_list, | 2525 | list_add(&new_auth_tok->mount_crypt_stat_list, |
| 2455 | &mount_crypt_stat->global_auth_tok_list); | 2526 | &mount_crypt_stat->global_auth_tok_list); |
| 2456 | mount_crypt_stat->num_global_auth_toks++; | ||
| 2457 | mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); | 2527 | mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); |
| 2458 | out: | 2528 | out: |
| 2459 | return rc; | 2529 | return rc; |
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 758323a0f09a..c27c0ecf90bc 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
| @@ -122,7 +122,6 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) | |||
| 122 | ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); | 122 | ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); |
| 123 | int rc = 0; | 123 | int rc = 0; |
| 124 | 124 | ||
| 125 | mutex_lock(&inode_info->lower_file_mutex); | ||
| 126 | if (!inode_info->lower_file) { | 125 | if (!inode_info->lower_file) { |
| 127 | struct dentry *lower_dentry; | 126 | struct dentry *lower_dentry; |
| 128 | struct vfsmount *lower_mnt = | 127 | struct vfsmount *lower_mnt = |
| @@ -138,7 +137,6 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) | |||
| 138 | inode_info->lower_file = NULL; | 137 | inode_info->lower_file = NULL; |
| 139 | } | 138 | } |
| 140 | } | 139 | } |
| 141 | mutex_unlock(&inode_info->lower_file_mutex); | ||
| 142 | return rc; | 140 | return rc; |
| 143 | } | 141 | } |
| 144 | 142 | ||
| @@ -241,14 +239,14 @@ static int ecryptfs_init_global_auth_toks( | |||
| 241 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat) | 239 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat) |
| 242 | { | 240 | { |
| 243 | struct ecryptfs_global_auth_tok *global_auth_tok; | 241 | struct ecryptfs_global_auth_tok *global_auth_tok; |
| 242 | struct ecryptfs_auth_tok *auth_tok; | ||
| 244 | int rc = 0; | 243 | int rc = 0; |
| 245 | 244 | ||
| 246 | list_for_each_entry(global_auth_tok, | 245 | list_for_each_entry(global_auth_tok, |
| 247 | &mount_crypt_stat->global_auth_tok_list, | 246 | &mount_crypt_stat->global_auth_tok_list, |
| 248 | mount_crypt_stat_list) { | 247 | mount_crypt_stat_list) { |
| 249 | rc = ecryptfs_keyring_auth_tok_for_sig( | 248 | rc = ecryptfs_keyring_auth_tok_for_sig( |
| 250 | &global_auth_tok->global_auth_tok_key, | 249 | &global_auth_tok->global_auth_tok_key, &auth_tok, |
| 251 | &global_auth_tok->global_auth_tok, | ||
| 252 | global_auth_tok->sig); | 250 | global_auth_tok->sig); |
| 253 | if (rc) { | 251 | if (rc) { |
| 254 | printk(KERN_ERR "Could not find valid key in user " | 252 | printk(KERN_ERR "Could not find valid key in user " |
| @@ -256,8 +254,10 @@ static int ecryptfs_init_global_auth_toks( | |||
| 256 | "option: [%s]\n", global_auth_tok->sig); | 254 | "option: [%s]\n", global_auth_tok->sig); |
| 257 | global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID; | 255 | global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID; |
| 258 | goto out; | 256 | goto out; |
| 259 | } else | 257 | } else { |
| 260 | global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; | 258 | global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; |
| 259 | up_write(&(global_auth_tok->global_auth_tok_key)->sem); | ||
| 260 | } | ||
| 261 | } | 261 | } |
| 262 | out: | 262 | out: |
| 263 | return rc; | 263 | return rc; |
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index cc64fca89f8d..6a44148c5fb9 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
| @@ -62,6 +62,18 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) | |||
| 62 | { | 62 | { |
| 63 | int rc; | 63 | int rc; |
| 64 | 64 | ||
| 65 | /* | ||
| 66 | * Refuse to write the page out if we are called from reclaim context | ||
| 67 | * since our writepage() path may potentially allocate memory when | ||
| 68 | * calling into the lower fs vfs_write() which may in turn invoke | ||
| 69 | * us again. | ||
| 70 | */ | ||
| 71 | if (current->flags & PF_MEMALLOC) { | ||
| 72 | redirty_page_for_writepage(wbc, page); | ||
| 73 | rc = 0; | ||
| 74 | goto out; | ||
| 75 | } | ||
| 76 | |||
| 65 | rc = ecryptfs_encrypt_page(page); | 77 | rc = ecryptfs_encrypt_page(page); |
| 66 | if (rc) { | 78 | if (rc) { |
| 67 | ecryptfs_printk(KERN_WARNING, "Error encrypting " | 79 | ecryptfs_printk(KERN_WARNING, "Error encrypting " |
| @@ -70,8 +82,8 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) | |||
| 70 | goto out; | 82 | goto out; |
| 71 | } | 83 | } |
| 72 | SetPageUptodate(page); | 84 | SetPageUptodate(page); |
| 73 | unlock_page(page); | ||
| 74 | out: | 85 | out: |
| 86 | unlock_page(page); | ||
| 75 | return rc; | 87 | return rc; |
| 76 | } | 88 | } |
| 77 | 89 | ||
| @@ -193,11 +205,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page) | |||
| 193 | &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat; | 205 | &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat; |
| 194 | int rc = 0; | 206 | int rc = 0; |
| 195 | 207 | ||
| 196 | if (!crypt_stat | 208 | if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { |
| 197 | || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED) | ||
| 198 | || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { | ||
| 199 | ecryptfs_printk(KERN_DEBUG, | ||
| 200 | "Passing through unencrypted page\n"); | ||
| 201 | rc = ecryptfs_read_lower_page_segment(page, page->index, 0, | 209 | rc = ecryptfs_read_lower_page_segment(page, page->index, 0, |
| 202 | PAGE_CACHE_SIZE, | 210 | PAGE_CACHE_SIZE, |
| 203 | page->mapping->host); | 211 | page->mapping->host); |
| @@ -295,8 +303,7 @@ static int ecryptfs_write_begin(struct file *file, | |||
| 295 | struct ecryptfs_crypt_stat *crypt_stat = | 303 | struct ecryptfs_crypt_stat *crypt_stat = |
| 296 | &ecryptfs_inode_to_private(mapping->host)->crypt_stat; | 304 | &ecryptfs_inode_to_private(mapping->host)->crypt_stat; |
| 297 | 305 | ||
| 298 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED) | 306 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { |
| 299 | || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { | ||
| 300 | rc = ecryptfs_read_lower_page_segment( | 307 | rc = ecryptfs_read_lower_page_segment( |
| 301 | page, index, 0, PAGE_CACHE_SIZE, mapping->host); | 308 | page, index, 0, PAGE_CACHE_SIZE, mapping->host); |
| 302 | if (rc) { | 309 | if (rc) { |
| @@ -374,6 +381,11 @@ static int ecryptfs_write_begin(struct file *file, | |||
| 374 | && (pos != 0)) | 381 | && (pos != 0)) |
| 375 | zero_user(page, 0, PAGE_CACHE_SIZE); | 382 | zero_user(page, 0, PAGE_CACHE_SIZE); |
| 376 | out: | 383 | out: |
| 384 | if (unlikely(rc)) { | ||
| 385 | unlock_page(page); | ||
| 386 | page_cache_release(page); | ||
| 387 | *pagep = NULL; | ||
| 388 | } | ||
| 377 | return rc; | 389 | return rc; |
| 378 | } | 390 | } |
| 379 | 391 | ||
| @@ -486,13 +498,8 @@ static int ecryptfs_write_end(struct file *file, | |||
| 486 | struct ecryptfs_crypt_stat *crypt_stat = | 498 | struct ecryptfs_crypt_stat *crypt_stat = |
| 487 | &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; | 499 | &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; |
| 488 | int rc; | 500 | int rc; |
| 501 | int need_unlock_page = 1; | ||
| 489 | 502 | ||
| 490 | if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { | ||
| 491 | ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " | ||
| 492 | "crypt_stat at memory location [%p]\n", crypt_stat); | ||
| 493 | crypt_stat->flags &= ~(ECRYPTFS_NEW_FILE); | ||
| 494 | } else | ||
| 495 | ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); | ||
| 496 | ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" | 503 | ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" |
| 497 | "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); | 504 | "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); |
| 498 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { | 505 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { |
| @@ -512,26 +519,26 @@ static int ecryptfs_write_end(struct file *file, | |||
| 512 | "zeros in page with index = [0x%.16lx]\n", index); | 519 | "zeros in page with index = [0x%.16lx]\n", index); |
| 513 | goto out; | 520 | goto out; |
| 514 | } | 521 | } |
| 515 | rc = ecryptfs_encrypt_page(page); | 522 | set_page_dirty(page); |
| 516 | if (rc) { | 523 | unlock_page(page); |
| 517 | ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " | 524 | need_unlock_page = 0; |
| 518 | "index [0x%.16lx])\n", index); | ||
| 519 | goto out; | ||
| 520 | } | ||
| 521 | if (pos + copied > i_size_read(ecryptfs_inode)) { | 525 | if (pos + copied > i_size_read(ecryptfs_inode)) { |
| 522 | i_size_write(ecryptfs_inode, pos + copied); | 526 | i_size_write(ecryptfs_inode, pos + copied); |
| 523 | ecryptfs_printk(KERN_DEBUG, "Expanded file size to " | 527 | ecryptfs_printk(KERN_DEBUG, "Expanded file size to " |
| 524 | "[0x%.16llx]\n", | 528 | "[0x%.16llx]\n", |
| 525 | (unsigned long long)i_size_read(ecryptfs_inode)); | 529 | (unsigned long long)i_size_read(ecryptfs_inode)); |
| 530 | balance_dirty_pages_ratelimited(mapping); | ||
| 531 | rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); | ||
| 532 | if (rc) { | ||
| 533 | printk(KERN_ERR "Error writing inode size to metadata; " | ||
| 534 | "rc = [%d]\n", rc); | ||
| 535 | goto out; | ||
| 536 | } | ||
| 526 | } | 537 | } |
| 527 | rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); | 538 | rc = copied; |
| 528 | if (rc) | ||
| 529 | printk(KERN_ERR "Error writing inode size to metadata; " | ||
| 530 | "rc = [%d]\n", rc); | ||
| 531 | else | ||
| 532 | rc = copied; | ||
| 533 | out: | 539 | out: |
| 534 | unlock_page(page); | 540 | if (need_unlock_page) |
| 541 | unlock_page(page); | ||
| 535 | page_cache_release(page); | 542 | page_cache_release(page); |
| 536 | return rc; | 543 | return rc; |
| 537 | } | 544 | } |
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index db184ef15d3d..85d430963116 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c | |||
| @@ -44,15 +44,11 @@ int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, | |||
| 44 | ssize_t rc; | 44 | ssize_t rc; |
| 45 | 45 | ||
| 46 | inode_info = ecryptfs_inode_to_private(ecryptfs_inode); | 46 | inode_info = ecryptfs_inode_to_private(ecryptfs_inode); |
| 47 | mutex_lock(&inode_info->lower_file_mutex); | ||
| 48 | BUG_ON(!inode_info->lower_file); | 47 | BUG_ON(!inode_info->lower_file); |
| 49 | inode_info->lower_file->f_pos = offset; | ||
| 50 | fs_save = get_fs(); | 48 | fs_save = get_fs(); |
| 51 | set_fs(get_ds()); | 49 | set_fs(get_ds()); |
| 52 | rc = vfs_write(inode_info->lower_file, data, size, | 50 | rc = vfs_write(inode_info->lower_file, data, size, &offset); |
| 53 | &inode_info->lower_file->f_pos); | ||
| 54 | set_fs(fs_save); | 51 | set_fs(fs_save); |
| 55 | mutex_unlock(&inode_info->lower_file_mutex); | ||
| 56 | mark_inode_dirty_sync(ecryptfs_inode); | 52 | mark_inode_dirty_sync(ecryptfs_inode); |
| 57 | return rc; | 53 | return rc; |
| 58 | } | 54 | } |
| @@ -234,15 +230,11 @@ int ecryptfs_read_lower(char *data, loff_t offset, size_t size, | |||
| 234 | mm_segment_t fs_save; | 230 | mm_segment_t fs_save; |
| 235 | ssize_t rc; | 231 | ssize_t rc; |
| 236 | 232 | ||
| 237 | mutex_lock(&inode_info->lower_file_mutex); | ||
| 238 | BUG_ON(!inode_info->lower_file); | 233 | BUG_ON(!inode_info->lower_file); |
| 239 | inode_info->lower_file->f_pos = offset; | ||
| 240 | fs_save = get_fs(); | 234 | fs_save = get_fs(); |
| 241 | set_fs(get_ds()); | 235 | set_fs(get_ds()); |
| 242 | rc = vfs_read(inode_info->lower_file, data, size, | 236 | rc = vfs_read(inode_info->lower_file, data, size, &offset); |
| 243 | &inode_info->lower_file->f_pos); | ||
| 244 | set_fs(fs_save); | 237 | set_fs(fs_save); |
| 245 | mutex_unlock(&inode_info->lower_file_mutex); | ||
| 246 | return rc; | 238 | return rc; |
| 247 | } | 239 | } |
| 248 | 240 | ||
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 3042fe123a34..bacc882e1ae4 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c | |||
| @@ -55,7 +55,6 @@ static struct inode *ecryptfs_alloc_inode(struct super_block *sb) | |||
| 55 | if (unlikely(!inode_info)) | 55 | if (unlikely(!inode_info)) |
| 56 | goto out; | 56 | goto out; |
| 57 | ecryptfs_init_crypt_stat(&inode_info->crypt_stat); | 57 | ecryptfs_init_crypt_stat(&inode_info->crypt_stat); |
| 58 | mutex_init(&inode_info->lower_file_mutex); | ||
| 59 | inode_info->lower_file = NULL; | 58 | inode_info->lower_file = NULL; |
| 60 | inode = &inode_info->vfs_inode; | 59 | inode = &inode_info->vfs_inode; |
| 61 | out: | 60 | out: |
| @@ -198,7 +197,7 @@ static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 198 | const struct super_operations ecryptfs_sops = { | 197 | const struct super_operations ecryptfs_sops = { |
| 199 | .alloc_inode = ecryptfs_alloc_inode, | 198 | .alloc_inode = ecryptfs_alloc_inode, |
| 200 | .destroy_inode = ecryptfs_destroy_inode, | 199 | .destroy_inode = ecryptfs_destroy_inode, |
| 201 | .drop_inode = generic_delete_inode, | 200 | .drop_inode = generic_drop_inode, |
| 202 | .statfs = ecryptfs_statfs, | 201 | .statfs = ecryptfs_statfs, |
| 203 | .remount_fs = NULL, | 202 | .remount_fs = NULL, |
| 204 | .evict_inode = ecryptfs_evict_inode, | 203 | .evict_inode = ecryptfs_evict_inode, |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index c05324d3282c..596bb2c9de42 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
| @@ -94,75 +94,6 @@ xfs_buf_vmap_len( | |||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | /* | 96 | /* |
| 97 | * Page Region interfaces. | ||
| 98 | * | ||
| 99 | * For pages in filesystems where the blocksize is smaller than the | ||
| 100 | * pagesize, we use the page->private field (long) to hold a bitmap | ||
| 101 | * of uptodate regions within the page. | ||
| 102 | * | ||
| 103 | * Each such region is "bytes per page / bits per long" bytes long. | ||
| 104 | * | ||
| 105 | * NBPPR == number-of-bytes-per-page-region | ||
| 106 | * BTOPR == bytes-to-page-region (rounded up) | ||
| 107 | * BTOPRT == bytes-to-page-region-truncated (rounded down) | ||
| 108 | */ | ||
| 109 | #if (BITS_PER_LONG == 32) | ||
| 110 | #define PRSHIFT (PAGE_CACHE_SHIFT - 5) /* (32 == 1<<5) */ | ||
| 111 | #elif (BITS_PER_LONG == 64) | ||
| 112 | #define PRSHIFT (PAGE_CACHE_SHIFT - 6) /* (64 == 1<<6) */ | ||
| 113 | #else | ||
| 114 | #error BITS_PER_LONG must be 32 or 64 | ||
| 115 | #endif | ||
| 116 | #define NBPPR (PAGE_CACHE_SIZE/BITS_PER_LONG) | ||
| 117 | #define BTOPR(b) (((unsigned int)(b) + (NBPPR - 1)) >> PRSHIFT) | ||
| 118 | #define BTOPRT(b) (((unsigned int)(b) >> PRSHIFT)) | ||
| 119 | |||
| 120 | STATIC unsigned long | ||
| 121 | page_region_mask( | ||
| 122 | size_t offset, | ||
| 123 | size_t length) | ||
| 124 | { | ||
| 125 | unsigned long mask; | ||
| 126 | int first, final; | ||
| 127 | |||
| 128 | first = BTOPR(offset); | ||
| 129 | final = BTOPRT(offset + length - 1); | ||
| 130 | first = min(first, final); | ||
| 131 | |||
| 132 | mask = ~0UL; | ||
| 133 | mask <<= BITS_PER_LONG - (final - first); | ||
| 134 | mask >>= BITS_PER_LONG - (final); | ||
| 135 | |||
| 136 | ASSERT(offset + length <= PAGE_CACHE_SIZE); | ||
| 137 | ASSERT((final - first) < BITS_PER_LONG && (final - first) >= 0); | ||
| 138 | |||
| 139 | return mask; | ||
| 140 | } | ||
| 141 | |||
| 142 | STATIC void | ||
| 143 | set_page_region( | ||
| 144 | struct page *page, | ||
| 145 | size_t offset, | ||
| 146 | size_t length) | ||
| 147 | { | ||
| 148 | set_page_private(page, | ||
| 149 | page_private(page) | page_region_mask(offset, length)); | ||
| 150 | if (page_private(page) == ~0UL) | ||
| 151 | SetPageUptodate(page); | ||
| 152 | } | ||
| 153 | |||
| 154 | STATIC int | ||
| 155 | test_page_region( | ||
| 156 | struct page *page, | ||
| 157 | size_t offset, | ||
| 158 | size_t length) | ||
| 159 | { | ||
| 160 | unsigned long mask = page_region_mask(offset, length); | ||
| 161 | |||
| 162 | return (mask && (page_private(page) & mask) == mask); | ||
| 163 | } | ||
| 164 | |||
| 165 | /* | ||
| 166 | * xfs_buf_lru_add - add a buffer to the LRU. | 97 | * xfs_buf_lru_add - add a buffer to the LRU. |
| 167 | * | 98 | * |
| 168 | * The LRU takes a new reference to the buffer so that it will only be freed | 99 | * The LRU takes a new reference to the buffer so that it will only be freed |
| @@ -332,7 +263,7 @@ xfs_buf_free( | |||
| 332 | 263 | ||
| 333 | ASSERT(list_empty(&bp->b_lru)); | 264 | ASSERT(list_empty(&bp->b_lru)); |
| 334 | 265 | ||
| 335 | if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) { | 266 | if (bp->b_flags & _XBF_PAGES) { |
| 336 | uint i; | 267 | uint i; |
| 337 | 268 | ||
| 338 | if (xfs_buf_is_vmapped(bp)) | 269 | if (xfs_buf_is_vmapped(bp)) |
| @@ -342,25 +273,22 @@ xfs_buf_free( | |||
| 342 | for (i = 0; i < bp->b_page_count; i++) { | 273 | for (i = 0; i < bp->b_page_count; i++) { |
| 343 | struct page *page = bp->b_pages[i]; | 274 | struct page *page = bp->b_pages[i]; |
| 344 | 275 | ||
| 345 | if (bp->b_flags & _XBF_PAGE_CACHE) | 276 | __free_page(page); |
| 346 | ASSERT(!PagePrivate(page)); | ||
| 347 | page_cache_release(page); | ||
| 348 | } | 277 | } |
| 349 | } | 278 | } else if (bp->b_flags & _XBF_KMEM) |
| 279 | kmem_free(bp->b_addr); | ||
| 350 | _xfs_buf_free_pages(bp); | 280 | _xfs_buf_free_pages(bp); |
| 351 | xfs_buf_deallocate(bp); | 281 | xfs_buf_deallocate(bp); |
| 352 | } | 282 | } |
| 353 | 283 | ||
| 354 | /* | 284 | /* |
| 355 | * Finds all pages for buffer in question and builds it's page list. | 285 | * Allocates all the pages for buffer in question and builds it's page list. |
| 356 | */ | 286 | */ |
| 357 | STATIC int | 287 | STATIC int |
| 358 | _xfs_buf_lookup_pages( | 288 | xfs_buf_allocate_memory( |
| 359 | xfs_buf_t *bp, | 289 | xfs_buf_t *bp, |
| 360 | uint flags) | 290 | uint flags) |
| 361 | { | 291 | { |
| 362 | struct address_space *mapping = bp->b_target->bt_mapping; | ||
| 363 | size_t blocksize = bp->b_target->bt_bsize; | ||
| 364 | size_t size = bp->b_count_desired; | 292 | size_t size = bp->b_count_desired; |
| 365 | size_t nbytes, offset; | 293 | size_t nbytes, offset; |
| 366 | gfp_t gfp_mask = xb_to_gfp(flags); | 294 | gfp_t gfp_mask = xb_to_gfp(flags); |
| @@ -369,29 +297,55 @@ _xfs_buf_lookup_pages( | |||
| 369 | xfs_off_t end; | 297 | xfs_off_t end; |
| 370 | int error; | 298 | int error; |
| 371 | 299 | ||
| 300 | /* | ||
| 301 | * for buffers that are contained within a single page, just allocate | ||
| 302 | * the memory from the heap - there's no need for the complexity of | ||
| 303 | * page arrays to keep allocation down to order 0. | ||
| 304 | */ | ||
| 305 | if (bp->b_buffer_length < PAGE_SIZE) { | ||
| 306 | bp->b_addr = kmem_alloc(bp->b_buffer_length, xb_to_km(flags)); | ||
| 307 | if (!bp->b_addr) { | ||
| 308 | /* low memory - use alloc_page loop instead */ | ||
| 309 | goto use_alloc_page; | ||
| 310 | } | ||
| 311 | |||
| 312 | if (((unsigned long)(bp->b_addr + bp->b_buffer_length - 1) & | ||
| 313 | PAGE_MASK) != | ||
| 314 | ((unsigned long)bp->b_addr & PAGE_MASK)) { | ||
| 315 | /* b_addr spans two pages - use alloc_page instead */ | ||
| 316 | kmem_free(bp->b_addr); | ||
| 317 | bp->b_addr = NULL; | ||
| 318 | goto use_alloc_page; | ||
| 319 | } | ||
| 320 | bp->b_offset = offset_in_page(bp->b_addr); | ||
| 321 | bp->b_pages = bp->b_page_array; | ||
| 322 | bp->b_pages[0] = virt_to_page(bp->b_addr); | ||
| 323 | bp->b_page_count = 1; | ||
| 324 | bp->b_flags |= XBF_MAPPED | _XBF_KMEM; | ||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | use_alloc_page: | ||
| 372 | end = bp->b_file_offset + bp->b_buffer_length; | 329 | end = bp->b_file_offset + bp->b_buffer_length; |
| 373 | page_count = xfs_buf_btoc(end) - xfs_buf_btoct(bp->b_file_offset); | 330 | page_count = xfs_buf_btoc(end) - xfs_buf_btoct(bp->b_file_offset); |
| 374 | |||
| 375 | error = _xfs_buf_get_pages(bp, page_count, flags); | 331 | error = _xfs_buf_get_pages(bp, page_count, flags); |
| 376 | if (unlikely(error)) | 332 | if (unlikely(error)) |
| 377 | return error; | 333 | return error; |
| 378 | bp->b_flags |= _XBF_PAGE_CACHE; | ||
| 379 | 334 | ||
| 380 | offset = bp->b_offset; | 335 | offset = bp->b_offset; |
| 381 | first = bp->b_file_offset >> PAGE_CACHE_SHIFT; | 336 | first = bp->b_file_offset >> PAGE_SHIFT; |
| 337 | bp->b_flags |= _XBF_PAGES; | ||
| 382 | 338 | ||
| 383 | for (i = 0; i < bp->b_page_count; i++) { | 339 | for (i = 0; i < bp->b_page_count; i++) { |
| 384 | struct page *page; | 340 | struct page *page; |
| 385 | uint retries = 0; | 341 | uint retries = 0; |
| 386 | 342 | retry: | |
| 387 | retry: | 343 | page = alloc_page(gfp_mask); |
| 388 | page = find_or_create_page(mapping, first + i, gfp_mask); | ||
| 389 | if (unlikely(page == NULL)) { | 344 | if (unlikely(page == NULL)) { |
| 390 | if (flags & XBF_READ_AHEAD) { | 345 | if (flags & XBF_READ_AHEAD) { |
| 391 | bp->b_page_count = i; | 346 | bp->b_page_count = i; |
| 392 | for (i = 0; i < bp->b_page_count; i++) | 347 | error = ENOMEM; |
| 393 | unlock_page(bp->b_pages[i]); | 348 | goto out_free_pages; |
| 394 | return -ENOMEM; | ||
| 395 | } | 349 | } |
| 396 | 350 | ||
| 397 | /* | 351 | /* |
| @@ -412,33 +366,16 @@ _xfs_buf_lookup_pages( | |||
| 412 | 366 | ||
| 413 | XFS_STATS_INC(xb_page_found); | 367 | XFS_STATS_INC(xb_page_found); |
| 414 | 368 | ||
| 415 | nbytes = min_t(size_t, size, PAGE_CACHE_SIZE - offset); | 369 | nbytes = min_t(size_t, size, PAGE_SIZE - offset); |
| 416 | size -= nbytes; | 370 | size -= nbytes; |
| 417 | |||
| 418 | ASSERT(!PagePrivate(page)); | ||
| 419 | if (!PageUptodate(page)) { | ||
| 420 | page_count--; | ||
| 421 | if (blocksize >= PAGE_CACHE_SIZE) { | ||
| 422 | if (flags & XBF_READ) | ||
| 423 | bp->b_flags |= _XBF_PAGE_LOCKED; | ||
| 424 | } else if (!PagePrivate(page)) { | ||
| 425 | if (test_page_region(page, offset, nbytes)) | ||
| 426 | page_count++; | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | bp->b_pages[i] = page; | 371 | bp->b_pages[i] = page; |
| 431 | offset = 0; | 372 | offset = 0; |
| 432 | } | 373 | } |
| 374 | return 0; | ||
| 433 | 375 | ||
| 434 | if (!(bp->b_flags & _XBF_PAGE_LOCKED)) { | 376 | out_free_pages: |
| 435 | for (i = 0; i < bp->b_page_count; i++) | 377 | for (i = 0; i < bp->b_page_count; i++) |
| 436 | unlock_page(bp->b_pages[i]); | 378 | __free_page(bp->b_pages[i]); |
| 437 | } | ||
| 438 | |||
| 439 | if (page_count == bp->b_page_count) | ||
| 440 | bp->b_flags |= XBF_DONE; | ||
| 441 | |||
| 442 | return error; | 379 | return error; |
| 443 | } | 380 | } |
| 444 | 381 | ||
| @@ -450,14 +387,23 @@ _xfs_buf_map_pages( | |||
| 450 | xfs_buf_t *bp, | 387 | xfs_buf_t *bp, |
| 451 | uint flags) | 388 | uint flags) |
| 452 | { | 389 | { |
| 453 | /* A single page buffer is always mappable */ | 390 | ASSERT(bp->b_flags & _XBF_PAGES); |
| 454 | if (bp->b_page_count == 1) { | 391 | if (bp->b_page_count == 1) { |
| 392 | /* A single page buffer is always mappable */ | ||
| 455 | bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset; | 393 | bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset; |
| 456 | bp->b_flags |= XBF_MAPPED; | 394 | bp->b_flags |= XBF_MAPPED; |
| 457 | } else if (flags & XBF_MAPPED) { | 395 | } else if (flags & XBF_MAPPED) { |
| 458 | bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count, | 396 | int retried = 0; |
| 459 | -1, PAGE_KERNEL); | 397 | |
| 460 | if (unlikely(bp->b_addr == NULL)) | 398 | do { |
| 399 | bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count, | ||
| 400 | -1, PAGE_KERNEL); | ||
| 401 | if (bp->b_addr) | ||
| 402 | break; | ||
| 403 | vm_unmap_aliases(); | ||
| 404 | } while (retried++ <= 1); | ||
| 405 | |||
| 406 | if (!bp->b_addr) | ||
| 461 | return -ENOMEM; | 407 | return -ENOMEM; |
| 462 | bp->b_addr += bp->b_offset; | 408 | bp->b_addr += bp->b_offset; |
| 463 | bp->b_flags |= XBF_MAPPED; | 409 | bp->b_flags |= XBF_MAPPED; |
| @@ -568,9 +514,14 @@ found: | |||
| 568 | } | 514 | } |
| 569 | } | 515 | } |
| 570 | 516 | ||
| 517 | /* | ||
| 518 | * if the buffer is stale, clear all the external state associated with | ||
| 519 | * it. We need to keep flags such as how we allocated the buffer memory | ||
| 520 | * intact here. | ||
| 521 | */ | ||
| 571 | if (bp->b_flags & XBF_STALE) { | 522 | if (bp->b_flags & XBF_STALE) { |
| 572 | ASSERT((bp->b_flags & _XBF_DELWRI_Q) == 0); | 523 | ASSERT((bp->b_flags & _XBF_DELWRI_Q) == 0); |
| 573 | bp->b_flags &= XBF_MAPPED; | 524 | bp->b_flags &= XBF_MAPPED | _XBF_KMEM | _XBF_PAGES; |
| 574 | } | 525 | } |
| 575 | 526 | ||
| 576 | trace_xfs_buf_find(bp, flags, _RET_IP_); | 527 | trace_xfs_buf_find(bp, flags, _RET_IP_); |
| @@ -591,7 +542,7 @@ xfs_buf_get( | |||
| 591 | xfs_buf_flags_t flags) | 542 | xfs_buf_flags_t flags) |
| 592 | { | 543 | { |
| 593 | xfs_buf_t *bp, *new_bp; | 544 | xfs_buf_t *bp, *new_bp; |
| 594 | int error = 0, i; | 545 | int error = 0; |
| 595 | 546 | ||
| 596 | new_bp = xfs_buf_allocate(flags); | 547 | new_bp = xfs_buf_allocate(flags); |
| 597 | if (unlikely(!new_bp)) | 548 | if (unlikely(!new_bp)) |
| @@ -599,7 +550,7 @@ xfs_buf_get( | |||
| 599 | 550 | ||
| 600 | bp = _xfs_buf_find(target, ioff, isize, flags, new_bp); | 551 | bp = _xfs_buf_find(target, ioff, isize, flags, new_bp); |
| 601 | if (bp == new_bp) { | 552 | if (bp == new_bp) { |
| 602 | error = _xfs_buf_lookup_pages(bp, flags); | 553 | error = xfs_buf_allocate_memory(bp, flags); |
| 603 | if (error) | 554 | if (error) |
| 604 | goto no_buffer; | 555 | goto no_buffer; |
| 605 | } else { | 556 | } else { |
| @@ -608,9 +559,6 @@ xfs_buf_get( | |||
| 608 | return NULL; | 559 | return NULL; |
| 609 | } | 560 | } |
| 610 | 561 | ||
| 611 | for (i = 0; i < bp->b_page_count; i++) | ||
| 612 | mark_page_accessed(bp->b_pages[i]); | ||
| 613 | |||
| 614 | if (!(bp->b_flags & XBF_MAPPED)) { | 562 | if (!(bp->b_flags & XBF_MAPPED)) { |
| 615 | error = _xfs_buf_map_pages(bp, flags); | 563 | error = _xfs_buf_map_pages(bp, flags); |
| 616 | if (unlikely(error)) { | 564 | if (unlikely(error)) { |
| @@ -711,8 +659,7 @@ xfs_buf_readahead( | |||
| 711 | { | 659 | { |
| 712 | struct backing_dev_info *bdi; | 660 | struct backing_dev_info *bdi; |
| 713 | 661 | ||
| 714 | bdi = target->bt_mapping->backing_dev_info; | 662 | if (bdi_read_congested(target->bt_bdi)) |
| 715 | if (bdi_read_congested(bdi)) | ||
| 716 | return; | 663 | return; |
| 717 | 664 | ||
| 718 | xfs_buf_read(target, ioff, isize, | 665 | xfs_buf_read(target, ioff, isize, |
| @@ -790,10 +737,10 @@ xfs_buf_associate_memory( | |||
| 790 | size_t buflen; | 737 | size_t buflen; |
| 791 | int page_count; | 738 | int page_count; |
| 792 | 739 | ||
| 793 | pageaddr = (unsigned long)mem & PAGE_CACHE_MASK; | 740 | pageaddr = (unsigned long)mem & PAGE_MASK; |
| 794 | offset = (unsigned long)mem - pageaddr; | 741 | offset = (unsigned long)mem - pageaddr; |
| 795 | buflen = PAGE_CACHE_ALIGN(len + offset); | 742 | buflen = PAGE_ALIGN(len + offset); |
| 796 | page_count = buflen >> PAGE_CACHE_SHIFT; | 743 | page_count = buflen >> PAGE_SHIFT; |
| 797 | 744 | ||
| 798 | /* Free any previous set of page pointers */ | 745 | /* Free any previous set of page pointers */ |
| 799 | if (bp->b_pages) | 746 | if (bp->b_pages) |
| @@ -810,13 +757,12 @@ xfs_buf_associate_memory( | |||
| 810 | 757 | ||
| 811 | for (i = 0; i < bp->b_page_count; i++) { | 758 | for (i = 0; i < bp->b_page_count; i++) { |
| 812 | bp->b_pages[i] = mem_to_page((void *)pageaddr); | 759 | bp->b_pages[i] = mem_to_page((void *)pageaddr); |
| 813 | pageaddr += PAGE_CACHE_SIZE; | 760 | pageaddr += PAGE_SIZE; |
| 814 | } | 761 | } |
| 815 | 762 | ||
| 816 | bp->b_count_desired = len; | 763 | bp->b_count_desired = len; |
| 817 | bp->b_buffer_length = buflen; | 764 | bp->b_buffer_length = buflen; |
| 818 | bp->b_flags |= XBF_MAPPED; | 765 | bp->b_flags |= XBF_MAPPED; |
| 819 | bp->b_flags &= ~_XBF_PAGE_LOCKED; | ||
| 820 | 766 | ||
| 821 | return 0; | 767 | return 0; |
| 822 | } | 768 | } |
| @@ -923,20 +869,7 @@ xfs_buf_rele( | |||
| 923 | 869 | ||
| 924 | 870 | ||
| 925 | /* | 871 | /* |
| 926 | * Mutual exclusion on buffers. Locking model: | 872 | * Lock a buffer object, if it is not already locked. |
| 927 | * | ||
| 928 | * Buffers associated with inodes for which buffer locking | ||
| 929 | * is not enabled are not protected by semaphores, and are | ||
| 930 | * assumed to be exclusively owned by the caller. There is a | ||
| 931 | * spinlock in the buffer, used by the caller when concurrent | ||
| 932 | * access is possible. | ||
| 933 | */ | ||
| 934 | |||
| 935 | /* | ||
| 936 | * Locks a buffer object, if it is not already locked. Note that this in | ||
| 937 | * no way locks the underlying pages, so it is only useful for | ||
| 938 | * synchronizing concurrent use of buffer objects, not for synchronizing | ||
| 939 | * independent access to the underlying pages. | ||
| 940 | * | 873 | * |
| 941 | * If we come across a stale, pinned, locked buffer, we know that we are | 874 | * If we come across a stale, pinned, locked buffer, we know that we are |
| 942 | * being asked to lock a buffer that has been reallocated. Because it is | 875 | * being asked to lock a buffer that has been reallocated. Because it is |
| @@ -970,10 +903,7 @@ xfs_buf_lock_value( | |||
| 970 | } | 903 | } |
| 971 | 904 | ||
| 972 | /* | 905 | /* |
| 973 | * Locks a buffer object. | 906 | * Lock a buffer object. |
| 974 | * Note that this in no way locks the underlying pages, so it is only | ||
| 975 | * useful for synchronizing concurrent use of buffer objects, not for | ||
| 976 | * synchronizing independent access to the underlying pages. | ||
| 977 | * | 907 | * |
| 978 | * If we come across a stale, pinned, locked buffer, we know that we | 908 | * If we come across a stale, pinned, locked buffer, we know that we |
| 979 | * are being asked to lock a buffer that has been reallocated. Because | 909 | * are being asked to lock a buffer that has been reallocated. Because |
| @@ -1246,10 +1176,8 @@ _xfs_buf_ioend( | |||
| 1246 | xfs_buf_t *bp, | 1176 | xfs_buf_t *bp, |
| 1247 | int schedule) | 1177 | int schedule) |
| 1248 | { | 1178 | { |
| 1249 | if (atomic_dec_and_test(&bp->b_io_remaining) == 1) { | 1179 | if (atomic_dec_and_test(&bp->b_io_remaining) == 1) |
| 1250 | bp->b_flags &= ~_XBF_PAGE_LOCKED; | ||
| 1251 | xfs_buf_ioend(bp, schedule); | 1180 | xfs_buf_ioend(bp, schedule); |
| 1252 | } | ||
| 1253 | } | 1181 | } |
| 1254 | 1182 | ||
| 1255 | STATIC void | 1183 | STATIC void |
| @@ -1258,35 +1186,12 @@ xfs_buf_bio_end_io( | |||
| 1258 | int error) | 1186 | int error) |
| 1259 | { | 1187 | { |
| 1260 | xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; | 1188 | xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; |
| 1261 | unsigned int blocksize = bp->b_target->bt_bsize; | ||
| 1262 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | ||
| 1263 | 1189 | ||
| 1264 | xfs_buf_ioerror(bp, -error); | 1190 | xfs_buf_ioerror(bp, -error); |
| 1265 | 1191 | ||
| 1266 | if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) | 1192 | if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) |
| 1267 | invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); | 1193 | invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); |
| 1268 | 1194 | ||
| 1269 | do { | ||
| 1270 | struct page *page = bvec->bv_page; | ||
| 1271 | |||
| 1272 | ASSERT(!PagePrivate(page)); | ||
| 1273 | if (unlikely(bp->b_error)) { | ||
| 1274 | if (bp->b_flags & XBF_READ) | ||
| 1275 | ClearPageUptodate(page); | ||
| 1276 | } else if (blocksize >= PAGE_CACHE_SIZE) { | ||
| 1277 | SetPageUptodate(page); | ||
| 1278 | } else if (!PagePrivate(page) && | ||
| 1279 | (bp->b_flags & _XBF_PAGE_CACHE)) { | ||
| 1280 | set_page_region(page, bvec->bv_offset, bvec->bv_len); | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | if (--bvec >= bio->bi_io_vec) | ||
| 1284 | prefetchw(&bvec->bv_page->flags); | ||
| 1285 | |||
| 1286 | if (bp->b_flags & _XBF_PAGE_LOCKED) | ||
| 1287 | unlock_page(page); | ||
| 1288 | } while (bvec >= bio->bi_io_vec); | ||
| 1289 | |||
| 1290 | _xfs_buf_ioend(bp, 1); | 1195 | _xfs_buf_ioend(bp, 1); |
| 1291 | bio_put(bio); | 1196 | bio_put(bio); |
| 1292 | } | 1197 | } |
| @@ -1300,7 +1205,6 @@ _xfs_buf_ioapply( | |||
| 1300 | int offset = bp->b_offset; | 1205 | int offset = bp->b_offset; |
| 1301 | int size = bp->b_count_desired; | 1206 | int size = bp->b_count_desired; |
| 1302 | sector_t sector = bp->b_bn; | 1207 | sector_t sector = bp->b_bn; |
| 1303 | unsigned int blocksize = bp->b_target->bt_bsize; | ||
| 1304 | 1208 | ||
| 1305 | total_nr_pages = bp->b_page_count; | 1209 | total_nr_pages = bp->b_page_count; |
| 1306 | map_i = 0; | 1210 | map_i = 0; |
| @@ -1321,29 +1225,6 @@ _xfs_buf_ioapply( | |||
| 1321 | (bp->b_flags & XBF_READ_AHEAD) ? READA : READ; | 1225 | (bp->b_flags & XBF_READ_AHEAD) ? READA : READ; |
| 1322 | } | 1226 | } |
| 1323 | 1227 | ||
| 1324 | /* Special code path for reading a sub page size buffer in -- | ||
| 1325 | * we populate up the whole page, and hence the other metadata | ||
| 1326 | * in the same page. This optimization is only valid when the | ||
| 1327 | * filesystem block size is not smaller than the page size. | ||
| 1328 | */ | ||
| 1329 | if ((bp->b_buffer_length < PAGE_CACHE_SIZE) && | ||
| 1330 | ((bp->b_flags & (XBF_READ|_XBF_PAGE_LOCKED)) == | ||
| 1331 | (XBF_READ|_XBF_PAGE_LOCKED)) && | ||
| 1332 | (blocksize >= PAGE_CACHE_SIZE)) { | ||
| 1333 | bio = bio_alloc(GFP_NOIO, 1); | ||
| 1334 | |||
| 1335 | bio->bi_bdev = bp->b_target->bt_bdev; | ||
| 1336 | bio->bi_sector = sector - (offset >> BBSHIFT); | ||
| 1337 | bio->bi_end_io = xfs_buf_bio_end_io; | ||
| 1338 | bio->bi_private = bp; | ||
| 1339 | |||
| 1340 | bio_add_page(bio, bp->b_pages[0], PAGE_CACHE_SIZE, 0); | ||
| 1341 | size = 0; | ||
| 1342 | |||
| 1343 | atomic_inc(&bp->b_io_remaining); | ||
| 1344 | |||
| 1345 | goto submit_io; | ||
| 1346 | } | ||
| 1347 | 1228 | ||
| 1348 | next_chunk: | 1229 | next_chunk: |
| 1349 | atomic_inc(&bp->b_io_remaining); | 1230 | atomic_inc(&bp->b_io_remaining); |
| @@ -1357,8 +1238,9 @@ next_chunk: | |||
| 1357 | bio->bi_end_io = xfs_buf_bio_end_io; | 1238 | bio->bi_end_io = xfs_buf_bio_end_io; |
| 1358 | bio->bi_private = bp; | 1239 | bio->bi_private = bp; |
| 1359 | 1240 | ||
| 1241 | |||
| 1360 | for (; size && nr_pages; nr_pages--, map_i++) { | 1242 | for (; size && nr_pages; nr_pages--, map_i++) { |
| 1361 | int rbytes, nbytes = PAGE_CACHE_SIZE - offset; | 1243 | int rbytes, nbytes = PAGE_SIZE - offset; |
| 1362 | 1244 | ||
| 1363 | if (nbytes > size) | 1245 | if (nbytes > size) |
| 1364 | nbytes = size; | 1246 | nbytes = size; |
| @@ -1373,7 +1255,6 @@ next_chunk: | |||
| 1373 | total_nr_pages--; | 1255 | total_nr_pages--; |
| 1374 | } | 1256 | } |
| 1375 | 1257 | ||
| 1376 | submit_io: | ||
| 1377 | if (likely(bio->bi_size)) { | 1258 | if (likely(bio->bi_size)) { |
| 1378 | if (xfs_buf_is_vmapped(bp)) { | 1259 | if (xfs_buf_is_vmapped(bp)) { |
| 1379 | flush_kernel_vmap_range(bp->b_addr, | 1260 | flush_kernel_vmap_range(bp->b_addr, |
| @@ -1383,18 +1264,7 @@ submit_io: | |||
| 1383 | if (size) | 1264 | if (size) |
| 1384 | goto next_chunk; | 1265 | goto next_chunk; |
| 1385 | } else { | 1266 | } else { |
| 1386 | /* | ||
| 1387 | * if we get here, no pages were added to the bio. However, | ||
| 1388 | * we can't just error out here - if the pages are locked then | ||
| 1389 | * we have to unlock them otherwise we can hang on a later | ||
| 1390 | * access to the page. | ||
| 1391 | */ | ||
| 1392 | xfs_buf_ioerror(bp, EIO); | 1267 | xfs_buf_ioerror(bp, EIO); |
| 1393 | if (bp->b_flags & _XBF_PAGE_LOCKED) { | ||
| 1394 | int i; | ||
| 1395 | for (i = 0; i < bp->b_page_count; i++) | ||
| 1396 | unlock_page(bp->b_pages[i]); | ||
| 1397 | } | ||
| 1398 | bio_put(bio); | 1268 | bio_put(bio); |
| 1399 | } | 1269 | } |
| 1400 | } | 1270 | } |
| @@ -1458,8 +1328,8 @@ xfs_buf_offset( | |||
| 1458 | return XFS_BUF_PTR(bp) + offset; | 1328 | return XFS_BUF_PTR(bp) + offset; |
| 1459 | 1329 | ||
| 1460 | offset += bp->b_offset; | 1330 | offset += bp->b_offset; |
| 1461 | page = bp->b_pages[offset >> PAGE_CACHE_SHIFT]; | 1331 | page = bp->b_pages[offset >> PAGE_SHIFT]; |
| 1462 | return (xfs_caddr_t)page_address(page) + (offset & (PAGE_CACHE_SIZE-1)); | 1332 | return (xfs_caddr_t)page_address(page) + (offset & (PAGE_SIZE-1)); |
| 1463 | } | 1333 | } |
| 1464 | 1334 | ||
| 1465 | /* | 1335 | /* |
| @@ -1481,9 +1351,9 @@ xfs_buf_iomove( | |||
| 1481 | page = bp->b_pages[xfs_buf_btoct(boff + bp->b_offset)]; | 1351 | page = bp->b_pages[xfs_buf_btoct(boff + bp->b_offset)]; |
| 1482 | cpoff = xfs_buf_poff(boff + bp->b_offset); | 1352 | cpoff = xfs_buf_poff(boff + bp->b_offset); |
| 1483 | csize = min_t(size_t, | 1353 | csize = min_t(size_t, |
| 1484 | PAGE_CACHE_SIZE-cpoff, bp->b_count_desired-boff); | 1354 | PAGE_SIZE-cpoff, bp->b_count_desired-boff); |
| 1485 | 1355 | ||
| 1486 | ASSERT(((csize + cpoff) <= PAGE_CACHE_SIZE)); | 1356 | ASSERT(((csize + cpoff) <= PAGE_SIZE)); |
| 1487 | 1357 | ||
| 1488 | switch (mode) { | 1358 | switch (mode) { |
| 1489 | case XBRW_ZERO: | 1359 | case XBRW_ZERO: |
| @@ -1596,7 +1466,6 @@ xfs_free_buftarg( | |||
| 1596 | xfs_flush_buftarg(btp, 1); | 1466 | xfs_flush_buftarg(btp, 1); |
| 1597 | if (mp->m_flags & XFS_MOUNT_BARRIER) | 1467 | if (mp->m_flags & XFS_MOUNT_BARRIER) |
| 1598 | xfs_blkdev_issue_flush(btp); | 1468 | xfs_blkdev_issue_flush(btp); |
| 1599 | iput(btp->bt_mapping->host); | ||
| 1600 | 1469 | ||
| 1601 | kthread_stop(btp->bt_task); | 1470 | kthread_stop(btp->bt_task); |
| 1602 | kmem_free(btp); | 1471 | kmem_free(btp); |
| @@ -1620,15 +1489,6 @@ xfs_setsize_buftarg_flags( | |||
| 1620 | return EINVAL; | 1489 | return EINVAL; |
| 1621 | } | 1490 | } |
| 1622 | 1491 | ||
| 1623 | if (verbose && | ||
| 1624 | (PAGE_CACHE_SIZE / BITS_PER_LONG) > sectorsize) { | ||
| 1625 | printk(KERN_WARNING | ||
| 1626 | "XFS: %u byte sectors in use on device %s. " | ||
| 1627 | "This is suboptimal; %u or greater is ideal.\n", | ||
| 1628 | sectorsize, XFS_BUFTARG_NAME(btp), | ||
| 1629 | (unsigned int)PAGE_CACHE_SIZE / BITS_PER_LONG); | ||
| 1630 | } | ||
| 1631 | |||
| 1632 | return 0; | 1492 | return 0; |
| 1633 | } | 1493 | } |
| 1634 | 1494 | ||
| @@ -1643,7 +1503,7 @@ xfs_setsize_buftarg_early( | |||
| 1643 | struct block_device *bdev) | 1503 | struct block_device *bdev) |
| 1644 | { | 1504 | { |
| 1645 | return xfs_setsize_buftarg_flags(btp, | 1505 | return xfs_setsize_buftarg_flags(btp, |
| 1646 | PAGE_CACHE_SIZE, bdev_logical_block_size(bdev), 0); | 1506 | PAGE_SIZE, bdev_logical_block_size(bdev), 0); |
| 1647 | } | 1507 | } |
| 1648 | 1508 | ||
| 1649 | int | 1509 | int |
| @@ -1656,40 +1516,6 @@ xfs_setsize_buftarg( | |||
| 1656 | } | 1516 | } |
| 1657 | 1517 | ||
| 1658 | STATIC int | 1518 | STATIC int |
| 1659 | xfs_mapping_buftarg( | ||
| 1660 | xfs_buftarg_t *btp, | ||
| 1661 | struct block_device *bdev) | ||
| 1662 | { | ||
| 1663 | struct backing_dev_info *bdi; | ||
| 1664 | struct inode *inode; | ||
| 1665 | struct address_space *mapping; | ||
| 1666 | static const struct address_space_operations mapping_aops = { | ||
| 1667 | .migratepage = fail_migrate_page, | ||
| 1668 | }; | ||
| 1669 | |||
| 1670 | inode = new_inode(bdev->bd_inode->i_sb); | ||
| 1671 | if (!inode) { | ||
| 1672 | printk(KERN_WARNING | ||
| 1673 | "XFS: Cannot allocate mapping inode for device %s\n", | ||
| 1674 | XFS_BUFTARG_NAME(btp)); | ||
| 1675 | return ENOMEM; | ||
| 1676 | } | ||
| 1677 | inode->i_ino = get_next_ino(); | ||
| 1678 | inode->i_mode = S_IFBLK; | ||
| 1679 | inode->i_bdev = bdev; | ||
| 1680 | inode->i_rdev = bdev->bd_dev; | ||
| 1681 | bdi = blk_get_backing_dev_info(bdev); | ||
| 1682 | if (!bdi) | ||
| 1683 | bdi = &default_backing_dev_info; | ||
| 1684 | mapping = &inode->i_data; | ||
| 1685 | mapping->a_ops = &mapping_aops; | ||
| 1686 | mapping->backing_dev_info = bdi; | ||
| 1687 | mapping_set_gfp_mask(mapping, GFP_NOFS); | ||
| 1688 | btp->bt_mapping = mapping; | ||
| 1689 | return 0; | ||
| 1690 | } | ||
| 1691 | |||
| 1692 | STATIC int | ||
| 1693 | xfs_alloc_delwrite_queue( | 1519 | xfs_alloc_delwrite_queue( |
| 1694 | xfs_buftarg_t *btp, | 1520 | xfs_buftarg_t *btp, |
| 1695 | const char *fsname) | 1521 | const char *fsname) |
| @@ -1717,12 +1543,14 @@ xfs_alloc_buftarg( | |||
| 1717 | btp->bt_mount = mp; | 1543 | btp->bt_mount = mp; |
| 1718 | btp->bt_dev = bdev->bd_dev; | 1544 | btp->bt_dev = bdev->bd_dev; |
| 1719 | btp->bt_bdev = bdev; | 1545 | btp->bt_bdev = bdev; |
| 1546 | btp->bt_bdi = blk_get_backing_dev_info(bdev); | ||
| 1547 | if (!btp->bt_bdi) | ||
| 1548 | goto error; | ||
| 1549 | |||
| 1720 | INIT_LIST_HEAD(&btp->bt_lru); | 1550 | INIT_LIST_HEAD(&btp->bt_lru); |
| 1721 | spin_lock_init(&btp->bt_lru_lock); | 1551 | spin_lock_init(&btp->bt_lru_lock); |
| 1722 | if (xfs_setsize_buftarg_early(btp, bdev)) | 1552 | if (xfs_setsize_buftarg_early(btp, bdev)) |
| 1723 | goto error; | 1553 | goto error; |
| 1724 | if (xfs_mapping_buftarg(btp, bdev)) | ||
| 1725 | goto error; | ||
| 1726 | if (xfs_alloc_delwrite_queue(btp, fsname)) | 1554 | if (xfs_alloc_delwrite_queue(btp, fsname)) |
| 1727 | goto error; | 1555 | goto error; |
| 1728 | btp->bt_shrinker.shrink = xfs_buftarg_shrink; | 1556 | btp->bt_shrinker.shrink = xfs_buftarg_shrink; |
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index cbe65950e524..a9a1c4512645 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h | |||
| @@ -61,30 +61,11 @@ typedef enum { | |||
| 61 | #define XBF_DONT_BLOCK (1 << 16)/* do not block in current thread */ | 61 | #define XBF_DONT_BLOCK (1 << 16)/* do not block in current thread */ |
| 62 | 62 | ||
| 63 | /* flags used only internally */ | 63 | /* flags used only internally */ |
| 64 | #define _XBF_PAGE_CACHE (1 << 17)/* backed by pagecache */ | ||
| 65 | #define _XBF_PAGES (1 << 18)/* backed by refcounted pages */ | 64 | #define _XBF_PAGES (1 << 18)/* backed by refcounted pages */ |
| 66 | #define _XBF_RUN_QUEUES (1 << 19)/* run block device task queue */ | 65 | #define _XBF_RUN_QUEUES (1 << 19)/* run block device task queue */ |
| 66 | #define _XBF_KMEM (1 << 20)/* backed by heap memory */ | ||
| 67 | #define _XBF_DELWRI_Q (1 << 21)/* buffer on delwri queue */ | 67 | #define _XBF_DELWRI_Q (1 << 21)/* buffer on delwri queue */ |
| 68 | 68 | ||
| 69 | /* | ||
| 70 | * Special flag for supporting metadata blocks smaller than a FSB. | ||
| 71 | * | ||
| 72 | * In this case we can have multiple xfs_buf_t on a single page and | ||
| 73 | * need to lock out concurrent xfs_buf_t readers as they only | ||
| 74 | * serialise access to the buffer. | ||
| 75 | * | ||
| 76 | * If the FSB size >= PAGE_CACHE_SIZE case, we have no serialisation | ||
| 77 | * between reads of the page. Hence we can have one thread read the | ||
| 78 | * page and modify it, but then race with another thread that thinks | ||
| 79 | * the page is not up-to-date and hence reads it again. | ||
| 80 | * | ||
| 81 | * The result is that the first modifcation to the page is lost. | ||
| 82 | * This sort of AGF/AGI reading race can happen when unlinking inodes | ||
| 83 | * that require truncation and results in the AGI unlinked list | ||
| 84 | * modifications being lost. | ||
| 85 | */ | ||
| 86 | #define _XBF_PAGE_LOCKED (1 << 22) | ||
| 87 | |||
| 88 | typedef unsigned int xfs_buf_flags_t; | 69 | typedef unsigned int xfs_buf_flags_t; |
| 89 | 70 | ||
| 90 | #define XFS_BUF_FLAGS \ | 71 | #define XFS_BUF_FLAGS \ |
| @@ -100,12 +81,10 @@ typedef unsigned int xfs_buf_flags_t; | |||
| 100 | { XBF_LOCK, "LOCK" }, /* should never be set */\ | 81 | { XBF_LOCK, "LOCK" }, /* should never be set */\ |
| 101 | { XBF_TRYLOCK, "TRYLOCK" }, /* ditto */\ | 82 | { XBF_TRYLOCK, "TRYLOCK" }, /* ditto */\ |
| 102 | { XBF_DONT_BLOCK, "DONT_BLOCK" }, /* ditto */\ | 83 | { XBF_DONT_BLOCK, "DONT_BLOCK" }, /* ditto */\ |
| 103 | { _XBF_PAGE_CACHE, "PAGE_CACHE" }, \ | ||
| 104 | { _XBF_PAGES, "PAGES" }, \ | 84 | { _XBF_PAGES, "PAGES" }, \ |
| 105 | { _XBF_RUN_QUEUES, "RUN_QUEUES" }, \ | 85 | { _XBF_RUN_QUEUES, "RUN_QUEUES" }, \ |
| 106 | { _XBF_DELWRI_Q, "DELWRI_Q" }, \ | 86 | { _XBF_KMEM, "KMEM" }, \ |
| 107 | { _XBF_PAGE_LOCKED, "PAGE_LOCKED" } | 87 | { _XBF_DELWRI_Q, "DELWRI_Q" } |
| 108 | |||
| 109 | 88 | ||
| 110 | typedef enum { | 89 | typedef enum { |
| 111 | XBT_FORCE_SLEEP = 0, | 90 | XBT_FORCE_SLEEP = 0, |
| @@ -120,7 +99,7 @@ typedef struct xfs_bufhash { | |||
| 120 | typedef struct xfs_buftarg { | 99 | typedef struct xfs_buftarg { |
| 121 | dev_t bt_dev; | 100 | dev_t bt_dev; |
| 122 | struct block_device *bt_bdev; | 101 | struct block_device *bt_bdev; |
| 123 | struct address_space *bt_mapping; | 102 | struct backing_dev_info *bt_bdi; |
| 124 | struct xfs_mount *bt_mount; | 103 | struct xfs_mount *bt_mount; |
| 125 | unsigned int bt_bsize; | 104 | unsigned int bt_bsize; |
| 126 | unsigned int bt_sshift; | 105 | unsigned int bt_sshift; |
| @@ -139,17 +118,6 @@ typedef struct xfs_buftarg { | |||
| 139 | unsigned int bt_lru_nr; | 118 | unsigned int bt_lru_nr; |
| 140 | } xfs_buftarg_t; | 119 | } xfs_buftarg_t; |
| 141 | 120 | ||
| 142 | /* | ||
| 143 | * xfs_buf_t: Buffer structure for pagecache-based buffers | ||
| 144 | * | ||
| 145 | * This buffer structure is used by the pagecache buffer management routines | ||
| 146 | * to refer to an assembly of pages forming a logical buffer. | ||
| 147 | * | ||
| 148 | * The buffer structure is used on a temporary basis only, and discarded when | ||
| 149 | * released. The real data storage is recorded in the pagecache. Buffers are | ||
| 150 | * hashed to the block device on which the file system resides. | ||
| 151 | */ | ||
| 152 | |||
| 153 | struct xfs_buf; | 121 | struct xfs_buf; |
| 154 | typedef void (*xfs_buf_iodone_t)(struct xfs_buf *); | 122 | typedef void (*xfs_buf_iodone_t)(struct xfs_buf *); |
| 155 | 123 | ||
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index a55c1b46b219..52aadfbed132 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
| @@ -896,6 +896,7 @@ xfs_file_fallocate( | |||
| 896 | xfs_flock64_t bf; | 896 | xfs_flock64_t bf; |
| 897 | xfs_inode_t *ip = XFS_I(inode); | 897 | xfs_inode_t *ip = XFS_I(inode); |
| 898 | int cmd = XFS_IOC_RESVSP; | 898 | int cmd = XFS_IOC_RESVSP; |
| 899 | int attr_flags = XFS_ATTR_NOLOCK; | ||
| 899 | 900 | ||
| 900 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | 901 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) |
| 901 | return -EOPNOTSUPP; | 902 | return -EOPNOTSUPP; |
| @@ -918,7 +919,10 @@ xfs_file_fallocate( | |||
| 918 | goto out_unlock; | 919 | goto out_unlock; |
| 919 | } | 920 | } |
| 920 | 921 | ||
| 921 | error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK); | 922 | if (file->f_flags & O_DSYNC) |
| 923 | attr_flags |= XFS_ATTR_SYNC; | ||
| 924 | |||
| 925 | error = -xfs_change_file_space(ip, cmd, &bf, 0, attr_flags); | ||
| 922 | if (error) | 926 | if (error) |
| 923 | goto out_unlock; | 927 | goto out_unlock; |
| 924 | 928 | ||
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 0ca0e3c024d7..acca2c5ca3fa 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
| @@ -624,6 +624,10 @@ xfs_ioc_space( | |||
| 624 | 624 | ||
| 625 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 625 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) |
| 626 | attr_flags |= XFS_ATTR_NONBLOCK; | 626 | attr_flags |= XFS_ATTR_NONBLOCK; |
| 627 | |||
| 628 | if (filp->f_flags & O_DSYNC) | ||
| 629 | attr_flags |= XFS_ATTR_SYNC; | ||
| 630 | |||
| 627 | if (ioflags & IO_INVIS) | 631 | if (ioflags & IO_INVIS) |
| 628 | attr_flags |= XFS_ATTR_DMI; | 632 | attr_flags |= XFS_ATTR_DMI; |
| 629 | 633 | ||
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 818c4cf2de86..1ba5c451da36 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -1078,7 +1078,7 @@ xfs_fs_write_inode( | |||
| 1078 | error = 0; | 1078 | error = 0; |
| 1079 | goto out_unlock; | 1079 | goto out_unlock; |
| 1080 | } | 1080 | } |
| 1081 | error = xfs_iflush(ip, 0); | 1081 | error = xfs_iflush(ip, SYNC_TRYLOCK); |
| 1082 | } | 1082 | } |
| 1083 | 1083 | ||
| 1084 | out_unlock: | 1084 | out_unlock: |
| @@ -1539,10 +1539,14 @@ xfs_fs_fill_super( | |||
| 1539 | if (error) | 1539 | if (error) |
| 1540 | goto out_free_sb; | 1540 | goto out_free_sb; |
| 1541 | 1541 | ||
| 1542 | error = xfs_mountfs(mp); | 1542 | /* |
| 1543 | if (error) | 1543 | * we must configure the block size in the superblock before we run the |
| 1544 | goto out_filestream_unmount; | 1544 | * full mount process as the mount process can lookup and cache inodes. |
| 1545 | 1545 | * For the same reason we must also initialise the syncd and register | |
| 1546 | * the inode cache shrinker so that inodes can be reclaimed during | ||
| 1547 | * operations like a quotacheck that iterate all inodes in the | ||
| 1548 | * filesystem. | ||
| 1549 | */ | ||
| 1546 | sb->s_magic = XFS_SB_MAGIC; | 1550 | sb->s_magic = XFS_SB_MAGIC; |
| 1547 | sb->s_blocksize = mp->m_sb.sb_blocksize; | 1551 | sb->s_blocksize = mp->m_sb.sb_blocksize; |
| 1548 | sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; | 1552 | sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; |
| @@ -1550,6 +1554,16 @@ xfs_fs_fill_super( | |||
| 1550 | sb->s_time_gran = 1; | 1554 | sb->s_time_gran = 1; |
| 1551 | set_posix_acl_flag(sb); | 1555 | set_posix_acl_flag(sb); |
| 1552 | 1556 | ||
| 1557 | error = xfs_syncd_init(mp); | ||
| 1558 | if (error) | ||
| 1559 | goto out_filestream_unmount; | ||
| 1560 | |||
| 1561 | xfs_inode_shrinker_register(mp); | ||
| 1562 | |||
| 1563 | error = xfs_mountfs(mp); | ||
| 1564 | if (error) | ||
| 1565 | goto out_syncd_stop; | ||
| 1566 | |||
| 1553 | root = igrab(VFS_I(mp->m_rootip)); | 1567 | root = igrab(VFS_I(mp->m_rootip)); |
| 1554 | if (!root) { | 1568 | if (!root) { |
| 1555 | error = ENOENT; | 1569 | error = ENOENT; |
| @@ -1565,14 +1579,11 @@ xfs_fs_fill_super( | |||
| 1565 | goto fail_vnrele; | 1579 | goto fail_vnrele; |
| 1566 | } | 1580 | } |
| 1567 | 1581 | ||
| 1568 | error = xfs_syncd_init(mp); | ||
| 1569 | if (error) | ||
| 1570 | goto fail_vnrele; | ||
| 1571 | |||
| 1572 | xfs_inode_shrinker_register(mp); | ||
| 1573 | |||
| 1574 | return 0; | 1582 | return 0; |
| 1575 | 1583 | ||
| 1584 | out_syncd_stop: | ||
| 1585 | xfs_inode_shrinker_unregister(mp); | ||
| 1586 | xfs_syncd_stop(mp); | ||
| 1576 | out_filestream_unmount: | 1587 | out_filestream_unmount: |
| 1577 | xfs_filestream_unmount(mp); | 1588 | xfs_filestream_unmount(mp); |
| 1578 | out_free_sb: | 1589 | out_free_sb: |
| @@ -1596,6 +1607,9 @@ xfs_fs_fill_super( | |||
| 1596 | } | 1607 | } |
| 1597 | 1608 | ||
| 1598 | fail_unmount: | 1609 | fail_unmount: |
| 1610 | xfs_inode_shrinker_unregister(mp); | ||
| 1611 | xfs_syncd_stop(mp); | ||
| 1612 | |||
| 1599 | /* | 1613 | /* |
| 1600 | * Blow away any referenced inode in the filestreams cache. | 1614 | * Blow away any referenced inode in the filestreams cache. |
| 1601 | * This can and will cause log traffic as inodes go inactive | 1615 | * This can and will cause log traffic as inodes go inactive |
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 6c10f1d2e3d3..594cd822d84d 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
| @@ -761,8 +761,10 @@ xfs_reclaim_inode( | |||
| 761 | struct xfs_perag *pag, | 761 | struct xfs_perag *pag, |
| 762 | int sync_mode) | 762 | int sync_mode) |
| 763 | { | 763 | { |
| 764 | int error = 0; | 764 | int error; |
| 765 | 765 | ||
| 766 | restart: | ||
| 767 | error = 0; | ||
| 766 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 768 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
| 767 | if (!xfs_iflock_nowait(ip)) { | 769 | if (!xfs_iflock_nowait(ip)) { |
| 768 | if (!(sync_mode & SYNC_WAIT)) | 770 | if (!(sync_mode & SYNC_WAIT)) |
| @@ -788,9 +790,31 @@ xfs_reclaim_inode( | |||
| 788 | if (xfs_inode_clean(ip)) | 790 | if (xfs_inode_clean(ip)) |
| 789 | goto reclaim; | 791 | goto reclaim; |
| 790 | 792 | ||
| 791 | /* Now we have an inode that needs flushing */ | 793 | /* |
| 792 | error = xfs_iflush(ip, sync_mode); | 794 | * Now we have an inode that needs flushing. |
| 795 | * | ||
| 796 | * We do a nonblocking flush here even if we are doing a SYNC_WAIT | ||
| 797 | * reclaim as we can deadlock with inode cluster removal. | ||
| 798 | * xfs_ifree_cluster() can lock the inode buffer before it locks the | ||
| 799 | * ip->i_lock, and we are doing the exact opposite here. As a result, | ||
| 800 | * doing a blocking xfs_itobp() to get the cluster buffer will result | ||
| 801 | * in an ABBA deadlock with xfs_ifree_cluster(). | ||
| 802 | * | ||
| 803 | * As xfs_ifree_cluser() must gather all inodes that are active in the | ||
| 804 | * cache to mark them stale, if we hit this case we don't actually want | ||
| 805 | * to do IO here - we want the inode marked stale so we can simply | ||
| 806 | * reclaim it. Hence if we get an EAGAIN error on a SYNC_WAIT flush, | ||
| 807 | * just unlock the inode, back off and try again. Hopefully the next | ||
| 808 | * pass through will see the stale flag set on the inode. | ||
| 809 | */ | ||
| 810 | error = xfs_iflush(ip, SYNC_TRYLOCK | sync_mode); | ||
| 793 | if (sync_mode & SYNC_WAIT) { | 811 | if (sync_mode & SYNC_WAIT) { |
| 812 | if (error == EAGAIN) { | ||
| 813 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
| 814 | /* backoff longer than in xfs_ifree_cluster */ | ||
| 815 | delay(2); | ||
| 816 | goto restart; | ||
| 817 | } | ||
| 794 | xfs_iflock(ip); | 818 | xfs_iflock(ip); |
| 795 | goto reclaim; | 819 | goto reclaim; |
| 796 | } | 820 | } |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index da871f532236..742c8330994a 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -2835,7 +2835,7 @@ xfs_iflush( | |||
| 2835 | * Get the buffer containing the on-disk inode. | 2835 | * Get the buffer containing the on-disk inode. |
| 2836 | */ | 2836 | */ |
| 2837 | error = xfs_itobp(mp, NULL, ip, &dip, &bp, | 2837 | error = xfs_itobp(mp, NULL, ip, &dip, &bp, |
| 2838 | (flags & SYNC_WAIT) ? XBF_LOCK : XBF_TRYLOCK); | 2838 | (flags & SYNC_TRYLOCK) ? XBF_TRYLOCK : XBF_LOCK); |
| 2839 | if (error || !bp) { | 2839 | if (error || !bp) { |
| 2840 | xfs_ifunlock(ip); | 2840 | xfs_ifunlock(ip); |
| 2841 | return error; | 2841 | return error; |
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index fd4f398bd6f1..46cc40131d4a 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
| @@ -760,11 +760,11 @@ xfs_inode_item_push( | |||
| 760 | * Push the inode to it's backing buffer. This will not remove the | 760 | * Push the inode to it's backing buffer. This will not remove the |
| 761 | * inode from the AIL - a further push will be required to trigger a | 761 | * inode from the AIL - a further push will be required to trigger a |
| 762 | * buffer push. However, this allows all the dirty inodes to be pushed | 762 | * buffer push. However, this allows all the dirty inodes to be pushed |
| 763 | * to the buffer before it is pushed to disk. THe buffer IO completion | 763 | * to the buffer before it is pushed to disk. The buffer IO completion |
| 764 | * will pull th einode from the AIL, mark it clean and unlock the flush | 764 | * will pull the inode from the AIL, mark it clean and unlock the flush |
| 765 | * lock. | 765 | * lock. |
| 766 | */ | 766 | */ |
| 767 | (void) xfs_iflush(ip, 0); | 767 | (void) xfs_iflush(ip, SYNC_TRYLOCK); |
| 768 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 768 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 769 | } | 769 | } |
| 770 | 770 | ||
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index 3bea66132334..03b3b7f85a3b 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
| @@ -383,7 +383,8 @@ xfs_trans_read_buf( | |||
| 383 | bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK); | 383 | bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK); |
| 384 | if (bp == NULL) { | 384 | if (bp == NULL) { |
| 385 | *bpp = NULL; | 385 | *bpp = NULL; |
| 386 | return 0; | 386 | return (flags & XBF_TRYLOCK) ? |
| 387 | 0 : XFS_ERROR(ENOMEM); | ||
| 387 | } | 388 | } |
| 388 | if (XFS_BUF_GETERROR(bp) != 0) { | 389 | if (XFS_BUF_GETERROR(bp) != 0) { |
| 389 | XFS_BUF_SUPER_STALE(bp); | 390 | XFS_BUF_SUPER_STALE(bp); |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 37d8146ee15b..c48b4217ec47 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -2831,7 +2831,8 @@ xfs_change_file_space( | |||
| 2831 | ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; | 2831 | ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; |
| 2832 | 2832 | ||
| 2833 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 2833 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 2834 | xfs_trans_set_sync(tp); | 2834 | if (attr_flags & XFS_ATTR_SYNC) |
| 2835 | xfs_trans_set_sync(tp); | ||
| 2835 | 2836 | ||
| 2836 | error = xfs_trans_commit(tp, 0); | 2837 | error = xfs_trans_commit(tp, 0); |
| 2837 | 2838 | ||
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index f6702927eee4..3bcd23353d6c 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h | |||
| @@ -18,6 +18,7 @@ int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags); | |||
| 18 | #define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */ | 18 | #define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */ |
| 19 | #define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */ | 19 | #define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */ |
| 20 | #define XFS_ATTR_NOACL 0x08 /* Don't call xfs_acl_chmod */ | 20 | #define XFS_ATTR_NOACL 0x08 /* Don't call xfs_acl_chmod */ |
| 21 | #define XFS_ATTR_SYNC 0x10 /* synchronous operation required */ | ||
| 21 | 22 | ||
| 22 | int xfs_readlink(struct xfs_inode *ip, char *link); | 23 | int xfs_readlink(struct xfs_inode *ip, char *link); |
| 23 | int xfs_release(struct xfs_inode *ip); | 24 | int xfs_release(struct xfs_inode *ip); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index b677bd77f2d6..52f283c1edb2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -357,6 +357,8 @@ struct inodes_stat_t { | |||
| 357 | #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ | 357 | #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ |
| 358 | #define FS_EXTENT_FL 0x00080000 /* Extents */ | 358 | #define FS_EXTENT_FL 0x00080000 /* Extents */ |
| 359 | #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ | 359 | #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ |
| 360 | #define FS_NOCOW_FL 0x00800000 /* Do not cow file */ | ||
| 361 | #define FS_COW_FL 0x02000000 /* Cow file */ | ||
| 360 | #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ | 362 | #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ |
| 361 | 363 | ||
| 362 | #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ | 364 | #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ |
diff --git a/include/linux/input.h b/include/linux/input.h index 056ae8a5bd9b..f3a7794a18c4 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
| @@ -664,6 +664,13 @@ struct input_keymap_entry { | |||
| 664 | #define KEY_TOUCHPAD_ON 0x213 | 664 | #define KEY_TOUCHPAD_ON 0x213 |
| 665 | #define KEY_TOUCHPAD_OFF 0x214 | 665 | #define KEY_TOUCHPAD_OFF 0x214 |
| 666 | 666 | ||
| 667 | #define KEY_CAMERA_ZOOMIN 0x215 | ||
| 668 | #define KEY_CAMERA_ZOOMOUT 0x216 | ||
| 669 | #define KEY_CAMERA_UP 0x217 | ||
| 670 | #define KEY_CAMERA_DOWN 0x218 | ||
| 671 | #define KEY_CAMERA_LEFT 0x219 | ||
| 672 | #define KEY_CAMERA_RIGHT 0x21a | ||
| 673 | |||
| 667 | #define BTN_TRIGGER_HAPPY 0x2c0 | 674 | #define BTN_TRIGGER_HAPPY 0x2c0 |
| 668 | #define BTN_TRIGGER_HAPPY1 0x2c0 | 675 | #define BTN_TRIGGER_HAPPY1 0x2c0 |
| 669 | #define BTN_TRIGGER_HAPPY2 0x2c1 | 676 | #define BTN_TRIGGER_HAPPY2 0x2c1 |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 5d876c9b3a3d..b3741c83774c 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
| @@ -135,7 +135,7 @@ struct msi_desc; | |||
| 135 | * struct irq_data - per irq and irq chip data passed down to chip functions | 135 | * struct irq_data - per irq and irq chip data passed down to chip functions |
| 136 | * @irq: interrupt number | 136 | * @irq: interrupt number |
| 137 | * @node: node index useful for balancing | 137 | * @node: node index useful for balancing |
| 138 | * @state_use_accessor: status information for irq chip functions. | 138 | * @state_use_accessors: status information for irq chip functions. |
| 139 | * Use accessor functions to deal with it | 139 | * Use accessor functions to deal with it |
| 140 | * @chip: low level interrupt hardware access | 140 | * @chip: low level interrupt hardware access |
| 141 | * @handler_data: per-IRQ data for the irq_chip methods | 141 | * @handler_data: per-IRQ data for the irq_chip methods |
| @@ -174,6 +174,9 @@ struct irq_data { | |||
| 174 | * from suspend | 174 | * from suspend |
| 175 | * IRDQ_MOVE_PCNTXT - Interrupt can be moved in process | 175 | * IRDQ_MOVE_PCNTXT - Interrupt can be moved in process |
| 176 | * context | 176 | * context |
| 177 | * IRQD_IRQ_DISABLED - Disabled state of the interrupt | ||
| 178 | * IRQD_IRQ_MASKED - Masked state of the interrupt | ||
| 179 | * IRQD_IRQ_INPROGRESS - In progress state of the interrupt | ||
| 177 | */ | 180 | */ |
| 178 | enum { | 181 | enum { |
| 179 | IRQD_TRIGGER_MASK = 0xf, | 182 | IRQD_TRIGGER_MASK = 0xf, |
| @@ -184,6 +187,9 @@ enum { | |||
| 184 | IRQD_LEVEL = (1 << 13), | 187 | IRQD_LEVEL = (1 << 13), |
| 185 | IRQD_WAKEUP_STATE = (1 << 14), | 188 | IRQD_WAKEUP_STATE = (1 << 14), |
| 186 | IRQD_MOVE_PCNTXT = (1 << 15), | 189 | IRQD_MOVE_PCNTXT = (1 << 15), |
| 190 | IRQD_IRQ_DISABLED = (1 << 16), | ||
| 191 | IRQD_IRQ_MASKED = (1 << 17), | ||
| 192 | IRQD_IRQ_INPROGRESS = (1 << 18), | ||
| 187 | }; | 193 | }; |
| 188 | 194 | ||
| 189 | static inline bool irqd_is_setaffinity_pending(struct irq_data *d) | 195 | static inline bool irqd_is_setaffinity_pending(struct irq_data *d) |
| @@ -206,6 +212,11 @@ static inline bool irqd_affinity_was_set(struct irq_data *d) | |||
| 206 | return d->state_use_accessors & IRQD_AFFINITY_SET; | 212 | return d->state_use_accessors & IRQD_AFFINITY_SET; |
| 207 | } | 213 | } |
| 208 | 214 | ||
| 215 | static inline void irqd_mark_affinity_was_set(struct irq_data *d) | ||
| 216 | { | ||
| 217 | d->state_use_accessors |= IRQD_AFFINITY_SET; | ||
| 218 | } | ||
| 219 | |||
| 209 | static inline u32 irqd_get_trigger_type(struct irq_data *d) | 220 | static inline u32 irqd_get_trigger_type(struct irq_data *d) |
| 210 | { | 221 | { |
| 211 | return d->state_use_accessors & IRQD_TRIGGER_MASK; | 222 | return d->state_use_accessors & IRQD_TRIGGER_MASK; |
| @@ -235,6 +246,36 @@ static inline bool irqd_can_move_in_process_context(struct irq_data *d) | |||
| 235 | return d->state_use_accessors & IRQD_MOVE_PCNTXT; | 246 | return d->state_use_accessors & IRQD_MOVE_PCNTXT; |
| 236 | } | 247 | } |
| 237 | 248 | ||
| 249 | static inline bool irqd_irq_disabled(struct irq_data *d) | ||
| 250 | { | ||
| 251 | return d->state_use_accessors & IRQD_IRQ_DISABLED; | ||
| 252 | } | ||
| 253 | |||
| 254 | static inline bool irqd_irq_masked(struct irq_data *d) | ||
| 255 | { | ||
| 256 | return d->state_use_accessors & IRQD_IRQ_MASKED; | ||
| 257 | } | ||
| 258 | |||
| 259 | static inline bool irqd_irq_inprogress(struct irq_data *d) | ||
| 260 | { | ||
| 261 | return d->state_use_accessors & IRQD_IRQ_INPROGRESS; | ||
| 262 | } | ||
| 263 | |||
| 264 | /* | ||
| 265 | * Functions for chained handlers which can be enabled/disabled by the | ||
| 266 | * standard disable_irq/enable_irq calls. Must be called with | ||
| 267 | * irq_desc->lock held. | ||
| 268 | */ | ||
| 269 | static inline void irqd_set_chained_irq_inprogress(struct irq_data *d) | ||
| 270 | { | ||
| 271 | d->state_use_accessors |= IRQD_IRQ_INPROGRESS; | ||
| 272 | } | ||
| 273 | |||
| 274 | static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) | ||
| 275 | { | ||
| 276 | d->state_use_accessors &= ~IRQD_IRQ_INPROGRESS; | ||
| 277 | } | ||
| 278 | |||
| 238 | /** | 279 | /** |
| 239 | * struct irq_chip - hardware interrupt chip descriptor | 280 | * struct irq_chip - hardware interrupt chip descriptor |
| 240 | * | 281 | * |
| @@ -271,6 +312,8 @@ static inline bool irqd_can_move_in_process_context(struct irq_data *d) | |||
| 271 | * @irq_set_wake: enable/disable power-management wake-on of an IRQ | 312 | * @irq_set_wake: enable/disable power-management wake-on of an IRQ |
| 272 | * @irq_bus_lock: function to lock access to slow bus (i2c) chips | 313 | * @irq_bus_lock: function to lock access to slow bus (i2c) chips |
| 273 | * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips | 314 | * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips |
| 315 | * @irq_cpu_online: configure an interrupt source for a secondary CPU | ||
| 316 | * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU | ||
| 274 | * @irq_print_chip: optional to print special chip info in show_interrupts | 317 | * @irq_print_chip: optional to print special chip info in show_interrupts |
| 275 | * @flags: chip specific flags | 318 | * @flags: chip specific flags |
| 276 | * | 319 | * |
| @@ -319,6 +362,9 @@ struct irq_chip { | |||
| 319 | void (*irq_bus_lock)(struct irq_data *data); | 362 | void (*irq_bus_lock)(struct irq_data *data); |
| 320 | void (*irq_bus_sync_unlock)(struct irq_data *data); | 363 | void (*irq_bus_sync_unlock)(struct irq_data *data); |
| 321 | 364 | ||
| 365 | void (*irq_cpu_online)(struct irq_data *data); | ||
| 366 | void (*irq_cpu_offline)(struct irq_data *data); | ||
| 367 | |||
| 322 | void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); | 368 | void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); |
| 323 | 369 | ||
| 324 | unsigned long flags; | 370 | unsigned long flags; |
| @@ -335,11 +381,14 @@ struct irq_chip { | |||
| 335 | * IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type() | 381 | * IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type() |
| 336 | * IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled | 382 | * IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled |
| 337 | * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path | 383 | * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path |
| 384 | * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks | ||
| 385 | * when irq enabled | ||
| 338 | */ | 386 | */ |
| 339 | enum { | 387 | enum { |
| 340 | IRQCHIP_SET_TYPE_MASKED = (1 << 0), | 388 | IRQCHIP_SET_TYPE_MASKED = (1 << 0), |
| 341 | IRQCHIP_EOI_IF_HANDLED = (1 << 1), | 389 | IRQCHIP_EOI_IF_HANDLED = (1 << 1), |
| 342 | IRQCHIP_MASK_ON_SUSPEND = (1 << 2), | 390 | IRQCHIP_MASK_ON_SUSPEND = (1 << 2), |
| 391 | IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), | ||
| 343 | }; | 392 | }; |
| 344 | 393 | ||
| 345 | /* This include will go away once we isolated irq_desc usage to core code */ | 394 | /* This include will go away once we isolated irq_desc usage to core code */ |
| @@ -364,6 +413,10 @@ struct irqaction; | |||
| 364 | extern int setup_irq(unsigned int irq, struct irqaction *new); | 413 | extern int setup_irq(unsigned int irq, struct irqaction *new); |
| 365 | extern void remove_irq(unsigned int irq, struct irqaction *act); | 414 | extern void remove_irq(unsigned int irq, struct irqaction *act); |
| 366 | 415 | ||
| 416 | extern void irq_cpu_online(void); | ||
| 417 | extern void irq_cpu_offline(void); | ||
| 418 | extern int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *cpumask); | ||
| 419 | |||
| 367 | #ifdef CONFIG_GENERIC_HARDIRQS | 420 | #ifdef CONFIG_GENERIC_HARDIRQS |
| 368 | 421 | ||
| 369 | #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) | 422 | #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) |
| @@ -380,9 +433,6 @@ static inline void irq_move_masked_irq(struct irq_data *data) { } | |||
| 380 | 433 | ||
| 381 | extern int no_irq_affinity; | 434 | extern int no_irq_affinity; |
| 382 | 435 | ||
| 383 | /* Handle irq action chains: */ | ||
| 384 | extern irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action); | ||
| 385 | |||
| 386 | /* | 436 | /* |
| 387 | * Built-in IRQ handlers for various IRQ types, | 437 | * Built-in IRQ handlers for various IRQ types, |
| 388 | * callable via desc->handle_irq() | 438 | * callable via desc->handle_irq() |
| @@ -390,6 +440,7 @@ extern irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action); | |||
| 390 | extern void handle_level_irq(unsigned int irq, struct irq_desc *desc); | 440 | extern void handle_level_irq(unsigned int irq, struct irq_desc *desc); |
| 391 | extern void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc); | 441 | extern void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc); |
| 392 | extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc); | 442 | extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc); |
| 443 | extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc); | ||
| 393 | extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc); | 444 | extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc); |
| 394 | extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); | 445 | extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); |
| 395 | extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); | 446 | extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); |
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index 6e4f77ef4d20..b31843075198 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h | |||
| @@ -74,6 +74,45 @@ | |||
| 74 | #define AB8500_INT_ACC_DETECT_21DB_F 37 | 74 | #define AB8500_INT_ACC_DETECT_21DB_F 37 |
| 75 | #define AB8500_INT_ACC_DETECT_21DB_R 38 | 75 | #define AB8500_INT_ACC_DETECT_21DB_R 38 |
| 76 | #define AB8500_INT_GP_SW_ADC_CONV_END 39 | 76 | #define AB8500_INT_GP_SW_ADC_CONV_END 39 |
| 77 | #define AB8500_INT_ACC_DETECT_1DB_F 33 | ||
| 78 | #define AB8500_INT_ACC_DETECT_1DB_R 34 | ||
| 79 | #define AB8500_INT_ACC_DETECT_22DB_F 35 | ||
| 80 | #define AB8500_INT_ACC_DETECT_22DB_R 36 | ||
| 81 | #define AB8500_INT_ACC_DETECT_21DB_F 37 | ||
| 82 | #define AB8500_INT_ACC_DETECT_21DB_R 38 | ||
| 83 | #define AB8500_INT_GP_SW_ADC_CONV_END 39 | ||
| 84 | #define AB8500_INT_GPIO6R 40 | ||
| 85 | #define AB8500_INT_GPIO7R 41 | ||
| 86 | #define AB8500_INT_GPIO8R 42 | ||
| 87 | #define AB8500_INT_GPIO9R 43 | ||
| 88 | #define AB8500_INT_GPIO10R 44 | ||
| 89 | #define AB8500_INT_GPIO11R 45 | ||
| 90 | #define AB8500_INT_GPIO12R 46 | ||
| 91 | #define AB8500_INT_GPIO13R 47 | ||
| 92 | #define AB8500_INT_GPIO24R 48 | ||
| 93 | #define AB8500_INT_GPIO25R 49 | ||
| 94 | #define AB8500_INT_GPIO36R 50 | ||
| 95 | #define AB8500_INT_GPIO37R 51 | ||
| 96 | #define AB8500_INT_GPIO38R 52 | ||
| 97 | #define AB8500_INT_GPIO39R 53 | ||
| 98 | #define AB8500_INT_GPIO40R 54 | ||
| 99 | #define AB8500_INT_GPIO41R 55 | ||
| 100 | #define AB8500_INT_GPIO6F 56 | ||
| 101 | #define AB8500_INT_GPIO7F 57 | ||
| 102 | #define AB8500_INT_GPIO8F 58 | ||
| 103 | #define AB8500_INT_GPIO9F 59 | ||
| 104 | #define AB8500_INT_GPIO10F 60 | ||
| 105 | #define AB8500_INT_GPIO11F 61 | ||
| 106 | #define AB8500_INT_GPIO12F 62 | ||
| 107 | #define AB8500_INT_GPIO13F 63 | ||
| 108 | #define AB8500_INT_GPIO24F 64 | ||
| 109 | #define AB8500_INT_GPIO25F 65 | ||
| 110 | #define AB8500_INT_GPIO36F 66 | ||
| 111 | #define AB8500_INT_GPIO37F 67 | ||
| 112 | #define AB8500_INT_GPIO38F 68 | ||
| 113 | #define AB8500_INT_GPIO39F 69 | ||
| 114 | #define AB8500_INT_GPIO40F 70 | ||
| 115 | #define AB8500_INT_GPIO41F 71 | ||
| 77 | #define AB8500_INT_ADP_SOURCE_ERROR 72 | 116 | #define AB8500_INT_ADP_SOURCE_ERROR 72 |
| 78 | #define AB8500_INT_ADP_SINK_ERROR 73 | 117 | #define AB8500_INT_ADP_SINK_ERROR 73 |
| 79 | #define AB8500_INT_ADP_PROBE_PLUG 74 | 118 | #define AB8500_INT_ADP_PROBE_PLUG 74 |
| @@ -141,6 +180,7 @@ struct ab8500 { | |||
| 141 | 180 | ||
| 142 | struct regulator_reg_init; | 181 | struct regulator_reg_init; |
| 143 | struct regulator_init_data; | 182 | struct regulator_init_data; |
| 183 | struct ab8500_gpio_platform_data; | ||
| 144 | 184 | ||
| 145 | /** | 185 | /** |
| 146 | * struct ab8500_platform_data - AB8500 platform data | 186 | * struct ab8500_platform_data - AB8500 platform data |
| @@ -158,6 +198,7 @@ struct ab8500_platform_data { | |||
| 158 | struct ab8500_regulator_reg_init *regulator_reg_init; | 198 | struct ab8500_regulator_reg_init *regulator_reg_init; |
| 159 | int num_regulator; | 199 | int num_regulator; |
| 160 | struct regulator_init_data *regulator; | 200 | struct regulator_init_data *regulator; |
| 201 | struct ab8500_gpio_platform_data *gpio; | ||
| 161 | }; | 202 | }; |
| 162 | 203 | ||
| 163 | extern int __devinit ab8500_init(struct ab8500 *ab8500); | 204 | extern int __devinit ab8500_init(struct ab8500 *ab8500); |
diff --git a/include/linux/mfd/ab8500/gpio.h b/include/linux/mfd/ab8500/gpio.h new file mode 100644 index 000000000000..488a8c920a29 --- /dev/null +++ b/include/linux/mfd/ab8500/gpio.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | * Copyright ST-Ericsson 2010. | ||
| 3 | * | ||
| 4 | * Author: Bibek Basu <bibek.basu@stericsson.com> | ||
| 5 | * Licensed under GPLv2. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _AB8500_GPIO_H | ||
| 9 | #define _AB8500_GPIO_H | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Platform data to register a block: only the initial gpio/irq number. | ||
| 13 | */ | ||
| 14 | |||
| 15 | struct ab8500_gpio_platform_data { | ||
| 16 | int gpio_base; | ||
| 17 | u32 irq_base; | ||
| 18 | u8 config_reg[7]; | ||
| 19 | }; | ||
| 20 | |||
| 21 | #endif /* _AB8500_GPIO_H */ | ||
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h index 0e6dc3891942..c0f87da78f8a 100644 --- a/include/linux/sonypi.h +++ b/include/linux/sonypi.h | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | 40 | ||
| 41 | /* events the user application reading /dev/sonypi can use */ | 41 | /* events the user application reading /dev/sonypi can use */ |
| 42 | 42 | ||
| 43 | #define SONYPI_EVENT_IGNORE 0 | ||
| 43 | #define SONYPI_EVENT_JOGDIAL_DOWN 1 | 44 | #define SONYPI_EVENT_JOGDIAL_DOWN 1 |
| 44 | #define SONYPI_EVENT_JOGDIAL_UP 2 | 45 | #define SONYPI_EVENT_JOGDIAL_UP 2 |
| 45 | #define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3 | 46 | #define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3 |
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h new file mode 100644 index 000000000000..f445cff66ab7 --- /dev/null +++ b/include/trace/events/btrfs.h | |||
| @@ -0,0 +1,667 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM btrfs | ||
| 3 | |||
| 4 | #if !defined(_TRACE_BTRFS_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_BTRFS_H | ||
| 6 | |||
| 7 | #include <linux/writeback.h> | ||
| 8 | #include <linux/tracepoint.h> | ||
| 9 | |||
| 10 | struct btrfs_root; | ||
| 11 | struct btrfs_fs_info; | ||
| 12 | struct btrfs_inode; | ||
| 13 | struct extent_map; | ||
| 14 | struct btrfs_ordered_extent; | ||
| 15 | struct btrfs_delayed_ref_node; | ||
| 16 | struct btrfs_delayed_tree_ref; | ||
| 17 | struct btrfs_delayed_data_ref; | ||
| 18 | struct btrfs_delayed_ref_head; | ||
| 19 | struct map_lookup; | ||
| 20 | struct extent_buffer; | ||
| 21 | |||
| 22 | #define show_ref_type(type) \ | ||
| 23 | __print_symbolic(type, \ | ||
| 24 | { BTRFS_TREE_BLOCK_REF_KEY, "TREE_BLOCK_REF" }, \ | ||
| 25 | { BTRFS_EXTENT_DATA_REF_KEY, "EXTENT_DATA_REF" }, \ | ||
| 26 | { BTRFS_EXTENT_REF_V0_KEY, "EXTENT_REF_V0" }, \ | ||
| 27 | { BTRFS_SHARED_BLOCK_REF_KEY, "SHARED_BLOCK_REF" }, \ | ||
| 28 | { BTRFS_SHARED_DATA_REF_KEY, "SHARED_DATA_REF" }) | ||
| 29 | |||
| 30 | #define __show_root_type(obj) \ | ||
| 31 | __print_symbolic(obj, \ | ||
| 32 | { BTRFS_ROOT_TREE_OBJECTID, "ROOT_TREE" }, \ | ||
| 33 | { BTRFS_EXTENT_TREE_OBJECTID, "EXTENT_TREE" }, \ | ||
| 34 | { BTRFS_CHUNK_TREE_OBJECTID, "CHUNK_TREE" }, \ | ||
| 35 | { BTRFS_DEV_TREE_OBJECTID, "DEV_TREE" }, \ | ||
| 36 | { BTRFS_FS_TREE_OBJECTID, "FS_TREE" }, \ | ||
| 37 | { BTRFS_ROOT_TREE_DIR_OBJECTID, "ROOT_TREE_DIR" }, \ | ||
| 38 | { BTRFS_CSUM_TREE_OBJECTID, "CSUM_TREE" }, \ | ||
| 39 | { BTRFS_TREE_LOG_OBJECTID, "TREE_LOG" }, \ | ||
| 40 | { BTRFS_TREE_RELOC_OBJECTID, "TREE_RELOC" }, \ | ||
| 41 | { BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" }) | ||
| 42 | |||
| 43 | #define show_root_type(obj) \ | ||
| 44 | obj, ((obj >= BTRFS_DATA_RELOC_TREE_OBJECTID) || \ | ||
| 45 | (obj <= BTRFS_CSUM_TREE_OBJECTID )) ? __show_root_type(obj) : "-" | ||
| 46 | |||
| 47 | TRACE_EVENT(btrfs_transaction_commit, | ||
| 48 | |||
| 49 | TP_PROTO(struct btrfs_root *root), | ||
| 50 | |||
| 51 | TP_ARGS(root), | ||
| 52 | |||
| 53 | TP_STRUCT__entry( | ||
| 54 | __field( u64, generation ) | ||
| 55 | __field( u64, root_objectid ) | ||
| 56 | ), | ||
| 57 | |||
| 58 | TP_fast_assign( | ||
| 59 | __entry->generation = root->fs_info->generation; | ||
| 60 | __entry->root_objectid = root->root_key.objectid; | ||
| 61 | ), | ||
| 62 | |||
| 63 | TP_printk("root = %llu(%s), gen = %llu", | ||
| 64 | show_root_type(__entry->root_objectid), | ||
| 65 | (unsigned long long)__entry->generation) | ||
| 66 | ); | ||
| 67 | |||
| 68 | DECLARE_EVENT_CLASS(btrfs__inode, | ||
| 69 | |||
| 70 | TP_PROTO(struct inode *inode), | ||
| 71 | |||
| 72 | TP_ARGS(inode), | ||
| 73 | |||
| 74 | TP_STRUCT__entry( | ||
| 75 | __field( ino_t, ino ) | ||
| 76 | __field( blkcnt_t, blocks ) | ||
| 77 | __field( u64, disk_i_size ) | ||
| 78 | __field( u64, generation ) | ||
| 79 | __field( u64, last_trans ) | ||
| 80 | __field( u64, logged_trans ) | ||
| 81 | __field( u64, root_objectid ) | ||
| 82 | ), | ||
| 83 | |||
| 84 | TP_fast_assign( | ||
| 85 | __entry->ino = inode->i_ino; | ||
| 86 | __entry->blocks = inode->i_blocks; | ||
| 87 | __entry->disk_i_size = BTRFS_I(inode)->disk_i_size; | ||
| 88 | __entry->generation = BTRFS_I(inode)->generation; | ||
| 89 | __entry->last_trans = BTRFS_I(inode)->last_trans; | ||
| 90 | __entry->logged_trans = BTRFS_I(inode)->logged_trans; | ||
| 91 | __entry->root_objectid = | ||
| 92 | BTRFS_I(inode)->root->root_key.objectid; | ||
| 93 | ), | ||
| 94 | |||
| 95 | TP_printk("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, " | ||
| 96 | "disk_i_size = %llu, last_trans = %llu, logged_trans = %llu", | ||
| 97 | show_root_type(__entry->root_objectid), | ||
| 98 | (unsigned long long)__entry->generation, | ||
| 99 | (unsigned long)__entry->ino, | ||
| 100 | (unsigned long long)__entry->blocks, | ||
| 101 | (unsigned long long)__entry->disk_i_size, | ||
| 102 | (unsigned long long)__entry->last_trans, | ||
| 103 | (unsigned long long)__entry->logged_trans) | ||
| 104 | ); | ||
| 105 | |||
| 106 | DEFINE_EVENT(btrfs__inode, btrfs_inode_new, | ||
| 107 | |||
| 108 | TP_PROTO(struct inode *inode), | ||
| 109 | |||
| 110 | TP_ARGS(inode) | ||
| 111 | ); | ||
| 112 | |||
| 113 | DEFINE_EVENT(btrfs__inode, btrfs_inode_request, | ||
| 114 | |||
| 115 | TP_PROTO(struct inode *inode), | ||
| 116 | |||
| 117 | TP_ARGS(inode) | ||
| 118 | ); | ||
| 119 | |||
| 120 | DEFINE_EVENT(btrfs__inode, btrfs_inode_evict, | ||
| 121 | |||
| 122 | TP_PROTO(struct inode *inode), | ||
| 123 | |||
| 124 | TP_ARGS(inode) | ||
| 125 | ); | ||
| 126 | |||
| 127 | #define __show_map_type(type) \ | ||
| 128 | __print_symbolic(type, \ | ||
| 129 | { EXTENT_MAP_LAST_BYTE, "LAST_BYTE" }, \ | ||
| 130 | { EXTENT_MAP_HOLE, "HOLE" }, \ | ||
| 131 | { EXTENT_MAP_INLINE, "INLINE" }, \ | ||
| 132 | { EXTENT_MAP_DELALLOC, "DELALLOC" }) | ||
| 133 | |||
| 134 | #define show_map_type(type) \ | ||
| 135 | type, (type >= EXTENT_MAP_LAST_BYTE) ? "-" : __show_map_type(type) | ||
| 136 | |||
| 137 | #define show_map_flags(flag) \ | ||
| 138 | __print_flags(flag, "|", \ | ||
| 139 | { EXTENT_FLAG_PINNED, "PINNED" }, \ | ||
| 140 | { EXTENT_FLAG_COMPRESSED, "COMPRESSED" }, \ | ||
| 141 | { EXTENT_FLAG_VACANCY, "VACANCY" }, \ | ||
| 142 | { EXTENT_FLAG_PREALLOC, "PREALLOC" }) | ||
| 143 | |||
| 144 | TRACE_EVENT(btrfs_get_extent, | ||
| 145 | |||
| 146 | TP_PROTO(struct btrfs_root *root, struct extent_map *map), | ||
| 147 | |||
| 148 | TP_ARGS(root, map), | ||
| 149 | |||
| 150 | TP_STRUCT__entry( | ||
| 151 | __field( u64, root_objectid ) | ||
| 152 | __field( u64, start ) | ||
| 153 | __field( u64, len ) | ||
| 154 | __field( u64, orig_start ) | ||
| 155 | __field( u64, block_start ) | ||
| 156 | __field( u64, block_len ) | ||
| 157 | __field( unsigned long, flags ) | ||
| 158 | __field( int, refs ) | ||
| 159 | __field( unsigned int, compress_type ) | ||
| 160 | ), | ||
| 161 | |||
| 162 | TP_fast_assign( | ||
| 163 | __entry->root_objectid = root->root_key.objectid; | ||
| 164 | __entry->start = map->start; | ||
| 165 | __entry->len = map->len; | ||
| 166 | __entry->orig_start = map->orig_start; | ||
| 167 | __entry->block_start = map->block_start; | ||
| 168 | __entry->block_len = map->block_len; | ||
| 169 | __entry->flags = map->flags; | ||
| 170 | __entry->refs = atomic_read(&map->refs); | ||
| 171 | __entry->compress_type = map->compress_type; | ||
| 172 | ), | ||
| 173 | |||
| 174 | TP_printk("root = %llu(%s), start = %llu, len = %llu, " | ||
| 175 | "orig_start = %llu, block_start = %llu(%s), " | ||
| 176 | "block_len = %llu, flags = %s, refs = %u, " | ||
| 177 | "compress_type = %u", | ||
| 178 | show_root_type(__entry->root_objectid), | ||
| 179 | (unsigned long long)__entry->start, | ||
| 180 | (unsigned long long)__entry->len, | ||
| 181 | (unsigned long long)__entry->orig_start, | ||
| 182 | show_map_type(__entry->block_start), | ||
| 183 | (unsigned long long)__entry->block_len, | ||
| 184 | show_map_flags(__entry->flags), | ||
| 185 | __entry->refs, __entry->compress_type) | ||
| 186 | ); | ||
| 187 | |||
| 188 | #define show_ordered_flags(flags) \ | ||
| 189 | __print_symbolic(flags, \ | ||
| 190 | { BTRFS_ORDERED_IO_DONE, "IO_DONE" }, \ | ||
| 191 | { BTRFS_ORDERED_COMPLETE, "COMPLETE" }, \ | ||
| 192 | { BTRFS_ORDERED_NOCOW, "NOCOW" }, \ | ||
| 193 | { BTRFS_ORDERED_COMPRESSED, "COMPRESSED" }, \ | ||
| 194 | { BTRFS_ORDERED_PREALLOC, "PREALLOC" }, \ | ||
| 195 | { BTRFS_ORDERED_DIRECT, "DIRECT" }) | ||
| 196 | |||
| 197 | DECLARE_EVENT_CLASS(btrfs__ordered_extent, | ||
| 198 | |||
| 199 | TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), | ||
| 200 | |||
| 201 | TP_ARGS(inode, ordered), | ||
| 202 | |||
| 203 | TP_STRUCT__entry( | ||
| 204 | __field( ino_t, ino ) | ||
| 205 | __field( u64, file_offset ) | ||
| 206 | __field( u64, start ) | ||
| 207 | __field( u64, len ) | ||
| 208 | __field( u64, disk_len ) | ||
| 209 | __field( u64, bytes_left ) | ||
| 210 | __field( unsigned long, flags ) | ||
| 211 | __field( int, compress_type ) | ||
| 212 | __field( int, refs ) | ||
| 213 | __field( u64, root_objectid ) | ||
| 214 | ), | ||
| 215 | |||
| 216 | TP_fast_assign( | ||
| 217 | __entry->ino = inode->i_ino; | ||
| 218 | __entry->file_offset = ordered->file_offset; | ||
| 219 | __entry->start = ordered->start; | ||
| 220 | __entry->len = ordered->len; | ||
| 221 | __entry->disk_len = ordered->disk_len; | ||
| 222 | __entry->bytes_left = ordered->bytes_left; | ||
| 223 | __entry->flags = ordered->flags; | ||
| 224 | __entry->compress_type = ordered->compress_type; | ||
| 225 | __entry->refs = atomic_read(&ordered->refs); | ||
| 226 | __entry->root_objectid = | ||
| 227 | BTRFS_I(inode)->root->root_key.objectid; | ||
| 228 | ), | ||
| 229 | |||
| 230 | TP_printk("root = %llu(%s), ino = %llu, file_offset = %llu, " | ||
| 231 | "start = %llu, len = %llu, disk_len = %llu, " | ||
| 232 | "bytes_left = %llu, flags = %s, compress_type = %d, " | ||
| 233 | "refs = %d", | ||
| 234 | show_root_type(__entry->root_objectid), | ||
| 235 | (unsigned long long)__entry->ino, | ||
| 236 | (unsigned long long)__entry->file_offset, | ||
| 237 | (unsigned long long)__entry->start, | ||
| 238 | (unsigned long long)__entry->len, | ||
| 239 | (unsigned long long)__entry->disk_len, | ||
| 240 | (unsigned long long)__entry->bytes_left, | ||
| 241 | show_ordered_flags(__entry->flags), | ||
| 242 | __entry->compress_type, __entry->refs) | ||
| 243 | ); | ||
| 244 | |||
| 245 | DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_add, | ||
| 246 | |||
| 247 | TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), | ||
| 248 | |||
| 249 | TP_ARGS(inode, ordered) | ||
| 250 | ); | ||
| 251 | |||
| 252 | DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_remove, | ||
| 253 | |||
| 254 | TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), | ||
| 255 | |||
| 256 | TP_ARGS(inode, ordered) | ||
| 257 | ); | ||
| 258 | |||
| 259 | DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_start, | ||
| 260 | |||
| 261 | TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), | ||
| 262 | |||
| 263 | TP_ARGS(inode, ordered) | ||
| 264 | ); | ||
| 265 | |||
| 266 | DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_put, | ||
| 267 | |||
| 268 | TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), | ||
| 269 | |||
| 270 | TP_ARGS(inode, ordered) | ||
| 271 | ); | ||
| 272 | |||
| 273 | DECLARE_EVENT_CLASS(btrfs__writepage, | ||
| 274 | |||
| 275 | TP_PROTO(struct page *page, struct inode *inode, | ||
| 276 | struct writeback_control *wbc), | ||
| 277 | |||
| 278 | TP_ARGS(page, inode, wbc), | ||
| 279 | |||
| 280 | TP_STRUCT__entry( | ||
| 281 | __field( ino_t, ino ) | ||
| 282 | __field( pgoff_t, index ) | ||
| 283 | __field( long, nr_to_write ) | ||
| 284 | __field( long, pages_skipped ) | ||
| 285 | __field( loff_t, range_start ) | ||
| 286 | __field( loff_t, range_end ) | ||
| 287 | __field( char, nonblocking ) | ||
| 288 | __field( char, for_kupdate ) | ||
| 289 | __field( char, for_reclaim ) | ||
| 290 | __field( char, range_cyclic ) | ||
| 291 | __field( pgoff_t, writeback_index ) | ||
| 292 | __field( u64, root_objectid ) | ||
| 293 | ), | ||
| 294 | |||
| 295 | TP_fast_assign( | ||
| 296 | __entry->ino = inode->i_ino; | ||
| 297 | __entry->index = page->index; | ||
| 298 | __entry->nr_to_write = wbc->nr_to_write; | ||
| 299 | __entry->pages_skipped = wbc->pages_skipped; | ||
| 300 | __entry->range_start = wbc->range_start; | ||
| 301 | __entry->range_end = wbc->range_end; | ||
| 302 | __entry->nonblocking = wbc->nonblocking; | ||
| 303 | __entry->for_kupdate = wbc->for_kupdate; | ||
| 304 | __entry->for_reclaim = wbc->for_reclaim; | ||
| 305 | __entry->range_cyclic = wbc->range_cyclic; | ||
| 306 | __entry->writeback_index = inode->i_mapping->writeback_index; | ||
| 307 | __entry->root_objectid = | ||
| 308 | BTRFS_I(inode)->root->root_key.objectid; | ||
| 309 | ), | ||
| 310 | |||
| 311 | TP_printk("root = %llu(%s), ino = %lu, page_index = %lu, " | ||
| 312 | "nr_to_write = %ld, pages_skipped = %ld, range_start = %llu, " | ||
| 313 | "range_end = %llu, nonblocking = %d, for_kupdate = %d, " | ||
| 314 | "for_reclaim = %d, range_cyclic = %d, writeback_index = %lu", | ||
| 315 | show_root_type(__entry->root_objectid), | ||
| 316 | (unsigned long)__entry->ino, __entry->index, | ||
| 317 | __entry->nr_to_write, __entry->pages_skipped, | ||
| 318 | __entry->range_start, __entry->range_end, | ||
| 319 | __entry->nonblocking, __entry->for_kupdate, | ||
| 320 | __entry->for_reclaim, __entry->range_cyclic, | ||
| 321 | (unsigned long)__entry->writeback_index) | ||
| 322 | ); | ||
| 323 | |||
| 324 | DEFINE_EVENT(btrfs__writepage, __extent_writepage, | ||
| 325 | |||
| 326 | TP_PROTO(struct page *page, struct inode *inode, | ||
| 327 | struct writeback_control *wbc), | ||
| 328 | |||
| 329 | TP_ARGS(page, inode, wbc) | ||
| 330 | ); | ||
| 331 | |||
| 332 | TRACE_EVENT(btrfs_writepage_end_io_hook, | ||
| 333 | |||
| 334 | TP_PROTO(struct page *page, u64 start, u64 end, int uptodate), | ||
| 335 | |||
| 336 | TP_ARGS(page, start, end, uptodate), | ||
| 337 | |||
| 338 | TP_STRUCT__entry( | ||
| 339 | __field( ino_t, ino ) | ||
| 340 | __field( pgoff_t, index ) | ||
| 341 | __field( u64, start ) | ||
| 342 | __field( u64, end ) | ||
| 343 | __field( int, uptodate ) | ||
| 344 | __field( u64, root_objectid ) | ||
| 345 | ), | ||
| 346 | |||
| 347 | TP_fast_assign( | ||
| 348 | __entry->ino = page->mapping->host->i_ino; | ||
| 349 | __entry->index = page->index; | ||
| 350 | __entry->start = start; | ||
| 351 | __entry->end = end; | ||
| 352 | __entry->uptodate = uptodate; | ||
| 353 | __entry->root_objectid = | ||
| 354 | BTRFS_I(page->mapping->host)->root->root_key.objectid; | ||
| 355 | ), | ||
| 356 | |||
| 357 | TP_printk("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, " | ||
| 358 | "end = %llu, uptodate = %d", | ||
| 359 | show_root_type(__entry->root_objectid), | ||
| 360 | (unsigned long)__entry->ino, (unsigned long)__entry->index, | ||
| 361 | (unsigned long long)__entry->start, | ||
| 362 | (unsigned long long)__entry->end, __entry->uptodate) | ||
| 363 | ); | ||
| 364 | |||
| 365 | TRACE_EVENT(btrfs_sync_file, | ||
| 366 | |||
| 367 | TP_PROTO(struct file *file, int datasync), | ||
| 368 | |||
| 369 | TP_ARGS(file, datasync), | ||
| 370 | |||
| 371 | TP_STRUCT__entry( | ||
| 372 | __field( ino_t, ino ) | ||
| 373 | __field( ino_t, parent ) | ||
| 374 | __field( int, datasync ) | ||
| 375 | __field( u64, root_objectid ) | ||
| 376 | ), | ||
| 377 | |||
| 378 | TP_fast_assign( | ||
| 379 | struct dentry *dentry = file->f_path.dentry; | ||
| 380 | struct inode *inode = dentry->d_inode; | ||
| 381 | |||
| 382 | __entry->ino = inode->i_ino; | ||
| 383 | __entry->parent = dentry->d_parent->d_inode->i_ino; | ||
| 384 | __entry->datasync = datasync; | ||
| 385 | __entry->root_objectid = | ||
| 386 | BTRFS_I(inode)->root->root_key.objectid; | ||
| 387 | ), | ||
| 388 | |||
| 389 | TP_printk("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d", | ||
| 390 | show_root_type(__entry->root_objectid), | ||
| 391 | (unsigned long)__entry->ino, (unsigned long)__entry->parent, | ||
| 392 | __entry->datasync) | ||
| 393 | ); | ||
| 394 | |||
| 395 | TRACE_EVENT(btrfs_sync_fs, | ||
| 396 | |||
| 397 | TP_PROTO(int wait), | ||
| 398 | |||
| 399 | TP_ARGS(wait), | ||
| 400 | |||
| 401 | TP_STRUCT__entry( | ||
| 402 | __field( int, wait ) | ||
| 403 | ), | ||
| 404 | |||
| 405 | TP_fast_assign( | ||
| 406 | __entry->wait = wait; | ||
| 407 | ), | ||
| 408 | |||
| 409 | TP_printk("wait = %d", __entry->wait) | ||
| 410 | ); | ||
| 411 | |||
| 412 | #define show_ref_action(action) \ | ||
| 413 | __print_symbolic(action, \ | ||
| 414 | { BTRFS_ADD_DELAYED_REF, "ADD_DELAYED_REF" }, \ | ||
| 415 | { BTRFS_DROP_DELAYED_REF, "DROP_DELAYED_REF" }, \ | ||
| 416 | { BTRFS_ADD_DELAYED_EXTENT, "ADD_DELAYED_EXTENT" }, \ | ||
| 417 | { BTRFS_UPDATE_DELAYED_HEAD, "UPDATE_DELAYED_HEAD" }) | ||
| 418 | |||
| 419 | |||
| 420 | TRACE_EVENT(btrfs_delayed_tree_ref, | ||
| 421 | |||
| 422 | TP_PROTO(struct btrfs_delayed_ref_node *ref, | ||
| 423 | struct btrfs_delayed_tree_ref *full_ref, | ||
| 424 | int action), | ||
| 425 | |||
| 426 | TP_ARGS(ref, full_ref, action), | ||
| 427 | |||
| 428 | TP_STRUCT__entry( | ||
| 429 | __field( u64, bytenr ) | ||
| 430 | __field( u64, num_bytes ) | ||
| 431 | __field( int, action ) | ||
| 432 | __field( u64, parent ) | ||
| 433 | __field( u64, ref_root ) | ||
| 434 | __field( int, level ) | ||
| 435 | __field( int, type ) | ||
| 436 | ), | ||
| 437 | |||
| 438 | TP_fast_assign( | ||
| 439 | __entry->bytenr = ref->bytenr; | ||
| 440 | __entry->num_bytes = ref->num_bytes; | ||
| 441 | __entry->action = action; | ||
| 442 | __entry->parent = full_ref->parent; | ||
| 443 | __entry->ref_root = full_ref->root; | ||
| 444 | __entry->level = full_ref->level; | ||
| 445 | __entry->type = ref->type; | ||
| 446 | ), | ||
| 447 | |||
| 448 | TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, " | ||
| 449 | "parent = %llu(%s), ref_root = %llu(%s), level = %d, " | ||
| 450 | "type = %s", | ||
| 451 | (unsigned long long)__entry->bytenr, | ||
| 452 | (unsigned long long)__entry->num_bytes, | ||
| 453 | show_ref_action(__entry->action), | ||
| 454 | show_root_type(__entry->parent), | ||
| 455 | show_root_type(__entry->ref_root), | ||
| 456 | __entry->level, show_ref_type(__entry->type)) | ||
| 457 | ); | ||
| 458 | |||
| 459 | TRACE_EVENT(btrfs_delayed_data_ref, | ||
| 460 | |||
| 461 | TP_PROTO(struct btrfs_delayed_ref_node *ref, | ||
| 462 | struct btrfs_delayed_data_ref *full_ref, | ||
| 463 | int action), | ||
| 464 | |||
| 465 | TP_ARGS(ref, full_ref, action), | ||
| 466 | |||
| 467 | TP_STRUCT__entry( | ||
| 468 | __field( u64, bytenr ) | ||
| 469 | __field( u64, num_bytes ) | ||
| 470 | __field( int, action ) | ||
| 471 | __field( u64, parent ) | ||
| 472 | __field( u64, ref_root ) | ||
| 473 | __field( u64, owner ) | ||
| 474 | __field( u64, offset ) | ||
| 475 | __field( int, type ) | ||
| 476 | ), | ||
| 477 | |||
| 478 | TP_fast_assign( | ||
| 479 | __entry->bytenr = ref->bytenr; | ||
| 480 | __entry->num_bytes = ref->num_bytes; | ||
| 481 | __entry->action = action; | ||
| 482 | __entry->parent = full_ref->parent; | ||
| 483 | __entry->ref_root = full_ref->root; | ||
| 484 | __entry->owner = full_ref->objectid; | ||
| 485 | __entry->offset = full_ref->offset; | ||
| 486 | __entry->type = ref->type; | ||
| 487 | ), | ||
| 488 | |||
| 489 | TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, " | ||
| 490 | "parent = %llu(%s), ref_root = %llu(%s), owner = %llu, " | ||
| 491 | "offset = %llu, type = %s", | ||
| 492 | (unsigned long long)__entry->bytenr, | ||
| 493 | (unsigned long long)__entry->num_bytes, | ||
| 494 | show_ref_action(__entry->action), | ||
| 495 | show_root_type(__entry->parent), | ||
| 496 | show_root_type(__entry->ref_root), | ||
| 497 | (unsigned long long)__entry->owner, | ||
| 498 | (unsigned long long)__entry->offset, | ||
| 499 | show_ref_type(__entry->type)) | ||
| 500 | ); | ||
| 501 | |||
| 502 | TRACE_EVENT(btrfs_delayed_ref_head, | ||
| 503 | |||
| 504 | TP_PROTO(struct btrfs_delayed_ref_node *ref, | ||
| 505 | struct btrfs_delayed_ref_head *head_ref, | ||
| 506 | int action), | ||
| 507 | |||
| 508 | TP_ARGS(ref, head_ref, action), | ||
| 509 | |||
| 510 | TP_STRUCT__entry( | ||
| 511 | __field( u64, bytenr ) | ||
| 512 | __field( u64, num_bytes ) | ||
| 513 | __field( int, action ) | ||
| 514 | __field( int, is_data ) | ||
| 515 | ), | ||
| 516 | |||
| 517 | TP_fast_assign( | ||
| 518 | __entry->bytenr = ref->bytenr; | ||
| 519 | __entry->num_bytes = ref->num_bytes; | ||
| 520 | __entry->action = action; | ||
| 521 | __entry->is_data = head_ref->is_data; | ||
| 522 | ), | ||
| 523 | |||
| 524 | TP_printk("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d", | ||
| 525 | (unsigned long long)__entry->bytenr, | ||
| 526 | (unsigned long long)__entry->num_bytes, | ||
| 527 | show_ref_action(__entry->action), | ||
| 528 | __entry->is_data) | ||
| 529 | ); | ||
| 530 | |||
| 531 | #define show_chunk_type(type) \ | ||
| 532 | __print_flags(type, "|", \ | ||
| 533 | { BTRFS_BLOCK_GROUP_DATA, "DATA" }, \ | ||
| 534 | { BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \ | ||
| 535 | { BTRFS_BLOCK_GROUP_METADATA, "METADATA"}, \ | ||
| 536 | { BTRFS_BLOCK_GROUP_RAID0, "RAID0" }, \ | ||
| 537 | { BTRFS_BLOCK_GROUP_RAID1, "RAID1" }, \ | ||
| 538 | { BTRFS_BLOCK_GROUP_DUP, "DUP" }, \ | ||
| 539 | { BTRFS_BLOCK_GROUP_RAID10, "RAID10"}) | ||
| 540 | |||
| 541 | DECLARE_EVENT_CLASS(btrfs__chunk, | ||
| 542 | |||
| 543 | TP_PROTO(struct btrfs_root *root, struct map_lookup *map, | ||
| 544 | u64 offset, u64 size), | ||
| 545 | |||
| 546 | TP_ARGS(root, map, offset, size), | ||
| 547 | |||
| 548 | TP_STRUCT__entry( | ||
| 549 | __field( int, num_stripes ) | ||
| 550 | __field( u64, type ) | ||
| 551 | __field( int, sub_stripes ) | ||
| 552 | __field( u64, offset ) | ||
| 553 | __field( u64, size ) | ||
| 554 | __field( u64, root_objectid ) | ||
| 555 | ), | ||
| 556 | |||
| 557 | TP_fast_assign( | ||
| 558 | __entry->num_stripes = map->num_stripes; | ||
| 559 | __entry->type = map->type; | ||
| 560 | __entry->sub_stripes = map->sub_stripes; | ||
| 561 | __entry->offset = offset; | ||
| 562 | __entry->size = size; | ||
| 563 | __entry->root_objectid = root->root_key.objectid; | ||
| 564 | ), | ||
| 565 | |||
| 566 | TP_printk("root = %llu(%s), offset = %llu, size = %llu, " | ||
| 567 | "num_stripes = %d, sub_stripes = %d, type = %s", | ||
| 568 | show_root_type(__entry->root_objectid), | ||
| 569 | (unsigned long long)__entry->offset, | ||
| 570 | (unsigned long long)__entry->size, | ||
| 571 | __entry->num_stripes, __entry->sub_stripes, | ||
| 572 | show_chunk_type(__entry->type)) | ||
| 573 | ); | ||
| 574 | |||
| 575 | DEFINE_EVENT(btrfs__chunk, btrfs_chunk_alloc, | ||
| 576 | |||
| 577 | TP_PROTO(struct btrfs_root *root, struct map_lookup *map, | ||
| 578 | u64 offset, u64 size), | ||
| 579 | |||
| 580 | TP_ARGS(root, map, offset, size) | ||
| 581 | ); | ||
| 582 | |||
| 583 | DEFINE_EVENT(btrfs__chunk, btrfs_chunk_free, | ||
| 584 | |||
| 585 | TP_PROTO(struct btrfs_root *root, struct map_lookup *map, | ||
| 586 | u64 offset, u64 size), | ||
| 587 | |||
| 588 | TP_ARGS(root, map, offset, size) | ||
| 589 | ); | ||
| 590 | |||
| 591 | TRACE_EVENT(btrfs_cow_block, | ||
| 592 | |||
| 593 | TP_PROTO(struct btrfs_root *root, struct extent_buffer *buf, | ||
| 594 | struct extent_buffer *cow), | ||
| 595 | |||
| 596 | TP_ARGS(root, buf, cow), | ||
| 597 | |||
| 598 | TP_STRUCT__entry( | ||
| 599 | __field( u64, root_objectid ) | ||
| 600 | __field( u64, buf_start ) | ||
| 601 | __field( int, refs ) | ||
| 602 | __field( u64, cow_start ) | ||
| 603 | __field( int, buf_level ) | ||
| 604 | __field( int, cow_level ) | ||
| 605 | ), | ||
| 606 | |||
| 607 | TP_fast_assign( | ||
| 608 | __entry->root_objectid = root->root_key.objectid; | ||
| 609 | __entry->buf_start = buf->start; | ||
| 610 | __entry->refs = atomic_read(&buf->refs); | ||
| 611 | __entry->cow_start = cow->start; | ||
| 612 | __entry->buf_level = btrfs_header_level(buf); | ||
| 613 | __entry->cow_level = btrfs_header_level(cow); | ||
| 614 | ), | ||
| 615 | |||
| 616 | TP_printk("root = %llu(%s), refs = %d, orig_buf = %llu " | ||
| 617 | "(orig_level = %d), cow_buf = %llu (cow_level = %d)", | ||
| 618 | show_root_type(__entry->root_objectid), | ||
| 619 | __entry->refs, | ||
| 620 | (unsigned long long)__entry->buf_start, | ||
| 621 | __entry->buf_level, | ||
| 622 | (unsigned long long)__entry->cow_start, | ||
| 623 | __entry->cow_level) | ||
| 624 | ); | ||
| 625 | |||
| 626 | DECLARE_EVENT_CLASS(btrfs__reserved_extent, | ||
| 627 | |||
| 628 | TP_PROTO(struct btrfs_root *root, u64 start, u64 len), | ||
| 629 | |||
| 630 | TP_ARGS(root, start, len), | ||
| 631 | |||
| 632 | TP_STRUCT__entry( | ||
| 633 | __field( u64, root_objectid ) | ||
| 634 | __field( u64, start ) | ||
| 635 | __field( u64, len ) | ||
| 636 | ), | ||
| 637 | |||
| 638 | TP_fast_assign( | ||
| 639 | __entry->root_objectid = root->root_key.objectid; | ||
| 640 | __entry->start = start; | ||
| 641 | __entry->len = len; | ||
| 642 | ), | ||
| 643 | |||
| 644 | TP_printk("root = %llu(%s), start = %llu, len = %llu", | ||
| 645 | show_root_type(__entry->root_objectid), | ||
| 646 | (unsigned long long)__entry->start, | ||
| 647 | (unsigned long long)__entry->len) | ||
| 648 | ); | ||
| 649 | |||
| 650 | DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_alloc, | ||
| 651 | |||
| 652 | TP_PROTO(struct btrfs_root *root, u64 start, u64 len), | ||
| 653 | |||
| 654 | TP_ARGS(root, start, len) | ||
| 655 | ); | ||
| 656 | |||
| 657 | DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_free, | ||
| 658 | |||
| 659 | TP_PROTO(struct btrfs_root *root, u64 start, u64 len), | ||
| 660 | |||
| 661 | TP_ARGS(root, start, len) | ||
| 662 | ); | ||
| 663 | |||
| 664 | #endif /* _TRACE_BTRFS_H */ | ||
| 665 | |||
| 666 | /* This part must be outside protection */ | ||
| 667 | #include <trace/define_trace.h> | ||
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index 00f2c037267a..72606ba10b14 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig | |||
| @@ -51,6 +51,10 @@ config HARDIRQS_SW_RESEND | |||
| 51 | config IRQ_PREFLOW_FASTEOI | 51 | config IRQ_PREFLOW_FASTEOI |
| 52 | bool | 52 | bool |
| 53 | 53 | ||
| 54 | # Edge style eoi based handler (cell) | ||
| 55 | config IRQ_EDGE_EOI_HANDLER | ||
| 56 | bool | ||
| 57 | |||
| 54 | # Support forced irq threading | 58 | # Support forced irq threading |
| 55 | config IRQ_FORCED_THREADING | 59 | config IRQ_FORCED_THREADING |
| 56 | bool | 60 | bool |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index c9c0601f0615..03099d521f5e 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -37,6 +37,12 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip) | |||
| 37 | irq_chip_set_defaults(chip); | 37 | irq_chip_set_defaults(chip); |
| 38 | desc->irq_data.chip = chip; | 38 | desc->irq_data.chip = chip; |
| 39 | irq_put_desc_unlock(desc, flags); | 39 | irq_put_desc_unlock(desc, flags); |
| 40 | /* | ||
| 41 | * For !CONFIG_SPARSE_IRQ make the irq show up in | ||
| 42 | * allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is | ||
| 43 | * already marked, and this call is harmless. | ||
| 44 | */ | ||
| 45 | irq_reserve_irq(irq); | ||
| 40 | return 0; | 46 | return 0; |
| 41 | } | 47 | } |
| 42 | EXPORT_SYMBOL(irq_set_chip); | 48 | EXPORT_SYMBOL(irq_set_chip); |
| @@ -134,25 +140,25 @@ EXPORT_SYMBOL_GPL(irq_get_irq_data); | |||
| 134 | 140 | ||
| 135 | static void irq_state_clr_disabled(struct irq_desc *desc) | 141 | static void irq_state_clr_disabled(struct irq_desc *desc) |
| 136 | { | 142 | { |
| 137 | desc->istate &= ~IRQS_DISABLED; | 143 | irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED); |
| 138 | irq_compat_clr_disabled(desc); | 144 | irq_compat_clr_disabled(desc); |
| 139 | } | 145 | } |
| 140 | 146 | ||
| 141 | static void irq_state_set_disabled(struct irq_desc *desc) | 147 | static void irq_state_set_disabled(struct irq_desc *desc) |
| 142 | { | 148 | { |
| 143 | desc->istate |= IRQS_DISABLED; | 149 | irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); |
| 144 | irq_compat_set_disabled(desc); | 150 | irq_compat_set_disabled(desc); |
| 145 | } | 151 | } |
| 146 | 152 | ||
| 147 | static void irq_state_clr_masked(struct irq_desc *desc) | 153 | static void irq_state_clr_masked(struct irq_desc *desc) |
| 148 | { | 154 | { |
| 149 | desc->istate &= ~IRQS_MASKED; | 155 | irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED); |
| 150 | irq_compat_clr_masked(desc); | 156 | irq_compat_clr_masked(desc); |
| 151 | } | 157 | } |
| 152 | 158 | ||
| 153 | static void irq_state_set_masked(struct irq_desc *desc) | 159 | static void irq_state_set_masked(struct irq_desc *desc) |
| 154 | { | 160 | { |
| 155 | desc->istate |= IRQS_MASKED; | 161 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); |
| 156 | irq_compat_set_masked(desc); | 162 | irq_compat_set_masked(desc); |
| 157 | } | 163 | } |
| 158 | 164 | ||
| @@ -372,11 +378,11 @@ void handle_nested_irq(unsigned int irq) | |||
| 372 | kstat_incr_irqs_this_cpu(irq, desc); | 378 | kstat_incr_irqs_this_cpu(irq, desc); |
| 373 | 379 | ||
| 374 | action = desc->action; | 380 | action = desc->action; |
| 375 | if (unlikely(!action || (desc->istate & IRQS_DISABLED))) | 381 | if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) |
| 376 | goto out_unlock; | 382 | goto out_unlock; |
| 377 | 383 | ||
| 378 | irq_compat_set_progress(desc); | 384 | irq_compat_set_progress(desc); |
| 379 | desc->istate |= IRQS_INPROGRESS; | 385 | irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
| 380 | raw_spin_unlock_irq(&desc->lock); | 386 | raw_spin_unlock_irq(&desc->lock); |
| 381 | 387 | ||
| 382 | action_ret = action->thread_fn(action->irq, action->dev_id); | 388 | action_ret = action->thread_fn(action->irq, action->dev_id); |
| @@ -384,7 +390,7 @@ void handle_nested_irq(unsigned int irq) | |||
| 384 | note_interrupt(irq, desc, action_ret); | 390 | note_interrupt(irq, desc, action_ret); |
| 385 | 391 | ||
| 386 | raw_spin_lock_irq(&desc->lock); | 392 | raw_spin_lock_irq(&desc->lock); |
| 387 | desc->istate &= ~IRQS_INPROGRESS; | 393 | irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
| 388 | irq_compat_clr_progress(desc); | 394 | irq_compat_clr_progress(desc); |
| 389 | 395 | ||
| 390 | out_unlock: | 396 | out_unlock: |
| @@ -416,14 +422,14 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) | |||
| 416 | { | 422 | { |
| 417 | raw_spin_lock(&desc->lock); | 423 | raw_spin_lock(&desc->lock); |
| 418 | 424 | ||
| 419 | if (unlikely(desc->istate & IRQS_INPROGRESS)) | 425 | if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
| 420 | if (!irq_check_poll(desc)) | 426 | if (!irq_check_poll(desc)) |
| 421 | goto out_unlock; | 427 | goto out_unlock; |
| 422 | 428 | ||
| 423 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); | 429 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
| 424 | kstat_incr_irqs_this_cpu(irq, desc); | 430 | kstat_incr_irqs_this_cpu(irq, desc); |
| 425 | 431 | ||
| 426 | if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) | 432 | if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) |
| 427 | goto out_unlock; | 433 | goto out_unlock; |
| 428 | 434 | ||
| 429 | handle_irq_event(desc); | 435 | handle_irq_event(desc); |
| @@ -448,7 +454,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
| 448 | raw_spin_lock(&desc->lock); | 454 | raw_spin_lock(&desc->lock); |
| 449 | mask_ack_irq(desc); | 455 | mask_ack_irq(desc); |
| 450 | 456 | ||
| 451 | if (unlikely(desc->istate & IRQS_INPROGRESS)) | 457 | if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
| 452 | if (!irq_check_poll(desc)) | 458 | if (!irq_check_poll(desc)) |
| 453 | goto out_unlock; | 459 | goto out_unlock; |
| 454 | 460 | ||
| @@ -459,12 +465,12 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
| 459 | * If its disabled or no action available | 465 | * If its disabled or no action available |
| 460 | * keep it masked and get out of here | 466 | * keep it masked and get out of here |
| 461 | */ | 467 | */ |
| 462 | if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) | 468 | if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) |
| 463 | goto out_unlock; | 469 | goto out_unlock; |
| 464 | 470 | ||
| 465 | handle_irq_event(desc); | 471 | handle_irq_event(desc); |
| 466 | 472 | ||
| 467 | if (!(desc->istate & (IRQS_DISABLED | IRQS_ONESHOT))) | 473 | if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) |
| 468 | unmask_irq(desc); | 474 | unmask_irq(desc); |
| 469 | out_unlock: | 475 | out_unlock: |
| 470 | raw_spin_unlock(&desc->lock); | 476 | raw_spin_unlock(&desc->lock); |
| @@ -496,7 +502,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
| 496 | { | 502 | { |
| 497 | raw_spin_lock(&desc->lock); | 503 | raw_spin_lock(&desc->lock); |
| 498 | 504 | ||
| 499 | if (unlikely(desc->istate & IRQS_INPROGRESS)) | 505 | if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
| 500 | if (!irq_check_poll(desc)) | 506 | if (!irq_check_poll(desc)) |
| 501 | goto out; | 507 | goto out; |
| 502 | 508 | ||
| @@ -507,7 +513,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
| 507 | * If its disabled or no action available | 513 | * If its disabled or no action available |
| 508 | * then mask it and get out of here: | 514 | * then mask it and get out of here: |
| 509 | */ | 515 | */ |
| 510 | if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) { | 516 | if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { |
| 511 | irq_compat_set_pending(desc); | 517 | irq_compat_set_pending(desc); |
| 512 | desc->istate |= IRQS_PENDING; | 518 | desc->istate |= IRQS_PENDING; |
| 513 | mask_irq(desc); | 519 | mask_irq(desc); |
| @@ -558,8 +564,8 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
| 558 | * we shouldn't process the IRQ. Mark it pending, handle | 564 | * we shouldn't process the IRQ. Mark it pending, handle |
| 559 | * the necessary masking and go out | 565 | * the necessary masking and go out |
| 560 | */ | 566 | */ |
| 561 | if (unlikely((desc->istate & (IRQS_DISABLED | IRQS_INPROGRESS) || | 567 | if (unlikely(irqd_irq_disabled(&desc->irq_data) || |
| 562 | !desc->action))) { | 568 | irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { |
| 563 | if (!irq_check_poll(desc)) { | 569 | if (!irq_check_poll(desc)) { |
| 564 | irq_compat_set_pending(desc); | 570 | irq_compat_set_pending(desc); |
| 565 | desc->istate |= IRQS_PENDING; | 571 | desc->istate |= IRQS_PENDING; |
| @@ -584,20 +590,65 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
| 584 | * Renable it, if it was not disabled in meantime. | 590 | * Renable it, if it was not disabled in meantime. |
| 585 | */ | 591 | */ |
| 586 | if (unlikely(desc->istate & IRQS_PENDING)) { | 592 | if (unlikely(desc->istate & IRQS_PENDING)) { |
| 587 | if (!(desc->istate & IRQS_DISABLED) && | 593 | if (!irqd_irq_disabled(&desc->irq_data) && |
| 588 | (desc->istate & IRQS_MASKED)) | 594 | irqd_irq_masked(&desc->irq_data)) |
| 589 | unmask_irq(desc); | 595 | unmask_irq(desc); |
| 590 | } | 596 | } |
| 591 | 597 | ||
| 592 | handle_irq_event(desc); | 598 | handle_irq_event(desc); |
| 593 | 599 | ||
| 594 | } while ((desc->istate & IRQS_PENDING) && | 600 | } while ((desc->istate & IRQS_PENDING) && |
| 595 | !(desc->istate & IRQS_DISABLED)); | 601 | !irqd_irq_disabled(&desc->irq_data)); |
| 596 | 602 | ||
| 597 | out_unlock: | 603 | out_unlock: |
| 598 | raw_spin_unlock(&desc->lock); | 604 | raw_spin_unlock(&desc->lock); |
| 599 | } | 605 | } |
| 600 | 606 | ||
| 607 | #ifdef CONFIG_IRQ_EDGE_EOI_HANDLER | ||
| 608 | /** | ||
| 609 | * handle_edge_eoi_irq - edge eoi type IRQ handler | ||
| 610 | * @irq: the interrupt number | ||
| 611 | * @desc: the interrupt description structure for this irq | ||
| 612 | * | ||
| 613 | * Similar as the above handle_edge_irq, but using eoi and w/o the | ||
| 614 | * mask/unmask logic. | ||
| 615 | */ | ||
| 616 | void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc) | ||
| 617 | { | ||
| 618 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
| 619 | |||
| 620 | raw_spin_lock(&desc->lock); | ||
| 621 | |||
| 622 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); | ||
| 623 | /* | ||
| 624 | * If we're currently running this IRQ, or its disabled, | ||
| 625 | * we shouldn't process the IRQ. Mark it pending, handle | ||
| 626 | * the necessary masking and go out | ||
| 627 | */ | ||
| 628 | if (unlikely(irqd_irq_disabled(&desc->irq_data) || | ||
| 629 | irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { | ||
| 630 | if (!irq_check_poll(desc)) { | ||
| 631 | desc->istate |= IRQS_PENDING; | ||
| 632 | goto out_eoi; | ||
| 633 | } | ||
| 634 | } | ||
| 635 | kstat_incr_irqs_this_cpu(irq, desc); | ||
| 636 | |||
| 637 | do { | ||
| 638 | if (unlikely(!desc->action)) | ||
| 639 | goto out_eoi; | ||
| 640 | |||
| 641 | handle_irq_event(desc); | ||
| 642 | |||
| 643 | } while ((desc->istate & IRQS_PENDING) && | ||
| 644 | !irqd_irq_disabled(&desc->irq_data)); | ||
| 645 | |||
| 646 | out_unlock: | ||
| 647 | chip->irq_eoi(&desc->irq_data); | ||
| 648 | raw_spin_unlock(&desc->lock); | ||
| 649 | } | ||
| 650 | #endif | ||
| 651 | |||
| 601 | /** | 652 | /** |
| 602 | * handle_percpu_irq - Per CPU local irq handler | 653 | * handle_percpu_irq - Per CPU local irq handler |
| 603 | * @irq: the interrupt number | 654 | * @irq: the interrupt number |
| @@ -642,8 +693,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 642 | if (handle == handle_bad_irq) { | 693 | if (handle == handle_bad_irq) { |
| 643 | if (desc->irq_data.chip != &no_irq_chip) | 694 | if (desc->irq_data.chip != &no_irq_chip) |
| 644 | mask_ack_irq(desc); | 695 | mask_ack_irq(desc); |
| 645 | irq_compat_set_disabled(desc); | 696 | irq_state_set_disabled(desc); |
| 646 | desc->istate |= IRQS_DISABLED; | ||
| 647 | desc->depth = 1; | 697 | desc->depth = 1; |
| 648 | } | 698 | } |
| 649 | desc->handle_irq = handle; | 699 | desc->handle_irq = handle; |
| @@ -684,8 +734,70 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) | |||
| 684 | irqd_set(&desc->irq_data, IRQD_PER_CPU); | 734 | irqd_set(&desc->irq_data, IRQD_PER_CPU); |
| 685 | if (irq_settings_can_move_pcntxt(desc)) | 735 | if (irq_settings_can_move_pcntxt(desc)) |
| 686 | irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); | 736 | irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); |
| 737 | if (irq_settings_is_level(desc)) | ||
| 738 | irqd_set(&desc->irq_data, IRQD_LEVEL); | ||
| 687 | 739 | ||
| 688 | irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); | 740 | irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); |
| 689 | 741 | ||
| 690 | irq_put_desc_unlock(desc, flags); | 742 | irq_put_desc_unlock(desc, flags); |
| 691 | } | 743 | } |
| 744 | |||
| 745 | /** | ||
| 746 | * irq_cpu_online - Invoke all irq_cpu_online functions. | ||
| 747 | * | ||
| 748 | * Iterate through all irqs and invoke the chip.irq_cpu_online() | ||
| 749 | * for each. | ||
| 750 | */ | ||
| 751 | void irq_cpu_online(void) | ||
| 752 | { | ||
| 753 | struct irq_desc *desc; | ||
| 754 | struct irq_chip *chip; | ||
| 755 | unsigned long flags; | ||
| 756 | unsigned int irq; | ||
| 757 | |||
| 758 | for_each_active_irq(irq) { | ||
| 759 | desc = irq_to_desc(irq); | ||
| 760 | if (!desc) | ||
| 761 | continue; | ||
| 762 | |||
| 763 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 764 | |||
| 765 | chip = irq_data_get_irq_chip(&desc->irq_data); | ||
| 766 | if (chip && chip->irq_cpu_online && | ||
| 767 | (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || | ||
| 768 | !irqd_irq_disabled(&desc->irq_data))) | ||
| 769 | chip->irq_cpu_online(&desc->irq_data); | ||
| 770 | |||
| 771 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 772 | } | ||
| 773 | } | ||
| 774 | |||
| 775 | /** | ||
| 776 | * irq_cpu_offline - Invoke all irq_cpu_offline functions. | ||
| 777 | * | ||
| 778 | * Iterate through all irqs and invoke the chip.irq_cpu_offline() | ||
| 779 | * for each. | ||
| 780 | */ | ||
| 781 | void irq_cpu_offline(void) | ||
| 782 | { | ||
| 783 | struct irq_desc *desc; | ||
| 784 | struct irq_chip *chip; | ||
| 785 | unsigned long flags; | ||
| 786 | unsigned int irq; | ||
| 787 | |||
| 788 | for_each_active_irq(irq) { | ||
| 789 | desc = irq_to_desc(irq); | ||
| 790 | if (!desc) | ||
| 791 | continue; | ||
| 792 | |||
| 793 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 794 | |||
| 795 | chip = irq_data_get_irq_chip(&desc->irq_data); | ||
| 796 | if (chip && chip->irq_cpu_offline && | ||
| 797 | (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || | ||
| 798 | !irqd_irq_disabled(&desc->irq_data))) | ||
| 799 | chip->irq_cpu_offline(&desc->irq_data); | ||
| 800 | |||
| 801 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
| 802 | } | ||
| 803 | } | ||
diff --git a/kernel/irq/debug.h b/kernel/irq/debug.h index d1a33b7fa61d..a0bd875ba3d5 100644 --- a/kernel/irq/debug.h +++ b/kernel/irq/debug.h | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #define P(f) if (desc->status & f) printk("%14s set\n", #f) | 7 | #define P(f) if (desc->status & f) printk("%14s set\n", #f) |
| 8 | #define PS(f) if (desc->istate & f) printk("%14s set\n", #f) | 8 | #define PS(f) if (desc->istate & f) printk("%14s set\n", #f) |
| 9 | /* FIXME */ | ||
| 10 | #define PD(f) do { } while (0) | ||
| 9 | 11 | ||
| 10 | static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) | 12 | static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) |
| 11 | { | 13 | { |
| @@ -28,13 +30,15 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) | |||
| 28 | P(IRQ_NOAUTOEN); | 30 | P(IRQ_NOAUTOEN); |
| 29 | 31 | ||
| 30 | PS(IRQS_AUTODETECT); | 32 | PS(IRQS_AUTODETECT); |
| 31 | PS(IRQS_INPROGRESS); | ||
| 32 | PS(IRQS_REPLAY); | 33 | PS(IRQS_REPLAY); |
| 33 | PS(IRQS_WAITING); | 34 | PS(IRQS_WAITING); |
| 34 | PS(IRQS_DISABLED); | ||
| 35 | PS(IRQS_PENDING); | 35 | PS(IRQS_PENDING); |
| 36 | PS(IRQS_MASKED); | 36 | |
| 37 | PD(IRQS_INPROGRESS); | ||
| 38 | PD(IRQS_DISABLED); | ||
| 39 | PD(IRQS_MASKED); | ||
| 37 | } | 40 | } |
| 38 | 41 | ||
| 39 | #undef P | 42 | #undef P |
| 40 | #undef PS | 43 | #undef PS |
| 44 | #undef PD | ||
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 517561fc7317..1a2fb77f2fd6 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
| @@ -178,25 +178,13 @@ irqreturn_t handle_irq_event(struct irq_desc *desc) | |||
| 178 | irq_compat_clr_pending(desc); | 178 | irq_compat_clr_pending(desc); |
| 179 | desc->istate &= ~IRQS_PENDING; | 179 | desc->istate &= ~IRQS_PENDING; |
| 180 | irq_compat_set_progress(desc); | 180 | irq_compat_set_progress(desc); |
| 181 | desc->istate |= IRQS_INPROGRESS; | 181 | irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
| 182 | raw_spin_unlock(&desc->lock); | 182 | raw_spin_unlock(&desc->lock); |
| 183 | 183 | ||
| 184 | ret = handle_irq_event_percpu(desc, action); | 184 | ret = handle_irq_event_percpu(desc, action); |
| 185 | 185 | ||
| 186 | raw_spin_lock(&desc->lock); | 186 | raw_spin_lock(&desc->lock); |
| 187 | desc->istate &= ~IRQS_INPROGRESS; | 187 | irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
| 188 | irq_compat_clr_progress(desc); | 188 | irq_compat_clr_progress(desc); |
| 189 | return ret; | 189 | return ret; |
| 190 | } | 190 | } |
| 191 | |||
| 192 | /** | ||
| 193 | * handle_IRQ_event - irq action chain handler | ||
| 194 | * @irq: the interrupt number | ||
| 195 | * @action: the interrupt action chain for this irq | ||
| 196 | * | ||
| 197 | * Handles the action chain of an irq event | ||
| 198 | */ | ||
| 199 | irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | ||
| 200 | { | ||
| 201 | return handle_irq_event_percpu(irq_to_desc(irq), action); | ||
| 202 | } | ||
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 6c6ec9a49027..6b8b9713e28d 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -44,26 +44,20 @@ enum { | |||
| 44 | * IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt | 44 | * IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt |
| 45 | * detection | 45 | * detection |
| 46 | * IRQS_POLL_INPROGRESS - polling in progress | 46 | * IRQS_POLL_INPROGRESS - polling in progress |
| 47 | * IRQS_INPROGRESS - Interrupt in progress | ||
| 48 | * IRQS_ONESHOT - irq is not unmasked in primary handler | 47 | * IRQS_ONESHOT - irq is not unmasked in primary handler |
| 49 | * IRQS_REPLAY - irq is replayed | 48 | * IRQS_REPLAY - irq is replayed |
| 50 | * IRQS_WAITING - irq is waiting | 49 | * IRQS_WAITING - irq is waiting |
| 51 | * IRQS_DISABLED - irq is disabled | ||
| 52 | * IRQS_PENDING - irq is pending and replayed later | 50 | * IRQS_PENDING - irq is pending and replayed later |
| 53 | * IRQS_MASKED - irq is masked | ||
| 54 | * IRQS_SUSPENDED - irq is suspended | 51 | * IRQS_SUSPENDED - irq is suspended |
| 55 | */ | 52 | */ |
| 56 | enum { | 53 | enum { |
| 57 | IRQS_AUTODETECT = 0x00000001, | 54 | IRQS_AUTODETECT = 0x00000001, |
| 58 | IRQS_SPURIOUS_DISABLED = 0x00000002, | 55 | IRQS_SPURIOUS_DISABLED = 0x00000002, |
| 59 | IRQS_POLL_INPROGRESS = 0x00000008, | 56 | IRQS_POLL_INPROGRESS = 0x00000008, |
| 60 | IRQS_INPROGRESS = 0x00000010, | ||
| 61 | IRQS_ONESHOT = 0x00000020, | 57 | IRQS_ONESHOT = 0x00000020, |
| 62 | IRQS_REPLAY = 0x00000040, | 58 | IRQS_REPLAY = 0x00000040, |
| 63 | IRQS_WAITING = 0x00000080, | 59 | IRQS_WAITING = 0x00000080, |
| 64 | IRQS_DISABLED = 0x00000100, | ||
| 65 | IRQS_PENDING = 0x00000200, | 60 | IRQS_PENDING = 0x00000200, |
| 66 | IRQS_MASKED = 0x00000400, | ||
| 67 | IRQS_SUSPENDED = 0x00000800, | 61 | IRQS_SUSPENDED = 0x00000800, |
| 68 | }; | 62 | }; |
| 69 | 63 | ||
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 6fb014f172f7..2c039c9b9383 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c | |||
| @@ -80,7 +80,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node) | |||
| 80 | desc->irq_data.handler_data = NULL; | 80 | desc->irq_data.handler_data = NULL; |
| 81 | desc->irq_data.msi_desc = NULL; | 81 | desc->irq_data.msi_desc = NULL; |
| 82 | irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); | 82 | irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); |
| 83 | desc->istate = IRQS_DISABLED; | 83 | irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); |
| 84 | desc->handle_irq = handle_bad_irq; | 84 | desc->handle_irq = handle_bad_irq; |
| 85 | desc->depth = 1; | 85 | desc->depth = 1; |
| 86 | desc->irq_count = 0; | 86 | desc->irq_count = 0; |
| @@ -238,7 +238,6 @@ int __init early_irq_init(void) | |||
| 238 | 238 | ||
| 239 | struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { | 239 | struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { |
| 240 | [0 ... NR_IRQS-1] = { | 240 | [0 ... NR_IRQS-1] = { |
| 241 | .istate = IRQS_DISABLED, | ||
| 242 | .handle_irq = handle_bad_irq, | 241 | .handle_irq = handle_bad_irq, |
| 243 | .depth = 1, | 242 | .depth = 1, |
| 244 | .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock), | 243 | .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock), |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a2aa73e536c..acf540768b8f 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -41,7 +41,7 @@ early_param("threadirqs", setup_forced_irqthreads); | |||
| 41 | void synchronize_irq(unsigned int irq) | 41 | void synchronize_irq(unsigned int irq) |
| 42 | { | 42 | { |
| 43 | struct irq_desc *desc = irq_to_desc(irq); | 43 | struct irq_desc *desc = irq_to_desc(irq); |
| 44 | unsigned int state; | 44 | bool inprogress; |
| 45 | 45 | ||
| 46 | if (!desc) | 46 | if (!desc) |
| 47 | return; | 47 | return; |
| @@ -53,16 +53,16 @@ void synchronize_irq(unsigned int irq) | |||
| 53 | * Wait until we're out of the critical section. This might | 53 | * Wait until we're out of the critical section. This might |
| 54 | * give the wrong answer due to the lack of memory barriers. | 54 | * give the wrong answer due to the lack of memory barriers. |
| 55 | */ | 55 | */ |
| 56 | while (desc->istate & IRQS_INPROGRESS) | 56 | while (irqd_irq_inprogress(&desc->irq_data)) |
| 57 | cpu_relax(); | 57 | cpu_relax(); |
| 58 | 58 | ||
| 59 | /* Ok, that indicated we're done: double-check carefully. */ | 59 | /* Ok, that indicated we're done: double-check carefully. */ |
| 60 | raw_spin_lock_irqsave(&desc->lock, flags); | 60 | raw_spin_lock_irqsave(&desc->lock, flags); |
| 61 | state = desc->istate; | 61 | inprogress = irqd_irq_inprogress(&desc->irq_data); |
| 62 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 62 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
| 63 | 63 | ||
| 64 | /* Oops, that failed? */ | 64 | /* Oops, that failed? */ |
| 65 | } while (state & IRQS_INPROGRESS); | 65 | } while (inprogress); |
| 66 | 66 | ||
| 67 | /* | 67 | /* |
| 68 | * We made sure that no hardirq handler is running. Now verify | 68 | * We made sure that no hardirq handler is running. Now verify |
| @@ -112,13 +112,13 @@ void irq_set_thread_affinity(struct irq_desc *desc) | |||
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | #ifdef CONFIG_GENERIC_PENDING_IRQ | 114 | #ifdef CONFIG_GENERIC_PENDING_IRQ |
| 115 | static inline bool irq_can_move_pcntxt(struct irq_desc *desc) | 115 | static inline bool irq_can_move_pcntxt(struct irq_data *data) |
| 116 | { | 116 | { |
| 117 | return irq_settings_can_move_pcntxt(desc); | 117 | return irqd_can_move_in_process_context(data); |
| 118 | } | 118 | } |
| 119 | static inline bool irq_move_pending(struct irq_desc *desc) | 119 | static inline bool irq_move_pending(struct irq_data *data) |
| 120 | { | 120 | { |
| 121 | return irqd_is_setaffinity_pending(&desc->irq_data); | 121 | return irqd_is_setaffinity_pending(data); |
| 122 | } | 122 | } |
| 123 | static inline void | 123 | static inline void |
| 124 | irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) | 124 | irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) |
| @@ -131,43 +131,34 @@ irq_get_pending(struct cpumask *mask, struct irq_desc *desc) | |||
| 131 | cpumask_copy(mask, desc->pending_mask); | 131 | cpumask_copy(mask, desc->pending_mask); |
| 132 | } | 132 | } |
| 133 | #else | 133 | #else |
| 134 | static inline bool irq_can_move_pcntxt(struct irq_desc *desc) { return true; } | 134 | static inline bool irq_can_move_pcntxt(struct irq_data *data) { return true; } |
| 135 | static inline bool irq_move_pending(struct irq_desc *desc) { return false; } | 135 | static inline bool irq_move_pending(struct irq_desc *data) { return false; } |
| 136 | static inline void | 136 | static inline void |
| 137 | irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) { } | 137 | irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) { } |
| 138 | static inline void | 138 | static inline void |
| 139 | irq_get_pending(struct cpumask *mask, struct irq_desc *desc) { } | 139 | irq_get_pending(struct cpumask *mask, struct irq_desc *desc) { } |
| 140 | #endif | 140 | #endif |
| 141 | 141 | ||
| 142 | /** | 142 | int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask) |
| 143 | * irq_set_affinity - Set the irq affinity of a given irq | ||
| 144 | * @irq: Interrupt to set affinity | ||
| 145 | * @cpumask: cpumask | ||
| 146 | * | ||
| 147 | */ | ||
| 148 | int irq_set_affinity(unsigned int irq, const struct cpumask *mask) | ||
| 149 | { | 143 | { |
| 150 | struct irq_desc *desc = irq_to_desc(irq); | 144 | struct irq_chip *chip = irq_data_get_irq_chip(data); |
| 151 | struct irq_chip *chip = desc->irq_data.chip; | 145 | struct irq_desc *desc = irq_data_to_desc(data); |
| 152 | unsigned long flags; | ||
| 153 | int ret = 0; | 146 | int ret = 0; |
| 154 | 147 | ||
| 155 | if (!chip->irq_set_affinity) | 148 | if (!chip || !chip->irq_set_affinity) |
| 156 | return -EINVAL; | 149 | return -EINVAL; |
| 157 | 150 | ||
| 158 | raw_spin_lock_irqsave(&desc->lock, flags); | 151 | if (irq_can_move_pcntxt(data)) { |
| 159 | 152 | ret = chip->irq_set_affinity(data, mask, false); | |
| 160 | if (irq_can_move_pcntxt(desc)) { | ||
| 161 | ret = chip->irq_set_affinity(&desc->irq_data, mask, false); | ||
| 162 | switch (ret) { | 153 | switch (ret) { |
| 163 | case IRQ_SET_MASK_OK: | 154 | case IRQ_SET_MASK_OK: |
| 164 | cpumask_copy(desc->irq_data.affinity, mask); | 155 | cpumask_copy(data->affinity, mask); |
| 165 | case IRQ_SET_MASK_OK_NOCOPY: | 156 | case IRQ_SET_MASK_OK_NOCOPY: |
| 166 | irq_set_thread_affinity(desc); | 157 | irq_set_thread_affinity(desc); |
| 167 | ret = 0; | 158 | ret = 0; |
| 168 | } | 159 | } |
| 169 | } else { | 160 | } else { |
| 170 | irqd_set_move_pending(&desc->irq_data); | 161 | irqd_set_move_pending(data); |
| 171 | irq_copy_pending(desc, mask); | 162 | irq_copy_pending(desc, mask); |
| 172 | } | 163 | } |
| 173 | 164 | ||
| @@ -176,7 +167,28 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *mask) | |||
| 176 | schedule_work(&desc->affinity_notify->work); | 167 | schedule_work(&desc->affinity_notify->work); |
| 177 | } | 168 | } |
| 178 | irq_compat_set_affinity(desc); | 169 | irq_compat_set_affinity(desc); |
| 179 | irqd_set(&desc->irq_data, IRQD_AFFINITY_SET); | 170 | irqd_set(data, IRQD_AFFINITY_SET); |
| 171 | |||
| 172 | return ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | /** | ||
| 176 | * irq_set_affinity - Set the irq affinity of a given irq | ||
| 177 | * @irq: Interrupt to set affinity | ||
| 178 | * @mask: cpumask | ||
| 179 | * | ||
| 180 | */ | ||
| 181 | int irq_set_affinity(unsigned int irq, const struct cpumask *mask) | ||
| 182 | { | ||
| 183 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 184 | unsigned long flags; | ||
| 185 | int ret; | ||
| 186 | |||
| 187 | if (!desc) | ||
| 188 | return -EINVAL; | ||
| 189 | |||
| 190 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
| 191 | ret = __irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask); | ||
| 180 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 192 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
| 181 | return ret; | 193 | return ret; |
| 182 | } | 194 | } |
| @@ -206,7 +218,7 @@ static void irq_affinity_notify(struct work_struct *work) | |||
| 206 | goto out; | 218 | goto out; |
| 207 | 219 | ||
| 208 | raw_spin_lock_irqsave(&desc->lock, flags); | 220 | raw_spin_lock_irqsave(&desc->lock, flags); |
| 209 | if (irq_move_pending(desc)) | 221 | if (irq_move_pending(&desc->irq_data)) |
| 210 | irq_get_pending(cpumask, desc); | 222 | irq_get_pending(cpumask, desc); |
| 211 | else | 223 | else |
| 212 | cpumask_copy(cpumask, desc->irq_data.affinity); | 224 | cpumask_copy(cpumask, desc->irq_data.affinity); |
| @@ -551,9 +563,9 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
| 551 | flags &= IRQ_TYPE_SENSE_MASK; | 563 | flags &= IRQ_TYPE_SENSE_MASK; |
| 552 | 564 | ||
| 553 | if (chip->flags & IRQCHIP_SET_TYPE_MASKED) { | 565 | if (chip->flags & IRQCHIP_SET_TYPE_MASKED) { |
| 554 | if (!(desc->istate & IRQS_MASKED)) | 566 | if (!irqd_irq_masked(&desc->irq_data)) |
| 555 | mask_irq(desc); | 567 | mask_irq(desc); |
| 556 | if (!(desc->istate & IRQS_DISABLED)) | 568 | if (!irqd_irq_disabled(&desc->irq_data)) |
| 557 | unmask = 1; | 569 | unmask = 1; |
| 558 | } | 570 | } |
| 559 | 571 | ||
| @@ -651,7 +663,7 @@ again: | |||
| 651 | * irq_wake_thread(). See the comment there which explains the | 663 | * irq_wake_thread(). See the comment there which explains the |
| 652 | * serialization. | 664 | * serialization. |
| 653 | */ | 665 | */ |
| 654 | if (unlikely(desc->istate & IRQS_INPROGRESS)) { | 666 | if (unlikely(irqd_irq_inprogress(&desc->irq_data))) { |
| 655 | raw_spin_unlock_irq(&desc->lock); | 667 | raw_spin_unlock_irq(&desc->lock); |
| 656 | chip_bus_sync_unlock(desc); | 668 | chip_bus_sync_unlock(desc); |
| 657 | cpu_relax(); | 669 | cpu_relax(); |
| @@ -668,12 +680,10 @@ again: | |||
| 668 | 680 | ||
| 669 | desc->threads_oneshot &= ~action->thread_mask; | 681 | desc->threads_oneshot &= ~action->thread_mask; |
| 670 | 682 | ||
| 671 | if (!desc->threads_oneshot && !(desc->istate & IRQS_DISABLED) && | 683 | if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && |
| 672 | (desc->istate & IRQS_MASKED)) { | 684 | irqd_irq_masked(&desc->irq_data)) |
| 673 | irq_compat_clr_masked(desc); | 685 | unmask_irq(desc); |
| 674 | desc->istate &= ~IRQS_MASKED; | 686 | |
| 675 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | ||
| 676 | } | ||
| 677 | out_unlock: | 687 | out_unlock: |
| 678 | raw_spin_unlock_irq(&desc->lock); | 688 | raw_spin_unlock_irq(&desc->lock); |
| 679 | chip_bus_sync_unlock(desc); | 689 | chip_bus_sync_unlock(desc); |
| @@ -767,7 +777,7 @@ static int irq_thread(void *data) | |||
| 767 | atomic_inc(&desc->threads_active); | 777 | atomic_inc(&desc->threads_active); |
| 768 | 778 | ||
| 769 | raw_spin_lock_irq(&desc->lock); | 779 | raw_spin_lock_irq(&desc->lock); |
| 770 | if (unlikely(desc->istate & IRQS_DISABLED)) { | 780 | if (unlikely(irqd_irq_disabled(&desc->irq_data))) { |
| 771 | /* | 781 | /* |
| 772 | * CHECKME: We might need a dedicated | 782 | * CHECKME: We might need a dedicated |
| 773 | * IRQ_THREAD_PENDING flag here, which | 783 | * IRQ_THREAD_PENDING flag here, which |
| @@ -985,8 +995,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 985 | } | 995 | } |
| 986 | 996 | ||
| 987 | desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \ | 997 | desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \ |
| 988 | IRQS_INPROGRESS | IRQS_ONESHOT | \ | 998 | IRQS_ONESHOT | IRQS_WAITING); |
| 989 | IRQS_WAITING); | 999 | irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
| 990 | 1000 | ||
| 991 | if (new->flags & IRQF_PERCPU) { | 1001 | if (new->flags & IRQF_PERCPU) { |
| 992 | irqd_set(&desc->irq_data, IRQD_PER_CPU); | 1002 | irqd_set(&desc->irq_data, IRQD_PER_CPU); |
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index ec4806d4778b..e33d9c8d5089 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c | |||
| @@ -60,13 +60,12 @@ void move_masked_irq(int irq) | |||
| 60 | 60 | ||
| 61 | void irq_move_irq(struct irq_data *idata) | 61 | void irq_move_irq(struct irq_data *idata) |
| 62 | { | 62 | { |
| 63 | struct irq_desc *desc = irq_data_to_desc(idata); | ||
| 64 | bool masked; | 63 | bool masked; |
| 65 | 64 | ||
| 66 | if (likely(!irqd_is_setaffinity_pending(idata))) | 65 | if (likely(!irqd_is_setaffinity_pending(idata))) |
| 67 | return; | 66 | return; |
| 68 | 67 | ||
| 69 | if (unlikely(desc->istate & IRQS_DISABLED)) | 68 | if (unlikely(irqd_irq_disabled(idata))) |
| 70 | return; | 69 | return; |
| 71 | 70 | ||
| 72 | /* | 71 | /* |
| @@ -74,7 +73,7 @@ void irq_move_irq(struct irq_data *idata) | |||
| 74 | * threaded interrupt with ONESHOT set, we can end up with an | 73 | * threaded interrupt with ONESHOT set, we can end up with an |
| 75 | * interrupt storm. | 74 | * interrupt storm. |
| 76 | */ | 75 | */ |
| 77 | masked = desc->istate & IRQS_MASKED; | 76 | masked = irqd_irq_masked(idata); |
| 78 | if (!masked) | 77 | if (!masked) |
| 79 | idata->chip->irq_mask(idata); | 78 | idata->chip->irq_mask(idata); |
| 80 | irq_move_masked_irq(idata); | 79 | irq_move_masked_irq(idata); |
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index dd586ebf9c8c..83f4799f46be 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c | |||
| @@ -45,12 +45,12 @@ bool irq_wait_for_poll(struct irq_desc *desc) | |||
| 45 | #ifdef CONFIG_SMP | 45 | #ifdef CONFIG_SMP |
| 46 | do { | 46 | do { |
| 47 | raw_spin_unlock(&desc->lock); | 47 | raw_spin_unlock(&desc->lock); |
| 48 | while (desc->istate & IRQS_INPROGRESS) | 48 | while (irqd_irq_inprogress(&desc->irq_data)) |
| 49 | cpu_relax(); | 49 | cpu_relax(); |
| 50 | raw_spin_lock(&desc->lock); | 50 | raw_spin_lock(&desc->lock); |
| 51 | } while (desc->istate & IRQS_INPROGRESS); | 51 | } while (irqd_irq_inprogress(&desc->irq_data)); |
| 52 | /* Might have been disabled in meantime */ | 52 | /* Might have been disabled in meantime */ |
| 53 | return !(desc->istate & IRQS_DISABLED) && desc->action; | 53 | return !irqd_irq_disabled(&desc->irq_data) && desc->action; |
| 54 | #else | 54 | #else |
| 55 | return false; | 55 | return false; |
| 56 | #endif | 56 | #endif |
| @@ -75,7 +75,7 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) | |||
| 75 | * Do not poll disabled interrupts unless the spurious | 75 | * Do not poll disabled interrupts unless the spurious |
| 76 | * disabled poller asks explicitely. | 76 | * disabled poller asks explicitely. |
| 77 | */ | 77 | */ |
| 78 | if ((desc->istate & IRQS_DISABLED) && !force) | 78 | if (irqd_irq_disabled(&desc->irq_data) && !force) |
| 79 | goto out; | 79 | goto out; |
| 80 | 80 | ||
| 81 | /* | 81 | /* |
| @@ -88,7 +88,7 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) | |||
| 88 | goto out; | 88 | goto out; |
| 89 | 89 | ||
| 90 | /* Already running on another processor */ | 90 | /* Already running on another processor */ |
| 91 | if (desc->istate & IRQS_INPROGRESS) { | 91 | if (irqd_irq_inprogress(&desc->irq_data)) { |
| 92 | /* | 92 | /* |
| 93 | * Already running: If it is shared get the other | 93 | * Already running: If it is shared get the other |
| 94 | * CPU to go looking for our mystery interrupt too | 94 | * CPU to go looking for our mystery interrupt too |
diff --git a/kernel/signal.c b/kernel/signal.c index 324eff5468ad..1186cf7fac77 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -2437,7 +2437,7 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, | |||
| 2437 | /* Not even root can pretend to send signals from the kernel. | 2437 | /* Not even root can pretend to send signals from the kernel. |
| 2438 | * Nor can they impersonate a kill()/tgkill(), which adds source info. | 2438 | * Nor can they impersonate a kill()/tgkill(), which adds source info. |
| 2439 | */ | 2439 | */ |
| 2440 | if (info.si_code != SI_QUEUE) { | 2440 | if (info.si_code >= 0 || info.si_code == SI_TKILL) { |
| 2441 | /* We used to allow any < 0 si_code */ | 2441 | /* We used to allow any < 0 si_code */ |
| 2442 | WARN_ON_ONCE(info.si_code < 0); | 2442 | WARN_ON_ONCE(info.si_code < 0); |
| 2443 | return -EPERM; | 2443 | return -EPERM; |
| @@ -2457,7 +2457,7 @@ long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) | |||
| 2457 | /* Not even root can pretend to send signals from the kernel. | 2457 | /* Not even root can pretend to send signals from the kernel. |
| 2458 | * Nor can they impersonate a kill()/tgkill(), which adds source info. | 2458 | * Nor can they impersonate a kill()/tgkill(), which adds source info. |
| 2459 | */ | 2459 | */ |
| 2460 | if (info->si_code != SI_QUEUE) { | 2460 | if (info->si_code >= 0 || info->si_code == SI_TKILL) { |
| 2461 | /* We used to allow any < 0 si_code */ | 2461 | /* We used to allow any < 0 si_code */ |
| 2462 | WARN_ON_ONCE(info->si_code < 0); | 2462 | WARN_ON_ONCE(info->si_code < 0); |
| 2463 | return -EPERM; | 2463 | return -EPERM; |
