diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2012-03-26 18:57:26 -0700 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2012-03-26 18:57:26 -0700 |
commit | fc2ed77b9d6b579d61024163c74f41c24394fcc7 (patch) | |
tree | 903d80ba1b1fc0eb15e122a8c12a72f72e7ed2de | |
parent | 3d04d42312eacc68fbcddea337f7eb34bc035dfb (diff) | |
parent | 50269e19ad990e79eeda101fc6df80cffd5d4831 (diff) | |
download | linux-fc2ed77b9d6b579d61024163c74f41c24394fcc7.tar.gz linux-fc2ed77b9d6b579d61024163c74f41c24394fcc7.tar.bz2 linux-fc2ed77b9d6b579d61024163c74f41c24394fcc7.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
720 files changed, 26817 insertions, 13396 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power index 8ffbc25376a0..840f7d64d483 100644 --- a/Documentation/ABI/testing/sysfs-devices-power +++ b/Documentation/ABI/testing/sysfs-devices-power @@ -165,3 +165,21 @@ Description: Not all drivers support this attribute. If it isn't supported, attempts to read or write it will yield I/O errors. + +What: /sys/devices/.../power/pm_qos_latency_us +Date: March 2012 +Contact: Rafael J. Wysocki <rjw@sisk.pl> +Description: + The /sys/devices/.../power/pm_qos_resume_latency_us attribute + contains the PM QoS resume latency limit for the given device, + which is the maximum allowed time it can take to resume the + device, after it has been suspended at run time, from a resume + request to the moment the device will be ready to process I/O, + in microseconds. If it is equal to 0, however, this means that + the PM QoS resume latency may be arbitrary. + + Not all drivers support this attribute. If it isn't supported, + it is not present. + + This attribute has no effect on system-wide suspend/resume and + hibernation. diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt new file mode 100644 index 000000000000..27dcaabfb4db --- /dev/null +++ b/Documentation/IRQ-domain.txt @@ -0,0 +1,117 @@ +irq_domain interrupt number mapping library + +The current design of the Linux kernel uses a single large number +space where each separate IRQ source is assigned a different number. +This is simple when there is only one interrupt controller, but in +systems with multiple interrupt controllers the kernel must ensure +that each one gets assigned non-overlapping allocations of Linux +IRQ numbers. + +The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of +irq numbers, but they don't provide any support for reverse mapping of +the controller-local IRQ (hwirq) number into the Linux IRQ number +space. + +The irq_domain library adds mapping between hwirq and IRQ numbers on +top of the irq_alloc_desc*() API. An irq_domain to manage mapping is +preferred over interrupt controller drivers open coding their own +reverse mapping scheme. + +irq_domain also implements translation from Device Tree interrupt +specifiers to hwirq numbers, and can be easily extended to support +other IRQ topology data sources. + +=== irq_domain usage === +An interrupt controller driver creates and registers an irq_domain by +calling one of the irq_domain_add_*() functions (each mapping method +has a different allocator function, more on that later). The function +will return a pointer to the irq_domain on success. The caller must +provide the allocator function with an irq_domain_ops structure with +the .map callback populated as a minimum. + +In most cases, the irq_domain will begin empty without any mappings +between hwirq and IRQ numbers. Mappings are added to the irq_domain +by calling irq_create_mapping() which accepts the irq_domain and a +hwirq number as arguments. If a mapping for the hwirq doesn't already +exist then it will allocate a new Linux irq_desc, associate it with +the hwirq, and call the .map() callback so the driver can perform any +required hardware setup. + +When an interrupt is received, irq_find_mapping() function should +be used to find the Linux IRQ number from the hwirq number. + +If the driver has the Linux IRQ number or the irq_data pointer, and +needs to know the associated hwirq number (such as in the irq_chip +callbacks) then it can be directly obtained from irq_data->hwirq. + +=== Types of irq_domain mappings === +There are several mechanisms available for reverse mapping from hwirq +to Linux irq, and each mechanism uses a different allocation function. +Which reverse map type should be used depends on the use case. Each +of the reverse map types are described below: + +==== Linear ==== +irq_domain_add_linear() + +The linear reverse map maintains a fixed size table indexed by the +hwirq number. When a hwirq is mapped, an irq_desc is allocated for +the hwirq, and the IRQ number is stored in the table. + +The Linear map is a good choice when the maximum number of hwirqs is +fixed and a relatively small number (~ < 256). The advantages of this +map are fixed time lookup for IRQ numbers, and irq_descs are only +allocated for in-use IRQs. The disadvantage is that the table must be +as large as the largest possible hwirq number. + +The majority of drivers should use the linear map. + +==== Tree ==== +irq_domain_add_tree() + +The irq_domain maintains a radix tree map from hwirq numbers to Linux +IRQs. When an hwirq is mapped, an irq_desc is allocated and the +hwirq is used as the lookup key for the radix tree. + +The tree map is a good choice if the hwirq number can be very large +since it doesn't need to allocate a table as large as the largest +hwirq number. The disadvantage is that hwirq to IRQ number lookup is +dependent on how many entries are in the table. + +Very few drivers should need this mapping. At the moment, powerpc +iseries is the only user. + +==== No Map ===- +irq_domain_add_nomap() + +The No Map mapping is to be used when the hwirq number is +programmable in the hardware. In this case it is best to program the +Linux IRQ number into the hardware itself so that no mapping is +required. Calling irq_create_direct_mapping() will allocate a Linux +IRQ number and call the .map() callback so that driver can program the +Linux IRQ number into the hardware. + +Most drivers cannot use this mapping. + +==== Legacy ==== +irq_domain_add_legacy() +irq_domain_add_legacy_isa() + +The Legacy mapping is a special case for drivers that already have a +range of irq_descs allocated for the hwirqs. It is used when the +driver cannot be immediately converted to use the linear mapping. For +example, many embedded system board support files use a set of #defines +for IRQ numbers that are passed to struct device registrations. In that +case the Linux IRQ numbers cannot be dynamically assigned and the legacy +mapping should be used. + +The legacy map assumes a contiguous range of IRQ numbers has already +been allocated for the controller and that the IRQ number can be +calculated by adding a fixed offset to the hwirq number, and +visa-versa. The disadvantage is that it requires the interrupt +controller to manage IRQ allocations and it requires an irq_desc to be +allocated for every hwirq, even if it is unused. + +The legacy map should only be used if fixed IRQ mappings must be +supported. For example, ISA controllers would use the legacy map for +mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ +numbers. diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt new file mode 100644 index 000000000000..6528e215c5fe --- /dev/null +++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt @@ -0,0 +1,21 @@ +* Samsung Exynos Power Domains + +Exynos processors include support for multiple power domains which are used +to gate power to one or more peripherals on the processor. + +Required Properties: +- compatiable: should be one of the following. + * samsung,exynos4210-pd - for exynos4210 type power domain. +- reg: physical base address of the controller and length of memory mapped + region. + +Optional Properties: +- samsung,exynos4210-pd-off: Specifies that the power domain is in turned-off + state during boot and remains to be turned-off until explicitly turned-on. + +Example: + + lcd0: power-domain-lcd0 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10023C00 0x10>; + }; diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index edc618a8aab2..e78e8bccac30 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -41,3 +41,9 @@ Boards: - OMAP4 PandaBoard : Low cost community board compatible = "ti,omap4-panda", "ti,omap4430" + +- OMAP3 EVM : Software Developement Board for OMAP35x, AM/DM37x + compatible = "ti,omap3-evm", "ti,omap3" + +- AM335X EVM : Software Developement Board for AM335x + compatible = "ti,am335x-evm", "ti,am33xx", "ti,omap3" diff --git a/Documentation/devicetree/bindings/regulator/twl-regulator.txt b/Documentation/devicetree/bindings/regulator/twl-regulator.txt new file mode 100644 index 000000000000..0c3395d55ac1 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/twl-regulator.txt @@ -0,0 +1,68 @@ +TWL family of regulators + +Required properties: +For twl6030 regulators/LDOs +- compatible: + - "ti,twl6030-vaux1" for VAUX1 LDO + - "ti,twl6030-vaux2" for VAUX2 LDO + - "ti,twl6030-vaux3" for VAUX3 LDO + - "ti,twl6030-vmmc" for VMMC LDO + - "ti,twl6030-vpp" for VPP LDO + - "ti,twl6030-vusim" for VUSIM LDO + - "ti,twl6030-vana" for VANA LDO + - "ti,twl6030-vcxio" for VCXIO LDO + - "ti,twl6030-vdac" for VDAC LDO + - "ti,twl6030-vusb" for VUSB LDO + - "ti,twl6030-v1v8" for V1V8 LDO + - "ti,twl6030-v2v1" for V2V1 LDO + - "ti,twl6030-clk32kg" for CLK32KG RESOURCE + - "ti,twl6030-vdd1" for VDD1 SMPS + - "ti,twl6030-vdd2" for VDD2 SMPS + - "ti,twl6030-vdd3" for VDD3 SMPS +For twl6025 regulators/LDOs +- compatible: + - "ti,twl6025-ldo1" for LDO1 LDO + - "ti,twl6025-ldo2" for LDO2 LDO + - "ti,twl6025-ldo3" for LDO3 LDO + - "ti,twl6025-ldo4" for LDO4 LDO + - "ti,twl6025-ldo5" for LDO5 LDO + - "ti,twl6025-ldo6" for LDO6 LDO + - "ti,twl6025-ldo7" for LDO7 LDO + - "ti,twl6025-ldoln" for LDOLN LDO + - "ti,twl6025-ldousb" for LDOUSB LDO + - "ti,twl6025-smps3" for SMPS3 SMPS + - "ti,twl6025-smps4" for SMPS4 SMPS + - "ti,twl6025-vio" for VIO SMPS +For twl4030 regulators/LDOs +- compatible: + - "ti,twl4030-vaux1" for VAUX1 LDO + - "ti,twl4030-vaux2" for VAUX2 LDO + - "ti,twl5030-vaux2" for VAUX2 LDO + - "ti,twl4030-vaux3" for VAUX3 LDO + - "ti,twl4030-vaux4" for VAUX4 LDO + - "ti,twl4030-vmmc1" for VMMC1 LDO + - "ti,twl4030-vmmc2" for VMMC2 LDO + - "ti,twl4030-vpll1" for VPLL1 LDO + - "ti,twl4030-vpll2" for VPLL2 LDO + - "ti,twl4030-vsim" for VSIM LDO + - "ti,twl4030-vdac" for VDAC LDO + - "ti,twl4030-vintana2" for VINTANA2 LDO + - "ti,twl4030-vio" for VIO LDO + - "ti,twl4030-vdd1" for VDD1 SMPS + - "ti,twl4030-vdd2" for VDD2 SMPS + - "ti,twl4030-vintana1" for VINTANA1 LDO + - "ti,twl4030-vintdig" for VINTDIG LDO + - "ti,twl4030-vusb1v5" for VUSB1V5 LDO + - "ti,twl4030-vusb1v8" for VUSB1V8 LDO + - "ti,twl4030-vusb3v1" for VUSB3V1 LDO + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt + +Example: + + xyz: regulator@0 { + compatible = "ti,twl6030-vaux1"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + }; diff --git a/Documentation/devicetree/bindings/spi/omap-spi.txt b/Documentation/devicetree/bindings/spi/omap-spi.txt new file mode 100644 index 000000000000..81df374adbb9 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/omap-spi.txt @@ -0,0 +1,20 @@ +OMAP2+ McSPI device + +Required properties: +- compatible : + - "ti,omap2-spi" for OMAP2 & OMAP3. + - "ti,omap4-spi" for OMAP4+. +- ti,spi-num-cs : Number of chipselect supported by the instance. +- ti,hwmods: Name of the hwmod associated to the McSPI + + +Example: + +mcspi1: mcspi@1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,omap4-mcspi"; + ti,hwmods = "mcspi1"; + ti,spi-num-cs = <4>; +}; + diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 41c0c5d1ba14..2a596a4fc23e 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -271,3 +271,8 @@ IOMAP pcim_iounmap() pcim_iomap_table() : array of mapped addresses indexed by BAR pcim_iomap_regions() : do request_region() and iomap() on multiple BARs + +REGULATOR + devm_regulator_get() + devm_regulator_put() + devm_regulator_bulk_get() diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index d5dc80f30352..4bfd982f8080 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -535,3 +535,11 @@ Why: This driver provides support for USB storage devices like "USB (CONFIG_USB_STORAGE) which only drawback is the additional SCSI stack. Who: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> + +---------------------------- + +What: kmap_atomic(page, km_type) +When: 3.5 +Why: The old kmap_atomic() with two arguments is deprecated, we only + keep it for backward compatibility for few cycles and then drop it. +Who: Cong Wang <amwang@redhat.com> diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index e5f982c845fd..2cfa25667123 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -2,6 +2,10 @@ Kernel driver adm1275 ===================== Supported chips: + * Analog Devices ADM1075 + Prefix: 'adm1075' + Addresses scanned: - + Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1075.pdf * Analog Devices ADM1275 Prefix: 'adm1275' Addresses scanned: - @@ -17,13 +21,13 @@ Author: Guenter Roeck <guenter.roeck@ericsson.com> Description ----------- -This driver supports hardware montoring for Analog Devices ADM1275 and ADM1276 -Hot-Swap Controller and Digital Power Monitor. +This driver supports hardware montoring for Analog Devices ADM1075, ADM1275, +and ADM1276 Hot-Swap Controller and Digital Power Monitor. -ADM1275 and ADM1276 are hot-swap controllers that allow a circuit board to be -removed from or inserted into a live backplane. They also feature current and -voltage readback via an integrated 12-bit analog-to-digital converter (ADC), -accessed using a PMBus interface. +ADM1075, ADM1275, and ADM1276 are hot-swap controllers that allow a circuit +board to be removed from or inserted into a live backplane. They also feature +current and voltage readback via an integrated 12-bit analog-to-digital +converter (ADC), accessed using a PMBus interface. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -36,6 +40,10 @@ This driver does not auto-detect devices. You will have to instantiate the devices explicitly. Please see Documentation/i2c/instantiating-devices for details. +The ADM1075, unlike many other PMBus devices, does not support internal voltage +or current scaling. Reported voltages, currents, and power are raw measurements, +and will typically have to be scaled. + Platform data support --------------------- @@ -51,7 +59,8 @@ The following attributes are supported. Limits are read-write, history reset attributes are write-only, all other attributes are read-only. in1_label "vin1" or "vout1" depending on chip variant and - configuration. + configuration. On ADM1075, vout1 reports the voltage on + the VAUX pin. in1_input Measured voltage. in1_min Minimum Voltage. in1_max Maximum voltage. @@ -74,3 +83,10 @@ curr1_crit Critical maximum current. Depending on the chip curr1_crit_alarm Critical current high alarm. curr1_highest Historical maximum current. curr1_reset_history Write any value to reset history. + +power1_label "pin1" +power1_input Input power. +power1_reset_history Write any value to reset history. + + Power attributes are supported on ADM1075 and ADM1276 + only. diff --git a/Documentation/hwmon/jc42 b/Documentation/hwmon/jc42 index 52729a756c1b..66ecb9fc8246 100644 --- a/Documentation/hwmon/jc42 +++ b/Documentation/hwmon/jc42 @@ -3,71 +3,50 @@ Kernel driver jc42 Supported chips: * Analog Devices ADT7408 - Prefix: 'adt7408' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://www.analog.com/static/imported-files/data_sheets/ADT7408.pdf * Atmel AT30TS00 - Prefix: 'at30ts00' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://www.atmel.com/Images/doc8585.pdf * IDT TSE2002B3, TSE2002GB2, TS3000B3, TS3000GB2 - Prefix: 'tse2002', 'ts3000' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf http://www.idt.com/sites/default/files/documents/IDT_TSE2002GB2A1_DST_20111107_120303145914.pdf http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf http://www.idt.com/sites/default/files/documents/IDT_TS3000GB2A1_DST_20111104_120303151012.pdf * Maxim MAX6604 - Prefix: 'max6604' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf * Microchip MCP9804, MCP9805, MCP98242, MCP98243, MCP9843 - Prefixes: 'mcp9804', 'mcp9805', 'mcp98242', 'mcp98243', 'mcp9843' - Addresses scanned: I2C 0x18 - 0x1f Datasheets: http://ww1.microchip.com/downloads/en/DeviceDoc/22203C.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21977b.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/21996a.pdf http://ww1.microchip.com/downloads/en/DeviceDoc/22153c.pdf - * NXP Semiconductors SE97, SE97B - Prefix: 'se97' - Addresses scanned: I2C 0x18 - 0x1f + * NXP Semiconductors SE97, SE97B, SE98, SE98A Datasheets: http://www.nxp.com/documents/data_sheet/SE97.pdf http://www.nxp.com/documents/data_sheet/SE97B.pdf - * NXP Semiconductors SE98 - Prefix: 'se98' - Addresses scanned: I2C 0x18 - 0x1f - Datasheets: http://www.nxp.com/documents/data_sheet/SE98.pdf + http://www.nxp.com/documents/data_sheet/SE98A.pdf * ON Semiconductor CAT34TS02, CAT6095 - Prefix: 'cat34ts02', 'cat6095' - Addresses scanned: I2C 0x18 - 0x1f Datasheet: http://www.onsemi.com/pub_link/Collateral/CAT34TS02-D.PDF http://www.onsemi.com/pub/Collateral/CAT6095-D.PDF - * ST Microelectronics STTS424, STTS424E02 - Prefix: 'stts424' - Addresses scanned: I2C 0x18 - 0x1f - Datasheets: - http://www.st.com/stonline/products/literature/ds/13447/stts424.pdf - http://www.st.com/stonline/products/literature/ds/13448/stts424e02.pdf - * ST Microelectronics STTS2002, STTS3000 - Prefix: 'stts2002', 'stts3000' - Addresses scanned: I2C 0x18 - 0x1f + * ST Microelectronics STTS424, STTS424E02, STTS2002, STTS3000 Datasheets: + http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157556.pdf + http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00157558.pdf http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00225278.pdf http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00270920.pdf * JEDEC JC 42.4 compliant temperature sensor chips - Prefix: 'jc42' - Addresses scanned: I2C 0x18 - 0x1f Datasheet: http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf + Common for all chips: + Prefix: 'jc42' + Addresses scanned: I2C 0x18 - 0x1f + Author: Guenter Roeck <guenter.roeck@ericsson.com> diff --git a/Documentation/hwmon/lm80 b/Documentation/hwmon/lm80 index cb5b407ba3e6..a60b43efc32b 100644 --- a/Documentation/hwmon/lm80 +++ b/Documentation/hwmon/lm80 @@ -7,6 +7,11 @@ Supported chips: Addresses scanned: I2C 0x28 - 0x2f Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ + * National Semiconductor LM96080 + Prefix: 'lm96080' + Addresses scanned: I2C 0x28 - 0x2f + Datasheet: Publicly available at the National Semiconductor website + http://www.national.com/ Authors: Frodo Looijaard <frodol@dds.nl>, @@ -17,7 +22,9 @@ Description This driver implements support for the National Semiconductor LM80. It is described as a 'Serial Interface ACPI-Compatible Microprocessor -System Hardware Monitor'. +System Hardware Monitor'. The LM96080 is a more recent incarnation, +it is pin and register compatible, with a few additional features not +yet supported by the driver. The LM80 implements one temperature sensor, two fan rotation speed sensors, seven voltage sensors, alarms, and some miscellaneous stuff. diff --git a/Documentation/hwmon/max34440 b/Documentation/hwmon/max34440 index 19743919ea56..04482226db20 100644 --- a/Documentation/hwmon/max34440 +++ b/Documentation/hwmon/max34440 @@ -11,6 +11,11 @@ Supported chips: Prefixes: 'max34441' Addresses scanned: - Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf + * Maxim MAX34446 + PMBus Power-Supply Data Logger + Prefixes: 'max34446' + Addresses scanned: - + Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34446.pdf Author: Guenter Roeck <guenter.roeck@ericsson.com> @@ -19,8 +24,8 @@ Description ----------- This driver supports hardware montoring for Maxim MAX34440 PMBus 6-Channel -Power-Supply Manager and MAX34441 PMBus 5-Channel Power-Supply Manager -and Intelligent Fan Controller. +Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply Manager +and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Logger. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -33,6 +38,13 @@ This driver does not auto-detect devices. You will have to instantiate the devices explicitly. Please see Documentation/i2c/instantiating-devices for details. +For MAX34446, the value of the currX_crit attribute determines if current or +voltage measurement is enabled for a given channel. Voltage measurement is +enabled if currX_crit is set to 0; current measurement is enabled if the +attribute is set to a positive value. Power measurement is only enabled if +channel 1 (3) is configured for voltage measurement, and channel 2 (4) is +configured for current measurement. + Platform data support --------------------- @@ -56,19 +68,31 @@ in[1-6]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. in[1-6]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. in[1-6]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status. in[1-6]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status. +in[1-6]_lowest Historical minimum voltage. in[1-6]_highest Historical maximum voltage. in[1-6]_reset_history Write any value to reset history. + MAX34446 only supports in[1-4]. + curr[1-6]_label "iout[1-6]". curr[1-6]_input Measured current. From READ_IOUT register. curr[1-6]_max Maximum current. From IOUT_OC_WARN_LIMIT register. curr[1-6]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register. curr[1-6]_max_alarm Current high alarm. From IOUT_OC_WARNING status. curr[1-6]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status. +curr[1-4]_average Historical average current (MAX34446 only). curr[1-6]_highest Historical maximum current. curr[1-6]_reset_history Write any value to reset history. in6 and curr6 attributes only exist for MAX34440. + MAX34446 only supports curr[1-4]. + +power[1,3]_label "pout[1,3]" +power[1,3]_input Measured power. +power[1,3]_average Historical average power. +power[1,3]_highest Historical maximum power. + + Power attributes only exist for MAX34446. temp[1-8]_input Measured temperatures. From READ_TEMPERATURE_1 register. temp1 is the chip's internal temperature. temp2..temp5 @@ -79,7 +103,9 @@ temp[1-8]_max Maximum temperature. From OT_WARN_LIMIT register. temp[1-8]_crit Critical high temperature. From OT_FAULT_LIMIT register. temp[1-8]_max_alarm Temperature high alarm. temp[1-8]_crit_alarm Temperature critical high alarm. +temp[1-8]_average Historical average temperature (MAX34446 only). temp[1-8]_highest Historical maximum temperature. temp[1-8]_reset_history Write any value to reset history. temp7 and temp8 attributes only exist for MAX34440. + MAX34446 only supports temp[1-3]. diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index d28b591753d1..f90f99920cc5 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus @@ -15,13 +15,20 @@ Supported chips: http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF * Lineage Power - Prefixes: 'pdt003', 'pdt006', 'pdt012', 'udt020' + Prefixes: 'mdt040', 'pdt003', 'pdt006', 'pdt012', 'udt020' Addresses scanned: - Datasheets: http://www.lineagepower.com/oem/pdf/PDT003A0X.pdf http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf + http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf + * Texas Instruments TPS40400, TPS40422 + Prefixes: 'tps40400', 'tps40422' + Addresses scanned: - + Datasheets: + http://www.ti.com/lit/gpn/tps40400 + http://www.ti.com/lit/gpn/tps40422 * Generic PMBus devices Prefix: 'pmbus' Addresses scanned: - diff --git a/Documentation/hwmon/sch5627 b/Documentation/hwmon/sch5627 index 446a054e4912..0551d266c51c 100644 --- a/Documentation/hwmon/sch5627 +++ b/Documentation/hwmon/sch5627 @@ -16,6 +16,11 @@ Description SMSC SCH5627 Super I/O chips include complete hardware monitoring capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures. +The SMSC SCH5627 hardware monitoring part also contains an integrated +watchdog. In order for this watchdog to function some motherboard specific +initialization most be done by the BIOS, so if the watchdog is not enabled +by the BIOS the sch5627 driver will not register a watchdog device. + The hardware monitoring part of the SMSC SCH5627 is accessed by talking through an embedded microcontroller. An application note describing the protocol for communicating with the microcontroller is available upon diff --git a/Documentation/hwmon/sch5636 b/Documentation/hwmon/sch5636 index f83bd1c260f0..7b0a01da0717 100644 --- a/Documentation/hwmon/sch5636 +++ b/Documentation/hwmon/sch5636 @@ -26,6 +26,9 @@ temperatures. Note that the driver detects how many fan headers / temperature sensors are actually implemented on the motherboard, so you will likely see fewer temperature and fan inputs. +The Fujitsu Theseus hwmon solution also contains an integrated watchdog. +This watchdog is fully supported by the sch5636 driver. + An application note describing the Theseus' registers, as well as an application note describing the protocol for communicating with the microcontroller is available upon request. Please mail me if you want a copy. diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100 index 98ebacbdd8d9..a995b41724fd 100644 --- a/Documentation/hwmon/zl6100 +++ b/Documentation/hwmon/zl6100 @@ -34,6 +34,14 @@ Supported chips: Prefix: 'zl6105' Addresses scanned: - Datasheet: http://www.intersil.com/data/fn/fn6906.pdf + * Intersil / Zilker Labs ZL9101M + Prefix: 'zl9101' + Addresses scanned: - + Datasheet: http://www.intersil.com/data/fn/fn7669.pdf + * Intersil / Zilker Labs ZL9117M + Prefix: 'zl9117' + Addresses scanned: - + Datasheet: http://www.intersil.com/data/fn/fn7914.pdf * Ericsson BMR450, BMR451 Prefix: 'bmr450', 'bmr451' Addresses scanned: - diff --git a/Documentation/networking/dns_resolver.txt b/Documentation/networking/dns_resolver.txt index 7f531ad83285..d86adcdae420 100644 --- a/Documentation/networking/dns_resolver.txt +++ b/Documentation/networking/dns_resolver.txt @@ -102,6 +102,10 @@ implemented in the module can be called after doing: If _expiry is non-NULL, the expiry time (TTL) of the result will be returned also. +The kernel maintains an internal keyring in which it caches looked up keys. +This can be cleared by any process that has the CAP_SYS_ADMIN capability by +the use of KEYCTL_KEYRING_CLEAR on the keyring ID. + =============================== READING DNS KEYS FROM USERSPACE diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 20af7def23c8..872815cd41d3 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -96,6 +96,12 @@ struct dev_pm_ops { int (*thaw)(struct device *dev); int (*poweroff)(struct device *dev); int (*restore)(struct device *dev); + int (*suspend_late)(struct device *dev); + int (*resume_early)(struct device *dev); + int (*freeze_late)(struct device *dev); + int (*thaw_early)(struct device *dev); + int (*poweroff_late)(struct device *dev); + int (*restore_early)(struct device *dev); int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*freeze_noirq)(struct device *dev); @@ -305,7 +311,7 @@ Entering System Suspend ----------------------- When the system goes into the standby or memory sleep state, the phases are: - prepare, suspend, suspend_noirq. + prepare, suspend, suspend_late, suspend_noirq. 1. The prepare phase is meant to prevent races by preventing new devices from being registered; the PM core would never know that all the @@ -324,7 +330,12 @@ When the system goes into the standby or memory sleep state, the phases are: appropriate low-power state, depending on the bus type the device is on, and they may enable wakeup events. - 3. The suspend_noirq phase occurs after IRQ handlers have been disabled, + 3 For a number of devices it is convenient to split suspend into the + "quiesce device" and "save device state" phases, in which cases + suspend_late is meant to do the latter. It is always executed after + runtime power management has been disabled for all devices. + + 4. The suspend_noirq phase occurs after IRQ handlers have been disabled, which means that the driver's interrupt handler will not be called while the callback method is running. The methods should save the values of the device's registers that weren't saved previously and finally put the @@ -359,7 +370,7 @@ Leaving System Suspend ---------------------- When resuming from standby or memory sleep, the phases are: - resume_noirq, resume, complete. + resume_noirq, resume_early, resume, complete. 1. The resume_noirq callback methods should perform any actions needed before the driver's interrupt handlers are invoked. This generally @@ -375,14 +386,18 @@ When resuming from standby or memory sleep, the phases are: device driver's ->pm.resume_noirq() method to perform device-specific actions. - 2. The resume methods should bring the the device back to its operating + 2. The resume_early methods should prepare devices for the execution of + the resume methods. This generally involves undoing the actions of the + preceding suspend_late phase. + + 3 The resume methods should bring the the device back to its operating state, so that it can perform normal I/O. This generally involves undoing the actions of the suspend phase. - 3. The complete phase uses only a bus callback. The method should undo the - actions of the prepare phase. Note, however, that new children may be - registered below the device as soon as the resume callbacks occur; it's - not necessary to wait until the complete phase. + 4. The complete phase should undo the actions of the prepare phase. Note, + however, that new children may be registered below the device as soon as + the resume callbacks occur; it's not necessary to wait until the + complete phase. At the end of these phases, drivers should be as functional as they were before suspending: I/O can be performed using DMA and IRQs, and the relevant clocks are @@ -429,8 +444,8 @@ an image of the system memory while everything is stable, reactivate all devices (thaw), write the image to permanent storage, and finally shut down the system (poweroff). The phases used to accomplish this are: - prepare, freeze, freeze_noirq, thaw_noirq, thaw, complete, - prepare, poweroff, poweroff_noirq + prepare, freeze, freeze_late, freeze_noirq, thaw_noirq, thaw_early, + thaw, complete, prepare, poweroff, poweroff_late, poweroff_noirq 1. The prepare phase is discussed in the "Entering System Suspend" section above. @@ -441,7 +456,11 @@ system (poweroff). The phases used to accomplish this are: save time it's best not to do so. Also, the device should not be prepared to generate wakeup events. - 3. The freeze_noirq phase is analogous to the suspend_noirq phase discussed + 3. The freeze_late phase is analogous to the suspend_late phase described + above, except that the device should not be put in a low-power state and + should not be allowed to generate wakeup events by it. + + 4. The freeze_noirq phase is analogous to the suspend_noirq phase discussed above, except again that the device should not be put in a low-power state and should not be allowed to generate wakeup events. @@ -449,15 +468,19 @@ At this point the system image is created. All devices should be inactive and the contents of memory should remain undisturbed while this happens, so that the image forms an atomic snapshot of the system state. - 4. The thaw_noirq phase is analogous to the resume_noirq phase discussed + 5. The thaw_noirq phase is analogous to the resume_noirq phase discussed above. The main difference is that its methods can assume the device is in the same state as at the end of the freeze_noirq phase. - 5. The thaw phase is analogous to the resume phase discussed above. Its + 6. The thaw_early phase is analogous to the resume_early phase described + above. Its methods should undo the actions of the preceding + freeze_late, if necessary. + + 7. The thaw phase is analogous to the resume phase discussed above. Its methods should bring the device back to an operating state, so that it can be used for saving the image if necessary. - 6. The complete phase is discussed in the "Leaving System Suspend" section + 8. The complete phase is discussed in the "Leaving System Suspend" section above. At this point the system image is saved, and the devices then need to be @@ -465,16 +488,19 @@ prepared for the upcoming system shutdown. This is much like suspending them before putting the system into the standby or memory sleep state, and the phases are similar. - 7. The prepare phase is discussed above. + 9. The prepare phase is discussed above. + + 10. The poweroff phase is analogous to the suspend phase. - 8. The poweroff phase is analogous to the suspend phase. + 11. The poweroff_late phase is analogous to the suspend_late phase. - 9. The poweroff_noirq phase is analogous to the suspend_noirq phase. + 12. The poweroff_noirq phase is analogous to the suspend_noirq phase. -The poweroff and poweroff_noirq callbacks should do essentially the same things -as the suspend and suspend_noirq callbacks. The only notable difference is that -they need not store the device register values, because the registers should -already have been stored during the freeze or freeze_noirq phases. +The poweroff, poweroff_late and poweroff_noirq callbacks should do essentially +the same things as the suspend, suspend_late and suspend_noirq callbacks, +respectively. The only notable difference is that they need not store the +device register values, because the registers should already have been stored +during the freeze, freeze_late or freeze_noirq phases. Leaving Hibernation @@ -518,22 +544,25 @@ To achieve this, the image kernel must restore the devices' pre-hibernation functionality. The operation is much like waking up from the memory sleep state, although it involves different phases: - restore_noirq, restore, complete + restore_noirq, restore_early, restore, complete 1. The restore_noirq phase is analogous to the resume_noirq phase. - 2. The restore phase is analogous to the resume phase. + 2. The restore_early phase is analogous to the resume_early phase. + + 3. The restore phase is analogous to the resume phase. - 3. The complete phase is discussed above. + 4. The complete phase is discussed above. -The main difference from resume[_noirq] is that restore[_noirq] must assume the -device has been accessed and reconfigured by the boot loader or the boot kernel. -Consequently the state of the device may be different from the state remembered -from the freeze and freeze_noirq phases. The device may even need to be reset -and completely re-initialized. In many cases this difference doesn't matter, so -the resume[_noirq] and restore[_norq] method pointers can be set to the same -routines. Nevertheless, different callback pointers are used in case there is a -situation where it actually matters. +The main difference from resume[_early|_noirq] is that restore[_early|_noirq] +must assume the device has been accessed and reconfigured by the boot loader or +the boot kernel. Consequently the state of the device may be different from the +state remembered from the freeze, freeze_late and freeze_noirq phases. The +device may even need to be reset and completely re-initialized. In many cases +this difference doesn't matter, so the resume[_early|_noirq] and +restore[_early|_norq] method pointers can be set to the same routines. +Nevertheless, different callback pointers are used in case there is a situation +where it actually does matter. Device Power Management Domains diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt index ebd7490ef1df..ec715cd78fbb 100644 --- a/Documentation/power/freezing-of-tasks.txt +++ b/Documentation/power/freezing-of-tasks.txt @@ -63,6 +63,27 @@ devices have been reinitialized, the function thaw_processes() is called in order to clear the PF_FROZEN flag for each frozen task. Then, the tasks that have been frozen leave __refrigerator() and continue running. + +Rationale behind the functions dealing with freezing and thawing of tasks: +------------------------------------------------------------------------- + +freeze_processes(): + - freezes only userspace tasks + +freeze_kernel_threads(): + - freezes all tasks (including kernel threads) because we can't freeze + kernel threads without freezing userspace tasks + +thaw_kernel_threads(): + - thaws only kernel threads; this is particularly useful if we need to do + anything special in between thawing of kernel threads and thawing of + userspace tasks, or if we want to postpone the thawing of userspace tasks + +thaw_processes(): + - thaws all tasks (including kernel threads) because we can't thaw userspace + tasks without thawing kernel threads + + III. Which kernel threads are freezable? Kernel threads are not freezable by default. However, a kernel thread may clear diff --git a/Documentation/security/00-INDEX b/Documentation/security/00-INDEX index 99b85d39751c..eeed1de546d4 100644 --- a/Documentation/security/00-INDEX +++ b/Documentation/security/00-INDEX @@ -6,6 +6,8 @@ SELinux.txt - how to get started with the SELinux security enhancement. Smack.txt - documentation on the Smack Linux Security Module. +Yama.txt + - documentation on the Yama Linux Security Module. apparmor.txt - documentation on the AppArmor security extension. credentials.txt diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt new file mode 100644 index 000000000000..a9511f179069 --- /dev/null +++ b/Documentation/security/Yama.txt @@ -0,0 +1,65 @@ +Yama is a Linux Security Module that collects a number of system-wide DAC +security protections that are not handled by the core kernel itself. To +select it at boot time, specify "security=yama" (though this will disable +any other LSM). + +Yama is controlled through sysctl in /proc/sys/kernel/yama: + +- ptrace_scope + +============================================================== + +ptrace_scope: + +As Linux grows in popularity, it will become a larger target for +malware. One particularly troubling weakness of the Linux process +interfaces is that a single user is able to examine the memory and +running state of any of their processes. For example, if one application +(e.g. Pidgin) was compromised, it would be possible for an attacker to +attach to other running processes (e.g. Firefox, SSH sessions, GPG agent, +etc) to extract additional credentials and continue to expand the scope +of their attack without resorting to user-assisted phishing. + +This is not a theoretical problem. SSH session hijacking +(http://www.storm.net.nz/projects/7) and arbitrary code injection +(http://c-skills.blogspot.com/2007/05/injectso.html) attacks already +exist and remain possible if ptrace is allowed to operate as before. +Since ptrace is not commonly used by non-developers and non-admins, system +builders should be allowed the option to disable this debugging system. + +For a solution, some applications use prctl(PR_SET_DUMPABLE, ...) to +specifically disallow such ptrace attachment (e.g. ssh-agent), but many +do not. A more general solution is to only allow ptrace directly from a +parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still +work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" +still work as root). + +For software that has defined application-specific relationships +between a debugging process and its inferior (crash handlers, etc), +prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which +other process (and its descendents) are allowed to call PTRACE_ATTACH +against it. Only one such declared debugging process can exists for +each inferior at a time. For example, this is used by KDE, Chromium, and +Firefox's crash handlers, and by Wine for allowing only Wine processes +to ptrace each other. If a process wishes to entirely disable these ptrace +restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...) +so that any otherwise allowed process (even those in external pid namespaces) +may attach. + +The sysctl settings are: + +0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other + process running under the same uid, as long as it is dumpable (i.e. + did not transition uids, start privileged, or have called + prctl(PR_SET_DUMPABLE...) already). + +1 - restricted ptrace: a process must have a predefined relationship + with the inferior it wants to call PTRACE_ATTACH on. By default, + this relationship is that of only its descendants when the above + classic criteria is also met. To change the relationship, an + inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare + an allowed debugger PID to call PTRACE_ATTACH on the inferior. + +The original children-only logic was based on the restrictions in grsecurity. + +============================================================== diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index fcbe7a703405..787717091421 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -554,6 +554,10 @@ The keyctl syscall functions are: process must have write permission on the keyring, and it must be a keyring (or else error ENOTDIR will result). + This function can also be used to clear special kernel keyrings if they + are appropriately marked if the user has CAP_SYS_ADMIN capability. The + DNS resolver cache keyring is an example of this. + (*) Link a key into a keyring: diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index 4884cb33845d..7312ec14dd89 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -1,7 +1,7 @@ Overview of Linux kernel SPI support ==================================== -21-May-2007 +02-Feb-2012 What is SPI? ------------ @@ -483,9 +483,9 @@ also initialize its own internal state. (See below about bus numbering and those methods.) After you initialize the spi_master, then use spi_register_master() to -publish it to the rest of the system. At that time, device nodes for -the controller and any predeclared spi devices will be made available, -and the driver model core will take care of binding them to drivers. +publish it to the rest of the system. At that time, device nodes for the +controller and any predeclared spi devices will be made available, and +the driver model core will take care of binding them to drivers. If you need to remove your SPI controller driver, spi_unregister_master() will reverse the effect of spi_register_master(). @@ -521,21 +521,53 @@ SPI MASTER METHODS ** When you code setup(), ASSUME that the controller ** is actively processing transfers for another device. - master->transfer(struct spi_device *spi, struct spi_message *message) - This must not sleep. Its responsibility is arrange that the - transfer happens and its complete() callback is issued. The two - will normally happen later, after other transfers complete, and - if the controller is idle it will need to be kickstarted. - master->cleanup(struct spi_device *spi) Your controller driver may use spi_device.controller_state to hold state it dynamically associates with that device. If you do that, be sure to provide the cleanup() method to free that state. + master->prepare_transfer_hardware(struct spi_master *master) + This will be called by the queue mechanism to signal to the driver + that a message is coming in soon, so the subsystem requests the + driver to prepare the transfer hardware by issuing this call. + This may sleep. + + master->unprepare_transfer_hardware(struct spi_master *master) + This will be called by the queue mechanism to signal to the driver + that there are no more messages pending in the queue and it may + relax the hardware (e.g. by power management calls). This may sleep. + + master->transfer_one_message(struct spi_master *master, + struct spi_message *mesg) + The subsystem calls the driver to transfer a single message while + queuing transfers that arrive in the meantime. When the driver is + finished with this message, it must call + spi_finalize_current_message() so the subsystem can issue the next + transfer. This may sleep. + + DEPRECATED METHODS + + master->transfer(struct spi_device *spi, struct spi_message *message) + This must not sleep. Its responsibility is arrange that the + transfer happens and its complete() callback is issued. The two + will normally happen later, after other transfers complete, and + if the controller is idle it will need to be kickstarted. This + method is not used on queued controllers and must be NULL if + transfer_one_message() and (un)prepare_transfer_hardware() are + implemented. + SPI MESSAGE QUEUE -The bulk of the driver will be managing the I/O queue fed by transfer(). +If you are happy with the standard queueing mechanism provided by the +SPI subsystem, just implement the queued methods specified above. Using +the message queue has the upside of centralizing a lot of code and +providing pure process-context execution of methods. The message queue +can also be elevated to realtime priority on high-priority SPI traffic. + +Unless the queueing mechanism in the SPI subsystem is selected, the bulk +of the driver will be managing the I/O queue fed by the now deprecated +function transfer(). That queue could be purely conceptual. For example, a driver used only for low-frequency sensor access might be fine using synchronous PIO. @@ -561,4 +593,6 @@ Stephen Street Mark Underwood Andrew Victor Vitaly Wool - +Grant Likely +Mark Brown +Linus Walleij diff --git a/MAINTAINERS b/MAINTAINERS index 8f254e7b6c73..92f9924c4335 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3666,6 +3666,15 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core F: kernel/irq/ +IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY) +M: Benjamin Herrenschmidt <benh@kernel.crashing.org> +M: Grant Likely <grant.likely@secretlab.ca> +T: git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next +S: Maintained +F: Documentation/IRQ-domain.txt +F: include/linux/irqdomain.h +F: kernel/irq/irqdomain.c + ISAPNP M: Jaroslav Kysela <perex@perex.cz> S: Maintained diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/arch/arm/boot/dts/testcases/tests-phandle.dtsi index ec0c4e6212c9..0007d3cd7dc2 100644 --- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi +++ b/arch/arm/boot/dts/testcases/tests-phandle.dtsi @@ -31,6 +31,8 @@ phandle-list-bad-phandle = <12345678 0 0>; phandle-list-bad-args = <&provider2 1 0>, <&provider3 0>; + empty-property; + unterminated-string = [40 41 42 43]; }; }; }; diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index c47d6199b784..f0783be17352 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c @@ -51,7 +51,6 @@ union gic_base { }; struct gic_chip_data { - unsigned int irq_offset; union gic_base dist_base; union gic_base cpu_base; #ifdef CONFIG_CPU_PM @@ -61,9 +60,7 @@ struct gic_chip_data { u32 __percpu *saved_ppi_enable; u32 __percpu *saved_ppi_conf; #endif -#ifdef CONFIG_IRQ_DOMAIN - struct irq_domain domain; -#endif + struct irq_domain *domain; unsigned int gic_irqs; #ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *); @@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) irqnr = irqstat & ~0x1c00; if (likely(irqnr > 15 && irqnr < 1021)) { - irqnr = irq_domain_to_irq(&gic->domain, irqnr); + irqnr = irq_find_mapping(gic->domain, irqnr); handle_IRQ(irqnr, regs); continue; } @@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) if (gic_irq == 1023) goto out; - cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); - if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) + cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); + if (unlikely(gic_irq < 32 || gic_irq > 1020)) do_bad_IRQ(cascade_irq, desc); else generic_handle_irq(cascade_irq); @@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) static void __init gic_dist_init(struct gic_chip_data *gic) { - unsigned int i, irq; + unsigned int i; u32 cpumask; unsigned int gic_irqs = gic->gic_irqs; - struct irq_domain *domain = &gic->domain; void __iomem *base = gic_data_dist_base(gic); u32 cpu = cpu_logical_map(smp_processor_id()); @@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic) for (i = 32; i < gic_irqs; i += 32) writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); - /* - * Setup the Linux IRQ subsystem. - */ - irq_domain_for_each_irq(domain, i, irq) { - if (i < 32) { - irq_set_percpu_devid(irq); - irq_set_chip_and_handler(irq, &gic_chip, - handle_percpu_devid_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); - } else { - irq_set_chip_and_handler(irq, &gic_chip, - handle_fasteoi_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - irq_set_chip_data(irq, gic); - } - writel_relaxed(1, base + GIC_DIST_CTRL); } @@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic) } #endif -#ifdef CONFIG_OF -static int gic_irq_domain_dt_translate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type) +static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + if (hw < 32) { + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, &gic_chip, + handle_percpu_devid_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + } else { + irq_set_chip_and_handler(irq, &gic_chip, + handle_fasteoi_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + irq_set_chip_data(irq, d->host_data); + return 0; +} + +static int gic_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) { if (d->of_node != controller) return -EINVAL; @@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d, *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return 0; } -#endif const struct irq_domain_ops gic_irq_domain_ops = { -#ifdef CONFIG_OF - .dt_translate = gic_irq_domain_dt_translate, -#endif + .map = gic_irq_domain_map, + .xlate = gic_irq_domain_xlate, }; void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, - u32 percpu_offset) + u32 percpu_offset, struct device_node *node) { + irq_hw_number_t hwirq_base; struct gic_chip_data *gic; - struct irq_domain *domain; - int gic_irqs; + int gic_irqs, irq_base; BUG_ON(gic_nr >= MAX_GIC_NR); gic = &gic_data[gic_nr]; - domain = &gic->domain; #ifdef CONFIG_GIC_NON_BANKED if (percpu_offset) { /* Frankein-GIC without banked registers... */ unsigned int cpu; @@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. */ - domain->hwirq_base = 32; + hwirq_base = 32; if (gic_nr == 0) { if ((irq_start & 31) > 0) { - domain->hwirq_base = 16; + hwirq_base = 16; if (irq_start != -1) irq_start = (irq_start & ~31) + 16; } @@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_irqs = 1020; gic->gic_irqs = gic_irqs; - domain->nr_irq = gic_irqs - domain->hwirq_base; - domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, - numa_node_id()); - if (IS_ERR_VALUE(domain->irq_base)) { + gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ + irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); + if (IS_ERR_VALUE(irq_base)) { WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", irq_start); - domain->irq_base = irq_start; + irq_base = irq_start; } - domain->priv = gic; - domain->ops = &gic_irq_domain_ops; - irq_domain_add(domain); + gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, + hwirq_base, &gic_irq_domain_ops, gic); + if (WARN_ON(!gic->domain)) + return; gic_chip.flags |= gic_arch_extn.flags; gic_dist_init(gic); @@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) void __iomem *dist_base; u32 percpu_offset; int irq; - struct irq_domain *domain = &gic_data[gic_cnt].domain; if (WARN_ON(!node)) return -ENODEV; @@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; - domain->of_node = of_node_get(node); - - gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset); + gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); if (parent) { irq = irq_of_parse_and_map(node, 0); diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index dcb004a804c7..7a66311f3066 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -56,7 +56,7 @@ struct vic_device { u32 int_enable; u32 soft_int; u32 protect; - struct irq_domain domain; + struct irq_domain *domain; }; /* we cannot allocate memory when VICs are initially registered */ @@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq, v->resume_sources = resume_sources; v->irq = irq; vic_id++; - - v->domain.irq_base = irq; - v->domain.nr_irq = 32; -#ifdef CONFIG_OF_IRQ - v->domain.of_node = of_node_get(node); -#endif /* CONFIG_OF */ - v->domain.ops = &irq_domain_simple_ops; - irq_domain_add(&v->domain); + v->domain = irq_domain_add_legacy(node, 32, irq, 0, + &irq_domain_simple_ops, v); } static void vic_ack_irq(struct irq_data *d) @@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, vic_register(base, irq_start, 0, node); } -static void __init __vic_init(void __iomem *base, unsigned int irq_start, +void __init __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources, struct device_node *node) { @@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) stat = readl_relaxed(vic->base + VIC_IRQ_STATUS); while (stat) { irq = ffs(stat) - 1; - handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs); + handle_IRQ(irq_find_mapping(vic->domain, irq), regs); stat &= ~(1 << irq); handled = 1; } diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h index 4bdfe0018696..4b1ce6cd477f 100644 --- a/arch/arm/include/asm/hardware/gic.h +++ b/arch/arm/include/asm/hardware/gic.h @@ -39,7 +39,7 @@ struct device_node; extern struct irq_chip gic_arch_extn; void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, - u32 offset); + u32 offset, struct device_node *); int gic_of_init(struct device_node *node, struct device_node *parent); void gic_secondary_init(unsigned int); void gic_handle_irq(struct pt_regs *regs); @@ -49,7 +49,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq); static inline void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu) { - gic_init_bases(nr, start, dist, cpu, 0); + gic_init_bases(nr, start, dist, cpu, 0, NULL); } #endif diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index f42ebd619590..e14af1a1a320 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h @@ -47,6 +47,8 @@ struct device_node; struct pt_regs; +void __vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, + u32 resume_sources, struct device_node *node); void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); int vic_of_init(struct device_node *node, struct device_node *parent); void vic_handle_irq(struct pt_regs *regs); diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h index a4edd19dd3d6..8c5e828f484d 100644 --- a/arch/arm/include/asm/highmem.h +++ b/arch/arm/include/asm/highmem.h @@ -57,7 +57,7 @@ static inline void *kmap_high_get(struct page *page) #ifdef CONFIG_HIGHMEM extern void *kmap(struct page *page); extern void kunmap(struct page *page); -extern void *__kmap_atomic(struct page *page); +extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(const void *ptr); diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 5d602f68a0e8..dfad6538b273 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -34,6 +34,7 @@ config CPU_EXYNOS4210 select ARM_CPU_SUSPEND if PM select S5P_PM if PM select S5P_SLEEP if PM + select PM_GENERIC_DOMAINS help Enable EXYNOS4210 CPU support @@ -74,11 +75,6 @@ config EXYNOS4_SETUP_FIMD0 help Common setup code for FIMD0. -config EXYNOS4_DEV_PD - bool - help - Compile in platform device definitions for Power Domain - config EXYNOS4_DEV_SYSMMU bool help @@ -195,7 +191,6 @@ config MACH_SMDKV310 select EXYNOS4_DEV_AHCI select SAMSUNG_DEV_KEYPAD select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select SAMSUNG_DEV_PWM select EXYNOS4_DEV_USB_OHCI select EXYNOS4_DEV_SYSMMU @@ -243,7 +238,6 @@ config MACH_UNIVERSAL_C210 select S5P_DEV_ONENAND select S5P_DEV_TV select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 @@ -277,7 +271,6 @@ config MACH_NURI select S5P_DEV_USB_EHCI select S5P_SETUP_MIPIPHY select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_SETUP_FIMC select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 @@ -310,7 +303,6 @@ config MACH_ORIGEN select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_PWM select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_PD select EXYNOS4_DEV_USB_OHCI select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_SDHCI diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 5fc202cdfdb6..d9191f9a7af8 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o @@ -45,7 +46,6 @@ obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o -obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index c59e18871006..6de298c5d2d3 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -402,7 +402,7 @@ void __init exynos4_init_irq(void) gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; if (!of_have_populated_dt()) - gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset); + gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL); #ifdef CONFIG_OF else of_irq_init(exynos4_dt_irq_match); diff --git a/arch/arm/mach-exynos/dev-pd.c b/arch/arm/mach-exynos/dev-pd.c deleted file mode 100644 index 3273f25d6a75..000000000000 --- a/arch/arm/mach-exynos/dev-pd.c +++ /dev/null @@ -1,139 +0,0 @@ -/* linux/arch/arm/mach-exynos4/dev-pd.c - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4 - Power Domain support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/delay.h> - -#include <mach/regs-pmu.h> - -#include <plat/pd.h> - -static int exynos4_pd_enable(struct device *dev) -{ - struct samsung_pd_info *pdata = dev->platform_data; - u32 timeout; - - __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base); - - /* Wait max 1ms */ - timeout = 10; - while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) - != S5P_INT_LOCAL_PWR_EN) { - if (timeout == 0) { - printk(KERN_ERR "Power domain %s enable failed.\n", - dev_name(dev)); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - - return 0; -} - -static int exynos4_pd_disable(struct device *dev) -{ - struct samsung_pd_info *pdata = dev->platform_data; - u32 timeout; - - __raw_writel(0, pdata->base); - - /* Wait max 1ms */ - timeout = 10; - while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) { - if (timeout == 0) { - printk(KERN_ERR "Power domain %s disable failed.\n", - dev_name(dev)); - return -ETIMEDOUT; - } - timeout--; - udelay(100); - } - - return 0; -} - -struct platform_device exynos4_device_pd[] = { - { - .name = "samsung-pd", - .id = 0, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_MFC_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 1, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_G3D_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 2, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_LCD0_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 3, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_LCD1_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 4, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_TV_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 5, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_CAM_CONF, - }, - }, - }, { - .name = "samsung-pd", - .id = 6, - .dev = { - .platform_data = &(struct samsung_pd_info) { - .enable = exynos4_pd_enable, - .disable = exynos4_pd_disable, - .base = S5P_PMU_GPS_CONF, - }, - }, - }, -}; diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 435261f83f46..aa37179d776c 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1263,9 +1263,6 @@ static struct platform_device *nuri_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_CAM], &s5p_device_fimc_md, /* NURI Devices */ @@ -1315,14 +1312,6 @@ static void __init nuri_machine_init(void) /* Last */ platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices)); - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev; } MACHINE_START(NURI, "NURI") diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 0679b8ad2d1e..fa5c4a59b0aa 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -621,13 +621,6 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_mfc_r, &s5p_device_mixer, &exynos4_device_ohci, - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_GPS], - &exynos4_device_pd[PD_MFC], &origen_device_gpiokeys, &origen_lcd_hv070wsa, }; @@ -695,13 +688,6 @@ static void __init origen_machine_init(void) platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; - - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); } diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index b2c5557f50e4..5258b8563676 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -277,13 +277,6 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_G3D], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_LCD1], - &exynos4_device_pd[PD_CAM], - &exynos4_device_pd[PD_TV], - &exynos4_device_pd[PD_GPS], &exynos4_device_spdif, &exynos4_device_sysmmu, &samsung_asoc_dma, @@ -336,10 +329,6 @@ static void s5p_tv_setup(void) WARN_ON(gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug")); s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - - /* setup dependencies between TV devices */ - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; } static void __init smdkv310_map_io(void) @@ -379,7 +368,6 @@ static void __init smdkv310_machine_init(void) clk_xusbxti.rate = 24000000; platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; } MACHINE_START(SMDKV310, "SMDKV310") diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 38939956c34f..b2d495b31094 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -971,7 +971,6 @@ static struct platform_device *universal_devices[] __initdata = { &s3c_device_i2c5, &s5p_device_i2c_hdmiphy, &hdmi_fixed_voltage, - &exynos4_device_pd[PD_TV], &s5p_device_hdmi, &s5p_device_sdo, &s5p_device_mixer, @@ -984,9 +983,6 @@ static struct platform_device *universal_devices[] __initdata = { &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, - &exynos4_device_pd[PD_MFC], - &exynos4_device_pd[PD_LCD0], - &exynos4_device_pd[PD_CAM], &cam_i_core_fixed_reg_dev, &cam_s_if_fixed_reg_dev, &s5p_device_fimc_md, @@ -1005,10 +1001,6 @@ void s5p_tv_setup(void) gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug"); s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3)); s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - - /* setup dependencies between TV devices */ - s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; - s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; } static void __init universal_reserve(void) @@ -1042,15 +1034,6 @@ static void __init universal_machine_init(void) /* Last */ platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); - - s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; - s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - - s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; - s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev; } MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c new file mode 100644 index 000000000000..0b04af2b13cc --- /dev/null +++ b/arch/arm/mach-exynos/pm_domains.c @@ -0,0 +1,195 @@ +/* + * Exynos Generic power domain support. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Implementation of Exynos specific power domain control which is used in + * conjunction with runtime-pm. Support for both device-tree and non-device-tree + * based power domain support is included. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> +#include <linux/delay.h> +#include <linux/of_address.h> + +#include <mach/regs-pmu.h> +#include <plat/devs.h> + +/* + * Exynos specific wrapper around the generic power domain + */ +struct exynos_pm_domain { + void __iomem *base; + char const *name; + bool is_off; + struct generic_pm_domain pd; +}; + +static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct exynos_pm_domain *pd; + void __iomem *base; + u32 timeout, pwr; + char *op; + + pd = container_of(domain, struct exynos_pm_domain, pd); + base = pd->base; + + pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; + __raw_writel(pwr, base); + + /* Wait max 1ms */ + timeout = 10; + + while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN) != pwr) { + if (!timeout) { + op = (power_on) ? "enable" : "disable"; + pr_err("Power domain %s %s failed\n", domain->name, op); + return -ETIMEDOUT; + } + timeout--; + cpu_relax(); + usleep_range(80, 100); + } + return 0; +} + +static int exynos_pd_power_on(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, true); +} + +static int exynos_pd_power_off(struct generic_pm_domain *domain) +{ + return exynos_pd_power(domain, false); +} + +#define EXYNOS_GPD(PD, BASE, NAME) \ +static struct exynos_pm_domain PD = { \ + .base = (void __iomem *)BASE, \ + .name = NAME, \ + .pd = { \ + .power_off = exynos_pd_power_off, \ + .power_on = exynos_pd_power_on, \ + }, \ +} + +#ifdef CONFIG_OF +static __init int exynos_pm_dt_parse_domains(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + struct exynos_pm_domain *pd; + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + pr_err("%s: failed to allocate memory for domain\n", + __func__); + return -ENOMEM; + } + + if (of_get_property(np, "samsung,exynos4210-pd-off", NULL)) + pd->is_off = true; + pd->name = np->name; + pd->base = of_iomap(np, 0); + pd->pd.power_off = exynos_pd_power_off; + pd->pd.power_on = exynos_pd_power_on; + pd->pd.of_node = np; + pm_genpd_init(&pd->pd, NULL, false); + } + return 0; +} +#else +static __init int exynos_pm_dt_parse_domains(void) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev, + struct exynos_pm_domain *pd) +{ + if (pdev->dev.bus) { + if (pm_genpd_add_device(&pd->pd, &pdev->dev)) + pr_info("%s: error in adding %s device to %s power" + "domain\n", __func__, dev_name(&pdev->dev), + pd->name); + } +} + +EXYNOS_GPD(exynos4_pd_mfc, S5P_PMU_MFC_CONF, "pd-mfc"); +EXYNOS_GPD(exynos4_pd_g3d, S5P_PMU_G3D_CONF, "pd-g3d"); +EXYNOS_GPD(exynos4_pd_lcd0, S5P_PMU_LCD0_CONF, "pd-lcd0"); +EXYNOS_GPD(exynos4_pd_lcd1, S5P_PMU_LCD1_CONF, "pd-lcd1"); +EXYNOS_GPD(exynos4_pd_tv, S5P_PMU_TV_CONF, "pd-tv"); +EXYNOS_GPD(exynos4_pd_cam, S5P_PMU_CAM_CONF, "pd-cam"); +EXYNOS_GPD(exynos4_pd_gps, S5P_PMU_GPS_CONF, "pd-gps"); + +static struct exynos_pm_domain *exynos4_pm_domains[] = { + &exynos4_pd_mfc, + &exynos4_pd_g3d, + &exynos4_pd_lcd0, + &exynos4_pd_lcd1, + &exynos4_pd_tv, + &exynos4_pd_cam, + &exynos4_pd_gps, +}; + +static __init int exynos4_pm_init_power_domain(void) +{ + int idx; + + if (of_have_populated_dt()) + return exynos_pm_dt_parse_domains(); + + for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++) + pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL, + exynos4_pm_domains[idx]->is_off); + +#ifdef CONFIG_S5P_DEV_FIMD0 + exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0); +#endif +#ifdef CONFIG_S5P_DEV_TV + exynos_pm_add_dev_to_genpd(&s5p_device_hdmi, &exynos4_pd_tv); + exynos_pm_add_dev_to_genpd(&s5p_device_mixer, &exynos4_pd_tv); +#endif +#ifdef CONFIG_S5P_DEV_MFC + exynos_pm_add_dev_to_genpd(&s5p_device_mfc, &exynos4_pd_mfc); +#endif +#ifdef CONFIG_S5P_DEV_FIMC0 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC1 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc1, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC2 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc2, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC3 + exynos_pm_add_dev_to_genpd(&s5p_device_fimc3, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS0 + exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS1 + exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam); +#endif + return 0; +} +arch_initcall(exynos4_pm_init_power_domain); + +static __init int exynos_pm_late_initcall(void) +{ + pm_genpd_poweroff_unused(); + return 0; +} +late_initcall(exynos_pm_late_initcall); diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index e6bad17b908c..1e03ef42faa0 100644 --- a/arch/arm/mach-imx/imx51-dt.c +++ b/arch/arm/mach-imx/imx51-dt.c @@ -47,7 +47,7 @@ static const struct of_dev_auxdata imx51_auxdata_lookup[] __initconst = { static int __init imx51_tzic_add_irq_domain(struct device_node *np, struct device_node *interrupt_parent) { - irq_domain_add_simple(np, 0); + irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); return 0; } @@ -57,7 +57,7 @@ static int __init imx51_gpio_add_irq_domain(struct device_node *np, static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS; gpio_irq_base -= 32; - irq_domain_add_simple(np, gpio_irq_base); + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); return 0; } diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c index 05ebb3e68679..fd5be0f20fbb 100644 --- a/arch/arm/mach-imx/imx53-dt.c +++ b/arch/arm/mach-imx/imx53-dt.c @@ -51,7 +51,7 @@ static const struct of_dev_auxdata imx53_auxdata_lookup[] __initconst = { static int __init imx53_tzic_add_irq_domain(struct device_node *np, struct device_node *interrupt_parent) { - irq_domain_add_simple(np, 0); + irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); return 0; } @@ -61,7 +61,7 @@ static int __init imx53_gpio_add_irq_domain(struct device_node *np, static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS; gpio_irq_base -= 32; - irq_domain_add_simple(np, gpio_irq_base); + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); return 0; } diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index c25728106917..6075d4d62dd6 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -97,7 +97,8 @@ static int __init imx6q_gpio_add_irq_domain(struct device_node *np, static int gpio_irq_base = MXC_GPIO_IRQ_START + ARCH_NR_GPIOS; gpio_irq_base -= 32; - irq_domain_add_simple(np, gpio_irq_base); + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, + NULL); return 0; } diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index e48854b9d990..5fddf94cc969 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -32,6 +32,8 @@ #include <linux/usb/ulpi.h> #include <linux/gfp.h> #include <linux/memblock.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> #include <media/soc_camera.h> @@ -570,6 +572,11 @@ static int __init pcm037_otg_mode(char *options) } __setup("otg_mode=", pcm037_otg_mode); +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vdd33a", "smsc911x"), + REGULATOR_SUPPLY("vddvario", "smsc911x"), +}; + /* * Board specific initialization. */ @@ -579,6 +586,8 @@ static void __init pcm037_init(void) imx31_soc_init(); + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + mxc_iomux_set_gpr(MUX_PGP_UH2, 1); mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins), diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index 0a113424632c..962e71169750 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -80,12 +80,8 @@ static struct of_device_id msm_dt_gic_match[] __initdata = { static void __init msm8x60_dt_init(void) { - struct device_node *node; - - node = of_find_matching_node_by_address(NULL, msm_dt_gic_match, - MSM8X60_QGIC_DIST_PHYS); - if (node) - irq_domain_add_simple(node, GIC_SPI_START); + irq_domain_generate_simple(msm_dt_gic_match, MSM8X60_QGIC_DIST_PHYS, + GIC_SPI_START); if (of_machine_is_compatible("qcom,msm8660-surf")) { printk(KERN_INFO "Init surf UART registers\n"); diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index ad497620539b..45fdfe2bd9d5 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -68,7 +68,7 @@ static void __init omap_generic_init(void) { struct device_node *node = of_find_matching_node(NULL, intc_match); if (node) - irq_domain_add_simple(node, 0); + irq_domain_add_legacy(node, 32, 0, 0, &irq_domain_simple_ops, NULL); omap_sdrc_init(NULL, NULL); diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c index d93ceef4a50a..37c2de9b6f26 100644 --- a/arch/arm/mach-prima2/irq.c +++ b/arch/arm/mach-prima2/irq.c @@ -68,7 +68,7 @@ void __init sirfsoc_of_irq_init(void) if (!sirfsoc_intc_base) panic("unable to map intc cpu registers\n"); - irq_domain_add_simple(np, 0); + irq_domain_add_legacy(np, 32, 0, 0, &irq_domain_simple_ops, NULL); of_node_put(np); diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index a83cf51fc099..cccf91b8fae1 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -1043,6 +1043,8 @@ void __init sh7372_add_standard_devices(void) sh7372_add_device_to_domain(&sh7372_a4r, &veu2_device); sh7372_add_device_to_domain(&sh7372_a4r, &veu3_device); sh7372_add_device_to_domain(&sh7372_a4r, &jpu_device); + sh7372_add_device_to_domain(&sh7372_a4r, &tmu00_device); + sh7372_add_device_to_domain(&sh7372_a4r, &tmu01_device); } void __init sh7372_add_early_devices(void) diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 1fa26d9a1a68..ea49bd93c6b9 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/io.h> +#include <linux/module.h> #include <mach/iomap.h> @@ -58,6 +59,7 @@ unsigned long long tegra_chip_uid(void) hi = fuse_readl(FUSE_UID_HIGH); return (hi << 32ull) | lo; } +EXPORT_SYMBOL(tegra_chip_uid); int tegra_sku_id(void) { diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c index 5140deeddf7b..a38f80238ea9 100644 --- a/arch/arm/mach-u300/i2c.c +++ b/arch/arm/mach-u300/i2c.c @@ -60,7 +60,6 @@ static struct regulator_consumer_supply supply_ldo_c[] = { */ static struct regulator_consumer_supply supply_ldo_d[] = { { - .dev = NULL, .supply = "vana15", /* Powers the SoC (CPU etc) */ }, }; @@ -92,7 +91,6 @@ static struct regulator_consumer_supply supply_ldo_k[] = { */ static struct regulator_consumer_supply supply_ldo_ext[] = { { - .dev = NULL, .supply = "vext", /* External power */ }, }; diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 02b7b9303f3b..008ce22b9a06 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -98,8 +98,11 @@ static const struct of_device_id sic_of_match[] __initconst = { void __init versatile_init_irq(void) { - vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0); - irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START); + struct device_node *np; + + np = of_find_matching_node_by_address(NULL, vic_of_match, + VERSATILE_VIC_BASE); + __vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np); writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c index d2852e1635b1..d130a5ece5d5 100644 --- a/arch/arm/mm/copypage-fa.c +++ b/arch/arm/mm/copypage-fa.c @@ -44,11 +44,11 @@ void fa_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); fa_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -58,7 +58,7 @@ void fa_copy_user_highpage(struct page *to, struct page *from, */ void fa_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -77,7 +77,7 @@ void fa_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns fa_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c index ac163de7dc01..49ee0c1a7209 100644 --- a/arch/arm/mm/copypage-feroceon.c +++ b/arch/arm/mm/copypage-feroceon.c @@ -72,17 +72,17 @@ void feroceon_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); flush_cache_page(vma, vaddr, page_to_pfn(from)); feroceon_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } void feroceon_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile ("\ mov r1, %2 \n\ mov r2, #0 \n\ @@ -102,7 +102,7 @@ void feroceon_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns feroceon_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v3.c b/arch/arm/mm/copypage-v3.c index f72303e1d804..3935bddd4769 100644 --- a/arch/arm/mm/copypage-v3.c +++ b/arch/arm/mm/copypage-v3.c @@ -42,11 +42,11 @@ void v3_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); v3_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -56,7 +56,7 @@ void v3_copy_user_highpage(struct page *to, struct page *from, */ void v3_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\n\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -72,7 +72,7 @@ void v3_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v3_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index 7d0a8c230342..ec8c3befb9c8 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -71,7 +71,7 @@ mc_copy_user_page(void *from, void *to) void v4_mc_copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr, struct vm_area_struct *vma) { - void *kto = kmap_atomic(to, KM_USER1); + void *kto = kmap_atomic(to); if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); @@ -85,7 +85,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from, raw_spin_unlock(&minicache_lock); - kunmap_atomic(kto, KM_USER1); + kunmap_atomic(kto); } /* @@ -93,7 +93,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from, */ void v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -111,7 +111,7 @@ void v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v4_mc_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c index cb589cbb2b6c..067d0fdd630c 100644 --- a/arch/arm/mm/copypage-v4wb.c +++ b/arch/arm/mm/copypage-v4wb.c @@ -52,12 +52,12 @@ void v4wb_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); flush_cache_page(vma, vaddr, page_to_pfn(from)); v4wb_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -67,7 +67,7 @@ void v4wb_copy_user_highpage(struct page *to, struct page *from, */ void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -86,7 +86,7 @@ void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v4wb_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c index 30c7d048a324..b85c5da2e510 100644 --- a/arch/arm/mm/copypage-v4wt.c +++ b/arch/arm/mm/copypage-v4wt.c @@ -48,11 +48,11 @@ void v4wt_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); v4wt_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -62,7 +62,7 @@ void v4wt_copy_user_highpage(struct page *to, struct page *from, */ void v4wt_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile("\ mov r1, %2 @ 1\n\ mov r2, #0 @ 1\n\ @@ -79,7 +79,7 @@ void v4wt_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 64) : "r1", "r2", "r3", "ip", "lr"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns v4wt_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index 3d9a1552cef6..8b03a5814d00 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c @@ -38,11 +38,11 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to, { void *kto, *kfrom; - kfrom = kmap_atomic(from, KM_USER0); - kto = kmap_atomic(to, KM_USER1); + kfrom = kmap_atomic(from); + kto = kmap_atomic(to); copy_page(kto, kfrom); - kunmap_atomic(kto, KM_USER1); - kunmap_atomic(kfrom, KM_USER0); + kunmap_atomic(kto); + kunmap_atomic(kfrom); } /* @@ -51,9 +51,9 @@ static void v6_copy_user_highpage_nonaliasing(struct page *to, */ static void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr) { - void *kaddr = kmap_atomic(page, KM_USER0); + void *kaddr = kmap_atomic(page); clear_page(kaddr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } /* diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c index f9cde0702f1e..03a2042aced5 100644 --- a/arch/arm/mm/copypage-xsc3.c +++ b/arch/arm/mm/copypage-xsc3.c @@ -75,12 +75,12 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, { void *kto, *kfrom; - kto = kmap_atomic(to, KM_USER0); - kfrom = kmap_atomic(from, KM_USER1); + kto = kmap_atomic(to); + kfrom = kmap_atomic(from); flush_cache_page(vma, vaddr, page_to_pfn(from)); xsc3_mc_copy_user_page(kto, kfrom); - kunmap_atomic(kfrom, KM_USER1); - kunmap_atomic(kto, KM_USER0); + kunmap_atomic(kfrom); + kunmap_atomic(kto); } /* @@ -90,7 +90,7 @@ void xsc3_mc_copy_user_highpage(struct page *to, struct page *from, */ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile ("\ mov r1, %2 \n\ mov r2, #0 \n\ @@ -105,7 +105,7 @@ void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns xsc3_mc_user_fns __initdata = { diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 610c24ced310..439d106ae638 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -93,7 +93,7 @@ mc_copy_user_page(void *from, void *to) void xscale_mc_copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr, struct vm_area_struct *vma) { - void *kto = kmap_atomic(to, KM_USER1); + void *kto = kmap_atomic(to); if (!test_and_set_bit(PG_dcache_clean, &from->flags)) __flush_dcache_page(page_mapping(from), from); @@ -107,7 +107,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from, raw_spin_unlock(&minicache_lock); - kunmap_atomic(kto, KM_USER1); + kunmap_atomic(kto); } /* @@ -116,7 +116,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from, void xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) { - void *ptr, *kaddr = kmap_atomic(page, KM_USER0); + void *ptr, *kaddr = kmap_atomic(page); asm volatile( "mov r1, %2 \n\ mov r2, #0 \n\ @@ -133,7 +133,7 @@ xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr) : "=r" (ptr) : "0" (kaddr), "I" (PAGE_SIZE / 32) : "r1", "r2", "r3", "ip"); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } struct cpu_user_fns xscale_mc_user_fns __initdata = { diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 807c0573abbe..5a21505d7550 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -36,7 +36,7 @@ void kunmap(struct page *page) } EXPORT_SYMBOL(kunmap); -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned int idx; unsigned long vaddr; @@ -81,7 +81,7 @@ void *__kmap_atomic(struct page *page) return (void *)vaddr; } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/arm/plat-mxc/3ds_debugboard.c b/arch/arm/plat-mxc/3ds_debugboard.c index f0ba0726306c..d1e31fa1b0c3 100644 --- a/arch/arm/plat-mxc/3ds_debugboard.c +++ b/arch/arm/plat-mxc/3ds_debugboard.c @@ -16,6 +16,8 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/smsc911x.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> #include <mach/hardware.h> @@ -148,6 +150,11 @@ static struct irq_chip expio_irq_chip = { .irq_unmask = expio_unmask_irq, }; +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vdd33a", "smsc911x"), + REGULATOR_SUPPLY("vddvario", "smsc911x"), +}; + int __init mxc_expio_init(u32 base, u32 p_irq) { int i; @@ -188,6 +195,8 @@ int __init mxc_expio_init(u32 base, u32 p_irq) irq_set_chained_handler(p_irq, mxc_expio_irq_handler); /* Register Lan device on the debugboard */ + regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + smsc911x_resources[0].start = LAN9217_BASE_ADDR(base); smsc911x_resources[0].end = LAN9217_BASE_ADDR(base) + 0x100 - 1; platform_device_register(&smsc_lan9217_device); diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index 26e67f0f0051..3c64b2894c13 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig @@ -12,6 +12,7 @@ config TMS320C6X select HAVE_GENERIC_HARDIRQS select HAVE_MEMBLOCK select HAVE_SPARSE_IRQ + select IRQ_DOMAIN select OF select OF_EARLY_FLATTREE diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h index a6ae3c9d9c40..f13b78d5e1ca 100644 --- a/arch/c6x/include/asm/irq.h +++ b/arch/c6x/include/asm/irq.h @@ -13,6 +13,7 @@ #ifndef _ASM_C6X_IRQ_H #define _ASM_C6X_IRQ_H +#include <linux/irqdomain.h> #include <linux/threads.h> #include <linux/list.h> #include <linux/radix-tree.h> @@ -41,253 +42,9 @@ /* This number is used when no interrupt has been assigned */ #define NO_IRQ 0 -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -/* Interrupt controller "host" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The host - * structure is generally created by the PIC code for a given PIC instance - * (though a host can cover more than one PIC if they have a flat number - * model). It's the host callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures are fairly agnostic to the fact that - * we use an open firmware device-tree. We do have references to struct - * device_node in two places: in irq_find_host() to find the host matching - * a given interrupt controller node, and of course as an argument to its - * counterpart host->ops->match() callback. However, those are treated as - * generic pointers by the core and the fact that it's actually a device-node - * pointer is purely a convention between callers and implementation. This - * code could thus be used on other architectures by replacing those two - * by some sort of arch-specific void * "token" used to identify interrupt - * controllers. - */ -struct irq_host; -struct radix_tree_root; -struct device_node; - -/* Functions below are provided by the host and called whenever a new mapping - * is created or an old mapping is disposed. The host can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_host_ops { - /* Match an interrupt controller device node to a host, returns - * 1 on a match - */ - int (*match)(struct irq_host *h, struct device_node *node); - - /* Create or update a mapping between a virtual irq number and a hw - * irq number. This is called only once for a given mapping. - */ - int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - - /* Dispose of such a mapping */ - void (*unmap)(struct irq_host *h, unsigned int virq); - - /* Translate device-tree interrupt specifier from raw format coming - * from the firmware to a irq_hw_number_t (interrupt line number) and - * type (sense) that can be passed to set_irq_type(). In the absence - * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() - * will return the hw number in the first cell and IRQ_TYPE_NONE for - * the type (which amount to keeping whatever default value the - * interrupt controller has for that line) - */ - int (*xlate)(struct irq_host *h, struct device_node *ctrler, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); -}; - -struct irq_host { - struct list_head link; - - /* type of reverse mapping technique */ - unsigned int revmap_type; -#define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */ -#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ -#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ -#define IRQ_HOST_MAP_TREE 3 /* radix tree */ - union { - struct { - unsigned int size; - unsigned int *revmap; - } linear; - struct radix_tree_root tree; - } revmap_data; - struct irq_host_ops *ops; - void *host_data; - irq_hw_number_t inval_irq; - - /* Optional device node pointer */ - struct device_node *of_node; -}; - struct irq_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); -extern bool virq_is_host(unsigned int virq, struct irq_host *host); - -/** - * irq_alloc_host - Allocate a new irq_host data structure - * @of_node: optional device-tree node of the interrupt controller - * @revmap_type: type of reverse mapping to use - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map - * @ops: map/unmap host callbacks - * @inval_irq: provide a hw number in that host space that is always invalid - * - * Allocates and initialize and irq_host structure. Note that in the case of - * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns - * for all legacy interrupts except 0 (which is always the invalid irq for - * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated - * later during boot automatically (the reverse mapping will use the slow path - * until that happens). - */ -extern struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq); - - -/** - * irq_find_host - Locates a host for a given device node - * @node: device-tree node of the interrupt controller - */ -extern struct irq_host *irq_find_host(struct device_node *node); - - -/** - * irq_set_default_host - Set a "default" host - * @host: default host pointer - * - * For convenience, it's possible to set a "default" host that will be used - * whenever NULL is passed to irq_create_mapping(). It makes life easier for - * platforms that want to manipulate a few hard coded interrupt numbers that - * aren't properly represented in the device-tree. - */ -extern void irq_set_default_host(struct irq_host *host); - - -/** - * irq_set_virq_count - Set the maximum number of virt irqs - * @count: number of linux virtual irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -extern void irq_set_virq_count(unsigned int count); - - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - - -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_find_mapping - Find a linux virq from an hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a slow path, for use by generic code. It's expected that an - * irq controller implementation directly calls the appropriate low level - * mapping function. - */ -extern unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_create_direct_mapping - Allocate a virq for direct mapping - * @host: host to allocate the virq for or NULL for default host - * - * This routine is used for irq controllers which can choose the hardware - * interrupt numbers they generate. In such a case it's simplest to use - * the linux virq as the hardware interrupt number. - */ -extern unsigned int irq_create_direct_mapping(struct irq_host *host); - -/** - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. - * @host: host owning this hardware interrupt - * @virq: linux irq number - * @hwirq: hardware irq number in that host space - * - * This is for use by irq controllers that use a radix tree reverse - * mapping for fast lookup. - */ -extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq); - -/** - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses radix tree - * revmaps - */ -extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_linear_revmap - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses linear - * revmaps. It does fallback to the slow path if the revmap doesn't exist - * yet and will create the revmap entry with appropriate locking - */ - -extern unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq); - - - -/** - * irq_alloc_virt - Allocate virtual irq numbers - * @host: host owning these new virtual irqs - * @count: number of consecutive numbers to allocate - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping - * - * This is a low level function that is used internally by irq_create_mapping() - * and that can be used by some irq controllers implementations for things - * like allocating ranges of numbers for MSIs. The revmaps are left untouched. - */ -extern unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint); - -/** - * irq_free_virt - Free virtual irq numbers - * @virq: virtual irq number of the first interrupt to free - * @count: number of interrupts to free - * - * This function is the opposite of irq_alloc_virt. It will not clear reverse - * maps, this should be done previously by unmap'ing the interrupt. In fact, - * all interrupts covered by the range being freed should have been unmapped - * prior to calling this. - */ -extern void irq_free_virt(unsigned int virq, unsigned int count); extern void __init init_pic_c64xplus(void); diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c index 0929e4b2b244..d77bcfdf0d8e 100644 --- a/arch/c6x/kernel/irq.c +++ b/arch/c6x/kernel/irq.c @@ -73,10 +73,10 @@ asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs) set_irq_regs(old_regs); } -static struct irq_host *core_host; +static struct irq_domain *core_domain; -static int core_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hw) +static int core_domain_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) { if (hw < 4 || hw >= NR_PRIORITY_IRQS) return -EINVAL; @@ -86,8 +86,9 @@ static int core_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops core_host_ops = { - .map = core_host_map, +static const struct irq_domain_ops core_domain_ops = { + .map = core_domain_map, + .xlate = irq_domain_xlate_onecell, }; void __init init_IRQ(void) @@ -100,10 +101,11 @@ void __init init_IRQ(void) np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic"); if (np != NULL) { /* create the core host */ - core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0, - &core_host_ops, 0); - if (core_host) - irq_set_default_host(core_host); + core_domain = irq_domain_add_legacy(np, NR_PRIORITY_IRQS, + 0, 0, &core_domain_ops, + NULL); + if (core_domain) + irq_set_default_host(core_domain); of_node_put(np); } @@ -128,601 +130,15 @@ int arch_show_interrupts(struct seq_file *p, int prec) return 0; } -/* - * IRQ controller and virtual interrupts - */ - -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { - irq_hw_number_t hwirq; - struct irq_host *host; -}; - -static LIST_HEAD(irq_hosts); -static DEFINE_RAW_SPINLOCK(irq_big_lock); -static DEFINE_MUTEX(revmap_trees_mutex); -static struct irq_map_entry irq_map[NR_IRQS]; -static unsigned int irq_virq_count = NR_IRQS; -static struct irq_host *irq_default_host; - irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { - return irq_map[d->irq].hwirq; + return d->hwirq; } EXPORT_SYMBOL_GPL(irqd_to_hwirq); irq_hw_number_t virq_to_hw(unsigned int virq) { - return irq_map[virq].hwirq; + struct irq_data *irq_data = irq_get_irq_data(virq); + return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; } EXPORT_SYMBOL_GPL(virq_to_hw); - -bool virq_is_host(unsigned int virq, struct irq_host *host) -{ - return irq_map[virq].host == host; -} -EXPORT_SYMBOL_GPL(virq_is_host); - -static int default_irq_host_match(struct irq_host *h, struct device_node *np) -{ - return h->of_node != NULL && h->of_node == np; -} - -struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq) -{ - struct irq_host *host; - unsigned int size = sizeof(struct irq_host); - unsigned int i; - unsigned int *rmap; - unsigned long flags; - - /* Allocate structure and revmap table if using linear mapping */ - if (revmap_type == IRQ_HOST_MAP_LINEAR) - size += revmap_arg * sizeof(unsigned int); - host = kzalloc(size, GFP_KERNEL); - if (host == NULL) - return NULL; - - /* Fill structure */ - host->revmap_type = revmap_type; - host->inval_irq = inval_irq; - host->ops = ops; - host->of_node = of_node_get(of_node); - - if (host->ops->match == NULL) - host->ops->match = default_irq_host_match; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* Check for the priority controller. */ - if (revmap_type == IRQ_HOST_MAP_PRIORITY) { - if (irq_map[0].host != NULL) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - of_node_put(host->of_node); - kfree(host); - return NULL; - } - irq_map[0].host = host; - } - - list_add(&host->link, &irq_hosts); - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - - /* Additional setups per revmap type */ - switch (revmap_type) { - case IRQ_HOST_MAP_PRIORITY: - /* 0 is always the invalid number for priority */ - host->inval_irq = 0; - /* setup us as the host for all priority interrupts */ - for (i = 1; i < NR_PRIORITY_IRQS; i++) { - irq_map[i].hwirq = i; - smp_wmb(); - irq_map[i].host = host; - smp_wmb(); - - ops->map(host, i, i); - } - break; - case IRQ_HOST_MAP_LINEAR: - rmap = (unsigned int *)(host + 1); - for (i = 0; i < revmap_arg; i++) - rmap[i] = NO_IRQ; - host->revmap_data.linear.size = revmap_arg; - smp_wmb(); - host->revmap_data.linear.revmap = rmap; - break; - case IRQ_HOST_MAP_TREE: - INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); - break; - default: - break; - } - - pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); - - return host; -} - -struct irq_host *irq_find_host(struct device_node *node) -{ - struct irq_host *h, *found = NULL; - unsigned long flags; - - /* We might want to match the legacy controller last since - * it might potentially be set to match all interrupts in - * the absence of a device node. This isn't a problem so far - * yet though... - */ - raw_spin_lock_irqsave(&irq_big_lock, flags); - list_for_each_entry(h, &irq_hosts, link) - if (h->ops->match(h, node)) { - found = h; - break; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_host *host) -{ - pr_debug("irq: Default host set to @0x%p\n", host); - - irq_default_host = host; -} - -void irq_set_virq_count(unsigned int count) -{ - pr_debug("irq: Trying to set virq count to %d\n", count); - - BUG_ON(count < NR_PRIORITY_IRQS); - if (count < NR_IRQS) - irq_virq_count = count; -} - -static int irq_setup_virq(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - int res; - - res = irq_alloc_desc_at(virq, 0); - if (res != virq) { - pr_debug("irq: -> allocating desc failed\n"); - goto error; - } - - /* map it */ - smp_wmb(); - irq_map[virq].hwirq = hwirq; - smp_mb(); - - if (host->ops->map(host, virq, hwirq)) { - pr_debug("irq: -> mapping failed, freeing\n"); - goto errdesc; - } - - irq_clear_status_flags(virq, IRQ_NOREQUEST); - - return 0; - -errdesc: - irq_free_descs(virq, 1); -error: - irq_free_virt(virq, 1); - return -1; -} - -unsigned int irq_create_direct_mapping(struct irq_host *host) -{ - unsigned int virq; - - if (host == NULL) - host = irq_default_host; - - BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); - - virq = irq_alloc_virt(host, 1, 0); - if (virq == NO_IRQ) { - pr_debug("irq: create_direct virq allocation failed\n"); - return NO_IRQ; - } - - pr_debug("irq: create_direct obtained virq %d\n", virq); - - if (irq_setup_virq(host, virq, virq)) - return NO_IRQ; - - return virq; -} - -unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int virq, hint; - - pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) { - printk(KERN_WARNING "irq_create_mapping called for" - " NULL host, hwirq=%lx\n", hwirq); - WARN_ON(1); - return NO_IRQ; - } - pr_debug("irq: -> using host @%p\n", host); - - /* Check if mapping already exists */ - virq = irq_find_mapping(host, hwirq); - if (virq != NO_IRQ) { - pr_debug("irq: -> existing mapping on virq %d\n", virq); - return virq; - } - - /* Allocate a virtual interrupt number */ - hint = hwirq % irq_virq_count; - virq = irq_alloc_virt(host, 1, hint); - if (virq == NO_IRQ) { - pr_debug("irq: -> virq allocation failed\n"); - return NO_IRQ; - } - - if (irq_setup_virq(host, virq, hwirq)) - return NO_IRQ; - - pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", - hwirq, host->of_node ? host->of_node->full_name : "null", virq); - - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - unsigned int virq; - - if (controller == NULL) - host = irq_default_host; - else - host = irq_find_host(controller); - if (host == NULL) { - printk(KERN_WARNING "irq: no irq host found for %s !\n", - controller->full_name); - return NO_IRQ; - } - - /* If host has no translation, then we assume interrupt line */ - if (host->ops->xlate == NULL) - hwirq = intspec[0]; - else { - if (host->ops->xlate(host, controller, intspec, intsize, - &hwirq, &type)) - return NO_IRQ; - } - - /* Create mapping */ - virq = irq_create_mapping(host, hwirq); - if (virq == NO_IRQ) - return virq; - - /* Set type if specified and different than the current one */ - if (type != IRQ_TYPE_NONE && - type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - -void irq_dispose_mapping(unsigned int virq) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - - if (virq == NO_IRQ) - return; - - /* Never unmap priority interrupts */ - if (virq < NR_PRIORITY_IRQS) - return; - - host = irq_map[virq].host; - if (WARN_ON(host == NULL)) - return; - - irq_set_status_flags(virq, IRQ_NOREQUEST); - - /* remove chip and handler */ - irq_set_chip_and_handler(virq, NULL, NULL); - - /* Make sure it's completed */ - synchronize_irq(virq); - - /* Tell the PIC about it */ - if (host->ops->unmap) - host->ops->unmap(host, virq); - smp_mb(); - - /* Clear reverse map */ - hwirq = irq_map[virq].hwirq; - switch (host->revmap_type) { - case IRQ_HOST_MAP_LINEAR: - if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; - break; - case IRQ_HOST_MAP_TREE: - mutex_lock(&revmap_trees_mutex); - radix_tree_delete(&host->revmap_data.tree, hwirq); - mutex_unlock(&revmap_trees_mutex); - break; - } - - /* Destroy map */ - smp_mb(); - irq_map[virq].hwirq = host->inval_irq; - - irq_free_descs(virq, 1); - /* Free it */ - irq_free_virt(virq, 1); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int i; - unsigned int hint = hwirq % irq_virq_count; - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) - return NO_IRQ; - - /* Slow path does a linear search of the map */ - i = hint; - do { - if (irq_map[i].host == host && - irq_map[i].hwirq == hwirq) - return i; - i++; - if (i >= irq_virq_count) - i = 4; - } while (i != hint); - return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); - -unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq) -{ - struct irq_map_entry *ptr; - unsigned int virq; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) - return irq_find_mapping(host, hwirq); - - /* - * The ptr returned references the static global irq_map. - * but freeing an irq can delete nodes along the path to - * do the lookup via call_rcu. - */ - rcu_read_lock(); - ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); - rcu_read_unlock(); - - /* - * If found in radix tree, then fine. - * Else fallback to linear lookup - this should not happen in practice - * as it means that we failed to insert the node in the radix tree. - */ - if (ptr) - virq = ptr - irq_map; - else - virq = irq_find_mapping(host, hwirq); - - return virq; -} - -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) - return; - - if (virq != NO_IRQ) { - mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, - &irq_map[virq]); - mutex_unlock(&revmap_trees_mutex); - } -} - -unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int *revmap; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) - return irq_find_mapping(host, hwirq); - - /* Check revmap bounds */ - if (unlikely(hwirq >= host->revmap_data.linear.size)) - return irq_find_mapping(host, hwirq); - - /* Check if revmap was allocated */ - revmap = host->revmap_data.linear.revmap; - if (unlikely(revmap == NULL)) - return irq_find_mapping(host, hwirq); - - /* Fill up revmap with slow path if no mapping found */ - if (unlikely(revmap[hwirq] == NO_IRQ)) - revmap[hwirq] = irq_find_mapping(host, hwirq); - - return revmap[hwirq]; -} - -unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint) -{ - unsigned long flags; - unsigned int i, j, found = NO_IRQ; - - if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS)) - return NO_IRQ; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* Use hint for 1 interrupt if any */ - if (count == 1 && hint >= NR_PRIORITY_IRQS && - hint < irq_virq_count && irq_map[hint].host == NULL) { - found = hint; - goto hint_found; - } - - /* Look for count consecutive numbers in the allocatable - * (non-legacy) space - */ - for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) { - if (irq_map[i].host != NULL) - j = 0; - else - j++; - - if (j == count) { - found = i - count + 1; - break; - } - } - if (found == NO_IRQ) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return NO_IRQ; - } - hint_found: - for (i = found; i < (found + count); i++) { - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = host; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} - -void irq_free_virt(unsigned int virq, unsigned int count) -{ - unsigned long flags; - unsigned int i; - - WARN_ON(virq < NR_PRIORITY_IRQS); - WARN_ON(count == 0 || (virq + count) > irq_virq_count); - - if (virq < NR_PRIORITY_IRQS) { - if (virq + count < NR_PRIORITY_IRQS) - return; - count -= NR_PRIORITY_IRQS - virq; - virq = NR_PRIORITY_IRQS; - } - - if (count > irq_virq_count || virq > irq_virq_count - count) { - if (virq > irq_virq_count) - return; - count = irq_virq_count - virq; - } - - raw_spin_lock_irqsave(&irq_big_lock, flags); - for (i = virq; i < (virq + count); i++) { - struct irq_host *host; - - host = irq_map[i].host; - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = NULL; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); -} - -#ifdef CONFIG_VIRQ_DEBUG -static int virq_debug_show(struct seq_file *m, void *private) -{ - unsigned long flags; - struct irq_desc *desc; - const char *p; - static const char none[] = "none"; - void *data; - int i; - - seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", - "chip name", "chip data", "host name"); - - for (i = 1; i < nr_irqs; i++) { - desc = irq_to_desc(i); - if (!desc) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - if (desc->action && desc->action->handler) { - struct irq_chip *chip; - - seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", irq_map[i].hwirq); - - chip = irq_desc_get_chip(desc); - if (chip && chip->name) - p = chip->name; - else - p = none; - seq_printf(m, "%-15s ", p); - - data = irq_desc_get_chip_data(desc); - seq_printf(m, "0x%16p ", data); - - if (irq_map[i].host && irq_map[i].host->of_node) - p = irq_map[i].host->of_node->full_name; - else - p = none; - seq_printf(m, "%s\n", p); - } - - raw_spin_unlock_irqrestore(&desc->lock, flags); - } - - return 0; -} - -static int virq_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, virq_debug_show, inode->i_private); -} - -static const struct file_operations virq_debug_fops = { - .open = virq_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init irq_debugfs_init(void) -{ - if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, - NULL, &virq_debug_fops) == NULL) - return -ENOMEM; - - return 0; -} -device_initcall(irq_debugfs_init); -#endif /* CONFIG_VIRQ_DEBUG */ diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 7c37a947fb1c..c1c4e2ae3f85 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -48,7 +48,7 @@ struct megamod_regs { }; struct megamod_pic { - struct irq_host *irqhost; + struct irq_domain *irqhost; struct megamod_regs __iomem *regs; raw_spinlock_t lock; @@ -116,7 +116,7 @@ static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc) } } -static int megamod_map(struct irq_host *h, unsigned int virq, +static int megamod_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct megamod_pic *pic = h->host_data; @@ -136,21 +136,9 @@ static int megamod_map(struct irq_host *h, unsigned int virq, return 0; } -static int megamod_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ - /* megamod intspecs must have 1 cell */ - BUG_ON(intsize != 1); - *out_hwirq = intspec[0]; - *out_type = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops megamod_host_ops = { +static const struct irq_domain_ops megamod_domain_ops = { .map = megamod_map, - .xlate = megamod_xlate, + .xlate = irq_domain_xlate_onecell, }; static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output) @@ -223,9 +211,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np) return NULL; } - pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - NR_COMBINERS * 32, &megamod_host_ops, - IRQ_UNMAPPED); + pic->irqhost = irq_domain_add_linear(np, NR_COMBINERS * 32, + &megamod_domain_ops, pic); if (!pic->irqhost) { pr_err("%s: Could not alloc host.\n", np->full_name); goto error_free; diff --git a/arch/frv/include/asm/highmem.h b/arch/frv/include/asm/highmem.h index a8d6565d415d..716956a5317b 100644 --- a/arch/frv/include/asm/highmem.h +++ b/arch/frv/include/asm/highmem.h @@ -157,7 +157,7 @@ static inline void kunmap_atomic_primary(void *kvaddr, enum km_type type) pagefault_enable(); } -void *__kmap_atomic(struct page *page); +void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); #endif /* !__ASSEMBLY__ */ diff --git a/arch/frv/mm/highmem.c b/arch/frv/mm/highmem.c index fd7fcd4c2e33..31902c9d5be5 100644 --- a/arch/frv/mm/highmem.c +++ b/arch/frv/mm/highmem.c @@ -37,7 +37,7 @@ struct page *kmap_atomic_to_page(void *ptr) return virt_to_page(ptr); } -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned long paddr; int type; @@ -64,7 +64,7 @@ void *__kmap_atomic(struct page *page) return NULL; } } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index c8d6efb99dbf..11060fa87da3 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -14,6 +14,7 @@ config MICROBLAZE select TRACING_SUPPORT select OF select OF_EARLY_FLATTREE + select IRQ_DOMAIN select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/microblaze/include/asm/hardirq.h b/arch/microblaze/include/asm/hardirq.h index cd1ac9aad56c..fb3c05a0cbbf 100644 --- a/arch/microblaze/include/asm/hardirq.h +++ b/arch/microblaze/include/asm/hardirq.h @@ -1,17 +1 @@ -/* - * Copyright (C) 2006 Atmark Techno, Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef _ASM_MICROBLAZE_HARDIRQ_H -#define _ASM_MICROBLAZE_HARDIRQ_H - -/* should be defined in each interrupt controller driver */ -extern unsigned int get_irq(struct pt_regs *regs); - #include <asm-generic/hardirq.h> - -#endif /* _ASM_MICROBLAZE_HARDIRQ_H */ diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h index a175132e4496..bab3b1393ad4 100644 --- a/arch/microblaze/include/asm/irq.h +++ b/arch/microblaze/include/asm/irq.h @@ -9,49 +9,13 @@ #ifndef _ASM_MICROBLAZE_IRQ_H #define _ASM_MICROBLAZE_IRQ_H - -/* - * Linux IRQ# is currently offset by one to map to the hardware - * irq number. So hardware IRQ0 maps to Linux irq 1. - */ -#define NO_IRQ_OFFSET 1 -#define IRQ_OFFSET NO_IRQ_OFFSET -#define NR_IRQS (32 + IRQ_OFFSET) +#define NR_IRQS (32 + 1) #include <asm-generic/irq.h> -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -extern unsigned int nr_irq; - struct pt_regs; extern void do_IRQ(struct pt_regs *regs); -/** FIXME - not implement - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ - return; -} - -struct irq_host; - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq); +/* should be defined in each interrupt controller driver */ +extern unsigned int get_irq(void); #endif /* _ASM_MICROBLAZE_IRQ_H */ diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 44b177e2ab12..ad120672cee5 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -9,6 +9,7 @@ */ #include <linux/init.h> +#include <linux/irqdomain.h> #include <linux/irq.h> #include <asm/page.h> #include <linux/io.h> @@ -25,8 +26,6 @@ static unsigned int intc_baseaddr; #define INTC_BASE intc_baseaddr #endif -unsigned int nr_irq; - /* No one else should require these constants, so define them locally here. */ #define ISR 0x00 /* Interrupt Status Register */ #define IPR 0x04 /* Interrupt Pending Register */ @@ -84,24 +83,45 @@ static struct irq_chip intc_dev = { .irq_mask_ack = intc_mask_ack, }; -unsigned int get_irq(struct pt_regs *regs) +static struct irq_domain *root_domain; + +unsigned int get_irq(void) { - int irq; + unsigned int hwirq, irq = -1; - /* - * NOTE: This function is the one that needs to be improved in - * order to handle multiple interrupt controllers. It currently - * is hardcoded to check for interrupts only on the first INTC. - */ - irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET; - pr_debug("get_irq: %d\n", irq); + hwirq = in_be32(INTC_BASE + IVR); + if (hwirq != -1U) + irq = irq_find_mapping(root_domain, hwirq); + + pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq); return irq; } +int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + u32 intr_mask = (u32)d->host_data; + + if (intr_mask & (1 << hw)) { + irq_set_chip_and_handler_name(irq, &intc_dev, + handle_edge_irq, "edge"); + irq_clear_status_flags(irq, IRQ_LEVEL); + } else { + irq_set_chip_and_handler_name(irq, &intc_dev, + handle_level_irq, "level"); + irq_set_status_flags(irq, IRQ_LEVEL); + } + return 0; +} + +static const struct irq_domain_ops xintc_irq_domain_ops = { + .xlate = irq_domain_xlate_onetwocell, + .map = xintc_map, +}; + void __init init_IRQ(void) { - u32 i, intr_mask; + u32 nr_irq, intr_mask; struct device_node *intc = NULL; #ifdef CONFIG_SELFMOD_INTC unsigned int intc_baseaddr = 0; @@ -146,16 +166,9 @@ void __init init_IRQ(void) /* Turn on the Master Enable. */ out_be32(intc_baseaddr + MER, MER_HIE | MER_ME); - for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) { - if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) { - irq_set_chip_and_handler_name(i, &intc_dev, - handle_edge_irq, "edge"); - irq_clear_status_flags(i, IRQ_LEVEL); - } else { - irq_set_chip_and_handler_name(i, &intc_dev, - handle_level_irq, "level"); - irq_set_status_flags(i, IRQ_LEVEL); - } - irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET; - } + /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm + * lazy and Michal can clean it up to something nicer when he tests + * and commits this patch. ~~gcl */ + root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops, + (void *)intr_mask); } diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index bbebcae72c02..ace700afbfdf 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs) trace_hardirqs_off(); irq_enter(); - irq = get_irq(regs); + irq = get_irq(); next_irq: BUG_ON(!irq); - /* Substract 1 because of get_irq */ - generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET); + generic_handle_irq(irq); - irq = get_irq(regs); - if (irq) { + irq = get_irq(); + if (irq != -1U) { pr_debug("next irq: %d\n", irq); ++concurrent_irq; goto next_irq; @@ -48,18 +47,3 @@ next_irq: set_irq_regs(old_regs); trace_hardirqs_on(); } - -/* MS: There is no any advance mapping mechanism. We are using simple 32bit - intc without any cascades or any connection that's why mapping is 1:1 */ -unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq) -{ - return hwirq + IRQ_OFFSET; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0] + IRQ_OFFSET; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 604cd9dd1333..70e6d0b41ab4 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p) unflatten_device_tree(); - /* NOTE I think that this function is not necessary to call */ - /* irq_early_init(); */ setup_cpuinfo(); microblaze_cache_init(); diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5ab6e89603c5..edbbae17e820 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2327,6 +2327,7 @@ config USE_OF bool "Flattened Device Tree support" select OF select OF_EARLY_FLATTREE + select IRQ_DOMAIN help Include support for flattened device tree machine descriptions. diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 77e644082a3b..2d91888c9b74 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h @@ -47,7 +47,7 @@ extern void kunmap_high(struct page *page); extern void *kmap(struct page *page); extern void kunmap(struct page *page); -extern void *__kmap_atomic(struct page *page); +extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern void *kmap_atomic_pfn(unsigned long pfn); extern struct page *kmap_atomic_to_page(void *ptr); diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 2354c870a63a..fb698dc09bc9 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -11,15 +11,12 @@ #include <linux/linkage.h> #include <linux/smp.h> +#include <linux/irqdomain.h> #include <asm/mipsmtregs.h> #include <irq.h> -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - #ifdef CONFIG_I8259 static inline int irq_canonicalize(int irq) { diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 6b8b4208481e..558b5395795d 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start, } #endif -/* - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# - * - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are - * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not - * supported. - */ -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - return intspec[0]; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - void __init early_init_devtree(void *params) { /* Setup flat device-tree pointer */ diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 4f9eb0b23036..c97087d12d07 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -498,7 +498,7 @@ static inline void local_r4k_flush_cache_page(void *args) if (map_coherent) vaddr = kmap_coherent(page, addr); else - vaddr = kmap_atomic(page, KM_USER0); + vaddr = kmap_atomic(page); addr = (unsigned long)vaddr; } @@ -521,7 +521,7 @@ static inline void local_r4k_flush_cache_page(void *args) if (map_coherent) kunmap_coherent(); else - kunmap_atomic(vaddr, KM_USER0); + kunmap_atomic(vaddr); } } diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 3634c7ea06ac..aff57057a949 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c @@ -41,7 +41,7 @@ EXPORT_SYMBOL(kunmap); * kmaps are appropriate for short, tight code paths only. */ -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned long vaddr; int idx, type; @@ -62,7 +62,7 @@ void *__kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 3b3ffd439cd7..1a85ba92eb5c 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -207,21 +207,21 @@ void copy_user_highpage(struct page *to, struct page *from, { void *vfrom, *vto; - vto = kmap_atomic(to, KM_USER1); + vto = kmap_atomic(to); if (cpu_has_dc_aliases && page_mapped(from) && !Page_dcache_dirty(from)) { vfrom = kmap_coherent(from, vaddr); copy_page(vto, vfrom); kunmap_coherent(); } else { - vfrom = kmap_atomic(from, KM_USER0); + vfrom = kmap_atomic(from); copy_page(vto, vfrom); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); } if ((!cpu_has_ic_fills_f_dc) || pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) flush_data_cache_page((unsigned long)vto); - kunmap_atomic(vto, KM_USER1); + kunmap_atomic(vto); /* Make sure this page is cleared on other CPU's too before using it */ smp_wmb(); } diff --git a/arch/mn10300/include/asm/highmem.h b/arch/mn10300/include/asm/highmem.h index bfe2d88604d9..7c137cd8aa37 100644 --- a/arch/mn10300/include/asm/highmem.h +++ b/arch/mn10300/include/asm/highmem.h @@ -70,7 +70,7 @@ static inline void kunmap(struct page *page) * be used in IRQ contexts, so in some (very limited) cases we need * it. */ -static inline unsigned long __kmap_atomic(struct page *page) +static inline unsigned long kmap_atomic(struct page *page) { unsigned long vaddr; int idx, type; diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h index e1f3fe26606c..bbb34e5343a2 100644 --- a/arch/openrisc/include/asm/prom.h +++ b/arch/openrisc/include/asm/prom.h @@ -24,6 +24,7 @@ #include <linux/types.h> #include <asm/irq.h> +#include <linux/irqdomain.h> #include <linux/atomic.h> #include <linux/of_irq.h> #include <linux/of_fdt.h> @@ -63,15 +64,6 @@ extern const void *of_get_mac_address(struct device_node *np); struct pci_dev; extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); -/* This routine is here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes. We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_OPENRISC_PROM_H */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index da601dd34c05..9f21ab0c02e3 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -140,7 +140,7 @@ static inline void *kmap(struct page *page) #define kunmap(page) kunmap_parisc(page_address(page)) -static inline void *__kmap_atomic(struct page *page) +static inline void *kmap_atomic(struct page *page) { pagefault_disable(); return page_address(page); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1919634a9b32..303703d716fe 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -135,6 +135,7 @@ config PPC select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQ select IRQ_PER_CPU + select IRQ_DOMAIN select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL select IRQ_FORCED_THREADING diff --git a/arch/powerpc/include/asm/ehv_pic.h b/arch/powerpc/include/asm/ehv_pic.h index a9e1f4f796f6..dc7d48e3ea90 100644 --- a/arch/powerpc/include/asm/ehv_pic.h +++ b/arch/powerpc/include/asm/ehv_pic.h @@ -25,7 +25,7 @@ struct ehv_pic { /* The remapper for this EHV_PIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; /* The "linux" controller struct */ struct irq_chip hc_irq; diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h index dbc264010d0b..caaf6e00630d 100644 --- a/arch/powerpc/include/asm/highmem.h +++ b/arch/powerpc/include/asm/highmem.h @@ -79,7 +79,7 @@ static inline void kunmap(struct page *page) kunmap_high(page); } -static inline void *__kmap_atomic(struct page *page) +static inline void *kmap_atomic(struct page *page) { return kmap_atomic_prot(page, kmap_prot); } diff --git a/arch/powerpc/include/asm/i8259.h b/arch/powerpc/include/asm/i8259.h index 105ade297aad..c3fdfbd5a673 100644 --- a/arch/powerpc/include/asm/i8259.h +++ b/arch/powerpc/include/asm/i8259.h @@ -6,7 +6,7 @@ extern void i8259_init(struct device_node *node, unsigned long intack_addr); extern unsigned int i8259_irq(void); -extern struct irq_host *i8259_get_host(void); +extern struct irq_domain *i8259_get_host(void); #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_I8259_H */ diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index c0e1bc319e35..fe0b09dceb7d 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ +#include <linux/irqdomain.h> #include <linux/threads.h> #include <linux/list.h> #include <linux/radix-tree.h> @@ -35,258 +36,12 @@ extern atomic_t ppc_n_lost_interrupts; /* Total number of virq in the platform */ #define NR_IRQS CONFIG_NR_IRQS -/* Number of irqs reserved for the legacy controller */ -#define NUM_ISA_INTERRUPTS 16 - /* Same thing, used by the generic IRQ code */ #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - -/* Interrupt controller "host" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The host - * structure is generally created by the PIC code for a given PIC instance - * (though a host can cover more than one PIC if they have a flat number - * model). It's the host callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures are fairly agnostic to the fact that - * we use an open firmware device-tree. We do have references to struct - * device_node in two places: in irq_find_host() to find the host matching - * a given interrupt controller node, and of course as an argument to its - * counterpart host->ops->match() callback. However, those are treated as - * generic pointers by the core and the fact that it's actually a device-node - * pointer is purely a convention between callers and implementation. This - * code could thus be used on other architectures by replacing those two - * by some sort of arch-specific void * "token" used to identify interrupt - * controllers. - */ -struct irq_host; -struct radix_tree_root; - -/* Functions below are provided by the host and called whenever a new mapping - * is created or an old mapping is disposed. The host can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_host_ops { - /* Match an interrupt controller device node to a host, returns - * 1 on a match - */ - int (*match)(struct irq_host *h, struct device_node *node); - - /* Create or update a mapping between a virtual irq number and a hw - * irq number. This is called only once for a given mapping. - */ - int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); - - /* Dispose of such a mapping */ - void (*unmap)(struct irq_host *h, unsigned int virq); - - /* Translate device-tree interrupt specifier from raw format coming - * from the firmware to a irq_hw_number_t (interrupt line number) and - * type (sense) that can be passed to set_irq_type(). In the absence - * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() - * will return the hw number in the first cell and IRQ_TYPE_NONE for - * the type (which amount to keeping whatever default value the - * interrupt controller has for that line) - */ - int (*xlate)(struct irq_host *h, struct device_node *ctrler, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); -}; - -struct irq_host { - struct list_head link; - - /* type of reverse mapping technique */ - unsigned int revmap_type; -#define IRQ_HOST_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */ -#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ -#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ -#define IRQ_HOST_MAP_TREE 3 /* radix tree */ - union { - struct { - unsigned int size; - unsigned int *revmap; - } linear; - struct radix_tree_root tree; - } revmap_data; - struct irq_host_ops *ops; - void *host_data; - irq_hw_number_t inval_irq; - - /* Optional device node pointer */ - struct device_node *of_node; -}; - struct irq_data; extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); -extern bool virq_is_host(unsigned int virq, struct irq_host *host); - -/** - * irq_alloc_host - Allocate a new irq_host data structure - * @of_node: optional device-tree node of the interrupt controller - * @revmap_type: type of reverse mapping to use - * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map - * @ops: map/unmap host callbacks - * @inval_irq: provide a hw number in that host space that is always invalid - * - * Allocates and initialize and irq_host structure. Note that in the case of - * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns - * for all legacy interrupts except 0 (which is always the invalid irq for - * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by - * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated - * later during boot automatically (the reverse mapping will use the slow path - * until that happens). - */ -extern struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq); - - -/** - * irq_find_host - Locates a host for a given device node - * @node: device-tree node of the interrupt controller - */ -extern struct irq_host *irq_find_host(struct device_node *node); - - -/** - * irq_set_default_host - Set a "default" host - * @host: default host pointer - * - * For convenience, it's possible to set a "default" host that will be used - * whenever NULL is passed to irq_create_mapping(). It makes life easier for - * platforms that want to manipulate a few hard coded interrupt numbers that - * aren't properly represented in the device-tree. - */ -extern void irq_set_default_host(struct irq_host *host); - - -/** - * irq_set_virq_count - Set the maximum number of virt irqs - * @count: number of linux virtual irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -extern void irq_set_virq_count(unsigned int count); - - -/** - * irq_create_mapping - Map a hardware interrupt into linux virq space - * @host: host owning this hardware interrupt or NULL for default host - * @hwirq: hardware irq number in that host space - * - * Only one mapping per hardware interrupt is permitted. Returns a linux - * virq number. - * If the sense/trigger is to be specified, set_irq_type() should be called - * on the number returned from that call. - */ -extern unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - - -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - */ -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_find_mapping - Find a linux virq from an hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a slow path, for use by generic code. It's expected that an - * irq controller implementation directly calls the appropriate low level - * mapping function. - */ -extern unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_create_direct_mapping - Allocate a virq for direct mapping - * @host: host to allocate the virq for or NULL for default host - * - * This routine is used for irq controllers which can choose the hardware - * interrupt numbers they generate. In such a case it's simplest to use - * the linux virq as the hardware interrupt number. - */ -extern unsigned int irq_create_direct_mapping(struct irq_host *host); - -/** - * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. - * @host: host owning this hardware interrupt - * @virq: linux irq number - * @hwirq: hardware irq number in that host space - * - * This is for use by irq controllers that use a radix tree reverse - * mapping for fast lookup. - */ -extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq); - -/** - * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses radix tree - * revmaps - */ -extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq); - -/** - * irq_linear_revmap - Find a linux virq from a hw irq number. - * @host: host owning this hardware interrupt - * @hwirq: hardware irq number in that host space - * - * This is a fast path, for use by irq controller code that uses linear - * revmaps. It does fallback to the slow path if the revmap doesn't exist - * yet and will create the revmap entry with appropriate locking - */ - -extern unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq); - - - -/** - * irq_alloc_virt - Allocate virtual irq numbers - * @host: host owning these new virtual irqs - * @count: number of consecutive numbers to allocate - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping - * - * This is a low level function that is used internally by irq_create_mapping() - * and that can be used by some irq controllers implementations for things - * like allocating ranges of numbers for MSIs. The revmaps are left untouched. - */ -extern unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint); - -/** - * irq_free_virt - Free virtual irq numbers - * @virq: virtual irq number of the first interrupt to free - * @count: number of interrupts to free - * - * This function is the opposite of irq_alloc_virt. It will not clear reverse - * maps, this should be done previously by unmap'ing the interrupt. In fact, - * all interrupts covered by the range being freed should have been unmapped - * prior to calling this. - */ -extern void irq_free_virt(unsigned int virq, unsigned int count); /** * irq_early_init - Init irq remapping subsystem diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 67b4d9837236..a5b7c56237f9 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -255,7 +255,7 @@ struct mpic struct device_node *node; /* The remapper for this MPIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; /* The "linux" controller struct */ struct irq_chip hc_irq; diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h index c48de98ba94e..4ae9a09c3b89 100644 --- a/arch/powerpc/include/asm/xics.h +++ b/arch/powerpc/include/asm/xics.h @@ -86,7 +86,7 @@ struct ics { extern unsigned int xics_default_server; extern unsigned int xics_default_distrib_server; extern unsigned int xics_interrupt_server_size; -extern struct irq_host *xics_host; +extern struct irq_domain *xics_host; struct xics_cppr { unsigned char stack[MAX_NUM_PRIORITIES]; diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index d39ae606ff8d..79bb282e6501 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -713,7 +713,7 @@ static struct dev_pm_ops ibmebus_bus_dev_pm_ops = { struct bus_type ibmebus_bus_type = { .name = "ibmebus", - .uevent = of_device_uevent, + .uevent = of_device_uevent_modalias, .bus_attrs = ibmebus_bus_attrs, .match = ibmebus_bus_bus_match, .probe = ibmebus_bus_device_probe, diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 01e2877e8e04..bdfb3eee3e6f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -490,409 +490,19 @@ void do_softirq(void) local_irq_restore(flags); } - -/* - * IRQ controller and virtual interrupts - */ - -/* The main irq map itself is an array of NR_IRQ entries containing the - * associate host and irq number. An entry with a host of NULL is free. - * An entry can be allocated if it's free, the allocator always then sets - * hwirq first to the host's invalid irq number and then fills ops. - */ -struct irq_map_entry { - irq_hw_number_t hwirq; - struct irq_host *host; -}; - -static LIST_HEAD(irq_hosts); -static DEFINE_RAW_SPINLOCK(irq_big_lock); -static DEFINE_MUTEX(revmap_trees_mutex); -static struct irq_map_entry irq_map[NR_IRQS]; -static unsigned int irq_virq_count = NR_IRQS; -static struct irq_host *irq_default_host; - irq_hw_number_t irqd_to_hwirq(struct irq_data *d) { - return irq_map[d->irq].hwirq; + return d->hwirq; } EXPORT_SYMBOL_GPL(irqd_to_hwirq); irq_hw_number_t virq_to_hw(unsigned int virq) { - return irq_map[virq].hwirq; + struct irq_data *irq_data = irq_get_irq_data(virq); + return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; } EXPORT_SYMBOL_GPL(virq_to_hw); -bool virq_is_host(unsigned int virq, struct irq_host *host) -{ - return irq_map[virq].host == host; -} -EXPORT_SYMBOL_GPL(virq_is_host); - -static int default_irq_host_match(struct irq_host *h, struct device_node *np) -{ - return h->of_node != NULL && h->of_node == np; -} - -struct irq_host *irq_alloc_host(struct device_node *of_node, - unsigned int revmap_type, - unsigned int revmap_arg, - struct irq_host_ops *ops, - irq_hw_number_t inval_irq) -{ - struct irq_host *host; - unsigned int size = sizeof(struct irq_host); - unsigned int i; - unsigned int *rmap; - unsigned long flags; - - /* Allocate structure and revmap table if using linear mapping */ - if (revmap_type == IRQ_HOST_MAP_LINEAR) - size += revmap_arg * sizeof(unsigned int); - host = kzalloc(size, GFP_KERNEL); - if (host == NULL) - return NULL; - - /* Fill structure */ - host->revmap_type = revmap_type; - host->inval_irq = inval_irq; - host->ops = ops; - host->of_node = of_node_get(of_node); - - if (host->ops->match == NULL) - host->ops->match = default_irq_host_match; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* If it's a legacy controller, check for duplicates and - * mark it as allocated (we use irq 0 host pointer for that - */ - if (revmap_type == IRQ_HOST_MAP_LEGACY) { - if (irq_map[0].host != NULL) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - of_node_put(host->of_node); - kfree(host); - return NULL; - } - irq_map[0].host = host; - } - - list_add(&host->link, &irq_hosts); - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - - /* Additional setups per revmap type */ - switch(revmap_type) { - case IRQ_HOST_MAP_LEGACY: - /* 0 is always the invalid number for legacy */ - host->inval_irq = 0; - /* setup us as the host for all legacy interrupts */ - for (i = 1; i < NUM_ISA_INTERRUPTS; i++) { - irq_map[i].hwirq = i; - smp_wmb(); - irq_map[i].host = host; - smp_wmb(); - - /* Legacy flags are left to default at this point, - * one can then use irq_create_mapping() to - * explicitly change them - */ - ops->map(host, i, i); - - /* Clear norequest flags */ - irq_clear_status_flags(i, IRQ_NOREQUEST); - } - break; - case IRQ_HOST_MAP_LINEAR: - rmap = (unsigned int *)(host + 1); - for (i = 0; i < revmap_arg; i++) - rmap[i] = NO_IRQ; - host->revmap_data.linear.size = revmap_arg; - smp_wmb(); - host->revmap_data.linear.revmap = rmap; - break; - case IRQ_HOST_MAP_TREE: - INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); - break; - default: - break; - } - - pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); - - return host; -} - -struct irq_host *irq_find_host(struct device_node *node) -{ - struct irq_host *h, *found = NULL; - unsigned long flags; - - /* We might want to match the legacy controller last since - * it might potentially be set to match all interrupts in - * the absence of a device node. This isn't a problem so far - * yet though... - */ - raw_spin_lock_irqsave(&irq_big_lock, flags); - list_for_each_entry(h, &irq_hosts, link) - if (h->ops->match(h, node)) { - found = h; - break; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} -EXPORT_SYMBOL_GPL(irq_find_host); - -void irq_set_default_host(struct irq_host *host) -{ - pr_debug("irq: Default host set to @0x%p\n", host); - - irq_default_host = host; -} - -void irq_set_virq_count(unsigned int count) -{ - pr_debug("irq: Trying to set virq count to %d\n", count); - - BUG_ON(count < NUM_ISA_INTERRUPTS); - if (count < NR_IRQS) - irq_virq_count = count; -} - -static int irq_setup_virq(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - int res; - - res = irq_alloc_desc_at(virq, 0); - if (res != virq) { - pr_debug("irq: -> allocating desc failed\n"); - goto error; - } - - /* map it */ - smp_wmb(); - irq_map[virq].hwirq = hwirq; - smp_mb(); - - if (host->ops->map(host, virq, hwirq)) { - pr_debug("irq: -> mapping failed, freeing\n"); - goto errdesc; - } - - irq_clear_status_flags(virq, IRQ_NOREQUEST); - - return 0; - -errdesc: - irq_free_descs(virq, 1); -error: - irq_free_virt(virq, 1); - return -1; -} - -unsigned int irq_create_direct_mapping(struct irq_host *host) -{ - unsigned int virq; - - if (host == NULL) - host = irq_default_host; - - BUG_ON(host == NULL); - WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); - - virq = irq_alloc_virt(host, 1, 0); - if (virq == NO_IRQ) { - pr_debug("irq: create_direct virq allocation failed\n"); - return NO_IRQ; - } - - pr_debug("irq: create_direct obtained virq %d\n", virq); - - if (irq_setup_virq(host, virq, virq)) - return NO_IRQ; - - return virq; -} - -unsigned int irq_create_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int virq, hint; - - pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) { - printk(KERN_WARNING "irq_create_mapping called for" - " NULL host, hwirq=%lx\n", hwirq); - WARN_ON(1); - return NO_IRQ; - } - pr_debug("irq: -> using host @%p\n", host); - - /* Check if mapping already exists */ - virq = irq_find_mapping(host, hwirq); - if (virq != NO_IRQ) { - pr_debug("irq: -> existing mapping on virq %d\n", virq); - return virq; - } - - /* Get a virtual interrupt number */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) { - /* Handle legacy */ - virq = (unsigned int)hwirq; - if (virq == 0 || virq >= NUM_ISA_INTERRUPTS) - return NO_IRQ; - return virq; - } else { - /* Allocate a virtual interrupt number */ - hint = hwirq % irq_virq_count; - virq = irq_alloc_virt(host, 1, hint); - if (virq == NO_IRQ) { - pr_debug("irq: -> virq allocation failed\n"); - return NO_IRQ; - } - } - - if (irq_setup_virq(host, virq, hwirq)) - return NO_IRQ; - - pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", - hwirq, host->of_node ? host->of_node->full_name : "null", virq); - - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_mapping); - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - unsigned int type = IRQ_TYPE_NONE; - unsigned int virq; - - if (controller == NULL) - host = irq_default_host; - else - host = irq_find_host(controller); - if (host == NULL) { - printk(KERN_WARNING "irq: no irq host found for %s !\n", - controller->full_name); - return NO_IRQ; - } - - /* If host has no translation, then we assume interrupt line */ - if (host->ops->xlate == NULL) - hwirq = intspec[0]; - else { - if (host->ops->xlate(host, controller, intspec, intsize, - &hwirq, &type)) - return NO_IRQ; - } - - /* Create mapping */ - virq = irq_create_mapping(host, hwirq); - if (virq == NO_IRQ) - return virq; - - /* Set type if specified and different than the current one */ - if (type != IRQ_TYPE_NONE && - type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - -void irq_dispose_mapping(unsigned int virq) -{ - struct irq_host *host; - irq_hw_number_t hwirq; - - if (virq == NO_IRQ) - return; - - host = irq_map[virq].host; - if (WARN_ON(host == NULL)) - return; - - /* Never unmap legacy interrupts */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) - return; - - irq_set_status_flags(virq, IRQ_NOREQUEST); - - /* remove chip and handler */ - irq_set_chip_and_handler(virq, NULL, NULL); - - /* Make sure it's completed */ - synchronize_irq(virq); - - /* Tell the PIC about it */ - if (host->ops->unmap) - host->ops->unmap(host, virq); - smp_mb(); - - /* Clear reverse map */ - hwirq = irq_map[virq].hwirq; - switch(host->revmap_type) { - case IRQ_HOST_MAP_LINEAR: - if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = NO_IRQ; - break; - case IRQ_HOST_MAP_TREE: - mutex_lock(&revmap_trees_mutex); - radix_tree_delete(&host->revmap_data.tree, hwirq); - mutex_unlock(&revmap_trees_mutex); - break; - } - - /* Destroy map */ - smp_mb(); - irq_map[virq].hwirq = host->inval_irq; - - irq_free_descs(virq, 1); - /* Free it */ - irq_free_virt(virq, 1); -} -EXPORT_SYMBOL_GPL(irq_dispose_mapping); - -unsigned int irq_find_mapping(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int i; - unsigned int hint = hwirq % irq_virq_count; - - /* Look for default host if nececssary */ - if (host == NULL) - host = irq_default_host; - if (host == NULL) - return NO_IRQ; - - /* legacy -> bail early */ - if (host->revmap_type == IRQ_HOST_MAP_LEGACY) - return hwirq; - - /* Slow path does a linear search of the map */ - if (hint < NUM_ISA_INTERRUPTS) - hint = NUM_ISA_INTERRUPTS; - i = hint; - do { - if (irq_map[i].host == host && - irq_map[i].hwirq == hwirq) - return i; - i++; - if (i >= irq_virq_count) - i = NUM_ISA_INTERRUPTS; - } while(i != hint); - return NO_IRQ; -} -EXPORT_SYMBOL_GPL(irq_find_mapping); - #ifdef CONFIG_SMP int irq_choose_cpu(const struct cpumask *mask) { @@ -929,232 +539,11 @@ int irq_choose_cpu(const struct cpumask *mask) } #endif -unsigned int irq_radix_revmap_lookup(struct irq_host *host, - irq_hw_number_t hwirq) -{ - struct irq_map_entry *ptr; - unsigned int virq; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) - return irq_find_mapping(host, hwirq); - - /* - * The ptr returned references the static global irq_map. - * but freeing an irq can delete nodes along the path to - * do the lookup via call_rcu. - */ - rcu_read_lock(); - ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); - rcu_read_unlock(); - - /* - * If found in radix tree, then fine. - * Else fallback to linear lookup - this should not happen in practice - * as it means that we failed to insert the node in the radix tree. - */ - if (ptr) - virq = ptr - irq_map; - else - virq = irq_find_mapping(host, hwirq); - - return virq; -} - -void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, - irq_hw_number_t hwirq) -{ - if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) - return; - - if (virq != NO_IRQ) { - mutex_lock(&revmap_trees_mutex); - radix_tree_insert(&host->revmap_data.tree, hwirq, - &irq_map[virq]); - mutex_unlock(&revmap_trees_mutex); - } -} - -unsigned int irq_linear_revmap(struct irq_host *host, - irq_hw_number_t hwirq) -{ - unsigned int *revmap; - - if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) - return irq_find_mapping(host, hwirq); - - /* Check revmap bounds */ - if (unlikely(hwirq >= host->revmap_data.linear.size)) - return irq_find_mapping(host, hwirq); - - /* Check if revmap was allocated */ - revmap = host->revmap_data.linear.revmap; - if (unlikely(revmap == NULL)) - return irq_find_mapping(host, hwirq); - - /* Fill up revmap with slow path if no mapping found */ - if (unlikely(revmap[hwirq] == NO_IRQ)) - revmap[hwirq] = irq_find_mapping(host, hwirq); - - return revmap[hwirq]; -} - -unsigned int irq_alloc_virt(struct irq_host *host, - unsigned int count, - unsigned int hint) -{ - unsigned long flags; - unsigned int i, j, found = NO_IRQ; - - if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS)) - return NO_IRQ; - - raw_spin_lock_irqsave(&irq_big_lock, flags); - - /* Use hint for 1 interrupt if any */ - if (count == 1 && hint >= NUM_ISA_INTERRUPTS && - hint < irq_virq_count && irq_map[hint].host == NULL) { - found = hint; - goto hint_found; - } - - /* Look for count consecutive numbers in the allocatable - * (non-legacy) space - */ - for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) { - if (irq_map[i].host != NULL) - j = 0; - else - j++; - - if (j == count) { - found = i - count + 1; - break; - } - } - if (found == NO_IRQ) { - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return NO_IRQ; - } - hint_found: - for (i = found; i < (found + count); i++) { - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = host; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); - return found; -} - -void irq_free_virt(unsigned int virq, unsigned int count) -{ - unsigned long flags; - unsigned int i; - - WARN_ON (virq < NUM_ISA_INTERRUPTS); - WARN_ON (count == 0 || (virq + count) > irq_virq_count); - - if (virq < NUM_ISA_INTERRUPTS) { - if (virq + count < NUM_ISA_INTERRUPTS) - return; - count =- NUM_ISA_INTERRUPTS - virq; - virq = NUM_ISA_INTERRUPTS; - } - - if (count > irq_virq_count || virq > irq_virq_count - count) { - if (virq > irq_virq_count) - return; - count = irq_virq_count - virq; - } - - raw_spin_lock_irqsave(&irq_big_lock, flags); - for (i = virq; i < (virq + count); i++) { - struct irq_host *host; - - host = irq_map[i].host; - irq_map[i].hwirq = host->inval_irq; - smp_wmb(); - irq_map[i].host = NULL; - } - raw_spin_unlock_irqrestore(&irq_big_lock, flags); -} - int arch_early_irq_init(void) { return 0; } -#ifdef CONFIG_VIRQ_DEBUG -static int virq_debug_show(struct seq_file *m, void *private) -{ - unsigned long flags; - struct irq_desc *desc; - const char *p; - static const char none[] = "none"; - void *data; - int i; - - seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", - "chip name", "chip data", "host name"); - - for (i = 1; i < nr_irqs; i++) { - desc = irq_to_desc(i); - if (!desc) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - if (desc->action && desc->action->handler) { - struct irq_chip *chip; - - seq_printf(m, "%5d ", i); - seq_printf(m, "0x%05lx ", irq_map[i].hwirq); - - chip = irq_desc_get_chip(desc); - if (chip && chip->name) - p = chip->name; - else - p = none; - seq_printf(m, "%-15s ", p); - - data = irq_desc_get_chip_data(desc); - seq_printf(m, "0x%16p ", data); - - if (irq_map[i].host && irq_map[i].host->of_node) - p = irq_map[i].host->of_node->full_name; - else - p = none; - seq_printf(m, "%s\n", p); - } - - raw_spin_unlock_irqrestore(&desc->lock, flags); - } - - return 0; -} - -static int virq_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, virq_debug_show, inode->i_private); -} - -static const struct file_operations virq_debug_fops = { - .open = virq_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init irq_debugfs_init(void) -{ - if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, - NULL, &virq_debug_fops) == NULL) - return -ENOMEM; - - return 0; -} -__initcall(irq_debugfs_init); -#endif /* CONFIG_VIRQ_DEBUG */ - #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index e2cfb9e1e20e..220fcdf26978 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -227,14 +227,14 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) hpage_offset /= 4; get_page(hpage); - page = kmap_atomic(hpage, KM_USER0); + page = kmap_atomic(hpage); /* patch dcbz into reserved instruction, so we trap */ for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) if ((page[i] & 0xff0007ff) == INS_DCBZ) page[i] &= 0xfffffff7; - kunmap_atomic(page, KM_USER0); + kunmap_atomic(page); put_page(hpage); } diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c index 329be36c0a8d..6747eece84af 100644 --- a/arch/powerpc/mm/dma-noncoherent.c +++ b/arch/powerpc/mm/dma-noncoherent.c @@ -365,12 +365,11 @@ static inline void __dma_sync_page_highmem(struct page *page, local_irq_save(flags); do { - start = (unsigned long)kmap_atomic(page + seg_nr, - KM_PPC_SYNC_PAGE) + seg_offset; + start = (unsigned long)kmap_atomic(page + seg_nr) + seg_offset; /* Sync this buffer segment */ __dma_sync((void *)start, seg_size, direction); - kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); + kunmap_atomic((void *)start); seg_nr++; /* Calculate next buffer segment size */ diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index a8b3cc7d90fe..57c7465e656e 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -910,9 +910,9 @@ void flush_dcache_icache_hugepage(struct page *page) if (!PageHighMem(page)) { __flush_dcache_icache(page_address(page+i)); } else { - start = kmap_atomic(page+i, KM_PPC_SYNC_ICACHE); + start = kmap_atomic(page+i); __flush_dcache_icache(start); - kunmap_atomic(start, KM_PPC_SYNC_ICACHE); + kunmap_atomic(start); } } } diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index d974b79a3068..baaafde7d135 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -458,9 +458,9 @@ void flush_dcache_icache_page(struct page *page) #endif #ifdef CONFIG_BOOKE { - void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); + void *start = kmap_atomic(page); __flush_dcache_icache(start); - kunmap_atomic(start, KM_PPC_SYNC_ICACHE); + kunmap_atomic(start); } #elif defined(CONFIG_8xx) || defined(CONFIG_PPC64) /* On 8xx there is no need to kmap since highmem is not supported */ diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 9f09319352c0..ca3a062ed1b9 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -21,7 +21,7 @@ #include <asm/prom.h> static struct device_node *cpld_pic_node; -static struct irq_host *cpld_pic_host; +static struct irq_domain *cpld_pic_host; /* * Bits to ignore in the misc_status register @@ -123,13 +123,13 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) } static int -cpld_pic_host_match(struct irq_host *h, struct device_node *node) +cpld_pic_host_match(struct irq_domain *h, struct device_node *node) { return cpld_pic_node == node; } static int -cpld_pic_host_map(struct irq_host *h, unsigned int virq, +cpld_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_status_flags(virq, IRQ_LEVEL); @@ -137,8 +137,7 @@ cpld_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct -irq_host_ops cpld_pic_host_ops = { +static const struct irq_domain_ops cpld_pic_host_ops = { .match = cpld_pic_host_match, .map = cpld_pic_host_map, }; @@ -191,8 +190,7 @@ mpc5121_ads_cpld_pic_init(void) cpld_pic_node = of_node_get(np); - cpld_pic_host = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); + cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL); if (!cpld_pic_host) { printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n"); goto end; diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 96f85e5e0cd3..17d91b7da315 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -45,7 +45,7 @@ static struct of_device_id mpc5200_gpio_ids[] __initdata = { struct media5200_irq { void __iomem *regs; spinlock_t lock; - struct irq_host *irqhost; + struct irq_domain *irqhost; }; struct media5200_irq media5200_irq; @@ -112,7 +112,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc) raw_spin_unlock(&desc->lock); } -static int media5200_irq_map(struct irq_host *h, unsigned int virq, +static int media5200_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw); @@ -122,7 +122,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq, return 0; } -static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, +static int media5200_irq_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -136,7 +136,7 @@ static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops media5200_irq_ops = { +static const struct irq_domain_ops media5200_irq_ops = { .map = media5200_irq_map, .xlate = media5200_irq_xlate, }; @@ -173,15 +173,12 @@ static void __init media5200_init_irq(void) spin_lock_init(&media5200_irq.lock); - media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_HOST_MAP_LINEAR, - MEDIA5200_NUM_IRQS, - &media5200_irq_ops, -1); + media5200_irq.irqhost = irq_domain_add_linear(fpga_np, + MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq); if (!media5200_irq.irqhost) goto out; pr_debug("%s: allocated irqhost\n", __func__); - media5200_irq.irqhost->host_data = &media5200_irq; - irq_set_handler_data(cascade_virq, &media5200_irq); irq_set_chained_handler(cascade_virq, media5200_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index f94f06e52762..028470b95886 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c @@ -81,7 +81,7 @@ MODULE_LICENSE("GPL"); * @regs: virtual address of GPT registers * @lock: spinlock to coordinate between different functions. * @gc: gpio_chip instance structure; used when GPIO is enabled - * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported + * @irqhost: Pointer to irq_domain instance; used when IRQ mode is supported * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates * if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates * if the timer is actively used as wdt which blocks gpt functions @@ -91,7 +91,7 @@ struct mpc52xx_gpt_priv { struct device *dev; struct mpc52xx_gpt __iomem *regs; spinlock_t lock; - struct irq_host *irqhost; + struct irq_domain *irqhost; u32 ipb_freq; u8 wdt_mode; @@ -204,7 +204,7 @@ void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc) } } -static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_gpt_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct mpc52xx_gpt_priv *gpt = h->host_data; @@ -216,7 +216,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, return 0; } -static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_gpt_irq_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -236,7 +236,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops mpc52xx_gpt_irq_ops = { +static const struct irq_domain_ops mpc52xx_gpt_irq_ops = { .map = mpc52xx_gpt_irq_map, .xlate = mpc52xx_gpt_irq_xlate, }; @@ -252,14 +252,12 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) if (!cascade_virq) return; - gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, - &mpc52xx_gpt_irq_ops, -1); + gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt); if (!gpt->irqhost) { - dev_err(gpt->dev, "irq_alloc_host() failed\n"); + dev_err(gpt->dev, "irq_domain_add_linear() failed\n"); return; } - gpt->irqhost->host_data = gpt; irq_set_handler_data(cascade_virq, gpt); irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 1a9a49570579..8520b58a5e9a 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -132,7 +132,7 @@ static struct of_device_id mpc52xx_sdma_ids[] __initdata = { static struct mpc52xx_intr __iomem *intr; static struct mpc52xx_sdma __iomem *sdma; -static struct irq_host *mpc52xx_irqhost = NULL; +static struct irq_domain *mpc52xx_irqhost = NULL; static unsigned char mpc52xx_map_senses[4] = { IRQ_TYPE_LEVEL_HIGH, @@ -301,7 +301,7 @@ static int mpc52xx_is_extirq(int l1, int l2) /** * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property */ -static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, +static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -335,7 +335,7 @@ static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, /** * mpc52xx_irqhost_map - Hook to map from virq to an irq_chip structure */ -static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, +static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t irq) { int l1irq; @@ -384,7 +384,7 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops mpc52xx_irqhost_ops = { +static const struct irq_domain_ops mpc52xx_irqhost_ops = { .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; @@ -444,9 +444,9 @@ void __init mpc52xx_init_irq(void) * As last step, add an irq host to translate the real * hw irq information provided by the ofw to linux virq */ - mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, + mpc52xx_irqhost = irq_domain_add_linear(picnode, MPC52xx_IRQ_HIGHTESTHWIRQ, - &mpc52xx_irqhost_ops, -1); + &mpc52xx_irqhost_ops, NULL); if (!mpc52xx_irqhost) panic(__FILE__ ": Cannot allocate the IRQ host\n"); diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 8ccf9ed62fe2..328d221fd1c0 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c @@ -29,7 +29,7 @@ static DEFINE_RAW_SPINLOCK(pci_pic_lock); struct pq2ads_pci_pic { struct device_node *node; - struct irq_host *host; + struct irq_domain *host; struct { u32 stat; @@ -103,7 +103,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc) } } -static int pci_pic_host_map(struct irq_host *h, unsigned int virq, +static int pci_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_status_flags(virq, IRQ_LEVEL); @@ -112,14 +112,14 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops pci_pic_host_ops = { +static const struct irq_domain_ops pci_pic_host_ops = { .map = pci_pic_host_map, }; int __init pq2ads_pci_init_irq(void) { struct pq2ads_pci_pic *priv; - struct irq_host *host; + struct irq_domain *host; struct device_node *np; int ret = -ENODEV; int irq; @@ -156,17 +156,13 @@ int __init pq2ads_pci_init_irq(void) out_be32(&priv->regs->mask, ~0); mb(); - host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, NUM_IRQS, - &pci_pic_host_ops, NUM_IRQS); + host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv); if (!host) { ret = -ENOMEM; goto out_unmap_regs; } - host->host_data = priv; - priv->host = host; - host->host_data = priv; irq_set_handler_data(irq, priv); irq_set_chained_handler(irq, pq2ads_pci_irq_demux); diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 12cb9bb2cc68..3bbbf7489487 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c @@ -51,7 +51,7 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = { static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock); static void __iomem *socrates_fpga_pic_iobase; -static struct irq_host *socrates_fpga_pic_irq_host; +static struct irq_domain *socrates_fpga_pic_irq_host; static unsigned int socrates_fpga_irqs[3]; static inline uint32_t socrates_fpga_pic_read(int reg) @@ -227,7 +227,7 @@ static struct irq_chip socrates_fpga_pic_chip = { .irq_set_type = socrates_fpga_pic_set_type, }; -static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, +static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { /* All interrupts are LEVEL sensitive */ @@ -238,7 +238,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int socrates_fpga_pic_host_xlate(struct irq_host *h, +static int socrates_fpga_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -269,7 +269,7 @@ static int socrates_fpga_pic_host_xlate(struct irq_host *h, return 0; } -static struct irq_host_ops socrates_fpga_pic_host_ops = { +static const struct irq_domain_ops socrates_fpga_pic_host_ops = { .map = socrates_fpga_pic_host_map, .xlate = socrates_fpga_pic_host_xlate, }; @@ -279,10 +279,9 @@ void socrates_fpga_pic_init(struct device_node *pic) unsigned long flags; int i; - /* Setup an irq_host structure */ - socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR, - SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, - SOCRATES_FPGA_NUM_IRQS); + /* Setup an irq_domain structure */ + socrates_fpga_pic_irq_host = irq_domain_add_linear(pic, + SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL); if (socrates_fpga_pic_irq_host == NULL) { pr_err("FPGA PIC: Unable to allocate host\n"); return; diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 94594e58594c..af3fd697de82 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c @@ -50,7 +50,7 @@ static DEFINE_RAW_SPINLOCK(gef_pic_lock); static void __iomem *gef_pic_irq_reg_base; -static struct irq_host *gef_pic_irq_host; +static struct irq_domain *gef_pic_irq_host; static int gef_pic_cascade_irq; /* @@ -153,7 +153,7 @@ static struct irq_chip gef_pic_chip = { /* When an interrupt is being configured, this call allows some flexibilty * in deciding which irq_chip structure is used */ -static int gef_pic_host_map(struct irq_host *h, unsigned int virq, +static int gef_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { /* All interrupts are LEVEL sensitive */ @@ -163,7 +163,7 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -177,7 +177,7 @@ static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops gef_pic_host_ops = { +static const struct irq_domain_ops gef_pic_host_ops = { .map = gef_pic_host_map, .xlate = gef_pic_host_xlate, }; @@ -211,10 +211,9 @@ void __init gef_pic_init(struct device_node *np) return; } - /* Setup an irq_host structure */ - gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - GEF_PIC_NUM_IRQS, - &gef_pic_host_ops, NO_IRQ); + /* Setup an irq_domain structure */ + gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS, + &gef_pic_host_ops, NULL); if (gef_pic_irq_host == NULL) return; diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index ee56a9ea6a79..1fb0b3cddeb3 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig @@ -26,6 +26,7 @@ config MPC86XADS config MPC885ADS bool "MPC885ADS" select CPM1 + select OF_DYNAMIC help Freescale Semiconductor MPC885 Application Development System (ADS). Also known as DUET. diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 40a6e34793b4..db360fc4cf0e 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -67,7 +67,7 @@ struct axon_msic { - struct irq_host *irq_host; + struct irq_domain *irq_domain; __le32 *fifo_virt; dma_addr_t fifo_phys; dcr_host_t dcr_host; @@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) static struct axon_msic *find_msi_translator(struct pci_dev *dev) { - struct irq_host *irq_host; + struct irq_domain *irq_domain; struct device_node *dn, *tmp; const phandle *ph; struct axon_msic *msic = NULL; @@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) goto out_error; } - irq_host = irq_find_host(dn); - if (!irq_host) { - dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n", + irq_domain = irq_find_host(dn); + if (!irq_domain) { + dev_dbg(&dev->dev, "axon_msi: no irq_domain found for node %s\n", dn->full_name); goto out_error; } - msic = irq_host->host_data; + msic = irq_domain->host_data; out_error: of_node_put(dn); @@ -280,7 +280,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) BUILD_BUG_ON(NR_IRQS > 65536); list_for_each_entry(entry, &dev->msi_list, list) { - virq = irq_create_direct_mapping(msic->irq_host); + virq = irq_create_direct_mapping(msic->irq_domain); if (virq == NO_IRQ) { dev_warn(&dev->dev, "axon_msi: virq allocation failed!\n"); @@ -318,7 +318,7 @@ static struct irq_chip msic_irq_chip = { .name = "AXON-MSI", }; -static int msic_host_map(struct irq_host *h, unsigned int virq, +static int msic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_data(virq, h->host_data); @@ -327,7 +327,7 @@ static int msic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops msic_host_ops = { +static const struct irq_domain_ops msic_host_ops = { .map = msic_host_map, }; @@ -337,7 +337,7 @@ static void axon_msi_shutdown(struct platform_device *device) u32 tmp; pr_devel("axon_msi: disabling %s\n", - msic->irq_host->of_node->full_name); + msic->irq_domain->of_node->full_name); tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; msic_dcr_write(msic, MSIC_CTRL_REG, tmp); @@ -392,16 +392,13 @@ static int axon_msi_probe(struct platform_device *device) } memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES); - msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP, - NR_IRQS, &msic_host_ops, 0); - if (!msic->irq_host) { - printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", + msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic); + if (!msic->irq_domain) { + printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n", dn->full_name); goto out_free_fifo; } - msic->irq_host->host_data = msic; - irq_set_handler_data(virq, msic); irq_set_chained_handler(virq, axon_msi_cascade); pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq); diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 55015e1f6939..e5c3a2c6090d 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -34,7 +34,7 @@ static DEFINE_RAW_SPINLOCK(beatic_irq_mask_lock); static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64]; -static struct irq_host *beatic_host; +static struct irq_domain *beatic_host; /* * In this implementation, "virq" == "IRQ plug number", @@ -122,7 +122,7 @@ static struct irq_chip beatic_pic = { * * Note that the number (virq) is already assigned at upper layer. */ -static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) +static void beatic_pic_host_unmap(struct irq_domain *h, unsigned int virq) { beat_destruct_irq_plug(virq); } @@ -133,7 +133,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) * * Note that the number (virq) is already assigned at upper layer. */ -static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, +static int beatic_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { int64_t err; @@ -154,7 +154,7 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, * Called from irq_create_of_mapping() only. * Note: We have only 1 entry to translate. */ -static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int beatic_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -166,13 +166,13 @@ static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static int beatic_pic_host_match(struct irq_host *h, struct device_node *np) +static int beatic_pic_host_match(struct irq_domain *h, struct device_node *np) { /* Match all */ return 1; } -static struct irq_host_ops beatic_pic_host_ops = { +static const struct irq_domain_ops beatic_pic_host_ops = { .map = beatic_pic_host_map, .unmap = beatic_pic_host_unmap, .xlate = beatic_pic_host_xlate, @@ -239,9 +239,7 @@ void __init beatic_init_IRQ(void) ppc_md.get_irq = beatic_get_irq; /* Allocate an irq host */ - beatic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &beatic_pic_host_ops, - 0); + beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL); BUG_ON(beatic_host == NULL); irq_set_default_host(beatic_host); } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 96a433dd2d64..2d42f3bb66d6 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -56,7 +56,7 @@ struct iic { static DEFINE_PER_CPU(struct iic, cpu_iic); #define IIC_NODE_COUNT 2 -static struct irq_host *iic_host; +static struct irq_domain *iic_host; /* Convert between "pending" bits and hw irq number */ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) @@ -186,7 +186,7 @@ void iic_message_pass(int cpu, int msg) out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4); } -struct irq_host *iic_get_irq_host(int node) +struct irq_domain *iic_get_irq_host(int node) { return iic_host; } @@ -222,13 +222,13 @@ void iic_request_IPIs(void) #endif /* CONFIG_SMP */ -static int iic_host_match(struct irq_host *h, struct device_node *node) +static int iic_host_match(struct irq_domain *h, struct device_node *node) { return of_device_is_compatible(node, "IBM,CBEA-Internal-Interrupt-Controller"); } -static int iic_host_map(struct irq_host *h, unsigned int virq, +static int iic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { switch (hw & IIC_IRQ_TYPE_MASK) { @@ -245,7 +245,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int iic_host_xlate(struct irq_host *h, struct device_node *ct, +static int iic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -285,7 +285,7 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops iic_host_ops = { +static const struct irq_domain_ops iic_host_ops = { .match = iic_host_match, .map = iic_host_map, .xlate = iic_host_xlate, @@ -378,8 +378,8 @@ static int __init setup_iic(void) void __init iic_init_IRQ(void) { /* Setup an irq host data structure */ - iic_host = irq_alloc_host(NULL, IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, - &iic_host_ops, IIC_IRQ_INVALID); + iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops, + NULL); BUG_ON(iic_host == NULL); irq_set_default_host(iic_host); diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 442c28c00f88..d8b7cc8a66ca 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -62,7 +62,7 @@ enum { #define SPIDER_IRQ_INVALID 63 struct spider_pic { - struct irq_host *host; + struct irq_domain *host; void __iomem *regs; unsigned int node_id; }; @@ -168,7 +168,7 @@ static struct irq_chip spider_pic = { .irq_set_type = spider_set_irq_type, }; -static int spider_host_map(struct irq_host *h, unsigned int virq, +static int spider_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_data(virq, h->host_data); @@ -180,7 +180,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int spider_host_xlate(struct irq_host *h, struct device_node *ct, +static int spider_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -194,7 +194,7 @@ static int spider_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops spider_host_ops = { +static const struct irq_domain_ops spider_host_ops = { .map = spider_host_map, .xlate = spider_host_xlate, }; @@ -299,12 +299,10 @@ static void __init spider_init_one(struct device_node *of_node, int chip, panic("spider_pic: can't map registers !"); /* Allocate a host */ - pic->host = irq_alloc_host(of_node, IRQ_HOST_MAP_LINEAR, - SPIDER_SRC_COUNT, &spider_host_ops, - SPIDER_IRQ_INVALID); + pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT, + &spider_host_ops, pic); if (pic->host == NULL) panic("spider_pic: can't allocate irq host !"); - pic->host->host_data = pic; /* Go through all sources and disable them */ for (i = 0; i < SPIDER_SRC_COUNT; i++) { diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index f61a2dd96b99..53d6eee01963 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -96,9 +96,9 @@ static struct irq_chip flipper_pic = { * */ -static struct irq_host *flipper_irq_host; +static struct irq_domain *flipper_irq_host; -static int flipper_pic_map(struct irq_host *h, unsigned int virq, +static int flipper_pic_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { irq_set_chip_data(virq, h->host_data); @@ -107,13 +107,13 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static int flipper_pic_match(struct irq_host *h, struct device_node *np) +static int flipper_pic_match(struct irq_domain *h, struct device_node *np) { return 1; } -static struct irq_host_ops flipper_irq_host_ops = { +static const struct irq_domain_ops flipper_irq_domain_ops = { .map = flipper_pic_map, .match = flipper_pic_match, }; @@ -130,10 +130,10 @@ static void __flipper_quiesce(void __iomem *io_base) out_be32(io_base + FLIPPER_ICR, 0xffffffff); } -struct irq_host * __init flipper_pic_init(struct device_node *np) +struct irq_domain * __init flipper_pic_init(struct device_node *np) { struct device_node *pi; - struct irq_host *irq_host = NULL; + struct irq_domain *irq_domain = NULL; struct resource res; void __iomem *io_base; int retval; @@ -159,17 +159,15 @@ struct irq_host * __init flipper_pic_init(struct device_node *np) __flipper_quiesce(io_base); - irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, FLIPPER_NR_IRQS, - &flipper_irq_host_ops, -1); - if (!irq_host) { - pr_err("failed to allocate irq_host\n"); + irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS, + &flipper_irq_domain_ops, io_base); + if (!irq_domain) { + pr_err("failed to allocate irq_domain\n"); return NULL; } - irq_host->host_data = io_base; - out: - return irq_host; + return irq_domain; } unsigned int flipper_pic_get_irq(void) diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index e4919170c6bc..3006b5117ec6 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -89,9 +89,9 @@ static struct irq_chip hlwd_pic = { * */ -static struct irq_host *hlwd_irq_host; +static struct irq_domain *hlwd_irq_host; -static int hlwd_pic_map(struct irq_host *h, unsigned int virq, +static int hlwd_pic_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { irq_set_chip_data(virq, h->host_data); @@ -100,11 +100,11 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops hlwd_irq_host_ops = { +static const struct irq_domain_ops hlwd_irq_domain_ops = { .map = hlwd_pic_map, }; -static unsigned int __hlwd_pic_get_irq(struct irq_host *h) +static unsigned int __hlwd_pic_get_irq(struct irq_domain *h) { void __iomem *io_base = h->host_data; int irq; @@ -123,14 +123,14 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); - struct irq_host *irq_host = irq_get_handler_data(cascade_virq); + struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq); unsigned int virq; raw_spin_lock(&desc->lock); chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */ raw_spin_unlock(&desc->lock); - virq = __hlwd_pic_get_irq(irq_host); + virq = __hlwd_pic_get_irq(irq_domain); if (virq != NO_IRQ) generic_handle_irq(virq); else @@ -155,9 +155,9 @@ static void __hlwd_quiesce(void __iomem *io_base) out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff); } -struct irq_host *hlwd_pic_init(struct device_node *np) +struct irq_domain *hlwd_pic_init(struct device_node *np) { - struct irq_host *irq_host; + struct irq_domain *irq_domain; struct resource res; void __iomem *io_base; int retval; @@ -177,15 +177,14 @@ struct irq_host *hlwd_pic_init(struct device_node *np) __hlwd_quiesce(io_base); - irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, HLWD_NR_IRQS, - &hlwd_irq_host_ops, -1); - if (!irq_host) { - pr_err("failed to allocate irq_host\n"); + irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS, + &hlwd_irq_domain_ops, io_base); + if (!irq_domain) { + pr_err("failed to allocate irq_domain\n"); return NULL; } - irq_host->host_data = io_base; - return irq_host; + return irq_domain; } unsigned int hlwd_pic_get_irq(void) @@ -200,7 +199,7 @@ unsigned int hlwd_pic_get_irq(void) void hlwd_pic_probe(void) { - struct irq_host *host; + struct irq_domain *host; struct device_node *np; const u32 *interrupts; int cascade_virq; diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig index b57cda3a0817..63835e09e5cc 100644 --- a/arch/powerpc/platforms/iseries/Kconfig +++ b/arch/powerpc/platforms/iseries/Kconfig @@ -1,6 +1,7 @@ config PPC_ISERIES bool "IBM Legacy iSeries" depends on PPC64 && PPC_BOOK3S + select OF_DYNAMIC select PPC_SMP_MUXED_IPI select PPC_INDIRECT_PIO select PPC_INDIRECT_MMIO diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index b2103453eb01..05ce5164cafc 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -342,7 +342,7 @@ unsigned int iSeries_get_irq(void) #ifdef CONFIG_PCI -static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, +static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); @@ -350,13 +350,13 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int iseries_irq_host_match(struct irq_host *h, struct device_node *np) +static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np) { /* Match all */ return 1; } -static struct irq_host_ops iseries_irq_host_ops = { +static const struct irq_domain_ops iseries_irq_domain_ops = { .map = iseries_irq_host_map, .match = iseries_irq_host_match, }; @@ -368,7 +368,7 @@ static struct irq_host_ops iseries_irq_host_ops = { void __init iSeries_init_IRQ(void) { /* Register PCI event handler and open an event path */ - struct irq_host *host; + struct irq_domain *host; int ret; /* @@ -380,8 +380,7 @@ void __init iSeries_init_IRQ(void) /* Create irq host. No need for a revmap since HV will give us * back our virtual irq number */ - host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &iseries_irq_host_ops, 0); + host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL); BUG_ON(host == NULL); irq_set_default_host(host); diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 7761aabfc293..92afc382a49e 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -61,7 +61,7 @@ static DEFINE_RAW_SPINLOCK(pmac_pic_lock); static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; static int pmac_irq_cascade = -1; -static struct irq_host *pmac_pic_host; +static struct irq_domain *pmac_pic_host; static void __pmac_retrigger(unsigned int irq_nr) { @@ -268,13 +268,13 @@ static struct irqaction gatwick_cascade_action = { .name = "cascade", }; -static int pmac_pic_host_match(struct irq_host *h, struct device_node *node) +static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node) { /* We match all, we don't always have a node anyway */ return 1; } -static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, +static int pmac_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { if (hw >= max_irqs) @@ -288,21 +288,10 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, - unsigned int *out_flags) - -{ - *out_flags = IRQ_TYPE_NONE; - *out_hwirq = *intspec; - return 0; -} - -static struct irq_host_ops pmac_pic_host_ops = { +static const struct irq_domain_ops pmac_pic_host_ops = { .match = pmac_pic_host_match, .map = pmac_pic_host_map, - .xlate = pmac_pic_host_xlate, + .xlate = irq_domain_xlate_onecell, }; static void __init pmac_pic_probe_oldstyle(void) @@ -352,9 +341,8 @@ static void __init pmac_pic_probe_oldstyle(void) /* * Allocate an irq host */ - pmac_pic_host = irq_alloc_host(master, IRQ_HOST_MAP_LINEAR, max_irqs, - &pmac_pic_host_ops, - max_irqs); + pmac_pic_host = irq_domain_add_linear(master, max_irqs, + &pmac_pic_host_ops, NULL); BUG_ON(pmac_pic_host == NULL); irq_set_default_host(pmac_pic_host); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 44d769258ebf..a81e5a88fbdf 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -125,7 +125,7 @@ static volatile u32 __iomem *psurge_start; static int psurge_type = PSURGE_NONE; /* irq for secondary cpus to report */ -static struct irq_host *psurge_host; +static struct irq_domain *psurge_host; int psurge_secondary_virq; /* @@ -176,7 +176,7 @@ static void smp_psurge_cause_ipi(int cpu, unsigned long data) psurge_set_ipi(cpu); } -static int psurge_host_map(struct irq_host *h, unsigned int virq, +static int psurge_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq); @@ -184,7 +184,7 @@ static int psurge_host_map(struct irq_host *h, unsigned int virq, return 0; } -struct irq_host_ops psurge_host_ops = { +static const struct irq_domain_ops psurge_host_ops = { .map = psurge_host_map, }; @@ -192,8 +192,7 @@ static int psurge_secondary_ipi_init(void) { int rc = -ENOMEM; - psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, - &psurge_host_ops, 0); + psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL); if (psurge_host) psurge_secondary_virq = irq_create_direct_mapping(psurge_host); diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 617efa12a3a5..2a4ff86cc21f 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -667,7 +667,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, static void dump_bmp(struct ps3_private* pd) {}; #endif /* defined(DEBUG) */ -static int ps3_host_map(struct irq_host *h, unsigned int virq, +static int ps3_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, @@ -678,13 +678,13 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int ps3_host_match(struct irq_host *h, struct device_node *np) +static int ps3_host_match(struct irq_domain *h, struct device_node *np) { /* Match all */ return 1; } -static struct irq_host_ops ps3_host_ops = { +static const struct irq_domain_ops ps3_host_ops = { .map = ps3_host_map, .match = ps3_host_match, }; @@ -751,10 +751,9 @@ void __init ps3_init_IRQ(void) { int result; unsigned cpu; - struct irq_host *host; + struct irq_domain *host; - host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, - PS3_INVALID_OUTLET); + host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL); irq_set_default_host(host); irq_set_virq_count(PS3_PLUG_MAX + 1); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index 31f22c1f657d..f2556257bbdc 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -3,6 +3,7 @@ config PPC_PSERIES bool "IBM pSeries & new (POWER5-based) iSeries" select HAVE_PCSPKR_PLATFORM select MPIC + select OF_DYNAMIC select PCI_MSI select PPC_XICS select PPC_ICP_NATIVE diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig index 57d22a2f4ba9..79d2225b7608 100644 --- a/arch/powerpc/platforms/wsp/Kconfig +++ b/arch/powerpc/platforms/wsp/Kconfig @@ -25,6 +25,7 @@ config PPC_CHROMA bool "PowerEN PCIe Chroma Card" select EPAPR_BOOT select PPC_WSP + select OF_DYNAMIC default y endmenu diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c index 19f353dfcd03..cb565bf93650 100644 --- a/arch/powerpc/platforms/wsp/opb_pic.c +++ b/arch/powerpc/platforms/wsp/opb_pic.c @@ -30,7 +30,7 @@ static int opb_index = 0; struct opb_pic { - struct irq_host *host; + struct irq_domain *host; void *regs; int index; spinlock_t lock; @@ -179,7 +179,7 @@ static struct irq_chip opb_irq_chip = { .irq_set_type = opb_set_irq_type }; -static int opb_host_map(struct irq_host *host, unsigned int virq, +static int opb_host_map(struct irq_domain *host, unsigned int virq, irq_hw_number_t hwirq) { struct opb_pic *opb; @@ -196,20 +196,9 @@ static int opb_host_map(struct irq_host *host, unsigned int virq, return 0; } -static int opb_host_xlate(struct irq_host *host, struct device_node *dn, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ - /* Interrupt size must == 2 */ - BUG_ON(intsize != 2); - *out_hwirq = intspec[0]; - *out_type = intspec[1]; - return 0; -} - -static struct irq_host_ops opb_host_ops = { +static const struct irq_domain_ops opb_host_ops = { .map = opb_host_map, - .xlate = opb_host_xlate, + .xlate = irq_domain_xlate_twocell, }; irqreturn_t opb_irq_handler(int irq, void *private) @@ -263,13 +252,11 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn) goto free_opb; } - /* Allocate an irq host so that Linux knows that despite only + /* Allocate an irq domain so that Linux knows that despite only * having one interrupt to issue, we're the controller for multiple * hardware IRQs, so later we can lookup their virtual IRQs. */ - opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR, - OPB_NR_IRQS, &opb_host_ops, -1); - + opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb); if (!opb->host) { printk(KERN_ERR "opb: Failed to allocate IRQ host!\n"); goto free_regs; @@ -277,7 +264,6 @@ struct opb_pic *opb_pic_init_one(struct device_node *dn) opb->index = opb_index++; spin_lock_init(&opb->lock); - opb->host->host_data = opb; /* Disable all interrupts by default */ opb_out(opb, OPB_MLSASIER, 0); diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 5d7d59a43c4c..d4fa03f2b6ac 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c @@ -54,7 +54,7 @@ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ immap_t __iomem *mpc8xx_immr; static cpic8xx_t __iomem *cpic_reg; -static struct irq_host *cpm_pic_host; +static struct irq_domain *cpm_pic_host; static void cpm_mask_irq(struct irq_data *d) { @@ -98,7 +98,7 @@ int cpm_get_irq(void) return irq_linear_revmap(cpm_pic_host, cpm_vec); } -static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, +static int cpm_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -123,7 +123,7 @@ static struct irqaction cpm_error_irqaction = { .name = "error", }; -static struct irq_host_ops cpm_pic_host_ops = { +static const struct irq_domain_ops cpm_pic_host_ops = { .map = cpm_pic_host_map, }; @@ -164,8 +164,7 @@ unsigned int cpm_pic_init(void) out_be32(&cpic_reg->cpic_cimr, 0); - cpm_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - 64, &cpm_pic_host_ops, 64); + cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL); if (cpm_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); sirq = NO_IRQ; diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index bcab50e2a9eb..d3be961e2ae7 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c @@ -50,7 +50,7 @@ static intctl_cpm2_t __iomem *cpm2_intctl; -static struct irq_host *cpm2_pic_host; +static struct irq_domain *cpm2_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; @@ -214,7 +214,7 @@ unsigned int cpm2_get_irq(void) return irq_linear_revmap(cpm2_pic_host, irq); } -static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, +static int cpm2_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -224,21 +224,9 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) -{ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops cpm2_pic_host_ops = { +static const struct irq_domain_ops cpm2_pic_host_ops = { .map = cpm2_pic_host_map, - .xlate = cpm2_pic_host_xlate, + .xlate = irq_domain_xlate_onetwocell, }; void cpm2_pic_init(struct device_node *node) @@ -275,8 +263,7 @@ void cpm2_pic_init(struct device_node *node) out_be32(&cpm2_intctl->ic_scprrl, 0x05309770); /* create a legacy host */ - cpm2_pic_host = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - 64, &cpm2_pic_host_ops, 64); + cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL); if (cpm2_pic_host == NULL) { printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n"); return; diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index b6731e4a6646..6e0e1005227f 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -182,13 +182,13 @@ unsigned int ehv_pic_get_irq(void) return irq_linear_revmap(global_ehv_pic->irqhost, irq); } -static int ehv_pic_host_match(struct irq_host *h, struct device_node *node) +static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless ehv_pic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int ehv_pic_host_map(struct irq_host *h, unsigned int virq, +static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct ehv_pic *ehv_pic = h->host_data; @@ -217,7 +217,7 @@ static int ehv_pic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -248,7 +248,7 @@ static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops ehv_pic_host_ops = { +static const struct irq_domain_ops ehv_pic_host_ops = { .match = ehv_pic_host_match, .map = ehv_pic_host_map, .xlate = ehv_pic_host_xlate, @@ -275,9 +275,8 @@ void __init ehv_pic_init(void) return; } - ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0); - + ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS, + &ehv_pic_host_ops, ehv_pic); if (!ehv_pic->irqhost) { of_node_put(np); kfree(ehv_pic); @@ -293,7 +292,6 @@ void __init ehv_pic_init(void) of_node_put(np2); } - ehv_pic->irqhost->host_data = ehv_pic; ehv_pic->hc_irq = ehv_pic_irq_chip; ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity; ehv_pic->coreint_flag = coreint_flag; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index ecb5c1946d22..0c01debe963b 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -60,7 +60,7 @@ static struct irq_chip fsl_msi_chip = { .name = "FSL-MSI", }; -static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, +static int fsl_msi_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct fsl_msi *msi_data = h->host_data; @@ -74,7 +74,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops fsl_msi_host_ops = { +static const struct irq_domain_ops fsl_msi_host_ops = { .map = fsl_msi_host_map, }; @@ -387,8 +387,8 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) } platform_set_drvdata(dev, msi); - msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR, - NR_MSI_IRQS, &fsl_msi_host_ops, 0); + msi->irqhost = irq_domain_add_linear(dev->dev.of_node, + NR_MSI_IRQS, &fsl_msi_host_ops, msi); if (msi->irqhost == NULL) { dev_err(&dev->dev, "No memory for MSI irqhost\n"); @@ -420,8 +420,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) msi->feature = features->fsl_pic_ip; - msi->irqhost->host_data = msi; - /* * Remember the phandle, so that we can match with any PCI nodes * that have an "fsl,msi" property. diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h index f6c646a52541..8225f8653f78 100644 --- a/arch/powerpc/sysdev/fsl_msi.h +++ b/arch/powerpc/sysdev/fsl_msi.h @@ -26,7 +26,7 @@ #define FSL_PIC_IP_VMPIC 0x00000003 struct fsl_msi { - struct irq_host *irqhost; + struct irq_domain *irqhost; unsigned long cascade_irq; diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index d18bb27e4df9..997df6a7ab5d 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -25,7 +25,7 @@ static unsigned char cached_8259[2] = { 0xff, 0xff }; static DEFINE_RAW_SPINLOCK(i8259_lock); -static struct irq_host *i8259_host; +static struct irq_domain *i8259_host; /* * Acknowledge the IRQ using either the PCI host bridge's interrupt @@ -163,12 +163,12 @@ static struct resource pic_edgectrl_iores = { .flags = IORESOURCE_BUSY, }; -static int i8259_host_match(struct irq_host *h, struct device_node *node) +static int i8259_host_match(struct irq_domain *h, struct device_node *node) { return h->of_node == NULL || h->of_node == node; } -static int i8259_host_map(struct irq_host *h, unsigned int virq, +static int i8259_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("i8259_host_map(%d, 0x%lx)\n", virq, hw); @@ -185,7 +185,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, +static int i8259_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -205,13 +205,13 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops i8259_host_ops = { +static struct irq_domain_ops i8259_host_ops = { .match = i8259_host_match, .map = i8259_host_map, .xlate = i8259_host_xlate, }; -struct irq_host *i8259_get_host(void) +struct irq_domain *i8259_get_host(void) { return i8259_host; } @@ -263,8 +263,7 @@ void i8259_init(struct device_node *node, unsigned long intack_addr) raw_spin_unlock_irqrestore(&i8259_lock, flags); /* create a legacy host */ - i8259_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY, - 0, &i8259_host_ops, 0); + i8259_host = irq_domain_add_legacy_isa(node, &i8259_host_ops, NULL); if (i8259_host == NULL) { printk(KERN_ERR "i8259: failed to allocate irq host !\n"); return; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index 95da897f05a7..b50f97811c25 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -672,13 +672,13 @@ static struct irq_chip ipic_edge_irq_chip = { .irq_set_type = ipic_set_irq_type, }; -static int ipic_host_match(struct irq_host *h, struct device_node *node) +static int ipic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless ipic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int ipic_host_map(struct irq_host *h, unsigned int virq, +static int ipic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct ipic *ipic = h->host_data; @@ -692,26 +692,10 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) - -{ - /* interrupt sense values coming from the device tree equal either - * LEVEL_LOW (low assertion) or EDGE_FALLING (high-to-low change) - */ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops ipic_host_ops = { +static struct irq_domain_ops ipic_host_ops = { .match = ipic_host_match, .map = ipic_host_map, - .xlate = ipic_host_xlate, + .xlate = irq_domain_xlate_onetwocell, }; struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) @@ -728,9 +712,8 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) if (ipic == NULL) return NULL; - ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - NR_IPIC_INTS, - &ipic_host_ops, 0); + ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS, + &ipic_host_ops, ipic); if (ipic->irqhost == NULL) { kfree(ipic); return NULL; @@ -738,8 +721,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) ipic->regs = ioremap(res.start, resource_size(&res)); - ipic->irqhost->host_data = ipic; - /* init hw */ ipic_write(ipic->regs, IPIC_SICNR, 0x0); diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h index 9391c57b0c51..90031d1282e1 100644 --- a/arch/powerpc/sysdev/ipic.h +++ b/arch/powerpc/sysdev/ipic.h @@ -43,7 +43,7 @@ struct ipic { volatile u32 __iomem *regs; /* The remapper for this IPIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; }; struct ipic_info { diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 2ca0a85fcce9..d5f5416be310 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -17,7 +17,7 @@ extern int cpm_get_irq(struct pt_regs *regs); -static struct irq_host *mpc8xx_pic_host; +static struct irq_domain *mpc8xx_pic_host; #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; static sysconf8xx_t __iomem *siu_reg; @@ -110,7 +110,7 @@ unsigned int mpc8xx_get_irq(void) } -static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, +static int mpc8xx_pic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw); @@ -121,7 +121,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, } -static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpc8xx_pic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -142,7 +142,7 @@ static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, } -static struct irq_host_ops mpc8xx_pic_host_ops = { +static struct irq_domain_ops mpc8xx_pic_host_ops = { .map = mpc8xx_pic_host_map, .xlate = mpc8xx_pic_host_xlate, }; @@ -171,8 +171,7 @@ int mpc8xx_pic_init(void) goto out; } - mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - 64, &mpc8xx_pic_host_ops, 64); + mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL); if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret = -ENOMEM; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 4e9ccb1015de..c83a512fa175 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -965,13 +965,13 @@ static struct irq_chip mpic_irq_ht_chip = { #endif /* CONFIG_MPIC_U3_HT_IRQS */ -static int mpic_host_match(struct irq_host *h, struct device_node *node) +static int mpic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless mpic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int mpic_host_map(struct irq_host *h, unsigned int virq, +static int mpic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct mpic *mpic = h->host_data; @@ -1041,7 +1041,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, +static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -1121,13 +1121,13 @@ static void mpic_cascade(unsigned int irq, struct irq_desc *desc) BUG_ON(!(mpic->flags & MPIC_SECONDARY)); virq = mpic_get_one_irq(mpic); - if (virq != NO_IRQ) + if (virq) generic_handle_irq(virq); chip->irq_eoi(&desc->irq_data); } -static struct irq_host_ops mpic_host_ops = { +static struct irq_domain_ops mpic_host_ops = { .match = mpic_host_match, .map = mpic_host_map, .xlate = mpic_host_xlate, @@ -1345,10 +1345,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); mpic->isu_mask = (1 << mpic->isu_shift) - 1; - mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR, + mpic->irqhost = irq_domain_add_linear(mpic->node, isu_size ? isu_size : mpic->num_sources, - &mpic_host_ops, - flags & MPIC_LARGE_VECTORS ? 2048 : 256); + &mpic_host_ops, mpic); /* * FIXME: The code leaks the MPIC object and mappings here; this @@ -1357,8 +1356,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, if (mpic->irqhost == NULL) return NULL; - mpic->irqhost->host_data = mpic; - /* Display version */ switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) { case 1: diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 0f67cd79d481..0622aa91b18a 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c @@ -32,7 +32,7 @@ void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq) static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) { irq_hw_number_t hwirq; - struct irq_host_ops *ops = mpic->irqhost->ops; + const struct irq_domain_ops *ops = mpic->irqhost->ops; struct device_node *np; int flags, index, i; struct of_irq oirq; diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 14d130268e7a..8848e99a83f2 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c @@ -70,7 +70,7 @@ static u32 mv64x60_cached_low_mask; static u32 mv64x60_cached_high_mask = MV64X60_HIGH_GPP_GROUPS; static u32 mv64x60_cached_gpp_mask; -static struct irq_host *mv64x60_irq_host; +static struct irq_domain *mv64x60_irq_host; /* * mv64x60_chip_low functions @@ -208,7 +208,7 @@ static struct irq_chip *mv64x60_chips[] = { [MV64x60_LEVEL1_GPP] = &mv64x60_chip_gpp, }; -static int mv64x60_host_map(struct irq_host *h, unsigned int virq, +static int mv64x60_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hwirq) { int level1; @@ -223,7 +223,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops mv64x60_host_ops = { +static struct irq_domain_ops mv64x60_host_ops = { .map = mv64x60_host_map, }; @@ -250,9 +250,8 @@ void __init mv64x60_init_irq(void) paddr = of_translate_address(np, reg); mv64x60_irq_reg_base = ioremap(paddr, reg[1]); - mv64x60_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - MV64x60_NUM_IRQS, - &mv64x60_host_ops, MV64x60_NUM_IRQS); + mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS, + &mv64x60_host_ops, NULL); spin_lock_irqsave(&mv64x60_lock, flags); out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK, diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 73034bd203c4..2fba6ef2f95e 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -245,13 +245,13 @@ static struct irq_chip qe_ic_irq_chip = { .irq_mask_ack = qe_ic_mask_irq, }; -static int qe_ic_host_match(struct irq_host *h, struct device_node *node) +static int qe_ic_host_match(struct irq_domain *h, struct device_node *node) { /* Exact match, unless qe_ic node is NULL */ return h->of_node == NULL || h->of_node == node; } -static int qe_ic_host_map(struct irq_host *h, unsigned int virq, +static int qe_ic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct qe_ic *qe_ic = h->host_data; @@ -272,23 +272,10 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 * intspec, unsigned int intsize, - irq_hw_number_t * out_hwirq, - unsigned int *out_flags) -{ - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_NONE; - return 0; -} - -static struct irq_host_ops qe_ic_host_ops = { +static struct irq_domain_ops qe_ic_host_ops = { .match = qe_ic_host_match, .map = qe_ic_host_map, - .xlate = qe_ic_host_xlate, + .xlate = irq_domain_xlate_onetwocell, }; /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ @@ -339,8 +326,8 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, if (qe_ic == NULL) return; - qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - NR_QE_IC_INTS, &qe_ic_host_ops, 0); + qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, + &qe_ic_host_ops, qe_ic); if (qe_ic->irqhost == NULL) { kfree(qe_ic); return; @@ -348,7 +335,6 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, qe_ic->regs = ioremap(res.start, resource_size(&res)); - qe_ic->irqhost->host_data = qe_ic; qe_ic->hc_irq = qe_ic_irq_chip; qe_ic->virq_high = irq_of_parse_and_map(node, 0); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h index c1361d005a8a..c327872ed35c 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.h +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h @@ -79,7 +79,7 @@ struct qe_ic { volatile u32 __iomem *regs; /* The remapper for this QEIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; /* The "linux" controller struct */ struct irq_chip hc_irq; diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 4d18658116e5..188012c58f7f 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -51,7 +51,7 @@ u32 tsi108_pci_cfg_base; static u32 tsi108_pci_cfg_phys; u32 tsi108_csr_vir_base; -static struct irq_host *pci_irq_host; +static struct irq_domain *pci_irq_host; extern u32 get_vir_csrbase(void); extern u32 tsi108_read_reg(u32 reg_offset); @@ -376,7 +376,7 @@ static struct irq_chip tsi108_pci_irq = { .irq_unmask = tsi108_pci_irq_unmask, }; -static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, +static int pci_irq_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) { @@ -385,7 +385,7 @@ static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static int pci_irq_host_map(struct irq_host *h, unsigned int virq, +static int pci_irq_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { unsigned int irq; DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); @@ -397,7 +397,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops pci_irq_host_ops = { +static struct irq_domain_ops pci_irq_domain_ops = { .map = pci_irq_host_map, .xlate = pci_irq_host_xlate, }; @@ -419,10 +419,9 @@ void __init tsi108_pci_int_init(struct device_node *node) { DBG("Tsi108_pci_int_init: initializing PCI interrupts\n"); - pci_irq_host = irq_alloc_host(node, IRQ_HOST_MAP_LEGACY, - 0, &pci_irq_host_ops, 0); + pci_irq_host = irq_domain_add_legacy_isa(node, &pci_irq_domain_ops, NULL); if (pci_irq_host == NULL) { - printk(KERN_ERR "pci_irq_host: failed to allocate irq host !\n"); + printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n"); return; } diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 063c901b1265..92033936a8f7 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -49,7 +49,7 @@ struct uic { raw_spinlock_t lock; /* The remapper for this UIC */ - struct irq_host *irqhost; + struct irq_domain *irqhost; }; static void uic_unmask_irq(struct irq_data *d) @@ -174,7 +174,7 @@ static struct irq_chip uic_irq_chip = { .irq_set_type = uic_set_irq_type, }; -static int uic_host_map(struct irq_host *h, unsigned int virq, +static int uic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct uic *uic = h->host_data; @@ -190,21 +190,9 @@ static int uic_host_map(struct irq_host *h, unsigned int virq, return 0; } -static int uic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) - -{ - /* UIC intspecs must have 2 cells */ - BUG_ON(intsize != 2); - *out_hwirq = intspec[0]; - *out_type = intspec[1]; - return 0; -} - -static struct irq_host_ops uic_host_ops = { +static struct irq_domain_ops uic_host_ops = { .map = uic_host_map, - .xlate = uic_host_xlate, + .xlate = irq_domain_xlate_twocell, }; void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) @@ -270,13 +258,11 @@ static struct uic * __init uic_init_one(struct device_node *node) } uic->dcrbase = *dcrreg; - uic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, - NR_UIC_INTS, &uic_host_ops, -1); + uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops, + uic); if (! uic->irqhost) return NULL; /* FIXME: panic? */ - uic->irqhost->host_data = uic; - /* Start with all interrupts disabled, level and non-critical */ mtdcr(uic->dcrbase + UIC_ER, 0); mtdcr(uic->dcrbase + UIC_CR, 0); diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index d72eda6a4c05..ea5e204e3450 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -40,7 +40,7 @@ unsigned int xics_interrupt_server_size = 8; DEFINE_PER_CPU(struct xics_cppr, xics_cppr); -struct irq_host *xics_host; +struct irq_domain *xics_host; static LIST_HEAD(ics_list); @@ -212,16 +212,16 @@ void xics_migrate_irqs_away(void) /* We can't set affinity on ISA interrupts */ if (virq < NUM_ISA_INTERRUPTS) continue; - if (!virq_is_host(virq, xics_host)) - continue; - irq = (unsigned int)virq_to_hw(virq); - /* We need to get IPIs still. */ - if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) - continue; desc = irq_to_desc(virq); /* We only need to migrate enabled IRQS */ if (!desc || !desc->action) continue; + if (desc->irq_data.domain != xics_host) + continue; + irq = desc->irq_data.hwirq; + /* We need to get IPIs still. */ + if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) + continue; chip = irq_desc_get_chip(desc); if (!chip || !chip->irq_set_affinity) continue; @@ -301,7 +301,7 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, } #endif /* CONFIG_SMP */ -static int xics_host_match(struct irq_host *h, struct device_node *node) +static int xics_host_match(struct irq_domain *h, struct device_node *node) { struct ics *ics; @@ -323,7 +323,7 @@ static struct irq_chip xics_ipi_chip = { .irq_unmask = xics_ipi_unmask, }; -static int xics_host_map(struct irq_host *h, unsigned int virq, +static int xics_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct ics *ics; @@ -351,7 +351,7 @@ static int xics_host_map(struct irq_host *h, unsigned int virq, return -EINVAL; } -static int xics_host_xlate(struct irq_host *h, struct device_node *ct, +static int xics_host_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -366,7 +366,7 @@ static int xics_host_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static struct irq_host_ops xics_host_ops = { +static struct irq_domain_ops xics_host_ops = { .match = xics_host_match, .map = xics_host_map, .xlate = xics_host_xlate, @@ -374,8 +374,7 @@ static struct irq_host_ops xics_host_ops = { static void __init xics_init_host(void) { - xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops, - XICS_IRQ_SPURIOUS); + xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL); BUG_ON(xics_host == NULL); irq_set_default_host(xics_host); } diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 6183799754af..8d73c3c0bee6 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -40,7 +40,7 @@ #define XINTC_IVR 24 /* Interrupt Vector */ #define XINTC_MER 28 /* Master Enable */ -static struct irq_host *master_irqhost; +static struct irq_domain *master_irqhost; #define XILINX_INTC_MAXIRQS (32) @@ -141,7 +141,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = { /** * xilinx_intc_xlate - translate virq# from device tree interrupts property */ -static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, +static int xilinx_intc_xlate(struct irq_domain *h, struct device_node *ct, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_flags) @@ -161,7 +161,7 @@ static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, return 0; } -static int xilinx_intc_map(struct irq_host *h, unsigned int virq, +static int xilinx_intc_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t irq) { irq_set_chip_data(virq, h->host_data); @@ -177,15 +177,15 @@ static int xilinx_intc_map(struct irq_host *h, unsigned int virq, return 0; } -static struct irq_host_ops xilinx_intc_ops = { +static struct irq_domain_ops xilinx_intc_ops = { .map = xilinx_intc_map, .xlate = xilinx_intc_xlate, }; -struct irq_host * __init +struct irq_domain * __init xilinx_intc_init(struct device_node *np) { - struct irq_host * irq; + struct irq_domain * irq; void * regs; /* Find and map the intc registers */ @@ -200,12 +200,11 @@ xilinx_intc_init(struct device_node *np) out_be32(regs + XINTC_IAR, ~(u32) 0); /* Acknowledge pending irqs */ out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */ - /* Allocate and initialize an irq_host structure. */ - irq = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, XILINX_INTC_MAXIRQS, - &xilinx_intc_ops, -1); + /* Allocate and initialize an irq_domain structure. */ + irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops, + regs); if (!irq) panic(__FILE__ ": Cannot allocate IRQ host\n"); - irq->host_data = regs; return irq; } diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 92eb98633ab0..112fea12522a 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c @@ -244,7 +244,7 @@ static void sh4_flush_cache_page(void *args) if (map_coherent) vaddr = kmap_coherent(page, address); else - vaddr = kmap_atomic(page, KM_USER0); + vaddr = kmap_atomic(page); address = (unsigned long)vaddr; } @@ -259,7 +259,7 @@ static void sh4_flush_cache_page(void *args) if (map_coherent) kunmap_coherent(vaddr); else - kunmap_atomic(vaddr, KM_USER0); + kunmap_atomic(vaddr); } } diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 5a580ea04429..616966a96cba 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c @@ -95,7 +95,7 @@ void copy_user_highpage(struct page *to, struct page *from, { void *vfrom, *vto; - vto = kmap_atomic(to, KM_USER1); + vto = kmap_atomic(to); if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && test_bit(PG_dcache_clean, &from->flags)) { @@ -103,16 +103,16 @@ void copy_user_highpage(struct page *to, struct page *from, copy_page(vto, vfrom); kunmap_coherent(vfrom); } else { - vfrom = kmap_atomic(from, KM_USER0); + vfrom = kmap_atomic(from); copy_page(vto, vfrom); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); } if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK) || (vma->vm_flags & VM_EXEC)) __flush_purge_region(vto, PAGE_SIZE); - kunmap_atomic(vto, KM_USER1); + kunmap_atomic(vto); /* Make sure this page is cleared on other CPU's too before using it */ smp_wmb(); } @@ -120,14 +120,14 @@ EXPORT_SYMBOL(copy_user_highpage); void clear_user_highpage(struct page *page, unsigned long vaddr) { - void *kaddr = kmap_atomic(page, KM_USER0); + void *kaddr = kmap_atomic(page); clear_page(kaddr); if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) __flush_purge_region(kaddr, PAGE_SIZE); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } EXPORT_SYMBOL(clear_user_highpage); diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h index 3d7afbb7f4bb..3b6e00dd96e5 100644 --- a/arch/sparc/include/asm/highmem.h +++ b/arch/sparc/include/asm/highmem.h @@ -70,7 +70,7 @@ static inline void kunmap(struct page *page) kunmap_high(page); } -extern void *__kmap_atomic(struct page *page); +extern void *kmap_atomic(struct page *page); extern void __kunmap_atomic(void *kvaddr); extern struct page *kmap_atomic_to_page(void *vaddr); diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h index edd3d3cde460..c28765110706 100644 --- a/arch/sparc/include/asm/prom.h +++ b/arch/sparc/include/asm/prom.h @@ -22,6 +22,7 @@ #include <linux/proc_fs.h> #include <linux/mutex.h> #include <linux/atomic.h> +#include <linux/irqdomain.h> #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2 #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 @@ -55,15 +56,6 @@ struct resource; extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size); -/* These routines are here to provide compatibility with how powerpc - * handles IRQ mapping for OF device nodes. We precompute and permanently - * register them in the platform_device objects, whereas powerpc computes them - * on request. - */ -static inline void irq_dispose_mapping(unsigned int virq) -{ -} - extern struct device_node *of_console_device; extern char *of_console_path; extern char *of_console_options; diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c index 77140a02c86a..055c66cf1bf4 100644 --- a/arch/sparc/mm/highmem.c +++ b/arch/sparc/mm/highmem.c @@ -30,7 +30,7 @@ #include <asm/tlbflush.h> #include <asm/fixmap.h> -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { unsigned long vaddr; long idx, type; @@ -64,7 +64,7 @@ void *__kmap_atomic(struct page *page) return (void*) vaddr; } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/tile/include/asm/highmem.h b/arch/tile/include/asm/highmem.h index b2a6c5de79ab..fc8429a31c85 100644 --- a/arch/tile/include/asm/highmem.h +++ b/arch/tile/include/asm/highmem.h @@ -59,7 +59,7 @@ void *kmap_fix_kpte(struct page *page, int finished); /* This macro is used only in map_new_virtual() to map "page". */ #define kmap_prot page_to_kpgprot(page) -void *__kmap_atomic(struct page *page); +void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 31dbbd9afe47..ef8e5a62b6e3 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c @@ -224,12 +224,12 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { /* PAGE_NONE is a magic value that tells us to check immutability. */ return kmap_atomic_prot(page, PAGE_NONE); } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); void __kunmap_atomic(void *kvaddr) { diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 9fefd924fb49..cd7df79c6a56 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -69,7 +69,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, return -1; page = pte_page(*pte); - addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + + addr = (unsigned long) kmap_atomic(page) + (addr & ~PAGE_MASK); current->thread.fault_catcher = &buf; @@ -82,7 +82,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, current->thread.fault_catcher = NULL; - kunmap_atomic((void *)addr, KM_UML_USERCOPY); + kunmap_atomic((void *)addr); return n; } diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d523a6c36835..6c29256a71a6 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -402,6 +402,7 @@ config X86_INTEL_CE select X86_REBOOTFIXUPS select OF select OF_EARLY_FLATTREE + select IRQ_DOMAIN ---help--- Select for the Intel CE media processor (CE4100) SOC. This option compiles in support for the CE4100 SOC for settop @@ -2080,6 +2081,7 @@ config OLPC select GPIOLIB select OF select OF_PROMTREE + select IRQ_DOMAIN ---help--- Add support for detecting the unique features of the OLPC XO hardware. diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 2b0b9631474b..e191ac048b59 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o +obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o @@ -25,6 +26,7 @@ salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o +camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index b3350bd32c60..c799352e24fc 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -1108,12 +1108,12 @@ static int __driver_rfc4106_encrypt(struct aead_request *req) one_entry_in_sg = 1; scatterwalk_start(&src_sg_walk, req->src); scatterwalk_start(&assoc_sg_walk, req->assoc); - src = scatterwalk_map(&src_sg_walk, 0); - assoc = scatterwalk_map(&assoc_sg_walk, 0); + src = scatterwalk_map(&src_sg_walk); + assoc = scatterwalk_map(&assoc_sg_walk); dst = src; if (unlikely(req->src != req->dst)) { scatterwalk_start(&dst_sg_walk, req->dst); - dst = scatterwalk_map(&dst_sg_walk, 0); + dst = scatterwalk_map(&dst_sg_walk); } } else { @@ -1137,11 +1137,11 @@ static int __driver_rfc4106_encrypt(struct aead_request *req) * back to the packet. */ if (one_entry_in_sg) { if (unlikely(req->src != req->dst)) { - scatterwalk_unmap(dst, 0); + scatterwalk_unmap(dst); scatterwalk_done(&dst_sg_walk, 0, 0); } - scatterwalk_unmap(src, 0); - scatterwalk_unmap(assoc, 0); + scatterwalk_unmap(src); + scatterwalk_unmap(assoc); scatterwalk_done(&src_sg_walk, 0, 0); scatterwalk_done(&assoc_sg_walk, 0, 0); } else { @@ -1190,12 +1190,12 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) one_entry_in_sg = 1; scatterwalk_start(&src_sg_walk, req->src); scatterwalk_start(&assoc_sg_walk, req->assoc); - src = scatterwalk_map(&src_sg_walk, 0); - assoc = scatterwalk_map(&assoc_sg_walk, 0); + src = scatterwalk_map(&src_sg_walk); + assoc = scatterwalk_map(&assoc_sg_walk); dst = src; if (unlikely(req->src != req->dst)) { scatterwalk_start(&dst_sg_walk, req->dst); - dst = scatterwalk_map(&dst_sg_walk, 0); + dst = scatterwalk_map(&dst_sg_walk); } } else { @@ -1220,11 +1220,11 @@ static int __driver_rfc4106_decrypt(struct aead_request *req) if (one_entry_in_sg) { if (unlikely(req->src != req->dst)) { - scatterwalk_unmap(dst, 0); + scatterwalk_unmap(dst); scatterwalk_done(&dst_sg_walk, 0, 0); } - scatterwalk_unmap(src, 0); - scatterwalk_unmap(assoc, 0); + scatterwalk_unmap(src); + scatterwalk_unmap(assoc); scatterwalk_done(&src_sg_walk, 0, 0); scatterwalk_done(&assoc_sg_walk, 0, 0); } else { diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c index b05aa163d55a..7967474de8f7 100644 --- a/arch/x86/crypto/blowfish_glue.c +++ b/arch/x86/crypto/blowfish_glue.c @@ -25,6 +25,7 @@ * */ +#include <asm/processor.h> #include <crypto/blowfish.h> #include <linux/crypto.h> #include <linux/init.h> @@ -76,27 +77,6 @@ static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); } -static struct crypto_alg bf_alg = { - .cra_name = "blowfish", - .cra_driver_name = "blowfish-asm", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = BF_MIN_KEY_SIZE, - .cia_max_keysize = BF_MAX_KEY_SIZE, - .cia_setkey = blowfish_setkey, - .cia_encrypt = blowfish_encrypt, - .cia_decrypt = blowfish_decrypt, - } - } -}; - static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, void (*fn)(struct bf_ctx *, u8 *, const u8 *), void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) @@ -160,28 +140,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way); } -static struct crypto_alg blk_ecb_alg = { - .cra_name = "ecb(blowfish)", - .cra_driver_name = "ecb-blowfish-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = BF_MIN_KEY_SIZE, - .max_keysize = BF_MAX_KEY_SIZE, - .setkey = blowfish_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}; - static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -307,29 +265,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_cbc_alg = { - .cra_name = "cbc(blowfish)", - .cra_driver_name = "cbc-blowfish-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = BF_MIN_KEY_SIZE, - .max_keysize = BF_MAX_KEY_SIZE, - .ivsize = BF_BLOCK_SIZE, - .setkey = blowfish_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}; - static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk) { u8 *ctrblk = walk->iv; @@ -423,7 +358,67 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { +static struct crypto_alg bf_algs[4] = { { + .cra_name = "blowfish", + .cra_driver_name = "blowfish-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_algs[0].cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = BF_MIN_KEY_SIZE, + .cia_max_keysize = BF_MAX_KEY_SIZE, + .cia_setkey = blowfish_setkey, + .cia_encrypt = blowfish_encrypt, + .cia_decrypt = blowfish_decrypt, + } + } +}, { + .cra_name = "ecb(blowfish)", + .cra_driver_name = "ecb-blowfish-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = BF_MIN_KEY_SIZE, + .max_keysize = BF_MAX_KEY_SIZE, + .setkey = blowfish_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "cbc(blowfish)", + .cra_driver_name = "cbc-blowfish-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = BF_MIN_KEY_SIZE, + .max_keysize = BF_MAX_KEY_SIZE, + .ivsize = BF_BLOCK_SIZE, + .setkey = blowfish_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { .cra_name = "ctr(blowfish)", .cra_driver_name = "ctr-blowfish-asm", .cra_priority = 300, @@ -433,7 +428,7 @@ static struct crypto_alg blk_ctr_alg = { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), + .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, @@ -444,43 +439,45 @@ static struct crypto_alg blk_ctr_alg = { .decrypt = ctr_crypt, }, }, -}; +} }; + +static bool is_blacklisted_cpu(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return false; + + if (boot_cpu_data.x86 == 0x0f) { + /* + * On Pentium 4, blowfish-x86_64 is slower than generic C + * implementation because use of 64bit rotates (which are really + * slow on P4). Therefore blacklist P4s. + */ + return true; + } + + return false; +} + +static int force; +module_param(force, int, 0); +MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); static int __init init(void) { - int err; + if (!force && is_blacklisted_cpu()) { + printk(KERN_INFO + "blowfish-x86_64: performance on this CPU " + "would be suboptimal: disabling " + "blowfish-x86_64.\n"); + return -ENODEV; + } - err = crypto_register_alg(&bf_alg); - if (err) - goto bf_err; - err = crypto_register_alg(&blk_ecb_alg); - if (err) - goto ecb_err; - err = crypto_register_alg(&blk_cbc_alg); - if (err) - goto cbc_err; - err = crypto_register_alg(&blk_ctr_alg); - if (err) - goto ctr_err; - - return 0; - -ctr_err: - crypto_unregister_alg(&blk_cbc_alg); -cbc_err: - crypto_unregister_alg(&blk_ecb_alg); -ecb_err: - crypto_unregister_alg(&bf_alg); -bf_err: - return err; + return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs)); } static void __exit fini(void) { - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); - crypto_unregister_alg(&bf_alg); + crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs)); } module_init(init); diff --git a/arch/x86/crypto/camellia-x86_64-asm_64.S b/arch/x86/crypto/camellia-x86_64-asm_64.S new file mode 100644 index 000000000000..0b3374335fdc --- /dev/null +++ b/arch/x86/crypto/camellia-x86_64-asm_64.S @@ -0,0 +1,520 @@ +/* + * Camellia Cipher Algorithm (x86_64) + * + * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +.file "camellia-x86_64-asm_64.S" +.text + +.extern camellia_sp10011110; +.extern camellia_sp22000222; +.extern camellia_sp03303033; +.extern camellia_sp00444404; +.extern camellia_sp02220222; +.extern camellia_sp30333033; +.extern camellia_sp44044404; +.extern camellia_sp11101110; + +#define sp10011110 camellia_sp10011110 +#define sp22000222 camellia_sp22000222 +#define sp03303033 camellia_sp03303033 +#define sp00444404 camellia_sp00444404 +#define sp02220222 camellia_sp02220222 +#define sp30333033 camellia_sp30333033 +#define sp44044404 camellia_sp44044404 +#define sp11101110 camellia_sp11101110 + +#define CAMELLIA_TABLE_BYTE_LEN 272 + +/* struct camellia_ctx: */ +#define key_table 0 +#define key_length CAMELLIA_TABLE_BYTE_LEN + +/* register macros */ +#define CTX %rdi +#define RIO %rsi +#define RIOd %esi + +#define RAB0 %rax +#define RCD0 %rcx +#define RAB1 %rbx +#define RCD1 %rdx + +#define RAB0d %eax +#define RCD0d %ecx +#define RAB1d %ebx +#define RCD1d %edx + +#define RAB0bl %al +#define RCD0bl %cl +#define RAB1bl %bl +#define RCD1bl %dl + +#define RAB0bh %ah +#define RCD0bh %ch +#define RAB1bh %bh +#define RCD1bh %dh + +#define RT0 %rsi +#define RT1 %rbp +#define RT2 %r8 + +#define RT0d %esi +#define RT1d %ebp +#define RT2d %r8d + +#define RT2bl %r8b + +#define RXOR %r9 +#define RRBP %r10 +#define RDST %r11 + +#define RXORd %r9d +#define RXORbl %r9b + +#define xor2ror16(T0, T1, tmp1, tmp2, ab, dst) \ + movzbl ab ## bl, tmp2 ## d; \ + movzbl ab ## bh, tmp1 ## d; \ + rorq $16, ab; \ + xorq T0(, tmp2, 8), dst; \ + xorq T1(, tmp1, 8), dst; + +/********************************************************************** + 1-way camellia + **********************************************************************/ +#define roundsm(ab, subkey, cd) \ + movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ + \ + xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ + xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ + \ + xorq RT2, cd ## 0; + +#define fls(l, r, kl, kr) \ + movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ + andl l ## 0d, RT0d; \ + roll $1, RT0d; \ + shlq $32, RT0; \ + xorq RT0, l ## 0; \ + movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ + orq r ## 0, RT1; \ + shrq $32, RT1; \ + xorq RT1, r ## 0; \ + \ + movq (key_table + ((kl) * 2) * 4)(CTX), RT2; \ + orq l ## 0, RT2; \ + shrq $32, RT2; \ + xorq RT2, l ## 0; \ + movl (key_table + ((kr) * 2) * 4)(CTX), RT0d; \ + andl r ## 0d, RT0d; \ + roll $1, RT0d; \ + shlq $32, RT0; \ + xorq RT0, r ## 0; + +#define enc_rounds(i) \ + roundsm(RAB, i + 2, RCD); \ + roundsm(RCD, i + 3, RAB); \ + roundsm(RAB, i + 4, RCD); \ + roundsm(RCD, i + 5, RAB); \ + roundsm(RAB, i + 6, RCD); \ + roundsm(RCD, i + 7, RAB); + +#define enc_fls(i) \ + fls(RAB, RCD, i + 0, i + 1); + +#define enc_inpack() \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rolq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rorq $32, RCD0; \ + xorq key_table(CTX), RAB0; + +#define enc_outunpack(op, max) \ + xorq key_table(CTX, max, 8), RCD0; \ + rorq $32, RCD0; \ + bswapq RCD0; \ + op ## q RCD0, (RIO); \ + rolq $32, RAB0; \ + bswapq RAB0; \ + op ## q RAB0, 4*2(RIO); + +#define dec_rounds(i) \ + roundsm(RAB, i + 7, RCD); \ + roundsm(RCD, i + 6, RAB); \ + roundsm(RAB, i + 5, RCD); \ + roundsm(RCD, i + 4, RAB); \ + roundsm(RAB, i + 3, RCD); \ + roundsm(RCD, i + 2, RAB); + +#define dec_fls(i) \ + fls(RAB, RCD, i + 1, i + 0); + +#define dec_inpack(max) \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rolq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rorq $32, RCD0; \ + xorq key_table(CTX, max, 8), RAB0; + +#define dec_outunpack() \ + xorq key_table(CTX), RCD0; \ + rorq $32, RCD0; \ + bswapq RCD0; \ + movq RCD0, (RIO); \ + rolq $32, RAB0; \ + bswapq RAB0; \ + movq RAB0, 4*2(RIO); + +.global __camellia_enc_blk; +.type __camellia_enc_blk,@function; + +__camellia_enc_blk: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool xor + */ + movq %rbp, RRBP; + + movq %rcx, RXOR; + movq %rsi, RDST; + movq %rdx, RIO; + + enc_inpack(); + + enc_rounds(0); + enc_fls(8); + enc_rounds(8); + enc_fls(16); + enc_rounds(16); + movl $24, RT1d; /* max */ + + cmpb $16, key_length(CTX); + je __enc_done; + + enc_fls(24); + enc_rounds(24); + movl $32, RT1d; /* max */ + +__enc_done: + testb RXORbl, RXORbl; + movq RDST, RIO; + + jnz __enc_xor; + + enc_outunpack(mov, RT1); + + movq RRBP, %rbp; + ret; + +__enc_xor: + enc_outunpack(xor, RT1); + + movq RRBP, %rbp; + ret; + +.global camellia_dec_blk; +.type camellia_dec_blk,@function; + +camellia_dec_blk: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + cmpl $16, key_length(CTX); + movl $32, RT2d; + movl $24, RXORd; + cmovel RXORd, RT2d; /* max */ + + movq %rbp, RRBP; + movq %rsi, RDST; + movq %rdx, RIO; + + dec_inpack(RT2); + + cmpb $24, RT2bl; + je __dec_rounds16; + + dec_rounds(24); + dec_fls(24); + +__dec_rounds16: + dec_rounds(16); + dec_fls(16); + dec_rounds(8); + dec_fls(8); + dec_rounds(0); + + movq RDST, RIO; + + dec_outunpack(); + + movq RRBP, %rbp; + ret; + +/********************************************************************** + 2-way camellia + **********************************************************************/ +#define roundsm2(ab, subkey, cd) \ + movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ + xorq RT2, cd ## 1; \ + \ + xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ + xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ + xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ + \ + xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 1, cd ## 1); \ + xorq RT2, cd ## 0; \ + xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 1, cd ## 1); \ + xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 1, cd ## 1); \ + xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 1, cd ## 1); + +#define fls2(l, r, kl, kr) \ + movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ + andl l ## 0d, RT0d; \ + roll $1, RT0d; \ + shlq $32, RT0; \ + xorq RT0, l ## 0; \ + movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ + orq r ## 0, RT1; \ + shrq $32, RT1; \ + xorq RT1, r ## 0; \ + \ + movl (key_table + ((kl) * 2) * 4)(CTX), RT2d; \ + andl l ## 1d, RT2d; \ + roll $1, RT2d; \ + shlq $32, RT2; \ + xorq RT2, l ## 1; \ + movq (key_table + ((kr) * 2) * 4)(CTX), RT0; \ + orq r ## 1, RT0; \ + shrq $32, RT0; \ + xorq RT0, r ## 1; \ + \ + movq (key_table + ((kl) * 2) * 4)(CTX), RT1; \ + orq l ## 0, RT1; \ + shrq $32, RT1; \ + xorq RT1, l ## 0; \ + movl (key_table + ((kr) * 2) * 4)(CTX), RT2d; \ + andl r ## 0d, RT2d; \ + roll $1, RT2d; \ + shlq $32, RT2; \ + xorq RT2, r ## 0; \ + \ + movq (key_table + ((kl) * 2) * 4)(CTX), RT0; \ + orq l ## 1, RT0; \ + shrq $32, RT0; \ + xorq RT0, l ## 1; \ + movl (key_table + ((kr) * 2) * 4)(CTX), RT1d; \ + andl r ## 1d, RT1d; \ + roll $1, RT1d; \ + shlq $32, RT1; \ + xorq RT1, r ## 1; + +#define enc_rounds2(i) \ + roundsm2(RAB, i + 2, RCD); \ + roundsm2(RCD, i + 3, RAB); \ + roundsm2(RAB, i + 4, RCD); \ + roundsm2(RCD, i + 5, RAB); \ + roundsm2(RAB, i + 6, RCD); \ + roundsm2(RCD, i + 7, RAB); + +#define enc_fls2(i) \ + fls2(RAB, RCD, i + 0, i + 1); + +#define enc_inpack2() \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rorq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rolq $32, RCD0; \ + xorq key_table(CTX), RAB0; \ + \ + movq 8*2(RIO), RAB1; \ + bswapq RAB1; \ + rorq $32, RAB1; \ + movq 12*2(RIO), RCD1; \ + bswapq RCD1; \ + rolq $32, RCD1; \ + xorq key_table(CTX), RAB1; + +#define enc_outunpack2(op, max) \ + xorq key_table(CTX, max, 8), RCD0; \ + rolq $32, RCD0; \ + bswapq RCD0; \ + op ## q RCD0, (RIO); \ + rorq $32, RAB0; \ + bswapq RAB0; \ + op ## q RAB0, 4*2(RIO); \ + \ + xorq key_table(CTX, max, 8), RCD1; \ + rolq $32, RCD1; \ + bswapq RCD1; \ + op ## q RCD1, 8*2(RIO); \ + rorq $32, RAB1; \ + bswapq RAB1; \ + op ## q RAB1, 12*2(RIO); + +#define dec_rounds2(i) \ + roundsm2(RAB, i + 7, RCD); \ + roundsm2(RCD, i + 6, RAB); \ + roundsm2(RAB, i + 5, RCD); \ + roundsm2(RCD, i + 4, RAB); \ + roundsm2(RAB, i + 3, RCD); \ + roundsm2(RCD, i + 2, RAB); + +#define dec_fls2(i) \ + fls2(RAB, RCD, i + 1, i + 0); + +#define dec_inpack2(max) \ + movq (RIO), RAB0; \ + bswapq RAB0; \ + rorq $32, RAB0; \ + movq 4*2(RIO), RCD0; \ + bswapq RCD0; \ + rolq $32, RCD0; \ + xorq key_table(CTX, max, 8), RAB0; \ + \ + movq 8*2(RIO), RAB1; \ + bswapq RAB1; \ + rorq $32, RAB1; \ + movq 12*2(RIO), RCD1; \ + bswapq RCD1; \ + rolq $32, RCD1; \ + xorq key_table(CTX, max, 8), RAB1; + +#define dec_outunpack2() \ + xorq key_table(CTX), RCD0; \ + rolq $32, RCD0; \ + bswapq RCD0; \ + movq RCD0, (RIO); \ + rorq $32, RAB0; \ + bswapq RAB0; \ + movq RAB0, 4*2(RIO); \ + \ + xorq key_table(CTX), RCD1; \ + rolq $32, RCD1; \ + bswapq RCD1; \ + movq RCD1, 8*2(RIO); \ + rorq $32, RAB1; \ + bswapq RAB1; \ + movq RAB1, 12*2(RIO); + +.global __camellia_enc_blk_2way; +.type __camellia_enc_blk_2way,@function; + +__camellia_enc_blk_2way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool xor + */ + pushq %rbx; + + movq %rbp, RRBP; + movq %rcx, RXOR; + movq %rsi, RDST; + movq %rdx, RIO; + + enc_inpack2(); + + enc_rounds2(0); + enc_fls2(8); + enc_rounds2(8); + enc_fls2(16); + enc_rounds2(16); + movl $24, RT2d; /* max */ + + cmpb $16, key_length(CTX); + je __enc2_done; + + enc_fls2(24); + enc_rounds2(24); + movl $32, RT2d; /* max */ + +__enc2_done: + test RXORbl, RXORbl; + movq RDST, RIO; + jnz __enc2_xor; + + enc_outunpack2(mov, RT2); + + movq RRBP, %rbp; + popq %rbx; + ret; + +__enc2_xor: + enc_outunpack2(xor, RT2); + + movq RRBP, %rbp; + popq %rbx; + ret; + +.global camellia_dec_blk_2way; +.type camellia_dec_blk_2way,@function; + +camellia_dec_blk_2way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + cmpl $16, key_length(CTX); + movl $32, RT2d; + movl $24, RXORd; + cmovel RXORd, RT2d; /* max */ + + movq %rbx, RXOR; + movq %rbp, RRBP; + movq %rsi, RDST; + movq %rdx, RIO; + + dec_inpack2(RT2); + + cmpb $24, RT2bl; + je __dec2_rounds16; + + dec_rounds2(24); + dec_fls2(24); + +__dec2_rounds16: + dec_rounds2(16); + dec_fls2(16); + dec_rounds2(8); + dec_fls2(8); + dec_rounds2(0); + + movq RDST, RIO; + + dec_outunpack2(); + + movq RRBP, %rbp; + movq RXOR, %rbx; + ret; diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c new file mode 100644 index 000000000000..1ca36a93fd2f --- /dev/null +++ b/arch/x86/crypto/camellia_glue.c @@ -0,0 +1,1952 @@ +/* + * Glue Code for assembler optimized version of Camellia + * + * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * Camellia parts based on code by: + * Copyright (C) 2006 NTT (Nippon Telegraph and Telephone Corporation) + * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: + * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> + * CTR part based on code (crypto/ctr.c) by: + * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +#include <asm/processor.h> +#include <asm/unaligned.h> +#include <linux/crypto.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <crypto/algapi.h> +#include <crypto/b128ops.h> +#include <crypto/lrw.h> +#include <crypto/xts.h> + +#define CAMELLIA_MIN_KEY_SIZE 16 +#define CAMELLIA_MAX_KEY_SIZE 32 +#define CAMELLIA_BLOCK_SIZE 16 +#define CAMELLIA_TABLE_BYTE_LEN 272 + +struct camellia_ctx { + u64 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; + u32 key_length; +}; + +/* regular block cipher functions */ +asmlinkage void __camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void camellia_dec_blk(struct camellia_ctx *ctx, u8 *dst, + const u8 *src); + +/* 2-way parallel cipher functions */ +asmlinkage void __camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void camellia_dec_blk_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src); + +static inline void camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk(ctx, dst, src, false); +} + +static inline void camellia_enc_blk_xor(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk(ctx, dst, src, true); +} + +static inline void camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk_2way(ctx, dst, src, false); +} + +static inline void camellia_enc_blk_xor_2way(struct camellia_ctx *ctx, u8 *dst, + const u8 *src) +{ + __camellia_enc_blk_2way(ctx, dst, src, true); +} + +static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + camellia_enc_blk(crypto_tfm_ctx(tfm), dst, src); +} + +static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + camellia_dec_blk(crypto_tfm_ctx(tfm), dst, src); +} + +/* camellia sboxes */ +const u64 camellia_sp10011110[256] = { + 0x7000007070707000, 0x8200008282828200, 0x2c00002c2c2c2c00, + 0xec0000ecececec00, 0xb30000b3b3b3b300, 0x2700002727272700, + 0xc00000c0c0c0c000, 0xe50000e5e5e5e500, 0xe40000e4e4e4e400, + 0x8500008585858500, 0x5700005757575700, 0x3500003535353500, + 0xea0000eaeaeaea00, 0x0c00000c0c0c0c00, 0xae0000aeaeaeae00, + 0x4100004141414100, 0x2300002323232300, 0xef0000efefefef00, + 0x6b00006b6b6b6b00, 0x9300009393939300, 0x4500004545454500, + 0x1900001919191900, 0xa50000a5a5a5a500, 0x2100002121212100, + 0xed0000edededed00, 0x0e00000e0e0e0e00, 0x4f00004f4f4f4f00, + 0x4e00004e4e4e4e00, 0x1d00001d1d1d1d00, 0x6500006565656500, + 0x9200009292929200, 0xbd0000bdbdbdbd00, 0x8600008686868600, + 0xb80000b8b8b8b800, 0xaf0000afafafaf00, 0x8f00008f8f8f8f00, + 0x7c00007c7c7c7c00, 0xeb0000ebebebeb00, 0x1f00001f1f1f1f00, + 0xce0000cececece00, 0x3e00003e3e3e3e00, 0x3000003030303000, + 0xdc0000dcdcdcdc00, 0x5f00005f5f5f5f00, 0x5e00005e5e5e5e00, + 0xc50000c5c5c5c500, 0x0b00000b0b0b0b00, 0x1a00001a1a1a1a00, + 0xa60000a6a6a6a600, 0xe10000e1e1e1e100, 0x3900003939393900, + 0xca0000cacacaca00, 0xd50000d5d5d5d500, 0x4700004747474700, + 0x5d00005d5d5d5d00, 0x3d00003d3d3d3d00, 0xd90000d9d9d9d900, + 0x0100000101010100, 0x5a00005a5a5a5a00, 0xd60000d6d6d6d600, + 0x5100005151515100, 0x5600005656565600, 0x6c00006c6c6c6c00, + 0x4d00004d4d4d4d00, 0x8b00008b8b8b8b00, 0x0d00000d0d0d0d00, + 0x9a00009a9a9a9a00, 0x6600006666666600, 0xfb0000fbfbfbfb00, + 0xcc0000cccccccc00, 0xb00000b0b0b0b000, 0x2d00002d2d2d2d00, + 0x7400007474747400, 0x1200001212121200, 0x2b00002b2b2b2b00, + 0x2000002020202000, 0xf00000f0f0f0f000, 0xb10000b1b1b1b100, + 0x8400008484848400, 0x9900009999999900, 0xdf0000dfdfdfdf00, + 0x4c00004c4c4c4c00, 0xcb0000cbcbcbcb00, 0xc20000c2c2c2c200, + 0x3400003434343400, 0x7e00007e7e7e7e00, 0x7600007676767600, + 0x0500000505050500, 0x6d00006d6d6d6d00, 0xb70000b7b7b7b700, + 0xa90000a9a9a9a900, 0x3100003131313100, 0xd10000d1d1d1d100, + 0x1700001717171700, 0x0400000404040400, 0xd70000d7d7d7d700, + 0x1400001414141400, 0x5800005858585800, 0x3a00003a3a3a3a00, + 0x6100006161616100, 0xde0000dededede00, 0x1b00001b1b1b1b00, + 0x1100001111111100, 0x1c00001c1c1c1c00, 0x3200003232323200, + 0x0f00000f0f0f0f00, 0x9c00009c9c9c9c00, 0x1600001616161600, + 0x5300005353535300, 0x1800001818181800, 0xf20000f2f2f2f200, + 0x2200002222222200, 0xfe0000fefefefe00, 0x4400004444444400, + 0xcf0000cfcfcfcf00, 0xb20000b2b2b2b200, 0xc30000c3c3c3c300, + 0xb50000b5b5b5b500, 0x7a00007a7a7a7a00, 0x9100009191919100, + 0x2400002424242400, 0x0800000808080800, 0xe80000e8e8e8e800, + 0xa80000a8a8a8a800, 0x6000006060606000, 0xfc0000fcfcfcfc00, + 0x6900006969696900, 0x5000005050505000, 0xaa0000aaaaaaaa00, + 0xd00000d0d0d0d000, 0xa00000a0a0a0a000, 0x7d00007d7d7d7d00, + 0xa10000a1a1a1a100, 0x8900008989898900, 0x6200006262626200, + 0x9700009797979700, 0x5400005454545400, 0x5b00005b5b5b5b00, + 0x1e00001e1e1e1e00, 0x9500009595959500, 0xe00000e0e0e0e000, + 0xff0000ffffffff00, 0x6400006464646400, 0xd20000d2d2d2d200, + 0x1000001010101000, 0xc40000c4c4c4c400, 0x0000000000000000, + 0x4800004848484800, 0xa30000a3a3a3a300, 0xf70000f7f7f7f700, + 0x7500007575757500, 0xdb0000dbdbdbdb00, 0x8a00008a8a8a8a00, + 0x0300000303030300, 0xe60000e6e6e6e600, 0xda0000dadadada00, + 0x0900000909090900, 0x3f00003f3f3f3f00, 0xdd0000dddddddd00, + 0x9400009494949400, 0x8700008787878700, 0x5c00005c5c5c5c00, + 0x8300008383838300, 0x0200000202020200, 0xcd0000cdcdcdcd00, + 0x4a00004a4a4a4a00, 0x9000009090909000, 0x3300003333333300, + 0x7300007373737300, 0x6700006767676700, 0xf60000f6f6f6f600, + 0xf30000f3f3f3f300, 0x9d00009d9d9d9d00, 0x7f00007f7f7f7f00, + 0xbf0000bfbfbfbf00, 0xe20000e2e2e2e200, 0x5200005252525200, + 0x9b00009b9b9b9b00, 0xd80000d8d8d8d800, 0x2600002626262600, + 0xc80000c8c8c8c800, 0x3700003737373700, 0xc60000c6c6c6c600, + 0x3b00003b3b3b3b00, 0x8100008181818100, 0x9600009696969600, + 0x6f00006f6f6f6f00, 0x4b00004b4b4b4b00, 0x1300001313131300, + 0xbe0000bebebebe00, 0x6300006363636300, 0x2e00002e2e2e2e00, + 0xe90000e9e9e9e900, 0x7900007979797900, 0xa70000a7a7a7a700, + 0x8c00008c8c8c8c00, 0x9f00009f9f9f9f00, 0x6e00006e6e6e6e00, + 0xbc0000bcbcbcbc00, 0x8e00008e8e8e8e00, 0x2900002929292900, + 0xf50000f5f5f5f500, 0xf90000f9f9f9f900, 0xb60000b6b6b6b600, + 0x2f00002f2f2f2f00, 0xfd0000fdfdfdfd00, 0xb40000b4b4b4b400, + 0x5900005959595900, 0x7800007878787800, 0x9800009898989800, + 0x0600000606060600, 0x6a00006a6a6a6a00, 0xe70000e7e7e7e700, + 0x4600004646464600, 0x7100007171717100, 0xba0000babababa00, + 0xd40000d4d4d4d400, 0x2500002525252500, 0xab0000abababab00, + 0x4200004242424200, 0x8800008888888800, 0xa20000a2a2a2a200, + 0x8d00008d8d8d8d00, 0xfa0000fafafafa00, 0x7200007272727200, + 0x0700000707070700, 0xb90000b9b9b9b900, 0x5500005555555500, + 0xf80000f8f8f8f800, 0xee0000eeeeeeee00, 0xac0000acacacac00, + 0x0a00000a0a0a0a00, 0x3600003636363600, 0x4900004949494900, + 0x2a00002a2a2a2a00, 0x6800006868686800, 0x3c00003c3c3c3c00, + 0x3800003838383800, 0xf10000f1f1f1f100, 0xa40000a4a4a4a400, + 0x4000004040404000, 0x2800002828282800, 0xd30000d3d3d3d300, + 0x7b00007b7b7b7b00, 0xbb0000bbbbbbbb00, 0xc90000c9c9c9c900, + 0x4300004343434300, 0xc10000c1c1c1c100, 0x1500001515151500, + 0xe30000e3e3e3e300, 0xad0000adadadad00, 0xf40000f4f4f4f400, + 0x7700007777777700, 0xc70000c7c7c7c700, 0x8000008080808000, + 0x9e00009e9e9e9e00, +}; + +const u64 camellia_sp22000222[256] = { + 0xe0e0000000e0e0e0, 0x0505000000050505, 0x5858000000585858, + 0xd9d9000000d9d9d9, 0x6767000000676767, 0x4e4e0000004e4e4e, + 0x8181000000818181, 0xcbcb000000cbcbcb, 0xc9c9000000c9c9c9, + 0x0b0b0000000b0b0b, 0xaeae000000aeaeae, 0x6a6a0000006a6a6a, + 0xd5d5000000d5d5d5, 0x1818000000181818, 0x5d5d0000005d5d5d, + 0x8282000000828282, 0x4646000000464646, 0xdfdf000000dfdfdf, + 0xd6d6000000d6d6d6, 0x2727000000272727, 0x8a8a0000008a8a8a, + 0x3232000000323232, 0x4b4b0000004b4b4b, 0x4242000000424242, + 0xdbdb000000dbdbdb, 0x1c1c0000001c1c1c, 0x9e9e0000009e9e9e, + 0x9c9c0000009c9c9c, 0x3a3a0000003a3a3a, 0xcaca000000cacaca, + 0x2525000000252525, 0x7b7b0000007b7b7b, 0x0d0d0000000d0d0d, + 0x7171000000717171, 0x5f5f0000005f5f5f, 0x1f1f0000001f1f1f, + 0xf8f8000000f8f8f8, 0xd7d7000000d7d7d7, 0x3e3e0000003e3e3e, + 0x9d9d0000009d9d9d, 0x7c7c0000007c7c7c, 0x6060000000606060, + 0xb9b9000000b9b9b9, 0xbebe000000bebebe, 0xbcbc000000bcbcbc, + 0x8b8b0000008b8b8b, 0x1616000000161616, 0x3434000000343434, + 0x4d4d0000004d4d4d, 0xc3c3000000c3c3c3, 0x7272000000727272, + 0x9595000000959595, 0xabab000000ababab, 0x8e8e0000008e8e8e, + 0xbaba000000bababa, 0x7a7a0000007a7a7a, 0xb3b3000000b3b3b3, + 0x0202000000020202, 0xb4b4000000b4b4b4, 0xadad000000adadad, + 0xa2a2000000a2a2a2, 0xacac000000acacac, 0xd8d8000000d8d8d8, + 0x9a9a0000009a9a9a, 0x1717000000171717, 0x1a1a0000001a1a1a, + 0x3535000000353535, 0xcccc000000cccccc, 0xf7f7000000f7f7f7, + 0x9999000000999999, 0x6161000000616161, 0x5a5a0000005a5a5a, + 0xe8e8000000e8e8e8, 0x2424000000242424, 0x5656000000565656, + 0x4040000000404040, 0xe1e1000000e1e1e1, 0x6363000000636363, + 0x0909000000090909, 0x3333000000333333, 0xbfbf000000bfbfbf, + 0x9898000000989898, 0x9797000000979797, 0x8585000000858585, + 0x6868000000686868, 0xfcfc000000fcfcfc, 0xecec000000ececec, + 0x0a0a0000000a0a0a, 0xdada000000dadada, 0x6f6f0000006f6f6f, + 0x5353000000535353, 0x6262000000626262, 0xa3a3000000a3a3a3, + 0x2e2e0000002e2e2e, 0x0808000000080808, 0xafaf000000afafaf, + 0x2828000000282828, 0xb0b0000000b0b0b0, 0x7474000000747474, + 0xc2c2000000c2c2c2, 0xbdbd000000bdbdbd, 0x3636000000363636, + 0x2222000000222222, 0x3838000000383838, 0x6464000000646464, + 0x1e1e0000001e1e1e, 0x3939000000393939, 0x2c2c0000002c2c2c, + 0xa6a6000000a6a6a6, 0x3030000000303030, 0xe5e5000000e5e5e5, + 0x4444000000444444, 0xfdfd000000fdfdfd, 0x8888000000888888, + 0x9f9f0000009f9f9f, 0x6565000000656565, 0x8787000000878787, + 0x6b6b0000006b6b6b, 0xf4f4000000f4f4f4, 0x2323000000232323, + 0x4848000000484848, 0x1010000000101010, 0xd1d1000000d1d1d1, + 0x5151000000515151, 0xc0c0000000c0c0c0, 0xf9f9000000f9f9f9, + 0xd2d2000000d2d2d2, 0xa0a0000000a0a0a0, 0x5555000000555555, + 0xa1a1000000a1a1a1, 0x4141000000414141, 0xfafa000000fafafa, + 0x4343000000434343, 0x1313000000131313, 0xc4c4000000c4c4c4, + 0x2f2f0000002f2f2f, 0xa8a8000000a8a8a8, 0xb6b6000000b6b6b6, + 0x3c3c0000003c3c3c, 0x2b2b0000002b2b2b, 0xc1c1000000c1c1c1, + 0xffff000000ffffff, 0xc8c8000000c8c8c8, 0xa5a5000000a5a5a5, + 0x2020000000202020, 0x8989000000898989, 0x0000000000000000, + 0x9090000000909090, 0x4747000000474747, 0xefef000000efefef, + 0xeaea000000eaeaea, 0xb7b7000000b7b7b7, 0x1515000000151515, + 0x0606000000060606, 0xcdcd000000cdcdcd, 0xb5b5000000b5b5b5, + 0x1212000000121212, 0x7e7e0000007e7e7e, 0xbbbb000000bbbbbb, + 0x2929000000292929, 0x0f0f0000000f0f0f, 0xb8b8000000b8b8b8, + 0x0707000000070707, 0x0404000000040404, 0x9b9b0000009b9b9b, + 0x9494000000949494, 0x2121000000212121, 0x6666000000666666, + 0xe6e6000000e6e6e6, 0xcece000000cecece, 0xeded000000ededed, + 0xe7e7000000e7e7e7, 0x3b3b0000003b3b3b, 0xfefe000000fefefe, + 0x7f7f0000007f7f7f, 0xc5c5000000c5c5c5, 0xa4a4000000a4a4a4, + 0x3737000000373737, 0xb1b1000000b1b1b1, 0x4c4c0000004c4c4c, + 0x9191000000919191, 0x6e6e0000006e6e6e, 0x8d8d0000008d8d8d, + 0x7676000000767676, 0x0303000000030303, 0x2d2d0000002d2d2d, + 0xdede000000dedede, 0x9696000000969696, 0x2626000000262626, + 0x7d7d0000007d7d7d, 0xc6c6000000c6c6c6, 0x5c5c0000005c5c5c, + 0xd3d3000000d3d3d3, 0xf2f2000000f2f2f2, 0x4f4f0000004f4f4f, + 0x1919000000191919, 0x3f3f0000003f3f3f, 0xdcdc000000dcdcdc, + 0x7979000000797979, 0x1d1d0000001d1d1d, 0x5252000000525252, + 0xebeb000000ebebeb, 0xf3f3000000f3f3f3, 0x6d6d0000006d6d6d, + 0x5e5e0000005e5e5e, 0xfbfb000000fbfbfb, 0x6969000000696969, + 0xb2b2000000b2b2b2, 0xf0f0000000f0f0f0, 0x3131000000313131, + 0x0c0c0000000c0c0c, 0xd4d4000000d4d4d4, 0xcfcf000000cfcfcf, + 0x8c8c0000008c8c8c, 0xe2e2000000e2e2e2, 0x7575000000757575, + 0xa9a9000000a9a9a9, 0x4a4a0000004a4a4a, 0x5757000000575757, + 0x8484000000848484, 0x1111000000111111, 0x4545000000454545, + 0x1b1b0000001b1b1b, 0xf5f5000000f5f5f5, 0xe4e4000000e4e4e4, + 0x0e0e0000000e0e0e, 0x7373000000737373, 0xaaaa000000aaaaaa, + 0xf1f1000000f1f1f1, 0xdddd000000dddddd, 0x5959000000595959, + 0x1414000000141414, 0x6c6c0000006c6c6c, 0x9292000000929292, + 0x5454000000545454, 0xd0d0000000d0d0d0, 0x7878000000787878, + 0x7070000000707070, 0xe3e3000000e3e3e3, 0x4949000000494949, + 0x8080000000808080, 0x5050000000505050, 0xa7a7000000a7a7a7, + 0xf6f6000000f6f6f6, 0x7777000000777777, 0x9393000000939393, + 0x8686000000868686, 0x8383000000838383, 0x2a2a0000002a2a2a, + 0xc7c7000000c7c7c7, 0x5b5b0000005b5b5b, 0xe9e9000000e9e9e9, + 0xeeee000000eeeeee, 0x8f8f0000008f8f8f, 0x0101000000010101, + 0x3d3d0000003d3d3d, +}; + +const u64 camellia_sp03303033[256] = { + 0x0038380038003838, 0x0041410041004141, 0x0016160016001616, + 0x0076760076007676, 0x00d9d900d900d9d9, 0x0093930093009393, + 0x0060600060006060, 0x00f2f200f200f2f2, 0x0072720072007272, + 0x00c2c200c200c2c2, 0x00abab00ab00abab, 0x009a9a009a009a9a, + 0x0075750075007575, 0x0006060006000606, 0x0057570057005757, + 0x00a0a000a000a0a0, 0x0091910091009191, 0x00f7f700f700f7f7, + 0x00b5b500b500b5b5, 0x00c9c900c900c9c9, 0x00a2a200a200a2a2, + 0x008c8c008c008c8c, 0x00d2d200d200d2d2, 0x0090900090009090, + 0x00f6f600f600f6f6, 0x0007070007000707, 0x00a7a700a700a7a7, + 0x0027270027002727, 0x008e8e008e008e8e, 0x00b2b200b200b2b2, + 0x0049490049004949, 0x00dede00de00dede, 0x0043430043004343, + 0x005c5c005c005c5c, 0x00d7d700d700d7d7, 0x00c7c700c700c7c7, + 0x003e3e003e003e3e, 0x00f5f500f500f5f5, 0x008f8f008f008f8f, + 0x0067670067006767, 0x001f1f001f001f1f, 0x0018180018001818, + 0x006e6e006e006e6e, 0x00afaf00af00afaf, 0x002f2f002f002f2f, + 0x00e2e200e200e2e2, 0x0085850085008585, 0x000d0d000d000d0d, + 0x0053530053005353, 0x00f0f000f000f0f0, 0x009c9c009c009c9c, + 0x0065650065006565, 0x00eaea00ea00eaea, 0x00a3a300a300a3a3, + 0x00aeae00ae00aeae, 0x009e9e009e009e9e, 0x00ecec00ec00ecec, + 0x0080800080008080, 0x002d2d002d002d2d, 0x006b6b006b006b6b, + 0x00a8a800a800a8a8, 0x002b2b002b002b2b, 0x0036360036003636, + 0x00a6a600a600a6a6, 0x00c5c500c500c5c5, 0x0086860086008686, + 0x004d4d004d004d4d, 0x0033330033003333, 0x00fdfd00fd00fdfd, + 0x0066660066006666, 0x0058580058005858, 0x0096960096009696, + 0x003a3a003a003a3a, 0x0009090009000909, 0x0095950095009595, + 0x0010100010001010, 0x0078780078007878, 0x00d8d800d800d8d8, + 0x0042420042004242, 0x00cccc00cc00cccc, 0x00efef00ef00efef, + 0x0026260026002626, 0x00e5e500e500e5e5, 0x0061610061006161, + 0x001a1a001a001a1a, 0x003f3f003f003f3f, 0x003b3b003b003b3b, + 0x0082820082008282, 0x00b6b600b600b6b6, 0x00dbdb00db00dbdb, + 0x00d4d400d400d4d4, 0x0098980098009898, 0x00e8e800e800e8e8, + 0x008b8b008b008b8b, 0x0002020002000202, 0x00ebeb00eb00ebeb, + 0x000a0a000a000a0a, 0x002c2c002c002c2c, 0x001d1d001d001d1d, + 0x00b0b000b000b0b0, 0x006f6f006f006f6f, 0x008d8d008d008d8d, + 0x0088880088008888, 0x000e0e000e000e0e, 0x0019190019001919, + 0x0087870087008787, 0x004e4e004e004e4e, 0x000b0b000b000b0b, + 0x00a9a900a900a9a9, 0x000c0c000c000c0c, 0x0079790079007979, + 0x0011110011001111, 0x007f7f007f007f7f, 0x0022220022002222, + 0x00e7e700e700e7e7, 0x0059590059005959, 0x00e1e100e100e1e1, + 0x00dada00da00dada, 0x003d3d003d003d3d, 0x00c8c800c800c8c8, + 0x0012120012001212, 0x0004040004000404, 0x0074740074007474, + 0x0054540054005454, 0x0030300030003030, 0x007e7e007e007e7e, + 0x00b4b400b400b4b4, 0x0028280028002828, 0x0055550055005555, + 0x0068680068006868, 0x0050500050005050, 0x00bebe00be00bebe, + 0x00d0d000d000d0d0, 0x00c4c400c400c4c4, 0x0031310031003131, + 0x00cbcb00cb00cbcb, 0x002a2a002a002a2a, 0x00adad00ad00adad, + 0x000f0f000f000f0f, 0x00caca00ca00caca, 0x0070700070007070, + 0x00ffff00ff00ffff, 0x0032320032003232, 0x0069690069006969, + 0x0008080008000808, 0x0062620062006262, 0x0000000000000000, + 0x0024240024002424, 0x00d1d100d100d1d1, 0x00fbfb00fb00fbfb, + 0x00baba00ba00baba, 0x00eded00ed00eded, 0x0045450045004545, + 0x0081810081008181, 0x0073730073007373, 0x006d6d006d006d6d, + 0x0084840084008484, 0x009f9f009f009f9f, 0x00eeee00ee00eeee, + 0x004a4a004a004a4a, 0x00c3c300c300c3c3, 0x002e2e002e002e2e, + 0x00c1c100c100c1c1, 0x0001010001000101, 0x00e6e600e600e6e6, + 0x0025250025002525, 0x0048480048004848, 0x0099990099009999, + 0x00b9b900b900b9b9, 0x00b3b300b300b3b3, 0x007b7b007b007b7b, + 0x00f9f900f900f9f9, 0x00cece00ce00cece, 0x00bfbf00bf00bfbf, + 0x00dfdf00df00dfdf, 0x0071710071007171, 0x0029290029002929, + 0x00cdcd00cd00cdcd, 0x006c6c006c006c6c, 0x0013130013001313, + 0x0064640064006464, 0x009b9b009b009b9b, 0x0063630063006363, + 0x009d9d009d009d9d, 0x00c0c000c000c0c0, 0x004b4b004b004b4b, + 0x00b7b700b700b7b7, 0x00a5a500a500a5a5, 0x0089890089008989, + 0x005f5f005f005f5f, 0x00b1b100b100b1b1, 0x0017170017001717, + 0x00f4f400f400f4f4, 0x00bcbc00bc00bcbc, 0x00d3d300d300d3d3, + 0x0046460046004646, 0x00cfcf00cf00cfcf, 0x0037370037003737, + 0x005e5e005e005e5e, 0x0047470047004747, 0x0094940094009494, + 0x00fafa00fa00fafa, 0x00fcfc00fc00fcfc, 0x005b5b005b005b5b, + 0x0097970097009797, 0x00fefe00fe00fefe, 0x005a5a005a005a5a, + 0x00acac00ac00acac, 0x003c3c003c003c3c, 0x004c4c004c004c4c, + 0x0003030003000303, 0x0035350035003535, 0x00f3f300f300f3f3, + 0x0023230023002323, 0x00b8b800b800b8b8, 0x005d5d005d005d5d, + 0x006a6a006a006a6a, 0x0092920092009292, 0x00d5d500d500d5d5, + 0x0021210021002121, 0x0044440044004444, 0x0051510051005151, + 0x00c6c600c600c6c6, 0x007d7d007d007d7d, 0x0039390039003939, + 0x0083830083008383, 0x00dcdc00dc00dcdc, 0x00aaaa00aa00aaaa, + 0x007c7c007c007c7c, 0x0077770077007777, 0x0056560056005656, + 0x0005050005000505, 0x001b1b001b001b1b, 0x00a4a400a400a4a4, + 0x0015150015001515, 0x0034340034003434, 0x001e1e001e001e1e, + 0x001c1c001c001c1c, 0x00f8f800f800f8f8, 0x0052520052005252, + 0x0020200020002020, 0x0014140014001414, 0x00e9e900e900e9e9, + 0x00bdbd00bd00bdbd, 0x00dddd00dd00dddd, 0x00e4e400e400e4e4, + 0x00a1a100a100a1a1, 0x00e0e000e000e0e0, 0x008a8a008a008a8a, + 0x00f1f100f100f1f1, 0x00d6d600d600d6d6, 0x007a7a007a007a7a, + 0x00bbbb00bb00bbbb, 0x00e3e300e300e3e3, 0x0040400040004040, + 0x004f4f004f004f4f, +}; + +const u64 camellia_sp00444404[256] = { + 0x0000707070700070, 0x00002c2c2c2c002c, 0x0000b3b3b3b300b3, + 0x0000c0c0c0c000c0, 0x0000e4e4e4e400e4, 0x0000575757570057, + 0x0000eaeaeaea00ea, 0x0000aeaeaeae00ae, 0x0000232323230023, + 0x00006b6b6b6b006b, 0x0000454545450045, 0x0000a5a5a5a500a5, + 0x0000edededed00ed, 0x00004f4f4f4f004f, 0x00001d1d1d1d001d, + 0x0000929292920092, 0x0000868686860086, 0x0000afafafaf00af, + 0x00007c7c7c7c007c, 0x00001f1f1f1f001f, 0x00003e3e3e3e003e, + 0x0000dcdcdcdc00dc, 0x00005e5e5e5e005e, 0x00000b0b0b0b000b, + 0x0000a6a6a6a600a6, 0x0000393939390039, 0x0000d5d5d5d500d5, + 0x00005d5d5d5d005d, 0x0000d9d9d9d900d9, 0x00005a5a5a5a005a, + 0x0000515151510051, 0x00006c6c6c6c006c, 0x00008b8b8b8b008b, + 0x00009a9a9a9a009a, 0x0000fbfbfbfb00fb, 0x0000b0b0b0b000b0, + 0x0000747474740074, 0x00002b2b2b2b002b, 0x0000f0f0f0f000f0, + 0x0000848484840084, 0x0000dfdfdfdf00df, 0x0000cbcbcbcb00cb, + 0x0000343434340034, 0x0000767676760076, 0x00006d6d6d6d006d, + 0x0000a9a9a9a900a9, 0x0000d1d1d1d100d1, 0x0000040404040004, + 0x0000141414140014, 0x00003a3a3a3a003a, 0x0000dededede00de, + 0x0000111111110011, 0x0000323232320032, 0x00009c9c9c9c009c, + 0x0000535353530053, 0x0000f2f2f2f200f2, 0x0000fefefefe00fe, + 0x0000cfcfcfcf00cf, 0x0000c3c3c3c300c3, 0x00007a7a7a7a007a, + 0x0000242424240024, 0x0000e8e8e8e800e8, 0x0000606060600060, + 0x0000696969690069, 0x0000aaaaaaaa00aa, 0x0000a0a0a0a000a0, + 0x0000a1a1a1a100a1, 0x0000626262620062, 0x0000545454540054, + 0x00001e1e1e1e001e, 0x0000e0e0e0e000e0, 0x0000646464640064, + 0x0000101010100010, 0x0000000000000000, 0x0000a3a3a3a300a3, + 0x0000757575750075, 0x00008a8a8a8a008a, 0x0000e6e6e6e600e6, + 0x0000090909090009, 0x0000dddddddd00dd, 0x0000878787870087, + 0x0000838383830083, 0x0000cdcdcdcd00cd, 0x0000909090900090, + 0x0000737373730073, 0x0000f6f6f6f600f6, 0x00009d9d9d9d009d, + 0x0000bfbfbfbf00bf, 0x0000525252520052, 0x0000d8d8d8d800d8, + 0x0000c8c8c8c800c8, 0x0000c6c6c6c600c6, 0x0000818181810081, + 0x00006f6f6f6f006f, 0x0000131313130013, 0x0000636363630063, + 0x0000e9e9e9e900e9, 0x0000a7a7a7a700a7, 0x00009f9f9f9f009f, + 0x0000bcbcbcbc00bc, 0x0000292929290029, 0x0000f9f9f9f900f9, + 0x00002f2f2f2f002f, 0x0000b4b4b4b400b4, 0x0000787878780078, + 0x0000060606060006, 0x0000e7e7e7e700e7, 0x0000717171710071, + 0x0000d4d4d4d400d4, 0x0000abababab00ab, 0x0000888888880088, + 0x00008d8d8d8d008d, 0x0000727272720072, 0x0000b9b9b9b900b9, + 0x0000f8f8f8f800f8, 0x0000acacacac00ac, 0x0000363636360036, + 0x00002a2a2a2a002a, 0x00003c3c3c3c003c, 0x0000f1f1f1f100f1, + 0x0000404040400040, 0x0000d3d3d3d300d3, 0x0000bbbbbbbb00bb, + 0x0000434343430043, 0x0000151515150015, 0x0000adadadad00ad, + 0x0000777777770077, 0x0000808080800080, 0x0000828282820082, + 0x0000ecececec00ec, 0x0000272727270027, 0x0000e5e5e5e500e5, + 0x0000858585850085, 0x0000353535350035, 0x00000c0c0c0c000c, + 0x0000414141410041, 0x0000efefefef00ef, 0x0000939393930093, + 0x0000191919190019, 0x0000212121210021, 0x00000e0e0e0e000e, + 0x00004e4e4e4e004e, 0x0000656565650065, 0x0000bdbdbdbd00bd, + 0x0000b8b8b8b800b8, 0x00008f8f8f8f008f, 0x0000ebebebeb00eb, + 0x0000cececece00ce, 0x0000303030300030, 0x00005f5f5f5f005f, + 0x0000c5c5c5c500c5, 0x00001a1a1a1a001a, 0x0000e1e1e1e100e1, + 0x0000cacacaca00ca, 0x0000474747470047, 0x00003d3d3d3d003d, + 0x0000010101010001, 0x0000d6d6d6d600d6, 0x0000565656560056, + 0x00004d4d4d4d004d, 0x00000d0d0d0d000d, 0x0000666666660066, + 0x0000cccccccc00cc, 0x00002d2d2d2d002d, 0x0000121212120012, + 0x0000202020200020, 0x0000b1b1b1b100b1, 0x0000999999990099, + 0x00004c4c4c4c004c, 0x0000c2c2c2c200c2, 0x00007e7e7e7e007e, + 0x0000050505050005, 0x0000b7b7b7b700b7, 0x0000313131310031, + 0x0000171717170017, 0x0000d7d7d7d700d7, 0x0000585858580058, + 0x0000616161610061, 0x00001b1b1b1b001b, 0x00001c1c1c1c001c, + 0x00000f0f0f0f000f, 0x0000161616160016, 0x0000181818180018, + 0x0000222222220022, 0x0000444444440044, 0x0000b2b2b2b200b2, + 0x0000b5b5b5b500b5, 0x0000919191910091, 0x0000080808080008, + 0x0000a8a8a8a800a8, 0x0000fcfcfcfc00fc, 0x0000505050500050, + 0x0000d0d0d0d000d0, 0x00007d7d7d7d007d, 0x0000898989890089, + 0x0000979797970097, 0x00005b5b5b5b005b, 0x0000959595950095, + 0x0000ffffffff00ff, 0x0000d2d2d2d200d2, 0x0000c4c4c4c400c4, + 0x0000484848480048, 0x0000f7f7f7f700f7, 0x0000dbdbdbdb00db, + 0x0000030303030003, 0x0000dadadada00da, 0x00003f3f3f3f003f, + 0x0000949494940094, 0x00005c5c5c5c005c, 0x0000020202020002, + 0x00004a4a4a4a004a, 0x0000333333330033, 0x0000676767670067, + 0x0000f3f3f3f300f3, 0x00007f7f7f7f007f, 0x0000e2e2e2e200e2, + 0x00009b9b9b9b009b, 0x0000262626260026, 0x0000373737370037, + 0x00003b3b3b3b003b, 0x0000969696960096, 0x00004b4b4b4b004b, + 0x0000bebebebe00be, 0x00002e2e2e2e002e, 0x0000797979790079, + 0x00008c8c8c8c008c, 0x00006e6e6e6e006e, 0x00008e8e8e8e008e, + 0x0000f5f5f5f500f5, 0x0000b6b6b6b600b6, 0x0000fdfdfdfd00fd, + 0x0000595959590059, 0x0000989898980098, 0x00006a6a6a6a006a, + 0x0000464646460046, 0x0000babababa00ba, 0x0000252525250025, + 0x0000424242420042, 0x0000a2a2a2a200a2, 0x0000fafafafa00fa, + 0x0000070707070007, 0x0000555555550055, 0x0000eeeeeeee00ee, + 0x00000a0a0a0a000a, 0x0000494949490049, 0x0000686868680068, + 0x0000383838380038, 0x0000a4a4a4a400a4, 0x0000282828280028, + 0x00007b7b7b7b007b, 0x0000c9c9c9c900c9, 0x0000c1c1c1c100c1, + 0x0000e3e3e3e300e3, 0x0000f4f4f4f400f4, 0x0000c7c7c7c700c7, + 0x00009e9e9e9e009e, +}; + +const u64 camellia_sp02220222[256] = { + 0x00e0e0e000e0e0e0, 0x0005050500050505, 0x0058585800585858, + 0x00d9d9d900d9d9d9, 0x0067676700676767, 0x004e4e4e004e4e4e, + 0x0081818100818181, 0x00cbcbcb00cbcbcb, 0x00c9c9c900c9c9c9, + 0x000b0b0b000b0b0b, 0x00aeaeae00aeaeae, 0x006a6a6a006a6a6a, + 0x00d5d5d500d5d5d5, 0x0018181800181818, 0x005d5d5d005d5d5d, + 0x0082828200828282, 0x0046464600464646, 0x00dfdfdf00dfdfdf, + 0x00d6d6d600d6d6d6, 0x0027272700272727, 0x008a8a8a008a8a8a, + 0x0032323200323232, 0x004b4b4b004b4b4b, 0x0042424200424242, + 0x00dbdbdb00dbdbdb, 0x001c1c1c001c1c1c, 0x009e9e9e009e9e9e, + 0x009c9c9c009c9c9c, 0x003a3a3a003a3a3a, 0x00cacaca00cacaca, + 0x0025252500252525, 0x007b7b7b007b7b7b, 0x000d0d0d000d0d0d, + 0x0071717100717171, 0x005f5f5f005f5f5f, 0x001f1f1f001f1f1f, + 0x00f8f8f800f8f8f8, 0x00d7d7d700d7d7d7, 0x003e3e3e003e3e3e, + 0x009d9d9d009d9d9d, 0x007c7c7c007c7c7c, 0x0060606000606060, + 0x00b9b9b900b9b9b9, 0x00bebebe00bebebe, 0x00bcbcbc00bcbcbc, + 0x008b8b8b008b8b8b, 0x0016161600161616, 0x0034343400343434, + 0x004d4d4d004d4d4d, 0x00c3c3c300c3c3c3, 0x0072727200727272, + 0x0095959500959595, 0x00ababab00ababab, 0x008e8e8e008e8e8e, + 0x00bababa00bababa, 0x007a7a7a007a7a7a, 0x00b3b3b300b3b3b3, + 0x0002020200020202, 0x00b4b4b400b4b4b4, 0x00adadad00adadad, + 0x00a2a2a200a2a2a2, 0x00acacac00acacac, 0x00d8d8d800d8d8d8, + 0x009a9a9a009a9a9a, 0x0017171700171717, 0x001a1a1a001a1a1a, + 0x0035353500353535, 0x00cccccc00cccccc, 0x00f7f7f700f7f7f7, + 0x0099999900999999, 0x0061616100616161, 0x005a5a5a005a5a5a, + 0x00e8e8e800e8e8e8, 0x0024242400242424, 0x0056565600565656, + 0x0040404000404040, 0x00e1e1e100e1e1e1, 0x0063636300636363, + 0x0009090900090909, 0x0033333300333333, 0x00bfbfbf00bfbfbf, + 0x0098989800989898, 0x0097979700979797, 0x0085858500858585, + 0x0068686800686868, 0x00fcfcfc00fcfcfc, 0x00ececec00ececec, + 0x000a0a0a000a0a0a, 0x00dadada00dadada, 0x006f6f6f006f6f6f, + 0x0053535300535353, 0x0062626200626262, 0x00a3a3a300a3a3a3, + 0x002e2e2e002e2e2e, 0x0008080800080808, 0x00afafaf00afafaf, + 0x0028282800282828, 0x00b0b0b000b0b0b0, 0x0074747400747474, + 0x00c2c2c200c2c2c2, 0x00bdbdbd00bdbdbd, 0x0036363600363636, + 0x0022222200222222, 0x0038383800383838, 0x0064646400646464, + 0x001e1e1e001e1e1e, 0x0039393900393939, 0x002c2c2c002c2c2c, + 0x00a6a6a600a6a6a6, 0x0030303000303030, 0x00e5e5e500e5e5e5, + 0x0044444400444444, 0x00fdfdfd00fdfdfd, 0x0088888800888888, + 0x009f9f9f009f9f9f, 0x0065656500656565, 0x0087878700878787, + 0x006b6b6b006b6b6b, 0x00f4f4f400f4f4f4, 0x0023232300232323, + 0x0048484800484848, 0x0010101000101010, 0x00d1d1d100d1d1d1, + 0x0051515100515151, 0x00c0c0c000c0c0c0, 0x00f9f9f900f9f9f9, + 0x00d2d2d200d2d2d2, 0x00a0a0a000a0a0a0, 0x0055555500555555, + 0x00a1a1a100a1a1a1, 0x0041414100414141, 0x00fafafa00fafafa, + 0x0043434300434343, 0x0013131300131313, 0x00c4c4c400c4c4c4, + 0x002f2f2f002f2f2f, 0x00a8a8a800a8a8a8, 0x00b6b6b600b6b6b6, + 0x003c3c3c003c3c3c, 0x002b2b2b002b2b2b, 0x00c1c1c100c1c1c1, + 0x00ffffff00ffffff, 0x00c8c8c800c8c8c8, 0x00a5a5a500a5a5a5, + 0x0020202000202020, 0x0089898900898989, 0x0000000000000000, + 0x0090909000909090, 0x0047474700474747, 0x00efefef00efefef, + 0x00eaeaea00eaeaea, 0x00b7b7b700b7b7b7, 0x0015151500151515, + 0x0006060600060606, 0x00cdcdcd00cdcdcd, 0x00b5b5b500b5b5b5, + 0x0012121200121212, 0x007e7e7e007e7e7e, 0x00bbbbbb00bbbbbb, + 0x0029292900292929, 0x000f0f0f000f0f0f, 0x00b8b8b800b8b8b8, + 0x0007070700070707, 0x0004040400040404, 0x009b9b9b009b9b9b, + 0x0094949400949494, 0x0021212100212121, 0x0066666600666666, + 0x00e6e6e600e6e6e6, 0x00cecece00cecece, 0x00ededed00ededed, + 0x00e7e7e700e7e7e7, 0x003b3b3b003b3b3b, 0x00fefefe00fefefe, + 0x007f7f7f007f7f7f, 0x00c5c5c500c5c5c5, 0x00a4a4a400a4a4a4, + 0x0037373700373737, 0x00b1b1b100b1b1b1, 0x004c4c4c004c4c4c, + 0x0091919100919191, 0x006e6e6e006e6e6e, 0x008d8d8d008d8d8d, + 0x0076767600767676, 0x0003030300030303, 0x002d2d2d002d2d2d, + 0x00dedede00dedede, 0x0096969600969696, 0x0026262600262626, + 0x007d7d7d007d7d7d, 0x00c6c6c600c6c6c6, 0x005c5c5c005c5c5c, + 0x00d3d3d300d3d3d3, 0x00f2f2f200f2f2f2, 0x004f4f4f004f4f4f, + 0x0019191900191919, 0x003f3f3f003f3f3f, 0x00dcdcdc00dcdcdc, + 0x0079797900797979, 0x001d1d1d001d1d1d, 0x0052525200525252, + 0x00ebebeb00ebebeb, 0x00f3f3f300f3f3f3, 0x006d6d6d006d6d6d, + 0x005e5e5e005e5e5e, 0x00fbfbfb00fbfbfb, 0x0069696900696969, + 0x00b2b2b200b2b2b2, 0x00f0f0f000f0f0f0, 0x0031313100313131, + 0x000c0c0c000c0c0c, 0x00d4d4d400d4d4d4, 0x00cfcfcf00cfcfcf, + 0x008c8c8c008c8c8c, 0x00e2e2e200e2e2e2, 0x0075757500757575, + 0x00a9a9a900a9a9a9, 0x004a4a4a004a4a4a, 0x0057575700575757, + 0x0084848400848484, 0x0011111100111111, 0x0045454500454545, + 0x001b1b1b001b1b1b, 0x00f5f5f500f5f5f5, 0x00e4e4e400e4e4e4, + 0x000e0e0e000e0e0e, 0x0073737300737373, 0x00aaaaaa00aaaaaa, + 0x00f1f1f100f1f1f1, 0x00dddddd00dddddd, 0x0059595900595959, + 0x0014141400141414, 0x006c6c6c006c6c6c, 0x0092929200929292, + 0x0054545400545454, 0x00d0d0d000d0d0d0, 0x0078787800787878, + 0x0070707000707070, 0x00e3e3e300e3e3e3, 0x0049494900494949, + 0x0080808000808080, 0x0050505000505050, 0x00a7a7a700a7a7a7, + 0x00f6f6f600f6f6f6, 0x0077777700777777, 0x0093939300939393, + 0x0086868600868686, 0x0083838300838383, 0x002a2a2a002a2a2a, + 0x00c7c7c700c7c7c7, 0x005b5b5b005b5b5b, 0x00e9e9e900e9e9e9, + 0x00eeeeee00eeeeee, 0x008f8f8f008f8f8f, 0x0001010100010101, + 0x003d3d3d003d3d3d, +}; + +const u64 camellia_sp30333033[256] = { + 0x3800383838003838, 0x4100414141004141, 0x1600161616001616, + 0x7600767676007676, 0xd900d9d9d900d9d9, 0x9300939393009393, + 0x6000606060006060, 0xf200f2f2f200f2f2, 0x7200727272007272, + 0xc200c2c2c200c2c2, 0xab00ababab00abab, 0x9a009a9a9a009a9a, + 0x7500757575007575, 0x0600060606000606, 0x5700575757005757, + 0xa000a0a0a000a0a0, 0x9100919191009191, 0xf700f7f7f700f7f7, + 0xb500b5b5b500b5b5, 0xc900c9c9c900c9c9, 0xa200a2a2a200a2a2, + 0x8c008c8c8c008c8c, 0xd200d2d2d200d2d2, 0x9000909090009090, + 0xf600f6f6f600f6f6, 0x0700070707000707, 0xa700a7a7a700a7a7, + 0x2700272727002727, 0x8e008e8e8e008e8e, 0xb200b2b2b200b2b2, + 0x4900494949004949, 0xde00dedede00dede, 0x4300434343004343, + 0x5c005c5c5c005c5c, 0xd700d7d7d700d7d7, 0xc700c7c7c700c7c7, + 0x3e003e3e3e003e3e, 0xf500f5f5f500f5f5, 0x8f008f8f8f008f8f, + 0x6700676767006767, 0x1f001f1f1f001f1f, 0x1800181818001818, + 0x6e006e6e6e006e6e, 0xaf00afafaf00afaf, 0x2f002f2f2f002f2f, + 0xe200e2e2e200e2e2, 0x8500858585008585, 0x0d000d0d0d000d0d, + 0x5300535353005353, 0xf000f0f0f000f0f0, 0x9c009c9c9c009c9c, + 0x6500656565006565, 0xea00eaeaea00eaea, 0xa300a3a3a300a3a3, + 0xae00aeaeae00aeae, 0x9e009e9e9e009e9e, 0xec00ececec00ecec, + 0x8000808080008080, 0x2d002d2d2d002d2d, 0x6b006b6b6b006b6b, + 0xa800a8a8a800a8a8, 0x2b002b2b2b002b2b, 0x3600363636003636, + 0xa600a6a6a600a6a6, 0xc500c5c5c500c5c5, 0x8600868686008686, + 0x4d004d4d4d004d4d, 0x3300333333003333, 0xfd00fdfdfd00fdfd, + 0x6600666666006666, 0x5800585858005858, 0x9600969696009696, + 0x3a003a3a3a003a3a, 0x0900090909000909, 0x9500959595009595, + 0x1000101010001010, 0x7800787878007878, 0xd800d8d8d800d8d8, + 0x4200424242004242, 0xcc00cccccc00cccc, 0xef00efefef00efef, + 0x2600262626002626, 0xe500e5e5e500e5e5, 0x6100616161006161, + 0x1a001a1a1a001a1a, 0x3f003f3f3f003f3f, 0x3b003b3b3b003b3b, + 0x8200828282008282, 0xb600b6b6b600b6b6, 0xdb00dbdbdb00dbdb, + 0xd400d4d4d400d4d4, 0x9800989898009898, 0xe800e8e8e800e8e8, + 0x8b008b8b8b008b8b, 0x0200020202000202, 0xeb00ebebeb00ebeb, + 0x0a000a0a0a000a0a, 0x2c002c2c2c002c2c, 0x1d001d1d1d001d1d, + 0xb000b0b0b000b0b0, 0x6f006f6f6f006f6f, 0x8d008d8d8d008d8d, + 0x8800888888008888, 0x0e000e0e0e000e0e, 0x1900191919001919, + 0x8700878787008787, 0x4e004e4e4e004e4e, 0x0b000b0b0b000b0b, + 0xa900a9a9a900a9a9, 0x0c000c0c0c000c0c, 0x7900797979007979, + 0x1100111111001111, 0x7f007f7f7f007f7f, 0x2200222222002222, + 0xe700e7e7e700e7e7, 0x5900595959005959, 0xe100e1e1e100e1e1, + 0xda00dadada00dada, 0x3d003d3d3d003d3d, 0xc800c8c8c800c8c8, + 0x1200121212001212, 0x0400040404000404, 0x7400747474007474, + 0x5400545454005454, 0x3000303030003030, 0x7e007e7e7e007e7e, + 0xb400b4b4b400b4b4, 0x2800282828002828, 0x5500555555005555, + 0x6800686868006868, 0x5000505050005050, 0xbe00bebebe00bebe, + 0xd000d0d0d000d0d0, 0xc400c4c4c400c4c4, 0x3100313131003131, + 0xcb00cbcbcb00cbcb, 0x2a002a2a2a002a2a, 0xad00adadad00adad, + 0x0f000f0f0f000f0f, 0xca00cacaca00caca, 0x7000707070007070, + 0xff00ffffff00ffff, 0x3200323232003232, 0x6900696969006969, + 0x0800080808000808, 0x6200626262006262, 0x0000000000000000, + 0x2400242424002424, 0xd100d1d1d100d1d1, 0xfb00fbfbfb00fbfb, + 0xba00bababa00baba, 0xed00ededed00eded, 0x4500454545004545, + 0x8100818181008181, 0x7300737373007373, 0x6d006d6d6d006d6d, + 0x8400848484008484, 0x9f009f9f9f009f9f, 0xee00eeeeee00eeee, + 0x4a004a4a4a004a4a, 0xc300c3c3c300c3c3, 0x2e002e2e2e002e2e, + 0xc100c1c1c100c1c1, 0x0100010101000101, 0xe600e6e6e600e6e6, + 0x2500252525002525, 0x4800484848004848, 0x9900999999009999, + 0xb900b9b9b900b9b9, 0xb300b3b3b300b3b3, 0x7b007b7b7b007b7b, + 0xf900f9f9f900f9f9, 0xce00cecece00cece, 0xbf00bfbfbf00bfbf, + 0xdf00dfdfdf00dfdf, 0x7100717171007171, 0x2900292929002929, + 0xcd00cdcdcd00cdcd, 0x6c006c6c6c006c6c, 0x1300131313001313, + 0x6400646464006464, 0x9b009b9b9b009b9b, 0x6300636363006363, + 0x9d009d9d9d009d9d, 0xc000c0c0c000c0c0, 0x4b004b4b4b004b4b, + 0xb700b7b7b700b7b7, 0xa500a5a5a500a5a5, 0x8900898989008989, + 0x5f005f5f5f005f5f, 0xb100b1b1b100b1b1, 0x1700171717001717, + 0xf400f4f4f400f4f4, 0xbc00bcbcbc00bcbc, 0xd300d3d3d300d3d3, + 0x4600464646004646, 0xcf00cfcfcf00cfcf, 0x3700373737003737, + 0x5e005e5e5e005e5e, 0x4700474747004747, 0x9400949494009494, + 0xfa00fafafa00fafa, 0xfc00fcfcfc00fcfc, 0x5b005b5b5b005b5b, + 0x9700979797009797, 0xfe00fefefe00fefe, 0x5a005a5a5a005a5a, + 0xac00acacac00acac, 0x3c003c3c3c003c3c, 0x4c004c4c4c004c4c, + 0x0300030303000303, 0x3500353535003535, 0xf300f3f3f300f3f3, + 0x2300232323002323, 0xb800b8b8b800b8b8, 0x5d005d5d5d005d5d, + 0x6a006a6a6a006a6a, 0x9200929292009292, 0xd500d5d5d500d5d5, + 0x2100212121002121, 0x4400444444004444, 0x5100515151005151, + 0xc600c6c6c600c6c6, 0x7d007d7d7d007d7d, 0x3900393939003939, + 0x8300838383008383, 0xdc00dcdcdc00dcdc, 0xaa00aaaaaa00aaaa, + 0x7c007c7c7c007c7c, 0x7700777777007777, 0x5600565656005656, + 0x0500050505000505, 0x1b001b1b1b001b1b, 0xa400a4a4a400a4a4, + 0x1500151515001515, 0x3400343434003434, 0x1e001e1e1e001e1e, + 0x1c001c1c1c001c1c, 0xf800f8f8f800f8f8, 0x5200525252005252, + 0x2000202020002020, 0x1400141414001414, 0xe900e9e9e900e9e9, + 0xbd00bdbdbd00bdbd, 0xdd00dddddd00dddd, 0xe400e4e4e400e4e4, + 0xa100a1a1a100a1a1, 0xe000e0e0e000e0e0, 0x8a008a8a8a008a8a, + 0xf100f1f1f100f1f1, 0xd600d6d6d600d6d6, 0x7a007a7a7a007a7a, + 0xbb00bbbbbb00bbbb, 0xe300e3e3e300e3e3, 0x4000404040004040, + 0x4f004f4f4f004f4f, +}; + +const u64 camellia_sp44044404[256] = { + 0x7070007070700070, 0x2c2c002c2c2c002c, 0xb3b300b3b3b300b3, + 0xc0c000c0c0c000c0, 0xe4e400e4e4e400e4, 0x5757005757570057, + 0xeaea00eaeaea00ea, 0xaeae00aeaeae00ae, 0x2323002323230023, + 0x6b6b006b6b6b006b, 0x4545004545450045, 0xa5a500a5a5a500a5, + 0xeded00ededed00ed, 0x4f4f004f4f4f004f, 0x1d1d001d1d1d001d, + 0x9292009292920092, 0x8686008686860086, 0xafaf00afafaf00af, + 0x7c7c007c7c7c007c, 0x1f1f001f1f1f001f, 0x3e3e003e3e3e003e, + 0xdcdc00dcdcdc00dc, 0x5e5e005e5e5e005e, 0x0b0b000b0b0b000b, + 0xa6a600a6a6a600a6, 0x3939003939390039, 0xd5d500d5d5d500d5, + 0x5d5d005d5d5d005d, 0xd9d900d9d9d900d9, 0x5a5a005a5a5a005a, + 0x5151005151510051, 0x6c6c006c6c6c006c, 0x8b8b008b8b8b008b, + 0x9a9a009a9a9a009a, 0xfbfb00fbfbfb00fb, 0xb0b000b0b0b000b0, + 0x7474007474740074, 0x2b2b002b2b2b002b, 0xf0f000f0f0f000f0, + 0x8484008484840084, 0xdfdf00dfdfdf00df, 0xcbcb00cbcbcb00cb, + 0x3434003434340034, 0x7676007676760076, 0x6d6d006d6d6d006d, + 0xa9a900a9a9a900a9, 0xd1d100d1d1d100d1, 0x0404000404040004, + 0x1414001414140014, 0x3a3a003a3a3a003a, 0xdede00dedede00de, + 0x1111001111110011, 0x3232003232320032, 0x9c9c009c9c9c009c, + 0x5353005353530053, 0xf2f200f2f2f200f2, 0xfefe00fefefe00fe, + 0xcfcf00cfcfcf00cf, 0xc3c300c3c3c300c3, 0x7a7a007a7a7a007a, + 0x2424002424240024, 0xe8e800e8e8e800e8, 0x6060006060600060, + 0x6969006969690069, 0xaaaa00aaaaaa00aa, 0xa0a000a0a0a000a0, + 0xa1a100a1a1a100a1, 0x6262006262620062, 0x5454005454540054, + 0x1e1e001e1e1e001e, 0xe0e000e0e0e000e0, 0x6464006464640064, + 0x1010001010100010, 0x0000000000000000, 0xa3a300a3a3a300a3, + 0x7575007575750075, 0x8a8a008a8a8a008a, 0xe6e600e6e6e600e6, + 0x0909000909090009, 0xdddd00dddddd00dd, 0x8787008787870087, + 0x8383008383830083, 0xcdcd00cdcdcd00cd, 0x9090009090900090, + 0x7373007373730073, 0xf6f600f6f6f600f6, 0x9d9d009d9d9d009d, + 0xbfbf00bfbfbf00bf, 0x5252005252520052, 0xd8d800d8d8d800d8, + 0xc8c800c8c8c800c8, 0xc6c600c6c6c600c6, 0x8181008181810081, + 0x6f6f006f6f6f006f, 0x1313001313130013, 0x6363006363630063, + 0xe9e900e9e9e900e9, 0xa7a700a7a7a700a7, 0x9f9f009f9f9f009f, + 0xbcbc00bcbcbc00bc, 0x2929002929290029, 0xf9f900f9f9f900f9, + 0x2f2f002f2f2f002f, 0xb4b400b4b4b400b4, 0x7878007878780078, + 0x0606000606060006, 0xe7e700e7e7e700e7, 0x7171007171710071, + 0xd4d400d4d4d400d4, 0xabab00ababab00ab, 0x8888008888880088, + 0x8d8d008d8d8d008d, 0x7272007272720072, 0xb9b900b9b9b900b9, + 0xf8f800f8f8f800f8, 0xacac00acacac00ac, 0x3636003636360036, + 0x2a2a002a2a2a002a, 0x3c3c003c3c3c003c, 0xf1f100f1f1f100f1, + 0x4040004040400040, 0xd3d300d3d3d300d3, 0xbbbb00bbbbbb00bb, + 0x4343004343430043, 0x1515001515150015, 0xadad00adadad00ad, + 0x7777007777770077, 0x8080008080800080, 0x8282008282820082, + 0xecec00ececec00ec, 0x2727002727270027, 0xe5e500e5e5e500e5, + 0x8585008585850085, 0x3535003535350035, 0x0c0c000c0c0c000c, + 0x4141004141410041, 0xefef00efefef00ef, 0x9393009393930093, + 0x1919001919190019, 0x2121002121210021, 0x0e0e000e0e0e000e, + 0x4e4e004e4e4e004e, 0x6565006565650065, 0xbdbd00bdbdbd00bd, + 0xb8b800b8b8b800b8, 0x8f8f008f8f8f008f, 0xebeb00ebebeb00eb, + 0xcece00cecece00ce, 0x3030003030300030, 0x5f5f005f5f5f005f, + 0xc5c500c5c5c500c5, 0x1a1a001a1a1a001a, 0xe1e100e1e1e100e1, + 0xcaca00cacaca00ca, 0x4747004747470047, 0x3d3d003d3d3d003d, + 0x0101000101010001, 0xd6d600d6d6d600d6, 0x5656005656560056, + 0x4d4d004d4d4d004d, 0x0d0d000d0d0d000d, 0x6666006666660066, + 0xcccc00cccccc00cc, 0x2d2d002d2d2d002d, 0x1212001212120012, + 0x2020002020200020, 0xb1b100b1b1b100b1, 0x9999009999990099, + 0x4c4c004c4c4c004c, 0xc2c200c2c2c200c2, 0x7e7e007e7e7e007e, + 0x0505000505050005, 0xb7b700b7b7b700b7, 0x3131003131310031, + 0x1717001717170017, 0xd7d700d7d7d700d7, 0x5858005858580058, + 0x6161006161610061, 0x1b1b001b1b1b001b, 0x1c1c001c1c1c001c, + 0x0f0f000f0f0f000f, 0x1616001616160016, 0x1818001818180018, + 0x2222002222220022, 0x4444004444440044, 0xb2b200b2b2b200b2, + 0xb5b500b5b5b500b5, 0x9191009191910091, 0x0808000808080008, + 0xa8a800a8a8a800a8, 0xfcfc00fcfcfc00fc, 0x5050005050500050, + 0xd0d000d0d0d000d0, 0x7d7d007d7d7d007d, 0x8989008989890089, + 0x9797009797970097, 0x5b5b005b5b5b005b, 0x9595009595950095, + 0xffff00ffffff00ff, 0xd2d200d2d2d200d2, 0xc4c400c4c4c400c4, + 0x4848004848480048, 0xf7f700f7f7f700f7, 0xdbdb00dbdbdb00db, + 0x0303000303030003, 0xdada00dadada00da, 0x3f3f003f3f3f003f, + 0x9494009494940094, 0x5c5c005c5c5c005c, 0x0202000202020002, + 0x4a4a004a4a4a004a, 0x3333003333330033, 0x6767006767670067, + 0xf3f300f3f3f300f3, 0x7f7f007f7f7f007f, 0xe2e200e2e2e200e2, + 0x9b9b009b9b9b009b, 0x2626002626260026, 0x3737003737370037, + 0x3b3b003b3b3b003b, 0x9696009696960096, 0x4b4b004b4b4b004b, + 0xbebe00bebebe00be, 0x2e2e002e2e2e002e, 0x7979007979790079, + 0x8c8c008c8c8c008c, 0x6e6e006e6e6e006e, 0x8e8e008e8e8e008e, + 0xf5f500f5f5f500f5, 0xb6b600b6b6b600b6, 0xfdfd00fdfdfd00fd, + 0x5959005959590059, 0x9898009898980098, 0x6a6a006a6a6a006a, + 0x4646004646460046, 0xbaba00bababa00ba, 0x2525002525250025, + 0x4242004242420042, 0xa2a200a2a2a200a2, 0xfafa00fafafa00fa, + 0x0707000707070007, 0x5555005555550055, 0xeeee00eeeeee00ee, + 0x0a0a000a0a0a000a, 0x4949004949490049, 0x6868006868680068, + 0x3838003838380038, 0xa4a400a4a4a400a4, 0x2828002828280028, + 0x7b7b007b7b7b007b, 0xc9c900c9c9c900c9, 0xc1c100c1c1c100c1, + 0xe3e300e3e3e300e3, 0xf4f400f4f4f400f4, 0xc7c700c7c7c700c7, + 0x9e9e009e9e9e009e, +}; + +const u64 camellia_sp11101110[256] = { + 0x7070700070707000, 0x8282820082828200, 0x2c2c2c002c2c2c00, + 0xececec00ececec00, 0xb3b3b300b3b3b300, 0x2727270027272700, + 0xc0c0c000c0c0c000, 0xe5e5e500e5e5e500, 0xe4e4e400e4e4e400, + 0x8585850085858500, 0x5757570057575700, 0x3535350035353500, + 0xeaeaea00eaeaea00, 0x0c0c0c000c0c0c00, 0xaeaeae00aeaeae00, + 0x4141410041414100, 0x2323230023232300, 0xefefef00efefef00, + 0x6b6b6b006b6b6b00, 0x9393930093939300, 0x4545450045454500, + 0x1919190019191900, 0xa5a5a500a5a5a500, 0x2121210021212100, + 0xededed00ededed00, 0x0e0e0e000e0e0e00, 0x4f4f4f004f4f4f00, + 0x4e4e4e004e4e4e00, 0x1d1d1d001d1d1d00, 0x6565650065656500, + 0x9292920092929200, 0xbdbdbd00bdbdbd00, 0x8686860086868600, + 0xb8b8b800b8b8b800, 0xafafaf00afafaf00, 0x8f8f8f008f8f8f00, + 0x7c7c7c007c7c7c00, 0xebebeb00ebebeb00, 0x1f1f1f001f1f1f00, + 0xcecece00cecece00, 0x3e3e3e003e3e3e00, 0x3030300030303000, + 0xdcdcdc00dcdcdc00, 0x5f5f5f005f5f5f00, 0x5e5e5e005e5e5e00, + 0xc5c5c500c5c5c500, 0x0b0b0b000b0b0b00, 0x1a1a1a001a1a1a00, + 0xa6a6a600a6a6a600, 0xe1e1e100e1e1e100, 0x3939390039393900, + 0xcacaca00cacaca00, 0xd5d5d500d5d5d500, 0x4747470047474700, + 0x5d5d5d005d5d5d00, 0x3d3d3d003d3d3d00, 0xd9d9d900d9d9d900, + 0x0101010001010100, 0x5a5a5a005a5a5a00, 0xd6d6d600d6d6d600, + 0x5151510051515100, 0x5656560056565600, 0x6c6c6c006c6c6c00, + 0x4d4d4d004d4d4d00, 0x8b8b8b008b8b8b00, 0x0d0d0d000d0d0d00, + 0x9a9a9a009a9a9a00, 0x6666660066666600, 0xfbfbfb00fbfbfb00, + 0xcccccc00cccccc00, 0xb0b0b000b0b0b000, 0x2d2d2d002d2d2d00, + 0x7474740074747400, 0x1212120012121200, 0x2b2b2b002b2b2b00, + 0x2020200020202000, 0xf0f0f000f0f0f000, 0xb1b1b100b1b1b100, + 0x8484840084848400, 0x9999990099999900, 0xdfdfdf00dfdfdf00, + 0x4c4c4c004c4c4c00, 0xcbcbcb00cbcbcb00, 0xc2c2c200c2c2c200, + 0x3434340034343400, 0x7e7e7e007e7e7e00, 0x7676760076767600, + 0x0505050005050500, 0x6d6d6d006d6d6d00, 0xb7b7b700b7b7b700, + 0xa9a9a900a9a9a900, 0x3131310031313100, 0xd1d1d100d1d1d100, + 0x1717170017171700, 0x0404040004040400, 0xd7d7d700d7d7d700, + 0x1414140014141400, 0x5858580058585800, 0x3a3a3a003a3a3a00, + 0x6161610061616100, 0xdedede00dedede00, 0x1b1b1b001b1b1b00, + 0x1111110011111100, 0x1c1c1c001c1c1c00, 0x3232320032323200, + 0x0f0f0f000f0f0f00, 0x9c9c9c009c9c9c00, 0x1616160016161600, + 0x5353530053535300, 0x1818180018181800, 0xf2f2f200f2f2f200, + 0x2222220022222200, 0xfefefe00fefefe00, 0x4444440044444400, + 0xcfcfcf00cfcfcf00, 0xb2b2b200b2b2b200, 0xc3c3c300c3c3c300, + 0xb5b5b500b5b5b500, 0x7a7a7a007a7a7a00, 0x9191910091919100, + 0x2424240024242400, 0x0808080008080800, 0xe8e8e800e8e8e800, + 0xa8a8a800a8a8a800, 0x6060600060606000, 0xfcfcfc00fcfcfc00, + 0x6969690069696900, 0x5050500050505000, 0xaaaaaa00aaaaaa00, + 0xd0d0d000d0d0d000, 0xa0a0a000a0a0a000, 0x7d7d7d007d7d7d00, + 0xa1a1a100a1a1a100, 0x8989890089898900, 0x6262620062626200, + 0x9797970097979700, 0x5454540054545400, 0x5b5b5b005b5b5b00, + 0x1e1e1e001e1e1e00, 0x9595950095959500, 0xe0e0e000e0e0e000, + 0xffffff00ffffff00, 0x6464640064646400, 0xd2d2d200d2d2d200, + 0x1010100010101000, 0xc4c4c400c4c4c400, 0x0000000000000000, + 0x4848480048484800, 0xa3a3a300a3a3a300, 0xf7f7f700f7f7f700, + 0x7575750075757500, 0xdbdbdb00dbdbdb00, 0x8a8a8a008a8a8a00, + 0x0303030003030300, 0xe6e6e600e6e6e600, 0xdadada00dadada00, + 0x0909090009090900, 0x3f3f3f003f3f3f00, 0xdddddd00dddddd00, + 0x9494940094949400, 0x8787870087878700, 0x5c5c5c005c5c5c00, + 0x8383830083838300, 0x0202020002020200, 0xcdcdcd00cdcdcd00, + 0x4a4a4a004a4a4a00, 0x9090900090909000, 0x3333330033333300, + 0x7373730073737300, 0x6767670067676700, 0xf6f6f600f6f6f600, + 0xf3f3f300f3f3f300, 0x9d9d9d009d9d9d00, 0x7f7f7f007f7f7f00, + 0xbfbfbf00bfbfbf00, 0xe2e2e200e2e2e200, 0x5252520052525200, + 0x9b9b9b009b9b9b00, 0xd8d8d800d8d8d800, 0x2626260026262600, + 0xc8c8c800c8c8c800, 0x3737370037373700, 0xc6c6c600c6c6c600, + 0x3b3b3b003b3b3b00, 0x8181810081818100, 0x9696960096969600, + 0x6f6f6f006f6f6f00, 0x4b4b4b004b4b4b00, 0x1313130013131300, + 0xbebebe00bebebe00, 0x6363630063636300, 0x2e2e2e002e2e2e00, + 0xe9e9e900e9e9e900, 0x7979790079797900, 0xa7a7a700a7a7a700, + 0x8c8c8c008c8c8c00, 0x9f9f9f009f9f9f00, 0x6e6e6e006e6e6e00, + 0xbcbcbc00bcbcbc00, 0x8e8e8e008e8e8e00, 0x2929290029292900, + 0xf5f5f500f5f5f500, 0xf9f9f900f9f9f900, 0xb6b6b600b6b6b600, + 0x2f2f2f002f2f2f00, 0xfdfdfd00fdfdfd00, 0xb4b4b400b4b4b400, + 0x5959590059595900, 0x7878780078787800, 0x9898980098989800, + 0x0606060006060600, 0x6a6a6a006a6a6a00, 0xe7e7e700e7e7e700, + 0x4646460046464600, 0x7171710071717100, 0xbababa00bababa00, + 0xd4d4d400d4d4d400, 0x2525250025252500, 0xababab00ababab00, + 0x4242420042424200, 0x8888880088888800, 0xa2a2a200a2a2a200, + 0x8d8d8d008d8d8d00, 0xfafafa00fafafa00, 0x7272720072727200, + 0x0707070007070700, 0xb9b9b900b9b9b900, 0x5555550055555500, + 0xf8f8f800f8f8f800, 0xeeeeee00eeeeee00, 0xacacac00acacac00, + 0x0a0a0a000a0a0a00, 0x3636360036363600, 0x4949490049494900, + 0x2a2a2a002a2a2a00, 0x6868680068686800, 0x3c3c3c003c3c3c00, + 0x3838380038383800, 0xf1f1f100f1f1f100, 0xa4a4a400a4a4a400, + 0x4040400040404000, 0x2828280028282800, 0xd3d3d300d3d3d300, + 0x7b7b7b007b7b7b00, 0xbbbbbb00bbbbbb00, 0xc9c9c900c9c9c900, + 0x4343430043434300, 0xc1c1c100c1c1c100, 0x1515150015151500, + 0xe3e3e300e3e3e300, 0xadadad00adadad00, 0xf4f4f400f4f4f400, + 0x7777770077777700, 0xc7c7c700c7c7c700, 0x8080800080808000, + 0x9e9e9e009e9e9e00, +}; + +/* key constants */ +#define CAMELLIA_SIGMA1L (0xA09E667FL) +#define CAMELLIA_SIGMA1R (0x3BCC908BL) +#define CAMELLIA_SIGMA2L (0xB67AE858L) +#define CAMELLIA_SIGMA2R (0x4CAA73B2L) +#define CAMELLIA_SIGMA3L (0xC6EF372FL) +#define CAMELLIA_SIGMA3R (0xE94F82BEL) +#define CAMELLIA_SIGMA4L (0x54FF53A5L) +#define CAMELLIA_SIGMA4R (0xF1D36F1CL) +#define CAMELLIA_SIGMA5L (0x10E527FAL) +#define CAMELLIA_SIGMA5R (0xDE682D1DL) +#define CAMELLIA_SIGMA6L (0xB05688C2L) +#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) + +/* macros */ +#define ROLDQ(l, r, bits) ({ \ + u64 t = l; \ + l = (l << bits) | (r >> (64 - bits)); \ + r = (r << bits) | (t >> (64 - bits)); \ +}) + +#define CAMELLIA_F(x, kl, kr, y) ({ \ + u64 ii = x ^ (((u64)kl << 32) | kr); \ + y = camellia_sp11101110[(uint8_t)ii]; \ + y ^= camellia_sp44044404[(uint8_t)(ii >> 8)]; \ + ii >>= 16; \ + y ^= camellia_sp30333033[(uint8_t)ii]; \ + y ^= camellia_sp02220222[(uint8_t)(ii >> 8)]; \ + ii >>= 16; \ + y ^= camellia_sp00444404[(uint8_t)ii]; \ + y ^= camellia_sp03303033[(uint8_t)(ii >> 8)]; \ + ii >>= 16; \ + y ^= camellia_sp22000222[(uint8_t)ii]; \ + y ^= camellia_sp10011110[(uint8_t)(ii >> 8)]; \ + y = ror64(y, 32); \ +}) + +#define SET_SUBKEY_LR(INDEX, sRL) (subkey[(INDEX)] = ror64((sRL), 32)) + +static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max) +{ + u64 kw4, tt; + u32 dw, tl, tr; + + /* absorb kw2 to other subkeys */ + /* round 2 */ + subRL[3] ^= subRL[1]; + /* round 4 */ + subRL[5] ^= subRL[1]; + /* round 6 */ + subRL[7] ^= subRL[1]; + + subRL[1] ^= (subRL[1] & ~subRL[9]) << 32; + /* modified for FLinv(kl2) */ + dw = (subRL[1] & subRL[9]) >> 32, + subRL[1] ^= rol32(dw, 1); + + /* round 8 */ + subRL[11] ^= subRL[1]; + /* round 10 */ + subRL[13] ^= subRL[1]; + /* round 12 */ + subRL[15] ^= subRL[1]; + + subRL[1] ^= (subRL[1] & ~subRL[17]) << 32; + /* modified for FLinv(kl4) */ + dw = (subRL[1] & subRL[17]) >> 32, + subRL[1] ^= rol32(dw, 1); + + /* round 14 */ + subRL[19] ^= subRL[1]; + /* round 16 */ + subRL[21] ^= subRL[1]; + /* round 18 */ + subRL[23] ^= subRL[1]; + + if (max == 24) { + /* kw3 */ + subRL[24] ^= subRL[1]; + + /* absorb kw4 to other subkeys */ + kw4 = subRL[25]; + } else { + subRL[1] ^= (subRL[1] & ~subRL[25]) << 32; + /* modified for FLinv(kl6) */ + dw = (subRL[1] & subRL[25]) >> 32, + subRL[1] ^= rol32(dw, 1); + + /* round 20 */ + subRL[27] ^= subRL[1]; + /* round 22 */ + subRL[29] ^= subRL[1]; + /* round 24 */ + subRL[31] ^= subRL[1]; + /* kw3 */ + subRL[32] ^= subRL[1]; + + /* absorb kw4 to other subkeys */ + kw4 = subRL[33]; + /* round 23 */ + subRL[30] ^= kw4; + /* round 21 */ + subRL[28] ^= kw4; + /* round 19 */ + subRL[26] ^= kw4; + + kw4 ^= (kw4 & ~subRL[24]) << 32; + /* modified for FL(kl5) */ + dw = (kw4 & subRL[24]) >> 32, + kw4 ^= rol32(dw, 1); + } + + /* round 17 */ + subRL[22] ^= kw4; + /* round 15 */ + subRL[20] ^= kw4; + /* round 13 */ + subRL[18] ^= kw4; + + kw4 ^= (kw4 & ~subRL[16]) << 32; + /* modified for FL(kl3) */ + dw = (kw4 & subRL[16]) >> 32, + kw4 ^= rol32(dw, 1); + + /* round 11 */ + subRL[14] ^= kw4; + /* round 9 */ + subRL[12] ^= kw4; + /* round 7 */ + subRL[10] ^= kw4; + + kw4 ^= (kw4 & ~subRL[8]) << 32; + /* modified for FL(kl1) */ + dw = (kw4 & subRL[8]) >> 32, + kw4 ^= rol32(dw, 1); + + /* round 5 */ + subRL[6] ^= kw4; + /* round 3 */ + subRL[4] ^= kw4; + /* round 1 */ + subRL[2] ^= kw4; + /* kw1 */ + subRL[0] ^= kw4; + + /* key XOR is end of F-function */ + SET_SUBKEY_LR(0, subRL[0] ^ subRL[2]); /* kw1 */ + SET_SUBKEY_LR(2, subRL[3]); /* round 1 */ + SET_SUBKEY_LR(3, subRL[2] ^ subRL[4]); /* round 2 */ + SET_SUBKEY_LR(4, subRL[3] ^ subRL[5]); /* round 3 */ + SET_SUBKEY_LR(5, subRL[4] ^ subRL[6]); /* round 4 */ + SET_SUBKEY_LR(6, subRL[5] ^ subRL[7]); /* round 5 */ + + tl = (subRL[10] >> 32) ^ (subRL[10] & ~subRL[8]); + dw = tl & (subRL[8] >> 32), /* FL(kl1) */ + tr = subRL[10] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(7, subRL[6] ^ tt); /* round 6 */ + SET_SUBKEY_LR(8, subRL[8]); /* FL(kl1) */ + SET_SUBKEY_LR(9, subRL[9]); /* FLinv(kl2) */ + + tl = (subRL[7] >> 32) ^ (subRL[7] & ~subRL[9]); + dw = tl & (subRL[9] >> 32), /* FLinv(kl2) */ + tr = subRL[7] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(10, subRL[11] ^ tt); /* round 7 */ + SET_SUBKEY_LR(11, subRL[10] ^ subRL[12]); /* round 8 */ + SET_SUBKEY_LR(12, subRL[11] ^ subRL[13]); /* round 9 */ + SET_SUBKEY_LR(13, subRL[12] ^ subRL[14]); /* round 10 */ + SET_SUBKEY_LR(14, subRL[13] ^ subRL[15]); /* round 11 */ + + tl = (subRL[18] >> 32) ^ (subRL[18] & ~subRL[16]); + dw = tl & (subRL[16] >> 32), /* FL(kl3) */ + tr = subRL[18] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(15, subRL[14] ^ tt); /* round 12 */ + SET_SUBKEY_LR(16, subRL[16]); /* FL(kl3) */ + SET_SUBKEY_LR(17, subRL[17]); /* FLinv(kl4) */ + + tl = (subRL[15] >> 32) ^ (subRL[15] & ~subRL[17]); + dw = tl & (subRL[17] >> 32), /* FLinv(kl4) */ + tr = subRL[15] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(18, subRL[19] ^ tt); /* round 13 */ + SET_SUBKEY_LR(19, subRL[18] ^ subRL[20]); /* round 14 */ + SET_SUBKEY_LR(20, subRL[19] ^ subRL[21]); /* round 15 */ + SET_SUBKEY_LR(21, subRL[20] ^ subRL[22]); /* round 16 */ + SET_SUBKEY_LR(22, subRL[21] ^ subRL[23]); /* round 17 */ + + if (max == 24) { + SET_SUBKEY_LR(23, subRL[22]); /* round 18 */ + SET_SUBKEY_LR(24, subRL[24] ^ subRL[23]); /* kw3 */ + } else { + tl = (subRL[26] >> 32) ^ (subRL[26] & ~subRL[24]); + dw = tl & (subRL[24] >> 32), /* FL(kl5) */ + tr = subRL[26] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(23, subRL[22] ^ tt); /* round 18 */ + SET_SUBKEY_LR(24, subRL[24]); /* FL(kl5) */ + SET_SUBKEY_LR(25, subRL[25]); /* FLinv(kl6) */ + + tl = (subRL[23] >> 32) ^ (subRL[23] & ~subRL[25]); + dw = tl & (subRL[25] >> 32), /* FLinv(kl6) */ + tr = subRL[23] ^ rol32(dw, 1); + tt = (tr | ((u64)tl << 32)); + + SET_SUBKEY_LR(26, subRL[27] ^ tt); /* round 19 */ + SET_SUBKEY_LR(27, subRL[26] ^ subRL[28]); /* round 20 */ + SET_SUBKEY_LR(28, subRL[27] ^ subRL[29]); /* round 21 */ + SET_SUBKEY_LR(29, subRL[28] ^ subRL[30]); /* round 22 */ + SET_SUBKEY_LR(30, subRL[29] ^ subRL[31]); /* round 23 */ + SET_SUBKEY_LR(31, subRL[30]); /* round 24 */ + SET_SUBKEY_LR(32, subRL[32] ^ subRL[31]); /* kw3 */ + } +} + +static void camellia_setup128(const unsigned char *key, u64 *subkey) +{ + u64 kl, kr, ww; + u64 subRL[26]; + + /** + * k == kl || kr (|| is concatenation) + */ + kl = get_unaligned_be64(key); + kr = get_unaligned_be64(key + 8); + + /* generate KL dependent subkeys */ + /* kw1 */ + subRL[0] = kl; + /* kw2 */ + subRL[1] = kr; + + /* rotation left shift 15bit */ + ROLDQ(kl, kr, 15); + + /* k3 */ + subRL[4] = kl; + /* k4 */ + subRL[5] = kr; + + /* rotation left shift 15+30bit */ + ROLDQ(kl, kr, 30); + + /* k7 */ + subRL[10] = kl; + /* k8 */ + subRL[11] = kr; + + /* rotation left shift 15+30+15bit */ + ROLDQ(kl, kr, 15); + + /* k10 */ + subRL[13] = kr; + /* rotation left shift 15+30+15+17 bit */ + ROLDQ(kl, kr, 17); + + /* kl3 */ + subRL[16] = kl; + /* kl4 */ + subRL[17] = kr; + + /* rotation left shift 15+30+15+17+17 bit */ + ROLDQ(kl, kr, 17); + + /* k13 */ + subRL[18] = kl; + /* k14 */ + subRL[19] = kr; + + /* rotation left shift 15+30+15+17+17+17 bit */ + ROLDQ(kl, kr, 17); + + /* k17 */ + subRL[22] = kl; + /* k18 */ + subRL[23] = kr; + + /* generate KA */ + kl = subRL[0]; + kr = subRL[1]; + CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww); + kr ^= ww; + CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl); + + /* current status == (kll, klr, w0, w1) */ + CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr); + kr ^= ww; + CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww); + kl ^= ww; + + /* generate KA dependent subkeys */ + /* k1, k2 */ + subRL[2] = kl; + subRL[3] = kr; + ROLDQ(kl, kr, 15); + /* k5,k6 */ + subRL[6] = kl; + subRL[7] = kr; + ROLDQ(kl, kr, 15); + /* kl1, kl2 */ + subRL[8] = kl; + subRL[9] = kr; + ROLDQ(kl, kr, 15); + /* k9 */ + subRL[12] = kl; + ROLDQ(kl, kr, 15); + /* k11, k12 */ + subRL[14] = kl; + subRL[15] = kr; + ROLDQ(kl, kr, 34); + /* k15, k16 */ + subRL[20] = kl; + subRL[21] = kr; + ROLDQ(kl, kr, 17); + /* kw3, kw4 */ + subRL[24] = kl; + subRL[25] = kr; + + camellia_setup_tail(subkey, subRL, 24); +} + +static void camellia_setup256(const unsigned char *key, u64 *subkey) +{ + u64 kl, kr; /* left half of key */ + u64 krl, krr; /* right half of key */ + u64 ww; /* temporary variables */ + u64 subRL[34]; + + /** + * key = (kl || kr || krl || krr) (|| is concatenation) + */ + kl = get_unaligned_be64(key); + kr = get_unaligned_be64(key + 8); + krl = get_unaligned_be64(key + 16); + krr = get_unaligned_be64(key + 24); + + /* generate KL dependent subkeys */ + /* kw1 */ + subRL[0] = kl; + /* kw2 */ + subRL[1] = kr; + ROLDQ(kl, kr, 45); + /* k9 */ + subRL[12] = kl; + /* k10 */ + subRL[13] = kr; + ROLDQ(kl, kr, 15); + /* kl3 */ + subRL[16] = kl; + /* kl4 */ + subRL[17] = kr; + ROLDQ(kl, kr, 17); + /* k17 */ + subRL[22] = kl; + /* k18 */ + subRL[23] = kr; + ROLDQ(kl, kr, 34); + /* k23 */ + subRL[30] = kl; + /* k24 */ + subRL[31] = kr; + + /* generate KR dependent subkeys */ + ROLDQ(krl, krr, 15); + /* k3 */ + subRL[4] = krl; + /* k4 */ + subRL[5] = krr; + ROLDQ(krl, krr, 15); + /* kl1 */ + subRL[8] = krl; + /* kl2 */ + subRL[9] = krr; + ROLDQ(krl, krr, 30); + /* k13 */ + subRL[18] = krl; + /* k14 */ + subRL[19] = krr; + ROLDQ(krl, krr, 34); + /* k19 */ + subRL[26] = krl; + /* k20 */ + subRL[27] = krr; + ROLDQ(krl, krr, 34); + + /* generate KA */ + kl = subRL[0] ^ krl; + kr = subRL[1] ^ krr; + + CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww); + kr ^= ww; + CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl); + kl ^= krl; + CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr); + kr ^= ww ^ krr; + CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww); + kl ^= ww; + + /* generate KB */ + krl ^= kl; + krr ^= kr; + CAMELLIA_F(krl, CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, ww); + krr ^= ww; + CAMELLIA_F(krr, CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, ww); + krl ^= ww; + + /* generate KA dependent subkeys */ + ROLDQ(kl, kr, 15); + /* k5 */ + subRL[6] = kl; + /* k6 */ + subRL[7] = kr; + ROLDQ(kl, kr, 30); + /* k11 */ + subRL[14] = kl; + /* k12 */ + subRL[15] = kr; + /* rotation left shift 32bit */ + ROLDQ(kl, kr, 32); + /* kl5 */ + subRL[24] = kl; + /* kl6 */ + subRL[25] = kr; + /* rotation left shift 17 from k11,k12 -> k21,k22 */ + ROLDQ(kl, kr, 17); + /* k21 */ + subRL[28] = kl; + /* k22 */ + subRL[29] = kr; + + /* generate KB dependent subkeys */ + /* k1 */ + subRL[2] = krl; + /* k2 */ + subRL[3] = krr; + ROLDQ(krl, krr, 30); + /* k7 */ + subRL[10] = krl; + /* k8 */ + subRL[11] = krr; + ROLDQ(krl, krr, 30); + /* k15 */ + subRL[20] = krl; + /* k16 */ + subRL[21] = krr; + ROLDQ(krl, krr, 51); + /* kw3 */ + subRL[32] = krl; + /* kw4 */ + subRL[33] = krr; + + camellia_setup_tail(subkey, subRL, 32); +} + +static void camellia_setup192(const unsigned char *key, u64 *subkey) +{ + unsigned char kk[32]; + u64 krl, krr; + + memcpy(kk, key, 24); + memcpy((unsigned char *)&krl, key+16, 8); + krr = ~krl; + memcpy(kk+24, (unsigned char *)&krr, 8); + camellia_setup256(kk, subkey); +} + +static int __camellia_setkey(struct camellia_ctx *cctx, + const unsigned char *key, + unsigned int key_len, u32 *flags) +{ + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + cctx->key_length = key_len; + + switch (key_len) { + case 16: + camellia_setup128(key, cctx->key_table); + break; + case 24: + camellia_setup192(key, cctx->key_table); + break; + case 32: + camellia_setup256(key, cctx->key_table); + break; + } + + return 0; +} + +static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len, + &tfm->crt_flags); +} + +static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, + void (*fn)(struct camellia_ctx *, u8 *, const u8 *), + void (*fn_2way)(struct camellia_ctx *, u8 *, const u8 *)) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes; + int err; + + err = blkcipher_walk_virt(desc, walk); + + while ((nbytes = walk->nbytes)) { + u8 *wsrc = walk->src.virt.addr; + u8 *wdst = walk->dst.virt.addr; + + /* Process two block batch */ + if (nbytes >= bsize * 2) { + do { + fn_2way(ctx, wdst, wsrc); + + wsrc += bsize * 2; + wdst += bsize * 2; + nbytes -= bsize * 2; + } while (nbytes >= bsize * 2); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + fn(ctx, wdst, wsrc); + + wsrc += bsize; + wdst += bsize; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + err = blkcipher_walk_done(desc, walk, nbytes); + } + + return err; +} + +static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_crypt(desc, &walk, camellia_enc_blk, camellia_enc_blk_2way); +} + +static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_crypt(desc, &walk, camellia_dec_blk, camellia_dec_blk_2way); +} + +static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u128 *src = (u128 *)walk->src.virt.addr; + u128 *dst = (u128 *)walk->dst.virt.addr; + u128 *iv = (u128 *)walk->iv; + + do { + u128_xor(dst, src, iv); + camellia_enc_blk(ctx, (u8 *)dst, (u8 *)dst); + iv = dst; + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + + u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); + return nbytes; +} + +static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes = __cbc_encrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u128 *src = (u128 *)walk->src.virt.addr; + u128 *dst = (u128 *)walk->dst.virt.addr; + u128 ivs[2 - 1]; + u128 last_iv; + + /* Start of the last block. */ + src += nbytes / bsize - 1; + dst += nbytes / bsize - 1; + + last_iv = *src; + + /* Process two block batch */ + if (nbytes >= bsize * 2) { + do { + nbytes -= bsize * (2 - 1); + src -= 2 - 1; + dst -= 2 - 1; + + ivs[0] = src[0]; + + camellia_dec_blk_2way(ctx, (u8 *)dst, (u8 *)src); + + u128_xor(dst + 1, dst + 1, ivs + 0); + + nbytes -= bsize; + if (nbytes < bsize) + goto done; + + u128_xor(dst, dst, src - 1); + src -= 1; + dst -= 1; + } while (nbytes >= bsize * 2); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + for (;;) { + camellia_dec_blk(ctx, (u8 *)dst, (u8 *)src); + + nbytes -= bsize; + if (nbytes < bsize) + break; + + u128_xor(dst, dst, src - 1); + src -= 1; + dst -= 1; + } + +done: + u128_xor(dst, dst, (u128 *)walk->iv); + *(u128 *)walk->iv = last_iv; + + return nbytes; +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + + while ((nbytes = walk.nbytes)) { + nbytes = __cbc_decrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static inline void u128_to_be128(be128 *dst, const u128 *src) +{ + dst->a = cpu_to_be64(src->a); + dst->b = cpu_to_be64(src->b); +} + +static inline void be128_to_u128(u128 *dst, const be128 *src) +{ + dst->a = be64_to_cpu(src->a); + dst->b = be64_to_cpu(src->b); +} + +static inline void u128_inc(u128 *i) +{ + i->b++; + if (!i->b) + i->a++; +} + +static void ctr_crypt_final(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + u8 keystream[CAMELLIA_BLOCK_SIZE]; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + u128 ctrblk; + + memcpy(keystream, src, nbytes); + camellia_enc_blk_xor(ctx, keystream, walk->iv); + memcpy(dst, keystream, nbytes); + + be128_to_u128(&ctrblk, (be128 *)walk->iv); + u128_inc(&ctrblk); + u128_to_be128((be128 *)walk->iv, &ctrblk); +} + +static unsigned int __ctr_crypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + unsigned int bsize = CAMELLIA_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u128 *src = (u128 *)walk->src.virt.addr; + u128 *dst = (u128 *)walk->dst.virt.addr; + u128 ctrblk; + be128 ctrblocks[2]; + + be128_to_u128(&ctrblk, (be128 *)walk->iv); + + /* Process two block batch */ + if (nbytes >= bsize * 2) { + do { + if (dst != src) { + dst[0] = src[0]; + dst[1] = src[1]; + } + + /* create ctrblks for parallel encrypt */ + u128_to_be128(&ctrblocks[0], &ctrblk); + u128_inc(&ctrblk); + u128_to_be128(&ctrblocks[1], &ctrblk); + u128_inc(&ctrblk); + + camellia_enc_blk_xor_2way(ctx, (u8 *)dst, + (u8 *)ctrblocks); + + src += 2; + dst += 2; + nbytes -= bsize * 2; + } while (nbytes >= bsize * 2); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + if (dst != src) + *dst = *src; + + u128_to_be128(&ctrblocks[0], &ctrblk); + u128_inc(&ctrblk); + + camellia_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + u128_to_be128((be128 *)walk->iv, &ctrblk); + return nbytes; +} + +static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, CAMELLIA_BLOCK_SIZE); + + while ((nbytes = walk.nbytes) >= CAMELLIA_BLOCK_SIZE) { + nbytes = __ctr_crypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + if (walk.nbytes) { + ctr_crypt_final(desc, &walk); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + +static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAMELLIA_BLOCK_SIZE; + struct camellia_ctx *ctx = priv; + int i; + + while (nbytes >= 2 * bsize) { + camellia_enc_blk_2way(ctx, srcdst, srcdst); + srcdst += bsize * 2; + nbytes -= bsize * 2; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + camellia_enc_blk(ctx, srcdst, srcdst); +} + +static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAMELLIA_BLOCK_SIZE; + struct camellia_ctx *ctx = priv; + int i; + + while (nbytes >= 2 * bsize) { + camellia_dec_blk_2way(ctx, srcdst, srcdst); + srcdst += bsize * 2; + nbytes -= bsize * 2; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + camellia_dec_blk(ctx, srcdst, srcdst); +} + +struct camellia_lrw_ctx { + struct lrw_table_ctx lrw_table; + struct camellia_ctx camellia_ctx; +}; + +static int lrw_camellia_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + err = __camellia_setkey(&ctx->camellia_ctx, key, + keylen - CAMELLIA_BLOCK_SIZE, + &tfm->crt_flags); + if (err) + return err; + + return lrw_init_table(&ctx->lrw_table, + key + keylen - CAMELLIA_BLOCK_SIZE); +} + +static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &ctx->camellia_ctx, + .crypt_fn = encrypt_callback, + }; + + return lrw_crypt(desc, dst, src, nbytes, &req); +} + +static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &ctx->camellia_ctx, + .crypt_fn = decrypt_callback, + }; + + return lrw_crypt(desc, dst, src, nbytes, &req); +} + +static void lrw_exit_tfm(struct crypto_tfm *tfm) +{ + struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + + lrw_free_table(&ctx->lrw_table); +} + +struct camellia_xts_ctx { + struct camellia_ctx tweak_ctx; + struct camellia_ctx crypt_ctx; +}; + +static int xts_camellia_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct camellia_xts_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + int err; + + /* key consists of keys of equal size concatenated, therefore + * the length must be even + */ + if (keylen % 2) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* first half of xts-key is for crypt */ + err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return __camellia_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2, + flags); +} + +static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk), + .crypt_ctx = &ctx->crypt_ctx, + .crypt_fn = encrypt_callback, + }; + + return xts_crypt(desc, dst, src, nbytes, &req); +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[2 * 4]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk), + .crypt_ctx = &ctx->crypt_ctx, + .crypt_fn = decrypt_callback, + }; + + return xts_crypt(desc, dst, src, nbytes, &req); +} + +static struct crypto_alg camellia_algs[6] = { { + .cra_name = "camellia", + .cra_driver_name = "camellia-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[0].cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, + .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, + .cia_setkey = camellia_setkey, + .cia_encrypt = camellia_encrypt, + .cia_decrypt = camellia_decrypt + } + } +}, { + .cra_name = "ecb(camellia)", + .cra_driver_name = "ecb-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .setkey = camellia_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "cbc(camellia)", + .cra_driver_name = "cbc-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = camellia_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "ctr(camellia)", + .cra_driver_name = "ctr-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct camellia_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[3].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = camellia_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "lrw(camellia)", + .cra_driver_name = "lrw-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[4].cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE + + CAMELLIA_BLOCK_SIZE, + .max_keysize = CAMELLIA_MAX_KEY_SIZE + + CAMELLIA_BLOCK_SIZE, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = lrw_camellia_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "xts(camellia)", + .cra_driver_name = "xts-camellia-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAMELLIA_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct camellia_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(camellia_algs[5].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2, + .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2, + .ivsize = CAMELLIA_BLOCK_SIZE, + .setkey = xts_camellia_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +} }; + +static bool is_blacklisted_cpu(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return false; + + if (boot_cpu_data.x86 == 0x0f) { + /* + * On Pentium 4, camellia-asm is slower than original assembler + * implementation because excessive uses of 64bit rotate and + * left-shifts (which are really slow on P4) needed to store and + * handle 128bit block in two 64bit registers. + */ + return true; + } + + return false; +} + +static int force; +module_param(force, int, 0); +MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); + +int __init init(void) +{ + if (!force && is_blacklisted_cpu()) { + printk(KERN_INFO + "camellia-x86_64: performance on this CPU " + "would be suboptimal: disabling " + "camellia-x86_64.\n"); + return -ENODEV; + } + + return crypto_register_algs(camellia_algs, ARRAY_SIZE(camellia_algs)); +} + +void __exit fini(void) +{ + crypto_unregister_algs(camellia_algs, ARRAY_SIZE(camellia_algs)); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Camellia Cipher Algorithm, asm optimized"); +MODULE_ALIAS("camellia"); +MODULE_ALIAS("camellia-asm"); diff --git a/arch/x86/crypto/serpent-sse2-i586-asm_32.S b/arch/x86/crypto/serpent-sse2-i586-asm_32.S index 4e37677ca851..c00053d42f99 100644 --- a/arch/x86/crypto/serpent-sse2-i586-asm_32.S +++ b/arch/x86/crypto/serpent-sse2-i586-asm_32.S @@ -463,23 +463,20 @@ pand x0, x4; \ pxor x2, x4; -#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ - movdqa x2, t3; \ - movdqa x0, t1; \ - unpcklps x3, t3; \ +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ movdqa x0, t2; \ - unpcklps x1, t1; \ - unpckhps x1, t2; \ - movdqa t3, x1; \ - unpckhps x3, x2; \ - movdqa t1, x0; \ - movhlps t1, x1; \ - movdqa t2, t1; \ - movlhps t3, x0; \ - movlhps x2, t1; \ - movhlps t2, x2; \ - movdqa x2, x3; \ - movdqa t1, x2; + punpckldq x1, x0; \ + punpckhdq x1, t2; \ + movdqa x2, t1; \ + punpckhdq x3, x2; \ + punpckldq x3, t1; \ + movdqa x0, x1; \ + punpcklqdq t1, x0; \ + punpckhqdq t1, x1; \ + movdqa t2, x3; \ + punpcklqdq x2, t2; \ + punpckhqdq x2, x3; \ + movdqa t2, x2; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S index 7f24a1540821..3ee1ff04d3e9 100644 --- a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S +++ b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S @@ -585,23 +585,20 @@ get_key(i, 1, RK1); \ SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \ -#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ - movdqa x2, t3; \ - movdqa x0, t1; \ - unpcklps x3, t3; \ +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ movdqa x0, t2; \ - unpcklps x1, t1; \ - unpckhps x1, t2; \ - movdqa t3, x1; \ - unpckhps x3, x2; \ - movdqa t1, x0; \ - movhlps t1, x1; \ - movdqa t2, t1; \ - movlhps t3, x0; \ - movlhps x2, t1; \ - movhlps t2, x2; \ - movdqa x2, x3; \ - movdqa t1, x2; + punpckldq x1, x0; \ + punpckhdq x1, t2; \ + movdqa x2, t1; \ + punpckhdq x3, x2; \ + punpckldq x3, t1; \ + movdqa x0, x1; \ + punpcklqdq t1, x0; \ + punpckhqdq t1, x1; \ + movdqa t2, x3; \ + punpcklqdq x2, t2; \ + punpckhqdq x2, x3; \ + movdqa t2, x2; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index 7955a9b76b91..4b21be85e0a1 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -145,28 +145,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, false); } -static struct crypto_alg blk_ecb_alg = { - .cra_name = "__ecb-serpent-sse2", - .cra_driver_name = "__driver-ecb-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .setkey = serpent_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}; - static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -295,28 +273,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_cbc_alg = { - .cra_name = "__cbc-serpent-sse2", - .cra_driver_name = "__driver-cbc-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .setkey = serpent_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}; - static inline void u128_to_be128(be128 *dst, const u128 *src) { dst->a = cpu_to_be64(src->a); @@ -439,29 +395,6 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { - .cra_name = "__ctr-serpent-sse2", - .cra_driver_name = "__driver-ctr-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = serpent_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}; - struct crypt_priv { struct serpent_ctx *ctx; bool fpu_enabled; @@ -580,32 +513,6 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm) lrw_free_table(&ctx->lrw_table); } -static struct crypto_alg blk_lrw_alg = { - .cra_name = "__lrw-serpent-sse2", - .cra_driver_name = "__driver-lrw-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE + - SERPENT_BLOCK_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE + - SERPENT_BLOCK_SIZE, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = lrw_serpent_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}; - struct serpent_xts_ctx { struct serpent_ctx tweak_ctx; struct serpent_ctx crypt_ctx; @@ -689,29 +596,6 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ret; } -static struct crypto_alg blk_xts_alg = { - .cra_name = "__xts-serpent-sse2", - .cra_driver_name = "__driver-xts-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_xts_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE * 2, - .max_keysize = SERPENT_MAX_KEY_SIZE * 2, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = xts_serpent_setkey, - .encrypt = xts_encrypt, - .decrypt = xts_decrypt, - }, - }, -}; - static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int key_len) { @@ -792,28 +676,133 @@ static void ablk_exit(struct crypto_tfm *tfm) cryptd_free_ablkcipher(ctx->cryptd_tfm); } -static void ablk_init_common(struct crypto_tfm *tfm, - struct cryptd_ablkcipher *cryptd_tfm) +static int ablk_init(struct crypto_tfm *tfm) { struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); + struct cryptd_ablkcipher *cryptd_tfm; + char drv_name[CRYPTO_MAX_ALG_NAME]; + + snprintf(drv_name, sizeof(drv_name), "__driver-%s", + crypto_tfm_alg_driver_name(tfm)); + + cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); ctx->cryptd_tfm = cryptd_tfm; tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + crypto_ablkcipher_reqsize(&cryptd_tfm->base); -} - -static int ablk_ecb_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); return 0; } -static struct crypto_alg ablk_ecb_alg = { +static struct crypto_alg serpent_algs[10] = { { + .cra_name = "__ecb-serpent-sse2", + .cra_driver_name = "__driver-ecb-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .setkey = serpent_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "__cbc-serpent-sse2", + .cra_driver_name = "__driver-cbc-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .setkey = serpent_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "__ctr-serpent-sse2", + .cra_driver_name = "__driver-ctr-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = serpent_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "__lrw-serpent-sse2", + .cra_driver_name = "__driver-lrw-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE + + SERPENT_BLOCK_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE + + SERPENT_BLOCK_SIZE, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = lrw_serpent_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "__xts-serpent-sse2", + .cra_driver_name = "__driver-xts-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE * 2, + .max_keysize = SERPENT_MAX_KEY_SIZE * 2, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = xts_serpent_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}, { .cra_name = "ecb(serpent)", .cra_driver_name = "ecb-serpent-sse2", .cra_priority = 400, @@ -823,8 +812,8 @@ static struct crypto_alg ablk_ecb_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), - .cra_init = ablk_ecb_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -835,20 +824,7 @@ static struct crypto_alg ablk_ecb_alg = { .decrypt = ablk_decrypt, }, }, -}; - -static int ablk_cbc_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_cbc_alg = { +}, { .cra_name = "cbc(serpent)", .cra_driver_name = "cbc-serpent-sse2", .cra_priority = 400, @@ -858,8 +834,8 @@ static struct crypto_alg ablk_cbc_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), - .cra_init = ablk_cbc_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -871,20 +847,7 @@ static struct crypto_alg ablk_cbc_alg = { .decrypt = ablk_decrypt, }, }, -}; - -static int ablk_ctr_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_ctr_alg = { +}, { .cra_name = "ctr(serpent)", .cra_driver_name = "ctr-serpent-sse2", .cra_priority = 400, @@ -894,8 +857,8 @@ static struct crypto_alg ablk_ctr_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), - .cra_init = ablk_ctr_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -908,20 +871,7 @@ static struct crypto_alg ablk_ctr_alg = { .geniv = "chainiv", }, }, -}; - -static int ablk_lrw_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_lrw_alg = { +}, { .cra_name = "lrw(serpent)", .cra_driver_name = "lrw-serpent-sse2", .cra_priority = 400, @@ -931,8 +881,8 @@ static struct crypto_alg ablk_lrw_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), - .cra_init = ablk_lrw_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -946,20 +896,7 @@ static struct crypto_alg ablk_lrw_alg = { .decrypt = ablk_decrypt, }, }, -}; - -static int ablk_xts_init(struct crypto_tfm *tfm) -{ - struct cryptd_ablkcipher *cryptd_tfm; - - cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); - ablk_init_common(tfm, cryptd_tfm); - return 0; -} - -static struct crypto_alg ablk_xts_alg = { +}, { .cra_name = "xts(serpent)", .cra_driver_name = "xts-serpent-sse2", .cra_priority = 400, @@ -969,8 +906,8 @@ static struct crypto_alg ablk_xts_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), - .cra_init = ablk_xts_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -982,84 +919,21 @@ static struct crypto_alg ablk_xts_alg = { .decrypt = ablk_decrypt, }, }, -}; +} }; static int __init serpent_sse2_init(void) { - int err; - if (!cpu_has_xmm2) { printk(KERN_INFO "SSE2 instructions are not detected.\n"); return -ENODEV; } - err = crypto_register_alg(&blk_ecb_alg); - if (err) - goto blk_ecb_err; - err = crypto_register_alg(&blk_cbc_alg); - if (err) - goto blk_cbc_err; - err = crypto_register_alg(&blk_ctr_alg); - if (err) - goto blk_ctr_err; - err = crypto_register_alg(&ablk_ecb_alg); - if (err) - goto ablk_ecb_err; - err = crypto_register_alg(&ablk_cbc_alg); - if (err) - goto ablk_cbc_err; - err = crypto_register_alg(&ablk_ctr_alg); - if (err) - goto ablk_ctr_err; - err = crypto_register_alg(&blk_lrw_alg); - if (err) - goto blk_lrw_err; - err = crypto_register_alg(&ablk_lrw_alg); - if (err) - goto ablk_lrw_err; - err = crypto_register_alg(&blk_xts_alg); - if (err) - goto blk_xts_err; - err = crypto_register_alg(&ablk_xts_alg); - if (err) - goto ablk_xts_err; - return err; - - crypto_unregister_alg(&ablk_xts_alg); -ablk_xts_err: - crypto_unregister_alg(&blk_xts_alg); -blk_xts_err: - crypto_unregister_alg(&ablk_lrw_alg); -ablk_lrw_err: - crypto_unregister_alg(&blk_lrw_alg); -blk_lrw_err: - crypto_unregister_alg(&ablk_ctr_alg); -ablk_ctr_err: - crypto_unregister_alg(&ablk_cbc_alg); -ablk_cbc_err: - crypto_unregister_alg(&ablk_ecb_alg); -ablk_ecb_err: - crypto_unregister_alg(&blk_ctr_alg); -blk_ctr_err: - crypto_unregister_alg(&blk_cbc_alg); -blk_cbc_err: - crypto_unregister_alg(&blk_ecb_alg); -blk_ecb_err: - return err; + return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); } static void __exit serpent_sse2_exit(void) { - crypto_unregister_alg(&ablk_xts_alg); - crypto_unregister_alg(&blk_xts_alg); - crypto_unregister_alg(&ablk_lrw_alg); - crypto_unregister_alg(&blk_lrw_alg); - crypto_unregister_alg(&ablk_ctr_alg); - crypto_unregister_alg(&ablk_cbc_alg); - crypto_unregister_alg(&ablk_ecb_alg); - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); + crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); } module_init(serpent_sse2_init); diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c index dc6b3fb817fc..359ae084275c 100644 --- a/arch/x86/crypto/twofish_glue.c +++ b/arch/x86/crypto/twofish_glue.c @@ -68,7 +68,7 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = TF_BLOCK_SIZE, .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 3, + .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 7fee8c152f93..408fc0c5814e 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -25,6 +25,7 @@ * */ +#include <asm/processor.h> #include <linux/crypto.h> #include <linux/init.h> #include <linux/module.h> @@ -122,28 +123,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, twofish_dec_blk, twofish_dec_blk_3way); } -static struct crypto_alg blk_ecb_alg = { - .cra_name = "ecb(twofish)", - .cra_driver_name = "ecb-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .setkey = twofish_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}; - static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -267,29 +246,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_cbc_alg = { - .cra_name = "cbc(twofish)", - .cra_driver_name = "cbc-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = twofish_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}; - static inline void u128_to_be128(be128 *dst, const u128 *src) { dst->a = cpu_to_be64(src->a); @@ -411,29 +367,6 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { - .cra_name = "ctr(twofish)", - .cra_driver_name = "ctr-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = twofish_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}; - static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) { const unsigned int bsize = TF_BLOCK_SIZE; @@ -524,30 +457,6 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm) lrw_free_table(&ctx->lrw_table); } -static struct crypto_alg blk_lrw_alg = { - .cra_name = "lrw(twofish)", - .cra_driver_name = "lrw-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, - .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = lrw_twofish_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}; - struct twofish_xts_ctx { struct twofish_ctx tweak_ctx; struct twofish_ctx crypt_ctx; @@ -614,7 +523,91 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return xts_crypt(desc, dst, src, nbytes, &req); } -static struct crypto_alg blk_xts_alg = { +static struct crypto_alg tf_algs[5] = { { + .cra_name = "ecb(twofish)", + .cra_driver_name = "ecb-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[0].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .setkey = twofish_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "cbc(twofish)", + .cra_driver_name = "cbc-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[1].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = twofish_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "ctr(twofish)", + .cra_driver_name = "ctr-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[2].cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = twofish_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "lrw(twofish)", + .cra_driver_name = "lrw-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tf_algs[3].cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, + .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = lrw_twofish_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { .cra_name = "xts(twofish)", .cra_driver_name = "xts-twofish-3way", .cra_priority = 300, @@ -624,7 +617,7 @@ static struct crypto_alg blk_xts_alg = { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), + .cra_list = LIST_HEAD_INIT(tf_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, @@ -635,50 +628,62 @@ static struct crypto_alg blk_xts_alg = { .decrypt = xts_decrypt, }, }, -}; +} }; + +static bool is_blacklisted_cpu(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) + return false; + + if (boot_cpu_data.x86 == 0x06 && + (boot_cpu_data.x86_model == 0x1c || + boot_cpu_data.x86_model == 0x26 || + boot_cpu_data.x86_model == 0x36)) { + /* + * On Atom, twofish-3way is slower than original assembler + * implementation. Twofish-3way trades off some performance in + * storing blocks in 64bit registers to allow three blocks to + * be processed parallel. Parallel operation then allows gaining + * more performance than was trade off, on out-of-order CPUs. + * However Atom does not benefit from this parallellism and + * should be blacklisted. + */ + return true; + } + + if (boot_cpu_data.x86 == 0x0f) { + /* + * On Pentium 4, twofish-3way is slower than original assembler + * implementation because excessive uses of 64bit rotate and + * left-shifts (which are really slow on P4) needed to store and + * handle 128bit block in two 64bit registers. + */ + return true; + } + + return false; +} + +static int force; +module_param(force, int, 0); +MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); int __init init(void) { - int err; + if (!force && is_blacklisted_cpu()) { + printk(KERN_INFO + "twofish-x86_64-3way: performance on this CPU " + "would be suboptimal: disabling " + "twofish-x86_64-3way.\n"); + return -ENODEV; + } - err = crypto_register_alg(&blk_ecb_alg); - if (err) - goto ecb_err; - err = crypto_register_alg(&blk_cbc_alg); - if (err) - goto cbc_err; - err = crypto_register_alg(&blk_ctr_alg); - if (err) - goto ctr_err; - err = crypto_register_alg(&blk_lrw_alg); - if (err) - goto blk_lrw_err; - err = crypto_register_alg(&blk_xts_alg); - if (err) - goto blk_xts_err; - - return 0; - - crypto_unregister_alg(&blk_xts_alg); -blk_xts_err: - crypto_unregister_alg(&blk_lrw_alg); -blk_lrw_err: - crypto_unregister_alg(&blk_ctr_alg); -ctr_err: - crypto_unregister_alg(&blk_cbc_alg); -cbc_err: - crypto_unregister_alg(&blk_ecb_alg); -ecb_err: - return err; + return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs)); } void __exit fini(void) { - crypto_unregister_alg(&blk_xts_alg); - crypto_unregister_alg(&blk_lrw_alg); - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); + crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs)); } module_init(init); diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h index 3bd04022fd0c..302a323b3f67 100644 --- a/arch/x86/include/asm/highmem.h +++ b/arch/x86/include/asm/highmem.h @@ -61,7 +61,7 @@ void *kmap(struct page *page); void kunmap(struct page *page); void *kmap_atomic_prot(struct page *page, pgprot_t prot); -void *__kmap_atomic(struct page *page); +void *kmap_atomic(struct page *page); void __kunmap_atomic(void *kvaddr); void *kmap_atomic_pfn(unsigned long pfn); void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h deleted file mode 100644 index 423bbbddf36d..000000000000 --- a/arch/x86/include/asm/irq_controller.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __IRQ_CONTROLLER__ -#define __IRQ_CONTROLLER__ - -struct irq_domain { - int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize, - u32 *out_hwirq, u32 *out_type); - void *priv; - struct device_node *controller; - struct list_head l; -}; - -#endif diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h index 644dd885f05a..60bef663609a 100644 --- a/arch/x86/include/asm/prom.h +++ b/arch/x86/include/asm/prom.h @@ -21,7 +21,6 @@ #include <asm/irq.h> #include <linux/atomic.h> #include <asm/setup.h> -#include <asm/irq_controller.h> #ifdef CONFIG_OF extern int of_ioapic; @@ -43,15 +42,6 @@ extern char cmd_line[COMMAND_LINE_SIZE]; #define pci_address_to_pio pci_address_to_pio unsigned long pci_address_to_pio(phys_addr_t addr); -/** - * irq_dispose_mapping - Unmap an interrupt - * @virq: linux virq number of the interrupt to unmap - * - * FIXME: We really should implement proper virq handling like power, - * but that's going to be major surgery. - */ -static inline void irq_dispose_mapping(unsigned int virq) { } - #define HAVE_ARCH_DEVTREE_FIXUPS #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index f76623cbe263..5d56931a15b3 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -1234,8 +1234,7 @@ static int suspend(int vetoable) struct apm_user *as; dpm_suspend_start(PMSG_SUSPEND); - - dpm_suspend_noirq(PMSG_SUSPEND); + dpm_suspend_end(PMSG_SUSPEND); local_irq_disable(); syscore_suspend(); @@ -1259,9 +1258,9 @@ static int suspend(int vetoable) syscore_resume(); local_irq_enable(); - dpm_resume_noirq(PMSG_RESUME); - + dpm_resume_start(PMSG_RESUME); dpm_resume_end(PMSG_RESUME); + queue_event(APM_NORMAL_RESUME, NULL); spin_lock(&user_list_lock); for (as = user_list; as != NULL; as = as->next) { @@ -1277,7 +1276,7 @@ static void standby(void) { int err; - dpm_suspend_noirq(PMSG_SUSPEND); + dpm_suspend_end(PMSG_SUSPEND); local_irq_disable(); syscore_suspend(); @@ -1291,7 +1290,7 @@ static void standby(void) syscore_resume(); local_irq_enable(); - dpm_resume_noirq(PMSG_RESUME); + dpm_resume_start(PMSG_RESUME); } static apm_event_t get_event(void) diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c index 642f75a68cd5..11891ca7b716 100644 --- a/arch/x86/kernel/crash_dump_32.c +++ b/arch/x86/kernel/crash_dump_32.c @@ -62,16 +62,16 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, if (!userbuf) { memcpy(buf, (vaddr + offset), csize); - kunmap_atomic(vaddr, KM_PTE0); + kunmap_atomic(vaddr); } else { if (!kdump_buf_page) { printk(KERN_WARNING "Kdump: Kdump buffer page not" " allocated\n"); - kunmap_atomic(vaddr, KM_PTE0); + kunmap_atomic(vaddr); return -EFAULT; } copy_page(kdump_buf_page, vaddr); - kunmap_atomic(vaddr, KM_PTE0); + kunmap_atomic(vaddr); if (copy_to_user(buf, (kdump_buf_page + offset), csize)) return -EFAULT; } diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 52821799a702..3ae2ced4a874 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -4,6 +4,7 @@ #include <linux/bootmem.h> #include <linux/export.h> #include <linux/io.h> +#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/list.h> #include <linux/of.h> @@ -17,64 +18,14 @@ #include <linux/initrd.h> #include <asm/hpet.h> -#include <asm/irq_controller.h> #include <asm/apic.h> #include <asm/pci_x86.h> __initdata u64 initial_dtb; char __initdata cmd_line[COMMAND_LINE_SIZE]; -static LIST_HEAD(irq_domains); -static DEFINE_RAW_SPINLOCK(big_irq_lock); int __initdata of_ioapic; -#ifdef CONFIG_X86_IO_APIC -static void add_interrupt_host(struct irq_domain *ih) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&big_irq_lock, flags); - list_add(&ih->l, &irq_domains); - raw_spin_unlock_irqrestore(&big_irq_lock, flags); -} -#endif - -static struct irq_domain *get_ih_from_node(struct device_node *controller) -{ - struct irq_domain *ih, *found = NULL; - unsigned long flags; - - raw_spin_lock_irqsave(&big_irq_lock, flags); - list_for_each_entry(ih, &irq_domains, l) { - if (ih->controller == controller) { - found = ih; - break; - } - } - raw_spin_unlock_irqrestore(&big_irq_lock, flags); - return found; -} - -unsigned int irq_create_of_mapping(struct device_node *controller, - const u32 *intspec, unsigned int intsize) -{ - struct irq_domain *ih; - u32 virq, type; - int ret; - - ih = get_ih_from_node(controller); - if (!ih) - return 0; - ret = ih->xlate(ih, intspec, intsize, &virq, &type); - if (ret) - return 0; - if (type == IRQ_TYPE_NONE) - return virq; - irq_set_irq_type(virq, type); - return virq; -} -EXPORT_SYMBOL_GPL(irq_create_of_mapping); - unsigned long pci_address_to_pio(phys_addr_t address) { /* @@ -354,36 +305,43 @@ static struct of_ioapic_type of_ioapic_type[] = }, }; -static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, - u32 *out_hwirq, u32 *out_type) +static int ioapic_xlate(struct irq_domain *domain, + struct device_node *controller, + const u32 *intspec, u32 intsize, + irq_hw_number_t *out_hwirq, u32 *out_type) { - struct mp_ioapic_gsi *gsi_cfg; struct io_apic_irq_attr attr; struct of_ioapic_type *it; - u32 line, idx, type; + u32 line, idx; + int rc; - if (intsize < 2) + if (WARN_ON(intsize < 2)) return -EINVAL; - line = *intspec; - idx = (u32) id->priv; - gsi_cfg = mp_ioapic_gsi_routing(idx); - *out_hwirq = line + gsi_cfg->gsi_base; - - intspec++; - type = *intspec; + line = intspec[0]; - if (type >= ARRAY_SIZE(of_ioapic_type)) + if (intspec[1] >= ARRAY_SIZE(of_ioapic_type)) return -EINVAL; - it = of_ioapic_type + type; - *out_type = it->out_type; + it = &of_ioapic_type[intspec[1]]; + idx = (u32) domain->host_data; set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); - return io_apic_setup_irq_pin_once(*out_hwirq, cpu_to_node(0), &attr); + rc = io_apic_setup_irq_pin_once(irq_find_mapping(domain, line), + cpu_to_node(0), &attr); + if (rc) + return rc; + + *out_hwirq = line; + *out_type = it->out_type; + return 0; } +const struct irq_domain_ops ioapic_irq_domain_ops = { + .xlate = ioapic_xlate, +}; + static void __init ioapic_add_ofnode(struct device_node *np) { struct resource r; @@ -399,13 +357,14 @@ static void __init ioapic_add_ofnode(struct device_node *np) for (i = 0; i < nr_ioapics; i++) { if (r.start == mpc_ioapic_addr(i)) { struct irq_domain *id; + struct mp_ioapic_gsi *gsi_cfg; + + gsi_cfg = mp_ioapic_gsi_routing(i); - id = kzalloc(sizeof(*id), GFP_KERNEL); + id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0, + &ioapic_irq_domain_ops, + (void*)i); BUG_ON(!id); - id->controller = np; - id->xlate = ioapic_xlate; - id->priv = (void *)i; - add_interrupt_host(id); return; } } diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index cfdc6e0ef002..31bfc6927bc0 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1283,9 +1283,9 @@ void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr) return; - vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); + vapic = kmap_atomic(vcpu->arch.apic->vapic_page); data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)); - kunmap_atomic(vapic, KM_USER0); + kunmap_atomic(vapic); apic_set_tpr(vcpu->arch.apic, data & 0xff); } @@ -1310,9 +1310,9 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) max_isr = 0; data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); - vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0); + vapic = kmap_atomic(vcpu->arch.apic->vapic_page); *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data; - kunmap_atomic(vapic, KM_USER0); + kunmap_atomic(vapic); } void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 15610285ebb6..df5a70311be8 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -92,9 +92,9 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, if (unlikely(npages != 1)) return -EFAULT; - table = kmap_atomic(page, KM_USER0); + table = kmap_atomic(page); ret = CMPXCHG(&table[index], orig_pte, new_pte); - kunmap_atomic(table, KM_USER0); + kunmap_atomic(table); kvm_release_page_dirty(page); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9cbfc0698118..bb4fd2636bc2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1162,12 +1162,12 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) */ vcpu->hv_clock.version += 2; - shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0); + shared_kaddr = kmap_atomic(vcpu->time_page); memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock, sizeof(vcpu->hv_clock)); - kunmap_atomic(shared_kaddr, KM_USER0); + kunmap_atomic(shared_kaddr); mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); return 0; @@ -3848,7 +3848,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, goto emul_write; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); kaddr += offset_in_page(gpa); switch (bytes) { case 1: @@ -3866,7 +3866,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, default: BUG(); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); kvm_release_page_dirty(page); if (!exchanged) diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index e218d5df85ff..d9b094ca7aaa 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -760,9 +760,9 @@ survive: break; } - maddr = kmap_atomic(pg, KM_USER0); + maddr = kmap_atomic(pg); memcpy(maddr + offset, from, len); - kunmap_atomic(maddr, KM_USER0); + kunmap_atomic(maddr); set_page_dirty_lock(pg); put_page(pg); up_read(¤t->mm->mmap_sem); diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index f4f29b19fac5..6f31ee56c008 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -51,11 +51,11 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) } EXPORT_SYMBOL(kmap_atomic_prot); -void *__kmap_atomic(struct page *page) +void *kmap_atomic(struct page *page) { return kmap_atomic_prot(page, kmap_prot); } -EXPORT_SYMBOL(__kmap_atomic); +EXPORT_SYMBOL(kmap_atomic); /* * This is the same as kmap_atomic() but can map memory that doesn't diff --git a/crypto/Kconfig b/crypto/Kconfig index e6cfe1a25137..6318edd6a457 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -654,6 +654,24 @@ config CRYPTO_CAMELLIA See also: <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html> +config CRYPTO_CAMELLIA_X86_64 + tristate "Camellia cipher algorithm (x86_64)" + depends on (X86 || UML_X86) && 64BIT + depends on CRYPTO + select CRYPTO_ALGAPI + select CRYPTO_LRW + select CRYPTO_XTS + help + Camellia cipher algorithm module (x86_64). + + Camellia is a symmetric key block cipher developed jointly + at NTT and Mitsubishi Electric Corporation. + + The Camellia specifies three key sizes: 128, 192 and 256 bits. + + See also: + <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html> + config CRYPTO_CAST5 tristate "CAST5 (CAST-128) cipher algorithm" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index f638063f4ea9..30f33d675330 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o obj-$(CONFIG_CRYPTO_AES) += aes_generic.o -obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o +obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o diff --git a/crypto/ahash.c b/crypto/ahash.c index ac93c99cfae8..33bc9b62e9ae 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -46,7 +46,7 @@ static int hash_walk_next(struct crypto_hash_walk *walk) unsigned int nbytes = min(walk->entrylen, ((unsigned int)(PAGE_SIZE)) - offset); - walk->data = crypto_kmap(walk->pg, 0); + walk->data = kmap_atomic(walk->pg); walk->data += offset; if (offset & alignmask) { @@ -93,7 +93,7 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) return nbytes; } - crypto_kunmap(walk->data, 0); + kunmap_atomic(walk->data); crypto_yield(walk->flags); if (err) diff --git a/crypto/algapi.c b/crypto/algapi.c index 9d4a9fe913f8..056571b85445 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -405,6 +405,41 @@ int crypto_unregister_alg(struct crypto_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_alg); +int crypto_register_algs(struct crypto_alg *algs, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = crypto_register_alg(&algs[i]); + if (ret) + goto err; + } + + return 0; + +err: + for (--i; i >= 0; --i) + crypto_unregister_alg(&algs[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(crypto_register_algs); + +int crypto_unregister_algs(struct crypto_alg *algs, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = crypto_unregister_alg(&algs[i]); + if (ret) + pr_err("Failed to unregister %s %s: %d\n", + algs[i].cra_driver_name, algs[i].cra_name, ret); + } + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_unregister_algs); + int crypto_register_template(struct crypto_template *tmpl) { struct crypto_template *q; diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c index 0d5a90ca6501..361b5e8239bc 100644 --- a/crypto/async_tx/async_memcpy.c +++ b/crypto/async_tx/async_memcpy.c @@ -79,13 +79,13 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset, /* wait for any prerequisite operations */ async_tx_quiesce(&submit->depend_tx); - dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset; - src_buf = kmap_atomic(src, KM_USER1) + src_offset; + dest_buf = kmap_atomic(dest) + dest_offset; + src_buf = kmap_atomic(src) + src_offset; memcpy(dest_buf, src_buf, len); - kunmap_atomic(src_buf, KM_USER1); - kunmap_atomic(dest_buf, KM_USER0); + kunmap_atomic(src_buf); + kunmap_atomic(dest_buf); async_tx_sync_epilog(submit); } diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 1e61d1a888b2..4dd80c725498 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -43,22 +43,22 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, static inline void blkcipher_map_src(struct blkcipher_walk *walk) { - walk->src.virt.addr = scatterwalk_map(&walk->in, 0); + walk->src.virt.addr = scatterwalk_map(&walk->in); } static inline void blkcipher_map_dst(struct blkcipher_walk *walk) { - walk->dst.virt.addr = scatterwalk_map(&walk->out, 1); + walk->dst.virt.addr = scatterwalk_map(&walk->out); } static inline void blkcipher_unmap_src(struct blkcipher_walk *walk) { - scatterwalk_unmap(walk->src.virt.addr, 0); + scatterwalk_unmap(walk->src.virt.addr); } static inline void blkcipher_unmap_dst(struct blkcipher_walk *walk) { - scatterwalk_unmap(walk->dst.virt.addr, 1); + scatterwalk_unmap(walk->dst.virt.addr); } /* Get a spot of the specified length that does not straddle a page. diff --git a/crypto/camellia.c b/crypto/camellia_generic.c index 64cff46ea5e4..f7aaaaf86982 100644 --- a/crypto/camellia.c +++ b/crypto/camellia_generic.c @@ -337,43 +337,40 @@ static const u32 camellia_sp4404[256] = { /* * macros */ -#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ - do { \ +#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) ({ \ w0 = ll; \ ll = (ll << bits) + (lr >> (32 - bits)); \ lr = (lr << bits) + (rl >> (32 - bits)); \ rl = (rl << bits) + (rr >> (32 - bits)); \ rr = (rr << bits) + (w0 >> (32 - bits)); \ - } while (0) +}) -#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ - do { \ +#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) ({ \ w0 = ll; \ w1 = lr; \ ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ - } while (0) +}) -#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ - do { \ +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) ({ \ il = xl ^ kl; \ ir = xr ^ kr; \ t0 = il >> 16; \ t1 = ir >> 16; \ - yl = camellia_sp1110[(u8)(ir )] \ - ^ camellia_sp0222[ (t1 >> 8)] \ - ^ camellia_sp3033[(u8)(t1 )] \ + yl = camellia_sp1110[(u8)(ir)] \ + ^ camellia_sp0222[(u8)(t1 >> 8)] \ + ^ camellia_sp3033[(u8)(t1)] \ ^ camellia_sp4404[(u8)(ir >> 8)]; \ - yr = camellia_sp1110[ (t0 >> 8)] \ - ^ camellia_sp0222[(u8)(t0 )] \ + yr = camellia_sp1110[(u8)(t0 >> 8)] \ + ^ camellia_sp0222[(u8)(t0)] \ ^ camellia_sp3033[(u8)(il >> 8)] \ - ^ camellia_sp4404[(u8)(il )]; \ + ^ camellia_sp4404[(u8)(il)]; \ yl ^= yr; \ yr = ror32(yr, 8); \ yr ^= yl; \ - } while (0) +}) #define SUBKEY_L(INDEX) (subkey[(INDEX)*2]) #define SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1]) @@ -382,7 +379,6 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) { u32 dw, tl, tr; u32 kw4l, kw4r; - int i; /* absorb kw2 to other subkeys */ /* round 2 */ @@ -557,24 +553,6 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_L(32) = subL[32] ^ subL[31]; /* kw3 */ SUBKEY_R(32) = subR[32] ^ subR[31]; } - - /* apply the inverse of the last half of P-function */ - i = 2; - do { - dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */ - SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw; - dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */ - SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw; - dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */ - SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw; - dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */ - SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw; - dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 8);/* round 5 */ - SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw; - dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */ - SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw; - i += 8; - } while (i < max); } static void camellia_setup128(const unsigned char *key, u32 *subkey) @@ -851,8 +829,7 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) /* * Encrypt/decrypt */ -#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ - do { \ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) ({ \ t0 = kll; \ t2 = krr; \ t0 &= ll; \ @@ -865,23 +842,23 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) t1 |= lr; \ ll ^= t1; \ rr ^= rol32(t3, 1); \ - } while (0) +}) -#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) \ - do { \ +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) ({ \ + yl ^= kl; \ + yr ^= kr; \ ir = camellia_sp1110[(u8)xr]; \ - il = camellia_sp1110[ (xl >> 24)]; \ - ir ^= camellia_sp0222[ (xr >> 24)]; \ + il = camellia_sp1110[(u8)(xl >> 24)]; \ + ir ^= camellia_sp0222[(u8)(xr >> 24)]; \ il ^= camellia_sp0222[(u8)(xl >> 16)]; \ ir ^= camellia_sp3033[(u8)(xr >> 16)]; \ il ^= camellia_sp3033[(u8)(xl >> 8)]; \ ir ^= camellia_sp4404[(u8)(xr >> 8)]; \ il ^= camellia_sp4404[(u8)xl]; \ - il ^= kl; \ - ir ^= il ^ kr; \ + ir ^= il; \ yl ^= ir; \ - yr ^= ror32(il, 8) ^ ir; \ - } while (0) + yr ^= ror32(il, 8) ^ ir; \ +}) /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) @@ -893,7 +870,7 @@ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) io[1] ^= SUBKEY_R(0); /* main iteration */ -#define ROUNDS(i) do { \ +#define ROUNDS(i) ({ \ CAMELLIA_ROUNDSM(io[0], io[1], \ SUBKEY_L(i + 2), SUBKEY_R(i + 2), \ io[2], io[3], il, ir); \ @@ -912,13 +889,13 @@ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) CAMELLIA_ROUNDSM(io[2], io[3], \ SUBKEY_L(i + 7), SUBKEY_R(i + 7), \ io[0], io[1], il, ir); \ -} while (0) -#define FLS(i) do { \ +}) +#define FLS(i) ({ \ CAMELLIA_FLS(io[0], io[1], io[2], io[3], \ SUBKEY_L(i + 0), SUBKEY_R(i + 0), \ SUBKEY_L(i + 1), SUBKEY_R(i + 1), \ t0, t1, il, ir); \ -} while (0) +}) ROUNDS(0); FLS(8); @@ -948,7 +925,7 @@ static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i) io[1] ^= SUBKEY_R(i); /* main iteration */ -#define ROUNDS(i) do { \ +#define ROUNDS(i) ({ \ CAMELLIA_ROUNDSM(io[0], io[1], \ SUBKEY_L(i + 7), SUBKEY_R(i + 7), \ io[2], io[3], il, ir); \ @@ -967,13 +944,13 @@ static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i) CAMELLIA_ROUNDSM(io[2], io[3], \ SUBKEY_L(i + 2), SUBKEY_R(i + 2), \ io[0], io[1], il, ir); \ -} while (0) -#define FLS(i) do { \ +}) +#define FLS(i) ({ \ CAMELLIA_FLS(io[0], io[1], io[2], io[3], \ SUBKEY_L(i + 1), SUBKEY_R(i + 1), \ SUBKEY_L(i + 0), SUBKEY_R(i + 0), \ t0, t1, il, ir); \ -} while (0) +}) if (i == 32) { ROUNDS(24); @@ -1035,6 +1012,7 @@ static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)in; __be32 *dst = (__be32 *)out; + unsigned int max; u32 tmp[4]; @@ -1043,9 +1021,12 @@ static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) tmp[2] = be32_to_cpu(src[2]); tmp[3] = be32_to_cpu(src[3]); - camellia_do_encrypt(cctx->key_table, tmp, - cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ - ); + if (cctx->key_length == 16) + max = 24; + else + max = 32; /* for key lengths of 24 and 32 */ + + camellia_do_encrypt(cctx->key_table, tmp, max); /* do_encrypt returns 0,1 swapped with 2,3 */ dst[0] = cpu_to_be32(tmp[2]); @@ -1059,6 +1040,7 @@ static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)in; __be32 *dst = (__be32 *)out; + unsigned int max; u32 tmp[4]; @@ -1067,9 +1049,12 @@ static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) tmp[2] = be32_to_cpu(src[2]); tmp[3] = be32_to_cpu(src[3]); - camellia_do_decrypt(cctx->key_table, tmp, - cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ - ); + if (cctx->key_length == 16) + max = 24; + else + max = 32; /* for key lengths of 24 and 32 */ + + camellia_do_decrypt(cctx->key_table, tmp, max); /* do_decrypt returns 0,1 swapped with 2,3 */ dst[0] = cpu_to_be32(tmp[2]); @@ -1114,3 +1099,4 @@ module_exit(camellia_fini); MODULE_DESCRIPTION("Camellia Cipher Algorithm"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("camellia"); diff --git a/crypto/ccm.c b/crypto/ccm.c index c36d654cf56a..32fe1bb5decb 100644 --- a/crypto/ccm.c +++ b/crypto/ccm.c @@ -216,12 +216,12 @@ static void get_data_to_compute(struct crypto_cipher *tfm, scatterwalk_start(&walk, sg_next(walk.sg)); n = scatterwalk_clamp(&walk, len); } - data_src = scatterwalk_map(&walk, 0); + data_src = scatterwalk_map(&walk); compute_mac(tfm, data_src, n, pctx); len -= n; - scatterwalk_unmap(data_src, 0); + scatterwalk_unmap(data_src); scatterwalk_advance(&walk, n); scatterwalk_done(&walk, 0, len); if (len) diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index b6ac1387770c..f76e42bcc6e7 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -304,7 +304,7 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh, static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { - int exact; + int exact = 0; const char *name; struct crypto_alg *alg; struct crypto_user_alg *p = nlmsg_data(nlh); diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 41e529af0773..7281b8a93ad3 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -40,9 +40,9 @@ void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) } EXPORT_SYMBOL_GPL(scatterwalk_start); -void *scatterwalk_map(struct scatter_walk *walk, int out) +void *scatterwalk_map(struct scatter_walk *walk) { - return crypto_kmap(scatterwalk_page(walk), out) + + return kmap_atomic(scatterwalk_page(walk)) + offset_in_page(walk->offset); } EXPORT_SYMBOL_GPL(scatterwalk_map); @@ -83,9 +83,9 @@ void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, if (len_this_page > nbytes) len_this_page = nbytes; - vaddr = scatterwalk_map(walk, out); + vaddr = scatterwalk_map(walk); memcpy_dir(buf, vaddr, len_this_page, out); - scatterwalk_unmap(vaddr, out); + scatterwalk_unmap(vaddr); scatterwalk_advance(walk, len_this_page); diff --git a/crypto/shash.c b/crypto/shash.c index 9100912716ae..21fc12e2378f 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -281,10 +281,10 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { void *data; - data = crypto_kmap(sg_page(sg), 0); + data = kmap_atomic(sg_page(sg)); err = crypto_shash_digest(desc, data + offset, nbytes, req->result); - crypto_kunmap(data, 0); + kunmap_atomic(data); crypto_yield(desc->flags); } else err = crypto_shash_init(desc) ?: @@ -420,9 +420,9 @@ static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg, desc->flags = hdesc->flags; - data = crypto_kmap(sg_page(sg), 0); + data = kmap_atomic(sg_page(sg)); err = crypto_shash_digest(desc, data + offset, nbytes, out); - crypto_kunmap(data, 0); + kunmap_atomic(data); crypto_yield(desc->flags); goto out; } diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 7736a9f05aba..8f147bff0980 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1297,6 +1297,18 @@ static int do_test(int m) speed_template_16_24_32); test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); + test_cipher_speed("ctr(camellia)", ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_cipher_speed("ctr(camellia)", DECRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_cipher_speed("lrw(camellia)", ENCRYPT, sec, NULL, 0, + speed_template_32_40_48); + test_cipher_speed("lrw(camellia)", DECRYPT, sec, NULL, 0, + speed_template_32_40_48); + test_cipher_speed("xts(camellia)", ENCRYPT, sec, NULL, 0, + speed_template_32_48_64); + test_cipher_speed("xts(camellia)", DECRYPT, sec, NULL, 0, + speed_template_32_48_64); break; case 206: diff --git a/crypto/testmgr.c b/crypto/testmgr.c index bb54b882d738..5674878ff6c1 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1846,6 +1846,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "ctr(camellia)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = camellia_ctr_enc_tv_template, + .count = CAMELLIA_CTR_ENC_TEST_VECTORS + }, + .dec = { + .vecs = camellia_ctr_dec_tv_template, + .count = CAMELLIA_CTR_DEC_TEST_VECTORS + } + } + } + }, { .alg = "ctr(serpent)", .test = alg_test_skcipher, .suite = { @@ -2297,6 +2312,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "lrw(camellia)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = camellia_lrw_enc_tv_template, + .count = CAMELLIA_LRW_ENC_TEST_VECTORS + }, + .dec = { + .vecs = camellia_lrw_dec_tv_template, + .count = CAMELLIA_LRW_DEC_TEST_VECTORS + } + } + } + }, { .alg = "lrw(serpent)", .test = alg_test_skcipher, .suite = { @@ -2634,6 +2664,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "xts(camellia)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = camellia_xts_enc_tv_template, + .count = CAMELLIA_XTS_ENC_TEST_VECTORS + }, + .dec = { + .vecs = camellia_xts_dec_tv_template, + .count = CAMELLIA_XTS_DEC_TEST_VECTORS + } + } + } + }, { .alg = "xts(serpent)", .test = alg_test_skcipher, .suite = { diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 43e84d32b341..36e5a8ee0e1e 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -11332,10 +11332,16 @@ static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { /* * CAMELLIA test vectors. */ -#define CAMELLIA_ENC_TEST_VECTORS 3 -#define CAMELLIA_DEC_TEST_VECTORS 3 -#define CAMELLIA_CBC_ENC_TEST_VECTORS 2 -#define CAMELLIA_CBC_DEC_TEST_VECTORS 2 +#define CAMELLIA_ENC_TEST_VECTORS 4 +#define CAMELLIA_DEC_TEST_VECTORS 4 +#define CAMELLIA_CBC_ENC_TEST_VECTORS 3 +#define CAMELLIA_CBC_DEC_TEST_VECTORS 3 +#define CAMELLIA_CTR_ENC_TEST_VECTORS 2 +#define CAMELLIA_CTR_DEC_TEST_VECTORS 2 +#define CAMELLIA_LRW_ENC_TEST_VECTORS 8 +#define CAMELLIA_LRW_DEC_TEST_VECTORS 8 +#define CAMELLIA_XTS_ENC_TEST_VECTORS 5 +#define CAMELLIA_XTS_DEC_TEST_VECTORS 5 static struct cipher_testvec camellia_enc_tv_template[] = { { @@ -11372,6 +11378,27 @@ static struct cipher_testvec camellia_enc_tv_template[] = { "\x20\xef\x7c\x91\x9e\x3a\x75\x09", .rlen = 16, }, + { /* Generated with Crypto++ */ + .key = "\x3F\x85\x62\x3F\x1C\xF9\xD6\x1C" + "\xF9\xD6\xB3\x90\x6D\x4A\x90\x6D" + "\x4A\x27\x04\xE1\x27\x04\xE1\xBE" + "\x9B\x78\xBE\x9B\x78\x55\x32\x0F", + .klen = 32, + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", + .ilen = 48, + .result = "\xED\xCD\xDB\xB8\x68\xCE\xBD\xEA" + "\x9D\x9D\xCD\x9F\x4F\xFC\x4D\xB7" + "\xA5\xFF\x6F\x43\x0F\xBA\x32\x04" + "\xB3\xC2\xB9\x03\xAA\x91\x56\x29" + "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9" + "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A", + .rlen = 48, + }, }; static struct cipher_testvec camellia_dec_tv_template[] = { @@ -11409,6 +11436,27 @@ static struct cipher_testvec camellia_dec_tv_template[] = { "\xfe\xdc\xba\x98\x76\x54\x32\x10", .rlen = 16, }, + { /* Generated with Crypto++ */ + .key = "\x3F\x85\x62\x3F\x1C\xF9\xD6\x1C" + "\xF9\xD6\xB3\x90\x6D\x4A\x90\x6D" + "\x4A\x27\x04\xE1\x27\x04\xE1\xBE" + "\x9B\x78\xBE\x9B\x78\x55\x32\x0F", + .klen = 32, + .input = "\xED\xCD\xDB\xB8\x68\xCE\xBD\xEA" + "\x9D\x9D\xCD\x9F\x4F\xFC\x4D\xB7" + "\xA5\xFF\x6F\x43\x0F\xBA\x32\x04" + "\xB3\xC2\xB9\x03\xAA\x91\x56\x29" + "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9" + "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A", + .ilen = 48, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", + .rlen = 48, + }, }; static struct cipher_testvec camellia_cbc_enc_tv_template[] = { @@ -11440,6 +11488,29 @@ static struct cipher_testvec camellia_cbc_enc_tv_template[] = { "\x15\x78\xe0\x5e\xf2\xcb\x87\x16", .rlen = 32, }, + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", + .ilen = 48, + .result = "\xCD\x3E\x2A\x3B\x3E\x94\xC5\x77" + "\xBA\xBB\x5B\xB1\xDE\x7B\xA4\x40" + "\x88\x39\xE3\xFD\x94\x4B\x25\x58" + "\xE1\x4B\xC4\x18\x7A\xFD\x17\x2B" + "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27" + "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01", + .rlen = 48, + }, }; static struct cipher_testvec camellia_cbc_dec_tv_template[] = { @@ -11471,6 +11542,1310 @@ static struct cipher_testvec camellia_cbc_dec_tv_template[] = { "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", .rlen = 32, }, + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\xCD\x3E\x2A\x3B\x3E\x94\xC5\x77" + "\xBA\xBB\x5B\xB1\xDE\x7B\xA4\x40" + "\x88\x39\xE3\xFD\x94\x4B\x25\x58" + "\xE1\x4B\xC4\x18\x7A\xFD\x17\x2B" + "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27" + "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01", + .ilen = 48, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", + .rlen = 48, + }, +}; + +static struct cipher_testvec camellia_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", + .ilen = 48, + .result = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" + "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" + "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" + "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" + "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" + "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C", + .rlen = 48, + }, + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D", + .ilen = 51, + .result = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" + "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" + "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" + "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" + "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" + "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C" + "\x1E\x43\xEF", + .rlen = 51, + }, +}; + +static struct cipher_testvec camellia_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" + "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" + "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" + "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" + "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" + "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C", + .ilen = 48, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", + .rlen = 48, + }, + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" + "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" + "\x78\xBE\x9B\x78\x55\x32\x0F\x55", + .klen = 32, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" + "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", + .input = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" + "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" + "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" + "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" + "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" + "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C" + "\x1E\x43\xEF", + .ilen = 51, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" + "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" + "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" + "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" + "\xDF\x76\x0D", + .rlen = 51, + }, + +}; + +static struct cipher_testvec camellia_lrw_enc_tv_template[] = { + /* Generated from AES-LRW test vectors */ + { + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" + "\x4c\x26\x84\x14\xb5\x68\x01\x85" + "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03" + "\xee\x5a\x83\x0c\xcc\x09\x4c\x87", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x92\x68\x19\xd7\xb7\x5b\x0a\x31" + "\x97\xcc\x72\xbe\x99\x17\xeb\x3e", + .rlen = 16, + }, { + .key = "\x59\x70\x47\x14\xf5\x57\x47\x8c" + "\xd7\x79\xe8\x0f\x54\x88\x79\x44" + "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea" + "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x02", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x73\x09\xb7\x50\xb6\x77\x30\x50" + "\x5c\x8a\x9c\x26\x77\x9d\xfc\x4a", + .rlen = 16, + }, { + .key = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50" + "\x30\xfe\x69\xe2\x37\x7f\x98\x47" + "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6" + "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x02\x00\x00\x00\x00", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x90\xae\x83\xe0\x22\xb9\x60\x91" + "\xfa\xa9\xb7\x98\xe3\xed\x87\x01", + .rlen = 16, + }, { + .key = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15" + "\x25\x83\xf7\x3c\x1f\x01\x28\x74" + "\xca\xc6\xbc\x35\x4d\x4a\x65\x54" + "\x90\xae\x61\xcf\x7b\xae\xbd\xcc" + "\xad\xe4\x94\xc5\x4a\x29\xae\x70", + .klen = 40, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x99\xe9\x6e\xd4\xc9\x21\xa5\xf0" + "\xd8\x83\xef\xd9\x07\x16\x5f\x35", + .rlen = 16, + }, { + .key = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff" + "\xf8\x86\xce\xac\x93\xc5\xad\xc6" + "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd" + "\x52\x13\xb2\xb7\xf0\xff\x11\xd8" + "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f", + .klen = 40, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x02\x00\x00\x00\x00", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x42\x88\xf4\xcb\x21\x11\x6d\x8e" + "\xde\x1a\xf2\x29\xf1\x4a\xe0\x15", + .rlen = 16, + }, { + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" + "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" + "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" + "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" + "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x40\xaa\x34\x86\x4a\x8f\x78\xb9" + "\xdb\xdb\x0f\x3d\x48\x70\xbe\x8d", + .rlen = 16, + }, { + .key = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d" + "\xd4\x70\x98\x0b\xc7\x95\x84\xc8" + "\xb2\xfb\x64\xce\x60\x97\x87\x8d" + "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7" + "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4" + "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x02\x00\x00\x00\x00", + .input = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .ilen = 16, + .result = "\x04\xab\x28\x37\x31\x7a\x26\xab" + "\xa1\x70\x1b\x9c\xe7\xdd\x83\xff", + .rlen = 16, + }, { + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" + "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" + "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" + "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" + "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x05\x11\xb7\x18\xab\xc6\x2d\xac" + "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c" + "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8" + "\x50\x38\x1f\x71\x49\xb6\x57\xd6" + "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90" + "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6" + "\xad\x1e\x9e\x20\x5f\x38\xbe\x04" + "\xda\x10\x8e\xed\xa2\xa4\x87\xab" + "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c" + "\xc9\xac\x42\x31\x95\x7c\xc9\x04" + "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6" + "\x15\xd7\x3f\x4f\x2f\x66\x69\x03" + "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65" + "\x4c\x96\x12\xed\x7c\x92\x03\x01" + "\x6f\xbc\x35\x93\xac\xf1\x27\xf1" + "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50" + "\x89\xa4\x8e\x66\x44\x85\xcc\xfd" + "\x33\x14\x70\xe3\x96\xb2\xc3\xd3" + "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5" + "\x2d\x64\x75\xdd\xb4\x54\xe6\x74" + "\x8c\xd3\x9d\x9e\x86\xab\x51\x53" + "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40" + "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5" + "\x76\x12\x73\x44\x1a\x56\xd7\x72" + "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda" + "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd" + "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60" + "\x1a\xe2\x70\x85\x58\xc2\x1b\x09" + "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9" + "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8" + "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8" + "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10" + "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1" + "\x90\x3e\x76\x4a\x74\xa4\x21\x2c" + "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e" + "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f" + "\x8d\x23\x31\x74\x84\xeb\x88\x6e" + "\xcc\xb9\xbc\x22\x83\x19\x07\x22" + "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78" + "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5" + "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41" + "\x3c\xce\x8f\x42\x60\x71\xa7\x75" + "\x08\x40\x65\x8a\x82\xbf\xf5\x43" + "\x71\x96\xa9\x4d\x44\x8a\x20\xbe" + "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65" + "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9" + "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4" + "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a" + "\x62\x73\x65\xfd\x46\x63\x25\x3d" + "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf" + "\x24\xf3\xb4\xac\x64\xba\xdf\x4b" + "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7" + "\xc5\x68\x77\x84\x32\x2b\xcc\x85" + "\x74\x96\xf0\x12\x77\x61\xb9\xeb" + "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8" + "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24" + "\xda\x39\x87\x45\xc0\x2b\xbb\x01" + "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce" + "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6" + "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32" + "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45" + "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6" + "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" + "\x21\xc4\xc2\x75\x67\x89\x37\x0a", + .ilen = 512, + .result = "\x90\x69\x8e\xf2\x14\x86\x59\xf9" + "\xec\xe7\xfa\x3f\x48\x9d\x7f\x96" + "\x67\x76\xac\x2c\xd2\x63\x18\x93" + "\x13\xf8\xf1\xf6\x71\x77\xb3\xee" + "\x93\xb2\xcc\xf3\x26\xc1\x16\x4f" + "\xd4\xe8\x43\xc1\x68\xa3\x3e\x06" + "\x38\x51\xff\xa8\xb9\xa4\xeb\xb1" + "\x62\xdd\x78\x81\xea\x1d\xef\x04" + "\x1d\x07\xc1\x67\xc8\xd6\x77\xa1" + "\x84\x95\xf4\x9a\xd9\xbc\x2d\xe2" + "\xf6\x80\xfc\x91\x2a\xbc\x42\xa0" + "\x40\x41\x69\xaa\x71\xc0\x37\xec" + "\x39\xf3\xf2\xec\x82\xc3\x88\x79" + "\xbc\xc3\xaa\xb7\xcf\x6a\x72\x80" + "\x4c\xf4\x84\x8f\x13\x9e\x94\x5c" + "\xe5\xb2\x91\xbb\x92\x51\x4d\xf1" + "\xd6\x0d\x71\x6b\x7a\xc2\x2f\x12" + "\x6f\x75\xc7\x80\x99\x50\x84\xcf" + "\xa8\xeb\xd6\xe1\x1c\x59\x81\x7e" + "\xb9\xb3\xde\x7a\x93\x14\x12\xa2" + "\xf7\x43\xb3\x9d\x1a\x87\x65\x91" + "\x42\x08\x40\x82\x06\x1c\x2d\x55" + "\x6e\x48\xd5\x74\x07\x6e\x9d\x80" + "\xeb\xb4\x97\xa1\x36\xdf\xfa\x74" + "\x79\x7f\x5a\x75\xe7\x71\xc8\x8c" + "\x7e\xf8\x3a\x77\xcd\x32\x05\xf9" + "\x3d\xd4\xe9\xa2\xbb\xc4\x8b\x83" + "\x42\x5c\x82\xfa\xe9\x4b\x96\x3b" + "\x7f\x89\x8b\xf9\xf1\x87\xda\xf0" + "\x87\xef\x13\x5d\xf0\xe2\xc5\xc1" + "\xed\x14\xa9\x57\x19\x63\x40\x04" + "\x24\xeb\x6e\x19\xd1\x3d\x70\x78" + "\xeb\xda\x55\x70\x2c\x4f\x41\x5b" + "\x56\x9f\x1a\xd3\xac\xf1\xc0\xc3" + "\x21\xec\xd7\xd2\x55\x32\x7c\x2e" + "\x3c\x48\x8e\xb4\x85\x35\x47\xfe" + "\xe2\x88\x79\x98\x6a\xc9\x8d\xff" + "\xe9\x89\x6e\xb8\xe2\x97\x00\xbd" + "\xa4\x8f\xba\xd0\x8c\xcb\x79\x99" + "\xb3\xb2\xb2\x7a\xc3\xb7\xef\x75" + "\x23\x52\x76\xc3\x50\x6e\x66\xf8" + "\xa2\xe2\xce\xba\x40\x21\x3f\xc9" + "\x0a\x32\x7f\xf7\x08\x8c\x66\xcf" + "\xd3\xdf\x57\x59\x83\xb8\xe1\x85" + "\xd6\x8f\xfb\x48\x1f\x3a\xc4\x2f" + "\xb4\x2d\x58\xab\xd8\x7f\x5e\x3a" + "\xbc\x62\x3e\xe2\x6a\x52\x0d\x76" + "\x2f\x1c\x1a\x30\xed\x95\x2a\x44" + "\x35\xa5\x83\x04\x84\x01\x99\x56" + "\xb7\xe3\x10\x96\xfa\xdc\x19\xdd" + "\xe2\x7f\xcb\xa0\x49\x1b\xff\x4c" + "\x73\xf6\xbb\x94\x00\xe8\xa9\x3d" + "\xe2\x20\xe9\x3f\xfa\x07\x5d\x77" + "\x06\xd5\x4f\x4d\x02\xb8\x40\x1b" + "\x30\xed\x1a\x50\x19\xef\xc4\x2c" + "\x02\xd9\xc5\xd3\x11\x33\x37\xe5" + "\x2b\xa3\x95\xa6\xee\xd8\x74\x1d" + "\x68\xa0\xeb\xbf\xdd\x5e\x99\x96" + "\x91\xc3\x94\x24\xa5\x12\xa2\x37" + "\xb3\xac\xcf\x2a\xfd\x55\x34\xfe" + "\x79\x92\x3e\xe6\x1b\x49\x57\x5d" + "\x93\x6c\x01\xf7\xcc\x4e\x20\xd1" + "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9" + "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95", + .rlen = 512, + }, +}; + +static struct cipher_testvec camellia_lrw_dec_tv_template[] = { + /* Generated from AES-LRW test vectors */ + /* same as enc vectors with input and result reversed */ + { + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" + "\x4c\x26\x84\x14\xb5\x68\x01\x85" + "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03" + "\xee\x5a\x83\x0c\xcc\x09\x4c\x87", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x92\x68\x19\xd7\xb7\x5b\x0a\x31" + "\x97\xcc\x72\xbe\x99\x17\xeb\x3e", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\x59\x70\x47\x14\xf5\x57\x47\x8c" + "\xd7\x79\xe8\x0f\x54\x88\x79\x44" + "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea" + "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x02", + .input = "\x73\x09\xb7\x50\xb6\x77\x30\x50" + "\x5c\x8a\x9c\x26\x77\x9d\xfc\x4a", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50" + "\x30\xfe\x69\xe2\x37\x7f\x98\x47" + "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6" + "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x02\x00\x00\x00\x00", + .input = "\x90\xae\x83\xe0\x22\xb9\x60\x91" + "\xfa\xa9\xb7\x98\xe3\xed\x87\x01", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15" + "\x25\x83\xf7\x3c\x1f\x01\x28\x74" + "\xca\xc6\xbc\x35\x4d\x4a\x65\x54" + "\x90\xae\x61\xcf\x7b\xae\xbd\xcc" + "\xad\xe4\x94\xc5\x4a\x29\xae\x70", + .klen = 40, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x99\xe9\x6e\xd4\xc9\x21\xa5\xf0" + "\xd8\x83\xef\xd9\x07\x16\x5f\x35", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff" + "\xf8\x86\xce\xac\x93\xc5\xad\xc6" + "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd" + "\x52\x13\xb2\xb7\xf0\xff\x11\xd8" + "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f", + .klen = 40, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x02\x00\x00\x00\x00", + .input = "\x42\x88\xf4\xcb\x21\x11\x6d\x8e" + "\xde\x1a\xf2\x29\xf1\x4a\xe0\x15", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" + "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" + "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" + "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" + "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x40\xaa\x34\x86\x4a\x8f\x78\xb9" + "\xdb\xdb\x0f\x3d\x48\x70\xbe\x8d", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d" + "\xd4\x70\x98\x0b\xc7\x95\x84\xc8" + "\xb2\xfb\x64\xce\x60\x97\x87\x8d" + "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7" + "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4" + "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x02\x00\x00\x00\x00", + .input = "\x04\xab\x28\x37\x31\x7a\x26\xab" + "\xa1\x70\x1b\x9c\xe7\xdd\x83\xff", + .ilen = 16, + .result = "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x41\x42\x43\x44\x45\x46", + .rlen = 16, + }, { + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" + "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" + "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" + "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" + "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", + .klen = 48, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x01", + .input = "\x90\x69\x8e\xf2\x14\x86\x59\xf9" + "\xec\xe7\xfa\x3f\x48\x9d\x7f\x96" + "\x67\x76\xac\x2c\xd2\x63\x18\x93" + "\x13\xf8\xf1\xf6\x71\x77\xb3\xee" + "\x93\xb2\xcc\xf3\x26\xc1\x16\x4f" + "\xd4\xe8\x43\xc1\x68\xa3\x3e\x06" + "\x38\x51\xff\xa8\xb9\xa4\xeb\xb1" + "\x62\xdd\x78\x81\xea\x1d\xef\x04" + "\x1d\x07\xc1\x67\xc8\xd6\x77\xa1" + "\x84\x95\xf4\x9a\xd9\xbc\x2d\xe2" + "\xf6\x80\xfc\x91\x2a\xbc\x42\xa0" + "\x40\x41\x69\xaa\x71\xc0\x37\xec" + "\x39\xf3\xf2\xec\x82\xc3\x88\x79" + "\xbc\xc3\xaa\xb7\xcf\x6a\x72\x80" + "\x4c\xf4\x84\x8f\x13\x9e\x94\x5c" + "\xe5\xb2\x91\xbb\x92\x51\x4d\xf1" + "\xd6\x0d\x71\x6b\x7a\xc2\x2f\x12" + "\x6f\x75\xc7\x80\x99\x50\x84\xcf" + "\xa8\xeb\xd6\xe1\x1c\x59\x81\x7e" + "\xb9\xb3\xde\x7a\x93\x14\x12\xa2" + "\xf7\x43\xb3\x9d\x1a\x87\x65\x91" + "\x42\x08\x40\x82\x06\x1c\x2d\x55" + "\x6e\x48\xd5\x74\x07\x6e\x9d\x80" + "\xeb\xb4\x97\xa1\x36\xdf\xfa\x74" + "\x79\x7f\x5a\x75\xe7\x71\xc8\x8c" + "\x7e\xf8\x3a\x77\xcd\x32\x05\xf9" + "\x3d\xd4\xe9\xa2\xbb\xc4\x8b\x83" + "\x42\x5c\x82\xfa\xe9\x4b\x96\x3b" + "\x7f\x89\x8b\xf9\xf1\x87\xda\xf0" + "\x87\xef\x13\x5d\xf0\xe2\xc5\xc1" + "\xed\x14\xa9\x57\x19\x63\x40\x04" + "\x24\xeb\x6e\x19\xd1\x3d\x70\x78" + "\xeb\xda\x55\x70\x2c\x4f\x41\x5b" + "\x56\x9f\x1a\xd3\xac\xf1\xc0\xc3" + "\x21\xec\xd7\xd2\x55\x32\x7c\x2e" + "\x3c\x48\x8e\xb4\x85\x35\x47\xfe" + "\xe2\x88\x79\x98\x6a\xc9\x8d\xff" + "\xe9\x89\x6e\xb8\xe2\x97\x00\xbd" + "\xa4\x8f\xba\xd0\x8c\xcb\x79\x99" + "\xb3\xb2\xb2\x7a\xc3\xb7\xef\x75" + "\x23\x52\x76\xc3\x50\x6e\x66\xf8" + "\xa2\xe2\xce\xba\x40\x21\x3f\xc9" + "\x0a\x32\x7f\xf7\x08\x8c\x66\xcf" + "\xd3\xdf\x57\x59\x83\xb8\xe1\x85" + "\xd6\x8f\xfb\x48\x1f\x3a\xc4\x2f" + "\xb4\x2d\x58\xab\xd8\x7f\x5e\x3a" + "\xbc\x62\x3e\xe2\x6a\x52\x0d\x76" + "\x2f\x1c\x1a\x30\xed\x95\x2a\x44" + "\x35\xa5\x83\x04\x84\x01\x99\x56" + "\xb7\xe3\x10\x96\xfa\xdc\x19\xdd" + "\xe2\x7f\xcb\xa0\x49\x1b\xff\x4c" + "\x73\xf6\xbb\x94\x00\xe8\xa9\x3d" + "\xe2\x20\xe9\x3f\xfa\x07\x5d\x77" + "\x06\xd5\x4f\x4d\x02\xb8\x40\x1b" + "\x30\xed\x1a\x50\x19\xef\xc4\x2c" + "\x02\xd9\xc5\xd3\x11\x33\x37\xe5" + "\x2b\xa3\x95\xa6\xee\xd8\x74\x1d" + "\x68\xa0\xeb\xbf\xdd\x5e\x99\x96" + "\x91\xc3\x94\x24\xa5\x12\xa2\x37" + "\xb3\xac\xcf\x2a\xfd\x55\x34\xfe" + "\x79\x92\x3e\xe6\x1b\x49\x57\x5d" + "\x93\x6c\x01\xf7\xcc\x4e\x20\xd1" + "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9" + "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95", + .ilen = 512, + .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac" + "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c" + "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8" + "\x50\x38\x1f\x71\x49\xb6\x57\xd6" + "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90" + "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6" + "\xad\x1e\x9e\x20\x5f\x38\xbe\x04" + "\xda\x10\x8e\xed\xa2\xa4\x87\xab" + "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c" + "\xc9\xac\x42\x31\x95\x7c\xc9\x04" + "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6" + "\x15\xd7\x3f\x4f\x2f\x66\x69\x03" + "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65" + "\x4c\x96\x12\xed\x7c\x92\x03\x01" + "\x6f\xbc\x35\x93\xac\xf1\x27\xf1" + "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50" + "\x89\xa4\x8e\x66\x44\x85\xcc\xfd" + "\x33\x14\x70\xe3\x96\xb2\xc3\xd3" + "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5" + "\x2d\x64\x75\xdd\xb4\x54\xe6\x74" + "\x8c\xd3\x9d\x9e\x86\xab\x51\x53" + "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40" + "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5" + "\x76\x12\x73\x44\x1a\x56\xd7\x72" + "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda" + "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd" + "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60" + "\x1a\xe2\x70\x85\x58\xc2\x1b\x09" + "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9" + "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8" + "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8" + "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10" + "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1" + "\x90\x3e\x76\x4a\x74\xa4\x21\x2c" + "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e" + "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f" + "\x8d\x23\x31\x74\x84\xeb\x88\x6e" + "\xcc\xb9\xbc\x22\x83\x19\x07\x22" + "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78" + "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5" + "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41" + "\x3c\xce\x8f\x42\x60\x71\xa7\x75" + "\x08\x40\x65\x8a\x82\xbf\xf5\x43" + "\x71\x96\xa9\x4d\x44\x8a\x20\xbe" + "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65" + "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9" + "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4" + "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a" + "\x62\x73\x65\xfd\x46\x63\x25\x3d" + "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf" + "\x24\xf3\xb4\xac\x64\xba\xdf\x4b" + "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7" + "\xc5\x68\x77\x84\x32\x2b\xcc\x85" + "\x74\x96\xf0\x12\x77\x61\xb9\xeb" + "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8" + "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24" + "\xda\x39\x87\x45\xc0\x2b\xbb\x01" + "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce" + "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6" + "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32" + "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45" + "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6" + "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" + "\x21\xc4\xc2\x75\x67\x89\x37\x0a", + .rlen = 512, + }, +}; + +static struct cipher_testvec camellia_xts_enc_tv_template[] = { + /* Generated from AES-XTS test vectors */ + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ilen = 32, + .result = "\x06\xcb\xa5\xf1\x04\x63\xb2\x41" + "\xdc\xca\xfa\x09\xba\x74\xb9\x05" + "\x78\xba\xa4\xf8\x67\x4d\x7e\xad" + "\x20\x18\xf5\x0c\x41\x16\x2a\x61", + .rlen = 32, + }, { + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\xc2\xb9\xdc\x44\x1d\xdf\xf2\x86" + "\x8d\x35\x42\x0a\xa5\x5e\x3d\x4f" + "\xb5\x37\x06\xff\xbd\xd4\x91\x70" + "\x80\x1f\xb2\x39\x10\x89\x44\xf5", + .rlen = 32, + }, { + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\x52\x1f\x9d\xf5\x5a\x58\x5a\x7e" + "\x9f\xd0\x8e\x02\x9c\x9a\x6a\xa7" + "\xb4\x3b\xce\xe7\x17\xaa\x89\x6a" + "\x35\x3c\x6b\xb5\x61\x1c\x79\x38", + .rlen = 32, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\xc7\xf9\x0a\xaa\xcb\xb5\x8f\x33" + "\x60\xc3\xe9\x47\x90\xb7\x50\x57" + "\xa3\xad\x81\x2f\xf5\x22\x96\x02" + "\xaa\x7f\xea\xac\x29\x78\xca\x2a" + "\x7c\xcd\x31\x1a\x3c\x40\x0a\x73" + "\x09\x66\xad\x72\x0e\x4d\x5d\x77" + "\xbc\xb8\x76\x80\x37\x59\xa9\x01" + "\x9e\xfb\xdb\x6c\x93\xef\xb6\x8d" + "\x1e\xc1\x94\xa8\xd4\xb5\xb0\x01" + "\xd5\x01\x97\x28\xcd\x7a\x1f\xe8" + "\x08\xda\x76\x00\x65\xcf\x7b\x31" + "\xc6\xfa\xf2\x3b\x00\xa7\x6a\x9e" + "\x6c\x43\x80\x87\xe0\xbb\x4e\xe5" + "\xdc\x8a\xdf\xc3\x1d\x1b\x41\x04" + "\xfb\x54\xdd\x29\x27\xc2\x65\x17" + "\x36\x88\xb0\x85\x8d\x73\x7e\x4b" + "\x1d\x16\x8a\x52\xbc\xa6\xbc\xa4" + "\x8c\xd1\x04\x16\xbf\x8c\x01\x0f" + "\x7e\x6b\x59\x15\x29\xd1\x9b\xd3" + "\x6c\xee\xac\xdc\x45\x58\xca\x5b" + "\x70\x0e\x6a\x12\x86\x82\x79\x9f" + "\x16\xd4\x9d\x67\xcd\x70\x65\x26" + "\x21\x72\x1e\xa1\x94\x8a\x83\x0c" + "\x92\x42\x58\x5e\xa2\xc5\x31\xf3" + "\x7b\xd1\x31\xd4\x15\x80\x31\x61" + "\x5c\x53\x10\xdd\xea\xc8\x83\x5c" + "\x7d\xa7\x05\x66\xcc\x1e\xbb\x05" + "\x47\xae\xb4\x0f\x84\xd8\xf6\xb5" + "\xa1\xc6\x52\x00\x52\xe8\xdc\xd9" + "\x16\x31\xb2\x47\x91\x67\xaa\x28" + "\x2c\x29\x85\xa3\xf7\xf2\x24\x93" + "\x23\x80\x1f\xa8\x1b\x82\x8d\xdc" + "\x9f\x0b\xcd\xb4\x3c\x20\xbc\xec" + "\x4f\xc7\xee\xf8\xfd\xd9\xfb\x7e" + "\x3f\x0d\x23\xfa\x3f\xa7\xcc\x66" + "\x1c\xfe\xa6\x86\xf6\xf7\x85\xc7" + "\x43\xc1\xd4\xfc\xe4\x79\xc9\x1d" + "\xf8\x89\xcd\x20\x27\x84\x5d\x5c" + "\x8e\x4f\x1f\xeb\x08\x21\x4f\xa3" + "\xe0\x7e\x0b\x9c\xe7\x42\xcf\xb7" + "\x3f\x43\xcc\x86\x71\x34\x6a\xd9" + "\x5e\xec\x8f\x36\xc9\x0a\x03\xfe" + "\x18\x41\xdc\x9e\x2e\x75\x20\x3e" + "\xcc\x77\xe0\x8f\xe8\x43\x37\x4c" + "\xed\x1a\x5a\xb3\xfa\x43\xc9\x71" + "\x9f\xc5\xce\xcf\xff\xe7\x77\x1e" + "\x35\x93\xde\x6b\xc0\x6a\x7e\xa9" + "\x34\xb8\x27\x74\x08\xda\xf2\x4a" + "\x23\x5b\x9f\x55\x3a\x57\x82\x52" + "\xea\x6d\xc3\xc7\xf2\xc8\xb5\xdc" + "\xc5\xb9\xbb\xaa\xf2\x29\x9f\x49" + "\x7a\xef\xfe\xdc\x9f\xc9\x28\xe2" + "\x96\x0b\x35\x84\x05\x0d\xd6\x2a" + "\xea\x5a\xbf\x69\xde\xee\x4f\x8f" + "\x84\xb9\xcf\xa7\x57\xea\xe0\xe8" + "\x96\xef\x0f\x0e\xec\xc7\xa6\x74" + "\xb1\xfe\x7a\x6d\x11\xdd\x0e\x15" + "\x4a\x1e\x73\x7f\x55\xea\xf6\xe1" + "\x5b\xb6\x71\xda\xb0\x0c\xba\x26" + "\x5c\x48\x38\x6d\x1c\x32\xb2\x7d" + "\x05\x87\xc2\x1e\x7e\x2d\xd4\x33" + "\xcc\x06\xdb\xe7\x82\x29\x63\xd1" + "\x52\x84\x4f\xee\x27\xe8\x02\xd4" + "\x34\x3c\x69\xc2\xbd\x20\xe6\x7a", + .rlen = 512, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\x49\xcd\xb8\xbf\x2f\x73\x37\x28" + "\x9a\x7f\x6e\x57\x55\xb8\x07\x88" + "\x4a\x0d\x8b\x55\x60\xed\xb6\x7b" + "\xf1\x74\xac\x96\x05\x7b\x32\xca" + "\xd1\x4e\xf1\x58\x29\x16\x24\x6c" + "\xf2\xb3\xe4\x88\x84\xac\x4d\xee" + "\x97\x07\x82\xf0\x07\x12\x38\x0a" + "\x67\x62\xaf\xfd\x85\x9f\x0a\x55" + "\xa5\x20\xc5\x60\xe4\x68\x53\xa4" + "\x0e\x2e\x65\xe3\xe4\x0c\x30\x7c" + "\x1c\x01\x4f\x55\xa9\x13\xeb\x25" + "\x21\x87\xbc\xd3\xe7\x67\x4f\x38" + "\xa8\x14\x25\x71\xe9\x2e\x4c\x21" + "\x41\x82\x0c\x45\x39\x35\xa8\x75" + "\x03\x29\x01\x84\x8c\xab\x48\xbe" + "\x11\x56\x22\x67\xb7\x67\x1a\x09" + "\xa1\x72\x25\x41\x3c\x39\x65\x80" + "\x7d\x2f\xf8\x2c\x73\x04\x58\x9d" + "\xdd\x16\x8b\x63\x70\x4e\xc5\x17" + "\x21\xe0\x84\x51\x4b\x6f\x05\x52" + "\xe3\x63\x34\xfa\xa4\xaf\x33\x20" + "\xc1\xae\x32\xc4\xb8\x2b\xdb\x76" + "\xd9\x02\x31\x2f\xa3\xc6\xd0\x7b" + "\xaf\x1b\x84\xe3\x9b\xbf\xa6\xe0" + "\xb8\x8a\x13\x88\x71\xf4\x11\xa5" + "\xe9\xa9\x10\x33\xe0\xbe\x49\x89" + "\x41\x22\xf5\x9d\x80\x3e\x3b\x76" + "\x01\x16\x50\x6e\x7c\x6a\x81\xe9" + "\x13\x2c\xde\xb2\x5f\x79\xba\xb2" + "\xb1\x75\xae\xd2\x07\x98\x4b\x69" + "\xae\x7d\x5b\x90\xc2\x6c\xe6\x98" + "\xd3\x4c\xa1\xa3\x9c\xc9\x33\x6a" + "\x0d\x23\xb1\x79\x25\x13\x4b\xe5" + "\xaf\x93\x20\x5c\x7f\x06\x7a\x34" + "\x0b\x78\xe3\x67\x26\xe0\xad\x95" + "\xc5\x4e\x26\x22\xcf\x73\x77\x62" + "\x3e\x10\xd7\x90\x4b\x52\x1c\xc9" + "\xef\x38\x52\x18\x0e\x29\x7e\xef" + "\x34\xfe\x31\x95\xc5\xbc\xa8\xe2" + "\xa8\x4e\x9f\xea\xa6\xf0\xfe\x5d" + "\xc5\x39\x86\xed\x2f\x6d\xa0\xfe" + "\x96\xcd\x41\x10\x78\x4e\x0c\xc9" + "\xc3\x6d\x0f\xb7\xe8\xe0\x62\xab" + "\x8b\xf1\x21\x89\xa1\x12\xaa\xfa" + "\x9d\x70\xbe\x4c\xa8\x98\x89\x01" + "\xb9\xe2\x61\xde\x0c\x4a\x0b\xaa" + "\x89\xf5\x14\x79\x18\x8f\x3b\x0d" + "\x21\x17\xf8\x59\x15\x24\x64\x22" + "\x57\x48\x80\xd5\x3d\x92\x30\x07" + "\xd9\xa1\x4a\x23\x16\x43\x48\x0e" + "\x2b\x2d\x1b\x87\xef\x7e\xbd\xfa" + "\x49\xbc\x7e\x68\x6e\xa8\x46\x95" + "\xad\x5e\xfe\x0a\xa8\xd3\x1a\x5d" + "\x6b\x84\xf3\x00\xba\x52\x05\x02" + "\xe3\x96\x4e\xb6\x79\x3f\x43\xd3" + "\x4d\x3f\xd6\xab\x0a\xc4\x75\x2d" + "\xd1\x08\xc3\x6a\xc8\x37\x29\xa0" + "\xcc\x9a\x05\xdd\x5c\xe1\xff\x66" + "\xf2\x7a\x1d\xf2\xaf\xa9\x48\x89" + "\xf5\x21\x0f\x02\x48\x83\x74\xbf" + "\x2e\xe6\x93\x7b\xa0\xf4\xb1\x2b" + "\xb1\x02\x0a\x5c\x79\x19\x3b\x75" + "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e" + "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95", + .rlen = 512, + }, +}; + +static struct cipher_testvec camellia_xts_dec_tv_template[] = { + /* Generated from AES-XTS test vectors */ + /* same as enc vectors with input and result reversed */ + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x06\xcb\xa5\xf1\x04\x63\xb2\x41" + "\xdc\xca\xfa\x09\xba\x74\xb9\x05" + "\x78\xba\xa4\xf8\x67\x4d\x7e\xad" + "\x20\x18\xf5\x0c\x41\x16\x2a\x61", + .ilen = 32, + .result = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .rlen = 32, + }, { + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xc2\xb9\xdc\x44\x1d\xdf\xf2\x86" + "\x8d\x35\x42\x0a\xa5\x5e\x3d\x4f" + "\xb5\x37\x06\xff\xbd\xd4\x91\x70" + "\x80\x1f\xb2\x39\x10\x89\x44\xf5", + .ilen = 32, + .result = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .rlen = 32, + }, { + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x52\x1f\x9d\xf5\x5a\x58\x5a\x7e" + "\x9f\xd0\x8e\x02\x9c\x9a\x6a\xa7" + "\xb4\x3b\xce\xe7\x17\xaa\x89\x6a" + "\x35\x3c\x6b\xb5\x61\x1c\x79\x38", + .ilen = 32, + .result = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .rlen = 32, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\xc7\xf9\x0a\xaa\xcb\xb5\x8f\x33" + "\x60\xc3\xe9\x47\x90\xb7\x50\x57" + "\xa3\xad\x81\x2f\xf5\x22\x96\x02" + "\xaa\x7f\xea\xac\x29\x78\xca\x2a" + "\x7c\xcd\x31\x1a\x3c\x40\x0a\x73" + "\x09\x66\xad\x72\x0e\x4d\x5d\x77" + "\xbc\xb8\x76\x80\x37\x59\xa9\x01" + "\x9e\xfb\xdb\x6c\x93\xef\xb6\x8d" + "\x1e\xc1\x94\xa8\xd4\xb5\xb0\x01" + "\xd5\x01\x97\x28\xcd\x7a\x1f\xe8" + "\x08\xda\x76\x00\x65\xcf\x7b\x31" + "\xc6\xfa\xf2\x3b\x00\xa7\x6a\x9e" + "\x6c\x43\x80\x87\xe0\xbb\x4e\xe5" + "\xdc\x8a\xdf\xc3\x1d\x1b\x41\x04" + "\xfb\x54\xdd\x29\x27\xc2\x65\x17" + "\x36\x88\xb0\x85\x8d\x73\x7e\x4b" + "\x1d\x16\x8a\x52\xbc\xa6\xbc\xa4" + "\x8c\xd1\x04\x16\xbf\x8c\x01\x0f" + "\x7e\x6b\x59\x15\x29\xd1\x9b\xd3" + "\x6c\xee\xac\xdc\x45\x58\xca\x5b" + "\x70\x0e\x6a\x12\x86\x82\x79\x9f" + "\x16\xd4\x9d\x67\xcd\x70\x65\x26" + "\x21\x72\x1e\xa1\x94\x8a\x83\x0c" + "\x92\x42\x58\x5e\xa2\xc5\x31\xf3" + "\x7b\xd1\x31\xd4\x15\x80\x31\x61" + "\x5c\x53\x10\xdd\xea\xc8\x83\x5c" + "\x7d\xa7\x05\x66\xcc\x1e\xbb\x05" + "\x47\xae\xb4\x0f\x84\xd8\xf6\xb5" + "\xa1\xc6\x52\x00\x52\xe8\xdc\xd9" + "\x16\x31\xb2\x47\x91\x67\xaa\x28" + "\x2c\x29\x85\xa3\xf7\xf2\x24\x93" + "\x23\x80\x1f\xa8\x1b\x82\x8d\xdc" + "\x9f\x0b\xcd\xb4\x3c\x20\xbc\xec" + "\x4f\xc7\xee\xf8\xfd\xd9\xfb\x7e" + "\x3f\x0d\x23\xfa\x3f\xa7\xcc\x66" + "\x1c\xfe\xa6\x86\xf6\xf7\x85\xc7" + "\x43\xc1\xd4\xfc\xe4\x79\xc9\x1d" + "\xf8\x89\xcd\x20\x27\x84\x5d\x5c" + "\x8e\x4f\x1f\xeb\x08\x21\x4f\xa3" + "\xe0\x7e\x0b\x9c\xe7\x42\xcf\xb7" + "\x3f\x43\xcc\x86\x71\x34\x6a\xd9" + "\x5e\xec\x8f\x36\xc9\x0a\x03\xfe" + "\x18\x41\xdc\x9e\x2e\x75\x20\x3e" + "\xcc\x77\xe0\x8f\xe8\x43\x37\x4c" + "\xed\x1a\x5a\xb3\xfa\x43\xc9\x71" + "\x9f\xc5\xce\xcf\xff\xe7\x77\x1e" + "\x35\x93\xde\x6b\xc0\x6a\x7e\xa9" + "\x34\xb8\x27\x74\x08\xda\xf2\x4a" + "\x23\x5b\x9f\x55\x3a\x57\x82\x52" + "\xea\x6d\xc3\xc7\xf2\xc8\xb5\xdc" + "\xc5\xb9\xbb\xaa\xf2\x29\x9f\x49" + "\x7a\xef\xfe\xdc\x9f\xc9\x28\xe2" + "\x96\x0b\x35\x84\x05\x0d\xd6\x2a" + "\xea\x5a\xbf\x69\xde\xee\x4f\x8f" + "\x84\xb9\xcf\xa7\x57\xea\xe0\xe8" + "\x96\xef\x0f\x0e\xec\xc7\xa6\x74" + "\xb1\xfe\x7a\x6d\x11\xdd\x0e\x15" + "\x4a\x1e\x73\x7f\x55\xea\xf6\xe1" + "\x5b\xb6\x71\xda\xb0\x0c\xba\x26" + "\x5c\x48\x38\x6d\x1c\x32\xb2\x7d" + "\x05\x87\xc2\x1e\x7e\x2d\xd4\x33" + "\xcc\x06\xdb\xe7\x82\x29\x63\xd1" + "\x52\x84\x4f\xee\x27\xe8\x02\xd4" + "\x34\x3c\x69\xc2\xbd\x20\xe6\x7a", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, + }, { + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x49\xcd\xb8\xbf\x2f\x73\x37\x28" + "\x9a\x7f\x6e\x57\x55\xb8\x07\x88" + "\x4a\x0d\x8b\x55\x60\xed\xb6\x7b" + "\xf1\x74\xac\x96\x05\x7b\x32\xca" + "\xd1\x4e\xf1\x58\x29\x16\x24\x6c" + "\xf2\xb3\xe4\x88\x84\xac\x4d\xee" + "\x97\x07\x82\xf0\x07\x12\x38\x0a" + "\x67\x62\xaf\xfd\x85\x9f\x0a\x55" + "\xa5\x20\xc5\x60\xe4\x68\x53\xa4" + "\x0e\x2e\x65\xe3\xe4\x0c\x30\x7c" + "\x1c\x01\x4f\x55\xa9\x13\xeb\x25" + "\x21\x87\xbc\xd3\xe7\x67\x4f\x38" + "\xa8\x14\x25\x71\xe9\x2e\x4c\x21" + "\x41\x82\x0c\x45\x39\x35\xa8\x75" + "\x03\x29\x01\x84\x8c\xab\x48\xbe" + "\x11\x56\x22\x67\xb7\x67\x1a\x09" + "\xa1\x72\x25\x41\x3c\x39\x65\x80" + "\x7d\x2f\xf8\x2c\x73\x04\x58\x9d" + "\xdd\x16\x8b\x63\x70\x4e\xc5\x17" + "\x21\xe0\x84\x51\x4b\x6f\x05\x52" + "\xe3\x63\x34\xfa\xa4\xaf\x33\x20" + "\xc1\xae\x32\xc4\xb8\x2b\xdb\x76" + "\xd9\x02\x31\x2f\xa3\xc6\xd0\x7b" + "\xaf\x1b\x84\xe3\x9b\xbf\xa6\xe0" + "\xb8\x8a\x13\x88\x71\xf4\x11\xa5" + "\xe9\xa9\x10\x33\xe0\xbe\x49\x89" + "\x41\x22\xf5\x9d\x80\x3e\x3b\x76" + "\x01\x16\x50\x6e\x7c\x6a\x81\xe9" + "\x13\x2c\xde\xb2\x5f\x79\xba\xb2" + "\xb1\x75\xae\xd2\x07\x98\x4b\x69" + "\xae\x7d\x5b\x90\xc2\x6c\xe6\x98" + "\xd3\x4c\xa1\xa3\x9c\xc9\x33\x6a" + "\x0d\x23\xb1\x79\x25\x13\x4b\xe5" + "\xaf\x93\x20\x5c\x7f\x06\x7a\x34" + "\x0b\x78\xe3\x67\x26\xe0\xad\x95" + "\xc5\x4e\x26\x22\xcf\x73\x77\x62" + "\x3e\x10\xd7\x90\x4b\x52\x1c\xc9" + "\xef\x38\x52\x18\x0e\x29\x7e\xef" + "\x34\xfe\x31\x95\xc5\xbc\xa8\xe2" + "\xa8\x4e\x9f\xea\xa6\xf0\xfe\x5d" + "\xc5\x39\x86\xed\x2f\x6d\xa0\xfe" + "\x96\xcd\x41\x10\x78\x4e\x0c\xc9" + "\xc3\x6d\x0f\xb7\xe8\xe0\x62\xab" + "\x8b\xf1\x21\x89\xa1\x12\xaa\xfa" + "\x9d\x70\xbe\x4c\xa8\x98\x89\x01" + "\xb9\xe2\x61\xde\x0c\x4a\x0b\xaa" + "\x89\xf5\x14\x79\x18\x8f\x3b\x0d" + "\x21\x17\xf8\x59\x15\x24\x64\x22" + "\x57\x48\x80\xd5\x3d\x92\x30\x07" + "\xd9\xa1\x4a\x23\x16\x43\x48\x0e" + "\x2b\x2d\x1b\x87\xef\x7e\xbd\xfa" + "\x49\xbc\x7e\x68\x6e\xa8\x46\x95" + "\xad\x5e\xfe\x0a\xa8\xd3\x1a\x5d" + "\x6b\x84\xf3\x00\xba\x52\x05\x02" + "\xe3\x96\x4e\xb6\x79\x3f\x43\xd3" + "\x4d\x3f\xd6\xab\x0a\xc4\x75\x2d" + "\xd1\x08\xc3\x6a\xc8\x37\x29\xa0" + "\xcc\x9a\x05\xdd\x5c\xe1\xff\x66" + "\xf2\x7a\x1d\xf2\xaf\xa9\x48\x89" + "\xf5\x21\x0f\x02\x48\x83\x74\xbf" + "\x2e\xe6\x93\x7b\xa0\xf4\xb1\x2b" + "\xb1\x02\x0a\x5c\x79\x19\x3b\x75" + "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e" + "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95", + .ilen = 512, + .result = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .rlen = 512, + }, }; /* diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 9691dd0966d7..d8af325a6bda 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -720,13 +720,13 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) /* FIXME: use a bounce buffer */ local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0); + buf = kmap_atomic(page); /* do the actual data transfer */ ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); - kunmap_atomic(buf, KM_IRQ0); + kunmap_atomic(buf); local_irq_restore(flags); } else { buf = page_address(page); @@ -865,13 +865,13 @@ next_sg: /* FIXME: use bounce buffer */ local_irq_save(flags); - buf = kmap_atomic(page, KM_IRQ0); + buf = kmap_atomic(page); /* do the actual data transfer */ consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw); - kunmap_atomic(buf, KM_IRQ0); + kunmap_atomic(buf); local_irq_restore(flags); } else { buf = page_address(page); diff --git a/drivers/base/core.c b/drivers/base/core.c index 7050a75dde38..e28ce9898af4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -18,6 +18,8 @@ #include <linux/string.h> #include <linux/kdev_t.h> #include <linux/notifier.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/genhd.h> #include <linux/kallsyms.h> #include <linux/mutex.h> @@ -267,6 +269,9 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->driver) add_uevent_var(env, "DRIVER=%s", dev->driver->name); + /* Add common DT information about the device */ + of_device_uevent(dev, env); + /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { retval = dev->bus->uevent(dev, env); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f0c605e99ade..a1a722502587 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -621,7 +621,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) int rc; /* Some devices have extra OF data and an OF-style MODALIAS */ - rc = of_device_uevent(dev,env); + rc = of_device_uevent_modalias(dev,env); if (rc != -ENODEV) return rc; diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 978bbf7ac6af..73ce9fbe9839 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -366,7 +366,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) not_suspended = 0; list_for_each_entry(pdd, &genpd->dev_list, list_node) if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) - || pdd->dev->power.irq_safe)) + || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on)) not_suspended++; if (not_suspended > genpd->in_progress) @@ -503,6 +503,9 @@ static int pm_genpd_runtime_suspend(struct device *dev) might_sleep_if(!genpd->dev_irq_safe); + if (dev_gpd_data(dev)->always_on) + return -EBUSY; + stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL; if (stop_ok && !stop_ok(dev)) return -EBUSY; @@ -764,8 +767,10 @@ static int pm_genpd_prepare(struct device *dev) genpd_acquire_lock(genpd); - if (genpd->prepared_count++ == 0) + if (genpd->prepared_count++ == 0) { + genpd->suspended_count = 0; genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF; + } genpd_release_lock(genpd); @@ -820,17 +825,16 @@ static int pm_genpd_suspend(struct device *dev) } /** - * pm_genpd_suspend_noirq - Late suspend of a device from an I/O PM domain. + * pm_genpd_suspend_late - Late suspend of a device from an I/O PM domain. * @dev: Device to suspend. * * Carry out a late suspend of a device under the assumption that its * pm_domain field points to the domain member of an object of type * struct generic_pm_domain representing a PM domain consisting of I/O devices. */ -static int pm_genpd_suspend_noirq(struct device *dev) +static int pm_genpd_suspend_late(struct device *dev) { struct generic_pm_domain *genpd; - int ret; dev_dbg(dev, "%s()\n", __func__); @@ -838,14 +842,28 @@ static int pm_genpd_suspend_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off) - return 0; + return genpd->suspend_power_off ? 0 : genpd_suspend_late(genpd, dev); +} - ret = genpd_suspend_late(genpd, dev); - if (ret) - return ret; +/** + * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain. + * @dev: Device to suspend. + * + * Stop the device and remove power from the domain if all devices in it have + * been stopped. + */ +static int pm_genpd_suspend_noirq(struct device *dev) +{ + struct generic_pm_domain *genpd; - if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) + dev_dbg(dev, "%s()\n", __func__); + + genpd = dev_to_genpd(dev); + if (IS_ERR(genpd)) + return -EINVAL; + + if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) return 0; genpd_stop_dev(genpd, dev); @@ -862,13 +880,10 @@ static int pm_genpd_suspend_noirq(struct device *dev) } /** - * pm_genpd_resume_noirq - Early resume of a device from an I/O power domain. + * pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain. * @dev: Device to resume. * - * Carry out an early resume of a device under the assumption that its - * pm_domain field points to the domain member of an object of type - * struct generic_pm_domain representing a power domain consisting of I/O - * devices. + * Restore power to the device's PM domain, if necessary, and start the device. */ static int pm_genpd_resume_noirq(struct device *dev) { @@ -880,7 +895,8 @@ static int pm_genpd_resume_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off) + if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) return 0; /* @@ -890,13 +906,34 @@ static int pm_genpd_resume_noirq(struct device *dev) */ pm_genpd_poweron(genpd); genpd->suspended_count--; - genpd_start_dev(genpd, dev); - return genpd_resume_early(genpd, dev); + return genpd_start_dev(genpd, dev); } /** - * pm_genpd_resume - Resume a device belonging to an I/O power domain. + * pm_genpd_resume_early - Early resume of a device in an I/O PM domain. + * @dev: Device to resume. + * + * Carry out an early resume of a device under the assumption that its + * pm_domain field points to the domain member of an object of type + * struct generic_pm_domain representing a power domain consisting of I/O + * devices. + */ +static int pm_genpd_resume_early(struct device *dev) +{ + struct generic_pm_domain *genpd; + + dev_dbg(dev, "%s()\n", __func__); + + genpd = dev_to_genpd(dev); + if (IS_ERR(genpd)) + return -EINVAL; + + return genpd->suspend_power_off ? 0 : genpd_resume_early(genpd, dev); +} + +/** + * pm_genpd_resume - Resume of device in an I/O PM domain. * @dev: Device to resume. * * Resume a device under the assumption that its pm_domain field points to the @@ -917,7 +954,7 @@ static int pm_genpd_resume(struct device *dev) } /** - * pm_genpd_freeze - Freeze a device belonging to an I/O power domain. + * pm_genpd_freeze - Freezing a device in an I/O PM domain. * @dev: Device to freeze. * * Freeze a device under the assumption that its pm_domain field points to the @@ -938,7 +975,29 @@ static int pm_genpd_freeze(struct device *dev) } /** - * pm_genpd_freeze_noirq - Late freeze of a device from an I/O power domain. + * pm_genpd_freeze_late - Late freeze of a device in an I/O PM domain. + * @dev: Device to freeze. + * + * Carry out a late freeze of a device under the assumption that its + * pm_domain field points to the domain member of an object of type + * struct generic_pm_domain representing a power domain consisting of I/O + * devices. + */ +static int pm_genpd_freeze_late(struct device *dev) +{ + struct generic_pm_domain *genpd; + + dev_dbg(dev, "%s()\n", __func__); + + genpd = dev_to_genpd(dev); + if (IS_ERR(genpd)) + return -EINVAL; + + return genpd->suspend_power_off ? 0 : genpd_freeze_late(genpd, dev); +} + +/** + * pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain. * @dev: Device to freeze. * * Carry out a late freeze of a device under the assumption that its @@ -949,7 +1008,6 @@ static int pm_genpd_freeze(struct device *dev) static int pm_genpd_freeze_noirq(struct device *dev) { struct generic_pm_domain *genpd; - int ret; dev_dbg(dev, "%s()\n", __func__); @@ -957,20 +1015,33 @@ static int pm_genpd_freeze_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off) - return 0; + return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? + 0 : genpd_stop_dev(genpd, dev); +} - ret = genpd_freeze_late(genpd, dev); - if (ret) - return ret; +/** + * pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain. + * @dev: Device to thaw. + * + * Start the device, unless power has been removed from the domain already + * before the system transition. + */ +static int pm_genpd_thaw_noirq(struct device *dev) +{ + struct generic_pm_domain *genpd; - genpd_stop_dev(genpd, dev); + dev_dbg(dev, "%s()\n", __func__); - return 0; + genpd = dev_to_genpd(dev); + if (IS_ERR(genpd)) + return -EINVAL; + + return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ? + 0 : genpd_start_dev(genpd, dev); } /** - * pm_genpd_thaw_noirq - Early thaw of a device from an I/O power domain. + * pm_genpd_thaw_early - Early thaw of device in an I/O PM domain. * @dev: Device to thaw. * * Carry out an early thaw of a device under the assumption that its @@ -978,7 +1049,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) * struct generic_pm_domain representing a power domain consisting of I/O * devices. */ -static int pm_genpd_thaw_noirq(struct device *dev) +static int pm_genpd_thaw_early(struct device *dev) { struct generic_pm_domain *genpd; @@ -988,12 +1059,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->suspend_power_off) - return 0; - - genpd_start_dev(genpd, dev); - - return genpd_thaw_early(genpd, dev); + return genpd->suspend_power_off ? 0 : genpd_thaw_early(genpd, dev); } /** @@ -1018,13 +1084,11 @@ static int pm_genpd_thaw(struct device *dev) } /** - * pm_genpd_restore_noirq - Early restore of a device from an I/O power domain. + * pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain. * @dev: Device to resume. * - * Carry out an early restore of a device under the assumption that its - * pm_domain field points to the domain member of an object of type - * struct generic_pm_domain representing a power domain consisting of I/O - * devices. + * Make sure the domain will be in the same power state as before the + * hibernation the system is resuming from and start the device if necessary. */ static int pm_genpd_restore_noirq(struct device *dev) { @@ -1040,23 +1104,35 @@ static int pm_genpd_restore_noirq(struct device *dev) * Since all of the "noirq" callbacks are executed sequentially, it is * guaranteed that this function will never run twice in parallel for * the same PM domain, so it is not necessary to use locking here. + * + * At this point suspended_count == 0 means we are being run for the + * first time for the given domain in the present cycle. */ - genpd->status = GPD_STATE_POWER_OFF; - if (genpd->suspend_power_off) { + if (genpd->suspended_count++ == 0) { /* - * The boot kernel might put the domain into the power on state, - * so make sure it really is powered off. + * The boot kernel might put the domain into arbitrary state, + * so make it appear as powered off to pm_genpd_poweron(), so + * that it tries to power it on in case it was really off. */ - if (genpd->power_off) - genpd->power_off(genpd); - return 0; + genpd->status = GPD_STATE_POWER_OFF; + if (genpd->suspend_power_off) { + /* + * If the domain was off before the hibernation, make + * sure it will be off going forward. + */ + if (genpd->power_off) + genpd->power_off(genpd); + + return 0; + } } + if (genpd->suspend_power_off) + return 0; + pm_genpd_poweron(genpd); - genpd->suspended_count--; - genpd_start_dev(genpd, dev); - return genpd_resume_early(genpd, dev); + return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev); } /** @@ -1099,11 +1175,15 @@ static void pm_genpd_complete(struct device *dev) #define pm_genpd_prepare NULL #define pm_genpd_suspend NULL +#define pm_genpd_suspend_late NULL #define pm_genpd_suspend_noirq NULL +#define pm_genpd_resume_early NULL #define pm_genpd_resume_noirq NULL #define pm_genpd_resume NULL #define pm_genpd_freeze NULL +#define pm_genpd_freeze_late NULL #define pm_genpd_freeze_noirq NULL +#define pm_genpd_thaw_early NULL #define pm_genpd_thaw_noirq NULL #define pm_genpd_thaw NULL #define pm_genpd_restore_noirq NULL @@ -1171,6 +1251,38 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, } /** + * __pm_genpd_of_add_device - Add a device to an I/O PM domain. + * @genpd_node: Device tree node pointer representing a PM domain to which the + * the device is added to. + * @dev: Device to be added. + * @td: Set of PM QoS timing parameters to attach to the device. + */ +int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev, + struct gpd_timing_data *td) +{ + struct generic_pm_domain *genpd = NULL, *gpd; + + dev_dbg(dev, "%s()\n", __func__); + + if (IS_ERR_OR_NULL(genpd_node) || IS_ERR_OR_NULL(dev)) + return -EINVAL; + + mutex_lock(&gpd_list_lock); + list_for_each_entry(gpd, &gpd_list, gpd_list_node) { + if (gpd->of_node == genpd_node) { + genpd = gpd; + break; + } + } + mutex_unlock(&gpd_list_lock); + + if (!genpd) + return -EINVAL; + + return __pm_genpd_add_device(genpd, dev, td); +} + +/** * pm_genpd_remove_device - Remove a device from an I/O PM domain. * @genpd: PM domain to remove the device from. * @dev: Device to be removed. @@ -1216,6 +1328,26 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, } /** + * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device. + * @dev: Device to set/unset the flag for. + * @val: The new value of the device's "always on" flag. + */ +void pm_genpd_dev_always_on(struct device *dev, bool val) +{ + struct pm_subsys_data *psd; + unsigned long flags; + + spin_lock_irqsave(&dev->power.lock, flags); + + psd = dev_to_psd(dev); + if (psd && psd->domain_data) + to_gpd_data(psd->domain_data)->always_on = val; + + spin_unlock_irqrestore(&dev->power.lock, flags); +} +EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on); + +/** * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. * @genpd: Master PM domain to add the subdomain to. * @subdomain: Subdomain to be added. @@ -1450,7 +1582,7 @@ static int pm_genpd_default_suspend_late(struct device *dev) { int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.suspend_late; - return cb ? cb(dev) : pm_generic_suspend_noirq(dev); + return cb ? cb(dev) : pm_generic_suspend_late(dev); } /** @@ -1461,7 +1593,7 @@ static int pm_genpd_default_resume_early(struct device *dev) { int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.resume_early; - return cb ? cb(dev) : pm_generic_resume_noirq(dev); + return cb ? cb(dev) : pm_generic_resume_early(dev); } /** @@ -1494,7 +1626,7 @@ static int pm_genpd_default_freeze_late(struct device *dev) { int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late; - return cb ? cb(dev) : pm_generic_freeze_noirq(dev); + return cb ? cb(dev) : pm_generic_freeze_late(dev); } /** @@ -1505,7 +1637,7 @@ static int pm_genpd_default_thaw_early(struct device *dev) { int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early; - return cb ? cb(dev) : pm_generic_thaw_noirq(dev); + return cb ? cb(dev) : pm_generic_thaw_early(dev); } /** @@ -1557,23 +1689,28 @@ void pm_genpd_init(struct generic_pm_domain *genpd, genpd->poweroff_task = NULL; genpd->resume_count = 0; genpd->device_count = 0; - genpd->suspended_count = 0; genpd->max_off_time_ns = -1; genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; genpd->domain.ops.runtime_idle = pm_generic_runtime_idle; genpd->domain.ops.prepare = pm_genpd_prepare; genpd->domain.ops.suspend = pm_genpd_suspend; + genpd->domain.ops.suspend_late = pm_genpd_suspend_late; genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq; genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq; + genpd->domain.ops.resume_early = pm_genpd_resume_early; genpd->domain.ops.resume = pm_genpd_resume; genpd->domain.ops.freeze = pm_genpd_freeze; + genpd->domain.ops.freeze_late = pm_genpd_freeze_late; genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq; genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq; + genpd->domain.ops.thaw_early = pm_genpd_thaw_early; genpd->domain.ops.thaw = pm_genpd_thaw; genpd->domain.ops.poweroff = pm_genpd_suspend; + genpd->domain.ops.poweroff_late = pm_genpd_suspend_late; genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq; genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq; + genpd->domain.ops.restore_early = pm_genpd_resume_early; genpd->domain.ops.restore = pm_genpd_resume; genpd->domain.ops.complete = pm_genpd_complete; genpd->dev_ops.save_state = pm_genpd_default_save_state; diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 10bdd793f0bd..d03d290f31c2 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -92,59 +92,28 @@ int pm_generic_prepare(struct device *dev) } /** - * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. - * @dev: Device to handle. - * @event: PM transition of the system under way. - * @bool: Whether or not this is the "noirq" stage. - * - * Execute the PM callback corresponding to @event provided by the driver of - * @dev, if defined, and return its error code. Return 0 if the callback is - * not present. + * pm_generic_suspend_noirq - Generic suspend_noirq callback for subsystems. + * @dev: Device to suspend. */ -static int __pm_generic_call(struct device *dev, int event, bool noirq) +int pm_generic_suspend_noirq(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - int (*callback)(struct device *); - - if (!pm) - return 0; - - switch (event) { - case PM_EVENT_SUSPEND: - callback = noirq ? pm->suspend_noirq : pm->suspend; - break; - case PM_EVENT_FREEZE: - callback = noirq ? pm->freeze_noirq : pm->freeze; - break; - case PM_EVENT_HIBERNATE: - callback = noirq ? pm->poweroff_noirq : pm->poweroff; - break; - case PM_EVENT_RESUME: - callback = noirq ? pm->resume_noirq : pm->resume; - break; - case PM_EVENT_THAW: - callback = noirq ? pm->thaw_noirq : pm->thaw; - break; - case PM_EVENT_RESTORE: - callback = noirq ? pm->restore_noirq : pm->restore; - break; - default: - callback = NULL; - break; - } - return callback ? callback(dev) : 0; + return pm && pm->suspend_noirq ? pm->suspend_noirq(dev) : 0; } +EXPORT_SYMBOL_GPL(pm_generic_suspend_noirq); /** - * pm_generic_suspend_noirq - Generic suspend_noirq callback for subsystems. + * pm_generic_suspend_late - Generic suspend_late callback for subsystems. * @dev: Device to suspend. */ -int pm_generic_suspend_noirq(struct device *dev) +int pm_generic_suspend_late(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_SUSPEND, true); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->suspend_late ? pm->suspend_late(dev) : 0; } -EXPORT_SYMBOL_GPL(pm_generic_suspend_noirq); +EXPORT_SYMBOL_GPL(pm_generic_suspend_late); /** * pm_generic_suspend - Generic suspend callback for subsystems. @@ -152,7 +121,9 @@ EXPORT_SYMBOL_GPL(pm_generic_suspend_noirq); */ int pm_generic_suspend(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_SUSPEND, false); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->suspend ? pm->suspend(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_suspend); @@ -162,17 +133,33 @@ EXPORT_SYMBOL_GPL(pm_generic_suspend); */ int pm_generic_freeze_noirq(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_FREEZE, true); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->freeze_noirq ? pm->freeze_noirq(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_freeze_noirq); /** + * pm_generic_freeze_late - Generic freeze_late callback for subsystems. + * @dev: Device to freeze. + */ +int pm_generic_freeze_late(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->freeze_late ? pm->freeze_late(dev) : 0; +} +EXPORT_SYMBOL_GPL(pm_generic_freeze_late); + +/** * pm_generic_freeze - Generic freeze callback for subsystems. * @dev: Device to freeze. */ int pm_generic_freeze(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_FREEZE, false); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->freeze ? pm->freeze(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_freeze); @@ -182,17 +169,33 @@ EXPORT_SYMBOL_GPL(pm_generic_freeze); */ int pm_generic_poweroff_noirq(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_HIBERNATE, true); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->poweroff_noirq ? pm->poweroff_noirq(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_poweroff_noirq); /** + * pm_generic_poweroff_late - Generic poweroff_late callback for subsystems. + * @dev: Device to handle. + */ +int pm_generic_poweroff_late(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->poweroff_late ? pm->poweroff_late(dev) : 0; +} +EXPORT_SYMBOL_GPL(pm_generic_poweroff_late); + +/** * pm_generic_poweroff - Generic poweroff callback for subsystems. * @dev: Device to handle. */ int pm_generic_poweroff(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_HIBERNATE, false); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->poweroff ? pm->poweroff(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_poweroff); @@ -202,17 +205,33 @@ EXPORT_SYMBOL_GPL(pm_generic_poweroff); */ int pm_generic_thaw_noirq(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_THAW, true); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->thaw_noirq ? pm->thaw_noirq(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_thaw_noirq); /** + * pm_generic_thaw_early - Generic thaw_early callback for subsystems. + * @dev: Device to thaw. + */ +int pm_generic_thaw_early(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->thaw_early ? pm->thaw_early(dev) : 0; +} +EXPORT_SYMBOL_GPL(pm_generic_thaw_early); + +/** * pm_generic_thaw - Generic thaw callback for subsystems. * @dev: Device to thaw. */ int pm_generic_thaw(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_THAW, false); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->thaw ? pm->thaw(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_thaw); @@ -222,17 +241,33 @@ EXPORT_SYMBOL_GPL(pm_generic_thaw); */ int pm_generic_resume_noirq(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_RESUME, true); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->resume_noirq ? pm->resume_noirq(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); /** + * pm_generic_resume_early - Generic resume_early callback for subsystems. + * @dev: Device to resume. + */ +int pm_generic_resume_early(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->resume_early ? pm->resume_early(dev) : 0; +} +EXPORT_SYMBOL_GPL(pm_generic_resume_early); + +/** * pm_generic_resume - Generic resume callback for subsystems. * @dev: Device to resume. */ int pm_generic_resume(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_RESUME, false); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->resume ? pm->resume(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_resume); @@ -242,17 +277,33 @@ EXPORT_SYMBOL_GPL(pm_generic_resume); */ int pm_generic_restore_noirq(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_RESTORE, true); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->restore_noirq ? pm->restore_noirq(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); /** + * pm_generic_restore_early - Generic restore_early callback for subsystems. + * @dev: Device to resume. + */ +int pm_generic_restore_early(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->restore_early ? pm->restore_early(dev) : 0; +} +EXPORT_SYMBOL_GPL(pm_generic_restore_early); + +/** * pm_generic_restore - Generic restore callback for subsystems. * @dev: Device to restore. */ int pm_generic_restore(struct device *dev) { - return __pm_generic_call(dev, PM_EVENT_RESTORE, false); + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + return pm && pm->restore ? pm->restore(dev) : 0; } EXPORT_SYMBOL_GPL(pm_generic_restore); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index e2cc3d2e0ecc..b462c0e341cb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -47,6 +47,7 @@ typedef int (*pm_callback_t)(struct device *); LIST_HEAD(dpm_list); LIST_HEAD(dpm_prepared_list); LIST_HEAD(dpm_suspended_list); +LIST_HEAD(dpm_late_early_list); LIST_HEAD(dpm_noirq_list); struct suspend_stats suspend_stats; @@ -246,6 +247,40 @@ static pm_callback_t pm_op(const struct dev_pm_ops *ops, pm_message_t state) } /** + * pm_late_early_op - Return the PM operation appropriate for given PM event. + * @ops: PM operations to choose from. + * @state: PM transition of the system being carried out. + * + * Runtime PM is disabled for @dev while this function is being executed. + */ +static pm_callback_t pm_late_early_op(const struct dev_pm_ops *ops, + pm_message_t state) +{ + switch (state.event) { +#ifdef CONFIG_SUSPEND + case PM_EVENT_SUSPEND: + return ops->suspend_late; + case PM_EVENT_RESUME: + return ops->resume_early; +#endif /* CONFIG_SUSPEND */ +#ifdef CONFIG_HIBERNATE_CALLBACKS + case PM_EVENT_FREEZE: + case PM_EVENT_QUIESCE: + return ops->freeze_late; + case PM_EVENT_HIBERNATE: + return ops->poweroff_late; + case PM_EVENT_THAW: + case PM_EVENT_RECOVER: + return ops->thaw_early; + case PM_EVENT_RESTORE: + return ops->restore_early; +#endif /* CONFIG_HIBERNATE_CALLBACKS */ + } + + return NULL; +} + +/** * pm_noirq_op - Return the PM operation appropriate for given PM event. * @ops: PM operations to choose from. * @state: PM transition of the system being carried out. @@ -374,21 +409,21 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) TRACE_RESUME(0); if (dev->pm_domain) { - info = "EARLY power domain "; + info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); } else if (dev->type && dev->type->pm) { - info = "EARLY type "; + info = "noirq type "; callback = pm_noirq_op(dev->type->pm, state); } else if (dev->class && dev->class->pm) { - info = "EARLY class "; + info = "noirq class "; callback = pm_noirq_op(dev->class->pm, state); } else if (dev->bus && dev->bus->pm) { - info = "EARLY bus "; + info = "noirq bus "; callback = pm_noirq_op(dev->bus->pm, state); } if (!callback && dev->driver && dev->driver->pm) { - info = "EARLY driver "; + info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); } @@ -399,13 +434,13 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } /** - * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices. + * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. * - * Call the "noirq" resume handlers for all devices marked as DPM_OFF_IRQ and + * Call the "noirq" resume handlers for all devices in dpm_noirq_list and * enable device drivers to receive interrupts. */ -void dpm_resume_noirq(pm_message_t state) +static void dpm_resume_noirq(pm_message_t state) { ktime_t starttime = ktime_get(); @@ -415,7 +450,7 @@ void dpm_resume_noirq(pm_message_t state) int error; get_device(dev); - list_move_tail(&dev->power.entry, &dpm_suspended_list); + list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); error = device_resume_noirq(dev, state); @@ -423,6 +458,80 @@ void dpm_resume_noirq(pm_message_t state) suspend_stats.failed_resume_noirq++; dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } + + mutex_lock(&dpm_list_mtx); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + dpm_show_time(starttime, state, "noirq"); + resume_device_irqs(); +} + +/** + * device_resume_early - Execute an "early resume" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * + * Runtime PM is disabled for @dev while this function is being executed. + */ +static int device_resume_early(struct device *dev, pm_message_t state) +{ + pm_callback_t callback = NULL; + char *info = NULL; + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); + + if (dev->pm_domain) { + info = "early power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "early type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "early class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "early bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } + + if (!callback && dev->driver && dev->driver->pm) { + info = "early driver "; + callback = pm_late_early_op(dev->driver->pm, state); + } + + error = dpm_run_callback(callback, dev, state, info); + + TRACE_RESUME(error); + return error; +} + +/** + * dpm_resume_early - Execute "early resume" callbacks for all devices. + * @state: PM transition of the system being carried out. + */ +static void dpm_resume_early(pm_message_t state) +{ + ktime_t starttime = ktime_get(); + + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_late_early_list)) { + struct device *dev = to_device(dpm_late_early_list.next); + int error; + + get_device(dev); + list_move_tail(&dev->power.entry, &dpm_suspended_list); + mutex_unlock(&dpm_list_mtx); + + error = device_resume_early(dev, state); + if (error) { + suspend_stats.failed_resume_early++; + dpm_save_failed_step(SUSPEND_RESUME_EARLY); + dpm_save_failed_dev(dev_name(dev)); pm_dev_err(dev, state, " early", error); } @@ -431,9 +540,18 @@ void dpm_resume_noirq(pm_message_t state) } mutex_unlock(&dpm_list_mtx); dpm_show_time(starttime, state, "early"); - resume_device_irqs(); } -EXPORT_SYMBOL_GPL(dpm_resume_noirq); + +/** + * dpm_resume_start - Execute "noirq" and "early" device callbacks. + * @state: PM transition of the system being carried out. + */ +void dpm_resume_start(pm_message_t state) +{ + dpm_resume_noirq(state); + dpm_resume_early(state); +} +EXPORT_SYMBOL_GPL(dpm_resume_start); /** * device_resume - Execute "resume" callbacks for given device. @@ -716,21 +834,21 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) char *info = NULL; if (dev->pm_domain) { - info = "LATE power domain "; + info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); } else if (dev->type && dev->type->pm) { - info = "LATE type "; + info = "noirq type "; callback = pm_noirq_op(dev->type->pm, state); } else if (dev->class && dev->class->pm) { - info = "LATE class "; + info = "noirq class "; callback = pm_noirq_op(dev->class->pm, state); } else if (dev->bus && dev->bus->pm) { - info = "LATE bus "; + info = "noirq bus "; callback = pm_noirq_op(dev->bus->pm, state); } if (!callback && dev->driver && dev->driver->pm) { - info = "LATE driver "; + info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); } @@ -738,21 +856,21 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) } /** - * dpm_suspend_noirq - Execute "late suspend" callbacks for non-sysdev devices. + * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. * @state: PM transition of the system being carried out. * * Prevent device drivers from receiving interrupts and call the "noirq" suspend * handlers for all non-sysdev devices. */ -int dpm_suspend_noirq(pm_message_t state) +static int dpm_suspend_noirq(pm_message_t state) { ktime_t starttime = ktime_get(); int error = 0; suspend_device_irqs(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_suspended_list)) { - struct device *dev = to_device(dpm_suspended_list.prev); + while (!list_empty(&dpm_late_early_list)) { + struct device *dev = to_device(dpm_late_early_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); @@ -761,7 +879,7 @@ int dpm_suspend_noirq(pm_message_t state) mutex_lock(&dpm_list_mtx); if (error) { - pm_dev_err(dev, state, " late", error); + pm_dev_err(dev, state, " noirq", error); suspend_stats.failed_suspend_noirq++; dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_save_failed_dev(dev_name(dev)); @@ -776,10 +894,95 @@ int dpm_suspend_noirq(pm_message_t state) if (error) dpm_resume_noirq(resume_event(state)); else + dpm_show_time(starttime, state, "noirq"); + return error; +} + +/** + * device_suspend_late - Execute a "late suspend" callback for given device. + * @dev: Device to handle. + * @state: PM transition of the system being carried out. + * + * Runtime PM is disabled for @dev while this function is being executed. + */ +static int device_suspend_late(struct device *dev, pm_message_t state) +{ + pm_callback_t callback = NULL; + char *info = NULL; + + if (dev->pm_domain) { + info = "late power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "late type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "late class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "late bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } + + if (!callback && dev->driver && dev->driver->pm) { + info = "late driver "; + callback = pm_late_early_op(dev->driver->pm, state); + } + + return dpm_run_callback(callback, dev, state, info); +} + +/** + * dpm_suspend_late - Execute "late suspend" callbacks for all devices. + * @state: PM transition of the system being carried out. + */ +static int dpm_suspend_late(pm_message_t state) +{ + ktime_t starttime = ktime_get(); + int error = 0; + + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_suspended_list)) { + struct device *dev = to_device(dpm_suspended_list.prev); + + get_device(dev); + mutex_unlock(&dpm_list_mtx); + + error = device_suspend_late(dev, state); + + mutex_lock(&dpm_list_mtx); + if (error) { + pm_dev_err(dev, state, " late", error); + suspend_stats.failed_suspend_late++; + dpm_save_failed_step(SUSPEND_SUSPEND_LATE); + dpm_save_failed_dev(dev_name(dev)); + put_device(dev); + break; + } + if (!list_empty(&dev->power.entry)) + list_move(&dev->power.entry, &dpm_late_early_list); + put_device(dev); + } + mutex_unlock(&dpm_list_mtx); + if (error) + dpm_resume_early(resume_event(state)); + else dpm_show_time(starttime, state, "late"); + return error; } -EXPORT_SYMBOL_GPL(dpm_suspend_noirq); + +/** + * dpm_suspend_end - Execute "late" and "noirq" device suspend callbacks. + * @state: PM transition of the system being carried out. + */ +int dpm_suspend_end(pm_message_t state) +{ + int error = dpm_suspend_late(state); + + return error ? : dpm_suspend_noirq(state); +} +EXPORT_SYMBOL_GPL(dpm_suspend_end); /** * legacy_suspend - Execute a legacy (bus or class) suspend callback for device. diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 9bf62323aaf3..eeb4bff9505c 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -71,6 +71,8 @@ extern void dpm_sysfs_remove(struct device *dev); extern void rpm_sysfs_remove(struct device *dev); extern int wakeup_sysfs_add(struct device *dev); extern void wakeup_sysfs_remove(struct device *dev); +extern int pm_qos_sysfs_add(struct device *dev); +extern void pm_qos_sysfs_remove(struct device *dev); #else /* CONFIG_PM */ @@ -79,5 +81,7 @@ static inline void dpm_sysfs_remove(struct device *dev) {} static inline void rpm_sysfs_remove(struct device *dev) {} static inline int wakeup_sysfs_add(struct device *dev) { return 0; } static inline void wakeup_sysfs_remove(struct device *dev) {} +static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } +static inline void pm_qos_sysfs_remove(struct device *dev) {} #endif diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index c5d358837461..71855570922d 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -41,6 +41,7 @@ #include <linux/mutex.h> #include <linux/export.h> +#include "power.h" static DEFINE_MUTEX(dev_pm_qos_mtx); @@ -166,6 +167,12 @@ void dev_pm_qos_constraints_destroy(struct device *dev) struct dev_pm_qos_request *req, *tmp; struct pm_qos_constraints *c; + /* + * If the device's PM QoS resume latency limit has been exposed to user + * space, it has to be hidden at this point. + */ + dev_pm_qos_hide_latency_limit(dev); + mutex_lock(&dev_pm_qos_mtx); dev->power.power_state = PMSG_INVALID; @@ -445,3 +452,57 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, return error; } EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); + +#ifdef CONFIG_PM_RUNTIME +static void __dev_pm_qos_drop_user_request(struct device *dev) +{ + dev_pm_qos_remove_request(dev->power.pq_req); + dev->power.pq_req = 0; +} + +/** + * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space. + * @dev: Device whose PM QoS latency limit is to be exposed to user space. + * @value: Initial value of the latency limit. + */ +int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) +{ + struct dev_pm_qos_request *req; + int ret; + + if (!device_is_registered(dev) || value < 0) + return -EINVAL; + + if (dev->power.pq_req) + return -EEXIST; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + ret = dev_pm_qos_add_request(dev, req, value); + if (ret < 0) + return ret; + + dev->power.pq_req = req; + ret = pm_qos_sysfs_add(dev); + if (ret) + __dev_pm_qos_drop_user_request(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); + +/** + * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space. + * @dev: Device whose PM QoS latency limit is to be hidden from user space. + */ +void dev_pm_qos_hide_latency_limit(struct device *dev) +{ + if (dev->power.pq_req) { + pm_qos_sysfs_remove(dev); + __dev_pm_qos_drop_user_request(dev); + } +} +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); +#endif /* CONFIG_PM_RUNTIME */ diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index adf41be0ea66..95c12f6cb5b9 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -5,6 +5,7 @@ #include <linux/device.h> #include <linux/string.h> #include <linux/export.h> +#include <linux/pm_qos.h> #include <linux/pm_runtime.h> #include <linux/atomic.h> #include <linux/jiffies.h> @@ -217,6 +218,31 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev, static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, autosuspend_delay_ms_store); +static ssize_t pm_qos_latency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", dev->power.pq_req->node.prio); +} + +static ssize_t pm_qos_latency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + s32 value; + int ret; + + if (kstrtos32(buf, 0, &value)) + return -EINVAL; + + if (value < 0) + return -EINVAL; + + ret = dev_pm_qos_update_request(dev->power.pq_req, value); + return ret < 0 ? ret : n; +} + +static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, + pm_qos_latency_show, pm_qos_latency_store); #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP @@ -490,6 +516,17 @@ static struct attribute_group pm_runtime_attr_group = { .attrs = runtime_attrs, }; +static struct attribute *pm_qos_attrs[] = { +#ifdef CONFIG_PM_RUNTIME + &dev_attr_pm_qos_resume_latency_us.attr, +#endif /* CONFIG_PM_RUNTIME */ + NULL, +}; +static struct attribute_group pm_qos_attr_group = { + .name = power_group_name, + .attrs = pm_qos_attrs, +}; + int dpm_sysfs_add(struct device *dev) { int rc; @@ -530,6 +567,16 @@ void wakeup_sysfs_remove(struct device *dev) sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); } +int pm_qos_sysfs_add(struct device *dev) +{ + return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group); +} + +void pm_qos_sysfs_remove(struct device *dev) +{ + sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group); +} + void rpm_sysfs_remove(struct device *dev) { sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index caf995fb774b..2a3e581b8dcd 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -53,6 +53,23 @@ static void pm_wakeup_timer_fn(unsigned long data); static LIST_HEAD(wakeup_sources); /** + * wakeup_source_prepare - Prepare a new wakeup source for initialization. + * @ws: Wakeup source to prepare. + * @name: Pointer to the name of the new wakeup source. + * + * Callers must ensure that the @name string won't be freed when @ws is still in + * use. + */ +void wakeup_source_prepare(struct wakeup_source *ws, const char *name) +{ + if (ws) { + memset(ws, 0, sizeof(*ws)); + ws->name = name; + } +} +EXPORT_SYMBOL_GPL(wakeup_source_prepare); + +/** * wakeup_source_create - Create a struct wakeup_source object. * @name: Name of the new wakeup source. */ @@ -60,37 +77,44 @@ struct wakeup_source *wakeup_source_create(const char *name) { struct wakeup_source *ws; - ws = kzalloc(sizeof(*ws), GFP_KERNEL); + ws = kmalloc(sizeof(*ws), GFP_KERNEL); if (!ws) return NULL; - spin_lock_init(&ws->lock); - if (name) - ws->name = kstrdup(name, GFP_KERNEL); - + wakeup_source_prepare(ws, name ? kstrdup(name, GFP_KERNEL) : NULL); return ws; } EXPORT_SYMBOL_GPL(wakeup_source_create); /** + * wakeup_source_drop - Prepare a struct wakeup_source object for destruction. + * @ws: Wakeup source to prepare for destruction. + * + * Callers must ensure that __pm_stay_awake() or __pm_wakeup_event() will never + * be run in parallel with this function for the same wakeup source object. + */ +void wakeup_source_drop(struct wakeup_source *ws) +{ + if (!ws) + return; + + del_timer_sync(&ws->timer); + __pm_relax(ws); +} +EXPORT_SYMBOL_GPL(wakeup_source_drop); + +/** * wakeup_source_destroy - Destroy a struct wakeup_source object. * @ws: Wakeup source to destroy. + * + * Use only for wakeup source objects created with wakeup_source_create(). */ void wakeup_source_destroy(struct wakeup_source *ws) { if (!ws) return; - spin_lock_irq(&ws->lock); - while (ws->active) { - spin_unlock_irq(&ws->lock); - - schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT)); - - spin_lock_irq(&ws->lock); - } - spin_unlock_irq(&ws->lock); - + wakeup_source_drop(ws); kfree(ws->name); kfree(ws); } @@ -105,6 +129,7 @@ void wakeup_source_add(struct wakeup_source *ws) if (WARN_ON(!ws)) return; + spin_lock_init(&ws->lock); setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws); ws->active = false; @@ -152,8 +177,10 @@ EXPORT_SYMBOL_GPL(wakeup_source_register); */ void wakeup_source_unregister(struct wakeup_source *ws) { - wakeup_source_remove(ws); - wakeup_source_destroy(ws); + if (ws) { + wakeup_source_remove(ws); + wakeup_source_destroy(ws); + } } EXPORT_SYMBOL_GPL(wakeup_source_unregister); @@ -349,7 +376,6 @@ static void wakeup_source_activate(struct wakeup_source *ws) { ws->active = true; ws->active_count++; - ws->timer_expires = jiffies; ws->last_time = ktime_get(); /* Increment the counter of events in progress. */ @@ -370,9 +396,14 @@ void __pm_stay_awake(struct wakeup_source *ws) return; spin_lock_irqsave(&ws->lock, flags); + ws->event_count++; if (!ws->active) wakeup_source_activate(ws); + + del_timer(&ws->timer); + ws->timer_expires = 0; + spin_unlock_irqrestore(&ws->lock, flags); } EXPORT_SYMBOL_GPL(__pm_stay_awake); @@ -438,6 +469,7 @@ static void wakeup_source_deactivate(struct wakeup_source *ws) ws->max_time = duration; del_timer(&ws->timer); + ws->timer_expires = 0; /* * Increment the counter of registered wakeup events and decrement the @@ -492,11 +524,22 @@ EXPORT_SYMBOL_GPL(pm_relax); * pm_wakeup_timer_fn - Delayed finalization of a wakeup event. * @data: Address of the wakeup source object associated with the event source. * - * Call __pm_relax() for the wakeup source whose address is stored in @data. + * Call wakeup_source_deactivate() for the wakeup source whose address is stored + * in @data if it is currently active and its timer has not been canceled and + * the expiration time of the timer is not in future. */ static void pm_wakeup_timer_fn(unsigned long data) { - __pm_relax((struct wakeup_source *)data); + struct wakeup_source *ws = (struct wakeup_source *)data; + unsigned long flags; + + spin_lock_irqsave(&ws->lock, flags); + + if (ws->active && ws->timer_expires + && time_after_eq(jiffies, ws->timer_expires)) + wakeup_source_deactivate(ws); + + spin_unlock_irqrestore(&ws->lock, flags); } /** @@ -534,7 +577,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) if (!expires) expires = 1; - if (time_after(expires, ws->timer_expires)) { + if (!ws->timer_expires || time_after(expires, ws->timer_expires)) { mod_timer(&ws->timer, expires); ws->timer_expires = expires; } diff --git a/drivers/block/brd.c b/drivers/block/brd.c index ec246437f5a4..531ceb31d0ff 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -242,9 +242,9 @@ static void copy_to_brd(struct brd_device *brd, const void *src, page = brd_lookup_page(brd, sector); BUG_ON(!page); - dst = kmap_atomic(page, KM_USER1); + dst = kmap_atomic(page); memcpy(dst + offset, src, copy); - kunmap_atomic(dst, KM_USER1); + kunmap_atomic(dst); if (copy < n) { src += copy; @@ -253,9 +253,9 @@ static void copy_to_brd(struct brd_device *brd, const void *src, page = brd_lookup_page(brd, sector); BUG_ON(!page); - dst = kmap_atomic(page, KM_USER1); + dst = kmap_atomic(page); memcpy(dst, src, copy); - kunmap_atomic(dst, KM_USER1); + kunmap_atomic(dst); } } @@ -273,9 +273,9 @@ static void copy_from_brd(void *dst, struct brd_device *brd, copy = min_t(size_t, n, PAGE_SIZE - offset); page = brd_lookup_page(brd, sector); if (page) { - src = kmap_atomic(page, KM_USER1); + src = kmap_atomic(page); memcpy(dst, src + offset, copy); - kunmap_atomic(src, KM_USER1); + kunmap_atomic(src); } else memset(dst, 0, copy); @@ -285,9 +285,9 @@ static void copy_from_brd(void *dst, struct brd_device *brd, copy = n - copy; page = brd_lookup_page(brd, sector); if (page) { - src = kmap_atomic(page, KM_USER1); + src = kmap_atomic(page); memcpy(dst, src, copy); - kunmap_atomic(src, KM_USER1); + kunmap_atomic(src); } else memset(dst, 0, copy); } @@ -309,7 +309,7 @@ static int brd_do_bvec(struct brd_device *brd, struct page *page, goto out; } - mem = kmap_atomic(page, KM_USER0); + mem = kmap_atomic(page); if (rw == READ) { copy_from_brd(mem + off, brd, sector, len); flush_dcache_page(page); @@ -317,7 +317,7 @@ static int brd_do_bvec(struct brd_device *brd, struct page *page, flush_dcache_page(page); copy_to_brd(brd, mem + off, sector, len); } - kunmap_atomic(mem, KM_USER0); + kunmap_atomic(mem); out: return err; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 912f585a760f..3030201c69d8 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -289,25 +289,25 @@ static unsigned int bm_bit_to_page_idx(struct drbd_bitmap *b, u64 bitnr) return page_nr; } -static unsigned long *__bm_map_pidx(struct drbd_bitmap *b, unsigned int idx, const enum km_type km) +static unsigned long *__bm_map_pidx(struct drbd_bitmap *b, unsigned int idx) { struct page *page = b->bm_pages[idx]; - return (unsigned long *) kmap_atomic(page, km); + return (unsigned long *) kmap_atomic(page); } static unsigned long *bm_map_pidx(struct drbd_bitmap *b, unsigned int idx) { - return __bm_map_pidx(b, idx, KM_IRQ1); + return __bm_map_pidx(b, idx); } -static void __bm_unmap(unsigned long *p_addr, const enum km_type km) +static void __bm_unmap(unsigned long *p_addr) { - kunmap_atomic(p_addr, km); + kunmap_atomic(p_addr); }; static void bm_unmap(unsigned long *p_addr) { - return __bm_unmap(p_addr, KM_IRQ1); + return __bm_unmap(p_addr); } /* long word offset of _bitmap_ sector */ @@ -543,15 +543,15 @@ static unsigned long bm_count_bits(struct drbd_bitmap *b) /* all but last page */ for (idx = 0; idx < b->bm_number_of_pages - 1; idx++) { - p_addr = __bm_map_pidx(b, idx, KM_USER0); + p_addr = __bm_map_pidx(b, idx); for (i = 0; i < LWPP; i++) bits += hweight_long(p_addr[i]); - __bm_unmap(p_addr, KM_USER0); + __bm_unmap(p_addr); cond_resched(); } /* last (or only) page */ last_word = ((b->bm_bits - 1) & BITS_PER_PAGE_MASK) >> LN2_BPL; - p_addr = __bm_map_pidx(b, idx, KM_USER0); + p_addr = __bm_map_pidx(b, idx); for (i = 0; i < last_word; i++) bits += hweight_long(p_addr[i]); p_addr[last_word] &= cpu_to_lel(mask); @@ -559,7 +559,7 @@ static unsigned long bm_count_bits(struct drbd_bitmap *b) /* 32bit arch, may have an unused padding long */ if (BITS_PER_LONG == 32 && (last_word & 1) == 0) p_addr[last_word+1] = 0; - __bm_unmap(p_addr, KM_USER0); + __bm_unmap(p_addr); return bits; } @@ -970,11 +970,11 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must * to use pre-allocated page pool */ void *src, *dest; page = alloc_page(__GFP_HIGHMEM|__GFP_WAIT); - dest = kmap_atomic(page, KM_USER0); - src = kmap_atomic(b->bm_pages[page_nr], KM_USER1); + dest = kmap_atomic(page); + src = kmap_atomic(b->bm_pages[page_nr]); memcpy(dest, src, PAGE_SIZE); - kunmap_atomic(src, KM_USER1); - kunmap_atomic(dest, KM_USER0); + kunmap_atomic(src); + kunmap_atomic(dest); bm_store_page_idx(page, page_nr); } else page = b->bm_pages[page_nr]; @@ -1163,7 +1163,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc * this returns a bit number, NOT a sector! */ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, - const int find_zero_bit, const enum km_type km) + const int find_zero_bit) { struct drbd_bitmap *b = mdev->bitmap; unsigned long *p_addr; @@ -1178,7 +1178,7 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, while (bm_fo < b->bm_bits) { /* bit offset of the first bit in the page */ bit_offset = bm_fo & ~BITS_PER_PAGE_MASK; - p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); + p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo)); if (find_zero_bit) i = find_next_zero_bit_le(p_addr, @@ -1187,7 +1187,7 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, i = find_next_bit_le(p_addr, PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); - __bm_unmap(p_addr, km); + __bm_unmap(p_addr); if (i < PAGE_SIZE*8) { bm_fo = bit_offset + i; if (bm_fo >= b->bm_bits) @@ -1215,7 +1215,7 @@ static unsigned long bm_find_next(struct drbd_conf *mdev, if (BM_DONT_TEST & b->bm_flags) bm_print_lock_info(mdev); - i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1); + i = __bm_find_next(mdev, bm_fo, find_zero_bit); spin_unlock_irq(&b->bm_lock); return i; @@ -1239,13 +1239,13 @@ unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo) { /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */ - return __bm_find_next(mdev, bm_fo, 0, KM_USER1); + return __bm_find_next(mdev, bm_fo, 0); } unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo) { /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */ - return __bm_find_next(mdev, bm_fo, 1, KM_USER1); + return __bm_find_next(mdev, bm_fo, 1); } /* returns number of bits actually changed. @@ -1273,14 +1273,14 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, unsigned int page_nr = bm_bit_to_page_idx(b, bitnr); if (page_nr != last_page_nr) { if (p_addr) - __bm_unmap(p_addr, KM_IRQ1); + __bm_unmap(p_addr); if (c < 0) bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); else if (c > 0) bm_set_page_need_writeout(b->bm_pages[last_page_nr]); changed_total += c; c = 0; - p_addr = __bm_map_pidx(b, page_nr, KM_IRQ1); + p_addr = __bm_map_pidx(b, page_nr); last_page_nr = page_nr; } if (val) @@ -1289,7 +1289,7 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); } if (p_addr) - __bm_unmap(p_addr, KM_IRQ1); + __bm_unmap(p_addr); if (c < 0) bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); else if (c > 0) @@ -1342,13 +1342,13 @@ static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b, { int i; int bits; - unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_IRQ1); + unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr]); for (i = first_word; i < last_word; i++) { bits = hweight_long(paddr[i]); paddr[i] = ~0UL; b->bm_set += BITS_PER_LONG - bits; } - kunmap_atomic(paddr, KM_IRQ1); + kunmap_atomic(paddr); } /* Same thing as drbd_bm_set_bits, diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index af2a25049bce..e09f9cebbb20 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2526,10 +2526,10 @@ void drbd_bcast_ee(struct drbd_conf *mdev, page = e->pages; page_chain_for_each(page) { - void *d = kmap_atomic(page, KM_USER0); + void *d = kmap_atomic(page); unsigned l = min_t(unsigned, len, PAGE_SIZE); memcpy(tl, d, l); - kunmap_atomic(d, KM_USER0); + kunmap_atomic(d); tl = (unsigned short*)((char*)tl + l); len -= l; if (len == 0) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index cd504353b278..bbca966f8f66 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -93,16 +93,16 @@ static int transfer_none(struct loop_device *lo, int cmd, struct page *loop_page, unsigned loop_off, int size, sector_t real_block) { - char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; - char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; + char *raw_buf = kmap_atomic(raw_page) + raw_off; + char *loop_buf = kmap_atomic(loop_page) + loop_off; if (cmd == READ) memcpy(loop_buf, raw_buf, size); else memcpy(raw_buf, loop_buf, size); - kunmap_atomic(loop_buf, KM_USER1); - kunmap_atomic(raw_buf, KM_USER0); + kunmap_atomic(loop_buf); + kunmap_atomic(raw_buf); cond_resched(); return 0; } @@ -112,8 +112,8 @@ static int transfer_xor(struct loop_device *lo, int cmd, struct page *loop_page, unsigned loop_off, int size, sector_t real_block) { - char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; - char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; + char *raw_buf = kmap_atomic(raw_page) + raw_off; + char *loop_buf = kmap_atomic(loop_page) + loop_off; char *in, *out, *key; int i, keysize; @@ -130,8 +130,8 @@ static int transfer_xor(struct loop_device *lo, int cmd, for (i = 0; i < size; i++) *out++ = *in++ ^ key[(i & 511) % keysize]; - kunmap_atomic(loop_buf, KM_USER1); - kunmap_atomic(raw_buf, KM_USER0); + kunmap_atomic(loop_buf); + kunmap_atomic(raw_buf); cond_resched(); return 0; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index d59edeabd93f..ba66e4445f41 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -987,14 +987,14 @@ static void pkt_copy_bio_data(struct bio *src_bio, int seg, int offs, struct pag while (copy_size > 0) { struct bio_vec *src_bvl = bio_iovec_idx(src_bio, seg); - void *vfrom = kmap_atomic(src_bvl->bv_page, KM_USER0) + + void *vfrom = kmap_atomic(src_bvl->bv_page) + src_bvl->bv_offset + offs; void *vto = page_address(dst_page) + dst_offs; int len = min_t(int, copy_size, src_bvl->bv_len - offs); BUG_ON(len < 0); memcpy(vto, vfrom, len); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); seg++; offs = 0; @@ -1019,10 +1019,10 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec) offs = 0; for (f = 0; f < pkt->frames; f++) { if (bvec[f].bv_page != pkt->pages[p]) { - void *vfrom = kmap_atomic(bvec[f].bv_page, KM_USER0) + bvec[f].bv_offset; + void *vfrom = kmap_atomic(bvec[f].bv_page) + bvec[f].bv_offset; void *vto = page_address(pkt->pages[p]) + offs; memcpy(vto, vfrom, CD_FRAMESIZE); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); bvec[f].bv_page = pkt->pages[p]; bvec[f].bv_offset = offs; } else { diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c index 0bc0cb70210b..de473ef3882b 100644 --- a/drivers/char/hw_random/tx4939-rng.c +++ b/drivers/char/hw_random/tx4939-rng.c @@ -115,10 +115,7 @@ static int __init tx4939_rng_probe(struct platform_device *dev) rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL); if (!rngdev) return -ENOMEM; - if (!devm_request_mem_region(&dev->dev, r->start, resource_size(r), - dev_name(&dev->dev))) - return -EBUSY; - rngdev->base = devm_ioremap(&dev->dev, r->start, resource_size(r)); + rngdev->base = devm_request_and_ioremap(&dev->dev, r); if (!rngdev->base) return -EBUSY; diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 7fc75e47e6d0..a048199ce866 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -5,7 +5,6 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM - depends on EXPERIMENTAL select SECURITYFS ---help--- If you have a TPM security chip in your system, which diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 32362cf35b8d..ad7c7320dd1b 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1221,12 +1221,13 @@ ssize_t tpm_read(struct file *file, char __user *buf, ret_size = atomic_read(&chip->data_pending); atomic_set(&chip->data_pending, 0); if (ret_size > 0) { /* relay data */ + ssize_t orig_ret_size = ret_size; if (size < ret_size) ret_size = size; mutex_lock(&chip->buffer_mutex); rc = copy_to_user(buf, chip->data_buffer, ret_size); - memset(chip->data_buffer, 0, ret_size); + memset(chip->data_buffer, 0, orig_ret_size); if (rc) ret_size = -EFAULT; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 010547138281..b1c5280ac159 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -99,6 +99,8 @@ struct tpm_vendor_specific { wait_queue_head_t int_queue; }; +#define TPM_VID_INTEL 0x8086 + struct tpm_chip { struct device *dev; /* Device stuff */ diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 70fac9abb0e2..d2a70cae76df 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -367,7 +367,12 @@ static int probe_itpm(struct tpm_chip *chip) 0x00, 0x00, 0x00, 0xf1 }; size_t len = sizeof(cmd_getticks); - int rem_itpm = itpm; + bool rem_itpm = itpm; + u16 vendor = ioread16(chip->vendor.iobase + TPM_DID_VID(0)); + + /* probe only iTPMS */ + if (vendor != TPM_VID_INTEL) + return 0; itpm = 0; @@ -390,9 +395,6 @@ static int probe_itpm(struct tpm_chip *chip) out: itpm = rem_itpm; tpm_tis_ready(chip); - /* some TPMs need a break here otherwise they will not work - * correctly on the immediately subsequent command */ - msleep(chip->vendor.timeout_b); release_locality(chip, chip->vendor.locality, 0); return rc; @@ -508,7 +510,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, resource_size_t len, unsigned int irq) { u32 vendor, intfcaps, intmask; - int rc, i, irq_s, irq_e; + int rc, i, irq_s, irq_e, probe; struct tpm_chip *chip; if (!(chip = tpm_register_hardware(dev, &tpm_tis))) @@ -538,11 +540,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); if (!itpm) { - itpm = probe_itpm(chip); - if (itpm < 0) { + probe = probe_itpm(chip); + if (probe < 0) { rc = -ENODEV; goto out_err; } + itpm = (probe == 0) ? 0 : 1; } if (itpm) diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index ca09bc421ddb..32fe9ef5cc5c 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -32,6 +32,7 @@ #include <linux/sh_timer.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/pm_domain.h> struct sh_cmt_priv { void __iomem *mapbase; @@ -689,6 +690,9 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev) struct sh_cmt_priv *p = platform_get_drvdata(pdev); int ret; + if (!is_early_platform_device(pdev)) + pm_genpd_dev_always_on(&pdev->dev, true); + if (p) { dev_info(&pdev->dev, "kept as earlytimer\n"); return 0; diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index db8d5955bad4..a2172f690418 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -31,6 +31,7 @@ #include <linux/sh_timer.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/pm_domain.h> struct sh_mtu2_priv { void __iomem *mapbase; @@ -306,6 +307,9 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev) struct sh_mtu2_priv *p = platform_get_drvdata(pdev); int ret; + if (!is_early_platform_device(pdev)) + pm_genpd_dev_always_on(&pdev->dev, true); + if (p) { dev_info(&pdev->dev, "kept as earlytimer\n"); return 0; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 079e96ad44e8..97f54b634be4 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -32,6 +32,7 @@ #include <linux/sh_timer.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/pm_domain.h> struct sh_tmu_priv { void __iomem *mapbase; @@ -410,6 +411,9 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev) struct sh_tmu_priv *p = platform_get_drvdata(pdev); int ret; + if (!is_early_platform_device(pdev)) + pm_genpd_dev_always_on(&pdev->dev, true); + if (p) { dev_info(&pdev->dev, "kept as earlytimer\n"); return 0; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 6d16b4b0d7a0..e707979767fb 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -293,4 +293,15 @@ config CRYPTO_DEV_S5P Select this to offload Samsung S5PV210 or S5PC110 from AES algorithms execution. +config CRYPTO_DEV_TEGRA_AES + tristate "Support for TEGRA AES hw engine" + depends on ARCH_TEGRA + select CRYPTO_AES + help + TEGRA processors have AES module accelerator. Select this if you + want to use the TEGRA module for AES algorithms. + + To compile this driver as a module, choose M here: the module + will be called tegra-aes. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 53ea50155319..f3e64eadd7af 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o +obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index e73cf2e8110a..534a36469d57 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1844,6 +1844,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha224),cbc(aes))", + .driver_name = "authenc-hmac-sha224-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .template_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "<built-in>", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha256),cbc(aes))", .driver_name = "authenc-hmac-sha256-cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, @@ -1864,6 +1883,26 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha384),cbc(aes))", + .driver_name = "authenc-hmac-sha384-cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .template_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "<built-in>", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + + { .name = "authenc(hmac(sha512),cbc(aes))", .driver_name = "authenc-hmac-sha512-cbc-aes-caam", .blocksize = AES_BLOCK_SIZE, @@ -1922,6 +1961,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha224),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha224-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .template_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "<built-in>", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha256),cbc(des3_ede))", .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam", .blocksize = DES3_EDE_BLOCK_SIZE, @@ -1942,6 +2000,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha384),cbc(des3_ede))", + .driver_name = "authenc-hmac-sha384-cbc-des3_ede-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .template_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "<built-in>", + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha512),cbc(des3_ede))", .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam", .blocksize = DES3_EDE_BLOCK_SIZE, @@ -2000,6 +2077,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha224),cbc(des))", + .driver_name = "authenc-hmac-sha224-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .template_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "<built-in>", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha256),cbc(des))", .driver_name = "authenc-hmac-sha256-cbc-des-caam", .blocksize = DES_BLOCK_SIZE, @@ -2020,6 +2116,25 @@ static struct caam_alg_template driver_algs[] = { .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, { + .name = "authenc(hmac(sha384),cbc(des))", + .driver_name = "authenc-hmac-sha384-cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .template_aead = { + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .givencrypt = aead_givencrypt, + .geniv = "<built-in>", + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + { .name = "authenc(hmac(sha512),cbc(des))", .driver_name = "authenc-hmac-sha512-cbc-des-caam", .blocksize = DES_BLOCK_SIZE, @@ -2205,7 +2320,8 @@ static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, alg->cra_blocksize = template->blocksize; alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct caam_ctx); - alg->cra_flags = CRYPTO_ALG_ASYNC | template->type; + alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + template->type; switch (template->type) { case CRYPTO_ALG_TYPE_ABLKCIPHER: alg->cra_type = &crypto_ablkcipher_type; @@ -2285,12 +2401,12 @@ static int __init caam_algapi_init(void) dev_warn(ctrldev, "%s alg registration failed\n", t_alg->crypto_alg.cra_driver_name); kfree(t_alg); - } else { + } else list_add_tail(&t_alg->entry, &priv->alg_list); - dev_info(ctrldev, "%s\n", - t_alg->crypto_alg.cra_driver_name); - } } + if (!list_empty(&priv->alg_list)) + dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", + (char *)of_get_property(dev_node, "compatible", NULL)); return err; } diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 8ae3ba2a160d..c5f61c55d923 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -46,7 +46,7 @@ static int caam_remove(struct platform_device *pdev) /* Probe routine for CAAM top (controller) level */ static int caam_probe(struct platform_device *pdev) { - int d, ring, rspec; + int ring, rspec; struct device *dev; struct device_node *nprop, *np; struct caam_ctrl __iomem *ctrl; diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 219d09cbb0d1..f3e36c86b6c3 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -393,7 +393,8 @@ static struct crypto_alg geode_cbc_alg = { .cra_driver_name = "cbc-aes-geode", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, @@ -479,7 +480,8 @@ static struct crypto_alg geode_ecb_alg = { .cra_driver_name = "ecb-aes-geode", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index fe765f49de58..c9c4befb5a8d 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -1731,9 +1731,9 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset while (size) { copy = min3(srest, dst->length, size); - daddr = kmap_atomic(sg_page(dst), KM_IRQ0); + daddr = kmap_atomic(sg_page(dst)); memcpy(daddr + dst->offset + offset, saddr, copy); - kunmap_atomic(daddr, KM_IRQ0); + kunmap_atomic(daddr); nbytes -= copy; size -= copy; @@ -1793,17 +1793,17 @@ static void hifn_process_ready(struct ablkcipher_request *req, int error) continue; } - saddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0); + saddr = kmap_atomic(sg_page(t)); err = ablkcipher_get(saddr, &t->length, t->offset, dst, nbytes, &nbytes); if (err < 0) { - kunmap_atomic(saddr, KM_SOFTIRQ0); + kunmap_atomic(saddr); break; } idx += err; - kunmap_atomic(saddr, KM_SOFTIRQ0); + kunmap_atomic(saddr); } hifn_cipher_walk_exit(&rctx->walk); @@ -2494,7 +2494,8 @@ static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t) t->drv_name, dev->name); alg->alg.cra_priority = 300; - alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; + alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; alg->alg.cra_blocksize = t->bsize; alg->alg.cra_ctxsize = sizeof(struct hifn_context); alg->alg.cra_alignmask = 0; diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 4c20c5bf6058..0053d7ebb5ca 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -265,7 +265,7 @@ static int setup_crypt_desc(void) BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64); crypt_virt = dma_alloc_coherent(dev, NPE_QLEN * sizeof(struct crypt_ctl), - &crypt_phys, GFP_KERNEL); + &crypt_phys, GFP_ATOMIC); if (!crypt_virt) return -ENOMEM; memset(crypt_virt, 0, NPE_QLEN * sizeof(struct crypt_ctl)); @@ -1449,6 +1449,7 @@ static int __init ixp_module_init(void) /* block ciphers */ cra->cra_type = &crypto_ablkcipher_type; cra->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; if (!cra->cra_ablkcipher.setkey) cra->cra_ablkcipher.setkey = ablk_setkey; @@ -1461,6 +1462,7 @@ static int __init ixp_module_init(void) /* authenc */ cra->cra_type = &crypto_aead_type; cra->cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; cra->cra_aead.setkey = aead_setkey; cra->cra_aead.setauthsize = aead_setauthsize; diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 0d40cf66b3cc..e6ecc5f23943 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -899,7 +899,8 @@ struct crypto_alg mv_aes_alg_ecb = { .cra_name = "ecb(aes)", .cra_driver_name = "mv-ecb-aes", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, .cra_blocksize = 16, .cra_ctxsize = sizeof(struct mv_ctx), .cra_alignmask = 0, @@ -921,7 +922,8 @@ struct crypto_alg mv_aes_alg_cbc = { .cra_name = "cbc(aes)", .cra_driver_name = "mv-cbc-aes", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_ctx), .cra_alignmask = 0, @@ -953,7 +955,8 @@ struct ahash_alg mv_sha1_alg = { .cra_driver_name = "mv-sha1", .cra_priority = 300, .cra_flags = - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), .cra_init = mv_cra_hash_sha1_init, @@ -977,7 +980,8 @@ struct ahash_alg mv_hmac_sha1_alg = { .cra_driver_name = "mv-hmac-sha1", .cra_priority = 300, .cra_flags = - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), .cra_init = mv_cra_hash_hmac_sha1_init, diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 8944dabc0e3c..67b97c5fd859 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1402,7 +1402,8 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl) snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->drv_name); alg->cra_priority = N2_CRA_PRIORITY; - alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; + alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; alg->cra_blocksize = tmpl->block_size; p->enc_type = tmpl->enc_type; alg->cra_ctxsize = sizeof(struct n2_cipher_context); @@ -1493,7 +1494,9 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->name); base->cra_priority = N2_CRA_PRIORITY; - base->cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK; + base->cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK; base->cra_blocksize = tmpl->block_size; base->cra_ctxsize = sizeof(struct n2_hash_ctx); base->cra_module = THIS_MODULE; diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 5b970d9e9956..63e57b57a12c 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -756,7 +756,9 @@ static struct crypto_alg algs[] = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-omap", .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), .cra_alignmask = 0, @@ -776,7 +778,9 @@ static struct crypto_alg algs[] = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-omap", .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), .cra_alignmask = 0, diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 6399a8f1938a..a3fd6fc504b1 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -953,6 +953,7 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-sha1", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -975,6 +976,7 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-md5", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -998,6 +1000,7 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-hmac-sha1", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -1022,6 +1025,7 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-hmac-md5", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index 58480d009324..410a03c01ca4 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -1322,6 +1322,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_driver_name = "cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, @@ -1349,6 +1350,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_driver_name = "ecb-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), @@ -1373,7 +1375,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "cbc(des)", .cra_driver_name = "cbc-des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1398,7 +1402,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "ecb(des)", .cra_driver_name = "ecb-des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1422,7 +1428,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "cbc(des3_ede)", .cra_driver_name = "cbc-des3-ede-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1447,7 +1455,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "ecb(des3_ede)", .cra_driver_name = "ecb-des3-ede-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1472,7 +1482,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha1),cbc(aes))", .cra_driver_name = "authenc-hmac-sha1-cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1500,7 +1512,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha256),cbc(aes))", .cra_driver_name = "authenc-hmac-sha256-cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1527,7 +1541,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(md5),cbc(aes))", .cra_driver_name = "authenc-hmac-md5-cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1554,7 +1570,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha1-cbc-3des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1582,7 +1600,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha256),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha256-cbc-3des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1609,7 +1629,9 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(md5),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-md5-cbc-3des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1639,7 +1661,9 @@ static struct spacc_alg l2_engine_algs[] = { .cra_name = "f8(kasumi)", .cra_driver_name = "f8-kasumi-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = 8, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 3376bca200fc..bc986f806086 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -518,7 +518,8 @@ static struct crypto_alg algs[] = { .cra_driver_name = "ecb-aes-s5p", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC, + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, @@ -538,7 +539,8 @@ static struct crypto_alg algs[] = { .cra_driver_name = "cbc-aes-s5p", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC, + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 2d8c78901686..dc641c796526 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2648,6 +2648,7 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, alg->cra_priority = TALITOS_CRA_PRIORITY; alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct talitos_ctx); + alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY; t_alg->dev = dev; diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c new file mode 100644 index 000000000000..422a9766c7c9 --- /dev/null +++ b/drivers/crypto/tegra-aes.c @@ -0,0 +1,1096 @@ +/* + * drivers/crypto/tegra-aes.c + * + * Driver for NVIDIA Tegra AES hardware engine residing inside the + * Bit Stream Engine for Video (BSEV) hardware block. + * + * The programming sequence for this engine is with the help + * of commands which travel via a command queue residing between the + * CPU and the BSEV block. The BSEV engine has an internal RAM (VRAM) + * where the final input plaintext, keys and the IV have to be copied + * before starting the encrypt/decrypt operation. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/completion.h> +#include <linux/workqueue.h> + +#include <mach/clk.h> + +#include <crypto/scatterwalk.h> +#include <crypto/aes.h> +#include <crypto/internal/rng.h> + +#include "tegra-aes.h" + +#define FLAGS_MODE_MASK 0x00FF +#define FLAGS_ENCRYPT BIT(0) +#define FLAGS_CBC BIT(1) +#define FLAGS_GIV BIT(2) +#define FLAGS_RNG BIT(3) +#define FLAGS_OFB BIT(4) +#define FLAGS_NEW_KEY BIT(5) +#define FLAGS_NEW_IV BIT(6) +#define FLAGS_INIT BIT(7) +#define FLAGS_FAST BIT(8) +#define FLAGS_BUSY 9 + +/* + * Defines AES engine Max process bytes size in one go, which takes 1 msec. + * AES engine spends about 176 cycles/16-bytes or 11 cycles/byte + * The duration CPU can use the BSE to 1 msec, then the number of available + * cycles of AVP/BSE is 216K. In this duration, AES can process 216/11 ~= 19KB + * Based on this AES_HW_DMA_BUFFER_SIZE_BYTES is configured to 16KB. + */ +#define AES_HW_DMA_BUFFER_SIZE_BYTES 0x4000 + +/* + * The key table length is 64 bytes + * (This includes first upto 32 bytes key + 16 bytes original initial vector + * and 16 bytes updated initial vector) + */ +#define AES_HW_KEY_TABLE_LENGTH_BYTES 64 + +/* + * The memory being used is divides as follows: + * 1. Key - 32 bytes + * 2. Original IV - 16 bytes + * 3. Updated IV - 16 bytes + * 4. Key schedule - 256 bytes + * + * 1+2+3 constitute the hw key table. + */ +#define AES_HW_IV_SIZE 16 +#define AES_HW_KEYSCHEDULE_LEN 256 +#define AES_IVKEY_SIZE (AES_HW_KEY_TABLE_LENGTH_BYTES + AES_HW_KEYSCHEDULE_LEN) + +/* Define commands required for AES operation */ +enum { + CMD_BLKSTARTENGINE = 0x0E, + CMD_DMASETUP = 0x10, + CMD_DMACOMPLETE = 0x11, + CMD_SETTABLE = 0x15, + CMD_MEMDMAVD = 0x22, +}; + +/* Define sub-commands */ +enum { + SUBCMD_VRAM_SEL = 0x1, + SUBCMD_CRYPTO_TABLE_SEL = 0x3, + SUBCMD_KEY_TABLE_SEL = 0x8, +}; + +/* memdma_vd command */ +#define MEMDMA_DIR_DTOVRAM 0 /* sdram -> vram */ +#define MEMDMA_DIR_VTODRAM 1 /* vram -> sdram */ +#define MEMDMA_DIR_SHIFT 25 +#define MEMDMA_NUM_WORDS_SHIFT 12 + +/* command queue bit shifts */ +enum { + CMDQ_KEYTABLEADDR_SHIFT = 0, + CMDQ_KEYTABLEID_SHIFT = 17, + CMDQ_VRAMSEL_SHIFT = 23, + CMDQ_TABLESEL_SHIFT = 24, + CMDQ_OPCODE_SHIFT = 26, +}; + +/* + * The secure key slot contains a unique secure key generated + * and loaded by the bootloader. This slot is marked as non-accessible + * to the kernel. + */ +#define SSK_SLOT_NUM 4 + +#define AES_NR_KEYSLOTS 8 +#define TEGRA_AES_QUEUE_LENGTH 50 +#define DEFAULT_RNG_BLK_SZ 16 + +/* The command queue depth */ +#define AES_HW_MAX_ICQ_LENGTH 5 + +struct tegra_aes_slot { + struct list_head node; + int slot_num; +}; + +static struct tegra_aes_slot ssk = { + .slot_num = SSK_SLOT_NUM, +}; + +struct tegra_aes_reqctx { + unsigned long mode; +}; + +struct tegra_aes_dev { + struct device *dev; + void __iomem *io_base; + dma_addr_t ivkey_phys_base; + void __iomem *ivkey_base; + struct clk *aes_clk; + struct tegra_aes_ctx *ctx; + int irq; + unsigned long flags; + struct completion op_complete; + u32 *buf_in; + dma_addr_t dma_buf_in; + u32 *buf_out; + dma_addr_t dma_buf_out; + u8 *iv; + u8 dt[DEFAULT_RNG_BLK_SZ]; + int ivlen; + u64 ctr; + spinlock_t lock; + struct crypto_queue queue; + struct tegra_aes_slot *slots; + struct ablkcipher_request *req; + size_t total; + struct scatterlist *in_sg; + size_t in_offset; + struct scatterlist *out_sg; + size_t out_offset; +}; + +static struct tegra_aes_dev *aes_dev; + +struct tegra_aes_ctx { + struct tegra_aes_dev *dd; + unsigned long flags; + struct tegra_aes_slot *slot; + u8 key[AES_MAX_KEY_SIZE]; + size_t keylen; +}; + +static struct tegra_aes_ctx rng_ctx = { + .flags = FLAGS_NEW_KEY, + .keylen = AES_KEYSIZE_128, +}; + +/* keep registered devices data here */ +static struct list_head dev_list; +static DEFINE_SPINLOCK(list_lock); +static DEFINE_MUTEX(aes_lock); + +static void aes_workqueue_handler(struct work_struct *work); +static DECLARE_WORK(aes_work, aes_workqueue_handler); +static struct workqueue_struct *aes_wq; + +extern unsigned long long tegra_chip_uid(void); + +static inline u32 aes_readl(struct tegra_aes_dev *dd, u32 offset) +{ + return readl(dd->io_base + offset); +} + +static inline void aes_writel(struct tegra_aes_dev *dd, u32 val, u32 offset) +{ + writel(val, dd->io_base + offset); +} + +static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr, + int nblocks, int mode, bool upd_iv) +{ + u32 cmdq[AES_HW_MAX_ICQ_LENGTH]; + int i, eng_busy, icq_empty, ret; + u32 value; + + /* reset all the interrupt bits */ + aes_writel(dd, 0xFFFFFFFF, TEGRA_AES_INTR_STATUS); + + /* enable error, dma xfer complete interrupts */ + aes_writel(dd, 0x33, TEGRA_AES_INT_ENB); + + cmdq[0] = CMD_DMASETUP << CMDQ_OPCODE_SHIFT; + cmdq[1] = in_addr; + cmdq[2] = CMD_BLKSTARTENGINE << CMDQ_OPCODE_SHIFT | (nblocks-1); + cmdq[3] = CMD_DMACOMPLETE << CMDQ_OPCODE_SHIFT; + + value = aes_readl(dd, TEGRA_AES_CMDQUE_CONTROL); + /* access SDRAM through AHB */ + value &= ~TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD; + value &= ~TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD; + value |= TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD | + TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD | + TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD; + aes_writel(dd, value, TEGRA_AES_CMDQUE_CONTROL); + dev_dbg(dd->dev, "cmd_q_ctrl=0x%x", value); + + value = (0x1 << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT) | + ((dd->ctx->keylen * 8) << + TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT) | + ((u32)upd_iv << TEGRA_AES_SECURE_IV_SELECT_SHIFT); + + if (mode & FLAGS_CBC) { + value |= ((((mode & FLAGS_ENCRYPT) ? 2 : 3) + << TEGRA_AES_SECURE_XOR_POS_SHIFT) | + (((mode & FLAGS_ENCRYPT) ? 2 : 3) + << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT) | + ((mode & FLAGS_ENCRYPT) ? 1 : 0) + << TEGRA_AES_SECURE_CORE_SEL_SHIFT); + } else if (mode & FLAGS_OFB) { + value |= ((TEGRA_AES_SECURE_XOR_POS_FIELD) | + (2 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT) | + (TEGRA_AES_SECURE_CORE_SEL_FIELD)); + } else if (mode & FLAGS_RNG) { + value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0) + << TEGRA_AES_SECURE_CORE_SEL_SHIFT | + TEGRA_AES_SECURE_RNG_ENB_FIELD); + } else { + value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0) + << TEGRA_AES_SECURE_CORE_SEL_SHIFT); + } + + dev_dbg(dd->dev, "secure_in_sel=0x%x", value); + aes_writel(dd, value, TEGRA_AES_SECURE_INPUT_SELECT); + + aes_writel(dd, out_addr, TEGRA_AES_SECURE_DEST_ADDR); + INIT_COMPLETION(dd->op_complete); + + for (i = 0; i < AES_HW_MAX_ICQ_LENGTH - 1; i++) { + do { + value = aes_readl(dd, TEGRA_AES_INTR_STATUS); + eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD; + icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD; + } while (eng_busy & (!icq_empty)); + aes_writel(dd, cmdq[i], TEGRA_AES_ICMDQUE_WR); + } + + ret = wait_for_completion_timeout(&dd->op_complete, + msecs_to_jiffies(150)); + if (ret == 0) { + dev_err(dd->dev, "timed out (0x%x)\n", + aes_readl(dd, TEGRA_AES_INTR_STATUS)); + return -ETIMEDOUT; + } + + aes_writel(dd, cmdq[AES_HW_MAX_ICQ_LENGTH - 1], TEGRA_AES_ICMDQUE_WR); + return 0; +} + +static void aes_release_key_slot(struct tegra_aes_slot *slot) +{ + if (slot->slot_num == SSK_SLOT_NUM) + return; + + spin_lock(&list_lock); + list_add_tail(&slot->node, &dev_list); + slot = NULL; + spin_unlock(&list_lock); +} + +static struct tegra_aes_slot *aes_find_key_slot(void) +{ + struct tegra_aes_slot *slot = NULL; + struct list_head *new_head; + int empty; + + spin_lock(&list_lock); + empty = list_empty(&dev_list); + if (!empty) { + slot = list_entry(&dev_list, struct tegra_aes_slot, node); + new_head = dev_list.next; + list_del(&dev_list); + dev_list.next = new_head->next; + dev_list.prev = NULL; + } + spin_unlock(&list_lock); + + return slot; +} + +static int aes_set_key(struct tegra_aes_dev *dd) +{ + u32 value, cmdq[2]; + struct tegra_aes_ctx *ctx = dd->ctx; + int eng_busy, icq_empty, dma_busy; + bool use_ssk = false; + + /* use ssk? */ + if (!dd->ctx->slot) { + dev_dbg(dd->dev, "using ssk"); + dd->ctx->slot = &ssk; + use_ssk = true; + } + + /* enable key schedule generation in hardware */ + value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG_EXT); + value &= ~TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD; + aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG_EXT); + + /* select the key slot */ + value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG); + value &= ~TEGRA_AES_SECURE_KEY_INDEX_FIELD; + value |= (ctx->slot->slot_num << TEGRA_AES_SECURE_KEY_INDEX_SHIFT); + aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG); + + if (use_ssk) + return 0; + + /* copy the key table from sdram to vram */ + cmdq[0] = CMD_MEMDMAVD << CMDQ_OPCODE_SHIFT | + MEMDMA_DIR_DTOVRAM << MEMDMA_DIR_SHIFT | + AES_HW_KEY_TABLE_LENGTH_BYTES / sizeof(u32) << + MEMDMA_NUM_WORDS_SHIFT; + cmdq[1] = (u32)dd->ivkey_phys_base; + + aes_writel(dd, cmdq[0], TEGRA_AES_ICMDQUE_WR); + aes_writel(dd, cmdq[1], TEGRA_AES_ICMDQUE_WR); + + do { + value = aes_readl(dd, TEGRA_AES_INTR_STATUS); + eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD; + icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD; + dma_busy = value & TEGRA_AES_DMA_BUSY_FIELD; + } while (eng_busy & (!icq_empty) & dma_busy); + + /* settable command to get key into internal registers */ + value = CMD_SETTABLE << CMDQ_OPCODE_SHIFT | + SUBCMD_CRYPTO_TABLE_SEL << CMDQ_TABLESEL_SHIFT | + SUBCMD_VRAM_SEL << CMDQ_VRAMSEL_SHIFT | + (SUBCMD_KEY_TABLE_SEL | ctx->slot->slot_num) << + CMDQ_KEYTABLEID_SHIFT; + aes_writel(dd, value, TEGRA_AES_ICMDQUE_WR); + + do { + value = aes_readl(dd, TEGRA_AES_INTR_STATUS); + eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD; + icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD; + } while (eng_busy & (!icq_empty)); + + return 0; +} + +static int tegra_aes_handle_req(struct tegra_aes_dev *dd) +{ + struct crypto_async_request *async_req, *backlog; + struct crypto_ablkcipher *tfm; + struct tegra_aes_ctx *ctx; + struct tegra_aes_reqctx *rctx; + struct ablkcipher_request *req; + unsigned long flags; + int dma_max = AES_HW_DMA_BUFFER_SIZE_BYTES; + int ret = 0, nblocks, total; + int count = 0; + dma_addr_t addr_in, addr_out; + struct scatterlist *in_sg, *out_sg; + + if (!dd) + return -EINVAL; + + spin_lock_irqsave(&dd->lock, flags); + backlog = crypto_get_backlog(&dd->queue); + async_req = crypto_dequeue_request(&dd->queue); + if (!async_req) + clear_bit(FLAGS_BUSY, &dd->flags); + spin_unlock_irqrestore(&dd->lock, flags); + + if (!async_req) + return -ENODATA; + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); + + req = ablkcipher_request_cast(async_req); + + dev_dbg(dd->dev, "%s: get new req\n", __func__); + + if (!req->src || !req->dst) + return -EINVAL; + + /* take mutex to access the aes hw */ + mutex_lock(&aes_lock); + + /* assign new request to device */ + dd->req = req; + dd->total = req->nbytes; + dd->in_offset = 0; + dd->in_sg = req->src; + dd->out_offset = 0; + dd->out_sg = req->dst; + + in_sg = dd->in_sg; + out_sg = dd->out_sg; + + total = dd->total; + + tfm = crypto_ablkcipher_reqtfm(req); + rctx = ablkcipher_request_ctx(req); + ctx = crypto_ablkcipher_ctx(tfm); + rctx->mode &= FLAGS_MODE_MASK; + dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; + + dd->iv = (u8 *)req->info; + dd->ivlen = crypto_ablkcipher_ivsize(tfm); + + /* assign new context to device */ + ctx->dd = dd; + dd->ctx = ctx; + + if (ctx->flags & FLAGS_NEW_KEY) { + /* copy the key */ + memcpy(dd->ivkey_base, ctx->key, ctx->keylen); + memset(dd->ivkey_base + ctx->keylen, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - ctx->keylen); + aes_set_key(dd); + ctx->flags &= ~FLAGS_NEW_KEY; + } + + if (((dd->flags & FLAGS_CBC) || (dd->flags & FLAGS_OFB)) && dd->iv) { + /* set iv to the aes hw slot + * Hw generates updated iv only after iv is set in slot. + * So key and iv is passed asynchronously. + */ + memcpy(dd->buf_in, dd->iv, dd->ivlen); + + ret = aes_start_crypt(dd, (u32)dd->dma_buf_in, + dd->dma_buf_out, 1, FLAGS_CBC, false); + if (ret < 0) { + dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); + goto out; + } + } + + while (total) { + dev_dbg(dd->dev, "remain: %d\n", total); + ret = dma_map_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE); + if (!ret) { + dev_err(dd->dev, "dma_map_sg() error\n"); + goto out; + } + + ret = dma_map_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE); + if (!ret) { + dev_err(dd->dev, "dma_map_sg() error\n"); + dma_unmap_sg(dd->dev, dd->in_sg, + 1, DMA_TO_DEVICE); + goto out; + } + + addr_in = sg_dma_address(in_sg); + addr_out = sg_dma_address(out_sg); + dd->flags |= FLAGS_FAST; + count = min_t(int, sg_dma_len(in_sg), dma_max); + WARN_ON(sg_dma_len(in_sg) != sg_dma_len(out_sg)); + nblocks = DIV_ROUND_UP(count, AES_BLOCK_SIZE); + + ret = aes_start_crypt(dd, addr_in, addr_out, nblocks, + dd->flags, true); + + dma_unmap_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE); + dma_unmap_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE); + + if (ret < 0) { + dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); + goto out; + } + dd->flags &= ~FLAGS_FAST; + + dev_dbg(dd->dev, "out: copied %d\n", count); + total -= count; + in_sg = sg_next(in_sg); + out_sg = sg_next(out_sg); + WARN_ON(((total != 0) && (!in_sg || !out_sg))); + } + +out: + mutex_unlock(&aes_lock); + + dd->total = total; + + if (dd->req->base.complete) + dd->req->base.complete(&dd->req->base, ret); + + dev_dbg(dd->dev, "%s: exit\n", __func__); + return ret; +} + +static int tegra_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct tegra_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct tegra_aes_dev *dd = aes_dev; + struct tegra_aes_slot *key_slot; + + if ((keylen != AES_KEYSIZE_128) && (keylen != AES_KEYSIZE_192) && + (keylen != AES_KEYSIZE_256)) { + dev_err(dd->dev, "unsupported key size\n"); + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + dev_dbg(dd->dev, "keylen: %d\n", keylen); + + ctx->dd = dd; + + if (key) { + if (!ctx->slot) { + key_slot = aes_find_key_slot(); + if (!key_slot) { + dev_err(dd->dev, "no empty slot\n"); + return -ENOMEM; + } + + ctx->slot = key_slot; + } + + memcpy(ctx->key, key, keylen); + ctx->keylen = keylen; + } + + ctx->flags |= FLAGS_NEW_KEY; + dev_dbg(dd->dev, "done\n"); + return 0; +} + +static void aes_workqueue_handler(struct work_struct *work) +{ + struct tegra_aes_dev *dd = aes_dev; + int ret; + + ret = clk_enable(dd->aes_clk); + if (ret) + BUG_ON("clock enable failed"); + + /* empty the crypto queue and then return */ + do { + ret = tegra_aes_handle_req(dd); + } while (!ret); + + clk_disable(dd->aes_clk); +} + +static irqreturn_t aes_irq(int irq, void *dev_id) +{ + struct tegra_aes_dev *dd = (struct tegra_aes_dev *)dev_id; + u32 value = aes_readl(dd, TEGRA_AES_INTR_STATUS); + int busy = test_bit(FLAGS_BUSY, &dd->flags); + + if (!busy) { + dev_dbg(dd->dev, "spurious interrupt\n"); + return IRQ_NONE; + } + + dev_dbg(dd->dev, "irq_stat: 0x%x\n", value); + if (value & TEGRA_AES_INT_ERROR_MASK) + aes_writel(dd, TEGRA_AES_INT_ERROR_MASK, TEGRA_AES_INTR_STATUS); + + if (!(value & TEGRA_AES_ENGINE_BUSY_FIELD)) + complete(&dd->op_complete); + else + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int tegra_aes_crypt(struct ablkcipher_request *req, unsigned long mode) +{ + struct tegra_aes_reqctx *rctx = ablkcipher_request_ctx(req); + struct tegra_aes_dev *dd = aes_dev; + unsigned long flags; + int err = 0; + int busy; + + dev_dbg(dd->dev, "nbytes: %d, enc: %d, cbc: %d, ofb: %d\n", + req->nbytes, !!(mode & FLAGS_ENCRYPT), + !!(mode & FLAGS_CBC), !!(mode & FLAGS_OFB)); + + rctx->mode = mode; + + spin_lock_irqsave(&dd->lock, flags); + err = ablkcipher_enqueue_request(&dd->queue, req); + busy = test_and_set_bit(FLAGS_BUSY, &dd->flags); + spin_unlock_irqrestore(&dd->lock, flags); + + if (!busy) + queue_work(aes_wq, &aes_work); + + return err; +} + +static int tegra_aes_ecb_encrypt(struct ablkcipher_request *req) +{ + return tegra_aes_crypt(req, FLAGS_ENCRYPT); +} + +static int tegra_aes_ecb_decrypt(struct ablkcipher_request *req) +{ + return tegra_aes_crypt(req, 0); +} + +static int tegra_aes_cbc_encrypt(struct ablkcipher_request *req) +{ + return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); +} + +static int tegra_aes_cbc_decrypt(struct ablkcipher_request *req) +{ + return tegra_aes_crypt(req, FLAGS_CBC); +} + +static int tegra_aes_ofb_encrypt(struct ablkcipher_request *req) +{ + return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_OFB); +} + +static int tegra_aes_ofb_decrypt(struct ablkcipher_request *req) +{ + return tegra_aes_crypt(req, FLAGS_OFB); +} + +static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata, + unsigned int dlen) +{ + struct tegra_aes_dev *dd = aes_dev; + struct tegra_aes_ctx *ctx = &rng_ctx; + int ret, i; + u8 *dest = rdata, *dt = dd->dt; + + /* take mutex to access the aes hw */ + mutex_lock(&aes_lock); + + ret = clk_enable(dd->aes_clk); + if (ret) + return ret; + + ctx->dd = dd; + dd->ctx = ctx; + dd->flags = FLAGS_ENCRYPT | FLAGS_RNG; + + memcpy(dd->buf_in, dt, DEFAULT_RNG_BLK_SZ); + + ret = aes_start_crypt(dd, (u32)dd->dma_buf_in, + (u32)dd->dma_buf_out, 1, dd->flags, true); + if (ret < 0) { + dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); + dlen = ret; + goto out; + } + memcpy(dest, dd->buf_out, dlen); + + /* update the DT */ + for (i = DEFAULT_RNG_BLK_SZ - 1; i >= 0; i--) { + dt[i] += 1; + if (dt[i] != 0) + break; + } + +out: + clk_disable(dd->aes_clk); + mutex_unlock(&aes_lock); + + dev_dbg(dd->dev, "%s: done\n", __func__); + return dlen; +} + +static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed, + unsigned int slen) +{ + struct tegra_aes_dev *dd = aes_dev; + struct tegra_aes_ctx *ctx = &rng_ctx; + struct tegra_aes_slot *key_slot; + struct timespec ts; + int ret = 0; + u64 nsec, tmp[2]; + u8 *dt; + + if (!ctx || !dd) { + dev_err(dd->dev, "ctx=0x%x, dd=0x%x\n", + (unsigned int)ctx, (unsigned int)dd); + return -EINVAL; + } + + if (slen < (DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) { + dev_err(dd->dev, "seed size invalid"); + return -ENOMEM; + } + + /* take mutex to access the aes hw */ + mutex_lock(&aes_lock); + + if (!ctx->slot) { + key_slot = aes_find_key_slot(); + if (!key_slot) { + dev_err(dd->dev, "no empty slot\n"); + mutex_unlock(&aes_lock); + return -ENOMEM; + } + ctx->slot = key_slot; + } + + ctx->dd = dd; + dd->ctx = ctx; + dd->ctr = 0; + + ctx->keylen = AES_KEYSIZE_128; + ctx->flags |= FLAGS_NEW_KEY; + + /* copy the key to the key slot */ + memcpy(dd->ivkey_base, seed + DEFAULT_RNG_BLK_SZ, AES_KEYSIZE_128); + memset(dd->ivkey_base + AES_KEYSIZE_128, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - AES_KEYSIZE_128); + + dd->iv = seed; + dd->ivlen = slen; + + dd->flags = FLAGS_ENCRYPT | FLAGS_RNG; + + ret = clk_enable(dd->aes_clk); + if (ret) + return ret; + + aes_set_key(dd); + + /* set seed to the aes hw slot */ + memcpy(dd->buf_in, dd->iv, DEFAULT_RNG_BLK_SZ); + ret = aes_start_crypt(dd, (u32)dd->dma_buf_in, + dd->dma_buf_out, 1, FLAGS_CBC, false); + if (ret < 0) { + dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); + goto out; + } + + if (dd->ivlen >= (2 * DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) { + dt = dd->iv + DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128; + } else { + getnstimeofday(&ts); + nsec = timespec_to_ns(&ts); + do_div(nsec, 1000); + nsec ^= dd->ctr << 56; + dd->ctr++; + tmp[0] = nsec; + tmp[1] = tegra_chip_uid(); + dt = (u8 *)tmp; + } + memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ); + +out: + clk_disable(dd->aes_clk); + mutex_unlock(&aes_lock); + + dev_dbg(dd->dev, "%s: done\n", __func__); + return ret; +} + +static int tegra_aes_cra_init(struct crypto_tfm *tfm) +{ + tfm->crt_ablkcipher.reqsize = sizeof(struct tegra_aes_reqctx); + + return 0; +} + +void tegra_aes_cra_exit(struct crypto_tfm *tfm) +{ + struct tegra_aes_ctx *ctx = + crypto_ablkcipher_ctx((struct crypto_ablkcipher *)tfm); + + if (ctx && ctx->slot) + aes_release_key_slot(ctx->slot); +} + +static struct crypto_alg algs[] = { + { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-tegra", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = tegra_aes_setkey, + .encrypt = tegra_aes_ecb_encrypt, + .decrypt = tegra_aes_ecb_decrypt, + }, + }, { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-tegra", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_MIN_KEY_SIZE, + .setkey = tegra_aes_setkey, + .encrypt = tegra_aes_cbc_encrypt, + .decrypt = tegra_aes_cbc_decrypt, + } + }, { + .cra_name = "ofb(aes)", + .cra_driver_name = "ofb-aes-tegra", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_u.ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_MIN_KEY_SIZE, + .setkey = tegra_aes_setkey, + .encrypt = tegra_aes_ofb_encrypt, + .decrypt = tegra_aes_ofb_decrypt, + } + }, { + .cra_name = "ansi_cprng", + .cra_driver_name = "rng-aes-tegra", + .cra_flags = CRYPTO_ALG_TYPE_RNG, + .cra_ctxsize = sizeof(struct tegra_aes_ctx), + .cra_type = &crypto_rng_type, + .cra_u.rng = { + .rng_make_random = tegra_aes_get_random, + .rng_reset = tegra_aes_rng_reset, + .seedsize = AES_KEYSIZE_128 + (2 * DEFAULT_RNG_BLK_SZ), + } + } +}; + +static int tegra_aes_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_aes_dev *dd; + struct resource *res; + int err = -ENOMEM, i = 0, j; + + dd = devm_kzalloc(dev, sizeof(struct tegra_aes_dev), GFP_KERNEL); + if (dd == NULL) { + dev_err(dev, "unable to alloc data struct.\n"); + return err; + } + + dd->dev = dev; + platform_set_drvdata(pdev, dd); + + dd->slots = devm_kzalloc(dev, sizeof(struct tegra_aes_slot) * + AES_NR_KEYSLOTS, GFP_KERNEL); + if (dd->slots == NULL) { + dev_err(dev, "unable to alloc slot struct.\n"); + goto out; + } + + spin_lock_init(&dd->lock); + crypto_init_queue(&dd->queue, TEGRA_AES_QUEUE_LENGTH); + + /* Get the module base address */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "invalid resource type: base\n"); + err = -ENODEV; + goto out; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Couldn't request MEM resource\n"); + return -ENODEV; + } + + dd->io_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!dd->io_base) { + dev_err(dev, "can't ioremap register space\n"); + err = -ENOMEM; + goto out; + } + + /* Initialize the vde clock */ + dd->aes_clk = clk_get(dev, "vde"); + if (IS_ERR(dd->aes_clk)) { + dev_err(dev, "iclock intialization failed.\n"); + err = -ENODEV; + goto out; + } + + err = clk_set_rate(dd->aes_clk, ULONG_MAX); + if (err) { + dev_err(dd->dev, "iclk set_rate fail(%d)\n", err); + goto out; + } + + /* + * the foll contiguous memory is allocated as follows - + * - hardware key table + * - key schedule + */ + dd->ivkey_base = dma_alloc_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES, + &dd->ivkey_phys_base, + GFP_KERNEL); + if (!dd->ivkey_base) { + dev_err(dev, "can not allocate iv/key buffer\n"); + err = -ENOMEM; + goto out; + } + + dd->buf_in = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, + &dd->dma_buf_in, GFP_KERNEL); + if (!dd->buf_in) { + dev_err(dev, "can not allocate dma-in buffer\n"); + err = -ENOMEM; + goto out; + } + + dd->buf_out = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, + &dd->dma_buf_out, GFP_KERNEL); + if (!dd->buf_out) { + dev_err(dev, "can not allocate dma-out buffer\n"); + err = -ENOMEM; + goto out; + } + + init_completion(&dd->op_complete); + aes_wq = alloc_workqueue("tegra_aes_wq", WQ_HIGHPRI | WQ_UNBOUND, 1); + if (!aes_wq) { + dev_err(dev, "alloc_workqueue failed\n"); + goto out; + } + + /* get the irq */ + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "invalid resource type: base\n"); + err = -ENODEV; + goto out; + } + dd->irq = res->start; + + err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH | + IRQF_SHARED, "tegra-aes", dd); + if (err) { + dev_err(dev, "request_irq failed\n"); + goto out; + } + + mutex_init(&aes_lock); + INIT_LIST_HEAD(&dev_list); + + spin_lock_init(&list_lock); + spin_lock(&list_lock); + for (i = 0; i < AES_NR_KEYSLOTS; i++) { + if (i == SSK_SLOT_NUM) + continue; + dd->slots[i].slot_num = i; + INIT_LIST_HEAD(&dd->slots[i].node); + list_add_tail(&dd->slots[i].node, &dev_list); + } + spin_unlock(&list_lock); + + aes_dev = dd; + for (i = 0; i < ARRAY_SIZE(algs); i++) { + INIT_LIST_HEAD(&algs[i].cra_list); + + algs[i].cra_priority = 300; + algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx); + algs[i].cra_module = THIS_MODULE; + algs[i].cra_init = tegra_aes_cra_init; + algs[i].cra_exit = tegra_aes_cra_exit; + + err = crypto_register_alg(&algs[i]); + if (err) + goto out; + } + + dev_info(dev, "registered"); + return 0; + +out: + for (j = 0; j < i; j++) + crypto_unregister_alg(&algs[j]); + if (dd->ivkey_base) + dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES, + dd->ivkey_base, dd->ivkey_phys_base); + if (dd->buf_in) + dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, + dd->buf_in, dd->dma_buf_in); + if (dd->buf_out) + dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, + dd->buf_out, dd->dma_buf_out); + if (IS_ERR(dd->aes_clk)) + clk_put(dd->aes_clk); + if (aes_wq) + destroy_workqueue(aes_wq); + spin_lock(&list_lock); + list_del(&dev_list); + spin_unlock(&list_lock); + + aes_dev = NULL; + + dev_err(dev, "%s: initialization failed.\n", __func__); + return err; +} + +static int __devexit tegra_aes_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_aes_dev *dd = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARRAY_SIZE(algs); i++) + crypto_unregister_alg(&algs[i]); + + cancel_work_sync(&aes_work); + destroy_workqueue(aes_wq); + spin_lock(&list_lock); + list_del(&dev_list); + spin_unlock(&list_lock); + + dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES, + dd->ivkey_base, dd->ivkey_phys_base); + dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, + dd->buf_in, dd->dma_buf_in); + dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, + dd->buf_out, dd->dma_buf_out); + clk_put(dd->aes_clk); + aes_dev = NULL; + + return 0; +} + +static struct of_device_id tegra_aes_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-aes", }, + { .compatible = "nvidia,tegra30-aes", }, + { }, +}; + +static struct platform_driver tegra_aes_driver = { + .probe = tegra_aes_probe, + .remove = __devexit_p(tegra_aes_remove), + .driver = { + .name = "tegra-aes", + .owner = THIS_MODULE, + .of_match_table = tegra_aes_of_match, + }, +}; + +module_platform_driver(tegra_aes_driver); + +MODULE_DESCRIPTION("Tegra AES/OFB/CPRNG hw acceleration support."); +MODULE_AUTHOR("NVIDIA Corporation"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/crypto/tegra-aes.h b/drivers/crypto/tegra-aes.h new file mode 100644 index 000000000000..6006333a8934 --- /dev/null +++ b/drivers/crypto/tegra-aes.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __CRYPTODEV_TEGRA_AES_H +#define __CRYPTODEV_TEGRA_AES_H + +#define TEGRA_AES_ICMDQUE_WR 0x1000 +#define TEGRA_AES_CMDQUE_CONTROL 0x1008 +#define TEGRA_AES_INTR_STATUS 0x1018 +#define TEGRA_AES_INT_ENB 0x1040 +#define TEGRA_AES_CONFIG 0x1044 +#define TEGRA_AES_IRAM_ACCESS_CFG 0x10A0 +#define TEGRA_AES_SECURE_DEST_ADDR 0x1100 +#define TEGRA_AES_SECURE_INPUT_SELECT 0x1104 +#define TEGRA_AES_SECURE_CONFIG 0x1108 +#define TEGRA_AES_SECURE_CONFIG_EXT 0x110C +#define TEGRA_AES_SECURE_SECURITY 0x1110 +#define TEGRA_AES_SECURE_HASH_RESULT0 0x1120 +#define TEGRA_AES_SECURE_HASH_RESULT1 0x1124 +#define TEGRA_AES_SECURE_HASH_RESULT2 0x1128 +#define TEGRA_AES_SECURE_HASH_RESULT3 0x112C +#define TEGRA_AES_SECURE_SEC_SEL0 0x1140 +#define TEGRA_AES_SECURE_SEC_SEL1 0x1144 +#define TEGRA_AES_SECURE_SEC_SEL2 0x1148 +#define TEGRA_AES_SECURE_SEC_SEL3 0x114C +#define TEGRA_AES_SECURE_SEC_SEL4 0x1150 +#define TEGRA_AES_SECURE_SEC_SEL5 0x1154 +#define TEGRA_AES_SECURE_SEC_SEL6 0x1158 +#define TEGRA_AES_SECURE_SEC_SEL7 0x115C + +/* interrupt status reg masks and shifts */ +#define TEGRA_AES_ENGINE_BUSY_FIELD BIT(0) +#define TEGRA_AES_ICQ_EMPTY_FIELD BIT(3) +#define TEGRA_AES_DMA_BUSY_FIELD BIT(23) + +/* secure select reg masks and shifts */ +#define TEGRA_AES_SECURE_SEL0_KEYREAD_ENB0_FIELD BIT(0) + +/* secure config ext masks and shifts */ +#define TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD BIT(15) + +/* secure config masks and shifts */ +#define TEGRA_AES_SECURE_KEY_INDEX_SHIFT 20 +#define TEGRA_AES_SECURE_KEY_INDEX_FIELD (0x1F << TEGRA_AES_SECURE_KEY_INDEX_SHIFT) +#define TEGRA_AES_SECURE_BLOCK_CNT_SHIFT 0 +#define TEGRA_AES_SECURE_BLOCK_CNT_FIELD (0xFFFFF << TEGRA_AES_SECURE_BLOCK_CNT_SHIFT) + +/* stream interface select masks and shifts */ +#define TEGRA_AES_CMDQ_CTRL_UCMDQEN_FIELD BIT(0) +#define TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD BIT(1) +#define TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD BIT(4) +#define TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD BIT(5) + +/* config register masks and shifts */ +#define TEGRA_AES_CONFIG_ENDIAN_ENB_FIELD BIT(10) +#define TEGRA_AES_CONFIG_MODE_SEL_SHIFT 0 +#define TEGRA_AES_CONFIG_MODE_SEL_FIELD (0x1F << TEGRA_AES_CONFIG_MODE_SEL_SHIFT) + +/* extended config */ +#define TEGRA_AES_SECURE_OFFSET_CNT_SHIFT 24 +#define TEGRA_AES_SECURE_OFFSET_CNT_FIELD (0xFF << TEGRA_AES_SECURE_OFFSET_CNT_SHIFT) +#define TEGRA_AES_SECURE_KEYSCHED_GEN_FIELD BIT(15) + +/* init vector select */ +#define TEGRA_AES_SECURE_IV_SELECT_SHIFT 10 +#define TEGRA_AES_SECURE_IV_SELECT_FIELD BIT(10) + +/* secure engine input */ +#define TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT 28 +#define TEGRA_AES_SECURE_INPUT_ALG_SEL_FIELD (0xF << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT) +#define TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT 16 +#define TEGRA_AES_SECURE_INPUT_KEY_LEN_FIELD (0xFFF << TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT) +#define TEGRA_AES_SECURE_RNG_ENB_FIELD BIT(11) +#define TEGRA_AES_SECURE_CORE_SEL_SHIFT 9 +#define TEGRA_AES_SECURE_CORE_SEL_FIELD BIT(9) +#define TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT 7 +#define TEGRA_AES_SECURE_VCTRAM_SEL_FIELD (0x3 << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT) +#define TEGRA_AES_SECURE_INPUT_SEL_SHIFT 5 +#define TEGRA_AES_SECURE_INPUT_SEL_FIELD (0x3 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT) +#define TEGRA_AES_SECURE_XOR_POS_SHIFT 3 +#define TEGRA_AES_SECURE_XOR_POS_FIELD (0x3 << TEGRA_AES_SECURE_XOR_POS_SHIFT) +#define TEGRA_AES_SECURE_HASH_ENB_FIELD BIT(2) +#define TEGRA_AES_SECURE_ON_THE_FLY_FIELD BIT(0) + +/* interrupt error mask */ +#define TEGRA_AES_INT_ERROR_MASK 0xFFF000 + +#endif diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index c189b82f5ece..70c31d43fff3 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -83,6 +83,7 @@ int update_devfreq(struct devfreq *devfreq) { unsigned long freq; int err = 0; + u32 flags = 0; if (!mutex_is_locked(&devfreq->lock)) { WARN(true, "devfreq->lock must be locked by the caller.\n"); @@ -94,7 +95,24 @@ int update_devfreq(struct devfreq *devfreq) if (err) return err; - err = devfreq->profile->target(devfreq->dev.parent, &freq); + /* + * Adjust the freuqency with user freq and QoS. + * + * List from the highest proiority + * max_freq (probably called by thermal when it's too hot) + * min_freq + */ + + if (devfreq->min_freq && freq < devfreq->min_freq) { + freq = devfreq->min_freq; + flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ + } + if (devfreq->max_freq && freq > devfreq->max_freq) { + freq = devfreq->max_freq; + flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ + } + + err = devfreq->profile->target(devfreq->dev.parent, &freq, flags); if (err) return err; @@ -501,12 +519,82 @@ static ssize_t show_central_polling(struct device *dev, !to_devfreq(dev)->governor->no_central_polling); } +static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct devfreq *df = to_devfreq(dev); + unsigned long value; + int ret; + unsigned long max; + + ret = sscanf(buf, "%lu", &value); + if (ret != 1) + goto out; + + mutex_lock(&df->lock); + max = df->max_freq; + if (value && max && value > max) { + ret = -EINVAL; + goto unlock; + } + + df->min_freq = value; + update_devfreq(df); + ret = count; +unlock: + mutex_unlock(&df->lock); +out: + return ret; +} + +static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq); +} + +static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct devfreq *df = to_devfreq(dev); + unsigned long value; + int ret; + unsigned long min; + + ret = sscanf(buf, "%lu", &value); + if (ret != 1) + goto out; + + mutex_lock(&df->lock); + min = df->min_freq; + if (value && min && value < min) { + ret = -EINVAL; + goto unlock; + } + + df->max_freq = value; + update_devfreq(df); + ret = count; +unlock: + mutex_unlock(&df->lock); +out: + return ret; +} + +static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq); +} + static struct device_attribute devfreq_attrs[] = { __ATTR(governor, S_IRUGO, show_governor, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), __ATTR(central_polling, S_IRUGO, show_central_polling, NULL), __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, store_polling_interval), + __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), + __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq), { }, }; @@ -555,14 +643,30 @@ module_exit(devfreq_exit); * freq value given to target callback. * @dev The devfreq user device. (parent of devfreq) * @freq The frequency given to target function + * @flags Flags handed from devfreq framework. * */ -struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq) +struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, + u32 flags) { - struct opp *opp = opp_find_freq_ceil(dev, freq); + struct opp *opp; - if (opp == ERR_PTR(-ENODEV)) + if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) { + /* The freq is an upper bound. opp should be lower */ opp = opp_find_freq_floor(dev, freq); + + /* If not available, use the closest opp */ + if (opp == ERR_PTR(-ENODEV)) + opp = opp_find_freq_ceil(dev, freq); + } else { + /* The freq is an lower bound. opp should be higher */ + opp = opp_find_freq_ceil(dev, freq); + + /* If not available, use the closest opp */ + if (opp == ERR_PTR(-ENODEV)) + opp = opp_find_freq_floor(dev, freq); + } + return opp; } diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index 6460577d6701..1a361e99965a 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c @@ -619,15 +619,19 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp, return err; } -static int exynos4_bus_target(struct device *dev, unsigned long *_freq) +static int exynos4_bus_target(struct device *dev, unsigned long *_freq, + u32 flags) { int err = 0; struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct busfreq_data *data = platform_get_drvdata(pdev); - struct opp *opp = devfreq_recommended_opp(dev, _freq); - unsigned long old_freq = opp_get_freq(data->curr_opp); + struct opp *opp = devfreq_recommended_opp(dev, _freq, flags); unsigned long freq = opp_get_freq(opp); + unsigned long old_freq = opp_get_freq(data->curr_opp); + + if (IS_ERR(opp)) + return PTR_ERR(opp); if (old_freq == freq) return 0; @@ -689,9 +693,7 @@ static int exynos4_get_busier_dmc(struct busfreq_data *data) static int exynos4_bus_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) { - struct platform_device *pdev = container_of(dev, struct platform_device, - dev); - struct busfreq_data *data = platform_get_drvdata(pdev); + struct busfreq_data *data = dev_get_drvdata(dev); int busier_dmc; int cycles_x2 = 2; /* 2 x cycles */ void __iomem *addr; @@ -739,9 +741,7 @@ static int exynos4_bus_get_dev_status(struct device *dev, static void exynos4_bus_exit(struct device *dev) { - struct platform_device *pdev = container_of(dev, struct platform_device, - dev); - struct busfreq_data *data = platform_get_drvdata(pdev); + struct busfreq_data *data = dev_get_drvdata(dev); devfreq_unregister_opp_notifier(dev, data->devfreq); } @@ -1087,9 +1087,7 @@ static __devexit int exynos4_busfreq_remove(struct platform_device *pdev) static int exynos4_busfreq_resume(struct device *dev) { - struct platform_device *pdev = container_of(dev, struct platform_device, - dev); - struct busfreq_data *data = platform_get_drvdata(pdev); + struct busfreq_data *data = dev_get_drvdata(dev); busfreq_mon_reset(data); return 0; @@ -1132,4 +1130,3 @@ module_exit(exynos4_busfreq_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("EXYNOS4 busfreq driver with devfreq framework"); MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); -MODULE_ALIAS("exynos4-busfreq"); diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index c0596b291761..574a06b1b1de 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -18,7 +18,10 @@ static int devfreq_performance_func(struct devfreq *df, * target callback should be able to get floor value as * said in devfreq.h */ - *freq = UINT_MAX; + if (!df->max_freq) + *freq = UINT_MAX; + else + *freq = df->max_freq; return 0; } diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index 2483a85a266f..d742d4a82d6a 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -18,7 +18,7 @@ static int devfreq_powersave_func(struct devfreq *df, * target callback should be able to get ceiling value as * said in devfreq.h */ - *freq = 0; + *freq = df->min_freq; return 0; } diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index efad8dcf9028..a2e3eae79011 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -25,6 +25,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; struct devfreq_simple_ondemand_data *data = df->data; + unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; if (err) return err; @@ -41,7 +42,7 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Assume MAX if it is going to be divided by zero */ if (stat.total_time == 0) { - *freq = UINT_MAX; + *freq = max; return 0; } @@ -54,13 +55,13 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, /* Set MAX if it's busy enough */ if (stat.busy_time * 100 > stat.total_time * dfso_upthreshold) { - *freq = UINT_MAX; + *freq = max; return 0; } /* Set MAX if we do not know the initial frequency */ if (stat.current_frequency == 0) { - *freq = UINT_MAX; + *freq = max; return 0; } @@ -79,6 +80,11 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); *freq = (unsigned long) b; + if (df->min_freq && *freq < df->min_freq) + *freq = df->min_freq; + if (df->max_freq && *freq > df->max_freq) + *freq = df->max_freq; + return 0; } diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 4f8b563da782..0681246fc89d 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -25,10 +25,19 @@ static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq) { struct userspace_data *data = df->data; - if (!data->valid) + if (data->valid) { + unsigned long adjusted_freq = data->user_frequency; + + if (df->max_freq && adjusted_freq > df->max_freq) + adjusted_freq = df->max_freq; + + if (df->min_freq && adjusted_freq < df->min_freq) + adjusted_freq = df->min_freq; + + *freq = adjusted_freq; + } else { *freq = df->previous_freq; /* No user freq specified yet */ - else - *freq = data->user_frequency; + } return 0; } diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index ca6c04d350ee..da09cd74bc5b 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -620,13 +620,13 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset, if (PageHighMem(pg)) local_irq_save(flags); - virt_addr = kmap_atomic(pg, KM_BOUNCE_READ); + virt_addr = kmap_atomic(pg); /* Perform architecture specific atomic scrub operation */ atomic_scrub(virt_addr + offset, size); /* Unmap and complete */ - kunmap_atomic(virt_addr, KM_BOUNCE_READ); + kunmap_atomic(virt_addr); if (PageHighMem(pg)) local_irq_restore(flags); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 5cd04b65c556..e6568c19c939 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -37,7 +37,7 @@ struct mpc8xxx_gpio_chip { * open drain mode safely */ u32 data; - struct irq_host *irq; + struct irq_domain *irq; void *of_dev_id_data; }; @@ -281,7 +281,7 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_set_type = mpc8xxx_irq_set_type, }; -static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, +static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; @@ -296,24 +296,9 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq, return 0; } -static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, - unsigned int *out_flags) - -{ - /* interrupt sense values coming from the device tree equal either - * EDGE_FALLING or EDGE_BOTH - */ - *out_hwirq = intspec[0]; - *out_flags = intspec[1]; - - return 0; -} - -static struct irq_host_ops mpc8xxx_gpio_irq_ops = { +static struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .map = mpc8xxx_gpio_irq_map, - .xlate = mpc8xxx_gpio_irq_xlate, + .xlate = irq_domain_xlate_twocell, }; static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { @@ -364,9 +349,8 @@ static void __init mpc8xxx_add_controller(struct device_node *np) if (hwirq == NO_IRQ) goto skip_irq; - mpc8xxx_gc->irq = - irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS, - &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS); + mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS, + &mpc8xxx_gpio_irq_ops, mpc8xxx_gc); if (!mpc8xxx_gc->irq) goto skip_irq; @@ -374,8 +358,6 @@ static void __init mpc8xxx_add_controller(struct device_node *np) if (id) mpc8xxx_gc->of_dev_id_data = id->data; - mpc8xxx_gc->irq->host_data = mpc8xxx_gc; - /* ack and mask all irqs */ out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 592865381c6e..4b8653b932f9 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -41,10 +41,10 @@ drm_clflush_page(struct page *page) if (unlikely(page == NULL)) return; - page_virtual = kmap_atomic(page, KM_USER0); + page_virtual = kmap_atomic(page); for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) clflush(page_virtual + i); - kunmap_atomic(page_virtual, KM_USER0); + kunmap_atomic(page_virtual); } static void drm_cache_flush_clflush(struct page *pages[], @@ -87,10 +87,10 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages) if (unlikely(page == NULL)) continue; - page_virtual = kmap_atomic(page, KM_USER0); + page_virtual = kmap_atomic(page); flush_dcache_range((unsigned long)page_virtual, (unsigned long)page_virtual + PAGE_SIZE); - kunmap_atomic(page_virtual, KM_USER0); + kunmap_atomic(page_virtual); } #else printk(KERN_ERR "Architecture has no drm_cache.c support\n"); diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index c904d73b1de3..e80ee82f6caf 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -125,14 +125,14 @@ static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page) int i; uint8_t *clf; - clf = kmap_atomic(page, KM_USER0); + clf = kmap_atomic(page); mb(); for (i = 0; i < clflush_count; ++i) { psb_clflush(clf); clf += clflush_add; } mb(); - kunmap_atomic(clf, KM_USER0); + kunmap_atomic(clf); } static void psb_pages_clflush(struct psb_mmu_driver *driver, @@ -325,7 +325,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) spin_lock(lock); - v = kmap_atomic(pt->p, KM_USER0); + v = kmap_atomic(pt->p); clf = (uint8_t *) v; ptes = (uint32_t *) v; for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) @@ -341,7 +341,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) mb(); } - kunmap_atomic(v, KM_USER0); + kunmap_atomic(v); spin_unlock(lock); pt->count = 0; @@ -376,18 +376,18 @@ struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, continue; } - v = kmap_atomic(pd->p, KM_USER0); + v = kmap_atomic(pd->p); pd->tables[index] = pt; v[index] = (page_to_pfn(pt->p) << 12) | pd->pd_mask; pt->index = index; - kunmap_atomic((void *) v, KM_USER0); + kunmap_atomic((void *) v); if (pd->hw_context != -1) { psb_mmu_clflush(pd->driver, (void *) &v[index]); atomic_set(&pd->driver->needs_tlbflush, 1); } } - pt->v = kmap_atomic(pt->p, KM_USER0); + pt->v = kmap_atomic(pt->p); return pt; } @@ -404,7 +404,7 @@ static struct psb_mmu_pt *psb_mmu_pt_map_lock(struct psb_mmu_pd *pd, spin_unlock(lock); return NULL; } - pt->v = kmap_atomic(pt->p, KM_USER0); + pt->v = kmap_atomic(pt->p); return pt; } @@ -413,9 +413,9 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) struct psb_mmu_pd *pd = pt->pd; uint32_t *v; - kunmap_atomic(pt->v, KM_USER0); + kunmap_atomic(pt->v); if (pt->count == 0) { - v = kmap_atomic(pd->p, KM_USER0); + v = kmap_atomic(pd->p); v[pt->index] = pd->invalid_pde; pd->tables[pt->index] = NULL; @@ -424,7 +424,7 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) (void *) &v[pt->index]); atomic_set(&pd->driver->needs_tlbflush, 1); } - kunmap_atomic(pt->v, KM_USER0); + kunmap_atomic(pt->v); spin_unlock(&pd->driver->lock); psb_mmu_free_pt(pt); return; @@ -457,7 +457,7 @@ void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, down_read(&driver->sem); spin_lock(&driver->lock); - v = kmap_atomic(pd->p, KM_USER0); + v = kmap_atomic(pd->p); v += start; while (gtt_pages--) { @@ -467,7 +467,7 @@ void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, /*ttm_tt_cache_flush(&pd->p, num_pages);*/ psb_pages_clflush(pd->driver, &pd->p, num_pages); - kunmap_atomic(v, KM_USER0); + kunmap_atomic(v); spin_unlock(&driver->lock); if (pd->hw_context != -1) @@ -830,9 +830,9 @@ int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, uint32_t *v; spin_lock(lock); - v = kmap_atomic(pd->p, KM_USER0); + v = kmap_atomic(pd->p); tmp = v[psb_mmu_pd_index(virtual)]; - kunmap_atomic(v, KM_USER0); + kunmap_atomic(v); spin_unlock(lock); if (tmp != pd->invalid_pde || !(tmp & PSB_PTE_VALID) || diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 2f75d203a2bf..c10cf5e2443a 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -309,11 +309,11 @@ int ttm_tt_swapin(struct ttm_tt *ttm) goto out_err; preempt_disable(); - from_virtual = kmap_atomic(from_page, KM_USER0); - to_virtual = kmap_atomic(to_page, KM_USER1); + from_virtual = kmap_atomic(from_page); + to_virtual = kmap_atomic(to_page); memcpy(to_virtual, from_virtual, PAGE_SIZE); - kunmap_atomic(to_virtual, KM_USER1); - kunmap_atomic(from_virtual, KM_USER0); + kunmap_atomic(to_virtual); + kunmap_atomic(from_virtual); preempt_enable(); page_cache_release(from_page); } @@ -365,11 +365,11 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) goto out_err; } preempt_disable(); - from_virtual = kmap_atomic(from_page, KM_USER0); - to_virtual = kmap_atomic(to_page, KM_USER1); + from_virtual = kmap_atomic(from_page); + to_virtual = kmap_atomic(to_page); memcpy(to_virtual, from_virtual, PAGE_SIZE); - kunmap_atomic(to_virtual, KM_USER1); - kunmap_atomic(from_virtual, KM_USER0); + kunmap_atomic(to_virtual); + kunmap_atomic(from_virtual); preempt_enable(); set_page_dirty(to_page); mark_page_accessed(to_page); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index f4e7763a7694..51c9ba5cd2fb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -136,10 +136,10 @@ static int vmw_gmr_build_descriptors(struct list_head *desc_pages, if (likely(page_virtual != NULL)) { desc_virtual->ppn = page_to_pfn(page); - kunmap_atomic(page_virtual, KM_USER0); + kunmap_atomic(page_virtual); } - page_virtual = kmap_atomic(page, KM_USER0); + page_virtual = kmap_atomic(page); desc_virtual = page_virtual - 1; prev_pfn = ~(0UL); @@ -169,7 +169,7 @@ static int vmw_gmr_build_descriptors(struct list_head *desc_pages, } if (likely(page_virtual != NULL)) - kunmap_atomic(page_virtual, KM_USER0); + kunmap_atomic(page_virtual); return 0; out_err: diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index dad895fec62a..811e6c47e7e6 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -598,11 +598,11 @@ config SENSORS_LM78 will be called lm78. config SENSORS_LM80 - tristate "National Semiconductor LM80" + tristate "National Semiconductor LM80 and LM96080" depends on I2C help If you say yes here you get support for National Semiconductor - LM80 sensor chips. + LM80 and LM96080 sensor chips. This driver can also be built as a module. If so, the module will be called lm80. @@ -1028,7 +1028,8 @@ config SENSORS_SCH5627 select SENSORS_SCH56XX_COMMON help If you say yes here you get support for the hardware monitoring - features of the SMSC SCH5627 Super-I/O chip. + features of the SMSC SCH5627 Super-I/O chip including support for + the integrated watchdog. This driver can also be built as a module. If so, the module will be called sch5627. @@ -1044,7 +1045,8 @@ config SENSORS_SCH5636 Currently this driver only supports the Fujitsu Theseus SCH5636 based hwmon solution. Say yes here if you want support for the Fujitsu - Theseus' hardware monitoring features. + Theseus' hardware monitoring features including support for the + integrated watchdog. This driver can also be built as a module. If so, the module will be called sch5636. diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 3b728e8f169b..a72bf25601a4 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1,25 +1,25 @@ /* - abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - This driver supports the sensor part of the first and second revision of - the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because - of lack of specs the CPU/RAM voltage & frequency control is not supported! -*/ + * This driver supports the sensor part of the first and second revision of + * the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because + * of lack of specs the CPU/RAM voltage & frequency control is not supported! + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -44,8 +44,10 @@ #define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */ /* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */ #define ABIT_UGURU_MAX_BANK1_SENSORS 16 -/* Warning if you increase one of the 2 MAX defines below to 10 or higher you - should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! */ +/* + * Warning if you increase one of the 2 MAX defines below to 10 or higher you + * should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! + */ /* max nr of sensors in bank2, currently mb's with max 6 fans are known */ #define ABIT_UGURU_MAX_BANK2_SENSORS 6 /* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */ @@ -70,16 +72,22 @@ #define ABIT_UGURU_IN_SENSOR 0 #define ABIT_UGURU_TEMP_SENSOR 1 #define ABIT_UGURU_NC 2 -/* In many cases we need to wait for the uGuru to reach a certain status, most - of the time it will reach this status within 30 - 90 ISA reads, and thus we - can best busy wait. This define gives the total amount of reads to try. */ +/* + * In many cases we need to wait for the uGuru to reach a certain status, most + * of the time it will reach this status within 30 - 90 ISA reads, and thus we + * can best busy wait. This define gives the total amount of reads to try. + */ #define ABIT_UGURU_WAIT_TIMEOUT 125 -/* However sometimes older versions of the uGuru seem to be distracted and they - do not respond for a long time. To handle this we sleep before each of the - last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. */ +/* + * However sometimes older versions of the uGuru seem to be distracted and they + * do not respond for a long time. To handle this we sleep before each of the + * last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. + */ #define ABIT_UGURU_WAIT_TIMEOUT_SLEEP 5 -/* Normally all expected status in abituguru_ready, are reported after the - first read, but sometimes not and we need to poll. */ +/* + * Normally all expected status in abituguru_ready, are reported after the + * first read, but sometimes not and we need to poll. + */ #define ABIT_UGURU_READY_TIMEOUT 5 /* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */ #define ABIT_UGURU_MAX_RETRIES 3 @@ -92,17 +100,25 @@ if (level <= verbose) \ printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg) /* Macros to help calculate the sysfs_names array length */ -/* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0, - in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 */ +/* + * sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0, + * in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 + */ #define ABITUGURU_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14) -/* sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0, - temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 */ +/* + * sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0, + * temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 + */ #define ABITUGURU_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16) -/* sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0, - fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 */ +/* + * sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0, + * fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 + */ #define ABITUGURU_FAN_NAMES_LENGTH (11 + 9 + 11 + 18 + 10 + 14) -/* sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0, - pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 */ +/* + * sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0, + * pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 + */ #define ABITUGURU_PWM_NAMES_LENGTH (12 + 24 + 2 * 21 + 2 * 22) /* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */ #define ABITUGURU_SYSFS_NAMES_LENGTH ( \ @@ -110,10 +126,12 @@ ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \ ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH) -/* All the macros below are named identical to the oguru and oguru2 programs - reverse engineered by Olle Sandberg, hence the names might not be 100% - logical. I could come up with better names, but I prefer keeping the names - identical so that this driver can be compared with his work more easily. */ +/* + * All the macros below are named identical to the oguru and oguru2 programs + * reverse engineered by Olle Sandberg, hence the names might not be 100% + * logical. I could come up with better names, but I prefer keeping the names + * identical so that this driver can be compared with his work more easily. + */ /* Two i/o-ports are used by uGuru */ #define ABIT_UGURU_BASE 0x00E0 /* Used to tell uGuru what to read and to read the actual data */ @@ -130,16 +148,22 @@ /* Constants */ /* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */ static const int abituguru_bank1_max_value[2] = { 3494, 255000 }; -/* Min / Max allowed values for sensor2 (fan) alarm threshold, these values - correspond to 300-3000 RPM */ +/* + * Min / Max allowed values for sensor2 (fan) alarm threshold, these values + * correspond to 300-3000 RPM + */ static const u8 abituguru_bank2_min_threshold = 5; static const u8 abituguru_bank2_max_threshold = 50; -/* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4 - are temperature trip points. */ +/* + * Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4 + * are temperature trip points. + */ static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 }; -/* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a - special case the minium allowed pwm% setting for this is 30% (77) on - some MB's this special case is handled in the code! */ +/* + * Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a + * special case the minium allowed pwm% setting for this is 30% (77) on + * some MB's this special case is handled in the code! + */ static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 }; static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 }; @@ -175,23 +199,29 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n" " 3 + retryable error reporting"); -/* For the Abit uGuru, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - abituguru device is allocated. */ +/* + * For the Abit uGuru, we need to keep some data in memory. + * The structure is dynamically allocated, at the same time when a new + * abituguru device is allocated. + */ struct abituguru_data { struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ unsigned long last_updated; /* In jiffies */ unsigned short addr; /* uguru base address */ char uguru_ready; /* is the uguru in ready state? */ - unsigned char update_timeouts; /* number of update timeouts since last - successful update */ - - /* The sysfs attr and their names are generated automatically, for bank1 - we cannot use a predefined array because we don't know beforehand - of a sensor is a volt or a temp sensor, for bank2 and the pwms its - easier todo things the same way. For in sensors we have 9 (temp 7) - sysfs entries per sensor, for bank2 and pwms 6. */ + unsigned char update_timeouts; /* + * number of update timeouts since last + * successful update + */ + + /* + * The sysfs attr and their names are generated automatically, for bank1 + * we cannot use a predefined array because we don't know beforehand + * of a sensor is a volt or a temp sensor, for bank2 and the pwms its + * easier todo things the same way. For in sensors we have 9 (temp 7) + * sysfs entries per sensor, for bank2 and pwms 6. + */ struct sensor_device_attribute_2 sysfs_attr[ ABIT_UGURU_MAX_BANK1_SENSORS * 9 + ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6]; @@ -203,11 +233,15 @@ struct abituguru_data { u8 bank1_sensors[2]; u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS]; u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS]; - /* This array holds 3 entries per sensor for the bank 1 sensor settings - (flags, min, max for voltage / flags, warn, shutdown for temp). */ + /* + * This array holds 3 entries per sensor for the bank 1 sensor settings + * (flags, min, max for voltage / flags, warn, shutdown for temp). + */ u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3]; - /* Maximum value for each sensor used for scaling in mV/millidegrees - Celsius. */ + /* + * Maximum value for each sensor used for scaling in mV/millidegrees + * Celsius. + */ int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS]; /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */ @@ -236,8 +270,10 @@ static int abituguru_wait(struct abituguru_data *data, u8 state) timeout--; if (timeout == 0) return -EBUSY; - /* sleep a bit before our last few tries, see the comment on - this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. */ + /* + * sleep a bit before our last few tries, see the comment on + * this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. + */ if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP) msleep(0); } @@ -273,8 +309,10 @@ static int abituguru_ready(struct abituguru_data *data) msleep(0); } - /* After this the ABIT_UGURU_DATA port should contain - ABIT_UGURU_STATUS_INPUT */ + /* + * After this the ABIT_UGURU_DATA port should contain + * ABIT_UGURU_STATUS_INPUT + */ timeout = ABIT_UGURU_READY_TIMEOUT; while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) { timeout--; @@ -290,27 +328,35 @@ static int abituguru_ready(struct abituguru_data *data) return 0; } -/* Send the bank and then sensor address to the uGuru for the next read/write - cycle. This function gets called as the first part of a read/write by - abituguru_read and abituguru_write. This function should never be - called by any other function. */ +/* + * Send the bank and then sensor address to the uGuru for the next read/write + * cycle. This function gets called as the first part of a read/write by + * abituguru_read and abituguru_write. This function should never be + * called by any other function. + */ static int abituguru_send_address(struct abituguru_data *data, u8 bank_addr, u8 sensor_addr, int retries) { - /* assume the caller does error handling itself if it has not requested - any retries, and thus be quiet. */ + /* + * assume the caller does error handling itself if it has not requested + * any retries, and thus be quiet. + */ int report_errors = retries; for (;;) { - /* Make sure the uguru is ready and then send the bank address, - after this the uguru is no longer "ready". */ + /* + * Make sure the uguru is ready and then send the bank address, + * after this the uguru is no longer "ready". + */ if (abituguru_ready(data) != 0) return -EIO; outb(bank_addr, data->addr + ABIT_UGURU_DATA); data->uguru_ready = 0; - /* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again - and send the sensor addr */ + /* + * Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again + * and send the sensor addr + */ if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) { if (retries) { ABIT_UGURU_DEBUG(3, "timeout exceeded " @@ -332,8 +378,10 @@ static int abituguru_send_address(struct abituguru_data *data, } } -/* Read count bytes from sensor sensor_addr in bank bank_addr and store the - result in buf, retry the send address part of the read retries times. */ +/* + * Read count bytes from sensor sensor_addr in bank bank_addr and store the + * result in buf, retry the send address part of the read retries times. + */ static int abituguru_read(struct abituguru_data *data, u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries) { @@ -362,13 +410,17 @@ static int abituguru_read(struct abituguru_data *data, return i; } -/* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send - address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. */ +/* + * Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send + * address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. + */ static int abituguru_write(struct abituguru_data *data, u8 bank_addr, u8 sensor_addr, u8 *buf, int count) { - /* We use the ready timeout as we have to wait for 0xAC just like the - ready function */ + /* + * We use the ready timeout as we have to wait for 0xAC just like the + * ready function + */ int i, timeout = ABIT_UGURU_READY_TIMEOUT; /* Send the address */ @@ -388,9 +440,11 @@ static int abituguru_write(struct abituguru_data *data, outb(buf[i], data->addr + ABIT_UGURU_CMD); } - /* Now we need to wait till the chip is ready to be read again, - so that we can read 0xAC as confirmation that our write has - succeeded. */ + /* + * Now we need to wait till the chip is ready to be read again, + * so that we can read 0xAC as confirmation that our write has + * succeeded. + */ if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state " "after write (bank: %d, sensor: %d)\n", (int)bank_addr, @@ -416,12 +470,14 @@ static int abituguru_write(struct abituguru_data *data, return i; } -/* Detect sensor type. Temp and Volt sensors are enabled with - different masks and will ignore enable masks not meant for them. - This enables us to test what kind of sensor we're dealing with. - By setting the alarm thresholds so that we will always get an - alarm for sensor type X and then enabling the sensor as sensor type - X, if we then get an alarm it is a sensor of type X. */ +/* + * Detect sensor type. Temp and Volt sensors are enabled with + * different masks and will ignore enable masks not meant for them. + * This enables us to test what kind of sensor we're dealing with. + * By setting the alarm thresholds so that we will always get an + * alarm for sensor type X and then enabling the sensor as sensor type + * X, if we then get an alarm it is a sensor of type X. + */ static int __devinit abituguru_detect_bank1_sensor_type(struct abituguru_data *data, u8 sensor_addr) @@ -448,16 +504,20 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, pr_warn("bank1-sensor: %d reading (%d) too close to limits, " "unable to determine sensor type, skipping sensor\n", (int)sensor_addr, (int)val); - /* assume no sensor is there for sensors for which we can't - determine the sensor type because their reading is too close - to their limits, this usually means no sensor is there. */ + /* + * assume no sensor is there for sensors for which we can't + * determine the sensor type because their reading is too close + * to their limits, this usually means no sensor is there. + */ return ABIT_UGURU_NC; } ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr); - /* Volt sensor test, enable volt low alarm, set min value ridicously - high, or vica versa if the reading is very high. If its a volt - sensor this should always give us an alarm. */ + /* + * Volt sensor test, enable volt low alarm, set min value ridicously + * high, or vica versa if the reading is very high. If its a volt + * sensor this should always give us an alarm. + */ if (val <= 240u) { buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE; buf[1] = 245; @@ -473,8 +533,10 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, buf, 3) != 3) goto abituguru_detect_bank1_sensor_type_exit; - /* Now we need 20 ms to give the uguru time to read the sensors - and raise a voltage alarm */ + /* + * Now we need 20 ms to give the uguru time to read the sensors + * and raise a voltage alarm + */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/50); /* Check for alarm and check the alarm is a volt low alarm. */ @@ -497,17 +559,21 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor " "test\n"); - /* Temp sensor test, enable sensor as a temp sensor, set beep value - ridicously low (but not too low, otherwise uguru ignores it). - If its a temp sensor this should always give us an alarm. */ + /* + * Temp sensor test, enable sensor as a temp sensor, set beep value + * ridicously low (but not too low, otherwise uguru ignores it). + * If its a temp sensor this should always give us an alarm. + */ buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE; buf[1] = 5; buf[2] = 10; if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, buf, 3) != 3) goto abituguru_detect_bank1_sensor_type_exit; - /* Now we need 50 ms to give the uguru time to read the sensors - and raise a temp alarm */ + /* + * Now we need 50 ms to give the uguru time to read the sensors + * and raise a temp alarm + */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/20); /* Check for alarm and check the alarm is a temp high alarm. */ @@ -532,9 +598,11 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, ret = ABIT_UGURU_NC; abituguru_detect_bank1_sensor_type_exit: - /* Restore original settings, failing here is really BAD, it has been - reported that some BIOS-es hang when entering the uGuru menu with - invalid settings present in the uGuru, so we try this 3 times. */ + /* + * Restore original settings, failing here is really BAD, it has been + * reported that some BIOS-es hang when entering the uGuru menu with + * invalid settings present in the uGuru, so we try this 3 times. + */ for (i = 0; i < 3; i++) if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, data->bank1_settings[sensor_addr], @@ -548,23 +616,25 @@ abituguru_detect_bank1_sensor_type_exit: return ret; } -/* These functions try to find out how many sensors there are in bank2 and how - many pwms there are. The purpose of this is to make sure that we don't give - the user the possibility to change settings for non-existent sensors / pwm. - The uGuru will happily read / write whatever memory happens to be after the - memory storing the PWM settings when reading/writing to a PWM which is not - there. Notice even if we detect a PWM which doesn't exist we normally won't - write to it, unless the user tries to change the settings. - - Although the uGuru allows reading (settings) from non existing bank2 - sensors, my version of the uGuru does seem to stop writing to them, the - write function above aborts in this case with: - "CMD reg does not hold 0xAC after write" - - Notice these 2 tests are non destructive iow read-only tests, otherwise - they would defeat their purpose. Although for the bank2_sensors detection a - read/write test would be feasible because of the reaction above, I've - however opted to stay on the safe side. */ +/* + * These functions try to find out how many sensors there are in bank2 and how + * many pwms there are. The purpose of this is to make sure that we don't give + * the user the possibility to change settings for non-existent sensors / pwm. + * The uGuru will happily read / write whatever memory happens to be after the + * memory storing the PWM settings when reading/writing to a PWM which is not + * there. Notice even if we detect a PWM which doesn't exist we normally won't + * write to it, unless the user tries to change the settings. + * + * Although the uGuru allows reading (settings) from non existing bank2 + * sensors, my version of the uGuru does seem to stop writing to them, the + * write function above aborts in this case with: + * "CMD reg does not hold 0xAC after write" + * + * Notice these 2 tests are non destructive iow read-only tests, otherwise + * they would defeat their purpose. Although for the bank2_sensors detection a + * read/write test would be feasible because of the reaction above, I've + * however opted to stay on the safe side. + */ static void __devinit abituguru_detect_no_bank2_sensors(struct abituguru_data *data) { @@ -580,12 +650,14 @@ abituguru_detect_no_bank2_sensors(struct abituguru_data *data) ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n"); for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) { - /* 0x89 are the known used bits: - -0x80 enable shutdown - -0x08 enable beep - -0x01 enable alarm - All other bits should be 0, but on some motherboards - 0x40 (bit 6) is also high for some of the fans?? */ + /* + * 0x89 are the known used bits: + * -0x80 enable shutdown + * -0x08 enable beep + * -0x01 enable alarm + * All other bits should be 0, but on some motherboards + * 0x40 (bit 6) is also high for some of the fans?? + */ if (data->bank2_settings[i][0] & ~0xC9) { ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " "to be a fan sensor: settings[0] = %02X\n", @@ -633,9 +705,11 @@ abituguru_detect_no_pwms(struct abituguru_data *data) ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n"); for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) { - /* 0x80 is the enable bit and the low - nibble is which temp sensor to use, - the other bits should be 0 */ + /* + * 0x80 is the enable bit and the low + * nibble is which temp sensor to use, + * the other bits should be 0 + */ if (data->pwm_settings[i][0] & ~0x8F) { ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " "to be a pwm channel: settings[0] = %02X\n", @@ -643,8 +717,10 @@ abituguru_detect_no_pwms(struct abituguru_data *data) break; } - /* the low nibble must correspond to one of the temp sensors - we've found */ + /* + * the low nibble must correspond to one of the temp sensors + * we've found + */ for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; j++) { if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] == @@ -711,9 +787,11 @@ abituguru_detect_no_pwms_exit: ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms); } -/* Following are the sysfs callback functions. These functions expect: - sensor_device_attribute_2->index: sensor address/offset in the bank - sensor_device_attribute_2->nr: register offset, bitmask or NA. */ +/* + * Following are the sysfs callback functions. These functions expect: + * sensor_device_attribute_2->index: sensor address/offset in the bank + * sensor_device_attribute_2->nr: register offset, bitmask or NA. + */ static struct abituguru_data *abituguru_update_device(struct device *dev); static ssize_t show_bank1_value(struct device *dev, @@ -763,10 +841,18 @@ static ssize_t store_bank1_setting(struct device *dev, struct device_attribute { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - u8 val = (simple_strtoul(buf, NULL, 10) * 255 + - data->bank1_max_value[attr->index]/2) / + unsigned long val; + ssize_t ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + ret = count; + val = (val * 255 + data->bank1_max_value[attr->index] / 2) / data->bank1_max_value[attr->index]; - ssize_t ret = count; + if (val > 255) + return -EINVAL; mutex_lock(&data->update_lock); if (data->bank1_settings[attr->index][attr->nr] != val) { @@ -788,13 +874,19 @@ static ssize_t store_bank2_setting(struct device *dev, struct device_attribute { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - u8 val = (simple_strtoul(buf, NULL, 10)*255 + ABIT_UGURU_FAN_MAX/2) / - ABIT_UGURU_FAN_MAX; - ssize_t ret = count; + unsigned long val; + ssize_t ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + ret = count; + val = (val * 255 + ABIT_UGURU_FAN_MAX / 2) / ABIT_UGURU_FAN_MAX; /* this check can be done before taking the lock */ - if ((val < abituguru_bank2_min_threshold) || - (val > abituguru_bank2_max_threshold)) + if (val < abituguru_bank2_min_threshold || + val > abituguru_bank2_max_threshold) return -EINVAL; mutex_lock(&data->update_lock); @@ -819,11 +911,13 @@ static ssize_t show_bank1_alarm(struct device *dev, struct abituguru_data *data = abituguru_update_device(dev); if (!data) return -EIO; - /* See if the alarm bit for this sensor is set, and if the - alarm matches the type of alarm we're looking for (for volt - it can be either low or high). The type is stored in a few - readonly bits in the settings part of the relevant sensor. - The bitmask of the type is passed to us in attr->nr. */ + /* + * See if the alarm bit for this sensor is set, and if the + * alarm matches the type of alarm we're looking for (for volt + * it can be either low or high). The type is stored in a few + * readonly bits in the settings part of the relevant sensor. + * The bitmask of the type is passed to us in attr->nr. + */ if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) && (data->bank1_settings[attr->index][0] & attr->nr)) return sprintf(buf, "1\n"); @@ -871,10 +965,15 @@ static ssize_t store_bank1_mask(struct device *dev, { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - int mask = simple_strtoul(buf, NULL, 10); - ssize_t ret = count; + ssize_t ret; u8 orig_val; + unsigned long mask; + + ret = kstrtoul(buf, 10, &mask); + if (ret) + return ret; + ret = count; mutex_lock(&data->update_lock); orig_val = data->bank1_settings[attr->index][0]; @@ -899,10 +998,15 @@ static ssize_t store_bank2_mask(struct device *dev, { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - int mask = simple_strtoul(buf, NULL, 10); - ssize_t ret = count; + ssize_t ret; u8 orig_val; + unsigned long mask; + ret = kstrtoul(buf, 10, &mask); + if (ret) + return ret; + + ret = count; mutex_lock(&data->update_lock); orig_val = data->bank2_settings[attr->index][0]; @@ -937,10 +1041,17 @@ static ssize_t store_pwm_setting(struct device *dev, struct device_attribute { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - u8 min, val = (simple_strtoul(buf, NULL, 10) + - abituguru_pwm_settings_multiplier[attr->nr]/2) / - abituguru_pwm_settings_multiplier[attr->nr]; - ssize_t ret = count; + u8 min; + unsigned long val; + ssize_t ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + ret = count; + val = (val + abituguru_pwm_settings_multiplier[attr->nr] / 2) / + abituguru_pwm_settings_multiplier[attr->nr]; /* special case pwm1 min pwm% */ if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2))) @@ -949,7 +1060,7 @@ static ssize_t store_pwm_setting(struct device *dev, struct device_attribute min = abituguru_pwm_min[attr->nr]; /* this check can be done before taking the lock */ - if ((val < min) || (val > abituguru_pwm_max[attr->nr])) + if (val < min || val > abituguru_pwm_max[attr->nr]) return -EINVAL; mutex_lock(&data->update_lock); @@ -981,8 +1092,10 @@ static ssize_t show_pwm_sensor(struct device *dev, struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); int i; - /* We need to walk to the temp sensor addresses to find what - the userspace id of the configured temp sensor is. */ + /* + * We need to walk to the temp sensor addresses to find what + * the userspace id of the configured temp sensor is. + */ for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++) if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] == (data->pwm_settings[attr->index][0] & 0x0F)) @@ -996,27 +1109,32 @@ static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10) - 1; - ssize_t ret = count; + ssize_t ret; + unsigned long val; + u8 orig_val; + u8 address; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + if (val == 0 || val > data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) + return -EINVAL; + + val -= 1; + ret = count; mutex_lock(&data->update_lock); - if (val < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) { - u8 orig_val = data->pwm_settings[attr->index][0]; - u8 address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val]; - data->pwm_settings[attr->index][0] &= 0xF0; - data->pwm_settings[attr->index][0] |= address; - if (data->pwm_settings[attr->index][0] != orig_val) { - if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, - attr->index, - data->pwm_settings[attr->index], - 5) < 1) { - data->pwm_settings[attr->index][0] = orig_val; - ret = -EIO; - } + orig_val = data->pwm_settings[attr->index][0]; + address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val]; + data->pwm_settings[attr->index][0] &= 0xF0; + data->pwm_settings[attr->index][0] |= address; + if (data->pwm_settings[attr->index][0] != orig_val) { + if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, attr->index, + data->pwm_settings[attr->index], 5) < 1) { + data->pwm_settings[attr->index][0] = orig_val; + ret = -EIO; } } - else - ret = -EINVAL; mutex_unlock(&data->update_lock); return ret; } @@ -1037,22 +1155,27 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute { struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct abituguru_data *data = dev_get_drvdata(dev); - u8 orig_val, user_val = simple_strtoul(buf, NULL, 10); - ssize_t ret = count; + u8 orig_val; + ssize_t ret; + unsigned long user_val; + + ret = kstrtoul(buf, 10, &user_val); + if (ret) + return ret; + ret = count; mutex_lock(&data->update_lock); orig_val = data->pwm_settings[attr->index][0]; switch (user_val) { - case 0: - data->pwm_settings[attr->index][0] &= - ~ABIT_UGURU_FAN_PWM_ENABLE; - break; - case 2: - data->pwm_settings[attr->index][0] |= - ABIT_UGURU_FAN_PWM_ENABLE; - break; - default: - ret = -EINVAL; + case 0: + data->pwm_settings[attr->index][0] &= + ~ABIT_UGURU_FAN_PWM_ENABLE; + break; + case 2: + data->pwm_settings[attr->index][0] |= ABIT_UGURU_FAN_PWM_ENABLE; + break; + default: + ret = -EINVAL; } if ((data->pwm_settings[attr->index][0] != orig_val) && (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, @@ -1147,13 +1270,16 @@ static int __devinit abituguru_probe(struct platform_device *pdev) int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV; char *sysfs_filename; - /* El weirdo probe order, to keep the sysfs order identical to the - BIOS and window-appliction listing order. */ + /* + * El weirdo probe order, to keep the sysfs order identical to the + * BIOS and window-appliction listing order. + */ const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = { 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02, 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C }; - if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL))) + data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL); + if (!data) return -ENOMEM; data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; @@ -1164,9 +1290,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev) if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT) data->uguru_ready = 1; - /* Completely read the uGuru this has 2 purposes: - - testread / see if one really is there. - - make an in memory copy of all the uguru settings for future use. */ + /* + * Completely read the uGuru this has 2 purposes: + * - testread / see if one really is there. + * - make an in memory copy of all the uguru settings for future use. + */ if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3) goto abituguru_probe_error; @@ -1181,11 +1309,13 @@ static int __devinit abituguru_probe(struct platform_device *pdev) ABIT_UGURU_MAX_RETRIES) != 3) goto abituguru_probe_error; } - /* Note: We don't know how many bank2 sensors / pwms there really are, - but in order to "detect" this we need to read the maximum amount - anyways. If we read sensors/pwms not there we'll just read crap - this can't hurt. We need the detection because we don't want - unwanted writes, which will hurt! */ + /* + * Note: We don't know how many bank2 sensors / pwms there really are, + * but in order to "detect" this we need to read the maximum amount + * anyways. If we read sensors/pwms not there we'll just read crap + * this can't hurt. We need the detection because we don't want + * unwanted writes, which will hurt! + */ for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) { if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i, &data->bank2_value[i], 1, @@ -1332,24 +1462,26 @@ static struct abituguru_data *abituguru_update_device(struct device *dev) mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ)) { success = 0; - if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, - data->alarms, 3, 0)) != 3) + err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, + data->alarms, 3, 0); + if (err != 3) goto LEAVE_UPDATE; for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { - if ((err = abituguru_read(data, - ABIT_UGURU_SENSOR_BANK1, i, - &data->bank1_value[i], 1, 0)) != 1) + err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, + i, &data->bank1_value[i], 1, 0); + if (err != 1) goto LEAVE_UPDATE; - if ((err = abituguru_read(data, - ABIT_UGURU_SENSOR_BANK1 + 1, i, - data->bank1_settings[i], 3, 0)) != 3) + err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, + i, data->bank1_settings[i], 3, 0); + if (err != 3) goto LEAVE_UPDATE; } - for (i = 0; i < data->bank2_sensors; i++) - if ((err = abituguru_read(data, - ABIT_UGURU_SENSOR_BANK2, i, - &data->bank2_value[i], 1, 0)) != 1) + for (i = 0; i < data->bank2_sensors; i++) { + err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i, + &data->bank2_value[i], 1, 0); + if (err != 1) goto LEAVE_UPDATE; + } /* success! */ success = 1; data->update_timeouts = 0; @@ -1385,8 +1517,10 @@ LEAVE_UPDATE: static int abituguru_suspend(struct platform_device *pdev, pm_message_t state) { struct abituguru_data *data = platform_get_drvdata(pdev); - /* make sure all communications with the uguru are done and no new - ones are started */ + /* + * make sure all communications with the uguru are done and no new + * ones are started + */ mutex_lock(&data->update_lock); return 0; } @@ -1418,12 +1552,14 @@ static struct platform_driver abituguru_driver = { static int __init abituguru_detect(void) { - /* See if there is an uguru there. After a reboot uGuru will hold 0x00 - at DATA and 0xAC, when this driver has already been loaded once - DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either - scenario but some will hold 0x00. - Some uGuru's initially hold 0x09 at DATA and will only hold 0x08 - after reading CMD first, so CMD must be read first! */ + /* + * See if there is an uguru there. After a reboot uGuru will hold 0x00 + * at DATA and 0xAC, when this driver has already been loaded once + * DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either + * scenario but some will hold 0x00. + * Some uGuru's initially hold 0x09 at DATA and will only hold 0x08 + * after reading CMD first, so CMD must be read first! + */ u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD); u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA); if (((data_val == 0x00) || (data_val == 0x08)) && diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 34a14a77e008..a5bc4287daa6 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1,28 +1,28 @@ /* - abituguru3.c - - Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com> - Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * abituguru3.c + * + * Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com> + * Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - This driver supports the sensor part of revision 3 of the custom Abit uGuru - chip found on newer Abit uGuru motherboards. Note: because of lack of specs - only reading the sensors and their settings is supported. -*/ + * This driver supports the sensor part of revision 3 of the custom Abit uGuru + * chip found on newer Abit uGuru motherboards. Note: because of lack of specs + * only reading the sensors and their settings is supported. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -62,13 +62,17 @@ #define ABIT_UGURU3_TEMP_SENSOR 1 #define ABIT_UGURU3_FAN_SENSOR 2 -/* Timeouts / Retries, if these turn out to need a lot of fiddling we could - convert them to params. Determined by trial and error. I assume this is - cpu-speed independent, since the ISA-bus and not the CPU should be the - bottleneck. */ +/* + * Timeouts / Retries, if these turn out to need a lot of fiddling we could + * convert them to params. Determined by trial and error. I assume this is + * cpu-speed independent, since the ISA-bus and not the CPU should be the + * bottleneck. + */ #define ABIT_UGURU3_WAIT_TIMEOUT 250 -/* Normally the 0xAC at the end of synchronize() is reported after the - first read, but sometimes not and we need to poll */ +/* + * Normally the 0xAC at the end of synchronize() is reported after the + * first read, but sometimes not and we need to poll + */ #define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5 /* utility macros */ #define ABIT_UGURU3_NAME "abituguru3" @@ -78,32 +82,45 @@ /* Macros to help calculate the sysfs_names array length */ #define ABIT_UGURU3_MAX_NO_SENSORS 26 -/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0, - in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */ -#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11) -/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0, - temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0, - temp??_label\0 */ +/* + * sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0, + * in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 + */ +#define ABIT_UGURU3_IN_NAMES_LENGTH \ + (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11) +/* + * sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0, + * temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0, + * temp??_label\0 + */ #define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13) -/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0, - fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */ +/* + * sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0, + * fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 + */ #define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12) -/* Worst case scenario 16 in sensors (longest names_length) and the rest - temp sensors (second longest names_length). */ +/* + * Worst case scenario 16 in sensors (longest names_length) and the rest + * temp sensors (second longest names_length). + */ #define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \ (ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH) -/* All the macros below are named identical to the openguru2 program - reverse engineered by Louis Kruger, hence the names might not be 100% - logical. I could come up with better names, but I prefer keeping the names - identical so that this driver can be compared with his work more easily. */ +/* + * All the macros below are named identical to the openguru2 program + * reverse engineered by Louis Kruger, hence the names might not be 100% + * logical. I could come up with better names, but I prefer keeping the names + * identical so that this driver can be compared with his work more easily. + */ /* Two i/o-ports are used by uGuru */ #define ABIT_UGURU3_BASE 0x00E0 #define ABIT_UGURU3_CMD 0x00 #define ABIT_UGURU3_DATA 0x04 #define ABIT_UGURU3_REGION_LENGTH 5 -/* The wait_xxx functions return this on success and the last contents - of the DATA register (0-255) on failure. */ +/* + * The wait_xxx functions return this on success and the last contents + * of the DATA register (0-255) on failure. + */ #define ABIT_UGURU3_SUCCESS -1 /* uGuru status flags */ #define ABIT_UGURU3_STATUS_READY_FOR_READ 0x01 @@ -112,7 +129,7 @@ /* Structures */ struct abituguru3_sensor_info { - const char* name; + const char *name; int port; int type; int multiplier; @@ -130,9 +147,11 @@ struct abituguru3_motherboard_info { struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1]; }; -/* For the Abit uGuru, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - abituguru3 device is allocated. */ +/* + * For the Abit uGuru, we need to keep some data in memory. + * The structure is dynamically allocated, at the same time when a new + * abituguru3 device is allocated. + */ struct abituguru3_data { struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ @@ -140,8 +159,10 @@ struct abituguru3_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - /* For convenience the sysfs attr and their names are generated - automatically. We have max 10 entries per sensor (for in sensors) */ + /* + * For convenience the sysfs attr and their names are generated + * automatically. We have max 10 entries per sensor (for in sensors) + */ struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS * 10]; @@ -151,9 +172,11 @@ struct abituguru3_data { /* Pointer to the sensors info for the detected motherboard */ const struct abituguru3_sensor_info *sensors; - /* The abituguru3 supports up to 48 sensors, and thus has registers - sets for 48 sensors, for convienence reasons / simplicity of the - code we always read and store all registers for all 48 sensors */ + /* + * The abituguru3 supports up to 48 sensors, and thus has registers + * sets for 48 sensors, for convienence reasons / simplicity of the + * code we always read and store all registers for all 48 sensors + */ /* Alarms for all 48 sensors (1 bit per sensor) */ u8 alarms[48/8]; @@ -161,9 +184,11 @@ struct abituguru3_data { /* Value of all 48 sensors */ u8 value[48]; - /* Settings of all 48 sensors, note in and temp sensors (the first 32 - sensors) have 3 bytes of settings, while fans only have 2 bytes, - for convenience we use 3 bytes for all sensors */ + /* + * Settings of all 48 sensors, note in and temp sensors (the first 32 + * sensors) have 3 bytes of settings, while fans only have 2 bytes, + * for convenience we use 3 bytes for all sensors + */ u8 settings[48][3]; }; @@ -626,8 +651,10 @@ static int abituguru3_wait_while_busy(struct abituguru3_data *data) timeout--; if (timeout == 0) return x; - /* sleep a bit before our last try, to give the uGuru3 one - last chance to respond. */ + /* + * sleep a bit before our last try, to give the uGuru3 one + * last chance to respond. + */ if (timeout == 1) msleep(1); } @@ -645,48 +672,57 @@ static int abituguru3_wait_for_read(struct abituguru3_data *data) timeout--; if (timeout == 0) return x; - /* sleep a bit before our last try, to give the uGuru3 one - last chance to respond. */ + /* + * sleep a bit before our last try, to give the uGuru3 one + * last chance to respond. + */ if (timeout == 1) msleep(1); } return ABIT_UGURU3_SUCCESS; } -/* This synchronizes us with the uGuru3's protocol state machine, this - must be done before each command. */ +/* + * This synchronizes us with the uGuru3's protocol state machine, this + * must be done before each command. + */ static int abituguru3_synchronize(struct abituguru3_data *data) { int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT; - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("synchronize timeout during initial busy " "wait, status: 0x%02x\n", x); return -EIO; } outb(0x20, data->addr + ABIT_UGURU3_DATA); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, " "status: 0x%02x\n", x); return -EIO; } outb(0x10, data->addr + ABIT_UGURU3_CMD); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, " "status: 0x%02x\n", x); return -EIO; } outb(0x00, data->addr + ABIT_UGURU3_CMD); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, " "status: 0x%02x\n", x); return -EIO; } - if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_for_read(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, " "status: 0x%02x\n", x); return -EIO; @@ -705,18 +741,22 @@ static int abituguru3_synchronize(struct abituguru3_data *data) return 0; } -/* Read count bytes from sensor sensor_addr in bank bank_addr and store the - result in buf */ +/* + * Read count bytes from sensor sensor_addr in bank bank_addr and store the + * result in buf + */ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset, u8 count, u8 *buf) { int i, x; - if ((x = abituguru3_synchronize(data))) + x = abituguru3_synchronize(data); + if (x) return x; outb(0x1A, data->addr + ABIT_UGURU3_DATA); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after " "sending 0x1A, status: 0x%02x\n", (unsigned int)bank, (unsigned int)offset, x); @@ -724,7 +764,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset, } outb(bank, data->addr + ABIT_UGURU3_CMD); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after " "sending the bank, status: 0x%02x\n", (unsigned int)bank, (unsigned int)offset, x); @@ -732,7 +773,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset, } outb(offset, data->addr + ABIT_UGURU3_CMD); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after " "sending the offset, status: 0x%02x\n", (unsigned int)bank, (unsigned int)offset, x); @@ -740,7 +782,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset, } outb(count, data->addr + ABIT_UGURU3_CMD); - if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_while_busy(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after " "sending the count, status: 0x%02x\n", (unsigned int)bank, (unsigned int)offset, x); @@ -748,8 +791,8 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset, } for (i = 0; i < count; i++) { - if ((x = abituguru3_wait_for_read(data)) != - ABIT_UGURU3_SUCCESS) { + x = abituguru3_wait_for_read(data); + if (x != ABIT_UGURU3_SUCCESS) { ABIT_UGURU3_DEBUG("timeout reading byte %d from " "0x%02x:0x%02x, status: 0x%02x\n", i, (unsigned int)bank, (unsigned int)offset, x); @@ -760,28 +803,34 @@ static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset, return i; } -/* Sensor settings are stored 1 byte per offset with the bytes - placed add consecutive offsets. */ +/* + * Sensor settings are stored 1 byte per offset with the bytes + * placed add consecutive offsets. + */ static int abituguru3_read_increment_offset(struct abituguru3_data *data, u8 bank, u8 offset, u8 count, u8 *buf, int offset_count) { int i, x; - for (i = 0; i < offset_count; i++) - if ((x = abituguru3_read(data, bank, offset + i, count, - buf + i * count)) != count) { + for (i = 0; i < offset_count; i++) { + x = abituguru3_read(data, bank, offset + i, count, + buf + i * count); + if (x != count) { if (x < 0) return x; return i * count + x; } + } return i * count; } -/* Following are the sysfs callback functions. These functions expect: - sensor_device_attribute_2->index: index into the data->sensors array - sensor_device_attribute_2->nr: register offset, bitmask or NA. */ +/* + * Following are the sysfs callback functions. These functions expect: + * sensor_device_attribute_2->index: index into the data->sensors array + * sensor_device_attribute_2->nr: register offset, bitmask or NA. + */ static struct abituguru3_data *abituguru3_update_device(struct device *dev); static ssize_t show_value(struct device *dev, @@ -807,8 +856,10 @@ static ssize_t show_value(struct device *dev, value = (value * sensor->multiplier) / sensor->divisor + sensor->offset; - /* alternatively we could update the sensors settings struct for this, - but then its contents would differ from the windows sw ini files */ + /* + * alternatively we could update the sensors settings struct for this, + * but then its contents would differ from the windows sw ini files + */ if (sensor->type == ABIT_UGURU3_TEMP_SENSOR) value *= 1000; @@ -827,10 +878,12 @@ static ssize_t show_alarm(struct device *dev, port = data->sensors[attr->index].port; - /* See if the alarm bit for this sensor is set and if a bitmask is - given in attr->nr also check if the alarm matches the type of alarm - we're looking for (for volt it can be either low or high). The type - is stored in a few readonly bits in the settings of the sensor. */ + /* + * See if the alarm bit for this sensor is set and if a bitmask is + * given in attr->nr also check if the alarm matches the type of alarm + * we're looking for (for volt it can be either low or high). The type + * is stored in a few readonly bits in the settings of the sensor. + */ if ((data->alarms[port / 8] & (0x01 << (port % 8))) && (!attr->nr || (data->settings[port][0] & attr->nr))) return sprintf(buf, "1\n"); @@ -923,7 +976,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) u8 buf[2]; u16 id; - if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL))) + data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL); + if (!data) return -ENOMEM; data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; @@ -931,10 +985,10 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); /* Read the motherboard ID */ - if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK, - ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) { + i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK, ABIT_UGURU3_BOARD_ID, + 2, buf); + if (i != 2) goto abituguru3_probe_error; - } /* Completely read the uGuru to see if one really is there */ if (!abituguru3_update_device(&pdev->dev)) @@ -1091,8 +1145,10 @@ LEAVE_UPDATE: static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state) { struct abituguru3_data *data = platform_get_drvdata(pdev); - /* make sure all communications with the uguru3 are done and no new - ones are started */ + /* + * make sure all communications with the uguru3 are done and no new + * ones are started + */ mutex_lock(&data->update_lock); return 0; } @@ -1134,7 +1190,8 @@ static int __init abituguru3_dmi_detect(void) if (!board_name) return err; - /* At the moment, we don't care about the part of the vendor + /* + * At the moment, we don't care about the part of the vendor * DMI string contained in brackets. Truncate the string at * the first occurrence of a bracket. Trim any trailing space * from the substring. @@ -1157,15 +1214,18 @@ static int __init abituguru3_dmi_detect(void) return 1; } -/* FIXME: Manual detection should die eventually; we need to collect stable +/* + * FIXME: Manual detection should die eventually; we need to collect stable * DMI model names first before we can rely entirely on CONFIG_DMI. */ static int __init abituguru3_detect(void) { - /* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or - 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05 - or 0x55 at CMD instead, why is unknown. */ + /* + * See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or + * 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05 + * or 0x55 at CMD instead, why is unknown. + */ u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA); u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD); if (((data_val == 0x00) || (data_val == 0x08)) && @@ -1197,7 +1257,8 @@ static int __init abituguru3_init(void) if (err < 0) return err; - /* Fall back to manual detection if there was no exact + /* + * Fall back to manual detection if there was no exact * board name match, or force was specified. */ if (err > 0) { diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index 5d760f3d21c2..0e0cfcc36f8d 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -167,17 +167,7 @@ static struct spi_driver ad7314_driver = { .id_table = ad7314_id, }; -static __init int ad7314_init(void) -{ - return spi_register_driver(&ad7314_driver); -} -module_init(ad7314_init); - -static __exit void ad7314_exit(void) -{ - spi_unregister_driver(&ad7314_driver); -} -module_exit(ad7314_exit); +module_spi_driver(ad7314_driver); MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index df29a7fff9e7..06d2d60d1fd0 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -50,7 +50,8 @@ struct ad7414_data { /* REG: (0.25C/bit, two's complement) << 6 */ static inline int ad7414_temp_from_reg(s16 reg) { - /* use integer division instead of equivalent right shift to + /* + * use integer division instead of equivalent right shift to * guarantee arithmetic shift and preserve the sign */ return ((int)reg / 64) * 250; @@ -130,7 +131,11 @@ static ssize_t set_max_min(struct device *dev, struct ad7414_data *data = i2c_get_clientdata(client); int index = to_sensor_dev_attr(attr)->index; u8 reg = AD7414_REG_LIMIT[index]; - long temp = simple_strtol(buf, NULL, 10); + long temp; + int ret = kstrtol(buf, 10, &temp); + + if (ret < 0) + return ret; temp = SENSORS_LIMIT(temp, -40000, 85000); temp = (temp + (temp < 0 ? -500 : 500)) / 1000; @@ -252,17 +257,7 @@ static struct i2c_driver ad7414_driver = { .id_table = ad7414_id, }; -static int __init ad7414_init(void) -{ - return i2c_add_driver(&ad7414_driver); -} -module_init(ad7414_init); - -static void __exit ad7414_exit(void) -{ - i2c_del_driver(&ad7414_driver); -} -module_exit(ad7414_exit); +module_i2c_driver(ad7414_driver); MODULE_AUTHOR("Stefan Roese <sr at denx.de>, " "Frank Edelhaeuser <frank.edelhaeuser at spansion.com>"); diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index 8cb718ce8237..a50a6bef16c4 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -167,7 +167,11 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct ad7418_data *data = i2c_get_clientdata(client); - long temp = simple_strtol(buf, NULL, 10); + long temp; + int ret = kstrtol(buf, 10, &temp); + + if (ret < 0) + return ret; mutex_lock(&data->lock); data->temp[attr->index] = LM75_TEMP_TO_REG(temp); @@ -228,7 +232,8 @@ static int ad7418_probe(struct i2c_client *client, goto exit; } - if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit; } @@ -261,7 +266,8 @@ static int ad7418_probe(struct i2c_client *client, ad7418_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) + err = sysfs_create_group(&client->dev.kobj, &data->attrs); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&client->dev); @@ -289,20 +295,9 @@ static int ad7418_remove(struct i2c_client *client) return 0; } -static int __init ad7418_init(void) -{ - return i2c_add_driver(&ad7418_driver); -} - -static void __exit ad7418_exit(void) -{ - i2c_del_driver(&ad7418_driver); -} +module_i2c_driver(ad7418_driver); MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); MODULE_DESCRIPTION("AD7416/17/18 driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); - -module_init(ad7418_init); -module_exit(ad7418_exit); diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index ceb24a365176..a3d3183454ad 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c @@ -248,18 +248,7 @@ static struct spi_driver adcxx_driver = { .remove = __devexit_p(adcxx_remove), }; -static int __init init_adcxx(void) -{ - return spi_register_driver(&adcxx_driver); -} - -static void __exit exit_adcxx(void) -{ - spi_unregister_driver(&adcxx_driver); -} - -module_init(init_adcxx); -module_exit(exit_adcxx); +module_spi_driver(adcxx_driver); MODULE_AUTHOR("Marc Pignat"); MODULE_DESCRIPTION("National Semiconductor adcxx8sxxx Linux driver"); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 0158cc35cb2e..4394e7e99c46 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -1,23 +1,23 @@ /* - adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and - Philip Edelbrock <phil@netroedge.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * adm1021.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and + * Philip Edelbrock <phil@netroedge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -70,10 +70,12 @@ enum chips { /* Initial values */ -/* Note: Even though I left the low and high limits named os and hyst, -they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actually triggers an alarm instead of -clearing it. Weird, ey? --Phil */ +/* + * Note: Even though I left the low and high limits named os and hyst, + * they don't quite work like a thermostat the way the LM75 does. I.e., + * a lower temp than THYST actually triggers an alarm instead of + * clearing it. Weird, ey? --Phil + */ /* Each client has this additional data */ struct adm1021_data { @@ -182,7 +184,13 @@ static ssize_t set_temp_max(struct device *dev, int index = to_sensor_dev_attr(devattr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1021_data *data = i2c_get_clientdata(client); - long temp = simple_strtol(buf, NULL, 10) / 1000; + long temp; + int err; + + err = kstrtol(buf, 10, &temp); + if (err) + return err; + temp /= 1000; mutex_lock(&data->update_lock); data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127); @@ -201,7 +209,13 @@ static ssize_t set_temp_min(struct device *dev, int index = to_sensor_dev_attr(devattr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1021_data *data = i2c_get_clientdata(client); - long temp = simple_strtol(buf, NULL, 10) / 1000; + long temp; + int err; + + err = kstrtol(buf, 10, &temp); + if (err) + return err; + temp /= 1000; mutex_lock(&data->update_lock); data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127); @@ -226,7 +240,14 @@ static ssize_t set_low_power(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct adm1021_data *data = i2c_get_clientdata(client); - int low_power = simple_strtol(buf, NULL, 10) != 0; + char low_power; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + low_power = val != 0; mutex_lock(&data->update_lock); if (low_power != data->low_power) { @@ -361,7 +382,8 @@ static int adm1021_probe(struct i2c_client *client, adm1021_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group))) + err = sysfs_create_group(&client->dev.kobj, &adm1021_group); + if (err) goto error1; data->hwmon_dev = hwmon_device_register(&client->dev); @@ -427,8 +449,10 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) data->alarms = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS) & 0x7c; if (data->type == adm1023) { - /* The ADM1023 provides 3 extra bits of precision for - * the remote sensor in extra registers. */ + /* + * The ADM1023 provides 3 extra bits of precision for + * the remote sensor in extra registers. + */ data->temp[1] += 125 * (i2c_smbus_read_byte_data( client, ADM1023_REG_REM_TEMP_PREC) >> 5); data->temp_max[1] += 125 * (i2c_smbus_read_byte_data( @@ -451,23 +475,12 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) return data; } -static int __init sensors_adm1021_init(void) -{ - return i2c_add_driver(&adm1021_driver); -} - -static void __exit sensors_adm1021_exit(void) -{ - i2c_del_driver(&adm1021_driver); -} +module_i2c_driver(adm1021_driver); -MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl> and " +MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " "Philip Edelbrock <phil@netroedge.com>"); MODULE_DESCRIPTION("adm1021 driver"); MODULE_LICENSE("GPL"); module_param(read_only, bool, 0); MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sensors_adm1021_init) -module_exit(sensors_adm1021_exit) diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 60befc0ee65f..b8557f9857d2 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -12,7 +12,7 @@ * resolution of about 0.5% of the nominal value). Temperature values are * reported with a 1 deg resolution and a 3 deg accuracy. Complete * datasheet can be obtained from Analog's website at: - * http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025 + * http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025 * * This driver also supports the ADM1025A, which differs from the ADM1025 * only in that it has "open-drain VID inputs while the ADM1025 has @@ -91,15 +91,16 @@ enum chips { adm1025, ne1619 }; static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; -#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) -#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ +#define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192) +#define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \ (val) * 192 >= (scale) * 255 ? 255 : \ - ((val) * 192 + (scale)/2) / (scale)) + ((val) * 192 + (scale) / 2) / (scale)) #define TEMP_FROM_REG(reg) ((reg) * 1000) #define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ (val) >= 126500 ? 127 : \ - (((val) < 0 ? (val)-500 : (val)+500) / 1000)) + (((val) < 0 ? (val) - 500 : \ + (val) + 500) / 1000)) /* * Functions declaration @@ -218,7 +219,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, int index = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[index] = IN_TO_REG(val, in_scale[index]); @@ -234,7 +240,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, int index = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[index] = IN_TO_REG(val, in_scale[index]); @@ -264,7 +275,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, int index = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[index] = TEMP_TO_REG(val); @@ -280,7 +296,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, int index = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[index] = TEMP_TO_REG(val); @@ -343,7 +364,14 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adm1025_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + data->vrm = val; return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); @@ -462,14 +490,15 @@ static int adm1025_probe(struct i2c_client *client, adm1025_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group))) + err = sysfs_create_group(&client->dev.kobj, &adm1025_group); + if (err) goto exit_free; /* Pin 11 is either in4 (+12V) or VID4 */ config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); if (!(config & 0x20)) { - if ((err = sysfs_create_group(&client->dev.kobj, - &adm1025_group_in4))) + err = sysfs_create_group(&client->dev.kobj, &adm1025_group_in4); + if (err) goto exit_remove; } @@ -506,7 +535,7 @@ static void adm1025_init_client(struct i2c_client *client) * setting yet, we better set the high limits to the max so that * no alarm triggers. */ - for (i=0; i<6; i++) { + for (i = 0; i < 6; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); if (reg == 0) @@ -514,7 +543,7 @@ static void adm1025_init_client(struct i2c_client *client) ADM1025_REG_IN_MAX(i), 0xFF); } - for (i=0; i<2; i++) { + for (i = 0; i < 2; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(i)); if (reg == 0) @@ -555,7 +584,7 @@ static struct adm1025_data *adm1025_update_device(struct device *dev) int i; dev_dbg(&client->dev, "Updating data.\n"); - for (i=0; i<6; i++) { + for (i = 0; i < 6; i++) { data->in[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN(i)); data->in_min[i] = i2c_smbus_read_byte_data(client, @@ -563,7 +592,7 @@ static struct adm1025_data *adm1025_update_device(struct device *dev) data->in_max[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); } - for (i=0; i<2; i++) { + for (i = 0; i < 2; i++) { data->temp[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP(i)); data->temp_min[i] = i2c_smbus_read_byte_data(client, @@ -589,19 +618,8 @@ static struct adm1025_data *adm1025_update_device(struct device *dev) return data; } -static int __init sensors_adm1025_init(void) -{ - return i2c_add_driver(&adm1025_driver); -} - -static void __exit sensors_adm1025_exit(void) -{ - i2c_del_driver(&adm1025_driver); -} +module_i2c_driver(adm1025_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("ADM1025 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_adm1025_init); -module_exit(sensors_adm1025_exit); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 0531867484f4..1003219b9f90 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1,27 +1,27 @@ /* - adm1026.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> - Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com> - - Chip details at: - - <http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * adm1026.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> + * Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com> + * + * Chip details at: + * + * <http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -90,7 +90,8 @@ MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs"); #define E2CFG_ROM 0x08 #define E2CFG_CLK_EXT 0x80 -/* There are 10 general analog inputs and 7 dedicated inputs +/* + * There are 10 general analog inputs and 7 dedicated inputs * They are: * 0 - 9 = AIN0 - AIN9 * 10 = Vbat @@ -117,7 +118,8 @@ static u16 ADM1026_REG_IN_MAX[] = { 0x43, 0x44, 0x45, 0x46, 0x47 }; -/* Temperatures are: +/* + * Temperatures are: * 0 - Internal * 1 - External 1 * 2 - External 2 @@ -170,12 +172,14 @@ static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; #define ADM1026_FAN_CONTROL_TEMP_RANGE 20 #define ADM1026_PWM_MAX 255 -/* Conversions. Rounding and limit checking is only done on the TO_REG +/* + * Conversions. Rounding and limit checking is only done on the TO_REG * variants. Note that you should be a bit careful with which arguments * these macros are called: arguments may be evaluated more than once. */ -/* IN are scaled according to built-in resistors. These are the +/* + * IN are scaled according to built-in resistors. These are the * voltages corresponding to 3/4 of full scale (192 or 0xc0) * NOTE: The -12V input needs an additional factor to account * for the Vref pullup resistor. @@ -197,23 +201,25 @@ static int adm1026_scaling[] = { /* .001 Volts */ 0, 255)) #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n])) -/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses +/* + * FAN speed is measured using 22.5kHz clock and counts for 2 pulses * and we assume a 2 pulse-per-rev fan tach signal * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 */ #define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \ - SENSORS_LIMIT(1350000/((val)*(div)), 1, 254)) -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1:(val) == 0xff ? 0 : \ - 1350000/((val)*(div))) -#define DIV_FROM_REG(val) (1<<(val)) + SENSORS_LIMIT(1350000 / ((val) * (div)), \ + 1, 254)) +#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \ + 1350000 / ((val) * (div))) +#define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) /* Temperature is reported in 1 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127, 127)) +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \ + / 1000, -127, 127)) #define TEMP_FROM_REG(val) ((val) * 1000) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ - -127, 127)) +#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val) + ((val) < 0 ? -500 : 500)) \ + / 1000, -127, 127)) #define OFFSET_FROM_REG(val) ((val) * 1000) #define PWM_TO_REG(val) (SENSORS_LIMIT(val, 0, 255)) @@ -222,14 +228,16 @@ static int adm1026_scaling[] = { /* .001 Volts */ #define PWM_MIN_TO_REG(val) ((val) & 0xf0) #define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4)) -/* Analog output is a voltage, and scaled to millivolts. The datasheet +/* + * Analog output is a voltage, and scaled to millivolts. The datasheet * indicates that the DAC could be used to drive the fans, but in our * example board (Arima HDAMA) it isn't connected to the fans at all. */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500), 0, 255)) -#define DAC_FROM_REG(val) (((val)*2500)/255) +#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val) * 255) + 500) / 2500), 0, 255)) +#define DAC_FROM_REG(val) (((val) * 2500) / 255) -/* Chip sampling rates +/* + * Chip sampling rates * * Some sensors are not updated more frequently than once per second * so it doesn't make sense to read them more often than that. @@ -243,11 +251,13 @@ static int adm1026_scaling[] = { /* .001 Volts */ #define ADM1026_DATA_INTERVAL (1 * HZ) #define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) -/* We allow for multiple chips in a single system. +/* + * We allow for multiple chips in a single system. * * For each registered ADM1026, we need to keep state information * at client->data. The adm1026_data structure is dynamically - * allocated, when a new client structure is allocated. */ + * allocated, when a new client structure is allocated. + */ struct pwm_data { u8 pwm; @@ -388,17 +398,16 @@ static void adm1026_init_client(struct i2c_client *client) dev_dbg(&client->dev, "THERM pin enabled. " "GPIO16 disabled.\n"); } - if (data->config3 & CFG3_VREF_250) { + if (data->config3 & CFG3_VREF_250) dev_dbg(&client->dev, "Vref is 2.50 Volts.\n"); - } else { + else dev_dbg(&client->dev, "Vref is 1.82 Volts.\n"); - } /* Read and pick apart the existing GPIO configuration */ value = 0; - for (i = 0;i <= 15;++i) { + for (i = 0; i <= 15; ++i) { if ((i & 0x03) == 0) { value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4); + ADM1026_REG_GPIO_CFG_0_3 + i / 4); } data->gpio_config[i] = value & 0x03; value >>= 2; @@ -408,7 +417,8 @@ static void adm1026_init_client(struct i2c_client *client) /* ... and then print it */ adm1026_print_gpio(client); - /* If the user asks us to reprogram the GPIO config, then + /* + * If the user asks us to reprogram the GPIO config, then * do it now. */ if (gpio_input[0] != -1 || gpio_output[0] != -1 @@ -417,7 +427,8 @@ static void adm1026_init_client(struct i2c_client *client) adm1026_fixup_gpio(client); } - /* WE INTENTIONALLY make no changes to the limits, + /* + * WE INTENTIONALLY make no changes to the limits, * offsets, pwms, fans and zones. If they were * configured, we don't want to mess with them. * If they weren't, the default is 100% PWM, no @@ -428,7 +439,7 @@ static void adm1026_init_client(struct i2c_client *client) * without first setting a value for pwm1.auto_pwm_min * will not result in potentially dangerous fan speed decrease. */ - data->pwm1.auto_pwm_min=255; + data->pwm1.auto_pwm_min = 255; /* Start monitoring */ value = adm1026_read_value(client, ADM1026_REG_CONFIG1); /* Set MONITOR, clear interrupt acknowledge and s/w reset */ @@ -440,7 +451,7 @@ static void adm1026_init_client(struct i2c_client *client) /* initialize fan_div[] to hardware defaults */ value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); - for (i = 0;i <= 7;++i) { + for (i = 0; i <= 7; ++i) { data->fan_div[i] = DIV_FROM_REG(value & 0x03); value >>= 2; } @@ -452,7 +463,7 @@ static void adm1026_print_gpio(struct i2c_client *client) int i; dev_dbg(&client->dev, "GPIO config is:\n"); - for (i = 0;i <= 7;++i) { + for (i = 0; i <= 7; ++i) { if (data->config2 & (1 << i)) { dev_dbg(&client->dev, "\t%sGP%s%d\n", data->gpio_config[i] & 0x02 ? "" : "!", @@ -462,7 +473,7 @@ static void adm1026_print_gpio(struct i2c_client *client) dev_dbg(&client->dev, "\tFAN%d\n", i); } } - for (i = 8;i <= 15;++i) { + for (i = 8; i <= 15; ++i) { dev_dbg(&client->dev, "\t%sGP%s%d\n", data->gpio_config[i] & 0x02 ? "" : "!", data->gpio_config[i] & 0x01 ? "OUT" : "IN", @@ -485,52 +496,46 @@ static void adm1026_fixup_gpio(struct i2c_client *client) int value; /* Make the changes requested. */ - /* We may need to unlock/stop monitoring or soft-reset the + /* + * We may need to unlock/stop monitoring or soft-reset the * chip before we can make changes. This hasn't been * tested much. FIXME */ /* Make outputs */ - for (i = 0;i <= 16;++i) { - if (gpio_output[i] >= 0 && gpio_output[i] <= 16) { + for (i = 0; i <= 16; ++i) { + if (gpio_output[i] >= 0 && gpio_output[i] <= 16) data->gpio_config[gpio_output[i]] |= 0x01; - } /* if GPIO0-7 is output, it isn't a FAN tach */ - if (gpio_output[i] >= 0 && gpio_output[i] <= 7) { + if (gpio_output[i] >= 0 && gpio_output[i] <= 7) data->config2 |= 1 << gpio_output[i]; - } } /* Input overrides output */ - for (i = 0;i <= 16;++i) { - if (gpio_input[i] >= 0 && gpio_input[i] <= 16) { - data->gpio_config[gpio_input[i]] &= ~ 0x01; - } + for (i = 0; i <= 16; ++i) { + if (gpio_input[i] >= 0 && gpio_input[i] <= 16) + data->gpio_config[gpio_input[i]] &= ~0x01; /* if GPIO0-7 is input, it isn't a FAN tach */ - if (gpio_input[i] >= 0 && gpio_input[i] <= 7) { + if (gpio_input[i] >= 0 && gpio_input[i] <= 7) data->config2 |= 1 << gpio_input[i]; - } } /* Inverted */ - for (i = 0;i <= 16;++i) { - if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) { - data->gpio_config[gpio_inverted[i]] &= ~ 0x02; - } + for (i = 0; i <= 16; ++i) { + if (gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16) + data->gpio_config[gpio_inverted[i]] &= ~0x02; } /* Normal overrides inverted */ - for (i = 0;i <= 16;++i) { - if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) { + for (i = 0; i <= 16; ++i) { + if (gpio_normal[i] >= 0 && gpio_normal[i] <= 16) data->gpio_config[gpio_normal[i]] |= 0x02; - } } /* Fan overrides input and output */ - for (i = 0;i <= 7;++i) { - if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) { + for (i = 0; i <= 7; ++i) { + if (gpio_fan[i] >= 0 && gpio_fan[i] <= 7) data->config2 &= ~(1 << gpio_fan[i]); - } } /* Write new configs to registers */ @@ -538,7 +543,7 @@ static void adm1026_fixup_gpio(struct i2c_client *client) data->config3 = (data->config3 & 0x3f) | ((data->gpio_config[16] & 0x03) << 6); adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); - for (i = 15, value = 0;i >= 0;--i) { + for (i = 15, value = 0; i >= 0; --i) { value <<= 2; value |= data->gpio_config[i] & 0x03; if ((i & 0x03) == 0) { @@ -563,22 +568,25 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) mutex_lock(&data->update_lock); if (!data->valid - || time_after(jiffies, data->last_reading + ADM1026_DATA_INTERVAL)) { + || time_after(jiffies, + data->last_reading + ADM1026_DATA_INTERVAL)) { /* Things that change quickly */ dev_dbg(&client->dev, "Reading sensor values\n"); - for (i = 0;i <= 16;++i) { + for (i = 0; i <= 16; ++i) { data->in[i] = adm1026_read_value(client, ADM1026_REG_IN[i]); } - for (i = 0;i <= 7;++i) { + for (i = 0; i <= 7; ++i) { data->fan[i] = adm1026_read_value(client, ADM1026_REG_FAN(i)); } - for (i = 0;i <= 2;++i) { - /* NOTE: temp[] is s8 and we assume 2's complement - * "conversion" in the assignment */ + for (i = 0; i <= 2; ++i) { + /* + * NOTE: temp[] is s8 and we assume 2's complement + * "conversion" in the assignment + */ data->temp[i] = adm1026_read_value(client, ADM1026_REG_TEMP[i]); } @@ -614,7 +622,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { /* Things that don't change often */ dev_dbg(&client->dev, "Reading config values\n"); - for (i = 0;i <= 16;++i) { + for (i = 0; i <= 16; ++i) { data->in_min[i] = adm1026_read_value(client, ADM1026_REG_IN_MIN[i]); data->in_max[i] = adm1026_read_value(client, @@ -624,7 +632,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); - for (i = 0;i <= 7;++i) { + for (i = 0; i <= 7; ++i) { data->fan_min[i] = adm1026_read_value(client, ADM1026_REG_FAN_MIN(i)); data->fan_div[i] = DIV_FROM_REG(value & 0x03); @@ -632,7 +640,8 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) } for (i = 0; i <= 2; ++i) { - /* NOTE: temp_xxx[] are s8 and we assume 2's + /* + * NOTE: temp_xxx[] are s8 and we assume 2's * complement "conversion" in the assignment */ data->temp_min[i] = adm1026_read_value(client, @@ -681,7 +690,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) data->gpio_config[16] = (data->config3 >> 6) & 0x03; value = 0; - for (i = 0;i <= 15;++i) { + for (i = 0; i <= 15; ++i) { if ((i & 0x03) == 0) { value = adm1026_read_value(client, ADM1026_REG_GPIO_CFG_0_3 + i/4); @@ -721,7 +730,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = INS_TO_REG(nr, val); @@ -744,7 +758,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = INS_TO_REG(nr, val); @@ -779,23 +798,31 @@ in_reg(13); in_reg(14); in_reg(15); -static ssize_t show_in16(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_in16(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in[16]) - NEG12_OFFSET); } -static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_in16_min(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_min[16]) - NEG12_OFFSET); } -static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET); @@ -803,17 +830,24 @@ static ssize_t set_in16_min(struct device *dev, struct device_attribute *attr, c mutex_unlock(&data->update_lock); return count; } -static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_in16_max(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", INS_FROM_REG(16, data->in_max[16]) - NEG12_OFFSET); } -static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET); @@ -823,10 +857,10 @@ static ssize_t set_in16_max(struct device *dev, struct device_attribute *attr, c } static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in16, NULL, 16); -static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, set_in16_min, 16); -static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, set_in16_max, 16); - - +static SENSOR_DEVICE_ATTR(in16_min, S_IRUGO | S_IWUSR, show_in16_min, + set_in16_min, 16); +static SENSOR_DEVICE_ATTR(in16_max, S_IRUGO | S_IWUSR, show_in16_max, + set_in16_max, 16); /* Now add fan read/write functions */ @@ -856,7 +890,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, data->fan_div[nr]); @@ -890,9 +929,8 @@ static void fixup_fan_min(struct device *dev, int fan, int old_div) int new_div = data->fan_div[fan]; /* 0 and 0xff are special. Don't adjust them */ - if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) { + if (data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff) return; - } new_min = data->fan_min[fan] * old_div / new_div; new_min = SENSORS_LIMIT(new_min, 1, 254); @@ -916,9 +954,14 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val, orig_div, new_div; + long val; + int orig_div, new_div; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; - val = simple_strtol(buf, NULL, 10); new_div = DIV_TO_REG(val); mutex_lock(&data->update_lock); @@ -939,9 +982,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, (DIV_TO_REG(data->fan_div[7]) << 6)); } - if (data->fan_div[nr] != orig_div) { + if (data->fan_div[nr] != orig_div) fixup_fan_min(dev, nr, orig_div); - } + mutex_unlock(&data->update_lock); return count; } @@ -983,7 +1026,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); @@ -1007,7 +1055,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); @@ -1046,7 +1099,12 @@ static ssize_t set_temp_offset(struct device *dev, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_offset[nr] = TEMP_TO_REG(val); @@ -1056,8 +1114,8 @@ static ssize_t set_temp_offset(struct device *dev, return count; } -#define temp_offset_reg(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ +#define temp_offset_reg(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_offset, S_IRUGO | S_IWUSR, \ show_temp_offset, set_temp_offset, offset - 1); temp_offset_reg(1); @@ -1097,7 +1155,12 @@ static ssize_t set_temp_auto_point1_temp(struct device *dev, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_tmin[nr] = TEMP_TO_REG(val); @@ -1131,15 +1194,21 @@ static ssize_t set_temp_crit_enable(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (val > 1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); + adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1); + mutex_unlock(&data->update_lock); - if ((val == 1) || (val==0)) { - mutex_lock(&data->update_lock); - data->config1 = (data->config1 & ~CFG1_THERM_HOT) | (val << 4); - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - mutex_unlock(&data->update_lock); - } return count; } @@ -1166,7 +1235,12 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_crit[nr] = TEMP_TO_REG(val); @@ -1184,17 +1258,24 @@ temp_crit_reg(1); temp_crit_reg(2); temp_crit_reg(3); -static ssize_t show_analog_out_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_analog_out_reg(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", DAC_FROM_REG(data->analog_out)); } -static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_analog_out_reg(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->analog_out = DAC_TO_REG(val); @@ -1206,7 +1287,8 @@ static ssize_t set_analog_out_reg(struct device *dev, struct device_attribute *a static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, set_analog_out_reg); -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); int vid = (data->gpio >> 11) & 0x1f; @@ -1214,25 +1296,35 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c dev_dbg(dev, "Setting VID from GPIO11-15.\n"); return sprintf(buf, "%d\n", vid_from_reg(vid, data->vrm)); } + static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) + +static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; - data->vrm = simple_strtol(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + data->vrm = val; return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms_reg(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->alarms); @@ -1277,18 +1369,24 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 24); static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25); static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 26); -static ssize_t show_alarm_mask(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarm_mask(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->alarm_mask); } -static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); unsigned long mask; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->alarm_mask = val & 0x7fffffff; @@ -1313,18 +1411,24 @@ static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, set_alarm_mask); -static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->gpio); } -static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); long gpio; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->gpio = val & 0x1ffff; @@ -1340,19 +1444,24 @@ static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, const static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); - -static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->gpio_mask); } -static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); long mask; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->gpio_mask = val & 0x1ffff; @@ -1368,19 +1477,26 @@ static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); -static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm1.pwm)); } -static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) + +static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); if (data->pwm1.enable == 1) { - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm1.pwm = PWM_TO_REG(val); @@ -1389,17 +1505,26 @@ static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, co } return count; } -static ssize_t show_auto_pwm_min(struct device *dev, struct device_attribute *attr, char *buf) + +static ssize_t show_auto_pwm_min(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", data->pwm1.auto_pwm_min); } -static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) + +static ssize_t set_auto_pwm_min(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm1.auto_pwm_min = SENSORS_LIMIT(val, 0, 255); @@ -1411,44 +1536,53 @@ static ssize_t set_auto_pwm_min(struct device *dev, struct device_attribute *att mutex_unlock(&data->update_lock); return count; } -static ssize_t show_auto_pwm_max(struct device *dev, struct device_attribute *attr, char *buf) + +static ssize_t show_auto_pwm_max(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", ADM1026_PWM_MAX); } -static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) + +static ssize_t show_pwm_enable(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", data->pwm1.enable); } -static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) + +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1026_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); int old_enable; + unsigned long val; + int err; - if ((val >= 0) && (val < 3)) { - mutex_lock(&data->update_lock); - old_enable = data->pwm1.enable; - data->pwm1.enable = val; - data->config1 = (data->config1 & ~CFG1_PWM_AFC) - | ((val == 2) ? CFG1_PWM_AFC : 0); - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ - data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | - PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm1.pwm); - } else if (!((old_enable == 1) && (val == 1))) { - /* set pwm to safe value */ - data->pwm1.pwm = 255; - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm1.pwm); - } - mutex_unlock(&data->update_lock); + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (val >= 3) + return -EINVAL; + + mutex_lock(&data->update_lock); + old_enable = data->pwm1.enable; + data->pwm1.enable = val; + data->config1 = (data->config1 & ~CFG1_PWM_AFC) + | ((val == 2) ? CFG1_PWM_AFC : 0); + adm1026_write_value(client, ADM1026_REG_CONFIG1, data->config1); + if (val == 2) { /* apply pwm1_auto_pwm_min to pwm1 */ + data->pwm1.pwm = PWM_TO_REG((data->pwm1.pwm & 0x0f) | + PWM_MIN_TO_REG(data->pwm1.auto_pwm_min)); + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); + } else if (!((old_enable == 1) && (val == 1))) { + /* set pwm to safe value */ + data->pwm1.pwm = 255; + adm1026_write_value(client, ADM1026_REG_PWM, data->pwm1.pwm); } + mutex_unlock(&data->update_lock); + return count; } @@ -1716,7 +1850,8 @@ static int adm1026_probe(struct i2c_client *client, adm1026_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group))) + err = sysfs_create_group(&client->dev.kobj, &adm1026_group); + if (err) goto exitfree; if (data->config1 & CFG1_AIN8_9) err = sysfs_create_group(&client->dev.kobj, @@ -1761,20 +1896,9 @@ static int adm1026_remove(struct i2c_client *client) return 0; } -static int __init sm_adm1026_init(void) -{ - return i2c_add_driver(&adm1026_driver); -} - -static void __exit sm_adm1026_exit(void) -{ - i2c_del_driver(&adm1026_driver); -} +module_i2c_driver(adm1026_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, " "Justin Thiessen <jthiessen@penguincomputing.com>"); MODULE_DESCRIPTION("ADM1026 driver"); - -module_init(sm_adm1026_init); -module_exit(sm_adm1026_exit); diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index 0b8a3b145bd2..80cc465d8ac7 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -78,7 +78,7 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, #define TEMP_FROM_REG(val) ((val) * 1000) -#define DIV_FROM_REG(val) ( 1 << (((val) >> 6) - 1)) +#define DIV_FROM_REG(val) (1 << (((val) >> 6) - 1)) /* Registers to be checked by adm1029_update_device() */ static const u8 ADM1029_REG_TEMP[] = { @@ -200,8 +200,11 @@ static ssize_t set_fan_div(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adm1029_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - long val = simple_strtol(buf, NULL, 10); u8 reg; + long val; + int ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; mutex_lock(&data->update_lock); @@ -237,9 +240,9 @@ static ssize_t set_fan_div(struct device *dev, } /* -Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others - S_IWUSR stand for Is Writable by User -*/ + * Access rights on sysfs. S_IRUGO: Is Readable by User, Group and Others + * S_IWUSR: Is Writable by User. + */ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); @@ -300,7 +303,8 @@ static int adm1029_detect(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - /* ADM1029 doesn't have CHIP ID, check just MAN ID + /* + * ADM1029 doesn't have CHIP ID, check just MAN ID * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED, * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values * documented @@ -318,8 +322,10 @@ static int adm1029_detect(struct i2c_client *client, return -ENODEV; if ((chip_id & 0xF0) != 0x00) { - /* There are no "official" CHIP ID, so actually - * we use Major/Minor revision for that */ + /* + * There are no "official" CHIP ID, so actually + * we use Major/Minor revision for that + */ pr_info("adm1029: Unknown major revision %x, " "please let us know\n", chip_id); return -ENODEV; @@ -355,7 +361,8 @@ static int adm1029_probe(struct i2c_client *client, } /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group))) + err = sysfs_create_group(&client->dev.kobj, &adm1029_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&client->dev); @@ -403,8 +410,8 @@ static int adm1029_remove(struct i2c_client *client) } /* -function that update the status of the chips (temperature for example) -*/ + * function that update the status of the chips (temperature for example) + */ static struct adm1029_data *adm1029_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -446,24 +453,8 @@ static struct adm1029_data *adm1029_update_device(struct device *dev) return data; } -/* - Common module stuff -*/ -static int __init sensors_adm1029_init(void) -{ - - return i2c_add_driver(&adm1029_driver); -} - -static void __exit sensors_adm1029_exit(void) -{ - - i2c_del_driver(&adm1029_driver); -} +module_i2c_driver(adm1029_driver); MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>"); MODULE_DESCRIPTION("adm1029 driver"); MODULE_LICENSE("GPL v2"); - -module_init(sensors_adm1029_init); -module_exit(sensors_adm1029_exit); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 97e2cfb0bc93..ff37363ea5bc 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -1,25 +1,25 @@ /* - adm1031.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Based on lm75.c and lm85.c - Supports adm1030 / adm1031 - Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org> - Reworked by Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * adm1031.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Based on lm75.c and lm85.c + * Supports adm1030 / adm1031 + * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org> + * Reworked by Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -80,7 +80,8 @@ struct adm1031_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned int update_interval; /* In milliseconds */ - /* The chan_select_table contains the possible configurations for + /* + * The chan_select_table contains the possible configurations for * auto fan control. */ const auto_chan_table_t *chan_select_table; @@ -205,7 +206,8 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) #define GET_FAN_AUTO_BITFIELD(data, idx) \ (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2] -/* The tables below contains the possible values for the auto fan +/* + * The tables below contains the possible values for the auto fan * control bitfields. the index in the table is the register value. * MSb is the auto fan control enable bit, so the four first entries * in the table disables auto fan control when both bitfields are zero. @@ -226,7 +228,8 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = { { 3 /* 0b11 */ , 0 }, }; -/* That function checks if a bitfield is valid and returns the other bitfield +/* + * That function checks if a bitfield is valid and returns the other bitfield * nearest match if no exact match where found. */ static int @@ -252,7 +255,8 @@ get_fan_auto_nearest(struct adm1031_data *data, break; } else if (val == (*data->chan_select_table)[i][chan] && first_match == -1) { - /* Save the first match in case of an exact match has + /* + * Save the first match in case of an exact match has * not been found */ first_match = i; @@ -306,9 +310,11 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr, if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { - /* Switch to Auto Fan Mode + /* + * Switch to Auto Fan Mode * Save PWM registers - * Set PWM registers to 33% Both */ + * Set PWM registers to 33% Both + */ data->old_pwm[0] = data->pwm[0]; data->old_pwm[1] = data->pwm[1]; adm1031_write_value(client, ADM1031_REG_PWM, 0x55); @@ -1131,19 +1137,8 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) return data; } -static int __init sensors_adm1031_init(void) -{ - return i2c_add_driver(&adm1031_driver); -} - -static void __exit sensors_adm1031_exit(void) -{ - i2c_del_driver(&adm1031_driver); -} +module_i2c_driver(adm1031_driver); MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>"); MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_adm1031_init); -module_exit(sensors_adm1031_exit); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 3f63f5f9741d..c3c2865a8967 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -1,12 +1,12 @@ /* * adm9240.c Part of lm_sensors, Linux kernel modules for hardware - * monitoring + * monitoring * * Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl> * Philip Edelbrock <phil@netroedge.com> * Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl> * Copyright (C) 2005 Grant Coady <gcoady.lk@gmail.com> with valuable - * guidance from Jean Delvare + * guidance from Jean Delvare * * Driver supports Analog Devices ADM9240 * Dallas Semiconductor DS1780 @@ -204,7 +204,12 @@ static ssize_t set_max(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[attr->index] = TEMP_TO_REG(val); @@ -255,7 +260,12 @@ static ssize_t set_in_min(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[attr->index] = IN_TO_REG(val, attr->index); @@ -272,7 +282,12 @@ static ssize_t set_in_max(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[attr->index] = IN_TO_REG(val, attr->index); @@ -283,7 +298,7 @@ static ssize_t set_in_max(struct device *dev, } #define vin(nr) \ -static SENSOR_DEVICE_ATTR(in##nr##_input, S_IRUGO, \ +static SENSOR_DEVICE_ATTR(in##nr##_input, S_IRUGO, \ show_in, NULL, nr); \ static SENSOR_DEVICE_ATTR(in##nr##_min, S_IRUGO | S_IWUSR, \ show_in_min, set_in_min, nr); \ @@ -357,9 +372,14 @@ static ssize_t set_fan_min(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); int nr = attr->index; u8 new_div; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -465,7 +485,12 @@ static ssize_t set_aout(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct adm9240_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->aout = AOUT_TO_REG(val); @@ -481,7 +506,12 @@ static ssize_t chassis_clear_legacy(struct device *dev, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - unsigned long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; dev_warn(dev, "Attribute chassis_clear is deprecated, " "use intrusion0_alarm instead\n"); @@ -632,7 +662,8 @@ static int adm9240_probe(struct i2c_client *new_client, adm9240_init_client(new_client); /* populate sysfs filesystem */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group))) + err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&new_client->dev); @@ -681,8 +712,7 @@ static void adm9240_init_client(struct i2c_client *client) } else { /* cold start: open limits before starting chip */ int i; - for (i = 0; i < 6; i++) - { + for (i = 0; i < 6; i++) { i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(i), 0); i2c_smbus_write_byte_data(client, @@ -717,8 +747,7 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4)) || !data->valid) { - for (i = 0; i < 6; i++) /* read voltages */ - { + for (i = 0; i < 6; i++) { /* read voltages */ data->in[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN(i)); } @@ -727,16 +756,17 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) i2c_smbus_read_byte_data(client, ADM9240_REG_INT(1)) << 8; - /* read temperature: assume temperature changes less than + /* + * read temperature: assume temperature changes less than * 0.5'C per two measurement cycles thus ignore possible - * but unlikely aliasing error on lsb reading. --Grant */ + * but unlikely aliasing error on lsb reading. --Grant + */ data->temp = ((i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP) << 8) | i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP_CONF)) / 128; - for (i = 0; i < 2; i++) /* read fans */ - { + for (i = 0; i < 2; i++) { /* read fans */ data->fan[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN(i)); @@ -760,15 +790,13 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) if (time_after(jiffies, data->last_updated_config + (HZ * 300)) || !data->valid) { - for (i = 0; i < 6; i++) - { + for (i = 0; i < 6; i++) { data->in_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN_MIN(i)); data->in_max[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_IN_MAX(i)); } - for (i = 0; i < 2; i++) - { + for (i = 0; i < 2; i++) { data->fan_min[i] = i2c_smbus_read_byte_data(client, ADM9240_REG_FAN_MIN(i)); } @@ -795,21 +823,9 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) return data; } -static int __init sensors_adm9240_init(void) -{ - return i2c_add_driver(&adm9240_driver); -} - -static void __exit sensors_adm9240_exit(void) -{ - i2c_del_driver(&adm9240_driver); -} +module_i2c_driver(adm9240_driver); MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, " "Grant Coady <gcoady.lk@gmail.com> and others"); MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_adm9240_init); -module_exit(sensors_adm9240_exit); - diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index dd87ae96c262..7765e4f74ec5 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -305,19 +305,8 @@ static struct i2c_driver ads1015_driver = { .id_table = ads1015_id, }; -static int __init sensors_ads1015_init(void) -{ - return i2c_add_driver(&ads1015_driver); -} - -static void __exit sensors_ads1015_exit(void) -{ - i2c_del_driver(&ads1015_driver); -} +module_i2c_driver(ads1015_driver); MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>"); MODULE_DESCRIPTION("ADS1015 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_ads1015_init); -module_exit(sensors_ads1015_exit); diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index ed60242d6a0a..bf3fdf495595 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -1,27 +1,27 @@ /* - ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC - (C) 2007 EADS Astrium - - This driver is based on the lm75 and other lm_sensors/hwmon drivers - - Written by Steve Hardy <shardy@redhat.com> - - Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC + * (C) 2007 EADS Astrium + * + * This driver is based on the lm75 and other lm_sensors/hwmon drivers + * + * Written by Steve Hardy <shardy@redhat.com> + * + * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -188,12 +188,13 @@ static int ads7828_detect(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) return -ENODEV; - /* Now, we do the remaining detection. There is no identification - dedicated register so attempt to sanity check using knowledge of - the chip - - Read from the 8 channel addresses - - Check the top 4 bits of each result are not set (12 data bits) - */ + /* + * Now, we do the remaining detection. There is no identification + * dedicated register so attempt to sanity check using knowledge of + * the chip + * - Read from the 8 channel addresses + * - Check the top 4 bits of each result are not set (12 data bits) + */ for (ch = 0; ch < ADS7828_NCH; ch++) { u16 in_data; u8 cmd = channel_cmd_byte(ch); diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index 04450f8bf5da..e65c6e45d36b 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -34,9 +34,11 @@ #define REG_SER_CONTROL 24 /*Serial Interface Control Register*/ #define REG_ID 31 /*ID Register*/ -/*From figure 17 in the datasheet -* These bits get ORed with the address to form -* the instruction byte */ +/* + * From figure 17 in the datasheet + * These bits get ORed with the address to form + * the instruction byte + */ /*Instruction Bit masks*/ #define INST_MODE_bm (1<<7) #define INST_READ_bm (1<<6) @@ -105,8 +107,10 @@ static ssize_t show_voltage(struct device *dev, uint8_t channel, mux_cnv; channel = attr->index; - /*TODO: add support for conversions - *other than single ended with a gain of 1*/ + /* + * TODO: add support for conversions + * other than single ended with a gain of 1 + */ /*MUX_M3_bm forces single ended*/ /*This is also where the gain of the PGA would be set*/ ads7871_write_reg8(spi, REG_GAIN_MUX, @@ -114,8 +118,10 @@ static ssize_t show_voltage(struct device *dev, ret = ads7871_read_reg8(spi, REG_GAIN_MUX); mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv); - /*on 400MHz arm9 platform the conversion - *is already done when we do this test*/ + /* + * on 400MHz arm9 platform the conversion + * is already done when we do this test + */ while ((i < 2) && mux_cnv) { i++; ret = ads7871_read_reg8(spi, REG_GAIN_MUX); @@ -179,8 +185,10 @@ static int __devinit ads7871_probe(struct spi_device *spi) ret = ads7871_read_reg8(spi, REG_OSC_CONTROL); dev_dbg(&spi->dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret); - /*because there is no other error checking on an SPI bus - we need to make sure we really have a chip*/ + /* + * because there is no other error checking on an SPI bus + * we need to make sure we really have a chip + */ if (val != ret) { err = -ENODEV; goto exit; @@ -234,18 +242,7 @@ static struct spi_driver ads7871_driver = { .remove = __devexit_p(ads7871_remove), }; -static int __init ads7871_init(void) -{ - return spi_register_driver(&ads7871_driver); -} - -static void __exit ads7871_exit(void) -{ - spi_unregister_driver(&ads7871_driver); -} - -module_init(ads7871_init); -module_exit(ads7871_exit); +module_spi_driver(ads7871_driver); MODULE_AUTHOR("Paul Thomas <pthomas8589@gmail.com>"); MODULE_DESCRIPTION("TI ADS7871 A/D driver"); diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 5b02f7a91018..71bacc56e138 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -8,7 +8,7 @@ * published by the Free Software Foundation. * * TODO: SPI, support for external temperature sensor - * use power-down mode for suspend?, interrupt handling? + * use power-down mode for suspend?, interrupt handling? */ #include <linux/kernel.h> @@ -348,17 +348,7 @@ static struct i2c_driver adt7411_driver = { .class = I2C_CLASS_HWMON, }; -static int __init sensors_adt7411_init(void) -{ - return i2c_add_driver(&adt7411_driver); -} -module_init(sensors_adt7411_init) - -static void __exit sensors_adt7411_exit(void) -{ - i2c_del_driver(&adt7411_driver); -} -module_exit(sensors_adt7411_exit) +module_i2c_driver(adt7411_driver); MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de> and " "Wolfram Sang <w.sang@pengutronix.de>"); diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 7a1494846cfd..339269f76e57 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -65,8 +65,8 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END }; #define ADT7462_REG_PWM_TEMP_MIN_MAX_ADDR 0x5F #define ADT7462_REG_PWM_TEMP_RANGE_BASE_ADDR 0x60 #define ADT7462_REG_PWM_TEMP_RANGE_MAX_ADDR 0x63 -#define ADT7462_PWM_HYST_MASK 0x0F -#define ADT7462_PWM_RANGE_MASK 0xF0 +#define ADT7462_PWM_HYST_MASK 0x0F +#define ADT7462_PWM_RANGE_MASK 0xF0 #define ADT7462_PWM_RANGE_SHIFT 4 #define ADT7462_REG_PWM_CFG_BASE_ADDR 0x21 #define ADT7462_REG_PWM_CFG_MAX_ADDR 0x24 @@ -85,7 +85,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END }; #define ADT7462_PIN15_INPUT 0x20 #define ADT7462_PIN13_INPUT 0x40 #define ADT7462_PIN8_INPUT 0x80 -#define ADT7462_PIN23_MASK 0x03 +#define ADT7462_PIN23_MASK 0x03 #define ADT7462_PIN23_SHIFT 0 #define ADT7462_PIN26_MASK 0x0C /* cfg2 */ #define ADT7462_PIN26_SHIFT 2 @@ -99,7 +99,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END }; #define ADT7462_PIN28_VOLT 0x5 #define ADT7462_REG_ALARM1 0xB8 -#define ADT7462_LT_ALARM 0x02 +#define ADT7462_LT_ALARM 0x02 #define ADT7462_R1T_ALARM 0x04 #define ADT7462_R2T_ALARM 0x08 #define ADT7462_R3T_ALARM 0x10 @@ -135,9 +135,9 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END }; #define ADT7462_ALARM_FLAG_MASK 0x0F #define ADT7462_TEMP_COUNT 4 -#define ADT7462_TEMP_REG(x) (ADT7462_REG_TEMP_BASE_ADDR + (x * 2)) -#define ADT7462_TEMP_MIN_REG(x) (ADT7462_REG_MIN_TEMP_BASE_ADDR + (x)) -#define ADT7462_TEMP_MAX_REG(x) (ADT7462_REG_MAX_TEMP_BASE_ADDR + (x)) +#define ADT7462_TEMP_REG(x) (ADT7462_REG_TEMP_BASE_ADDR + ((x) * 2)) +#define ADT7462_TEMP_MIN_REG(x) (ADT7462_REG_MIN_TEMP_BASE_ADDR + (x)) +#define ADT7462_TEMP_MAX_REG(x) (ADT7462_REG_MAX_TEMP_BASE_ADDR + (x)) #define TEMP_FRAC_OFFSET 6 #define ADT7462_FAN_COUNT 8 @@ -1727,8 +1727,7 @@ static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, show_pwm_auto_temp, set_pwm_auto_temp, 3); -static struct attribute *adt7462_attr[] = -{ +static struct attribute *adt7462_attr[] = { &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, @@ -1975,19 +1974,8 @@ static int adt7462_remove(struct i2c_client *client) return 0; } -static int __init adt7462_init(void) -{ - return i2c_add_driver(&adt7462_driver); -} - -static void __exit adt7462_exit(void) -{ - i2c_del_driver(&adt7462_driver); -} +module_i2c_driver(adt7462_driver); MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); MODULE_DESCRIPTION("ADT7462 driver"); MODULE_LICENSE("GPL"); - -module_init(adt7462_init); -module_exit(adt7462_exit); diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 5e10c79f2dfd..54ec890521ff 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -1131,8 +1131,7 @@ static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, show_pwm_auto_temp, set_pwm_auto_temp, 3); -static struct attribute *adt7470_attr[] = -{ +static struct attribute *adt7470_attr[] = { &dev_attr_alarm_mask.attr, &dev_attr_num_temp_sensors.attr, &dev_attr_auto_update_interval.attr, @@ -1276,7 +1275,8 @@ static int adt7470_probe(struct i2c_client *client, /* Register sysfs hooks */ data->attrs.attrs = adt7470_attr; - if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) + err = sysfs_create_group(&client->dev.kobj, &data->attrs); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&client->dev); @@ -1317,19 +1317,8 @@ static int adt7470_remove(struct i2c_client *client) return 0; } -static int __init adt7470_init(void) -{ - return i2c_add_driver(&adt7470_driver); -} - -static void __exit adt7470_exit(void) -{ - i2c_del_driver(&adt7470_driver); -} +module_i2c_driver(adt7470_driver); MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); MODULE_DESCRIPTION("ADT7470 driver"); MODULE_LICENSE("GPL"); - -module_init(adt7470_init); -module_exit(adt7470_exit); diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 7dab3547fee5..df29d13a5349 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -32,9 +32,10 @@ #define THERM 5 #define HYSTERSIS 6 -/* These are unique identifiers for the sysfs functions - unlike the - numbers above, these are not also indexes into an array -*/ +/* + * These are unique identifiers for the sysfs functions - unlike the + * numbers above, these are not also indexes into an array + */ #define ALARM 9 #define FAULT 10 @@ -288,8 +289,10 @@ static void adt7475_write_word(struct i2c_client *client, int reg, u16 val) i2c_smbus_write_byte_data(client, reg, val & 0xFF); } -/* Find the nearest value in a table - used for pwm frequency and - auto temp range */ +/* + * Find the nearest value in a table - used for pwm frequency and + * auto temp range + */ static int find_nearest(long val, const int *array, int size) { int i; @@ -385,16 +388,20 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, out = (out >> 4) & 0xF; else out = (out & 0xF); - /* Show the value as an absolute number tied to - * THERM */ + /* + * Show the value as an absolute number tied to + * THERM + */ out = reg2temp(data, data->temp[THERM][sattr->index]) - out * 1000; mutex_unlock(&data->lock); break; case OFFSET: - /* Offset is always 2's complement, regardless of the - * setting in CONFIG5 */ + /* + * Offset is always 2's complement, regardless of the + * setting in CONFIG5 + */ mutex_lock(&data->lock); out = (s8)data->temp[sattr->nr][sattr->index]; if (data->config5 & CONFIG5_TEMPOFFSET) @@ -452,8 +459,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, break; case HYSTERSIS: - /* The value will be given as an absolute value, turn it - into an offset based on THERM */ + /* + * The value will be given as an absolute value, turn it + * into an offset based on THERM + */ /* Read fresh THERM and HYSTERSIS values from the chip */ data->temp[THERM][sattr->index] = @@ -478,8 +487,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, default: data->temp[sattr->nr][sattr->index] = temp2reg(data, val); - /* We maintain an extra 2 digits of precision for simplicity - * - shift those back off before writing the value */ + /* + * We maintain an extra 2 digits of precision for simplicity + * - shift those back off before writing the value + */ out = (u8) (data->temp[sattr->nr][sattr->index] >> 2); } @@ -514,8 +525,10 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, return count; } -/* Table of autorange values - the user will write the value in millidegrees, - and we'll convert it */ +/* + * Table of autorange values - the user will write the value in millidegrees, + * and we'll convert it + */ static const int autorange_table[] = { 2000, 2500, 3330, 4000, 5000, 6670, 8000, 10000, 13330, 16000, 20000, 26670, 32000, 40000, @@ -558,8 +571,10 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr, data->range[sattr->index] = adt7475_read(TEMP_TRANGE_REG(sattr->index)); - /* The user will write an absolute value, so subtract the start point - to figure the range */ + /* + * The user will write an absolute value, so subtract the start point + * to figure the range + */ temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]); val = SENSORS_LIMIT(val, temp + autorange_table[0], temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]); @@ -664,8 +679,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm[CONTROL][sattr->index] = adt7475_read(PWM_CONFIG_REG(sattr->index)); - /* If we are not in manual mode, then we shouldn't allow - * the user to set the pwm speed */ + /* + * If we are not in manual mode, then we shouldn't allow + * the user to set the pwm speed + */ if (((data->pwm[CONTROL][sattr->index] >> 5) & 7) != 7) { mutex_unlock(&data->lock); return count; @@ -1232,7 +1249,7 @@ static void adt7475_remove_files(struct i2c_client *client, static int adt7475_probe(struct i2c_client *client, const struct i2c_device_id *id) { - static const char *names[] = { + static const char * const names[] = { [adt7473] = "ADT7473", [adt7475] = "ADT7475", [adt7476] = "ADT7476", @@ -1280,9 +1297,11 @@ static int adt7475_probe(struct i2c_client *client, if ((data->config4 & CONFIG4_PINFUNC) == 0x0) data->has_fan4 = 1; - /* THERM configuration is more complex on the ADT7476 and ADT7490, - because 2 different pins (TACH4 and +2.5 Vin) can be used for - this function */ + /* + * THERM configuration is more complex on the ADT7476 and ADT7490, + * because 2 different pins (TACH4 and +2.5 Vin) can be used for + * this function + */ if (id->driver_data == adt7490) { if ((data->config4 & CONFIG4_PINFUNC) == 0x1 && !(config3 & CONFIG3_THERM)) @@ -1294,8 +1313,10 @@ static int adt7475_probe(struct i2c_client *client, data->has_voltage |= (1 << 0); /* in0 */ } - /* On the ADT7476, the +12V input pin may instead be used as VID5, - and VID pins may alternatively be used as GPIO */ + /* + * On the ADT7476, the +12V input pin may instead be used as VID5, + * and VID pins may alternatively be used as GPIO + */ if (id->driver_data == adt7476) { u8 vid = adt7475_read(REG_VID); if (!(vid & VID_VIDSEL)) @@ -1314,8 +1335,10 @@ static int adt7475_probe(struct i2c_client *client, } data->bypass_attn &= data->has_voltage; - /* Call adt7475_read_pwm for all pwm's as this will reprogram any - pwm's which are disabled to manual mode with 0% duty cycle */ + /* + * Call adt7475_read_pwm for all pwm's as this will reprogram any + * pwm's which are disabled to manual mode with 0% duty cycle + */ for (i = 0; i < ADT7475_PWM_COUNT; i++) adt7475_read_pwm(client, i); @@ -1431,8 +1454,10 @@ static void adt7475_read_pwm(struct i2c_client *client, int index) data->pwm[CONTROL][index] = adt7475_read(PWM_CONFIG_REG(index)); - /* Figure out the internal value for pwmctrl and pwmchan - based on the current settings */ + /* + * Figure out the internal value for pwmctrl and pwmchan + * based on the current settings + */ v = (data->pwm[CONTROL][index] >> 5) & 7; if (v == 3) @@ -1440,10 +1465,11 @@ static void adt7475_read_pwm(struct i2c_client *client, int index) else if (v == 7) data->pwmctl[index] = 1; else if (v == 4) { - /* The fan is disabled - we don't want to - support that, so change to manual mode and - set the duty cycle to 0 instead - */ + /* + * The fan is disabled - we don't want to + * support that, so change to manual mode and + * set the duty cycle to 0 instead + */ data->pwm[INPUT][index] = 0; data->pwm[CONTROL][index] &= ~0xE0; data->pwm[CONTROL][index] |= (7 << 5); @@ -1600,19 +1626,8 @@ static struct adt7475_data *adt7475_update_device(struct device *dev) return data; } -static int __init sensors_adt7475_init(void) -{ - return i2c_add_driver(&adt7475_driver); -} - -static void __exit sensors_adt7475_exit(void) -{ - i2c_del_driver(&adt7475_driver); -} +module_i2c_driver(adt7475_driver); MODULE_AUTHOR("Advanced Micro Devices, Inc"); MODULE_DESCRIPTION("adt7475 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_adt7475_init); -module_exit(sensors_adt7475_exit); diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 89a6b9da0ec3..f600fa1f92e3 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -1,25 +1,25 @@ /* - amc6821.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si> - - Based on max6650.c: - Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * amc6821.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si> + * + * Based on max6650.c: + * Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/kernel.h> /* Needed for KERN_INFO */ @@ -47,7 +47,7 @@ static const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e, * Insmod parameters */ -static int pwminv = 0; /*Inverted PWM output. */ +static int pwminv; /*Inverted PWM output. */ module_param(pwminv, int, S_IRUGO); static int init = 1; /*Power-on initialization.*/ @@ -188,7 +188,7 @@ static struct i2c_driver amc6821_driver = { /* * Client data (each client gets its own) - */ + */ struct amc6821_data { struct device *hwmon_dev; @@ -836,8 +836,10 @@ static int amc6821_detect( return -ENODEV; } - /* Bit 7 of the address register is ignored, so we can check the - ID registers again */ + /* + * Bit 7 of the address register is ignored, so we can check the + * ID registers again + */ dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID); comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID); if (dev_id != 0x21 || comp_id != 0x49) { @@ -1080,9 +1082,10 @@ static struct amc6821_data *amc6821_update_device(struct device *dev) data->pwm1_auto_channels_temp = 3; data->pwm1_enable = 3; break; - case 1: /*semi-open loop: software sets rpm, chip controls pwm1, - *currently not implemented - */ + case 1: /* + * semi-open loop: software sets rpm, chip controls + * pwm1, currently not implemented + */ data->pwm1_auto_channels_temp = 0; data->pwm1_enable = 0; break; @@ -1095,20 +1098,7 @@ static struct amc6821_data *amc6821_update_device(struct device *dev) return data; } - -static int __init amc6821_init(void) -{ - return i2c_add_driver(&amc6821_driver); -} - -static void __exit amc6821_exit(void) -{ - i2c_del_driver(&amc6821_driver); -} - -module_init(amc6821_init); -module_exit(amc6821_exit); - +module_i2c_driver(amc6821_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>"); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index b9895531240d..f082e48ab113 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -344,8 +344,10 @@ static int applesmc_get_lower_bound(unsigned int *lo, const char *key) while (begin != end) { int middle = begin + (end - begin) / 2; entry = applesmc_get_entry_by_index(middle); - if (IS_ERR(entry)) + if (IS_ERR(entry)) { + *lo = 0; return PTR_ERR(entry); + } if (strcmp(entry->key, key) < 0) begin = middle + 1; else @@ -364,8 +366,10 @@ static int applesmc_get_upper_bound(unsigned int *hi, const char *key) while (begin != end) { int middle = begin + (end - begin) / 2; entry = applesmc_get_entry_by_index(middle); - if (IS_ERR(entry)) + if (IS_ERR(entry)) { + *hi = smcreg.key_count; return PTR_ERR(entry); + } if (strcmp(key, entry->key) < 0) end = middle; else @@ -1189,8 +1193,10 @@ static int applesmc_dmi_match(const struct dmi_system_id *id) return 1; } -/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". - * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ +/* + * Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". + * So we need to put "Apple MacBook Pro" before "Apple MacBook". + */ static __initdata struct dmi_system_id applesmc_whitelist[] = { { applesmc_dmi_match, "Apple MacBook Air", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index d7bd1f3f2a31..4b8814deabb1 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -1,40 +1,40 @@ /* - asb100.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com> - - (derived from w83781d.c) - - Copyright (C) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, - Philip Edelbrock <phil@netroedge.com>, and - Mark Studebaker <mdsxyz123@yahoo.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * asb100.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (C) 2004 Mark M. Hoffman <mhoffman@lightlink.com> + * + * (derived from w83781d.c) + * + * Copyright (C) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, + * Philip Edelbrock <phil@netroedge.com>, and + * Mark Studebaker <mdsxyz123@yahoo.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - This driver supports the hardware sensor chips: Asus ASB100 and - ASB100-A "BACH". - - ASB100-A supports pwm1, while plain ASB100 does not. There is no known - way for the driver to tell which one is there. - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - asb100 7 3 1 4 0x31 0x0694 yes no -*/ + * This driver supports the hardware sensor chips: Asus ASB100 and + * ASB100-A "BACH". + * + * ASB100-A supports pwm1, while plain ASB100 does not. There is no known + * way for the driver to tell which one is there. + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * asb100 7 3 1 4 0x31 0x0694 yes no + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -99,15 +99,19 @@ static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; /* bit 7 -> enable, bits 0-3 -> duty cycle */ #define ASB100_REG_PWM1 0x59 -/* CONVERSIONS - Rounding and limit checking is only done on the TO_REG variants. */ +/* + * CONVERSIONS + * Rounding and limit checking is only done on the TO_REG variants. + */ /* These constants are a guess, consistent w/ w83781d */ -#define ASB100_IN_MIN ( 0) -#define ASB100_IN_MAX (4080) +#define ASB100_IN_MIN 0 +#define ASB100_IN_MAX 4080 -/* IN: 1/1000 V (0V to 4.08V) - REG: 16mV/bit */ +/* + * IN: 1/1000 V (0V to 4.08V) + * REG: 16mV/bit + */ static u8 IN_TO_REG(unsigned val) { unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); @@ -131,19 +135,21 @@ static u8 FAN_TO_REG(long rpm, int div) static int FAN_FROM_REG(u8 val, int div) { - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); + return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div); } /* These constants are a guess, consistent w/ w83781d */ -#define ASB100_TEMP_MIN (-128000) -#define ASB100_TEMP_MAX ( 127000) +#define ASB100_TEMP_MIN -128000 +#define ASB100_TEMP_MAX 127000 -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: 0.001C/bit (-128C to +127C) + * REG: 1C/bit, two's complement + */ static u8 TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); + ntemp += (ntemp < 0 ? -500 : 500); return (u8)(ntemp / 1000); } @@ -152,8 +158,10 @@ static int TEMP_FROM_REG(u8 reg) return (s8)reg * 1000; } -/* PWM: 0 - 255 per sensors documentation - REG: (6.25% duty cycle per bit) */ +/* + * PWM: 0 - 255 per sensors documentation + * REG: (6.25% duty cycle per bit) + */ static u8 ASB100_PWM_TO_REG(int pwm) { pwm = SENSORS_LIMIT(pwm, 0, 255); @@ -167,16 +175,20 @@ static int ASB100_PWM_FROM_REG(u8 reg) #define DIV_FROM_REG(val) (1 << (val)) -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +/* + * FAN DIV: 1, 2, 4, or 8 (defaults to 2) + * REG: 0, 1, 2, or 3 (respectively) (defaults to 1) + */ static u8 DIV_TO_REG(long val) { - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; + return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1; } -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, at the same time the client itself is allocated. */ +/* + * For each registered client, we need to keep some data in memory. That + * data is pointed to by client->data. The structure itself is + * dynamically allocated, at the same time the client itself is allocated. + */ struct asb100_data { struct device *hwmon_dev; struct mutex lock; @@ -253,8 +265,10 @@ static ssize_t set_in_##reg(struct device *dev, struct device_attribute *attr, \ int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ - \ + unsigned long val; \ + int err = kstrtoul(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ asb100_write_value(client, ASB100_REG_IN_##REG(nr), \ @@ -315,7 +329,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -324,10 +343,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, return count; } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -335,8 +356,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); unsigned long min; - unsigned long val = simple_strtoul(buf, NULL, 10); int reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -421,8 +447,10 @@ static ssize_t set_##reg(struct device *dev, struct device_attribute *attr, \ int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct asb100_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ switch (nr) { \ case 1: case 2: \ @@ -476,7 +504,13 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct asb100_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + data->vrm = val; return count; } @@ -524,7 +558,12 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm &= 0x80; /* keep the enable bit */ @@ -546,7 +585,12 @@ static ssize_t set_pwm_enable1(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm &= 0x0f; /* keep the duty cycle bits */ @@ -768,7 +812,8 @@ static int asb100_probe(struct i2c_client *client, data->fan_min[2] = asb100_read_value(client, ASB100_REG_FAN_MIN(2)); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &asb100_group))) + err = sysfs_create_group(&client->dev.kobj, &asb100_group); + if (err) goto ERROR3; data->hwmon_dev = hwmon_device_register(&client->dev); @@ -805,8 +850,10 @@ static int asb100_remove(struct i2c_client *client) return 0; } -/* The SMBus locks itself, usually, but nothing may access the chip between - bank switches. */ +/* + * The SMBus locks itself, usually, but nothing may access the chip between + * bank switches. + */ static int asb100_read_value(struct i2c_client *client, u16 reg) { struct asb100_data *data = i2c_get_clientdata(client); @@ -971,19 +1018,8 @@ static struct asb100_data *asb100_update_device(struct device *dev) return data; } -static int __init asb100_init(void) -{ - return i2c_add_driver(&asb100_driver); -} - -static void __exit asb100_exit(void) -{ - i2c_del_driver(&asb100_driver); -} +module_i2c_driver(asb100_driver); MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); MODULE_DESCRIPTION("ASB100 Bach driver"); MODULE_LICENSE("GPL"); - -module_init(asb100_init); -module_exit(asb100_exit); diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 3efd32449982..7caa242915a6 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -268,9 +268,11 @@ static ssize_t store_fan16(struct device *dev, if (kstrtol(buf, 10, &reqval)) return -EINVAL; - /* If a minimum RPM of zero is requested, then we set the register to - 0xffff. This value allows the fan to be stopped completely without - generating an alarm. */ + /* + * If a minimum RPM of zero is requested, then we set the register to + * 0xffff. This value allows the fan to be stopped completely without + * generating an alarm. + */ reqval = (reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe)); diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 00e98517f94c..351d1f4593e7 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -38,7 +38,8 @@ static const struct dmi_system_id __initconst atk_force_new_if[] = { { } }; -/* Minimum time between readings, enforced in order to avoid +/* + * Minimum time between readings, enforced in order to avoid * hogging the CPU. */ #define CACHE_TIME HZ @@ -161,7 +162,8 @@ struct atk_sensor_data { char const *acpi_name; }; -/* Return buffer format: +/* + * Return buffer format: * [0-3] "value" is valid flag * [4-7] value * [8- ] unknown stuff on newer mobos @@ -310,7 +312,8 @@ static union acpi_object *atk_get_pack_member(struct atk_data *data, } -/* New package format is: +/* + * New package format is: * - flag (int) * class - used for de-muxing the request to the correct GITn * type (volt, temp, fan) @@ -613,7 +616,8 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; if (buf->flags == 0) { - /* The reading is not valid, possible causes: + /* + * The reading is not valid, possible causes: * - sensor failure * - enumeration was FUBAR (and we didn't notice) */ @@ -1311,14 +1315,16 @@ static int atk_probe_if(struct atk_data *data) dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n", acpi_format_exception(status)); - /* Check for hwmon methods: first check "old" style methods; note that + /* + * Check for hwmon methods: first check "old" style methods; note that * both may be present: in this case we stick to the old interface; * analysis of multiple DSDTs indicates that when both interfaces * are present the new one (GGRP/GITM) is not functional. */ if (new_if) dev_info(dev, "Overriding interface detection\n"); - if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if) + if (data->rtmp_handle && + data->rvlt_handle && data->rfan_handle && !new_if) data->old_interface = true; else if (data->enumerate_handle && data->read_handle && data->write_handle) diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 33cc143b2069..58af6aa93530 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -1,22 +1,22 @@ /* - atxp1.c - kernel module for setting CPU VID and general purpose - I/Os using the Attansic ATXP1 chip. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * atxp1.c - kernel module for setting CPU VID and general purpose + * I/Os using the Attansic ATXP1 chip. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ #include <linux/kernel.h> #include <linux/init.h> @@ -48,7 +48,7 @@ static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; static int atxp1_probe(struct i2c_client *client, const struct i2c_device_id *id); static int atxp1_remove(struct i2c_client *client); -static struct atxp1_data * atxp1_update_device(struct device *dev); +static struct atxp1_data *atxp1_update_device(struct device *dev); static int atxp1_detect(struct i2c_client *client, struct i2c_board_info *info); static const struct i2c_device_id atxp1_id[] = { @@ -83,7 +83,7 @@ struct atxp1_data { u8 vrm; /* Detected CPU VRM */ }; -static struct atxp1_data * atxp1_update_device(struct device *dev) +static struct atxp1_data *atxp1_update_device(struct device *dev) { struct i2c_client *client; struct atxp1_data *data; @@ -97,7 +97,8 @@ static struct atxp1_data * atxp1_update_device(struct device *dev) /* Update local register data */ data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); - data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID); + data->reg.cpu_vid = i2c_smbus_read_byte_data(client, + ATXP1_CVID); data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); @@ -106,33 +107,41 @@ static struct atxp1_data * atxp1_update_device(struct device *dev) mutex_unlock(&data->update_lock); - return(data); + return data; } /* sys file functions for cpu0_vid */ -static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t atxp1_showvcore(struct device *dev, + struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; data = atxp1_update_device(dev); - size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm)); + size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, + data->vrm)); return size; } -static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t atxp1_storevcore(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct atxp1_data *data; struct i2c_client *client; int vid, cvid; - unsigned int vcore; + unsigned long vcore; + int err; client = to_i2c_client(dev); data = atxp1_update_device(dev); - vcore = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &vcore); + if (err) + return err; + vcore /= 25; vcore *= 25; @@ -144,7 +153,10 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att return -1; } - /* If output enabled, use control register value. Otherwise original CPU VID */ + /* + * If output enabled, use control register value. + * Otherwise original CPU VID + */ if (data->reg.vid & ATXP1_VIDENA) cvid = data->reg.vid & ATXP1_VIDMASK; else @@ -154,18 +166,17 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att if (vid == cvid) return count; - dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid); + dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid); /* Write every 25 mV step to increase stability */ if (cvid > vid) { - for (; cvid >= vid; cvid--) { - i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); - } - } - else { - for (; cvid <= vid; cvid++) { - i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA); - } + for (; cvid >= vid; cvid--) + i2c_smbus_write_byte_data(client, + ATXP1_VID, cvid | ATXP1_VIDENA); + } else { + for (; cvid <= vid; cvid++) + i2c_smbus_write_byte_data(client, + ATXP1_VID, cvid | ATXP1_VIDENA); } data->valid = 0; @@ -173,13 +184,16 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att return count; } -/* CPU core reference voltage - unit: millivolt -*/ -static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore); +/* + * CPU core reference voltage + * unit: millivolt + */ +static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, + atxp1_storevcore); /* sys file functions for GPIO1 */ -static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t atxp1_showgpio1(struct device *dev, + struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; @@ -191,21 +205,26 @@ static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr return size; } -static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count) +static ssize_t atxp1_storegpio1(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct atxp1_data *data; struct i2c_client *client; - unsigned int value; + unsigned long value; + int err; client = to_i2c_client(dev); data = atxp1_update_device(dev); - value = simple_strtoul(buf, NULL, 16); + err = kstrtoul(buf, 16, &value); + if (err) + return err; value &= ATXP1_GPIO1MASK; if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { - dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value); i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); @@ -215,13 +234,15 @@ static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *att return count; } -/* GPIO1 data register - unit: Four bit as hex (e.g. 0x0f) -*/ +/* + * GPIO1 data register + * unit: Four bit as hex (e.g. 0x0f) + */ static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); /* sys file functions for GPIO2 */ -static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t atxp1_showgpio2(struct device *dev, + struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; @@ -233,19 +254,22 @@ static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr return size; } -static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t atxp1_storegpio2(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct atxp1_data *data; - struct i2c_client *client; - unsigned int value; - - client = to_i2c_client(dev); - data = atxp1_update_device(dev); + struct atxp1_data *data = atxp1_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + unsigned long value; + int err; - value = simple_strtoul(buf, NULL, 16) & 0xff; + err = kstrtoul(buf, 16, &value); + if (err) + return err; + value &= 0xff; if (value != data->reg.gpio2) { - dev_info(dev, "Writing 0x%x to GPIO1.\n", value); + dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value); i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); @@ -255,9 +279,10 @@ static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *att return count; } -/* GPIO2 data register - unit: Eight bit as hex (e.g. 0xff) -*/ +/* + * GPIO2 data register + * unit: Eight bit as hex (e.g. 0xff) + */ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); static struct attribute *atxp1_attributes[] = { @@ -290,8 +315,10 @@ static int atxp1_detect(struct i2c_client *new_client, (i2c_smbus_read_byte_data(new_client, 0xff) == 0))) return -ENODEV; - /* No vendor ID, now checking if registers 0x10,0x11 (non-existent) - * showing the same as register 0x00 */ + /* + * No vendor ID, now checking if registers 0x10,0x11 (non-existent) + * showing the same as register 0x00 + */ temp = i2c_smbus_read_byte_data(new_client, 0x00); if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && @@ -333,7 +360,8 @@ static int atxp1_probe(struct i2c_client *new_client, mutex_init(&data->update_lock); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group))) + err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&new_client->dev); @@ -357,7 +385,7 @@ exit: static int atxp1_remove(struct i2c_client *client) { - struct atxp1_data * data = i2c_get_clientdata(client); + struct atxp1_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &atxp1_group); @@ -367,15 +395,4 @@ static int atxp1_remove(struct i2c_client *client) return 0; }; -static int __init atxp1_init(void) -{ - return i2c_add_driver(&atxp1_driver); -}; - -static void __exit atxp1_exit(void) -{ - i2c_del_driver(&atxp1_driver); -}; - -module_init(atxp1_init); -module_exit(atxp1_exit); +module_i2c_driver(atxp1_driver); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 249ac460e3d9..0d3141fbbc20 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -58,8 +58,8 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) -#define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id -#define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id +#define TO_PHYS_ID(cpu) (cpu_data(cpu).phys_proc_id) +#define TO_CORE_ID(cpu) (cpu_data(cpu).cpu_core_id) #define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) #ifdef CONFIG_SMP diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index ffb229af7861..e7c6a19f3b25 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -82,12 +82,12 @@ enum chips { dme1737, sch5027, sch311x, sch5127 }; * --------------------------------------------------------------------- */ /* Voltages (in) numbered 0-7 (ix) */ -#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) : \ +#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) : \ (ix) < 7 ? 0x94 + (ix) : \ 0x1f) -#define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \ +#define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \ : 0x91 + (ix) * 2) -#define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \ +#define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \ : 0x92 + (ix) * 2) /* Temperatures (temp) numbered 0-2 (ix) */ @@ -97,14 +97,16 @@ enum chips { dme1737, sch5027, sch311x, sch5127 }; #define DME1737_REG_TEMP_OFFSET(ix) ((ix) == 0 ? 0x1f \ : 0x1c + (ix)) -/* Voltage and temperature LSBs +/* + * Voltage and temperature LSBs * The LSBs (4 bits each) are stored in 5 registers with the following layouts: * IN_TEMP_LSB(0) = [in5, in6] * IN_TEMP_LSB(1) = [temp3, temp1] * IN_TEMP_LSB(2) = [in4, temp2] * IN_TEMP_LSB(3) = [in3, in0] * IN_TEMP_LSB(4) = [in2, in1] - * IN_TEMP_LSB(5) = [res, in7] */ + * IN_TEMP_LSB(5) = [res, in7] + */ #define DME1737_REG_IN_TEMP_LSB(ix) (0x84 + (ix)) static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5}; static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4}; @@ -127,24 +129,30 @@ static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0}; #define DME1737_REG_PWM_MIN(ix) (0x64 + (ix)) /* only for pwm[0-2] */ #define DME1737_REG_PWM_FREQ(ix) ((ix) < 3 ? 0x5f + (ix) \ : 0xa3 + (ix)) -/* The layout of the ramp rate registers is different from the other pwm +/* + * The layout of the ramp rate registers is different from the other pwm * registers. The bits for the 3 PWMs are stored in 2 registers: * PWM_RR(0) = [OFF3, OFF2, OFF1, RES, RR1E, RR1-2, RR1-1, RR1-0] - * PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] */ + * PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] + */ #define DME1737_REG_PWM_RR(ix) (0x62 + (ix)) /* only for pwm[0-2] */ /* Thermal zones 0-2 */ #define DME1737_REG_ZONE_LOW(ix) (0x67 + (ix)) #define DME1737_REG_ZONE_ABS(ix) (0x6a + (ix)) -/* The layout of the hysteresis registers is different from the other zone +/* + * The layout of the hysteresis registers is different from the other zone * registers. The bits for the 3 zones are stored in 2 registers: * ZONE_HYST(0) = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0] - * ZONE_HYST(1) = [H3-3, H3-2, H3-1, H3-0, RES, RES, RES, RES] */ + * ZONE_HYST(1) = [H3-3, H3-2, H3-1, H3-0, RES, RES, RES, RES] + */ #define DME1737_REG_ZONE_HYST(ix) (0x6d + (ix)) -/* Alarm registers and bit mapping +/* + * Alarm registers and bit mapping * The 3 8-bit alarm registers will be concatenated to a single 32-bit - * alarm value [0, ALARM3, ALARM2, ALARM1]. */ + * alarm value [0, ALARM3, ALARM2, ALARM1]. + */ #define DME1737_REG_ALARM1 0x41 #define DME1737_REG_ALARM2 0x42 #define DME1737_REG_ALARM3 0x83 @@ -257,9 +265,11 @@ static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300, (type) == sch5127 ? IN_NOMINAL_SCH5127 : \ IN_NOMINAL_DME1737) -/* Voltage input +/* + * Voltage input * Voltage inputs have 16 bits resolution, limit values have 8 bits - * resolution. */ + * resolution. + */ static inline int IN_FROM_REG(int reg, int nominal, int res) { return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2)); @@ -270,10 +280,12 @@ static inline int IN_TO_REG(int val, int nominal) return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255); } -/* Temperature input +/* + * Temperature input * The register values represent temperatures in 2's complement notation from * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit - * values have 8 bits resolution. */ + * values have 8 bits resolution. + */ static inline int TEMP_FROM_REG(int reg, int res) { return (reg * 1000) >> (res - 8); @@ -300,18 +312,19 @@ static int TEMP_RANGE_TO_REG(int val, int reg) int i; for (i = 15; i > 0; i--) { - if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) { + if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) break; - } } return (reg & 0x0f) | (i << 4); } -/* Temperature hysteresis +/* + * Temperature hysteresis * Register layout: * reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0] - * reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] */ + * reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] + */ static inline int TEMP_HYST_FROM_REG(int reg, int ix) { return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000; @@ -327,11 +340,10 @@ static inline int TEMP_HYST_TO_REG(int val, int ix, int reg) /* Fan input RPM */ static inline int FAN_FROM_REG(int reg, int tpc) { - if (tpc) { + if (tpc) return tpc * reg; - } else { + else return (reg == 0 || reg == 0xffff) ? 0 : 90000 * 60 / reg; - } } static inline int FAN_TO_REG(int val, int tpc) @@ -344,17 +356,21 @@ static inline int FAN_TO_REG(int val, int tpc) } } -/* Fan TPC (tach pulse count) +/* + * Fan TPC (tach pulse count) * Converts a register value to a TPC multiplier or returns 0 if the tachometer - * is configured in legacy (non-tpc) mode */ + * is configured in legacy (non-tpc) mode + */ static inline int FAN_TPC_FROM_REG(int reg) { return (reg & 0x20) ? 0 : 60 >> (reg & 0x03); } -/* Fan type +/* + * Fan type * The type of a fan is expressed in number of pulses-per-revolution that it - * emits */ + * emits + */ static inline int FAN_TYPE_FROM_REG(int reg) { int edge = (reg >> 1) & 0x03; @@ -378,9 +394,8 @@ static int FAN_MAX_FROM_REG(int reg) int i; for (i = 10; i > 0; i--) { - if (reg == FAN_MAX[i]) { + if (reg == FAN_MAX[i]) break; - } } return 1000 + i * 500; @@ -391,15 +406,15 @@ static int FAN_MAX_TO_REG(int val) int i; for (i = 10; i > 0; i--) { - if (val > (1000 + (i - 1) * 500)) { + if (val > (1000 + (i - 1) * 500)) break; - } } return FAN_MAX[i]; } -/* PWM enable +/* + * PWM enable * Register to enable mapping: * 000: 2 fan on zone 1 auto * 001: 2 fan on zone 2 auto @@ -408,7 +423,8 @@ static int FAN_MAX_TO_REG(int val) * 100: -1 fan disabled * 101: 2 fan on hottest of zones 2,3 auto * 110: 2 fan on hottest of zones 1,2,3 auto - * 111: 1 fan in manual mode */ + * 111: 1 fan in manual mode + */ static inline int PWM_EN_FROM_REG(int reg) { static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1}; @@ -423,7 +439,8 @@ static inline int PWM_EN_TO_REG(int val, int reg) return (reg & 0x1f) | ((en & 0x07) << 5); } -/* PWM auto channels zone +/* + * PWM auto channels zone * Register to auto channels zone mapping (ACZ is a bitfield with bit x * corresponding to zone x+1): * 000: 001 fan on zone 1 auto @@ -433,7 +450,8 @@ static inline int PWM_EN_TO_REG(int val, int reg) * 100: 000 fan disabled * 101: 110 fan on hottest of zones 2,3 auto * 110: 111 fan on hottest of zones 1,2,3 auto - * 111: 000 fan in manual mode */ + * 111: 000 fan in manual mode + */ static inline int PWM_ACZ_FROM_REG(int reg) { static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0}; @@ -468,19 +486,20 @@ static int PWM_FREQ_TO_REG(int val, int reg) i = 11; } else { for (i = 9; i > 0; i--) { - if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) { + if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) break; - } } } return (reg & 0xf0) | i; } -/* PWM ramp rate +/* + * PWM ramp rate * Register layout: * reg[0] = [OFF3, OFF2, OFF1, RES, RR1-E, RR1-2, RR1-1, RR1-0] - * reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] */ + * reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] + */ static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5}; static inline int PWM_RR_FROM_REG(int reg, int ix) @@ -495,9 +514,8 @@ static int PWM_RR_TO_REG(int val, int ix, int reg) int i; for (i = 0; i < 7; i++) { - if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) { + if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) break; - } } return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i; @@ -516,9 +534,11 @@ static inline int PWM_RR_EN_TO_REG(int val, int ix, int reg) return val ? reg | en : reg & ~en; } -/* PWM min/off +/* + * PWM min/off * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for - * the register layout). */ + * the register layout). + */ static inline int PWM_OFF_FROM_REG(int reg, int ix) { return (reg >> (ix + 5)) & 0x01; @@ -604,12 +624,13 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* In (voltage) registers */ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { - /* Voltage inputs are stored as 16 bit values even + /* + * Voltage inputs are stored as 16 bit values even * though they have only 12 bits resolution. This is - * to make it consistent with the temp inputs. */ - if (ix == 7 && !(data->has_features & HAS_IN7)) { + * to make it consistent with the temp inputs. + */ + if (ix == 7 && !(data->has_features & HAS_IN7)) continue; - } data->in[ix] = dme1737_read(data, DME1737_REG_IN(ix)) << 8; data->in_min[ix] = dme1737_read(data, @@ -620,11 +641,13 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* Temp registers */ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) { - /* Temp inputs are stored as 16 bit values even + /* + * Temp inputs are stored as 16 bit values even * though they have only 12 bits resolution. This is * to take advantage of implicit conversions between * register values (2's complement) and temp values - * (signed decimal). */ + * (signed decimal). + */ data->temp[ix] = dme1737_read(data, DME1737_REG_TEMP(ix)) << 8; data->temp_min[ix] = dme1737_read(data, @@ -637,21 +660,21 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) } } - /* In and temp LSB registers + /* + * In and temp LSB registers * The LSBs are latched when the MSBs are read, so the order in * which the registers are read (MSB first, then LSB) is - * important! */ + * important! + */ for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) { - if (ix == 5 && !(data->has_features & HAS_IN7)) { + if (ix == 5 && !(data->has_features & HAS_IN7)) continue; - } lsb[ix] = dme1737_read(data, DME1737_REG_IN_TEMP_LSB(ix)); } for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { - if (ix == 7 && !(data->has_features & HAS_IN7)) { + if (ix == 7 && !(data->has_features & HAS_IN7)) continue; - } data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] << DME1737_REG_IN_LSB_SHL[ix]) & 0xf0; } @@ -662,11 +685,12 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* Fan registers */ for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) { - /* Skip reading registers if optional fans are not - * present */ - if (!(data->has_features & HAS_FAN(ix))) { + /* + * Skip reading registers if optional fans are not + * present + */ + if (!(data->has_features & HAS_FAN(ix))) continue; - } data->fan[ix] = dme1737_read(data, DME1737_REG_FAN(ix)); data->fan[ix] |= dme1737_read(data, @@ -686,11 +710,12 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* PWM registers */ for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) { - /* Skip reading registers if optional PWMs are not - * present */ - if (!(data->has_features & HAS_PWM(ix))) { + /* + * Skip reading registers if optional PWMs are not + * present + */ + if (!(data->has_features & HAS_PWM(ix))) continue; - } data->pwm[ix] = dme1737_read(data, DME1737_REG_PWM(ix)); data->pwm_freq[ix] = dme1737_read(data, @@ -711,9 +736,8 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* Thermal zone registers */ for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) { /* Skip reading registers if zone3 is not present */ - if ((ix == 2) && !(data->has_features & HAS_ZONE3)) { + if ((ix == 2) && !(data->has_features & HAS_ZONE3)) continue; - } /* sch5127 zone2 registers are special */ if ((ix == 1) && (data->type == sch5127)) { data->zone_low[1] = dme1737_read(data, @@ -737,8 +761,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* Alarm registers */ data->alarms = dme1737_read(data, DME1737_REG_ALARM1); - /* Bit 7 tells us if the other alarm registers are non-zero and - * therefore also need to be read */ + /* + * Bit 7 tells us if the other alarm registers are non-zero and + * therefore also need to be read + */ if (data->alarms & 0x80) { data->alarms |= dme1737_read(data, DME1737_REG_ALARM2) << 8; @@ -746,22 +772,18 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) DME1737_REG_ALARM3) << 16; } - /* The ISA chips require explicit clearing of alarm bits. + /* + * The ISA chips require explicit clearing of alarm bits. * Don't worry, an alarm will come back if the condition - * that causes it still exists */ + * that causes it still exists + */ if (!data->client) { - if (data->alarms & 0xff0000) { - dme1737_write(data, DME1737_REG_ALARM3, - 0xff); - } - if (data->alarms & 0xff00) { - dme1737_write(data, DME1737_REG_ALARM2, - 0xff); - } - if (data->alarms & 0xff) { - dme1737_write(data, DME1737_REG_ALARM1, - 0xff); - } + if (data->alarms & 0xff0000) + dme1737_write(data, DME1737_REG_ALARM3, 0xff); + if (data->alarms & 0xff00) + dme1737_write(data, DME1737_REG_ALARM2, 0xff); + if (data->alarms & 0xff) + dme1737_write(data, DME1737_REG_ALARM1, 0xff); } data->last_update = jiffies; @@ -822,7 +844,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -901,7 +928,12 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -952,11 +984,10 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr, switch (fn) { case SYS_ZONE_AUTO_CHANNELS_TEMP: /* check config2 for non-standard temp-to-zone mapping */ - if ((ix == 1) && (data->config2 & 0x02)) { + if ((ix == 1) && (data->config2 & 0x02)) res = 4; - } else { + else res = 1 << ix; - } break; case SYS_ZONE_AUTO_POINT1_TEMP_HYST: res = TEMP_FROM_REG(data->zone_low[ix], 8) - @@ -989,7 +1020,12 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -1014,8 +1050,10 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, /* Refresh the cache */ data->zone_low[ix] = dme1737_read(data, DME1737_REG_ZONE_LOW(ix)); - /* Modify the temp range value (which is stored in the upper - * nibble of the pwm_freq register) */ + /* + * Modify the temp range value (which is stored in the upper + * nibble of the pwm_freq register) + */ data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val - TEMP_FROM_REG(data->zone_low[ix], 8), dme1737_read(data, @@ -1095,7 +1133,12 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -1170,21 +1213,19 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, switch (fn) { case SYS_PWM: - if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) { + if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) res = 255; - } else { + else res = data->pwm[ix]; - } break; case SYS_PWM_FREQ: res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]); break; case SYS_PWM_ENABLE: - if (ix >= 3) { + if (ix >= 3) res = 1; /* pwm[5-6] hard-wired to manual mode */ - } else { + else res = PWM_EN_FROM_REG(data->pwm_config[ix]); - } break; case SYS_PWM_RAMP_RATE: /* Only valid for pwm[1-3] */ @@ -1192,19 +1233,17 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, break; case SYS_PWM_AUTO_CHANNELS_ZONE: /* Only valid for pwm[1-3] */ - if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) { + if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) res = PWM_ACZ_FROM_REG(data->pwm_config[ix]); - } else { + else res = data->pwm_acz[ix]; - } break; case SYS_PWM_AUTO_PWM_MIN: /* Only valid for pwm[1-3] */ - if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) { + if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) res = data->pwm_min[ix]; - } else { + else res = 0; - } break; case SYS_PWM_AUTO_POINT1_PWM: /* Only valid for pwm[1-3] */ @@ -1233,7 +1272,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -1307,8 +1351,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, /* Change permissions of pwm[ix] to read-only */ dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix], S_IRUGO); - /* Turn on auto mode using the saved zone channel - * assignment */ + /* + * Turn on auto mode using the saved zone channel + * assignment + */ data->pwm_config[ix] = PWM_ACZ_TO_REG( data->pwm_acz[ix], data->pwm_config[ix]); @@ -1338,8 +1384,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix, data->pwm_rr[ix > 0]); } - /* Enable/disable the feature only if the associated PWM - * output is in automatic mode. */ + /* + * Enable/disable the feature only if the associated PWM + * output is in automatic mode. + */ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) { data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix, data->pwm_rr[ix > 0]); @@ -1361,15 +1409,19 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_config[ix] = dme1737_read(data, DME1737_REG_PWM_CONFIG(ix)); if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) { - /* PWM is already in auto mode so update the temp - * channel assignment */ + /* + * PWM is already in auto mode so update the temp + * channel assignment + */ data->pwm_config[ix] = PWM_ACZ_TO_REG(val, data->pwm_config[ix]); dme1737_write(data, DME1737_REG_PWM_CONFIG(ix), data->pwm_config[ix]); } else { - /* PWM is not in auto mode so we save the temp - * channel assignment for later use */ + /* + * PWM is not in auto mode so we save the temp + * channel assignment for later use + */ data->pwm_acz[ix] = val; } break; @@ -1378,10 +1430,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, /* Refresh the cache */ data->pwm_min[ix] = dme1737_read(data, DME1737_REG_PWM_MIN(ix)); - /* There are only 2 values supported for the auto_pwm_min + /* + * There are only 2 values supported for the auto_pwm_min * value: 0 or auto_point1_pwm. So if the temperature drops * below the auto_point1_temp_hyst value, the fan either turns - * off or runs at auto_point1_pwm duty-cycle. */ + * off or runs at auto_point1_pwm duty-cycle. + */ if (val > ((data->pwm_min[ix] + 1) / 2)) { data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix, dme1737_read(data, @@ -1426,7 +1480,12 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct dme1737_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; data->vrm = val; return count; @@ -1586,10 +1645,12 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ -/* This struct holds all the attributes that are always present and need to be +/* + * This struct holds all the attributes that are always present and need to be * created unconditionally. The attributes that need modification of their * permissions are created read-only and write permissions are added or removed - * on the fly when required */ + * on the fly when required + */ static struct attribute *dme1737_attr[] = { /* Voltages */ &sensor_dev_attr_in0_input.dev_attr.attr, @@ -1652,9 +1713,11 @@ static const struct attribute_group dme1737_group = { .attrs = dme1737_attr, }; -/* The following struct holds temp offset attributes, which are not available +/* + * The following struct holds temp offset attributes, which are not available * in all chips. The following chips support them: - * DME1737, SCH311x */ + * DME1737, SCH311x + */ static struct attribute *dme1737_temp_offset_attr[] = { &sensor_dev_attr_temp1_offset.dev_attr.attr, &sensor_dev_attr_temp2_offset.dev_attr.attr, @@ -1666,9 +1729,11 @@ static const struct attribute_group dme1737_temp_offset_group = { .attrs = dme1737_temp_offset_attr, }; -/* The following struct holds VID related attributes, which are not available +/* + * The following struct holds VID related attributes, which are not available * in all chips. The following chips support them: - * DME1737 */ + * DME1737 + */ static struct attribute *dme1737_vid_attr[] = { &dev_attr_vrm.attr, &dev_attr_cpu0_vid.attr, @@ -1679,9 +1744,11 @@ static const struct attribute_group dme1737_vid_group = { .attrs = dme1737_vid_attr, }; -/* The following struct holds temp zone 3 related attributes, which are not +/* + * The following struct holds temp zone 3 related attributes, which are not * available in all chips. The following chips support them: - * DME1737, SCH311x, SCH5027 */ + * DME1737, SCH311x, SCH5027 + */ static struct attribute *dme1737_zone3_attr[] = { &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, @@ -1695,9 +1762,11 @@ static const struct attribute_group dme1737_zone3_group = { }; -/* The following struct holds temp zone hysteresis related attributes, which +/* + * The following struct holds temp zone hysteresis related attributes, which * are not available in all chips. The following chips support them: - * DME1737, SCH311x */ + * DME1737, SCH311x + */ static struct attribute *dme1737_zone_hyst_attr[] = { &sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr, &sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr, @@ -1709,9 +1778,11 @@ static const struct attribute_group dme1737_zone_hyst_group = { .attrs = dme1737_zone_hyst_attr, }; -/* The following struct holds voltage in7 related attributes, which +/* + * The following struct holds voltage in7 related attributes, which * are not available in all chips. The following chips support them: - * SCH5127 */ + * SCH5127 + */ static struct attribute *dme1737_in7_attr[] = { &sensor_dev_attr_in7_input.dev_attr.attr, &sensor_dev_attr_in7_min.dev_attr.attr, @@ -1724,9 +1795,11 @@ static const struct attribute_group dme1737_in7_group = { .attrs = dme1737_in7_attr, }; -/* The following structs hold the PWM attributes, some of which are optional. +/* + * The following structs hold the PWM attributes, some of which are optional. * Their creation depends on the chip configuration which is determined during - * module load. */ + * module load. + */ static struct attribute *dme1737_pwm1_attr[] = { &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_freq.dev_attr.attr, @@ -1779,18 +1852,22 @@ static const struct attribute_group dme1737_pwm_group[] = { { .attrs = dme1737_pwm6_attr }, }; -/* The following struct holds auto PWM min attributes, which are not available +/* + * The following struct holds auto PWM min attributes, which are not available * in all chips. Their creation depends on the chip type which is determined - * during module load. */ + * during module load. + */ static struct attribute *dme1737_auto_pwm_min_attr[] = { &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, }; -/* The following structs hold the fan attributes, some of which are optional. +/* + * The following structs hold the fan attributes, some of which are optional. * Their creation depends on the chip configuration which is determined during - * module load. */ + * module load. + */ static struct attribute *dme1737_fan1_attr[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -1843,8 +1920,10 @@ static const struct attribute_group dme1737_fan_group[] = { { .attrs = dme1737_fan6_attr }, }; -/* The permissions of the following zone attributes are changed to read- - * writeable if the chip is *not* locked. Otherwise they stay read-only. */ +/* + * The permissions of the following zone attributes are changed to read- + * writeable if the chip is *not* locked. Otherwise they stay read-only. + */ static struct attribute *dme1737_zone_chmod_attr[] = { &sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr, &sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr, @@ -1860,8 +1939,10 @@ static const struct attribute_group dme1737_zone_chmod_group = { }; -/* The permissions of the following zone 3 attributes are changed to read- - * writeable if the chip is *not* locked. Otherwise they stay read-only. */ +/* + * The permissions of the following zone 3 attributes are changed to read- + * writeable if the chip is *not* locked. Otherwise they stay read-only. + */ static struct attribute *dme1737_zone3_chmod_attr[] = { &sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr, &sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr, @@ -1873,9 +1954,11 @@ static const struct attribute_group dme1737_zone3_chmod_group = { .attrs = dme1737_zone3_chmod_attr, }; -/* The permissions of the following PWM attributes are changed to read- +/* + * The permissions of the following PWM attributes are changed to read- * writeable if the chip is *not* locked and the respective PWM is available. - * Otherwise they stay read-only. */ + * Otherwise they stay read-only. + */ static struct attribute *dme1737_pwm1_chmod_attr[] = { &sensor_dev_attr_pwm1_freq.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr, @@ -1920,8 +2003,10 @@ static const struct attribute_group dme1737_pwm_chmod_group[] = { { .attrs = dme1737_pwm6_chmod_attr }, }; -/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the - * chip is not locked. Otherwise they are read-only. */ +/* + * Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the + * chip is not locked. Otherwise they are read-only. + */ static struct attribute *dme1737_pwm_chmod_attr[] = { &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, @@ -1975,9 +2060,8 @@ static void dme1737_chmod_group(struct device *dev, { struct attribute **attr; - for (attr = group->attrs; *attr; attr++) { + for (attr = group->attrs; *attr; attr++) dme1737_chmod_file(dev, *attr, mode); - } } static void dme1737_remove_files(struct device *dev) @@ -2003,26 +2087,20 @@ static void dme1737_remove_files(struct device *dev) } } - if (data->has_features & HAS_TEMP_OFFSET) { + if (data->has_features & HAS_TEMP_OFFSET) sysfs_remove_group(&dev->kobj, &dme1737_temp_offset_group); - } - if (data->has_features & HAS_VID) { + if (data->has_features & HAS_VID) sysfs_remove_group(&dev->kobj, &dme1737_vid_group); - } - if (data->has_features & HAS_ZONE3) { + if (data->has_features & HAS_ZONE3) sysfs_remove_group(&dev->kobj, &dme1737_zone3_group); - } - if (data->has_features & HAS_ZONE_HYST) { + if (data->has_features & HAS_ZONE_HYST) sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group); - } - if (data->has_features & HAS_IN7) { + if (data->has_features & HAS_IN7) sysfs_remove_group(&dev->kobj, &dme1737_in7_group); - } sysfs_remove_group(&dev->kobj, &dme1737_group); - if (!data->client) { + if (!data->client) sysfs_remove_file(&dev->kobj, &dev_attr_name.attr); - } } static int dme1737_create_files(struct device *dev) @@ -2033,48 +2111,41 @@ static int dme1737_create_files(struct device *dev) /* Create a name attribute for ISA devices */ if (!data->client) { err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr); - if (err) { + if (err) goto exit; - } } /* Create standard sysfs attributes */ err = sysfs_create_group(&dev->kobj, &dme1737_group); - if (err) { + if (err) goto exit_remove; - } /* Create chip-dependent sysfs attributes */ if (data->has_features & HAS_TEMP_OFFSET) { err = sysfs_create_group(&dev->kobj, &dme1737_temp_offset_group); - if (err) { + if (err) goto exit_remove; - } } if (data->has_features & HAS_VID) { err = sysfs_create_group(&dev->kobj, &dme1737_vid_group); - if (err) { + if (err) goto exit_remove; - } } if (data->has_features & HAS_ZONE3) { err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group); - if (err) { + if (err) goto exit_remove; - } } if (data->has_features & HAS_ZONE_HYST) { err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group); - if (err) { + if (err) goto exit_remove; - } } if (data->has_features & HAS_IN7) { err = sysfs_create_group(&dev->kobj, &dme1737_in7_group); - if (err) { + if (err) goto exit_remove; - } } /* Create fan sysfs attributes */ @@ -2082,9 +2153,8 @@ static int dme1737_create_files(struct device *dev) if (data->has_features & HAS_FAN(ix)) { err = sysfs_create_group(&dev->kobj, &dme1737_fan_group[ix]); - if (err) { + if (err) goto exit_remove; - } } } @@ -2093,21 +2163,21 @@ static int dme1737_create_files(struct device *dev) if (data->has_features & HAS_PWM(ix)) { err = sysfs_create_group(&dev->kobj, &dme1737_pwm_group[ix]); - if (err) { + if (err) goto exit_remove; - } if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) { err = sysfs_create_file(&dev->kobj, dme1737_auto_pwm_min_attr[ix]); - if (err) { + if (err) goto exit_remove; - } } } } - /* Inform if the device is locked. Otherwise change the permissions of - * selected attributes from read-only to read-writeable. */ + /* + * Inform if the device is locked. Otherwise change the permissions of + * selected attributes from read-only to read-writeable. + */ if (data->config & 0x02) { dev_info(dev, "Device is locked. Some attributes " "will be read-only.\n"); @@ -2194,26 +2264,30 @@ static int dme1737_init_device(struct device *dev) return -EFAULT; } - /* Determine which optional fan and pwm features are enabled (only - * valid for I2C devices) */ + /* + * Determine which optional fan and pwm features are enabled (only + * valid for I2C devices) + */ if (client) { /* I2C chip */ data->config2 = dme1737_read(data, DME1737_REG_CONFIG2); /* Check if optional fan3 input is enabled */ - if (data->config2 & 0x04) { + if (data->config2 & 0x04) data->has_features |= HAS_FAN(2); - } - /* Fan4 and pwm3 are only available if the client's I2C address + /* + * Fan4 and pwm3 are only available if the client's I2C address * is the default 0x2e. Otherwise the I/Os associated with - * these functions are used for addr enable/select. */ - if (client->addr == 0x2e) { + * these functions are used for addr enable/select. + */ + if (client->addr == 0x2e) data->has_features |= HAS_FAN(3) | HAS_PWM(2); - } - /* Determine which of the optional fan[5-6] and pwm[5-6] + /* + * Determine which of the optional fan[5-6] and pwm[5-6] * features are enabled. For this, we need to query the runtime * registers through the Super-IO LPC interface. Try both - * config ports 0x2e and 0x4e. */ + * config ports 0x2e and 0x4e. + */ if (dme1737_i2c_get_features(0x2e, data) && dme1737_i2c_get_features(0x4e, data)) { dev_warn(dev, "Failed to query Super-IO for optional " @@ -2271,9 +2345,11 @@ static int dme1737_init_device(struct device *dev) ((reg >> 4) & 0x03) + 1); } - /* Switch pwm[1-3] to manual mode if they are currently disabled and + /* + * Switch pwm[1-3] to manual mode if they are currently disabled and * set the duty-cycles to 0% (which is identical to the PWMs being - * disabled). */ + * disabled). + */ if (!(data->config & 0x02)) { for (ix = 0; ix < 3; ix++) { data->pwm_config[ix] = dme1737_read(data, @@ -2298,9 +2374,8 @@ static int dme1737_init_device(struct device *dev) data->pwm_acz[2] = 4; /* pwm3 -> zone3 */ /* Set VRM */ - if (data->has_features & HAS_VID) { + if (data->has_features & HAS_VID) data->vrm = vid_which_vrm(); - } return 0; } @@ -2318,8 +2393,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) dme1737_sio_enter(sio_cip); - /* Check device ID - * We currently know about two kinds of DME1737 and SCH5027. */ + /* + * Check device ID + * We currently know about two kinds of DME1737 and SCH5027. + */ reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); if (!(reg == DME1737_ID_1 || reg == DME1737_ID_2 || reg == SCH5027_ID)) { @@ -2338,21 +2415,19 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) goto exit; } - /* Read the runtime registers to determine which optional features + /* + * Read the runtime registers to determine which optional features * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set - * to '10' if the respective feature is enabled. */ - if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ + * to '10' if the respective feature is enabled. + */ + if ((inb(addr + 0x43) & 0x0c) == 0x08) /* fan6 */ data->has_features |= HAS_FAN(5); - } - if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ + if ((inb(addr + 0x44) & 0x0c) == 0x08) /* pwm6 */ data->has_features |= HAS_PWM(5); - } - if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ + if ((inb(addr + 0x45) & 0x0c) == 0x08) /* fan5 */ data->has_features |= HAS_FAN(4); - } - if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ + if ((inb(addr + 0x46) & 0x0c) == 0x08) /* pwm5 */ data->has_features |= HAS_PWM(4); - } exit: dme1737_sio_exit(sio_cip); @@ -2369,9 +2444,8 @@ static int dme1737_i2c_detect(struct i2c_client *client, u8 company, verstep = 0; const char *name; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - } company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY); verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP); @@ -2486,8 +2560,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) dme1737_sio_enter(sio_cip); - /* Check device ID - * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 */ + /* + * Check device ID + * We currently know about SCH3112, SCH3114, SCH3116, and SCH5127 + */ reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20); if (!(reg == SCH3112_ID || reg == SCH3114_ID || reg == SCH3116_ID || reg == SCH5127_ID)) { @@ -2507,8 +2583,10 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) goto exit; } - /* Access to the hwmon registers is through an index/data register - * pair located at offset 0x70/0x71. */ + /* + * Access to the hwmon registers is through an index/data register + * pair located at offset 0x70/0x71. + */ *addr = base_addr + 0x70; exit: @@ -2610,11 +2688,10 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) } } - if (data->type == sch5127) { + if (data->type == sch5127) data->name = "sch5127"; - } else { + else data->name = "sch311x"; - } /* Initialize the mutex */ mutex_init(&data->update_lock); @@ -2689,9 +2766,8 @@ static int __init dme1737_init(void) unsigned short addr; err = i2c_add_driver(&dme1737_i2c_driver); - if (err) { + if (err) goto exit; - } if (dme1737_isa_detect(0x2e, &addr) && dme1737_isa_detect(0x4e, &addr) && @@ -2703,15 +2779,13 @@ static int __init dme1737_init(void) } err = platform_driver_register(&dme1737_isa_driver); - if (err) { + if (err) goto exit_del_i2c_driver; - } /* Sets global pdev as a side effect */ err = dme1737_isa_device_add(addr); - if (err) { + if (err) goto exit_del_isa_driver; - } return 0; diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index ef1ac996752e..f647a3307ebc 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -1,25 +1,25 @@ /* - ds1621.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23 - based on lm75.c by Frodo Looijaard <frodol@dds.nl> - Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with - the help of Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * ds1621.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23 + * based on lm75.c by Frodo Looijaard <frodol@dds.nl> + * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with + * the help of Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -67,7 +67,7 @@ static const u8 DS1621_REG_TEMP[3] = { /* Conversions */ #define ALARMS_FROM_REG(val) ((val) & \ - (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) + (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) /* Each client has this additional data */ struct ds1621_data { @@ -93,10 +93,10 @@ static void ds1621_init_client(struct i2c_client *client) new_conf &= ~DS1621_REG_CONFIG_POLARITY; else if (polarity == 1) new_conf |= DS1621_REG_CONFIG_POLARITY; - + if (conf != new_conf) i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); - + /* start conversion */ i2c_smbus_write_byte(client, DS1621_COM_START); } @@ -155,10 +155,15 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); struct ds1621_data *data = i2c_get_clientdata(client); - u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - data->temp[attr->index] = val; + data->temp[attr->index] = LM75_TEMP_TO_REG(val); i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index], data->temp[attr->index]); mutex_unlock(&data->update_lock); @@ -212,14 +217,17 @@ static int ds1621_detect(struct i2c_client *client, int conf, temp; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_SMBUS_WORD_DATA + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE)) return -ENODEV; - /* Now, we do the remaining detection. It is lousy. */ - /* The NVB bit should be low if no EEPROM write has been requested - during the latest 10ms, which is highly improbable in our case. */ + /* + * Now, we do the remaining detection. It is lousy. + * + * The NVB bit should be low if no EEPROM write has been requested + * during the latest 10ms, which is highly improbable in our case. + */ conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); if (conf < 0 || conf & DS1621_REG_CONFIG_NVB) return -ENODEV; @@ -254,7 +262,8 @@ static int ds1621_probe(struct i2c_client *client, ds1621_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group))) + err = sysfs_create_group(&client->dev.kobj, &ds1621_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&client->dev); @@ -265,11 +274,11 @@ static int ds1621_probe(struct i2c_client *client, return 0; - exit_remove_files: + exit_remove_files: sysfs_remove_group(&client->dev.kobj, &ds1621_group); - exit_free: + exit_free: kfree(data); - exit: + exit: return err; } @@ -305,20 +314,8 @@ static struct i2c_driver ds1621_driver = { .address_list = normal_i2c, }; -static int __init ds1621_init(void) -{ - return i2c_add_driver(&ds1621_driver); -} - -static void __exit ds1621_exit(void) -{ - i2c_del_driver(&ds1621_driver); -} - +module_i2c_driver(ds1621_driver); MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>"); MODULE_DESCRIPTION("DS1621 driver"); MODULE_LICENSE("GPL"); - -module_init(ds1621_init); -module_exit(ds1621_exit); diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 300c3d4d67df..50663efad412 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -297,19 +297,8 @@ static struct i2c_driver ds620_driver = { .id_table = ds620_id, }; -static int __init ds620_init(void) -{ - return i2c_add_driver(&ds620_driver); -} - -static void __exit ds620_exit(void) -{ - i2c_del_driver(&ds620_driver); -} +module_i2c_driver(ds620_driver); MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); MODULE_DESCRIPTION("DS620 driver"); MODULE_LICENSE("GPL"); - -module_init(ds620_init); -module_exit(ds620_exit); diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 270ffab711cb..149dcb0e148f 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -41,8 +41,10 @@ struct thermal_data { struct device *hwmon_dev; struct mutex mutex; - /* Cache the hyst value so we don't keep re-reading it. In theory - we could cache it forever as nobody else should be writing it. */ + /* + * Cache the hyst value so we don't keep re-reading it. In theory + * we could cache it forever as nobody else should be writing it. + */ u8 cached_hyst; unsigned long hyst_valid; }; @@ -283,8 +285,10 @@ static int emc1403_detect(struct i2c_client *client, case 0x23: strlcpy(info->type, "emc1423", I2C_NAME_SIZE); break; - /* Note: 0x25 is the 1404 which is very similar and this - driver could be extended */ + /* + * Note: 0x25 is the 1404 which is very similar and this + * driver could be extended + */ default: return -ENODEV; } @@ -366,18 +370,7 @@ static struct i2c_driver sensor_emc1403 = { .address_list = emc1403_address_list, }; -static int __init sensor_emc1403_init(void) -{ - return i2c_add_driver(&sensor_emc1403); -} - -static void __exit sensor_emc1403_exit(void) -{ - i2c_del_driver(&sensor_emc1403); -} - -module_init(sensor_emc1403_init); -module_exit(sensor_emc1403_exit); +module_i2c_driver(sensor_emc1403); MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); MODULE_DESCRIPTION("emc1403 Thermal Driver"); diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 865063914d76..9691f664c76e 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -1,21 +1,21 @@ /* - emc2103.c - Support for SMSC EMC2103 - Copyright (c) 2010 SMSC - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * emc2103.c - Support for SMSC EMC2103 + * Copyright (c) 2010 SMSC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -48,12 +48,14 @@ static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 }; /* equation 4 from datasheet: rpm = (3932160 * multipler) / count */ #define FAN_RPM_FACTOR 3932160 -/* 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes +/* + * 2103-2 and 2103-4's 3rd temperature sensor can be connected to two diodes * in anti-parallel mode, and in this configuration both can be read * independently (so we have 4 temperature inputs). The device can't * detect if it's connected in this mode, so we have to manually enable * it. Default is to leave the device in the state it's already in (-1). - * This parameter allows APD mode to be optionally forced on or off */ + * This parameter allows APD mode to be optionally forced on or off + */ static int apd = -1; module_param(apd, bint, 0); MODULE_PARM_DESC(init, "Set to zero to disable anti-parallel diode mode"); @@ -302,10 +304,12 @@ show_fan_div(struct device *dev, struct device_attribute *da, char *buf) return sprintf(buf, "%d\n", fan_div); } -/* Note: we also update the fan target here, because its value is - determined in part by the fan clock divider. This follows the principle - of least surprise; the user doesn't expect the fan target to change just - because the divider changed. */ +/* + * Note: we also update the fan target here, because its value is + * determined in part by the fan clock divider. This follows the principle + * of least surprise; the user doesn't expect the fan target to change just + * because the divider changed. + */ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { @@ -722,19 +726,8 @@ static struct i2c_driver emc2103_driver = { .address_list = normal_i2c, }; -static int __init sensors_emc2103_init(void) -{ - return i2c_add_driver(&emc2103_driver); -} - -static void __exit sensors_emc2103_exit(void) -{ - i2c_del_driver(&emc2103_driver); -} +module_i2c_driver(emc2103_driver); MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); MODULE_DESCRIPTION("SMSC EMC2103 hwmon driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_emc2103_init); -module_exit(sensors_emc2103_exit); diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index 6ebb9b738c9c..840f5112e602 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -552,17 +552,7 @@ static struct i2c_driver emc6w201_driver = { .address_list = normal_i2c, }; -static int __init sensors_emc6w201_init(void) -{ - return i2c_add_driver(&emc6w201_driver); -} -module_init(sensors_emc6w201_init); - -static void __exit sensors_emc6w201_exit(void) -{ - i2c_del_driver(&emc6w201_driver); -} -module_exit(sensors_emc6w201_exit); +module_i2c_driver(emc6w201_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver"); diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 6dbfd3e516e4..3e4da620e9c7 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -202,7 +202,7 @@ struct f71805f_sio_data { static inline long in_from_reg(u8 reg) { - return (reg * 8); + return reg * 8; } /* The 2 least significant bits are not used */ @@ -212,13 +212,13 @@ static inline u8 in_to_reg(long val) return 0; if (val >= 2016) return 0xfc; - return (((val + 16) / 32) << 2); + return ((val + 16) / 32) << 2; } /* in0 is downscaled by a factor 2 internally */ static inline long in0_from_reg(u8 reg) { - return (reg * 16); + return reg * 16; } static inline u8 in0_to_reg(long val) @@ -227,7 +227,7 @@ static inline u8 in0_to_reg(long val) return 0; if (val >= 4032) return 0xfc; - return (((val + 32) / 64) << 2); + return ((val + 32) / 64) << 2; } /* The 4 most significant bits are not used */ @@ -236,17 +236,19 @@ static inline long fan_from_reg(u16 reg) reg &= 0xfff; if (!reg || reg == 0xfff) return 0; - return (1500000 / reg); + return 1500000 / reg; } static inline u16 fan_to_reg(long rpm) { - /* If the low limit is set below what the chip can measure, - store the largest possible 12-bit value in the registers, - so that no alarm will ever trigger. */ + /* + * If the low limit is set below what the chip can measure, + * store the largest possible 12-bit value in the registers, + * so that no alarm will ever trigger. + */ if (rpm < 367) return 0xfff; - return (1500000 / rpm); + return 1500000 / rpm; } static inline unsigned long pwm_freq_from_reg(u8 reg) @@ -278,7 +280,7 @@ static inline int pwm_mode_from_reg(u8 reg) static inline long temp_from_reg(u8 reg) { - return (reg * 1000); + return reg * 1000; } static inline u8 temp_to_reg(long val) @@ -308,9 +310,11 @@ static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val) outb(val, data->addr + DATA_REG_OFFSET); } -/* It is important to read the MSB first, because doing so latches the - value of the LSB, so we are sure both bytes belong to the same value. - Must be called with data->update_lock held, except during initialization */ +/* + * It is important to read the MSB first, because doing so latches the + * value of the LSB, so we are sure both bytes belong to the same value. + * Must be called with data->update_lock held, except during initialization + */ static u16 f71805f_read16(struct f71805f_data *data, u8 reg) { u16 val; @@ -455,7 +459,12 @@ static ssize_t set_in0_max(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_high[nr] = in0_to_reg(val); @@ -471,7 +480,12 @@ static ssize_t set_in0_min(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_low[nr] = in0_to_reg(val); @@ -517,7 +531,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_high[nr] = in_to_reg(val); @@ -533,7 +552,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_low[nr] = in_to_reg(val); @@ -579,7 +603,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_low[nr] = fan_to_reg(val); @@ -595,7 +624,12 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_target[nr] = fan_to_reg(val); @@ -664,7 +698,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; if (val > 255) return -EINVAL; @@ -685,8 +724,13 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); u8 reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; if (val < 1 || val > 3) return -EINVAL; @@ -730,7 +774,12 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm_freq[nr] = pwm_freq_to_reg(val); @@ -742,7 +791,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute static ssize_t show_pwm_auto_point_temp(struct device *dev, struct device_attribute *devattr, - char* buf) + char *buf) { struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); @@ -755,13 +804,18 @@ static ssize_t show_pwm_auto_point_temp(struct device *dev, static ssize_t set_pwm_auto_point_temp(struct device *dev, struct device_attribute *devattr, - const char* buf, size_t count) + const char *buf, size_t count) { struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); int pwmnr = attr->nr; int apnr = attr->index; - unsigned long val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val); @@ -774,7 +828,7 @@ static ssize_t set_pwm_auto_point_temp(struct device *dev, static ssize_t show_pwm_auto_point_fan(struct device *dev, struct device_attribute *devattr, - char* buf) + char *buf) { struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); @@ -787,18 +841,23 @@ static ssize_t show_pwm_auto_point_fan(struct device *dev, static ssize_t set_pwm_auto_point_fan(struct device *dev, struct device_attribute *devattr, - const char* buf, size_t count) + const char *buf, size_t count) { struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); int pwmnr = attr->nr; int apnr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val); f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr), - data->auto_points[pwmnr].fan[apnr]); + data->auto_points[pwmnr].fan[apnr]); mutex_unlock(&data->update_lock); return count; @@ -851,7 +910,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_high[nr] = temp_to_reg(val); @@ -867,7 +931,12 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute struct f71805f_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_hyst[nr] = temp_to_reg(val); @@ -920,9 +989,9 @@ static ssize_t show_name(struct device *dev, struct device_attribute } static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL, 0); -static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, show_in0_max, set_in0_max, 0); -static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, show_in0_min, set_in0_min, 0); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, @@ -1010,8 +1079,10 @@ static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_hyst, set_temp_hyst, 2); static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); -/* pwm (value) files are created read-only, write permission is - then added or removed dynamically as needed */ +/* + * pwm (value) files are created read-only, write permission is + * then added or removed dynamically as needed + */ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, show_pwm, set_pwm, 0); static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, set_pwm_enable, 0); @@ -1246,8 +1317,10 @@ static const struct attribute_group f71805f_group_optin[4] = { { .attrs = f71805f_attributes_optin[3] }, }; -/* We don't include pwm_freq files in the arrays above, because they must be - created conditionally (only if pwm_mode is 1 == PWM) */ +/* + * We don't include pwm_freq files in the arrays above, because they must be + * created conditionally (only if pwm_mode is 1 == PWM) + */ static struct attribute *f71805f_attributes_pwm_freq[] = { &sensor_dev_attr_pwm1_freq.dev_attr.attr, &sensor_dev_attr_pwm2_freq.dev_attr.attr, @@ -1282,13 +1355,17 @@ static void __devinit f71805f_init_device(struct f71805f_data *data) f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40); } - /* Fan monitoring can be disabled. If it is, we won't be polling - the register values, and won't create the related sysfs files. */ + /* + * Fan monitoring can be disabled. If it is, we won't be polling + * the register values, and won't create the related sysfs files. + */ for (i = 0; i < 3; i++) { data->fan_ctrl[i] = f71805f_read8(data, F71805F_REG_FAN_CTRL(i)); - /* Clear latch full bit, else "speed mode" fan speed control - doesn't work */ + /* + * Clear latch full bit, else "speed mode" fan speed control + * doesn't work + */ if (data->fan_ctrl[i] & FAN_CTRL_LATCH_FULL) { data->fan_ctrl[i] &= ~FAN_CTRL_LATCH_FULL; f71805f_write8(data, F71805F_REG_FAN_CTRL(i), @@ -1304,12 +1381,13 @@ static int __devinit f71805f_probe(struct platform_device *pdev) struct resource *res; int i, err; - static const char *names[] = { + static const char * const names[] = { "f71805f", "f71872f", }; - if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; pr_err("Out of memory\n"); goto exit; @@ -1347,40 +1425,47 @@ static int __devinit f71805f_probe(struct platform_device *pdev) f71805f_init_device(data); /* Register sysfs interface files */ - if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) + err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group); + if (err) goto exit_release_region; if (data->has_in & (1 << 4)) { /* in4 */ - if ((err = sysfs_create_group(&pdev->dev.kobj, - &f71805f_group_optin[0]))) + err = sysfs_create_group(&pdev->dev.kobj, + &f71805f_group_optin[0]); + if (err) goto exit_remove_files; } if (data->has_in & (1 << 8)) { /* in8 */ - if ((err = sysfs_create_group(&pdev->dev.kobj, - &f71805f_group_optin[1]))) + err = sysfs_create_group(&pdev->dev.kobj, + &f71805f_group_optin[1]); + if (err) goto exit_remove_files; } if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */ - if ((err = sysfs_create_group(&pdev->dev.kobj, - &f71805f_group_optin[2]))) + err = sysfs_create_group(&pdev->dev.kobj, + &f71805f_group_optin[2]); + if (err) goto exit_remove_files; } if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */ - if ((err = sysfs_create_group(&pdev->dev.kobj, - &f71805f_group_optin[3]))) + err = sysfs_create_group(&pdev->dev.kobj, + &f71805f_group_optin[3]); + if (err) goto exit_remove_files; } for (i = 0; i < 3; i++) { /* If control mode is PWM, create pwm_freq file */ if (!(data->fan_ctrl[i] & FAN_CTRL_DC_MODE)) { - if ((err = sysfs_create_file(&pdev->dev.kobj, - f71805f_attributes_pwm_freq[i]))) + err = sysfs_create_file(&pdev->dev.kobj, + f71805f_attributes_pwm_freq[i]); + if (err) goto exit_remove_files; } /* If PWM is in manual mode, add write permission */ if (data->fan_ctrl[i] & FAN_CTRL_MODE_MANUAL) { - if ((err = sysfs_chmod_file(&pdev->dev.kobj, - f71805f_attr_pwm[i], - S_IRUGO | S_IWUSR))) { + err = sysfs_chmod_file(&pdev->dev.kobj, + f71805f_attr_pwm[i], + S_IRUGO | S_IWUSR); + if (err) { dev_err(&pdev->dev, "chmod +w pwm%d failed\n", i + 1); goto exit_remove_files; @@ -1495,7 +1580,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, int err = -ENODEV; u16 devid; - static const char *names[] = { + static const char * const names[] = { "F71805F/FG", "F71872F/FG or F71806F/FG", }; diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index e50305819f01..6d1226365e30 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -112,7 +112,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg, f71889fg, f71889ed, f71889a, f8000, f81865f }; -static const char *f71882fg_names[] = { +static const char *const f71882fg_names[] = { "f71808e", "f71808a", "f71858fg", @@ -252,9 +252,11 @@ struct f71882fg_data { u16 fan_full_speed[4]; u8 fan_status; u8 fan_beep; - /* Note: all models have max 3 temperature channels, but on some - they are addressed as 0-2 and on others as 1-3, so for coding - convenience we reserve space for 4 channels */ + /* + * Note: all models have max 3 temperature channels, but on some + * they are addressed as 0-2 and on others as 1-3, so for coding + * convenience we reserve space for 4 channels + */ u16 temp[4]; u8 temp_ovt[4]; u8 temp_high[4]; @@ -362,7 +364,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf); -static int __devinit f71882fg_probe(struct platform_device * pdev); +static int __devinit f71882fg_probe(struct platform_device *pdev); static int f71882fg_remove(struct platform_device *pdev); static struct platform_driver f71882fg_driver = { @@ -376,8 +378,10 @@ static struct platform_driver f71882fg_driver = { static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -/* Temp attr for the f71858fg, the f71858fg is special as it has its - temperature indexes start at 0 (the others start at 1) */ +/* + * Temp attr for the f71858fg, the f71858fg is special as it has its + * temperature indexes start at 0 (the others start at 1) + */ static struct sensor_device_attribute_2 f71858fg_temp_attr[] = { SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, @@ -424,9 +428,11 @@ static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { { store_temp_max, 0, 1), SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, store_temp_max_hyst, 0, 1), - /* Should really be temp1_max_alarm, but older versions did not handle - the max and crit alarms separately and lm_sensors v2 depends on the - presence of temp#_alarm files. The same goes for temp2/3 _alarm. */ + /* + * Should really be temp1_max_alarm, but older versions did not handle + * the max and crit alarms separately and lm_sensors v2 depends on the + * presence of temp#_alarm files. The same goes for temp2/3 _alarm. + */ SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, store_temp_crit, 0, 1), @@ -485,10 +491,11 @@ static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { { store_temp_beep, 0, 7), } }; -/* Temp attr for the f8000 - Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max) - is used as hysteresis value to clear alarms - Also like the f71858fg its temperature indexes start at 0 +/* + * Temp attr for the f8000 + * Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max) + * is used as hysteresis value to clear alarms + * Also like the f71858fg its temperature indexes start at 0 */ static struct sensor_device_attribute_2 f8000_temp_attr[] = { SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), @@ -603,8 +610,10 @@ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = { store_fan_beep, 0, 3), }; -/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the - standard models */ +/* + * PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the + * standard models + */ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { { SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, show_pwm_auto_point_channel, @@ -673,9 +682,11 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { { show_pwm_auto_point_temp_hyst, NULL, 3, 2), } }; -/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the - pwm setting when the temperature is above the pwmX_auto_point1_temp can be - programmed instead of being hardcoded to 0xff */ +/* + * PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the + * pwm setting when the temperature is above the pwmX_auto_point1_temp can be + * programmed instead of being hardcoded to 0xff + */ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { { SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, show_pwm_auto_point_channel, @@ -925,9 +936,11 @@ static struct sensor_device_attribute_2 f8000_fan_attr[] = { SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), }; -/* PWM attr for the f8000, zones mapped to temp instead of to pwm! - Also the register block at offset A0 maps to TEMP1 (so our temp2, as the - F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */ +/* + * PWM attr for the f8000, zones mapped to temp instead of to pwm! + * Also the register block at offset A0 maps to TEMP1 (so our temp2, as the + * F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 + */ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { { SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, show_pwm_auto_point_channel, @@ -2295,8 +2308,10 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) data->temp_config = f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG); if (data->temp_config & 0x10) - /* The f71858fg temperature alarms behave as - the f8000 alarms in this mode */ + /* + * The f71858fg temperature alarms behave as + * the f8000 alarms in this mode + */ err = f71882fg_create_sysfs_files(pdev, f8000_temp_attr, ARRAY_SIZE(f8000_temp_attr)); diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 6aa5a9fad879..729499e75210 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -917,19 +917,8 @@ static int f75375_detect(struct i2c_client *client, return 0; } -static int __init sensors_f75375_init(void) -{ - return i2c_add_driver(&f75375_driver); -} - -static void __exit sensors_f75375_exit(void) -{ - i2c_del_driver(&f75375_driver); -} +module_i2c_driver(f75375_driver); MODULE_AUTHOR("Riku Voipio"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("F75373/F75375/F75387 hardware monitoring driver"); - -module_init(sensors_f75375_init); -module_exit(sensors_f75375_exit); diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index aa6d8b686f82..8305d29459bd 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -1,4 +1,5 @@ -/* fschmd.c +/* + * fschmd.c * * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com> * @@ -76,12 +77,12 @@ enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl }; #define FSCHMD_CONTROL_ALERT_LED 0x01 /* watchdog */ -static const u8 FSCHMD_REG_WDOG_CONTROL[7] = - { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 }; -static const u8 FSCHMD_REG_WDOG_STATE[7] = - { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 }; -static const u8 FSCHMD_REG_WDOG_PRESET[7] = - { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a }; +static const u8 FSCHMD_REG_WDOG_CONTROL[7] = { + 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 }; +static const u8 FSCHMD_REG_WDOG_STATE[7] = { + 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 }; +static const u8 FSCHMD_REG_WDOG_PRESET[7] = { + 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a }; #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ @@ -103,10 +104,12 @@ static const u8 FSCHMD_REG_VOLT[7][6] = { static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; -/* minimum pwm at which the fan is driven (pwm can by increased depending on - the temp. Notice that for the scy some fans share there minimum speed. - Also notice that with the scy the sensor order is different than with the - other chips, this order was in the 2.4 driver and kept for consistency. */ +/* + * minimum pwm at which the fan is driven (pwm can by increased depending on + * the temp. Notice that for the scy some fans share there minimum speed. + * Also notice that with the scy the sensor order is different than with the + * other chips, this order was in the 2.4 driver and kept for consistency. + */ static const u8 FSCHMD_REG_FAN_MIN[7][7] = { { 0x55, 0x65 }, /* pos */ { 0x55, 0x65, 0xb5 }, /* her */ @@ -182,11 +185,13 @@ static const u8 FSCHMD_REG_TEMP_STATE[7][11] = { 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, }; -/* temperature high limit registers, FSC does not document these. Proven to be - there with field testing on the fscher and fschrc, already supported / used - in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers - at these addresses, but doesn't want to confirm they are the same as with - the fscher?? */ +/* + * temperature high limit registers, FSC does not document these. Proven to be + * there with field testing on the fscher and fschrc, already supported / used + * in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers + * at these addresses, but doesn't want to confirm they are the same as with + * the fscher?? + */ static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = { { 0, 0, 0 }, /* pos */ { 0x76, 0x86, 0x96 }, /* her */ @@ -198,13 +203,15 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = { 0xba, 0xca, 0xda, 0xea, 0xfa }, }; -/* These were found through experimenting with an fscher, currently they are - not used, but we keep them around for future reference. - On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), - AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence - the fan speed. -static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; -static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ +/* + * These were found through experimenting with an fscher, currently they are + * not used, but we keep them around for future reference. + * On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), + * AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence + * the fan speed. + * static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; + * static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; + */ static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; @@ -290,24 +297,30 @@ struct fschmd_data { u8 fan_ripple[7]; /* divider for rps */ }; -/* Global variables to hold information read from special DMI tables, which are - available on FSC machines with an fscher or later chip. There is no need to - protect these with a lock as they are only modified from our attach function - which always gets called with the i2c-core lock held and never accessed - before the attach function is done with them. */ +/* + * Global variables to hold information read from special DMI tables, which are + * available on FSC machines with an fscher or later chip. There is no need to + * protect these with a lock as they are only modified from our attach function + * which always gets called with the i2c-core lock held and never accessed + * before the attach function is done with them. + */ static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 }; static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 }; static int dmi_vref = -1; -/* Somewhat ugly :( global data pointer list with all fschmd devices, so that - we can find our device data as when using misc_register there is no other - method to get to ones device data from the open fop. */ +/* + * Somewhat ugly :( global data pointer list with all fschmd devices, so that + * we can find our device data as when using misc_register there is no other + * method to get to ones device data from the open fop. + */ static LIST_HEAD(watchdog_data_list); /* Note this lock not only protect list access, but also data.kref access */ static DEFINE_MUTEX(watchdog_data_mutex); -/* Release our data struct when we're detached from the i2c client *and* all - references to our watchdog device are released */ +/* + * Release our data struct when we're detached from the i2c client *and* all + * references to our watchdog device are released + */ static void fschmd_release_resources(struct kref *ref) { struct fschmd_data *data = container_of(ref, struct fschmd_data, kref); @@ -359,9 +372,14 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute { int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = dev_get_drvdata(dev); - long v = simple_strtol(buf, NULL, 10) / 1000; + long v; + int err; - v = SENSORS_LIMIT(v, -128, 127) + 128; + err = kstrtol(buf, 10, &v); + if (err) + return err; + + v = SENSORS_LIMIT(v / 1000, -128, 127) + 128; mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(to_i2c_client(dev), @@ -427,12 +445,23 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = dev_get_drvdata(dev); /* supported values: 2, 4, 8 */ - unsigned long v = simple_strtoul(buf, NULL, 10); + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; switch (v) { - case 2: v = 1; break; - case 4: v = 2; break; - case 8: v = 3; break; + case 2: + v = 1; + break; + case 4: + v = 2; + break; + case 8: + v = 3; + break; default: dev_err(dev, "fan_div value %lu not supported. " "Choose one of 2, 4 or 8!\n", v); @@ -502,7 +531,12 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, { int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = dev_get_drvdata(dev); - unsigned long v = simple_strtoul(buf, NULL, 10); + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ if (v || data->kind == fscsyl) { @@ -522,8 +556,10 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, } -/* The FSC hwmon family has the ability to force an attached alert led to flash - from software, we export this as an alert_led sysfs attr */ +/* + * The FSC hwmon family has the ability to force an attached alert led to flash + * from software, we export this as an alert_led sysfs attr + */ static ssize_t show_alert_led(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -540,7 +576,12 @@ static ssize_t store_alert_led(struct device *dev, { u8 reg; struct fschmd_data *data = dev_get_drvdata(dev); - unsigned long v = simple_strtoul(buf, NULL, 10); + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; mutex_lock(&data->update_lock); @@ -754,8 +795,10 @@ static int watchdog_stop(struct fschmd_data *data) } data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; - /* Don't store the stop flag in our watchdog control register copy, as - its a write only bit (read always returns 0) */ + /* + * Don't store the stop flag in our watchdog control register copy, as + * its a write only bit (read always returns 0) + */ i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL[data->kind], data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); @@ -769,10 +812,12 @@ static int watchdog_open(struct inode *inode, struct file *filp) struct fschmd_data *pos, *data = NULL; int watchdog_is_open; - /* We get called from drivers/char/misc.c with misc_mtx hold, and we - call misc_register() from fschmd_probe() with watchdog_data_mutex - hold, as misc_register() takes the misc_mtx lock, this is a possible - deadlock, so we use mutex_trylock here. */ + /* + * We get called from drivers/char/misc.c with misc_mtx hold, and we + * call misc_register() from fschmd_probe() with watchdog_data_mutex + * hold, as misc_register() takes the misc_mtx lock, this is a possible + * deadlock, so we use mutex_trylock here. + */ if (!mutex_trylock(&watchdog_data_mutex)) return -ERESTARTSYS; list_for_each_entry(pos, &watchdog_data_list, list) { @@ -847,7 +892,8 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf, return count; } -static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static long watchdog_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) { struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | @@ -930,30 +976,38 @@ static const struct file_operations watchdog_fops = { * Detect, register, unregister and update device functions */ -/* DMI decode routine to read voltage scaling factors from special DMI tables, - which are available on FSC machines with an fscher or later chip. */ +/* + * DMI decode routine to read voltage scaling factors from special DMI tables, + * which are available on FSC machines with an fscher or later chip. + */ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) { int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; - /* dmi code ugliness, we get passed the address of the contents of - a complete DMI record, but in the form of a dmi_header pointer, in - reality this address holds header->length bytes of which the header - are the first 4 bytes */ + /* + * dmi code ugliness, we get passed the address of the contents of + * a complete DMI record, but in the form of a dmi_header pointer, in + * reality this address holds header->length bytes of which the header + * are the first 4 bytes + */ u8 *dmi_data = (u8 *)header; /* We are looking for OEM-specific type 185 */ if (header->type != 185) return; - /* we are looking for what Siemens calls "subtype" 19, the subtype - is stored in byte 5 of the dmi block */ + /* + * we are looking for what Siemens calls "subtype" 19, the subtype + * is stored in byte 5 of the dmi block + */ if (header->length < 5 || dmi_data[4] != 19) return; - /* After the subtype comes 1 unknown byte and then blocks of 5 bytes, - consisting of what Siemens calls an "Entity" number, followed by - 2 16-bit words in LSB first order */ + /* + * After the subtype comes 1 unknown byte and then blocks of 5 bytes, + * consisting of what Siemens calls an "Entity" number, followed by + * 2 16-bit words in LSB first order + */ for (i = 6; (i + 4) < header->length; i += 5) { /* entity 1 - 3: voltage multiplier and offset */ if (dmi_data[i] >= 1 && dmi_data[i] <= 3) { @@ -988,9 +1042,11 @@ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) dmi_mult[i] = mult[i] * 10; dmi_offset[i] = offset[i] * 10; } - /* According to the docs there should be separate dmi entries - for the mult's and offsets of in3-5 of the syl, but on - my test machine these are not present */ + /* + * According to the docs there should be separate dmi entries + * for the mult's and offsets of in3-5 of the syl, but on + * my test machine these are not present + */ dmi_mult[3] = dmi_mult[2]; dmi_mult[4] = dmi_mult[1]; dmi_mult[5] = dmi_mult[2]; @@ -1058,15 +1114,19 @@ static int fschmd_probe(struct i2c_client *client, mutex_init(&data->watchdog_lock); INIT_LIST_HEAD(&data->list); kref_init(&data->kref); - /* Store client pointer in our data struct for watchdog usage - (where the client is found through a data ptr instead of the - otherway around) */ + /* + * Store client pointer in our data struct for watchdog usage + * (where the client is found through a data ptr instead of the + * otherway around) + */ data->client = client; data->kind = kind; if (kind == fscpos) { - /* The Poseidon has hardwired temp limits, fill these - in for the alarm resetting code */ + /* + * The Poseidon has hardwired temp limits, fill these + * in for the alarm resetting code + */ data->temp_max[0] = 70 + 128; data->temp_max[1] = 50 + 128; data->temp_max[2] = 50 + 128; @@ -1157,9 +1217,11 @@ static int fschmd_probe(struct i2c_client *client, goto exit_detach; } - /* We take the data_mutex lock early so that watchdog_open() cannot - run when misc_register() has completed, but we've not yet added - our data to the watchdog_data_list (and set the default timeout) */ + /* + * We take the data_mutex lock early so that watchdog_open() cannot + * run when misc_register() has completed, but we've not yet added + * our data to the watchdog_data_list (and set the default timeout) + */ mutex_lock(&watchdog_data_mutex); for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) { /* Register our watchdog part */ @@ -1225,8 +1287,10 @@ static int fschmd_remove(struct i2c_client *client) mutex_unlock(&data->watchdog_lock); } - /* Check if registered in case we're called from fschmd_detect - to cleanup after an error */ + /* + * Check if registered in case we're called from fschmd_detect + * to cleanup after an error + */ if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); @@ -1269,8 +1333,10 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) client, FSCHMD_REG_TEMP_LIMIT[data->kind][i]); - /* reset alarm if the alarm condition is gone, - the chip doesn't do this itself */ + /* + * reset alarm if the alarm condition is gone, + * the chip doesn't do this itself + */ if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) == FSCHMD_TEMP_ALARM_MASK && data->temp_act[i] < data->temp_max[i]) @@ -1314,20 +1380,9 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) return data; } -static int __init fschmd_init(void) -{ - return i2c_add_driver(&fschmd_driver); -} - -static void __exit fschmd_exit(void) -{ - i2c_del_driver(&fschmd_driver); -} +module_i2c_driver(fschmd_driver); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades " "and Syleus driver"); MODULE_LICENSE("GPL"); - -module_init(fschmd_init); -module_exit(fschmd_exit); diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 781277ddbaa5..ebcd2698e4dc 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -1,17 +1,17 @@ /* - g760a - Driver for the Global Mixed-mode Technology Inc. G760A - fan speed PWM controller chip - - Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> - - Complete datasheet is available at GMT's website: - http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. -*/ + * g760a - Driver for the Global Mixed-mode Technology Inc. G760A + * fan speed PWM controller chip + * + * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> + * + * Complete datasheet is available at GMT's website: + * http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ #include <linux/module.h> #include <linux/init.h> @@ -59,7 +59,8 @@ struct g760a_data { u8 act_cnt; /* formula: cnt = (CLK * 30)/(rpm * P) */ u8 fan_sta; /* bit 0: set when actual fan speed more than 20% * outside requested fan speed - * bit 1: set when fan speed below 1920 rpm */ + * bit 1: set when fan speed below 1920 rpm + */ }; #define G760A_DEFAULT_CLK 32768 @@ -99,7 +100,7 @@ static int g760a_write_value(struct i2c_client *client, enum g760a_regs reg, return i2c_smbus_write_byte_data(client, reg, value); } -/**************************************************************************** +/* * sysfs attributes */ @@ -192,7 +193,7 @@ static const struct attribute_group g760a_group = { .attrs = g760a_attributes, }; -/**************************************************************************** +/* * new-style driver model code */ @@ -250,21 +251,8 @@ static int g760a_remove(struct i2c_client *client) return 0; } -/* module management */ - -static int __init g760a_init(void) -{ - return i2c_add_driver(&g760a_driver); -} - -static void __exit g760a_exit(void) -{ - i2c_del_driver(&g760a_driver); -} +module_i2c_driver(g760a_driver); MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>"); MODULE_DESCRIPTION("GMT G760A driver"); MODULE_LICENSE("GPL"); - -module_init(g760a_init); -module_exit(g760a_exit); diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index a13e2da97e30..764a083ac7a7 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -83,11 +83,12 @@ enum chips { gl518sm_r00, gl518sm_r80 }; #define RAW_FROM_REG(val) val -#define BOOL_FROM_REG(val) ((val)?0:1) -#define BOOL_TO_REG(val) ((val)?0:1) +#define BOOL_FROM_REG(val) ((val) ? 0 : 1) +#define BOOL_TO_REG(val) ((val) ? 0 : 1) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0? \ - (val)-500:(val)+500)/1000)+119),0,255)) +#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \ + (val) - 500 : \ + (val) + 500) / 1000) + 119), 0, 255) #define TEMP_FROM_REG(val) (((val) - 119) * 1000) static inline u8 FAN_TO_REG(long rpm, int div) @@ -98,13 +99,13 @@ static inline u8 FAN_TO_REG(long rpm, int div) rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div; return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255); } -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val)*(div)))) +#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) * (div)))) -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) -#define IN_FROM_REG(val) ((val)*19) +#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255) +#define IN_FROM_REG(val) ((val) * 19) -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) -#define VDD_FROM_REG(val) (((val)*95+2)/4) +#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255) +#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) #define DIV_FROM_REG(val) (1 << (val)) @@ -169,7 +170,8 @@ static struct i2c_driver gl518_driver = { */ #define show(type, suffix, value) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##suffix(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ struct gl518_data *data = gl518_update_device(dev); \ return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ @@ -222,12 +224,16 @@ static ssize_t show_fan_div(struct device *dev, } #define set(type, suffix, value, reg) \ -static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ +static ssize_t set_##suffix(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct gl518_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err) \ + return err; \ \ mutex_lock(&data->update_lock); \ data->value = type##_TO_REG(val); \ @@ -237,13 +243,17 @@ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, c } #define set_bits(type, suffix, value, reg, mask, shift) \ -static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ +static ssize_t set_##suffix(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct gl518_data *data = i2c_get_clientdata(client); \ int regvalue; \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ + unsigned long val; \ + int err = kstrtoul(buf, 10, &val); \ + if (err) \ + return err; \ \ mutex_lock(&data->update_lock); \ regvalue = gl518_read_value(client, reg); \ @@ -280,7 +290,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, struct gl518_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; int regvalue; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); @@ -308,13 +323,26 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct gl518_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; int regvalue; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; switch (val) { - case 1: val = 0; break; - case 2: val = 1; break; - case 4: val = 2; break; - case 8: val = 3; break; + case 1: + val = 0; + break; + case 2: + val = 1; + break; + case 4: + val = 2; + break; + case 8: + val = 3; + break; default: dev_err(dev, "Invalid fan clock divider %lu, choose one " "of 1, 2, 4 or 8\n", val); @@ -395,8 +423,12 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr, struct gl518_data *data = i2c_get_clientdata(client); int bitnr = to_sensor_dev_attr(attr)->index; unsigned long bit; + int err; + + err = kstrtoul(buf, 10, &bit); + if (err) + return err; - bit = simple_strtoul(buf, NULL, 10); if (bit & ~1) return -EINVAL; @@ -528,12 +560,14 @@ static int gl518_probe(struct i2c_client *client, gl518_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group))) + err = sysfs_create_group(&client->dev.kobj, &gl518_group); + if (err) goto exit_free; - if (data->type == gl518sm_r80) - if ((err = sysfs_create_group(&client->dev.kobj, - &gl518_group_r80))) + if (data->type == gl518sm_r80) { + err = sysfs_create_group(&client->dev.kobj, &gl518_group_r80); + if (err) goto exit_remove_files; + } data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -554,8 +588,10 @@ exit: } -/* Called when we have found a new GL518SM. - Note that we preserve D4:NoFan2 and D2:beep_enable. */ +/* + * Called when we have found a new GL518SM. + * Note that we preserve D4:NoFan2 and D2:beep_enable. + */ static void gl518_init_client(struct i2c_client *client) { /* Make sure we leave D7:Reset untouched */ @@ -585,9 +621,11 @@ static int gl518_remove(struct i2c_client *client) return 0; } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the SMBus standard. */ +/* + * Registers 0x07 to 0x0c are word-sized, others are byte-sized + * GL518 uses a high-byte first convention, which is exactly opposite to + * the SMBus standard. + */ static int gl518_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) @@ -676,21 +714,10 @@ static struct gl518_data *gl518_update_device(struct device *dev) return data; } -static int __init sensors_gl518sm_init(void) -{ - return i2c_add_driver(&gl518_driver); -} - -static void __exit sensors_gl518sm_exit(void) -{ - i2c_del_driver(&gl518_driver); -} +module_i2c_driver(gl518_driver); MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " "Kyosti Malkki <kmalkki@cc.hut.fi> and " "Hong-Gunn Chew <hglinux@gunnet.org>"); MODULE_DESCRIPTION("GL518SM driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_gl518sm_init); -module_exit(sensors_gl518sm_exit); diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index cd6085bbfba7..5ff452b6a4d0 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -1,25 +1,25 @@ /* - gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>, - Kyösti Mälkki <kmalkki@cc.hut.fi> - Copyright (c) 2005 Maarten Deprez <maartendeprez@users.sourceforge.net> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>, + * Kyösti Mälkki <kmalkki@cc.hut.fi> + * Copyright (c) 2005 Maarten Deprez <maartendeprez@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ #include <linux/module.h> #include <linux/init.h> @@ -41,10 +41,11 @@ MODULE_PARM_DESC(extra_sensor_type, "Type of extra sensor (0=autodetect, 1=tempe /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; -/* Many GL520 constants specified below -One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _IN4 access the same register -*/ +/* + * Many GL520 constants specified below + * One of the inputs can be configured as either temp or voltage. + * That's why _TEMP2 and _IN4 access the same register + */ /* The GL520 registers */ #define GL520_REG_CHIP_ID 0x00 @@ -142,11 +143,11 @@ static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL); -#define VDD_FROM_REG(val) (((val)*95+2)/4) -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) +#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) +#define VDD_TO_REG(val) SENSORS_LIMIT((((val) * 4 + 47) / 95), 0, 255) -#define IN_FROM_REG(val) ((val)*19) -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) +#define IN_FROM_REG(val) ((val) * 19) +#define IN_TO_REG(val) SENSORS_LIMIT((((val) + 9) / 19), 0, 255) static ssize_t get_in_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -193,8 +194,13 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); int n = to_sensor_dev_attr(attr)->index; - long v = simple_strtol(buf, NULL, 10); u8 r; + long v; + int err; + + err = kstrtol(buf, 10, &v); + if (err) + return err; mutex_lock(&data->update_lock); @@ -222,8 +228,13 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); int n = to_sensor_dev_attr(attr)->index; - long v = simple_strtol(buf, NULL, 10); u8 r; + long v; + int err; + + err = kstrtol(buf, 10, &v); + if (err) + return err; if (n == 0) r = VDD_TO_REG(v); @@ -272,8 +283,10 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, get_in_max, set_in_max, 4); #define DIV_FROM_REG(val) (1 << (val)) -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) -#define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)) +#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div)))) +#define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \ + SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, \ + 255)) static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -317,8 +330,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); int n = to_sensor_dev_attr(attr)->index; - unsigned long v = simple_strtoul(buf, NULL, 10); u8 r; + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; mutex_lock(&data->update_lock); r = FAN_TO_REG(v, data->fan_div[n]); @@ -351,16 +369,30 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); int n = to_sensor_dev_attr(attr)->index; - unsigned long v = simple_strtoul(buf, NULL, 10); u8 r; + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; switch (v) { - case 1: r = 0; break; - case 2: r = 1; break; - case 4: r = 2; break; - case 8: r = 3; break; + case 1: + r = 0; + break; + case 2: + r = 1; + break; + case 4: + r = 2; + break; + case 8: + r = 3; + break; default: - dev_err(&client->dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); + dev_err(&client->dev, + "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", v); return -EINVAL; } @@ -385,7 +417,15 @@ static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr, { struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); - u8 r = simple_strtoul(buf, NULL, 10)?1:0; + u8 r; + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; + + r = (v ? 1 : 0); mutex_lock(&data->update_lock); data->fan_off = r; @@ -410,7 +450,8 @@ static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR, get_fan_off, set_fan_off); #define TEMP_FROM_REG(val) (((val) - 130) * 1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) +#define TEMP_TO_REG(val) SENSORS_LIMIT(((((val) < 0 ? \ + (val) - 500 : (val) + 500) / 1000) + 130), 0, 255) static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -430,8 +471,8 @@ static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n])); } -static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute - *attr, char *buf) +static ssize_t get_temp_max_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { int n = to_sensor_dev_attr(attr)->index; struct gl520_data *data = gl520_update_device(dev); @@ -445,7 +486,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); int n = to_sensor_dev_attr(attr)->index; - long v = simple_strtol(buf, NULL, 10); + long v; + int err; + + err = kstrtol(buf, 10, &v); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[n] = TEMP_TO_REG(v); @@ -460,7 +506,12 @@ static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); int n = to_sensor_dev_attr(attr)->index; - long v = simple_strtol(buf, NULL, 10); + long v; + int err; + + err = kstrtol(buf, 10, &v); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max_hyst[n] = TEMP_TO_REG(v); @@ -507,7 +558,15 @@ static ssize_t set_beep_enable(struct device *dev, struct device_attribute { struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); - u8 r = simple_strtoul(buf, NULL, 10)?0:1; + u8 r; + unsigned long v; + int err; + + err = kstrtoul(buf, 10, &v); + if (err) + return err; + + r = (v ? 0 : 1); mutex_lock(&data->update_lock); data->beep_enable = !r; @@ -523,7 +582,12 @@ static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr, { struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); - u8 r = simple_strtoul(buf, NULL, 10); + unsigned long r; + int err; + + err = kstrtoul(buf, 10, &r); + if (err) + return err; mutex_lock(&data->update_lock); r &= data->alarm_mask; @@ -575,7 +639,11 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr, int bitnr = to_sensor_dev_attr(attr)->index; unsigned long bit; - bit = simple_strtoul(buf, NULL, 10); + int err; + + err = kstrtoul(buf, 10, &bit); + if (err) + return err; if (bit & ~1) return -EINVAL; @@ -652,13 +720,16 @@ static const struct attribute_group gl520_group = { .attrs = gl520_attributes, }; -static struct attribute *gl520_attributes_opt[] = { +static struct attribute *gl520_attributes_in4[] = { &sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in4_beep.dev_attr.attr, + NULL +}; +static struct attribute *gl520_attributes_temp2[] = { &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, @@ -667,8 +738,12 @@ static struct attribute *gl520_attributes_opt[] = { NULL }; -static const struct attribute_group gl520_group_opt = { - .attrs = gl520_attributes_opt, +static const struct attribute_group gl520_group_in4 = { + .attrs = gl520_attributes_in4, +}; + +static const struct attribute_group gl520_group_temp2 = { + .attrs = gl520_attributes_temp2, }; @@ -717,35 +792,17 @@ static int gl520_probe(struct i2c_client *client, gl520_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group))) + err = sysfs_create_group(&client->dev.kobj, &gl520_group); + if (err) goto exit_free; - if (data->two_temps) { - if ((err = device_create_file(&client->dev, - &sensor_dev_attr_temp2_input.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_temp2_max.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_temp2_max_hyst.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_temp2_alarm.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_temp2_beep.dev_attr))) - goto exit_remove_files; - } else { - if ((err = device_create_file(&client->dev, - &sensor_dev_attr_in4_input.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_in4_min.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_in4_max.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_in4_alarm.dev_attr)) - || (err = device_create_file(&client->dev, - &sensor_dev_attr_in4_beep.dev_attr))) - goto exit_remove_files; - } + if (data->two_temps) + err = sysfs_create_group(&client->dev.kobj, &gl520_group_temp2); + else + err = sysfs_create_group(&client->dev.kobj, &gl520_group_in4); + if (err) + goto exit_remove_files; data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -757,7 +814,8 @@ static int gl520_probe(struct i2c_client *client, exit_remove_files: sysfs_remove_group(&client->dev.kobj, &gl520_group); - sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); + sysfs_remove_group(&client->dev.kobj, &gl520_group_in4); + sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2); exit_free: kfree(data); exit: @@ -809,15 +867,18 @@ static int gl520_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl520_group); - sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); + sysfs_remove_group(&client->dev.kobj, &gl520_group_in4); + sysfs_remove_group(&client->dev.kobj, &gl520_group_temp2); kfree(data); return 0; } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention */ +/* + * Registers 0x07 to 0x0c are word-sized, others are byte-sized + * GL520 uses a high-byte first convention + */ static int gl520_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) @@ -849,7 +910,8 @@ static struct gl520_data *gl520_update_device(struct device *dev) data->alarms = gl520_read_value(client, GL520_REG_ALARMS); data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; + data->vid = gl520_read_value(client, + GL520_REG_VID_INPUT) & 0x1f; for (i = 0; i < 4; i++) { data->in_input[i] = gl520_read_value(client, @@ -910,23 +972,10 @@ static struct gl520_data *gl520_update_device(struct device *dev) return data; } - -static int __init sensors_gl520sm_init(void) -{ - return i2c_add_driver(&gl520_driver); -} - -static void __exit sensors_gl520sm_exit(void) -{ - i2c_del_driver(&gl520_driver); -} - +module_i2c_driver(gl520_driver); MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " "Kyösti Mälkki <kmalkki@cc.hut.fi>, " "Maarten Deprez <maartendeprez@users.sourceforge.net>"); MODULE_DESCRIPTION("GL520SM driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_gl520sm_init); -module_exit(sensors_gl520sm_exit); diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 932da8a5aaf4..9f26400713f0 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -40,7 +40,7 @@ * available at http://developer.intel.com/. * * AMD Athlon 64 and AMD Opteron Processors, AMD Publication 26094, - * http://support.amd.com/us/Processor_TechDocs/26094.PDF + * http://support.amd.com/us/Processor_TechDocs/26094.PDF * Table 74. VID Code Voltages * This corresponds to an arbitrary VRM code of 24 in the functions below. * These CPU models (K8 revision <= E) have 5 VID pins. See also: @@ -83,27 +83,27 @@ int vid_from_reg(int val, u8 vrm) { int vid; - switch(vrm) { + switch (vrm) { - case 100: /* VRD 10.0 */ + case 100: /* VRD 10.0 */ /* compute in uV, round to mV */ val &= 0x3f; - if((val & 0x1f) == 0x1f) + if ((val & 0x1f) == 0x1f) return 0; - if((val & 0x1f) <= 0x09 || val == 0x0a) + if ((val & 0x1f) <= 0x09 || val == 0x0a) vid = 1087500 - (val & 0x1f) * 25000; else vid = 1862500 - (val & 0x1f) * 25000; - if(val & 0x20) + if (val & 0x20) vid -= 12500; - return((vid + 500) / 1000); + return (vid + 500) / 1000; case 110: /* Intel Conroe */ /* compute in uV, round to mV */ val &= 0xff; if (val < 0x02 || val > 0xb2) return 0; - return((1600000 - (val - 2) * 6250 + 500) / 1000); + return (1600000 - (val - 2) * 6250 + 500) / 1000; case 24: /* Athlon64 & Opteron */ val &= 0x1f; @@ -118,38 +118,38 @@ int vid_from_reg(int val, u8 vrm) case 91: /* VRM 9.1 */ case 90: /* VRM 9.0 */ val &= 0x1f; - return(val == 0x1f ? 0 : - 1850 - val * 25); + return val == 0x1f ? 0 : + 1850 - val * 25; case 85: /* VRM 8.5 */ val &= 0x1f; - return((val & 0x10 ? 25 : 0) + + return (val & 0x10 ? 25 : 0) + ((val & 0x0f) > 0x04 ? 2050 : 1250) - - ((val & 0x0f) * 50)); + ((val & 0x0f) * 50); case 84: /* VRM 8.4 */ val &= 0x0f; /* fall through */ case 82: /* VRM 8.2 */ val &= 0x1f; - return(val == 0x1f ? 0 : + return val == 0x1f ? 0 : val & 0x10 ? 5100 - (val) * 100 : - 2050 - (val) * 50); + 2050 - (val) * 50; case 17: /* Intel IMVP-II */ val &= 0x1f; - return(val & 0x10 ? 975 - (val & 0xF) * 25 : - 1750 - val * 50); + return val & 0x10 ? 975 - (val & 0xF) * 25 : + 1750 - val * 50; case 13: case 131: val &= 0x3f; /* Exception for Eden ULV 500 MHz */ if (vrm == 131 && val == 0x3f) val++; - return(1708 - val * 16); + return 1708 - val * 16; case 14: /* Intel Core */ /* compute in uV, round to mV */ val &= 0x7f; - return(val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000); + return val > 0x77 ? 0 : (1500000 - (val * 12500) + 500) / 1000; default: /* report 0 for unknown */ if (vrm) pr_warn("Requested unsupported VRM version (%u)\n", @@ -157,7 +157,7 @@ int vid_from_reg(int val, u8 vrm) return 0; } } - +EXPORT_SYMBOL(vid_from_reg); /* * After this point is the code to automatically determine which @@ -166,9 +166,10 @@ int vid_from_reg(int val, u8 vrm) struct vrm_model { u8 vendor; - u8 eff_family; - u8 eff_model; - u8 eff_stepping; + u8 family; + u8 model_from; + u8 model_to; + u8 stepping_to; u8 vrm_type; }; @@ -177,42 +178,52 @@ struct vrm_model { #ifdef CONFIG_X86 /* - * The stepping parameter is highest acceptable stepping for current line. + * The stepping_to parameter is highest acceptable stepping for current line. * The model match must be exact for 4-bit values. For model values 0x10 * and above (extended model), all models below the parameter will match. */ static struct vrm_model vrm_models[] = { - {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */ - {X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */ - /* In theory, all NPT family 0Fh processors have 6 VID pins and should - thus use vrm 25, however in practice not all mainboards route the - 6th VID pin because it is never needed. So we use the 5 VID pin - variant (vrm 24) for the models which exist today. */ - {X86_VENDOR_AMD, 0xF, 0x7F, ANY, 24}, /* NPT family 0Fh */ - {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* future fam. 0Fh */ - {X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */ - - {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ - {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ - {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ - {X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14}, /* Intel Core (65 nm) */ - {X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110}, /* Intel Conroe */ - {X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */ - {X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */ - {X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */ - {X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */ - {X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */ - - {X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */ - {X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */ - {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nehemiah */ - {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */ - {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */ - {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7-M, C7, Eden (Esther) */ - {X86_VENDOR_CENTAUR, 0x6, 0xD, ANY, 134}, /* C7-D, C7-M, C7, Eden (Esther) */ - - {X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */ + {X86_VENDOR_AMD, 0x6, 0x0, ANY, ANY, 90}, /* Athlon Duron etc */ + {X86_VENDOR_AMD, 0xF, 0x0, 0x3F, ANY, 24}, /* Athlon 64, Opteron */ + /* + * In theory, all NPT family 0Fh processors have 6 VID pins and should + * thus use vrm 25, however in practice not all mainboards route the + * 6th VID pin because it is never needed. So we use the 5 VID pin + * variant (vrm 24) for the models which exist today. + */ + {X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24}, /* NPT family 0Fh */ + {X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25}, /* future fam. 0Fh */ + {X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25}, /* NPT family 10h */ + + {X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82}, /* Pentium Pro, + * Pentium II, Xeon, + * Mobile Pentium, + * Celeron */ + {X86_VENDOR_INTEL, 0x6, 0x7, 0x7, ANY, 84}, /* Pentium III, Xeon */ + {X86_VENDOR_INTEL, 0x6, 0x8, 0x8, ANY, 82}, /* Pentium III, Xeon */ + {X86_VENDOR_INTEL, 0x6, 0x9, 0x9, ANY, 13}, /* Pentium M (130 nm) */ + {X86_VENDOR_INTEL, 0x6, 0xA, 0xA, ANY, 82}, /* Pentium III Xeon */ + {X86_VENDOR_INTEL, 0x6, 0xB, 0xB, ANY, 85}, /* Tualatin */ + {X86_VENDOR_INTEL, 0x6, 0xD, 0xD, ANY, 13}, /* Pentium M (90 nm) */ + {X86_VENDOR_INTEL, 0x6, 0xE, 0xE, ANY, 14}, /* Intel Core (65 nm) */ + {X86_VENDOR_INTEL, 0x6, 0xF, ANY, ANY, 110}, /* Intel Conroe and + * later */ + {X86_VENDOR_INTEL, 0xF, 0x0, 0x0, ANY, 90}, /* P4 */ + {X86_VENDOR_INTEL, 0xF, 0x1, 0x1, ANY, 90}, /* P4 Willamette */ + {X86_VENDOR_INTEL, 0xF, 0x2, 0x2, ANY, 90}, /* P4 Northwood */ + {X86_VENDOR_INTEL, 0xF, 0x3, ANY, ANY, 100}, /* Prescott and above + * assume VRD 10 */ + + {X86_VENDOR_CENTAUR, 0x6, 0x7, 0x7, ANY, 85}, /* Eden ESP/Ezra */ + {X86_VENDOR_CENTAUR, 0x6, 0x8, 0x8, 0x7, 85}, /* Ezra T */ + {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x9, 0x7, 85}, /* Nehemiah */ + {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x9, ANY, 17}, /* C3-M, Eden-N */ + {X86_VENDOR_CENTAUR, 0x6, 0xA, 0xA, 0x7, 0}, /* No information */ + {X86_VENDOR_CENTAUR, 0x6, 0xA, 0xA, ANY, 13}, /* C7-M, C7, + * Eden (Esther) */ + {X86_VENDOR_CENTAUR, 0x6, 0xD, 0xD, ANY, 134}, /* C7-D, C7-M, C7, + * Eden (Esther) */ }; /* @@ -248,20 +259,17 @@ static u8 get_via_model_d_vrm(void) } } -static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor) +static u8 find_vrm(u8 family, u8 model, u8 stepping, u8 vendor) { - int i = 0; - - while (vrm_models[i].vendor!=X86_VENDOR_UNKNOWN) { - if (vrm_models[i].vendor==vendor) - if ((vrm_models[i].eff_family==eff_family) - && ((vrm_models[i].eff_model==eff_model) || - (vrm_models[i].eff_model >= 0x10 && - eff_model <= vrm_models[i].eff_model) || - (vrm_models[i].eff_model==ANY)) && - (eff_stepping <= vrm_models[i].eff_stepping)) - return vrm_models[i].vrm_type; - i++; + int i; + + for (i = 0; i < ARRAY_SIZE(vrm_models); i++) { + if (vendor == vrm_models[i].vendor && + family == vrm_models[i].family && + model >= vrm_models[i].model_from && + model <= vrm_models[i].model_to && + stepping <= vrm_models[i].stepping_to) + return vrm_models[i].vrm_type; } return 0; @@ -270,21 +278,12 @@ static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor) u8 vid_which_vrm(void) { struct cpuinfo_x86 *c = &cpu_data(0); - u32 eax; - u8 eff_family, eff_model, eff_stepping, vrm_ret; + u8 vrm_ret; if (c->x86 < 6) /* Any CPU with family lower than 6 */ - return 0; /* doesn't have VID and/or CPUID */ - - eax = cpuid_eax(1); - eff_family = ((eax & 0x00000F00)>>8); - eff_model = ((eax & 0x000000F0)>>4); - eff_stepping = eax & 0xF; - if (eff_family == 0xF) { /* use extended model & family */ - eff_family += ((eax & 0x00F00000)>>20); - eff_model += ((eax & 0x000F0000)>>16)<<4; - } - vrm_ret = find_vrm(eff_family, eff_model, eff_stepping, c->x86_vendor); + return 0; /* doesn't have VID */ + + vrm_ret = find_vrm(c->x86, c->x86_model, c->x86_mask, c->x86_vendor); if (vrm_ret == 134) vrm_ret = get_via_model_d_vrm(); if (vrm_ret == 0) @@ -300,8 +299,6 @@ u8 vid_which_vrm(void) return 0; } #endif - -EXPORT_SYMBOL(vid_from_reg); EXPORT_SYMBOL(vid_which_vrm); MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>"); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 6460487e41b5..c3c471ca202f 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -1,14 +1,14 @@ /* - hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring - - This file defines the sysfs class "hwmon", for use by sensors drivers. - - Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. -*/ + * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring + * + * This file defines the sysfs class "hwmon", for use by sensors drivers. + * + * Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -55,6 +55,7 @@ struct device *hwmon_device_register(struct device *dev) return hwdev; } +EXPORT_SYMBOL_GPL(hwmon_device_register); /** * hwmon_device_unregister - removes the previously registered class device @@ -72,6 +73,7 @@ void hwmon_device_unregister(struct device *dev) dev_dbg(dev->parent, "hwmon_device_unregister() failed: bad class ID!\n"); } +EXPORT_SYMBOL_GPL(hwmon_device_unregister); static void __init hwmon_pci_quirks(void) { @@ -119,9 +121,6 @@ static void __exit hwmon_exit(void) subsys_initcall(hwmon_init); module_exit(hwmon_exit); -EXPORT_SYMBOL_GPL(hwmon_device_register); -EXPORT_SYMBOL_GPL(hwmon_device_unregister); - MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index d22f241b6a67..a18882cc073d 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -159,8 +159,12 @@ static ssize_t store_amb_min(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i5k_amb_data *data = dev_get_drvdata(dev); - unsigned long temp = simple_strtoul(buf, NULL, 10) / 500; + unsigned long temp; + int ret = kstrtoul(buf, 10, &temp); + if (ret < 0) + return ret; + temp = temp / 500; if (temp > 255) temp = 255; @@ -175,8 +179,12 @@ static ssize_t store_amb_mid(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i5k_amb_data *data = dev_get_drvdata(dev); - unsigned long temp = simple_strtoul(buf, NULL, 10) / 500; + unsigned long temp; + int ret = kstrtoul(buf, 10, &temp); + if (ret < 0) + return ret; + temp = temp / 500; if (temp > 255) temp = 255; @@ -191,8 +199,12 @@ static ssize_t store_amb_max(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i5k_amb_data *data = dev_get_drvdata(dev); - unsigned long temp = simple_strtoul(buf, NULL, 10) / 500; + unsigned long temp; + int ret = kstrtoul(buf, 10, &temp); + if (ret < 0) + return ret; + temp = temp / 500; if (temp > 255) temp = 255; diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index cc2981f749a6..37f17e0d9d5d 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -1045,7 +1045,7 @@ static struct aem_ro_sensor_template aem2_ro_sensors[] = { {"power6_average", aem2_show_pcap_value, POWER_CAP_MIN_WARNING}, {"power7_average", aem2_show_pcap_value, POWER_CAP_MIN}, -{"power3_average", aem2_show_pcap_value, POWER_AUX}, +{"power3_average", aem2_show_pcap_value, POWER_AUX}, {"power_cap", aem2_show_pcap_value, POWER_CAP}, {NULL, NULL, 0}, }; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0054d6f9cec9..0b204e4cf51c 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -176,12 +176,16 @@ static bool fix_pwm_polarity; #define IT87_REG_ALARM2 0x02 #define IT87_REG_ALARM3 0x03 -/* The IT8718F and IT8720F have the VID value in a different register, in - Super-I/O configuration space. */ +/* + * The IT8718F and IT8720F have the VID value in a different register, in + * Super-I/O configuration space. + */ #define IT87_REG_VID 0x0a -/* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b - for fan divisors. Later IT8712F revisions must use 16-bit tachometer - mode. */ +/* + * The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b + * for fan divisors. Later IT8712F revisions must use 16-bit tachometer + * mode. + */ #define IT87_REG_FAN_DIV 0x0b #define IT87_REG_FAN_16BIT 0x0c @@ -227,8 +231,10 @@ struct it87_sio_data { u8 skip_pwm; }; -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* + * For each registered chip, we need to keep some data in memory. + * The structure is dynamically allocated. + */ struct it87_data { struct device *hwmon_dev; enum chips type; @@ -259,14 +265,16 @@ struct it87_data { u8 fan_main_ctrl; /* Register value */ u8 fan_ctl; /* Register value */ - /* The following 3 arrays correspond to the same registers up to + /* + * The following 3 arrays correspond to the same registers up to * the IT8720F. The meaning of bits 6-0 depends on the value of bit * 7, and we want to preserve settings on mode changes, so we have * to track all values separately. * Starting with the IT8721F, the manual PWM duty cycles are stored * in separate registers (8-bit values), so the separate tracking * is no longer needed, but it is still done to keep the driver - * simple. */ + * simple. + */ u8 pwm_ctrl[3]; /* Register value */ u8 pwm_duty[3]; /* Manual PWM value set by user */ u8 pwm_temp_map[3]; /* PWM to temp. chan. mapping (bits 1-0) */ @@ -388,9 +396,11 @@ static const unsigned int pwm_freq[8] = { static inline int has_16bit_fans(const struct it87_data *data) { - /* IT8705F Datasheet 0.4.1, 3h == Version G. - IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. - These are the first revisions with 16bit tachometer support. */ + /* + * IT8705F Datasheet 0.4.1, 3h == Version G. + * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. + * These are the first revisions with 16-bit tachometer support. + */ return (data->type == it87 && data->revision >= 0x03) || (data->type == it8712 && data->revision >= 0x08) || data->type == it8716 @@ -402,9 +412,11 @@ static inline int has_16bit_fans(const struct it87_data *data) static inline int has_old_autopwm(const struct it87_data *data) { - /* The old automatic fan speed control interface is implemented - by IT8705F chips up to revision F and IT8712F chips up to - revision G. */ + /* + * The old automatic fan speed control interface is implemented + * by IT8705F chips up to revision F and IT8712F chips up to + * revision G. + */ return (data->type == it87 && data->revision < 0x03) || (data->type == it8712 && data->revision < 0x08); } @@ -606,10 +618,8 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - u8 reg = data->sensor; /* In case the value is updated while - we use it */ + u8 reg = data->sensor; /* In case value is updated while used */ if (reg & (1 << nr)) return sprintf(buf, "3\n"); /* thermal diode */ @@ -894,8 +904,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); if (has_newer_autopwm(data)) { - /* If we are in automatic mode, the PWM duty cycle register - * is read-only so we can't write the value */ + /* + * If we are in automatic mode, the PWM duty cycle register + * is read-only so we can't write the value. + */ if (data->pwm_ctrl[nr] & 0x80) { mutex_unlock(&data->update_lock); return -EBUSY; @@ -905,8 +917,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_duty[nr]); } else { data->pwm_duty[nr] = pwm_to_reg(data, val); - /* If we are in manual mode, write the duty cycle immediately; - * otherwise, just store it for later use. */ + /* + * If we are in manual mode, write the duty cycle immediately; + * otherwise, just store it for later use. + */ if (!(data->pwm_ctrl[nr] & 0x80)) { data->pwm_ctrl[nr] = data->pwm_duty[nr]; it87_write_value(data, IT87_REG_PWM(nr), @@ -965,8 +979,10 @@ static ssize_t set_pwm_temp_map(struct device *dev, long val; u8 reg; - /* This check can go away if we ever support automatic fan speed - control on newer chips. */ + /* + * This check can go away if we ever support automatic fan speed + * control on newer chips. + */ if (!has_old_autopwm(data)) { dev_notice(dev, "Mapping change disabled for safety reasons\n"); return -EINVAL; @@ -991,8 +1007,10 @@ static ssize_t set_pwm_temp_map(struct device *dev, mutex_lock(&data->update_lock); data->pwm_temp_map[nr] = reg; - /* If we are in automatic mode, write the temp mapping immediately; - * otherwise, just store it for later use. */ + /* + * If we are in automatic mode, write the temp mapping immediately; + * otherwise, just store it for later use. + */ if (data->pwm_ctrl[nr] & 0x80) { data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); @@ -1162,9 +1180,11 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, return count; } -/* We want to use the same sysfs file names as 8-bit fans, but we need - different variable names, so we have to use SENSOR_ATTR instead of - SENSOR_DEVICE_ATTR. */ +/* + * We want to use the same sysfs file names as 8-bit fans, but we need + * different variable names, so we have to use SENSOR_ATTR instead of + * SENSOR_DEVICE_ATTR. + */ #define show_fan16_offset(offset) \ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \ = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \ @@ -1321,12 +1341,12 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_label(struct device *dev, struct device_attribute *attr, char *buf) { - static const char *labels[] = { + static const char * const labels[] = { "+5V", "5VSB", "Vbat", }; - static const char *labels_it8721[] = { + static const char * const labels_it8721[] = { "+3.3V", "3VSB", "Vbat", @@ -1736,12 +1756,14 @@ static int __init it87_find(unsigned short *address, if (board_vendor && board_name) { if (strcmp(board_vendor, "nVIDIA") == 0 && strcmp(board_name, "FN68PT") == 0) { - /* On the Shuttle SN68PT, FAN_CTL2 is apparently not - connected to a fan, but to something else. One user - has reported instant system power-off when changing - the PWM2 duty cycle, so we disable it. - I use the board name string as the trigger in case - the same board is ever used in other systems. */ + /* + * On the Shuttle SN68PT, FAN_CTL2 is apparently not + * connected to a fan, but to something else. One user + * has reported instant system power-off when changing + * the PWM2 duty cycle, so we disable it. + * I use the board name string as the trigger in case + * the same board is ever used in other systems. + */ pr_info("Disabling pwm2 due to hardware constraints\n"); sio_data->skip_pwm = (1 << 1); } @@ -1793,7 +1815,7 @@ static int __devinit it87_probe(struct platform_device *pdev) int err = 0, i; int enable_pwm_interface; int fan_beep_need_rw; - static const char *names[] = { + static const char * const names[] = { "it87", "it8712", "it8716", @@ -1879,9 +1901,11 @@ static int __devinit it87_probe(struct platform_device *pdev) if (!fan_beep_need_rw) continue; - /* As we have a single beep enable bit for all fans, + /* + * As we have a single beep enable bit for all fans, * only the first enabled fan has a writable attribute - * for it. */ + * for it. + */ if (sysfs_chmod_file(&dev->kobj, it87_attributes_fan_beep[i], S_IRUGO | S_IWUSR)) @@ -1961,18 +1985,22 @@ static int __devexit it87_remove(struct platform_device *pdev) return 0; } -/* Must be called with data->update_lock held, except during initialization. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. */ +/* + * Must be called with data->update_lock held, except during initialization. + * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, + * would slow down the IT87 access and should not be necessary. + */ static int it87_read_value(struct it87_data *data, u8 reg) { outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); return inb_p(data->addr + IT87_DATA_REG_OFFSET); } -/* Must be called with data->update_lock held, except during initialization. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. */ +/* + * Must be called with data->update_lock held, except during initialization. + * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, + * would slow down the IT87 access and should not be necessary. + */ static void it87_write_value(struct it87_data *data, u8 reg, u8 value) { outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); @@ -1983,15 +2011,19 @@ static void it87_write_value(struct it87_data *data, u8 reg, u8 value) static int __devinit it87_check_pwm(struct device *dev) { struct it87_data *data = dev_get_drvdata(dev); - /* Some BIOSes fail to correctly configure the IT87 fans. All fans off + /* + * Some BIOSes fail to correctly configure the IT87 fans. All fans off * and polarity set to active low is sign that this is the case so we - * disable pwm control to protect the user. */ + * disable pwm control to protect the user. + */ int tmp = it87_read_value(data, IT87_REG_FAN_CTL); if ((tmp & 0x87) == 0) { if (fix_pwm_polarity) { - /* The user asks us to attempt a chip reconfiguration. + /* + * The user asks us to attempt a chip reconfiguration. * This means switching to active high polarity and - * inverting all fan speed values. */ + * inverting all fan speed values. + */ int i; u8 pwm[3]; @@ -1999,10 +2031,12 @@ static int __devinit it87_check_pwm(struct device *dev) pwm[i] = it87_read_value(data, IT87_REG_PWM(i)); - /* If any fan is in automatic pwm mode, the polarity + /* + * If any fan is in automatic pwm mode, the polarity * might be correct, as suspicious as it seems, so we * better don't change anything (but still disable the - * PWM interface). */ + * PWM interface). + */ if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { dev_info(dev, "Reconfiguring PWM to " "active high polarity\n"); @@ -2038,7 +2072,8 @@ static void __devinit it87_init_device(struct platform_device *pdev) int tmp, i; u8 mask; - /* For each PWM channel: + /* + * For each PWM channel: * - If it is in automatic mode, setting to manual mode should set * the fan to full speed by default. * - If it is in manual mode, we need a mapping to temperature @@ -2048,18 +2083,21 @@ static void __devinit it87_init_device(struct platform_device *pdev) * prior to switching to a different mode. * Note that this is no longer needed for the IT8721F and later, as * these have separate registers for the temperature mapping and the - * manual duty cycle. */ + * manual duty cycle. + */ for (i = 0; i < 3; i++) { data->pwm_temp_map[i] = i; data->pwm_duty[i] = 0x7f; /* Full speed */ data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */ } - /* Some chips seem to have default value 0xff for all limit + /* + * Some chips seem to have default value 0xff for all limit * registers. For low voltage limits it makes no sense and triggers * alarms, so change to 0 instead. For high temperature limits, it * means -1 degree C, which surprisingly doesn't trigger an alarm, - * but is still confusing, so change to 127 degrees C. */ + * but is still confusing, so change to 127 degrees C. + */ for (i = 0; i < 8; i++) { tmp = it87_read_value(data, IT87_REG_VIN_MIN(i)); if (tmp == 0xff) @@ -2071,10 +2109,12 @@ static void __devinit it87_init_device(struct platform_device *pdev) it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127); } - /* Temperature channels are not forcibly enabled, as they can be + /* + * Temperature channels are not forcibly enabled, as they can be * set to two different sensor types and we can't guess which one * is correct for a given system. These channels can be enabled at - * run-time through the temp{1-3}_type sysfs accessors if needed. */ + * run-time through the temp{1-3}_type sysfs accessors if needed. + */ /* Check if voltage monitors are reset manually or by some reason */ tmp = it87_read_value(data, IT87_REG_VIN_ENABLE); @@ -2157,8 +2197,10 @@ static struct it87_data *it87_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { if (update_vbat) { - /* Cleared after each update, so reenable. Value - returned by this read will be previous value */ + /* + * Cleared after each update, so reenable. Value + * returned by this read will be previous value + */ it87_write_value(data, IT87_REG_CONFIG, it87_read_value(data, IT87_REG_CONFIG) | 0x40); } @@ -2220,13 +2262,17 @@ static struct it87_data *it87_update_device(struct device *dev) it87_update_pwm_ctrl(data, i); data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); - /* The 8705 does not have VID capability. - The 8718 and later don't use IT87_REG_VID for the - same purpose. */ + /* + * The IT8705F does not have VID capability. + * The IT8718F and later don't use IT87_REG_VID for the + * same purpose. + */ if (data->type == it8712 || data->type == it8716) { data->vid = it87_read_value(data, IT87_REG_VID); - /* The older IT8712F revisions had only 5 VID pins, - but we assume it is always safe to read 6 bits. */ + /* + * The older IT8712F revisions had only 5 VID pins, + * but we assume it is always safe to read 6 bits. + */ data->vid &= 0x3f; } data->last_updated = jiffies; diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index b927ee5ccdd7..a9bfd6736d9a 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -180,25 +180,7 @@ static int jc42_remove(struct i2c_client *client); static struct jc42_data *jc42_update_device(struct device *dev); static const struct i2c_device_id jc42_id[] = { - { "adt7408", 0 }, - { "at30ts00", 0 }, - { "cat94ts02", 0 }, - { "cat6095", 0 }, { "jc42", 0 }, - { "max6604", 0 }, - { "mcp9804", 0 }, - { "mcp9805", 0 }, - { "mcp98242", 0 }, - { "mcp98243", 0 }, - { "mcp9843", 0 }, - { "se97", 0 }, - { "se97b", 0 }, - { "se98", 0 }, - { "stts424", 0 }, - { "stts2002", 0 }, - { "stts3000", 0 }, - { "tse2002", 0 }, - { "ts3000", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, jc42_id); @@ -350,8 +332,10 @@ set(temp_min, JC42_REG_TEMP_LOWER); set(temp_max, JC42_REG_TEMP_UPPER); set(temp_crit, JC42_REG_TEMP_CRITICAL); -/* JC42.4 compliant chips only support four hysteresis values. - * Pick best choice and go from there. */ +/* + * JC42.4 compliant chips only support four hysteresis values. + * Pick best choice and go from there. + */ static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -467,20 +451,19 @@ static const struct attribute_group jc42_group = { }; /* Return 0 if detection is successful, -ENODEV otherwise */ -static int jc42_detect(struct i2c_client *new_client, - struct i2c_board_info *info) +static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info) { - struct i2c_adapter *adapter = new_client->adapter; + struct i2c_adapter *adapter = client->adapter; int i, config, cap, manid, devid; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - cap = i2c_smbus_read_word_swapped(new_client, JC42_REG_CAP); - config = i2c_smbus_read_word_swapped(new_client, JC42_REG_CONFIG); - manid = i2c_smbus_read_word_swapped(new_client, JC42_REG_MANID); - devid = i2c_smbus_read_word_swapped(new_client, JC42_REG_DEVICEID); + cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP); + config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG); + manid = i2c_smbus_read_word_swapped(client, JC42_REG_MANID); + devid = i2c_smbus_read_word_swapped(client, JC42_REG_DEVICEID); if (cap < 0 || config < 0 || manid < 0 || devid < 0) return -ENODEV; @@ -499,47 +482,42 @@ static int jc42_detect(struct i2c_client *new_client, return -ENODEV; } -static int jc42_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct jc42_data *data; int config, cap, err; + struct device *dev = &client->dev; - data = kzalloc(sizeof(struct jc42_data), GFP_KERNEL); - if (!data) { - err = -ENOMEM; - goto exit; - } + data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL); + if (!data) + return -ENOMEM; - i2c_set_clientdata(new_client, data); + i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - cap = i2c_smbus_read_word_swapped(new_client, JC42_REG_CAP); - if (cap < 0) { - err = -EINVAL; - goto exit_free; - } + cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP); + if (cap < 0) + return cap; + data->extended = !!(cap & JC42_CAP_RANGE); - config = i2c_smbus_read_word_swapped(new_client, JC42_REG_CONFIG); - if (config < 0) { - err = -EINVAL; - goto exit_free; - } + config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG); + if (config < 0) + return config; + data->orig_config = config; if (config & JC42_CFG_SHUTDOWN) { config &= ~JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(new_client, JC42_REG_CONFIG, - config); + i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config); } data->config = config; /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &jc42_group); + err = sysfs_create_group(&dev->kobj, &jc42_group); if (err) - goto exit_free; + return err; - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; @@ -548,10 +526,7 @@ static int jc42_probe(struct i2c_client *new_client, return 0; exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &jc42_group); -exit_free: - kfree(data); -exit: + sysfs_remove_group(&dev->kobj, &jc42_group); return err; } @@ -563,7 +538,6 @@ static int jc42_remove(struct i2c_client *client) if (data->config != data->orig_config) i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, data->orig_config); - kfree(data); return 0; } @@ -614,19 +588,8 @@ abort: return ret; } -static int __init sensors_jc42_init(void) -{ - return i2c_add_driver(&jc42_driver); -} - -static void __exit sensors_jc42_exit(void) -{ - i2c_del_driver(&jc42_driver); -} +module_i2c_driver(jc42_driver); MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_DESCRIPTION("JC42 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_jc42_init); -module_exit(sensors_jc42_exit); diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 41aa6a319870..aba29d63f195 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -205,7 +205,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -static const struct pci_device_id k10temp_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index b923bc2307ad..575101988751 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -46,7 +46,7 @@ struct k8temp_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */ + u8 sensorsp; /* sensor presence bits - SEL_CORE, SEL_PLACE */ u32 temp[2][2]; /* core, place */ u8 swap_core_select; /* meaning of SEL_CORE is inverted */ u32 temp_offset; @@ -63,7 +63,7 @@ static struct k8temp_data *k8temp_update_device(struct device *dev) if (!data->valid || time_after(jiffies, data->last_updated + HZ)) { pci_read_config_byte(pdev, REG_TEMP, &tmp); - tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ + tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ pci_write_config_byte(pdev, REG_TEMP, tmp); pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]); @@ -82,7 +82,7 @@ static struct k8temp_data *k8temp_update_device(struct device *dev) &data->temp[1][0]); if (data->sensorsp & SEL_PLACE) { - tmp |= SEL_PLACE; /* Select sensor 1, core1 */ + tmp |= SEL_PLACE; /* Select sensor 1, core1 */ pci_write_config_byte(pdev, REG_TEMP, tmp); pci_read_config_dword(pdev, REG_TEMP, &data->temp[1][1]); @@ -136,7 +136,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0); static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -static const struct pci_device_id k8temp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(k8temp_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, { 0 }, }; @@ -183,7 +183,8 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, u8 model, stepping; struct k8temp_data *data; - if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit; } @@ -217,7 +218,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, data->temp_offset = 21000; pci_read_config_byte(pdev, REG_TEMP, &scfg); - scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ + scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ pci_write_config_byte(pdev, REG_TEMP, scfg); pci_read_config_byte(pdev, REG_TEMP, &scfg); @@ -238,7 +239,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, REG_TEMP, scfg); pci_read_config_dword(pdev, REG_TEMP, &temp); scfg |= SEL_CORE; /* prepare for next selection */ - if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */ + if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is unlikely */ data->sensorsp &= ~SEL_PLACE; } @@ -246,7 +247,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */ pci_write_config_byte(pdev, REG_TEMP, scfg); pci_read_config_dword(pdev, REG_TEMP, &temp); - if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */ + if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is unlikely */ data->sensorsp &= ~SEL_CORE; } diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index 58eded27f385..d264937c7f5e 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -448,7 +448,7 @@ static int pem_probe(struct i2c_client *client, | I2C_FUNC_SMBUS_WRITE_BYTE)) return -ENODEV; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -462,11 +462,11 @@ static int pem_probe(struct i2c_client *client, ret = pem_read_block(client, PEM_READ_FIRMWARE_REV, data->firmware_rev, sizeof(data->firmware_rev)); if (ret < 0) - goto out_kfree; + return ret; ret = i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS); if (ret < 0) - goto out_kfree; + return ret; dev_info(&client->dev, "Firmware revision %d.%d.%d\n", data->firmware_rev[0], data->firmware_rev[1], @@ -475,7 +475,7 @@ static int pem_probe(struct i2c_client *client, /* Register sysfs hooks */ ret = sysfs_create_group(&client->dev.kobj, &pem_group); if (ret) - goto out_kfree; + return ret; /* * Check if input readings are supported. @@ -534,8 +534,6 @@ out_remove_groups: sysfs_remove_group(&client->dev.kobj, &pem_input_group); sysfs_remove_group(&client->dev.kobj, &pem_fan_group); sysfs_remove_group(&client->dev.kobj, &pem_group); -out_kfree: - kfree(data); return ret; } @@ -549,7 +547,6 @@ static int pem_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &pem_fan_group); sysfs_remove_group(&client->dev.kobj, &pem_group); - kfree(data); return 0; } @@ -568,19 +565,8 @@ static struct i2c_driver pem_driver = { .id_table = pem_id, }; -static int __init pem_init(void) -{ - return i2c_add_driver(&pem_driver); -} - -static void __exit pem_exit(void) -{ - i2c_del_driver(&pem_driver); -} +module_i2c_driver(pem_driver); MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_DESCRIPTION("Lineage CPL PEM hardware monitoring driver"); MODULE_LICENSE("GPL"); - -module_init(pem_init); -module_exit(pem_exit); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 5e6457a6644d..15c05cc83e2c 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -1119,19 +1119,8 @@ static struct lm63_data *lm63_update_device(struct device *dev) return data; } -static int __init sensors_lm63_init(void) -{ - return i2c_add_driver(&lm63_driver); -} - -static void __exit sensors_lm63_exit(void) -{ - i2c_del_driver(&lm63_driver); -} +module_i2c_driver(lm63_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("LM63 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm63_init); -module_exit(sensors_lm63_exit); diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index c274ea25d899..472f79521a96 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -57,7 +57,7 @@ static ssize_t lm70_sense_temp(struct device *dev, struct spi_device *spi = to_spi_device(dev); int status, val = 0; u8 rxbuf[2]; - s16 raw=0; + s16 raw = 0; struct lm70 *p_lm70 = spi_get_drvdata(spi); if (mutex_lock_interruptible(&p_lm70->lock)) @@ -156,6 +156,15 @@ static int __devinit lm70_probe(struct spi_device *spi) mutex_init(&p_lm70->lock); p_lm70->chip = chip; + spi_set_drvdata(spi, p_lm70); + + status = device_create_file(&spi->dev, &dev_attr_temp1_input); + if (status) + goto out_dev_create_temp_file_failed; + status = device_create_file(&spi->dev, &dev_attr_name); + if (status) + goto out_dev_create_file_failed; + /* sysfs hook */ p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); if (IS_ERR(p_lm70->hwmon_dev)) { @@ -163,20 +172,14 @@ static int __devinit lm70_probe(struct spi_device *spi) status = PTR_ERR(p_lm70->hwmon_dev); goto out_dev_reg_failed; } - spi_set_drvdata(spi, p_lm70); - - if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input)) - || (status = device_create_file(&spi->dev, &dev_attr_name))) { - dev_dbg(&spi->dev, "device_create_file failure.\n"); - goto out_dev_create_file_failed; - } return 0; +out_dev_reg_failed: + device_remove_file(&spi->dev, &dev_attr_name); out_dev_create_file_failed: device_remove_file(&spi->dev, &dev_attr_temp1_input); - hwmon_device_unregister(p_lm70->hwmon_dev); -out_dev_reg_failed: +out_dev_create_temp_file_failed: spi_set_drvdata(spi, NULL); kfree(p_lm70); return status; @@ -186,9 +189,9 @@ static int __devexit lm70_remove(struct spi_device *spi) { struct lm70 *p_lm70 = spi_get_drvdata(spi); + hwmon_device_unregister(p_lm70->hwmon_dev); device_remove_file(&spi->dev, &dev_attr_temp1_input); device_remove_file(&spi->dev, &dev_attr_name); - hwmon_device_unregister(p_lm70->hwmon_dev); spi_set_drvdata(spi, NULL); kfree(p_lm70); @@ -213,18 +216,7 @@ static struct spi_driver lm70_driver = { .remove = __devexit_p(lm70_remove), }; -static int __init init_lm70(void) -{ - return spi_register_driver(&lm70_driver); -} - -static void __exit cleanup_lm70(void) -{ - spi_unregister_driver(&lm70_driver); -} - -module_init(init_lm70); -module_exit(cleanup_lm70); +module_spi_driver(lm70_driver); MODULE_AUTHOR("Kaiwan N Billimoria"); MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver"); diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 9c8093c4b307..8fa2632cbbaf 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -194,21 +194,8 @@ static struct i2c_driver lm73_driver = { .address_list = normal_i2c, }; -/* module glue */ - -static int __init sensors_lm73_init(void) -{ - return i2c_add_driver(&lm73_driver); -} - -static void __exit sensors_lm73_exit(void) -{ - i2c_del_driver(&lm73_driver); -} +module_i2c_driver(lm73_driver); MODULE_AUTHOR("Guillaume Ligneul <guillaume.ligneul@gmail.com>"); MODULE_DESCRIPTION("LM73 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm73_init); -module_exit(sensors_lm73_exit); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index b3311b1d3d92..a83f206af244 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -438,23 +438,8 @@ abort: return ret; } -/*-----------------------------------------------------------------------*/ - -/* module glue */ - -static int __init sensors_lm75_init(void) -{ - return i2c_add_driver(&lm75_driver); -} - -static void __exit sensors_lm75_exit(void) -{ - i2c_del_driver(&lm75_driver); -} +module_i2c_driver(lm75_driver); MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); MODULE_DESCRIPTION("LM75 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm75_init); -module_exit(sensors_lm75_exit); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 8dfc6782d596..0fca8613e7d8 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -1,29 +1,29 @@ /* - lm77.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2004 Andras BALI <drewie@freemail.hu> - - Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>. The LM77 - is a temperature sensor and thermal window comparator with 0.5 deg - resolution made by National Semiconductor. Complete datasheet can be - obtained at their site: - http://www.national.com/pf/LM/LM77.html - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * lm77.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (c) 2004 Andras BALI <drewie@freemail.hu> + * + * Heavily based on lm75.c by Frodo Looijaard <frodol@dds.nl>. The LM77 + * is a temperature sensor and thermal window comparator with 0.5 deg + * resolution made by National Semiconductor. Complete datasheet can be + * obtained at their site: + * http://www.national.com/pf/LM/LM77.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -49,7 +49,7 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, /* Each client has this additional data */ struct lm77_data { - struct device *hwmon_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ @@ -95,8 +95,10 @@ static struct i2c_driver lm77_driver = { #define LM77_TEMP_MIN (-55000) #define LM77_TEMP_MAX 125000 -/* In the temperature registers, the low 3 bits are not part of the - temperature values; they are the status bits. */ +/* + * In the temperature registers, the low 3 bits are not part of the + * temperature values; they are the status bits. + */ static inline s16 LM77_TEMP_TO_REG(int temp) { int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); @@ -112,7 +114,9 @@ static inline int LM77_TEMP_FROM_REG(s16 reg) /* read routines for temperature limits */ #define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ struct lm77_data *data = lm77_update_device(dev); \ return sprintf(buf, "%d\n", data->value); \ @@ -124,17 +128,20 @@ show(temp_min); show(temp_max); /* read routines for hysteresis values */ -static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_crit_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm77_data *data = lm77_update_device(dev); return sprintf(buf, "%d\n", data->temp_crit - data->temp_hyst); } -static ssize_t show_temp_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm77_data *data = lm77_update_device(dev); return sprintf(buf, "%d\n", data->temp_min + data->temp_hyst); } -static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_max_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm77_data *data = lm77_update_device(dev); return sprintf(buf, "%d\n", data->temp_max - data->temp_hyst); @@ -142,29 +149,42 @@ static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute *a /* write routines */ #define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm77_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->value = val; \ - lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm77_data *data = i2c_get_clientdata(client); \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err) \ + return err; \ + \ + mutex_lock(&data->update_lock); \ + data->value = val; \ + lm77_write_value(client, reg, LM77_TEMP_TO_REG(data->value)); \ + mutex_unlock(&data->update_lock); \ + return count; \ } set(temp_min, LM77_REG_TEMP_MIN); set(temp_max, LM77_REG_TEMP_MAX); -/* hysteresis is stored as a relative value on the chip, so it has to be - converted first */ -static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +/* + * hysteresis is stored as a relative value on the chip, so it has to be + * converted first + */ +static ssize_t set_temp_crit_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_hyst = data->temp_crit - val; @@ -175,13 +195,19 @@ static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *a } /* preserve hysteresis when setting T_crit */ -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm77_data *data = i2c_get_clientdata(client); - long val = simple_strtoul(buf, NULL, 10); int oldcrithyst; - + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); oldcrithyst = data->temp_crit - data->temp_hyst; data->temp_crit = val; @@ -251,17 +277,19 @@ static int lm77_detect(struct i2c_client *new_client, I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - /* Here comes the remaining detection. Since the LM77 has no - register dedicated to identification, we have to rely on the - following tricks: - - 1. the high 4 bits represent the sign and thus they should - always be the same - 2. the high 3 bits are unused in the configuration register - 3. addresses 0x06 and 0x07 return the last read value - 4. registers cycling over 8-address boundaries - - Word-sized registers are high-byte first. */ + /* + * Here comes the remaining detection. Since the LM77 has no + * register dedicated to identification, we have to rely on the + * following tricks: + * + * 1. the high 4 bits represent the sign and thus they should + * always be the same + * 2. the high 3 bits are unused in the configuration register + * 3. addresses 0x06 and 0x07 return the last read value + * 4. registers cycling over 8-address boundaries + * + * Word-sized registers are high-byte first. + */ /* addresses cycling */ cur = i2c_smbus_read_word_data(new_client, 0); @@ -330,7 +358,8 @@ static int lm77_probe(struct i2c_client *new_client, lm77_init_client(new_client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group))) + err = sysfs_create_group(&new_client->dev.kobj, &lm77_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&new_client->dev); @@ -358,8 +387,10 @@ static int lm77_remove(struct i2c_client *client) return 0; } -/* All registers are word-sized, except for the configuration register. - The LM77 uses the high-byte first convention. */ +/* + * All registers are word-sized, except for the configuration register. + * The LM77 uses the high-byte first convention. + */ static u16 lm77_read_value(struct i2c_client *client, u8 reg) { if (reg == LM77_REG_CONF) @@ -420,19 +451,8 @@ static struct lm77_data *lm77_update_device(struct device *dev) return data; } -static int __init sensors_lm77_init(void) -{ - return i2c_add_driver(&lm77_driver); -} - -static void __exit sensors_lm77_exit(void) -{ - i2c_del_driver(&lm77_driver); -} +module_i2c_driver(lm77_driver); MODULE_AUTHOR("Andras BALI <drewie@freemail.hu>"); MODULE_DESCRIPTION("LM77 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm77_init); -module_exit(sensors_lm77_exit); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 6df0b4681710..f6bc414e1e91 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -1,23 +1,23 @@ /* - lm78.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> - Copyright (c) 2007, 2011 Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * lm78.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + * Copyright (c) 2007, 2011 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -74,11 +74,15 @@ enum chips { lm78, lm79 }; #define LM78_REG_I2C_ADDR 0x48 -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. */ +/* + * Conversions. Rounding and limit checking is only done on the TO_REG + * variants. + */ -/* IN: mV, (0V to 4.08V) - REG: 16mV/bit */ +/* + * IN: mV (0V to 4.08V) + * REG: 16mV/bit + */ static inline u8 IN_TO_REG(unsigned long val) { unsigned long nval = SENSORS_LIMIT(val, 0, 4080); @@ -95,15 +99,17 @@ static inline u8 FAN_TO_REG(long rpm, int div) static inline int FAN_FROM_REG(u8 val, int div) { - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); + return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div); } -/* TEMP: mC (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: mC (-128C to +127C) + * REG: 1C/bit, two's complement + */ static inline s8 TEMP_TO_REG(int val) { int nval = SENSORS_LIMIT(val, -128000, 127000) ; - return nval<0 ? (nval-500)/1000 : (nval+500)/1000; + return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000; } static inline int TEMP_FROM_REG(s8 val) @@ -177,8 +183,13 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); int nr = attr->index; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val); @@ -192,8 +203,13 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *da, { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); int nr = attr->index; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val); @@ -201,7 +217,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *da, mutex_unlock(&data->update_lock); return count; } - + #define show_in_offset(offset) \ static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in, NULL, offset); \ @@ -237,7 +253,12 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct lm78_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_over = TEMP_TO_REG(val); @@ -257,7 +278,12 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct lm78_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_hyst = TEMP_TO_REG(val); @@ -280,7 +306,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *da, struct lm78_data *data = lm78_update_device(dev); int nr = attr->index; return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); + DIV_FROM_REG(data->fan_div[nr]))); } static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, @@ -289,8 +315,8 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = lm78_update_device(dev); int nr = attr->index; - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])) ); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); } static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, @@ -299,7 +325,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = dev_get_drvdata(dev); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -316,29 +347,44 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct lm78_data *data = dev_get_drvdata(dev); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long min; u8 reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; + case 1: + data->fan_div[nr] = 0; + break; + case 2: + data->fan_div[nr] = 1; + break; + case 4: + data->fan_div[nr] = 2; + break; + case 8: + data->fan_div[nr] = 3; + break; default: dev_err(dev, "fan_div value %ld not " "supported. Choose one of 1, 2, 4 or 8!\n", val); @@ -484,8 +530,10 @@ static struct platform_device *pdev; static unsigned short isa_address = 0x290; -/* I2C devices get this name attribute automatically, but for ISA devices - we must create it by ourselves. */ +/* + * I2C devices get this name attribute automatically, but for ISA devices + * we must create it by ourselves. + */ static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -515,8 +563,10 @@ static int lm78_alias_detect(struct i2c_client *client, u8 chipid) if ((lm78_read_value(isa, LM78_REG_CHIPID) & 0xfe) != (chipid & 0xfe)) return 0; /* Chip type doesn't match */ - /* We compare all the limit registers, the config register and the - * interrupt mask registers */ + /* + * We compare all the limit registers, the config register and the + * interrupt mask registers + */ for (i = 0x2b; i <= 0x3d; i++) { if (lm78_read_value(isa, i) != i2c_smbus_read_byte_data(client, i)) @@ -558,9 +608,11 @@ static int lm78_i2c_detect(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - /* We block updates of the ISA device to minimize the risk of - concurrent access to the same LM78 chip through different - interfaces. */ + /* + * We block updates of the ISA device to minimize the risk of + * concurrent access to the same LM78 chip through different + * interfaces. + */ if (isa) mutex_lock(&isa->update_lock); @@ -669,11 +721,13 @@ static struct i2c_driver lm78_driver = { .address_list = normal_i2c, }; -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. */ +/* + * The SMBus locks itself, but ISA access must be locked explicitly! + * We don't want to lock the whole ISA bus, so we lock each client + * separately. + * We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + * would slow down the LM78 access and should not be necessary. + */ static int lm78_read_value(struct lm78_data *data, u8 reg) { struct i2c_client *client = data->client; @@ -691,13 +745,6 @@ static int lm78_read_value(struct lm78_data *data, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) { struct i2c_client *client = data->client; @@ -823,8 +870,11 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev) lm78_init_device(data); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group)) - || (err = device_create_file(&pdev->dev, &dev_attr_name))) + err = sysfs_create_group(&pdev->dev.kobj, &lm78_group); + if (err) + goto exit_remove_files; + err = device_create_file(&pdev->dev, &dev_attr_name); + if (err) goto exit_remove_files; data->hwmon_dev = hwmon_device_register(&pdev->dev); @@ -876,9 +926,11 @@ static int __init lm78_isa_found(unsigned short address) int val, save, found = 0; int port; - /* Some boards declare base+0 to base+7 as a PNP device, some base+4 + /* + * Some boards declare base+0 to base+7 as a PNP device, some base+4 * to base+7 and some base+5 to base+6. So we better request each port - * individually for the probing phase. */ + * individually for the probing phase. + */ for (port = address; port < address + LM78_EXTENT; port++) { if (!request_region(port, 1, "lm78")) { pr_debug("Failed to request port 0x%x\n", port); @@ -887,8 +939,10 @@ static int __init lm78_isa_found(unsigned short address) } #define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like - chips. But only if we read 'undefined' registers. */ + /* + * We need the timeouts for at least some LM78-like + * chips. But only if we read 'undefined' registers. + */ val = inb_p(address + 1); if (inb_p(address + 2) != val || inb_p(address + 3) != val @@ -896,8 +950,10 @@ static int __init lm78_isa_found(unsigned short address) goto release; #undef REALLY_SLOW_IO - /* We should be able to change the 7 LSB of the address port. The - MSB (busy flag) should be clear initially, set after the write. */ + /* + * We should be able to change the 7 LSB of the address port. The + * MSB (busy flag) should be clear initially, set after the write. + */ save = inb_p(address + LM78_ADDR_REG_OFFSET); if (save & 0x80) goto release; @@ -1036,8 +1092,10 @@ static int __init sm_lm78_init(void) { int res; - /* We register the ISA device first, so that we can skip the - * registration of an I2C interface to the same device. */ + /* + * We register the ISA device first, so that we can skip the + * registration of an I2C interface to the same device. + */ res = lm78_isa_register(); if (res) goto exit; diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 0891b38ffec0..e2c43e1774be 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -1,8 +1,8 @@ /* * lm80.c - From lm_sensors, Linux kernel modules for hardware - * monitoring + * monitoring * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> - * and Philip Edelbrock <phil@netroedge.com> + * and Philip Edelbrock <phil@netroedge.com> * * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org> * @@ -60,11 +60,17 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, #define LM80_REG_FANDIV 0x05 #define LM80_REG_RES 0x06 +#define LM96080_REG_CONV_RATE 0x07 +#define LM96080_REG_MAN_ID 0x3e +#define LM96080_REG_DEV_ID 0x3f -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ + +/* + * Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + * Fixing this is just not worth it. + */ #define IN_TO_REG(val) (SENSORS_LIMIT(((val) + 5) / 10, 0, 255)) #define IN_FROM_REG(val) ((val) * 10) @@ -108,6 +114,7 @@ static inline long TEMP_FROM_REG(u16 temp) struct lm80_data { struct device *hwmon_dev; struct mutex update_lock; + char error; /* !=0 if error occurred during last update */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -144,6 +151,7 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); static const struct i2c_device_id lm80_id[] = { { "lm80", 0 }, + { "lm96080", 1 }, { } }; MODULE_DEVICE_TABLE(i2c, lm80_id); @@ -170,6 +178,8 @@ static ssize_t show_in_##suffix(struct device *dev, \ { \ int nr = to_sensor_dev_attr(attr)->index; \ struct lm80_data *data = lm80_update_device(dev); \ + if (IS_ERR(data)) \ + return PTR_ERR(data); \ return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \ } show_in(min, in_min) @@ -183,7 +193,10 @@ static ssize_t set_in_##suffix(struct device *dev, \ int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err < 0) \ + return err; \ \ mutex_lock(&data->update_lock);\ data->value[nr] = IN_TO_REG(val); \ @@ -200,6 +213,8 @@ static ssize_t show_fan_##suffix(struct device *dev, \ { \ int nr = to_sensor_dev_attr(attr)->index; \ struct lm80_data *data = lm80_update_device(dev); \ + if (IS_ERR(data)) \ + return PTR_ERR(data); \ return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \ DIV_FROM_REG(data->fan_div[nr]))); \ } @@ -211,6 +226,8 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, { int nr = to_sensor_dev_attr(attr)->index; struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } @@ -220,7 +237,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm80_data *data = i2c_get_clientdata(client); - long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err = kstrtoul(buf, 10, &val); + if (err < 0) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -229,18 +249,23 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, return count; } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm80_data *data = i2c_get_clientdata(client); - unsigned long min, val = simple_strtoul(buf, NULL, 10); + unsigned long min, val; u8 reg; + int err = kstrtoul(buf, 10, &val); + if (err < 0) + return err; /* Save fan_min */ mutex_lock(&data->update_lock); @@ -283,6 +308,8 @@ static ssize_t show_temp_input1(struct device *dev, struct device_attribute *attr, char *buf) { struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); } @@ -291,6 +318,8 @@ static ssize_t show_temp_##suffix(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct lm80_data *data = lm80_update_device(dev); \ + if (IS_ERR(data)) \ + return PTR_ERR(data); \ return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ } show_temp(hot_max, temp_hot_max); @@ -304,7 +333,10 @@ static ssize_t set_temp_##suffix(struct device *dev, \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm80_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err < 0) \ + return err; \ \ mutex_lock(&data->update_lock); \ data->value = TEMP_LIMIT_TO_REG(val); \ @@ -321,6 +353,8 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); return sprintf(buf, "%u\n", data->alarms); } @@ -329,6 +363,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, { int bitnr = to_sensor_dev_attr(attr)->index; struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } @@ -459,23 +495,44 @@ static const struct attribute_group lm80_group = { static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; - int i, cur; + int i, cur, man_id, dev_id; + const char *name = NULL; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0) + /* First check for unused bits, common to both chip types */ + if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0) + || (lm80_read_value(client, LM80_REG_CONFIG) & 0x80)) return -ENODEV; - for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(client, i); - if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(client, i + 0x80) != cur) - || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur)) + + /* + * The LM96080 has manufacturer and stepping/die rev registers so we + * can just check that. The LM80 does not have such registers so we + * have to use a more expensive trick. + */ + man_id = lm80_read_value(client, LM96080_REG_MAN_ID); + dev_id = lm80_read_value(client, LM96080_REG_DEV_ID); + if (man_id == 0x01 && dev_id == 0x08) { + /* Check more unused bits for confirmation */ + if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe) return -ENODEV; + + name = "lm96080"; + } else { + /* Check 6-bit addressing */ + for (i = 0x2a; i <= 0x3d; i++) { + cur = i2c_smbus_read_byte_data(client, i); + if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur) + || (i2c_smbus_read_byte_data(client, i + 0x80) != cur) + || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur)) + return -ENODEV; + } + + name = "lm80"; } - strlcpy(info->type, "lm80", I2C_NAME_SIZE); + strlcpy(info->type, name, I2C_NAME_SIZE); return 0; } @@ -547,9 +604,11 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) /* Called when we have found a new LM80. */ static void lm80_init_client(struct i2c_client *client) { - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ + /* + * Reset all except Watchdog values and last conversion values + * This sets fan-divs to 2, among others. This makes most other + * initializations unnecessary + */ lm80_write_value(client, LM80_REG_CONFIG, 0x80); /* Set 11-bit temperature resolution */ lm80_write_value(client, LM80_REG_RES, 0x08); @@ -563,66 +622,116 @@ static struct lm80_data *lm80_update_device(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct lm80_data *data = i2c_get_clientdata(client); int i; + int rv; + int prev_rv; + struct lm80_data *ret = data; mutex_lock(&data->update_lock); + if (data->error) + lm80_init_client(client); + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { dev_dbg(&client->dev, "Starting lm80 update\n"); for (i = 0; i <= 6; i++) { - data->in[i] = - lm80_read_value(client, LM80_REG_IN(i)); - data->in_min[i] = - lm80_read_value(client, LM80_REG_IN_MIN(i)); - data->in_max[i] = - lm80_read_value(client, LM80_REG_IN_MAX(i)); + rv = lm80_read_value(client, LM80_REG_IN(i)); + if (rv < 0) + goto abort; + data->in[i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); + if (rv < 0) + goto abort; + data->in_min[i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); + if (rv < 0) + goto abort; + data->in_max[i] = rv; } - data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); - data->fan_min[0] = - lm80_read_value(client, LM80_REG_FAN_MIN(1)); - data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); - data->fan_min[1] = - lm80_read_value(client, LM80_REG_FAN_MIN(2)); - - data->temp = - (lm80_read_value(client, LM80_REG_TEMP) << 8) | - (lm80_read_value(client, LM80_REG_RES) & 0xf0); - data->temp_os_max = - lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - data->temp_os_hyst = - lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - data->temp_hot_max = - lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - data->temp_hot_hyst = - lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - - i = lm80_read_value(client, LM80_REG_FANDIV); - data->fan_div[0] = (i >> 2) & 0x03; - data->fan_div[1] = (i >> 4) & 0x03; - data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + - (lm80_read_value(client, LM80_REG_ALARM2) << 8); + + rv = lm80_read_value(client, LM80_REG_FAN1); + if (rv < 0) + goto abort; + data->fan[0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + if (rv < 0) + goto abort; + data->fan_min[0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN2); + if (rv < 0) + goto abort; + data->fan[1] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); + if (rv < 0) + goto abort; + data->fan_min[1] = rv; + + prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_RES); + if (rv < 0) + goto abort; + data->temp = (prev_rv << 8) | (rv & 0xf0); + + rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); + if (rv < 0) + goto abort; + data->temp_os_max = rv; + + rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); + if (rv < 0) + goto abort; + data->temp_os_hyst = rv; + + rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); + if (rv < 0) + goto abort; + data->temp_hot_max = rv; + + rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); + if (rv < 0) + goto abort; + data->temp_hot_hyst = rv; + + rv = lm80_read_value(client, LM80_REG_FANDIV); + if (rv < 0) + goto abort; + data->fan_div[0] = (rv >> 2) & 0x03; + data->fan_div[1] = (rv >> 4) & 0x03; + + prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_ALARM2); + if (rv < 0) + goto abort; + data->alarms = prev_rv + (rv << 8); + data->last_updated = jiffies; data->valid = 1; + data->error = 0; } + goto done; + +abort: + ret = ERR_PTR(rv); + data->valid = 0; + data->error = 1; +done: mutex_unlock(&data->update_lock); - return data; + return ret; } -static int __init sensors_lm80_init(void) -{ - return i2c_add_driver(&lm80_driver); -} - -static void __exit sensors_lm80_exit(void) -{ - i2c_del_driver(&lm80_driver); -} +module_i2c_driver(lm80_driver); MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " "Philip Edelbrock <phil@netroedge.com>"); MODULE_DESCRIPTION("LM80 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm80_init); -module_exit(sensors_lm80_exit); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 8290476aee4a..cd45b9d85584 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -124,7 +124,7 @@ static struct lm83_data *lm83_update_device(struct device *dev); /* * Driver data (common to all clients) */ - + static const struct i2c_device_id lm83_id[] = { { "lm83", lm83 }, { "lm82", lm82 }, @@ -179,8 +179,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm83_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; int nr = attr->index; + int err; + + err = kstrtol(buf, 10, &val); + if (err < 0) + return err; mutex_lock(&data->update_lock); data->temp[nr] = TEMP_TO_REG(val); @@ -355,12 +360,14 @@ static int lm83_probe(struct i2c_client *new_client, * declare 1 and 3 common, and then 2 and 4 only for the LM83. */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group))) + err = sysfs_create_group(&new_client->dev.kobj, &lm83_group); + if (err) goto exit_free; if (id->driver_data == lm83) { - if ((err = sysfs_create_group(&new_client->dev.kobj, - &lm83_group_opt))) + err = sysfs_create_group(&new_client->dev.kobj, + &lm83_group_opt); + if (err) goto exit_remove_files; } @@ -423,19 +430,8 @@ static struct lm83_data *lm83_update_device(struct device *dev) return data; } -static int __init sensors_lm83_init(void) -{ - return i2c_add_driver(&lm83_driver); -} - -static void __exit sensors_lm83_exit(void) -{ - i2c_del_driver(&lm83_driver); -} +module_i2c_driver(lm83_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("LM83 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm83_init); -module_exit(sensors_lm83_exit); diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index da72dc12068c..864c7d999e0c 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1,28 +1,28 @@ /* - lm85.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> - Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> - Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> - Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com> - Copyright (C) 2007--2009 Jean Delvare <khali@linux-fr.org> - - Chip details at <http://www.national.com/ds/LM/LM85.pdf> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * lm85.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + * Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> + * Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> + * Copyright (c) 2004 Justin Thiessen <jthiessen@penguincomputing.com> + * Copyright (C) 2007--2009 Jean Delvare <khali@linux-fr.org> + * + * Chip details at <http://www.national.com/ds/LM/LM85.pdf> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -46,88 +46,89 @@ enum chips { /* The LM85 registers */ -#define LM85_REG_IN(nr) (0x20 + (nr)) -#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) -#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) +#define LM85_REG_IN(nr) (0x20 + (nr)) +#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) +#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) -#define LM85_REG_TEMP(nr) (0x25 + (nr)) -#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) -#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) +#define LM85_REG_TEMP(nr) (0x25 + (nr)) +#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) +#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) /* Fan speeds are LSB, MSB (2 bytes) */ -#define LM85_REG_FAN(nr) (0x28 + (nr) * 2) -#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) * 2) +#define LM85_REG_FAN(nr) (0x28 + (nr) * 2) +#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) * 2) -#define LM85_REG_PWM(nr) (0x30 + (nr)) +#define LM85_REG_PWM(nr) (0x30 + (nr)) -#define LM85_REG_COMPANY 0x3e -#define LM85_REG_VERSTEP 0x3f +#define LM85_REG_COMPANY 0x3e +#define LM85_REG_VERSTEP 0x3f -#define ADT7468_REG_CFG5 0x7c -#define ADT7468_OFF64 (1 << 0) -#define ADT7468_HFPWM (1 << 1) -#define IS_ADT7468_OFF64(data) \ +#define ADT7468_REG_CFG5 0x7c +#define ADT7468_OFF64 (1 << 0) +#define ADT7468_HFPWM (1 << 1) +#define IS_ADT7468_OFF64(data) \ ((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64)) -#define IS_ADT7468_HFPWM(data) \ +#define IS_ADT7468_HFPWM(data) \ ((data)->type == adt7468 && !((data)->cfg5 & ADT7468_HFPWM)) /* These are the recognized values for the above regs */ -#define LM85_COMPANY_NATIONAL 0x01 -#define LM85_COMPANY_ANALOG_DEV 0x41 -#define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_GENERIC2 0x70 -#define LM85_VERSTEP_LM85C 0x60 -#define LM85_VERSTEP_LM85B 0x62 -#define LM85_VERSTEP_LM96000_1 0x68 -#define LM85_VERSTEP_LM96000_2 0x69 -#define LM85_VERSTEP_ADM1027 0x60 -#define LM85_VERSTEP_ADT7463 0x62 -#define LM85_VERSTEP_ADT7463C 0x6A -#define LM85_VERSTEP_ADT7468_1 0x71 -#define LM85_VERSTEP_ADT7468_2 0x72 -#define LM85_VERSTEP_EMC6D100_A0 0x60 -#define LM85_VERSTEP_EMC6D100_A1 0x61 -#define LM85_VERSTEP_EMC6D102 0x65 -#define LM85_VERSTEP_EMC6D103_A0 0x68 -#define LM85_VERSTEP_EMC6D103_A1 0x69 -#define LM85_VERSTEP_EMC6D103S 0x6A /* Also known as EMC6D103:A2 */ - -#define LM85_REG_CONFIG 0x40 - -#define LM85_REG_ALARM1 0x41 -#define LM85_REG_ALARM2 0x42 - -#define LM85_REG_VID 0x43 +#define LM85_COMPANY_NATIONAL 0x01 +#define LM85_COMPANY_ANALOG_DEV 0x41 +#define LM85_COMPANY_SMSC 0x5c +#define LM85_VERSTEP_VMASK 0xf0 +#define LM85_VERSTEP_GENERIC 0x60 +#define LM85_VERSTEP_GENERIC2 0x70 +#define LM85_VERSTEP_LM85C 0x60 +#define LM85_VERSTEP_LM85B 0x62 +#define LM85_VERSTEP_LM96000_1 0x68 +#define LM85_VERSTEP_LM96000_2 0x69 +#define LM85_VERSTEP_ADM1027 0x60 +#define LM85_VERSTEP_ADT7463 0x62 +#define LM85_VERSTEP_ADT7463C 0x6A +#define LM85_VERSTEP_ADT7468_1 0x71 +#define LM85_VERSTEP_ADT7468_2 0x72 +#define LM85_VERSTEP_EMC6D100_A0 0x60 +#define LM85_VERSTEP_EMC6D100_A1 0x61 +#define LM85_VERSTEP_EMC6D102 0x65 +#define LM85_VERSTEP_EMC6D103_A0 0x68 +#define LM85_VERSTEP_EMC6D103_A1 0x69 +#define LM85_VERSTEP_EMC6D103S 0x6A /* Also known as EMC6D103:A2 */ + +#define LM85_REG_CONFIG 0x40 + +#define LM85_REG_ALARM1 0x41 +#define LM85_REG_ALARM2 0x42 + +#define LM85_REG_VID 0x43 /* Automated FAN control */ -#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) -#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) -#define LM85_REG_AFAN_SPIKE1 0x62 -#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) -#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) -#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) -#define LM85_REG_AFAN_HYST1 0x6d -#define LM85_REG_AFAN_HYST2 0x6e - -#define ADM1027_REG_EXTEND_ADC1 0x76 -#define ADM1027_REG_EXTEND_ADC2 0x77 +#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) +#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) +#define LM85_REG_AFAN_SPIKE1 0x62 +#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) +#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) +#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) +#define LM85_REG_AFAN_HYST1 0x6d +#define LM85_REG_AFAN_HYST2 0x6e + +#define ADM1027_REG_EXTEND_ADC1 0x76 +#define ADM1027_REG_EXTEND_ADC2 0x77 #define EMC6D100_REG_ALARM3 0x7d /* IN5, IN6 and IN7 */ -#define EMC6D100_REG_IN(nr) (0x70 + ((nr) - 5)) -#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr) - 5) * 2) -#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr) - 5) * 2) -#define EMC6D102_REG_EXTEND_ADC1 0x85 -#define EMC6D102_REG_EXTEND_ADC2 0x86 -#define EMC6D102_REG_EXTEND_ADC3 0x87 -#define EMC6D102_REG_EXTEND_ADC4 0x88 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. +#define EMC6D100_REG_IN(nr) (0x70 + ((nr) - 5)) +#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr) - 5) * 2) +#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr) - 5) * 2) +#define EMC6D102_REG_EXTEND_ADC1 0x85 +#define EMC6D102_REG_EXTEND_ADC2 0x86 +#define EMC6D102_REG_EXTEND_ADC3 0x87 +#define EMC6D102_REG_EXTEND_ADC4 0x88 + + +/* + * Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. */ /* IN are scaled according to built-in resistors */ @@ -166,7 +167,8 @@ static inline u16 FAN_TO_REG(unsigned long val) #define PWM_FROM_REG(val) (val) -/* ZONEs have the following parameters: +/* + * ZONEs have the following parameters: * Limit (low) temp, 1. degC * Hysteresis (below limit), 1. degC (0-15) * Range of speed control, .1 degC (2-80) @@ -228,7 +230,8 @@ static int FREQ_FROM_REG(const int *map, u8 reg) return map[reg & 0x07]; } -/* Since we can't use strings, I'm abusing these numbers +/* + * Since we can't use strings, I'm abusing these numbers * to stand in for the following meanings: * 1 -- PWM responds to Zone 1 * 2 -- PWM responds to Zone 2 @@ -258,7 +261,8 @@ static int ZONE_TO_REG(int zone) #define HYST_TO_REG(val) SENSORS_LIMIT(((val) + 500) / 1000, 0, 15) #define HYST_FROM_REG(val) ((val) * 1000) -/* Chip sampling rates +/* + * Chip sampling rates * * Some sensors are not updated more frequently than once per second * so it doesn't make sense to read them more often than that. @@ -274,7 +278,8 @@ static int ZONE_TO_REG(int zone) #define LM85_DATA_INTERVAL (HZ + HZ / 2) #define LM85_CONFIG_INTERVAL (1 * 60 * HZ) -/* LM85 can automatically adjust fan speeds based on temperature +/* + * LM85 can automatically adjust fan speeds based on temperature * This structure encapsulates an entire Zone config. There are * three zones (one for each temperature input) on the lm85 */ @@ -283,7 +288,8 @@ struct lm85_zone { u8 hyst; /* Low limit hysteresis. (0-15) */ u8 range; /* Temp range, encoded */ s8 critical; /* "All fans ON" temp limit */ - u8 max_desired; /* Actual "max" temperature specified. Preserved + u8 max_desired; /* + * Actual "max" temperature specified. Preserved * to prevent "drift" as other autofan control * values change. */ @@ -295,8 +301,10 @@ struct lm85_autofan { u8 min_off; /* Min PWM or OFF below "limit", flag */ }; -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* + * For each registered chip, we need to keep some data in memory. + * The structure is dynamically allocated. + */ struct lm85_data { struct device *hwmon_dev; const int *freq_map; @@ -391,7 +399,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val); @@ -443,7 +456,14 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lm85_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + data->vrm = val; return count; } @@ -500,7 +520,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm[nr] = PWM_TO_REG(val); @@ -537,8 +562,13 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); u8 config; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; switch (val) { case 0: @@ -548,8 +578,10 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute config = 7; break; case 2: - /* Here we have to choose arbitrarily one of the 5 possible - configurations; I go for the safest */ + /* + * Here we have to choose arbitrarily one of the 5 possible + * configurations; I go for the safest + */ config = 6; break; default: @@ -588,12 +620,19 @@ static ssize_t set_pwm_freq(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - /* The ADT7468 has a special high-frequency PWM output mode, + /* + * The ADT7468 has a special high-frequency PWM output mode, * where all PWM outputs are driven by a 22.5 kHz clock. - * This might confuse the user, but there's not much we can do. */ + * This might confuse the user, but there's not much we can do. + */ if (data->type == adt7468 && val >= 11300) { /* High freq. mode */ data->cfg5 &= ~ADT7468_HFPWM; lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5); @@ -648,7 +687,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = INS_TO_REG(nr, val); @@ -671,7 +715,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = INS_TO_REG(nr, val); @@ -722,7 +771,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; if (IS_ADT7468_OFF64(data)) val += 64; @@ -748,7 +802,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; if (IS_ADT7468_OFF64(data)) val += 64; @@ -789,7 +848,12 @@ static ssize_t set_pwm_auto_channels(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->autofan[nr].config = (data->autofan[nr].config & (~0xe0)) @@ -814,7 +878,12 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->autofan[nr].min_pwm = PWM_TO_REG(val); @@ -838,8 +907,13 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); u8 tmp; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->autofan[nr].min_off = val; @@ -885,7 +959,12 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); int min; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); min = TEMP_FROM_REG(data->zone[nr].limit); @@ -916,7 +995,12 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->zone[nr].limit = TEMP_TO_REG(val); @@ -951,7 +1035,12 @@ static ssize_t set_temp_auto_temp_max(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); int min; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); min = TEMP_FROM_REG(data->zone[nr].limit); @@ -979,7 +1068,12 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->zone[nr].critical = TEMP_TO_REG(val); @@ -1338,24 +1432,28 @@ static int lm85_probe(struct i2c_client *client, goto err_remove_files; } - /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used - as a sixth digital VID input rather than an analog input. */ + /* + * The ADT7463/68 have an optional VRM 10 mode where pin 21 is used + * as a sixth digital VID input rather than an analog input. + */ if (data->type == adt7463 || data->type == adt7468) { u8 vid = lm85_read_value(client, LM85_REG_VID); if (vid & 0x80) data->has_vid5 = true; } - if (!data->has_vid5) - if ((err = sysfs_create_group(&client->dev.kobj, - &lm85_group_in4))) + if (!data->has_vid5) { + err = sysfs_create_group(&client->dev.kobj, &lm85_group_in4); + if (err) goto err_remove_files; + } /* The EMC6D100 has 3 additional voltage inputs */ - if (data->type == emc6d100) - if ((err = sysfs_create_group(&client->dev.kobj, - &lm85_group_in567))) + if (data->type == emc6d100) { + err = sysfs_create_group(&client->dev.kobj, &lm85_group_in567); + if (err) goto err_remove_files; + } data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -1443,7 +1541,8 @@ static struct lm85_data *lm85_update_device(struct device *dev) /* Things that change quickly */ dev_dbg(&client->dev, "Reading sensor values\n"); - /* Have to read extended bits first to "freeze" the + /* + * Have to read extended bits first to "freeze" the * more significant bits that are read later. * There are 2 additional resolution bits per channel and we * have room for 4, so we shift them to the left. @@ -1503,9 +1602,10 @@ static struct lm85_data *lm85_update_device(struct device *dev) EMC6D100_REG_ALARM3) << 16; } else if (data->type == emc6d102 || data->type == emc6d103 || data->type == emc6d103s) { - /* Have to read LSB bits after the MSB ones because - the reading of the MSB bits has frozen the - LSBs (backward from the ADM1027). + /* + * Have to read LSB bits after the MSB ones because + * the reading of the MSB bits has frozen the + * LSBs (backward from the ADM1027). */ int ext1 = lm85_read_value(client, EMC6D102_REG_EXTEND_ADC1); @@ -1611,22 +1711,10 @@ static struct lm85_data *lm85_update_device(struct device *dev) return data; } - -static int __init sm_lm85_init(void) -{ - return i2c_add_driver(&lm85_driver); -} - -static void __exit sm_lm85_exit(void) -{ - i2c_del_driver(&lm85_driver); -} +module_i2c_driver(lm85_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, " "Margit Schubert-While <margitsw@t-online.de>, " "Justin Thiessen <jthiessen@penguincomputing.com>"); MODULE_DESCRIPTION("LM85-B, LM85-C driver"); - -module_init(sm_lm85_init); -module_exit(sm_lm85_exit); diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index f1e6e7512ffa..314d147bf1ac 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -119,20 +119,21 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; * The LM87 uses signed 8-bit values for temperatures. */ -#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) -#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ +#define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192) +#define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \ (val) * 192 >= (scale) * 255 ? 255 : \ - ((val) * 192 + (scale)/2) / (scale)) + ((val) * 192 + (scale) / 2) / (scale)) #define TEMP_FROM_REG(reg) ((reg) * 1000) #define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \ (val) >= 126500 ? 127 : \ - (((val) < 0 ? (val)-500 : (val)+500) / 1000)) + (((val) < 0 ? (val) - 500 : \ + (val) + 500) / 1000)) -#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ - (1350000 + (reg)*(div) / 2) / ((reg)*(div))) -#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ - (1350000 + (val)*(div) / 2) / ((val)*(div))) +#define FAN_FROM_REG(reg, div) ((reg) == 255 || (reg) == 0 ? 0 : \ + (1350000 + (reg)*(div) / 2) / ((reg) * (div))) +#define FAN_TO_REG(val, div) ((val) * (div) * 255 <= 1350000 ? 255 : \ + (1350000 + (val)*(div) / 2) / ((val) * (div))) #define FAN_DIV_FROM_REG(reg) (1 << (reg)) @@ -149,41 +150,6 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; #define CHAN_NO_VID (1 << 7) /* - * Functions declaration - */ - -static int lm87_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm87_detect(struct i2c_client *new_client, - struct i2c_board_info *info); -static void lm87_init_client(struct i2c_client *client); -static int lm87_remove(struct i2c_client *client); -static struct lm87_data *lm87_update_device(struct device *dev); - -/* - * Driver data (common to all clients) - */ - -static const struct i2c_device_id lm87_id[] = { - { "lm87", lm87 }, - { "adm1024", adm1024 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm87_id); - -static struct i2c_driver lm87_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm87", - }, - .probe = lm87_probe, - .remove = lm87_remove, - .id_table = lm87_id, - .detect = lm87_detect, - .address_list = normal_i2c, -}; - -/* * Client data (each client gets its own) */ @@ -217,10 +183,6 @@ struct lm87_data { u8 vrm; }; -/* - * Sysfs stuff - */ - static inline int lm87_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -231,79 +193,168 @@ static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value); } -#define show_in(offset) \ -static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - data->in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - data->in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - data->in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in##offset##_input, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); -show_in(6); -show_in(7); - -static void set_in_min(struct device *dev, const char *buf, int nr) +static struct lm87_data *lm87_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + int i, j; + + dev_dbg(&client->dev, "Updating data.\n"); + + i = (data->channel & CHAN_TEMP3) ? 1 : 0; + j = (data->channel & CHAN_TEMP3) ? 5 : 6; + for (; i < j; i++) { + data->in[i] = lm87_read_value(client, + LM87_REG_IN(i)); + data->in_min[i] = lm87_read_value(client, + LM87_REG_IN_MIN(i)); + data->in_max[i] = lm87_read_value(client, + LM87_REG_IN_MAX(i)); + } + + for (i = 0; i < 2; i++) { + if (data->channel & CHAN_NO_FAN(i)) { + data->in[6+i] = lm87_read_value(client, + LM87_REG_AIN(i)); + data->in_max[6+i] = lm87_read_value(client, + LM87_REG_AIN_MAX(i)); + data->in_min[6+i] = lm87_read_value(client, + LM87_REG_AIN_MIN(i)); + + } else { + data->fan[i] = lm87_read_value(client, + LM87_REG_FAN(i)); + data->fan_min[i] = lm87_read_value(client, + LM87_REG_FAN_MIN(i)); + } + } + + j = (data->channel & CHAN_TEMP3) ? 3 : 2; + for (i = 0 ; i < j; i++) { + data->temp[i] = lm87_read_value(client, + LM87_REG_TEMP[i]); + data->temp_high[i] = lm87_read_value(client, + LM87_REG_TEMP_HIGH[i]); + data->temp_low[i] = lm87_read_value(client, + LM87_REG_TEMP_LOW[i]); + } + + i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); + j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); + data->temp_crit_int = min(i, j); + + i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); + j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); + data->temp_crit_ext = min(i, j); + + i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + data->vid = (i & 0x0F) + | (lm87_read_value(client, LM87_REG_VID4) & 0x01) + << 4; + + data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) + | (lm87_read_value(client, LM87_REG_ALARMS2) + << 8); + data->aout = lm87_read_value(client, LM87_REG_AOUT); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* + * Sysfs stuff + */ + +static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[nr], + data->in_scale[nr])); +} + +static ssize_t show_in_min(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[nr], + data->in_scale[nr])); +} + +static ssize_t show_in_max(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[nr], + data->in_scale[nr])); +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm87_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]); - lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) : - LM87_REG_AIN_MIN(nr-6), data->in_min[nr]); + lm87_write_value(client, nr < 6 ? LM87_REG_IN_MIN(nr) : + LM87_REG_AIN_MIN(nr - 6), data->in_min[nr]); mutex_unlock(&data->update_lock); + return count; } -static void set_in_max(struct device *dev, const char *buf, int nr) +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = to_sensor_dev_attr(attr)->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]); - lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) : - LM87_REG_AIN_MAX(nr-6), data->in_max[nr]); + lm87_write_value(client, nr < 6 ? LM87_REG_IN_MAX(nr) : + LM87_REG_AIN_MAX(nr - 6), data->in_max[nr]); mutex_unlock(&data->update_lock); + return count; } #define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_in_min(dev, buf, offset); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_in_max(dev, buf, offset); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in##offset##_max, set_in##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in_input, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset) set_in(0); set_in(1); set_in(2); @@ -313,80 +364,95 @@ set_in(5); set_in(6); set_in(7); -#define show_temp(offset) \ -static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \ -} \ -static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp##offset##_input, NULL); -show_temp(1); -show_temp(2); -show_temp(3); - -static void set_temp_low(struct device *dev, const char *buf, int nr) +static ssize_t show_temp_input(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); +} + +static ssize_t show_temp_low(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%d\n", + TEMP_FROM_REG(data->temp_low[nr])); +} + +static ssize_t show_temp_high(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%d\n", + TEMP_FROM_REG(data->temp_high[nr])); +} + +static ssize_t set_temp_low(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = to_sensor_dev_attr(attr)->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_low[nr] = TEMP_TO_REG(val); lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]); mutex_unlock(&data->update_lock); + return count; } -static void set_temp_high(struct device *dev, const char *buf, int nr) +static ssize_t set_temp_high(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = to_sensor_dev_attr(attr)->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_high[nr] = TEMP_TO_REG(val); lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]); mutex_unlock(&data->update_lock); + return count; } #define set_temp(offset) \ -static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_temp_low(dev, buf, offset-1); \ - return count; \ -} \ -static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - set_temp_high(dev, buf, offset-1); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_high, set_temp##offset##_high); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_low, set_temp##offset##_low); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp_input, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_high, set_temp_high, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_low, set_temp_low, offset - 1) set_temp(1); set_temp(2); set_temp(3); -static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_crit_int(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); } -static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_crit_ext(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); @@ -396,64 +462,95 @@ static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL); static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); -#define show_fan(offset) \ -static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \ - FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \ - FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \ -} \ -static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct lm87_data *data = lm87_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan##offset##_input, NULL); -show_fan(1); -show_fan(2); - -static void set_fan_min(struct device *dev, const char *buf, int nr) +static ssize_t show_fan_input(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + FAN_DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + FAN_DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int nr = to_sensor_dev_attr(attr)->index; + + return sprintf(buf, "%d\n", + FAN_DIV_FROM_REG(data->fan_div[nr])); +} + +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = to_sensor_dev_attr(attr)->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr])); lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); + return count; } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan clock divider. This follows the principle - of least surprise; the user doesn't expect the fan minimum to change just - because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, const char *buf, - size_t count, int nr) +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan clock divider. This follows the principle + * of least surprise; the user doesn't expect the fan minimum to change just + * because the divider changed. + */ +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = to_sensor_dev_attr(attr)->index; + long val; + int err; unsigned long min; u8 reg; + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], FAN_DIV_FROM_REG(data->fan_div[nr])); switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; + case 1: + data->fan_div[nr] = 0; + break; + case 2: + data->fan_div[nr] = 1; + break; + case 4: + data->fan_div[nr] = 2; + break; + case 8: + data->fan_div[nr] = 3; + break; default: mutex_unlock(&data->update_lock); return -EINVAL; @@ -479,61 +576,69 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, } #define set_fan(offset) \ -static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - set_fan_min(dev, buf, offset-1); \ - return count; \ -} \ -static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - return set_fan_div(dev, buf, count, offset-1); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan##offset##_min, set_fan##offset##_min); \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan##offset##_div, set_fan##offset##_div); +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_input, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ + show_fan_div, set_fan_div, offset - 1) set_fan(1); set_fan(2); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lm87_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + data->vrm = val; return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_aout(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_aout(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->aout = AOUT_TO_REG(val); @@ -571,31 +676,31 @@ static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15); */ static struct attribute *lm87_attributes[] = { - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_max.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, - &dev_attr_in2_input.attr, - &dev_attr_in2_min.attr, - &dev_attr_in2_max.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, &sensor_dev_attr_in2_alarm.dev_attr.attr, - &dev_attr_in3_input.attr, - &dev_attr_in3_min.attr, - &dev_attr_in3_max.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, &sensor_dev_attr_in3_alarm.dev_attr.attr, - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, &sensor_dev_attr_in4_alarm.dev_attr.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_min.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, &dev_attr_temp1_crit.attr, &sensor_dev_attr_temp1_alarm.dev_attr.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_min.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, &dev_attr_temp2_crit.attr, &sensor_dev_attr_temp2_alarm.dev_attr.attr, &sensor_dev_attr_temp2_fault.dev_attr.attr, @@ -610,70 +715,110 @@ static const struct attribute_group lm87_group = { .attrs = lm87_attributes, }; -static struct attribute *lm87_attributes_opt[] = { - &dev_attr_in6_input.attr, - &dev_attr_in6_min.attr, - &dev_attr_in6_max.attr, +static struct attribute *lm87_attributes_in6[] = { + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, &sensor_dev_attr_in6_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm87_group_in6 = { + .attrs = lm87_attributes_in6, +}; - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, +static struct attribute *lm87_attributes_fan1[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm87_group_fan1 = { + .attrs = lm87_attributes_fan1, +}; - &dev_attr_in7_input.attr, - &dev_attr_in7_min.attr, - &dev_attr_in7_max.attr, +static struct attribute *lm87_attributes_in7[] = { + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, &sensor_dev_attr_in7_alarm.dev_attr.attr, + NULL +}; - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, +static const struct attribute_group lm87_group_in7 = { + .attrs = lm87_attributes_in7, +}; + +static struct attribute *lm87_attributes_fan2[] = { + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm87_group_fan2 = { + .attrs = lm87_attributes_fan2, +}; - &dev_attr_temp3_input.attr, - &dev_attr_temp3_max.attr, - &dev_attr_temp3_min.attr, +static struct attribute *lm87_attributes_temp3[] = { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, &dev_attr_temp3_crit.attr, &sensor_dev_attr_temp3_alarm.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm87_group_temp3 = { + .attrs = lm87_attributes_temp3, +}; - &dev_attr_in0_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in0_max.attr, +static struct attribute *lm87_attributes_in0_5[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, &sensor_dev_attr_in0_alarm.dev_attr.attr, - &dev_attr_in5_input.attr, - &dev_attr_in5_min.attr, - &dev_attr_in5_max.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, &sensor_dev_attr_in5_alarm.dev_attr.attr, + NULL +}; +static const struct attribute_group lm87_group_in0_5 = { + .attrs = lm87_attributes_in0_5, +}; + +static struct attribute *lm87_attributes_vid[] = { &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, - NULL }; -static const struct attribute_group lm87_group_opt = { - .attrs = lm87_attributes_opt, +static const struct attribute_group lm87_group_vid = { + .attrs = lm87_attributes_vid, }; /* Return 0 if detection is successful, -ENODEV otherwise */ -static int lm87_detect(struct i2c_client *new_client, - struct i2c_board_info *info) +static int lm87_detect(struct i2c_client *client, struct i2c_board_info *info) { - struct i2c_adapter *adapter = new_client->adapter; + struct i2c_adapter *adapter = client->adapter; const char *name; u8 cid, rev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - if (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) + if (lm87_read_value(client, LM87_REG_CONFIG) & 0x80) return -ENODEV; /* Now, we do the remaining detection. */ - cid = lm87_read_value(new_client, LM87_REG_COMPANY_ID); - rev = lm87_read_value(new_client, LM87_REG_REVISION); + cid = lm87_read_value(client, LM87_REG_COMPANY_ID); + rev = lm87_read_value(client, LM87_REG_REVISION); if (cid == 0x02 /* National Semiconductor */ && (rev >= 0x01 && rev <= 0x08)) @@ -683,7 +828,7 @@ static int lm87_detect(struct i2c_client *new_client, name = "adm1024"; else { dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x\n", - new_client->addr); + client->addr); return -ENODEV; } @@ -692,8 +837,63 @@ static int lm87_detect(struct i2c_client *new_client, return 0; } -static int lm87_probe(struct i2c_client *new_client, - const struct i2c_device_id *id) +static void lm87_remove_files(struct i2c_client *client) +{ + struct device *dev = &client->dev; + + sysfs_remove_group(&dev->kobj, &lm87_group); + sysfs_remove_group(&dev->kobj, &lm87_group_in6); + sysfs_remove_group(&dev->kobj, &lm87_group_fan1); + sysfs_remove_group(&dev->kobj, &lm87_group_in7); + sysfs_remove_group(&dev->kobj, &lm87_group_fan2); + sysfs_remove_group(&dev->kobj, &lm87_group_temp3); + sysfs_remove_group(&dev->kobj, &lm87_group_in0_5); + sysfs_remove_group(&dev->kobj, &lm87_group_vid); +} + +static void lm87_init_client(struct i2c_client *client) +{ + struct lm87_data *data = i2c_get_clientdata(client); + + if (client->dev.platform_data) { + data->channel = *(u8 *)client->dev.platform_data; + lm87_write_value(client, + LM87_REG_CHANNEL_MODE, data->channel); + } else { + data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); + } + data->config = lm87_read_value(client, LM87_REG_CONFIG) & 0x6F; + + if (!(data->config & 0x01)) { + int i; + + /* Limits are left uninitialized after power-up */ + for (i = 1; i < 6; i++) { + lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); + lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); + } + for (i = 0; i < 2; i++) { + lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); + lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); + lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); + lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); + } + if (data->channel & CHAN_TEMP3) { + lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); + lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); + } else { + lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); + lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); + } + } + + /* Make sure Start is set and INT#_Clear is clear */ + if ((data->config & 0x09) != 0x01) + lm87_write_value(client, LM87_REG_CONFIG, + (data->config & 0x77) | 0x01); +} + +static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm87_data *data; int err; @@ -704,12 +904,12 @@ static int lm87_probe(struct i2c_client *new_client, goto exit; } - i2c_set_clientdata(new_client, data); + i2c_set_clientdata(client, data); data->valid = 0; mutex_init(&data->update_lock); /* Initialize the LM87 chip */ - lm87_init_client(new_client); + lm87_init_client(client); data->in_scale[0] = 2500; data->in_scale[1] = 2700; @@ -721,97 +921,48 @@ static int lm87_probe(struct i2c_client *new_client, data->in_scale[7] = 1875; /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group); + if (err) goto exit_free; if (data->channel & CHAN_NO_FAN(0)) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_in6_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in6_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in6_max)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_in6_alarm.dev_attr))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_in6); + if (err) goto exit_remove; } else { - if ((err = device_create_file(&new_client->dev, - &dev_attr_fan1_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan1_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan1_div)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_alarm.dev_attr))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_fan1); + if (err) goto exit_remove; } if (data->channel & CHAN_NO_FAN(1)) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_in7_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in7_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in7_max)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_in7_alarm.dev_attr))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_in7); + if (err) goto exit_remove; } else { - if ((err = device_create_file(&new_client->dev, - &dev_attr_fan2_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan2_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_fan2_div)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_alarm.dev_attr))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_fan2); + if (err) goto exit_remove; } if (data->channel & CHAN_TEMP3) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_temp3_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_max)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_crit)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_alarm.dev_attr)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_fault.dev_attr))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_temp3); + if (err) goto exit_remove; } else { - if ((err = device_create_file(&new_client->dev, - &dev_attr_in0_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in0_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in0_max)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_in0_alarm.dev_attr)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in5_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in5_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in5_max)) - || (err = device_create_file(&new_client->dev, - &sensor_dev_attr_in5_alarm.dev_attr))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_in0_5); + if (err) goto exit_remove; } if (!(data->channel & CHAN_NO_VID)) { data->vrm = vid_which_vrm(); - if ((err = device_create_file(&new_client->dev, - &dev_attr_cpu0_vid)) - || (err = device_create_file(&new_client->dev, - &dev_attr_vrm))) + err = sysfs_create_group(&client->dev.kobj, &lm87_group_vid); + if (err) goto exit_remove; } - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; @@ -820,162 +971,51 @@ static int lm87_probe(struct i2c_client *new_client, return 0; exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &lm87_group); - sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt); + lm87_remove_files(client); exit_free: - lm87_write_value(new_client, LM87_REG_CONFIG, data->config); + lm87_write_value(client, LM87_REG_CONFIG, data->config); kfree(data); exit: return err; } -static void lm87_init_client(struct i2c_client *client) -{ - struct lm87_data *data = i2c_get_clientdata(client); - - if (client->dev.platform_data) { - data->channel = *(u8 *)client->dev.platform_data; - lm87_write_value(client, - LM87_REG_CHANNEL_MODE, data->channel); - } else { - data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); - } - data->config = lm87_read_value(client, LM87_REG_CONFIG) & 0x6F; - - if (!(data->config & 0x01)) { - int i; - - /* Limits are left uninitialized after power-up */ - for (i = 1; i < 6; i++) { - lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); - lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); - } - for (i = 0; i < 2; i++) { - lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); - lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); - lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); - lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); - } - if (data->channel & CHAN_TEMP3) { - lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); - lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); - } else { - lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); - lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); - } - } - - /* Make sure Start is set and INT#_Clear is clear */ - if ((data->config & 0x09) != 0x01) - lm87_write_value(client, LM87_REG_CONFIG, - (data->config & 0x77) | 0x01); -} - static int lm87_remove(struct i2c_client *client) { struct lm87_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm87_group); - sysfs_remove_group(&client->dev.kobj, &lm87_group_opt); + lm87_remove_files(client); lm87_write_value(client, LM87_REG_CONFIG, data->config); kfree(data); return 0; } -static struct lm87_data *lm87_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm87_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - int i, j; - - dev_dbg(&client->dev, "Updating data.\n"); - - i = (data->channel & CHAN_TEMP3) ? 1 : 0; - j = (data->channel & CHAN_TEMP3) ? 5 : 6; - for (; i < j; i++) { - data->in[i] = lm87_read_value(client, - LM87_REG_IN(i)); - data->in_min[i] = lm87_read_value(client, - LM87_REG_IN_MIN(i)); - data->in_max[i] = lm87_read_value(client, - LM87_REG_IN_MAX(i)); - } - - for (i = 0; i < 2; i++) { - if (data->channel & CHAN_NO_FAN(i)) { - data->in[6+i] = lm87_read_value(client, - LM87_REG_AIN(i)); - data->in_max[6+i] = lm87_read_value(client, - LM87_REG_AIN_MAX(i)); - data->in_min[6+i] = lm87_read_value(client, - LM87_REG_AIN_MIN(i)); - - } else { - data->fan[i] = lm87_read_value(client, - LM87_REG_FAN(i)); - data->fan_min[i] = lm87_read_value(client, - LM87_REG_FAN_MIN(i)); - } - } - - j = (data->channel & CHAN_TEMP3) ? 3 : 2; - for (i = 0 ; i < j; i++) { - data->temp[i] = lm87_read_value(client, - LM87_REG_TEMP[i]); - data->temp_high[i] = lm87_read_value(client, - LM87_REG_TEMP_HIGH[i]); - data->temp_low[i] = lm87_read_value(client, - LM87_REG_TEMP_LOW[i]); - } - - i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); - j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); - data->temp_crit_int = min(i, j); - - i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); - j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); - data->temp_crit_ext = min(i, j); - - i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = (i & 0x0F) - | (lm87_read_value(client, LM87_REG_VID4) & 0x01) - << 4; - - data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) - | (lm87_read_value(client, LM87_REG_ALARMS2) - << 8); - data->aout = lm87_read_value(client, LM87_REG_AOUT); - - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); +/* + * Driver data (common to all clients) + */ - return data; -} +static const struct i2c_device_id lm87_id[] = { + { "lm87", lm87 }, + { "adm1024", adm1024 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm87_id); -static int __init sensors_lm87_init(void) -{ - return i2c_add_driver(&lm87_driver); -} +static struct i2c_driver lm87_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm87", + }, + .probe = lm87_probe, + .remove = lm87_remove, + .id_table = lm87_id, + .detect = lm87_detect, + .address_list = normal_i2c, +}; -static void __exit sensors_lm87_exit(void) -{ - i2c_del_driver(&lm87_driver); -} +module_i2c_driver(lm87_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org> and others"); MODULE_DESCRIPTION("LM87 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm87_init); -module_exit(sensors_lm87_exit); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index d2dd5f90496d..248f2b40dfaf 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1514,19 +1514,8 @@ static struct i2c_driver lm90_driver = { .address_list = normal_i2c, }; -static int __init sensors_lm90_init(void) -{ - return i2c_add_driver(&lm90_driver); -} - -static void __exit sensors_lm90_exit(void) -{ - i2c_del_driver(&lm90_driver); -} +module_i2c_driver(lm90_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("LM90/ADM1032 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm90_init); -module_exit(sensors_lm90_exit); diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 8fcbd4d422c5..fdc691a4028f 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -49,8 +49,10 @@ #include <linux/err.h> #include <linux/mutex.h> -/* The LM92 and MAX6635 have 2 two-state pins for address selection, - resulting in 4 possible addresses. */ +/* + * The LM92 and MAX6635 have 2 two-state pins for address selection, + * resulting in 4 possible addresses. + */ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; @@ -63,11 +65,13 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, #define LM92_REG_TEMP_HIGH 0x05 /* 16-bit, RW */ #define LM92_REG_MAN_ID 0x07 /* 16-bit, RO, LM92 only */ -/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, - left-justified in 16-bit registers. No rounding is done, with such - a resolution it's just not worth it. Note that the MAX6635 doesn't - make use of the 4 lower bits for limits (i.e. effective resolution - for limits is 1 degree Celsius). */ +/* + * The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, + * left-justified in 16-bit registers. No rounding is done, with such + * a resolution it's just not worth it. Note that the MAX6635 doesn't + * make use of the 4 lower bits for limits (i.e. effective resolution + * for limits is 1 degree Celsius). + */ static inline int TEMP_FROM_REG(s16 reg) { return reg / 8 * 625 / 10; @@ -138,7 +142,8 @@ static struct lm92_data *lm92_update_device(struct device *dev) } #define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct lm92_data *data = lm92_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ @@ -149,13 +154,17 @@ show_temp(temp1_min); show_temp(temp1_max); #define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ + const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm92_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err) \ + return err; \ +\ mutex_lock(&data->update_lock); \ data->value = TEMP_TO_REG(val); \ i2c_smbus_write_word_swapped(client, reg, data->value); \ @@ -166,31 +175,40 @@ set_temp(temp1_crit, LM92_REG_TEMP_CRIT); set_temp(temp1_min, LM92_REG_TEMP_LOW); set_temp(temp1_max, LM92_REG_TEMP_HIGH); -static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp1_crit_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) - TEMP_FROM_REG(data->temp1_hyst)); } -static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp1_max_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) - TEMP_FROM_REG(data->temp1_hyst)); } -static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp1_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) + TEMP_FROM_REG(data->temp1_hyst)); } -static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t set_temp1_crit_hyst(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm92_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; @@ -200,7 +218,8 @@ static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute * return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); @@ -246,26 +265,30 @@ static void lm92_init_client(struct i2c_client *client) config & 0xFE); } -/* The MAX6635 has no identification register, so we have to use tricks - to identify it reliably. This is somewhat slow. - Note that we do NOT rely on the 2 MSB of the configuration register - always reading 0, as suggested by the datasheet, because it was once - reported not to be true. */ +/* + * The MAX6635 has no identification register, so we have to use tricks + * to identify it reliably. This is somewhat slow. + * Note that we do NOT rely on the 2 MSB of the configuration register + * always reading 0, as suggested by the datasheet, because it was once + * reported not to be true. + */ static int max6635_check(struct i2c_client *client) { u16 temp_low, temp_high, temp_hyst, temp_crit; u8 conf; int i; - /* No manufacturer ID register, so a read from this address will - always return the last read value. */ + /* + * No manufacturer ID register, so a read from this address will + * always return the last read value. + */ temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW); if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low) return 0; temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH); if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high) return 0; - + /* Limits are stored as integer values (signed, 9-bit). */ if ((temp_low & 0x7f00) || (temp_high & 0x7f00)) return 0; @@ -274,22 +297,24 @@ static int max6635_check(struct i2c_client *client) if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) return 0; - /* Registers addresses were found to cycle over 16-byte boundaries. - We don't test all registers with all offsets so as to save some - reads and time, but this should still be sufficient to dismiss - non-MAX6635 chips. */ + /* + * Registers addresses were found to cycle over 16-byte boundaries. + * We don't test all registers with all offsets so as to save some + * reads and time, but this should still be sufficient to dismiss + * non-MAX6635 chips. + */ conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); - for (i=16; i<96; i*=2) { + for (i = 16; i < 96; i *= 2) { if (temp_hyst != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HYST + i - 16) + LM92_REG_TEMP_HYST + i - 16) || temp_crit != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_CRIT + i) + LM92_REG_TEMP_CRIT + i) || temp_low != i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW + i + 16) || temp_high != i2c_smbus_read_word_data(client, - LM92_REG_TEMP_HIGH + i + 32) + LM92_REG_TEMP_HIGH + i + 32) || conf != i2c_smbus_read_byte_data(client, - LM92_REG_CONFIG + i)) + LM92_REG_CONFIG + i)) return 0; } @@ -362,7 +387,8 @@ static int lm92_probe(struct i2c_client *new_client, lm92_init_client(new_client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group))) + err = sysfs_create_group(&new_client->dev.kobj, &lm92_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&new_client->dev); @@ -416,19 +442,8 @@ static struct i2c_driver lm92_driver = { .address_list = normal_i2c, }; -static int __init sensors_lm92_init(void) -{ - return i2c_add_driver(&lm92_driver); -} - -static void __exit sensors_lm92_exit(void) -{ - i2c_del_driver(&lm92_driver); -} +module_i2c_driver(lm92_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("LM92/MAX6635 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm92_init); -module_exit(sensors_lm92_exit); diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 8bd6c5c9e05b..67e8fe256e02 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -1,42 +1,42 @@ /* - lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - - Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com> - Copyright (c) 2004 Utilitek Systems, Inc. - - derived in part from lm78.c: - Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> - - derived in part from lm85.c: - Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> - Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> - - derived in part from w83l785ts.c: - Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org> - - Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com> - Copyright (c) 2005 Aspen Systems, Inc. - - Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org> - Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab - - Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de> - Copyright (c) 2007 Hans J. Koch, Linutronix GmbH - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring + * + * Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com> + * Copyright (c) 2004 Utilitek Systems, Inc. + * + * derived in part from lm78.c: + * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> + * + * derived in part from lm85.c: + * Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> + * Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> + * + * derived in part from w83l785ts.c: + * Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org> + * + * Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com> + * Copyright (c) 2005 Aspen Systems, Inc. + * + * Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org> + * Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab + * + * Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de> + * Copyright (c) 2007 Hans J. Koch, Linutronix GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -83,7 +83,7 @@ #define LM93_REG_FAN_MIN(nr) (0xb4 + (nr) * 2) /* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */ -#define LM93_REG_PWM_CTL(nr,reg) (0xc8 + (reg) + (nr) * 4) +#define LM93_REG_PWM_CTL(nr, reg) (0xc8 + (reg) + (nr) * 4) #define LM93_PWM_CTL1 0x0 #define LM93_PWM_CTL2 0x1 #define LM93_PWM_CTL3 0x2 @@ -160,7 +160,7 @@ static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization."); -static int vccp_limit_type[2] = {0,0}; +static int vccp_limit_type[2] = {0, 0}; module_param_array(vccp_limit_type, int, NULL, 0); MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes."); @@ -187,8 +187,10 @@ static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = { { 0xfd, 9 }, }; -/* ALARMS: SYSCTL format described further below - REG: 64 bits in 8 registers, as immediately below */ +/* + * ALARMS: SYSCTL format described further below + * REG: 64 bits in 8 registers, as immediately below + */ struct block1_t { u8 host_status_1; u8 host_status_2; @@ -217,8 +219,10 @@ struct lm93_data { /* register values, arranged by block read groups */ struct block1_t block1; - /* temp1 - temp4: unfiltered readings - temp1 - temp2: filtered readings */ + /* + * temp1 - temp4: unfiltered readings + * temp1 - temp2: filtered readings + */ u8 block2[6]; /* vin1 - vin16: readings */ @@ -295,14 +299,18 @@ struct lm93_data { u8 sfc2; u8 sf_tach_to_pwm; - /* The two PWM CTL2 registers can read something other than what was - last written for the OVR_DC field (duty cycle override). So, we - save the user-commanded value here. */ + /* + * The two PWM CTL2 registers can read something other than what was + * last written for the OVR_DC field (duty cycle override). So, we + * save the user-commanded value here. + */ u8 pwm_override[2]; }; -/* VID: mV - REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */ +/* + * VID: mV + * REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 + */ static int LM93_VID_FROM_REG(u8 reg) { return vid_from_reg((reg & 0x3f), 100); @@ -317,12 +325,13 @@ static const u8 lm93_vin_reg_max[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, }; -/* Values from the datasheet. They're here for documentation only. -static const u8 lm93_vin_reg_nom[16] = { - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, -}; -*/ +/* + * Values from the datasheet. They're here for documentation only. + * static const u8 lm93_vin_reg_nom[16] = { + * 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + * 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, + * }; + */ /* min, max, and nominal voltage readings, per channel (mV)*/ static const unsigned long lm93_vin_val_min[16] = { @@ -334,12 +343,13 @@ static const unsigned long lm93_vin_val_max[16] = { 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600, 4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600, }; -/* Values from the datasheet. They're here for documentation only. -static const unsigned long lm93_vin_val_nom[16] = { - 927, 927, 927, 1200, 1500, 1500, 1200, 1200, - 3300, 5000, 2500, 1969, 984, 984, 309, 3300, -}; -*/ +/* + * Values from the datasheet. They're here for documentation only. + * static const unsigned long lm93_vin_val_nom[16] = { + * 927, 927, 927, 1200, 1500, 1500, 1200, 1200, + * 3300, 5000, 2500, 1969, 984, 984, 309, 3300, + * }; + */ static unsigned LM93_IN_FROM_REG(int nr, u8 reg) { @@ -353,8 +363,10 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg) return (slope * reg + intercept + 500) / 1000; } -/* IN: mV, limits determined by channel nr - REG: scaling determined by channel nr */ +/* + * IN: mV, limits determined by channel nr + * REG: scaling determined by channel nr + */ static u8 LM93_IN_TO_REG(int nr, unsigned val) { /* range limit */ @@ -386,12 +398,14 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid) return (uV_vid + uV_offset + 5000) / 10000; } -#define LM93_IN_MIN_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,0,vid) -#define LM93_IN_MAX_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,1,vid) +#define LM93_IN_MIN_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 0, (vid)) +#define LM93_IN_MAX_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 1, (vid)) -/* vid in mV , upper == 0 indicates low limit, otherwise upper limit - upper also determines which nibble of the register is returned - (the other nibble will be 0x0) */ +/* + * vid in mV , upper == 0 indicates low limit, otherwise upper limit + * upper also determines which nibble of the register is returned + * (the other nibble will be 0x0) + */ static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) { long uV_offset = vid * 1000 - val * 10000; @@ -404,22 +418,26 @@ static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) } } -/* TEMP: 1/1000 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: 1/1000 degrees C (-128C to +127C) + * REG: 1C/bit, two's complement + */ static int LM93_TEMP_FROM_REG(u8 reg) { return (s8)reg * 1000; } #define LM93_TEMP_MIN (-128000) -#define LM93_TEMP_MAX ( 127000) +#define LM93_TEMP_MAX (127000) -/* TEMP: 1/1000 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: 1/1000 degrees C (-128C to +127C) + * REG: 1C/bit, two's complement + */ static u8 LM93_TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); - ntemp += (ntemp<0 ? -500 : 500); + ntemp += (ntemp < 0 ? -500 : 500); return (u8)(ntemp / 1000); } @@ -430,21 +448,25 @@ static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr) return sfc2 & (nr < 2 ? 0x10 : 0x20); } -/* This function is common to all 4-bit temperature offsets - reg is 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ +/* + * This function is common to all 4-bit temperature offsets + * reg is 4 bits right justified + * mode 0 => 1C/bit, mode !0 => 0.5C/bit + */ static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode) { return (reg & 0x0f) * (mode ? 5 : 10); } -#define LM93_TEMP_OFFSET_MIN ( 0) +#define LM93_TEMP_OFFSET_MIN (0) #define LM93_TEMP_OFFSET_MAX0 (150) -#define LM93_TEMP_OFFSET_MAX1 ( 75) +#define LM93_TEMP_OFFSET_MAX1 (75) -/* This function is common to all 4-bit temperature offsets - returns 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ +/* + * This function is common to all 4-bit temperature offsets + * returns 4 bits right justified + * mode 0 => 1C/bit, mode !0 => 0.5C/bit + */ static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) { int factor = mode ? 5 : 10; @@ -466,9 +488,11 @@ static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode) return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode); } -/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) - REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) - 0 <= nr <= 3 */ +/* + * TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) + * REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) + * 0 <= nr <= 3 + */ static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode) { u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode); @@ -532,9 +556,12 @@ static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst, return reg; } -/* PWM: 0-255 per sensors documentation - REG: 0-13 as mapped below... right justified */ -typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t; +/* + * PWM: 0-255 per sensors documentation + * REG: 0-13 as mapped below... right justified + */ +enum pwm_freq { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ }; + static int lm93_pwm_map[2][16] = { { 0x00, /* 0.00% */ 0x40, /* 25.00% */ @@ -558,13 +585,13 @@ static int lm93_pwm_map[2][16] = { }, }; -static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq) +static int LM93_PWM_FROM_REG(u8 reg, enum pwm_freq freq) { return lm93_pwm_map[freq][reg & 0x0f]; } /* round up to nearest match */ -static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq) +static u8 LM93_PWM_TO_REG(int pwm, enum pwm_freq freq) { int i; for (i = 0; i < 13; i++) @@ -578,7 +605,7 @@ static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq) static int LM93_FAN_FROM_REG(u16 regs) { const u16 count = le16_to_cpu(regs) >> 2; - return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count; + return count == 0 ? -1 : count == 0x3fff ? 0 : 1350000 / count; } /* @@ -600,8 +627,10 @@ static u16 LM93_FAN_TO_REG(long rpm) return cpu_to_le16(regs); } -/* PWM FREQ: HZ - REG: 0-7 as mapped below */ +/* + * PWM FREQ: HZ + * REG: 0-7 as mapped below + */ static int lm93_pwm_freq_map[8] = { 22500, 96, 84, 72, 60, 48, 36, 12 }; @@ -623,8 +652,10 @@ static u8 LM93_PWM_FREQ_TO_REG(int freq) return (u8)i; } -/* TIME: 1/100 seconds - * REG: 0-7 as mapped below */ +/* + * TIME: 1/100 seconds + * REG: 0-7 as mapped below + */ static int lm93_spinup_time_map[8] = { 0, 10, 25, 40, 70, 100, 200, 400, }; @@ -654,24 +685,30 @@ static int LM93_RAMP_FROM_REG(u8 reg) return (reg & 0x0f) * 5; } -/* RAMP: 1/100 seconds - REG: 50mS/bit 4-bits right justified */ +/* + * RAMP: 1/100 seconds + * REG: 50mS/bit 4-bits right justified + */ static u8 LM93_RAMP_TO_REG(int ramp) { ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX); return (u8)((ramp + 2) / 5); } -/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% - * REG: (same) */ +/* + * PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% + * REG: (same) + */ static u8 LM93_PROCHOT_TO_REG(long prochot) { prochot = SENSORS_LIMIT(prochot, 0, 255); return (u8)prochot; } -/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) - * REG: 0-9 as mapped below */ +/* + * PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) + * REG: 0-9 as mapped below + */ static int lm93_interval_map[10] = { 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200, }; @@ -693,22 +730,25 @@ static u8 LM93_INTERVAL_TO_REG(long interval) return (u8)i; } -/* GPIO: 0-255, GPIO0 is LSB - * REG: inverted */ +/* + * GPIO: 0-255, GPIO0 is LSB + * REG: inverted + */ static unsigned LM93_GPI_FROM_REG(u8 reg) { return ~reg & 0xff; } -/* alarm bitmask definitions - The LM93 has nearly 64 bits of error status... I've pared that down to - what I think is a useful subset in order to fit it into 32 bits. - - Especially note that the #VRD_HOT alarms are missing because we provide - that information as values in another sysfs file. - - If libsensors is extended to support 64 bit values, this could be revisited. -*/ +/* + * alarm bitmask definitions + * The LM93 has nearly 64 bits of error status... I've pared that down to + * what I think is a useful subset in order to fit it into 32 bits. + * + * Especially note that the #VRD_HOT alarms are missing because we provide + * that information as values in another sysfs file. + * + * If libsensors is extended to support 64 bit values, this could be revisited. + */ #define LM93_ALARM_IN1 0x00000001 #define LM93_ALARM_IN2 0x00000002 #define LM93_ALARM_IN3 0x00000004 @@ -772,11 +812,12 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg) int value, i; /* retry in case of read errors */ - for (i=1; i<=MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) { + for (i = 1; i <= MAX_RETRIES; i++) { + value = i2c_smbus_read_byte_data(client, reg); + if (value >= 0) { return value; } else { - dev_warn(&client->dev,"lm93: read byte data failed, " + dev_warn(&client->dev, "lm93: read byte data failed, " "address 0x%02x.\n", reg); mdelay(i + 3); } @@ -784,7 +825,7 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg) } /* <TODO> what to return in case of error? */ - dev_err(&client->dev,"lm93: All read byte retries failed!!\n"); + dev_err(&client->dev, "lm93: All read byte retries failed!!\n"); return 0; } @@ -796,7 +837,7 @@ static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value) result = i2c_smbus_write_byte_data(client, reg, value); if (result < 0) - dev_warn(&client->dev,"lm93: write byte data failed, " + dev_warn(&client->dev, "lm93: write byte data failed, " "0x%02x at address 0x%02x.\n", value, reg); return result; @@ -807,11 +848,12 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg) int value, i; /* retry in case of read errors */ - for (i=1; i<=MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) { + for (i = 1; i <= MAX_RETRIES; i++) { + value = i2c_smbus_read_word_data(client, reg); + if (value >= 0) { return value; } else { - dev_warn(&client->dev,"lm93: read word data failed, " + dev_warn(&client->dev, "lm93: read word data failed, " "address 0x%02x.\n", reg); mdelay(i + 3); } @@ -819,7 +861,7 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg) } /* <TODO> what to return in case of error? */ - dev_err(&client->dev,"lm93: All read word retries failed!!\n"); + dev_err(&client->dev, "lm93: All read word retries failed!!\n"); return 0; } @@ -831,7 +873,7 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value) result = i2c_smbus_write_word_data(client, reg, value); if (result < 0) - dev_warn(&client->dev,"lm93: write word data failed, " + dev_warn(&client->dev, "lm93: write word data failed, " "0x%04x at address 0x%02x.\n", value, reg); return result; @@ -840,13 +882,13 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value) static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX]; /* - read block data into values, retry if not expected length - fbn => index to lm93_block_read_cmds table - (Fixed Block Number - section 14.5.2 of LM93 datasheet) -*/ + * read block data into values, retry if not expected length + * fbn => index to lm93_block_read_cmds table + * (Fixed Block Number - section 14.5.2 of LM93 datasheet) + */ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) { - int i, result=0; + int i, result = 0; for (i = 1; i <= MAX_RETRIES; i++) { result = i2c_smbus_read_block_data(client, @@ -855,7 +897,7 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) if (result == lm93_block_read_cmds[fbn].len) { break; } else { - dev_warn(&client->dev,"lm93: block read data failed, " + dev_warn(&client->dev, "lm93: block read data failed, " "command 0x%02x.\n", lm93_block_read_cmds[fbn].cmd); mdelay(i + 3); @@ -863,7 +905,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) } if (result == lm93_block_read_cmds[fbn].len) { - memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len); + memcpy(values, lm93_block_buffer, + lm93_block_read_cmds[fbn].len); } else { /* <TODO> what to do in case of error? */ } @@ -964,7 +1007,7 @@ static void lm93_update_client_common(struct lm93_data *data, static void lm93_update_client_full(struct lm93_data *data, struct i2c_client *client) { - dev_dbg(&client->dev,"starting device update (block data enabled)\n"); + dev_dbg(&client->dev, "starting device update (block data enabled)\n"); /* in1 - in16: values & limits */ lm93_read_block(client, 3, (u8 *)(data->block3)); @@ -996,10 +1039,10 @@ static void lm93_update_client_full(struct lm93_data *data, static void lm93_update_client_min(struct lm93_data *data, struct i2c_client *client) { - int i,j; + int i, j; u8 *ptr; - dev_dbg(&client->dev,"starting device update (block data disabled)\n"); + dev_dbg(&client->dev, "starting device update (block data disabled)\n"); /* in1 - in16: values & limits */ for (i = 0; i < 16; i++) { @@ -1037,7 +1080,7 @@ static void lm93_update_client_min(struct lm93_data *data, for (i = 0; i < 2; i++) { for (j = 0; j < 4; j++) { data->block9[i][j] = - lm93_read_byte(client, LM93_REG_PWM_CTL(i,j)); + lm93_read_byte(client, LM93_REG_PWM_CTL(i, j)); } } @@ -1097,14 +1140,13 @@ static ssize_t show_in_min(struct device *dev, int vccp = nr - 6; long rc, vid; - if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) { + if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { vid = LM93_VID_FROM_REG(data->vid[vccp]); rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid); + } else { + rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); } - else { - rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); \ - } - return sprintf(buf, "%ld\n", rc); \ + return sprintf(buf, "%ld\n", rc); } static ssize_t store_in_min(struct device *dev, struct device_attribute *attr, @@ -1113,20 +1155,24 @@ static ssize_t store_in_min(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); int vccp = nr - 6; long vid; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) { + if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { vid = LM93_VID_FROM_REG(data->vid[vccp]); data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) | LM93_IN_REL_TO_REG(val, 0, vid); lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp), data->vccp_limits[vccp]); - } - else { - data->block7[nr].min = LM93_IN_TO_REG(nr,val); + } else { + data->block7[nr].min = LM93_IN_TO_REG(nr, val); lm93_write_byte(client, LM93_REG_IN_MIN(nr), data->block7[nr].min); } @@ -1175,14 +1221,13 @@ static ssize_t show_in_max(struct device *dev, int vccp = nr - 6; long rc, vid; - if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) { + if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { vid = LM93_VID_FROM_REG(data->vid[vccp]); - rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp],vid); - } - else { - rc = LM93_IN_FROM_REG(nr,data->block7[nr].max); \ + rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp], vid); + } else { + rc = LM93_IN_FROM_REG(nr, data->block7[nr].max); } - return sprintf(buf,"%ld\n",rc); \ + return sprintf(buf, "%ld\n", rc); } static ssize_t store_in_max(struct device *dev, struct device_attribute *attr, @@ -1191,20 +1236,24 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); int vccp = nr - 6; long vid; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) { + if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { vid = LM93_VID_FROM_REG(data->vid[vccp]); data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) | LM93_IN_REL_TO_REG(val, 1, vid); lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp), data->vccp_limits[vccp]); - } - else { - data->block7[nr].max = LM93_IN_TO_REG(nr,val); + } else { + data->block7[nr].max = LM93_IN_TO_REG(nr, val); lm93_write_byte(client, LM93_REG_IN_MAX(nr), data->block7[nr].max); } @@ -1250,7 +1299,7 @@ static ssize_t show_temp(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block2[nr])); + return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->block2[nr])); } static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); @@ -1262,7 +1311,7 @@ static ssize_t show_temp_min(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].min)); + return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->temp_lim[nr].min)); } static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr, @@ -1271,7 +1320,12 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_lim[nr].min = LM93_TEMP_TO_REG(val); @@ -1292,7 +1346,7 @@ static ssize_t show_temp_max(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].max)); + return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->temp_lim[nr].max)); } static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr, @@ -1301,7 +1355,12 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_lim[nr].max = LM93_TEMP_TO_REG(val); @@ -1322,7 +1381,7 @@ static ssize_t show_temp_auto_base(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block10.base[nr])); + return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->block10.base[nr])); } static ssize_t store_temp_auto_base(struct device *dev, @@ -1332,7 +1391,12 @@ static ssize_t store_temp_auto_base(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->block10.base[nr] = LM93_TEMP_TO_REG(val); @@ -1349,11 +1413,11 @@ static SENSOR_DEVICE_ATTR(temp3_auto_base, S_IWUSR | S_IRUGO, show_temp_auto_base, store_temp_auto_base, 2); static ssize_t show_temp_auto_boost(struct device *dev, - struct device_attribute *attr,char *buf) + struct device_attribute *attr, char *buf) { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->boost[nr])); + return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->boost[nr])); } static ssize_t store_temp_auto_boost(struct device *dev, @@ -1363,7 +1427,12 @@ static ssize_t store_temp_auto_boost(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->boost[nr] = LM93_TEMP_TO_REG(val); @@ -1386,7 +1455,7 @@ static ssize_t show_temp_auto_boost_hyst(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode)); } @@ -1397,7 +1466,12 @@ static ssize_t store_temp_auto_boost_hyst(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); /* force 0.5C/bit mode */ @@ -1429,9 +1503,9 @@ static ssize_t show_temp_auto_offset(struct device *dev, int ofs = s_attr->nr; struct lm93_data *data = lm93_update_device(dev); int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs], - nr,mode)); + nr, mode)); } static ssize_t store_temp_auto_offset(struct device *dev, @@ -1443,7 +1517,12 @@ static ssize_t store_temp_auto_offset(struct device *dev, int ofs = s_attr->nr; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); /* force 0.5C/bit mode */ @@ -1539,7 +1618,7 @@ static ssize_t show_temp_auto_pwm_min(struct device *dev, struct lm93_data *data = lm93_update_device(dev); reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f; ctl4 = data->block9[nr][LM93_PWM_CTL4]; - return sprintf(buf,"%d\n",LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ? + return sprintf(buf, "%d\n", LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ)); } @@ -1550,12 +1629,17 @@ static ssize_t store_temp_auto_pwm_min(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 reg, ctl4; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr)); - ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); + ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); reg = (reg & 0x0f) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : @@ -1582,8 +1666,8 @@ static ssize_t show_temp_auto_offset_hyst(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - return sprintf(buf,"%d\n",LM93_TEMP_OFFSET_FROM_REG( - data->auto_pwm_min_hyst[nr/2], mode)); + return sprintf(buf, "%d\n", LM93_TEMP_OFFSET_FROM_REG( + data->auto_pwm_min_hyst[nr / 2], mode)); } static ssize_t store_temp_auto_offset_hyst(struct device *dev, @@ -1593,8 +1677,13 @@ static ssize_t store_temp_auto_offset_hyst(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); /* force 0.5C/bit mode */ @@ -1626,7 +1715,7 @@ static ssize_t show_fan_input(struct device *dev, int nr = s_attr->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block5[nr])); + return sprintf(buf, "%d\n", LM93_FAN_FROM_REG(data->block5[nr])); } static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); @@ -1640,7 +1729,7 @@ static ssize_t show_fan_min(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block8[nr])); + return sprintf(buf, "%d\n", LM93_FAN_FROM_REG(data->block8[nr])); } static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, @@ -1649,11 +1738,16 @@ static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->block8[nr] = LM93_FAN_TO_REG(val); - lm93_write_word(client,LM93_REG_FAN_MIN(nr),data->block8[nr]); + lm93_write_word(client, LM93_REG_FAN_MIN(nr), data->block8[nr]); mutex_unlock(&data->update_lock); return count; } @@ -1667,18 +1761,19 @@ static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3); -/* some tedious bit-twiddling here to deal with the register format: - - data->sf_tach_to_pwm: (tach to pwm mapping bits) - - bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 - T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1 - - data->sfc2: (enable bits) - - bit | 3 | 2 | 1 | 0 - T4 T3 T2 T1 -*/ +/* + * some tedious bit-twiddling here to deal with the register format: + * + * data->sf_tach_to_pwm: (tach to pwm mapping bits) + * + * bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 + * T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1 + * + * data->sfc2: (enable bits) + * + * bit | 3 | 2 | 1 | 0 + * T4 T3 T2 T1 + */ static ssize_t show_fan_smart_tach(struct device *dev, struct device_attribute *attr, char *buf) @@ -1694,11 +1789,13 @@ static ssize_t show_fan_smart_tach(struct device *dev, /* if there's a mapping and it's enabled */ if (mapping && ((data->sfc2 >> nr) & 0x01)) rc = mapping; - return sprintf(buf,"%ld\n",rc); + return sprintf(buf, "%ld\n", rc); } -/* helper function - must grab data->update_lock before calling - fan is 0-3, indicating fan1-fan4 */ +/* + * helper function - must grab data->update_lock before calling + * fan is 0-3, indicating fan1-fan4 + */ static void lm93_write_fan_smart_tach(struct i2c_client *client, struct lm93_data *data, int fan, long value) { @@ -1724,7 +1821,12 @@ static ssize_t store_fan_smart_tach(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); /* sanity test, ignore the write otherwise */ @@ -1732,7 +1834,7 @@ static ssize_t store_fan_smart_tach(struct device *dev, /* can't enable if pwm freq is 22.5KHz */ if (val) { u8 ctl4 = lm93_read_byte(client, - LM93_REG_PWM_CTL(val-1,LM93_PWM_CTL4)); + LM93_REG_PWM_CTL(val - 1, LM93_PWM_CTL4)); if ((ctl4 & 0x07) == 0) val = 0; } @@ -1766,7 +1868,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, else /* show present h/w value if manual pwm disabled */ rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - return sprintf(buf,"%ld\n",rc); + return sprintf(buf, "%ld\n", rc); } static ssize_t store_pwm(struct device *dev, struct device_attribute *attr, @@ -1775,19 +1877,24 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ctl2, ctl4; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2)); - ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val,(ctl4 & 0x07) ? + ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2)); + ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); + ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4; /* save user commanded value */ data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2); + lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2), ctl2); mutex_unlock(&data->update_lock); return count; } @@ -1808,7 +1915,7 @@ static ssize_t show_pwm_enable(struct device *dev, rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1; else rc = 2; - return sprintf(buf,"%ld\n",rc); + return sprintf(buf, "%ld\n", rc); } static ssize_t store_pwm_enable(struct device *dev, @@ -1818,26 +1925,33 @@ static ssize_t store_pwm_enable(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ctl2; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2)); + ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2)); switch (val) { case 0: ctl2 |= 0xF1; /* enable manual override, set PWM to max */ break; - case 1: ctl2 |= 0x01; /* enable manual override */ + case 1: + ctl2 |= 0x01; /* enable manual override */ break; - case 2: ctl2 &= ~0x01; /* disable manual override */ + case 2: + ctl2 &= ~0x01; /* disable manual override */ break; default: mutex_unlock(&data->update_lock); return -EINVAL; } - lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2); + lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2), ctl2); mutex_unlock(&data->update_lock); return count; } @@ -1855,12 +1969,14 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, u8 ctl4; ctl4 = data->block9[nr][LM93_PWM_CTL4]; - return sprintf(buf,"%d\n",LM93_PWM_FREQ_FROM_REG(ctl4)); + return sprintf(buf, "%d\n", LM93_PWM_FREQ_FROM_REG(ctl4)); } -/* helper function - must grab data->update_lock before calling - pwm is 0-1, indicating pwm1-pwm2 - this disables smart tach for all tach channels bound to the given pwm */ +/* + * helper function - must grab data->update_lock before calling + * pwm is 0-1, indicating pwm1-pwm2 + * this disables smart tach for all tach channels bound to the given pwm + */ static void lm93_disable_fan_smart_tach(struct i2c_client *client, struct lm93_data *data, int pwm) { @@ -1887,17 +2003,22 @@ static ssize_t store_pwm_freq(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ctl4; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); + ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val); data->block9[nr][LM93_PWM_CTL4] = ctl4; /* ctl4 == 0 -> 22.5KHz -> disable smart tach */ if (!ctl4) lm93_disable_fan_smart_tach(client, data, nr); - lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4); + lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4), ctl4); mutex_unlock(&data->update_lock); return count; } @@ -1912,7 +2033,7 @@ static ssize_t show_pwm_auto_channels(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",data->block9[nr][LM93_PWM_CTL1]); + return sprintf(buf, "%d\n", data->block9[nr][LM93_PWM_CTL1]); } static ssize_t store_pwm_auto_channels(struct device *dev, @@ -1922,11 +2043,16 @@ static ssize_t store_pwm_auto_channels(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255); - lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1), + lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1), data->block9[nr][LM93_PWM_CTL1]); mutex_unlock(&data->update_lock); return count; @@ -1938,7 +2064,7 @@ static SENSOR_DEVICE_ATTR(pwm2_auto_channels, S_IWUSR | S_IRUGO, show_pwm_auto_channels, store_pwm_auto_channels, 1); static ssize_t show_pwm_auto_spinup_min(struct device *dev, - struct device_attribute *attr,char *buf) + struct device_attribute *attr, char *buf) { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); @@ -1946,7 +2072,7 @@ static ssize_t show_pwm_auto_spinup_min(struct device *dev, ctl3 = data->block9[nr][LM93_PWM_CTL3]; ctl4 = data->block9[nr][LM93_PWM_CTL4]; - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ)); } @@ -1958,17 +2084,22 @@ static ssize_t store_pwm_auto_spinup_min(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ctl3, ctl4; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); - ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); - ctl3 = (ctl3 & 0xf0) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? + ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); + ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); + ctl3 = (ctl3 & 0xf0) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); data->block9[nr][LM93_PWM_CTL3] = ctl3; - lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); + lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); mutex_unlock(&data->update_lock); return count; } @@ -1985,7 +2116,7 @@ static ssize_t show_pwm_auto_spinup_time(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_SPINUP_TIME_FROM_REG( + return sprintf(buf, "%d\n", LM93_SPINUP_TIME_FROM_REG( data->block9[nr][LM93_PWM_CTL3])); } @@ -1996,14 +2127,19 @@ static ssize_t store_pwm_auto_spinup_time(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ctl3; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); + ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0); data->block9[nr][LM93_PWM_CTL3] = ctl3; - lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); + lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); mutex_unlock(&data->update_lock); return count; } @@ -2019,7 +2155,7 @@ static ssize_t show_pwm_auto_prochot_ramp(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f)); } @@ -2029,8 +2165,13 @@ static ssize_t store_pwm_auto_prochot_ramp(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ramp; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); @@ -2048,7 +2189,7 @@ static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f)); } @@ -2058,8 +2199,13 @@ static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 ramp; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); @@ -2078,7 +2224,7 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr])); + return sprintf(buf, "%d\n", LM93_VID_FROM_REG(data->vid[nr])); } static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0); @@ -2089,7 +2235,7 @@ static ssize_t show_prochot(struct device *dev, struct device_attribute *attr, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",data->block4[nr].cur); + return sprintf(buf, "%d\n", data->block4[nr].cur); } static SENSOR_DEVICE_ATTR(prochot1, S_IRUGO, show_prochot, NULL, 0); @@ -2100,7 +2246,7 @@ static ssize_t show_prochot_avg(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",data->block4[nr].avg); + return sprintf(buf, "%d\n", data->block4[nr].avg); } static SENSOR_DEVICE_ATTR(prochot1_avg, S_IRUGO, show_prochot_avg, NULL, 0); @@ -2111,7 +2257,7 @@ static ssize_t show_prochot_max(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",data->prochot_max[nr]); + return sprintf(buf, "%d\n", data->prochot_max[nr]); } static ssize_t store_prochot_max(struct device *dev, @@ -2121,7 +2267,12 @@ static ssize_t store_prochot_max(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val); @@ -2143,7 +2294,7 @@ static ssize_t show_prochot_override(struct device *dev, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n", + return sprintf(buf, "%d\n", (data->prochot_override & prochot_override_mask[nr]) ? 1 : 0); } @@ -2154,7 +2305,12 @@ static ssize_t store_prochot_override(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); if (val) @@ -2178,11 +2334,11 @@ static ssize_t show_prochot_interval(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); u8 tmp; - if (nr==1) + if (nr == 1) tmp = (data->prochot_interval & 0xf0) >> 4; else tmp = data->prochot_interval & 0x0f; - return sprintf(buf,"%d\n",LM93_INTERVAL_FROM_REG(tmp)); + return sprintf(buf, "%d\n", LM93_INTERVAL_FROM_REG(tmp)); } static ssize_t store_prochot_interval(struct device *dev, @@ -2192,12 +2348,17 @@ static ssize_t store_prochot_interval(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 tmp; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL); - if (nr==1) + if (nr == 1) tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4); else tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val); @@ -2217,7 +2378,7 @@ static ssize_t show_prochot_override_duty_cycle(struct device *dev, char *buf) { struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",data->prochot_override & 0x0f); + return sprintf(buf, "%d\n", data->prochot_override & 0x0f); } static ssize_t store_prochot_override_duty_cycle(struct device *dev, @@ -2226,7 +2387,12 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->prochot_override = (data->prochot_override & 0xf0) | @@ -2245,7 +2411,7 @@ static ssize_t show_prochot_short(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",(data->config & 0x10) ? 1 : 0); + return sprintf(buf, "%d\n", (data->config & 0x10) ? 1 : 0); } static ssize_t store_prochot_short(struct device *dev, @@ -2254,7 +2420,12 @@ static ssize_t store_prochot_short(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); if (val) @@ -2274,8 +2445,8 @@ static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr, { int nr = (to_sensor_dev_attr(attr))->index; struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n", - data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0); + return sprintf(buf, "%d\n", + data->block1.host_status_1 & (1 << (nr + 4)) ? 1 : 0); } static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0); @@ -2285,7 +2456,7 @@ static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_GPI_FROM_REG(data->gpi)); + return sprintf(buf, "%d\n", LM93_GPI_FROM_REG(data->gpi)); } static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL); @@ -2294,7 +2465,7 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); - return sprintf(buf,"%d\n",LM93_ALARMS_FROM_REG(data->block1)); + return sprintf(buf, "%d\n", LM93_ALARMS_FROM_REG(data->block1)); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); @@ -2494,13 +2665,13 @@ static void lm93_init_client(struct i2c_client *client) lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01); /* spin until ready */ - for (i=0; i<20; i++) { + for (i = 0; i < 20; i++) { msleep(10); if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80) return; } - dev_warn(&client->dev,"timed out waiting for sensor " + dev_warn(&client->dev, "timed out waiting for sensor " "chip to signal ready!\n"); } @@ -2540,7 +2711,7 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) } strlcpy(info->type, name, I2C_NAME_SIZE); - dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n", + dev_dbg(&adapter->dev, "loading %s at %d, 0x%02x\n", client->name, i2c_adapter_id(client->adapter), client->addr); @@ -2593,7 +2764,7 @@ static int lm93_probe(struct i2c_client *client, /* Register hwmon driver class */ data->hwmon_dev = hwmon_device_register(&client->dev); - if ( !IS_ERR(data->hwmon_dev)) + if (!IS_ERR(data->hwmon_dev)) return 0; err = PTR_ERR(data->hwmon_dev); @@ -2635,20 +2806,9 @@ static struct i2c_driver lm93_driver = { .address_list = normal_i2c, }; -static int __init lm93_init(void) -{ - return i2c_add_driver(&lm93_driver); -} - -static void __exit lm93_exit(void) -{ - i2c_del_driver(&lm93_driver); -} +module_i2c_driver(lm93_driver); MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, " "Hans J. Koch <hjk@hansjkoch.de>"); MODULE_DESCRIPTION("LM93 driver"); MODULE_LICENSE("GPL"); - -module_init(lm93_init); -module_exit(lm93_exit); diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 70bca671e083..bd8cdb7b96ed 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -455,19 +455,8 @@ static struct i2c_driver lm95241_driver = { .address_list = normal_i2c, }; -static int __init sensors_lm95241_init(void) -{ - return i2c_add_driver(&lm95241_driver); -} - -static void __exit sensors_lm95241_exit(void) -{ - i2c_del_driver(&lm95241_driver); -} +module_i2c_driver(lm95241_driver); MODULE_AUTHOR("Davide Rizzo <elpa.rizzo@gmail.com>"); MODULE_DESCRIPTION("LM95241 sensor driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm95241_init); -module_exit(sensors_lm95241_exit); diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 5e5fc1b0ace1..9a46c106a240 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -525,19 +525,8 @@ static struct i2c_driver lm95245_driver = { .address_list = normal_i2c, }; -static int __init sensors_lm95245_init(void) -{ - return i2c_add_driver(&lm95245_driver); -} - -static void __exit sensors_lm95245_exit(void) -{ - i2c_del_driver(&lm95245_driver); -} +module_i2c_driver(lm95245_driver); MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>"); MODULE_DESCRIPTION("LM95245 sensor driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_lm95245_init); -module_exit(sensors_lm95245_exit); diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index 4ac06b75aa60..4d005b219de2 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -154,7 +154,8 @@ static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \ ltc4151_show_value, NULL, LTC4151_SENSE_H); -/* Finally, construct an array of pointers to members of the above objects, +/* + * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ static struct attribute *ltc4151_attributes[] = { @@ -238,19 +239,8 @@ static struct i2c_driver ltc4151_driver = { .id_table = ltc4151_id, }; -static int __init ltc4151_init(void) -{ - return i2c_add_driver(<c4151_driver); -} - -static void __exit ltc4151_exit(void) -{ - i2c_del_driver(<c4151_driver); -} +module_i2c_driver(ltc4151_driver); MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>"); MODULE_DESCRIPTION("LTC4151 driver"); MODULE_LICENSE("GPL"); - -module_init(ltc4151_init); -module_exit(ltc4151_exit); diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index c7e6d8e81656..429c5b2b66fd 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -91,8 +91,10 @@ static int ltc4215_get_voltage(struct device *dev, u8 reg) voltage = regval * 605 / 10; break; case LTC4215_ADIN: - /* The ADIN input is divided by 12.5, and has 4.82 mV - * per increment, so we have the additional multiply */ + /* + * The ADIN input is divided by 12.5, and has 4.82 mV + * per increment, so we have the additional multiply + */ voltage = regval * 482 * 125 / 1000; break; default: @@ -109,7 +111,8 @@ static unsigned int ltc4215_get_current(struct device *dev) { struct ltc4215_data *data = ltc4215_update_device(dev); - /* The strange looking conversions that follow are fixed-point + /* + * The strange looking conversions that follow are fixed-point * math, since we cannot do floating point in the kernel. * * Step 1: convert sense register to microVolts @@ -176,7 +179,8 @@ static ssize_t ltc4215_show_alarm(struct device *dev, return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0); } -/* These macros are used below in constructing device attribute objects +/* + * These macros are used below in constructing device attribute objects * for use with sysfs_create_group() to make a sysfs device file * for each register. */ @@ -215,7 +219,8 @@ LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS); LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE); LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS); -/* Finally, construct an array of pointers to members of the above objects, +/* + * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ static struct attribute *ltc4215_attributes[] = { @@ -309,19 +314,8 @@ static struct i2c_driver ltc4215_driver = { .id_table = ltc4215_id, }; -static int __init ltc4215_init(void) -{ - return i2c_add_driver(<c4215_driver); -} - -static void __exit ltc4215_exit(void) -{ - i2c_del_driver(<c4215_driver); -} +module_i2c_driver(ltc4215_driver); MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); MODULE_DESCRIPTION("LTC4215 driver"); MODULE_LICENSE("GPL"); - -module_init(ltc4215_init); -module_exit(ltc4215_exit); diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 659308329308..b99b45bafdad 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -214,7 +214,8 @@ static unsigned int ltc4245_get_current(struct device *dev, u8 reg) unsigned int voltage; unsigned int curr; - /* The strange looking conversions that follow are fixed-point + /* + * The strange looking conversions that follow are fixed-point * math, since we cannot do floating point in the kernel. * * Step 1: convert sense register to microVolts @@ -317,7 +318,8 @@ static ssize_t ltc4245_show_gpio(struct device *dev, return snprintf(buf, PAGE_SIZE, "%u\n", val * 10); } -/* These macros are used below in constructing device attribute objects +/* + * These macros are used below in constructing device attribute objects * for use with sysfs_create_group() to make a sysfs device file * for each register. */ @@ -391,7 +393,8 @@ LTC4245_POWER(power2_input, LTC4245_5VSENSE); LTC4245_POWER(power3_input, LTC4245_3VSENSE); LTC4245_POWER(power4_input, LTC4245_VEESENSE); -/* Finally, construct an array of pointers to members of the above objects, +/* + * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ static struct attribute *ltc4245_std_attributes[] = { @@ -578,19 +581,8 @@ static struct i2c_driver ltc4245_driver = { .id_table = ltc4245_id, }; -static int __init ltc4245_init(void) -{ - return i2c_add_driver(<c4245_driver); -} - -static void __exit ltc4245_exit(void) -{ - i2c_del_driver(<c4245_driver); -} +module_i2c_driver(ltc4245_driver); MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); MODULE_DESCRIPTION("LTC4245 driver"); MODULE_LICENSE("GPL"); - -module_init(ltc4245_init); -module_exit(ltc4245_exit); diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index ce5235560f01..069b7d34d8f9 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -235,11 +235,9 @@ static int ltc4261_probe(struct i2c_client *client, return -ENODEV; } - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto out_kzalloc; - } + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -250,7 +248,7 @@ static int ltc4261_probe(struct i2c_client *client, /* Register sysfs hooks */ ret = sysfs_create_group(&client->dev.kobj, <c4261_group); if (ret) - goto out_sysfs_create_group; + return ret; data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -262,9 +260,6 @@ static int ltc4261_probe(struct i2c_client *client, out_hwmon_device_register: sysfs_remove_group(&client->dev.kobj, <c4261_group); -out_sysfs_create_group: - kfree(data); -out_kzalloc: return ret; } @@ -275,8 +270,6 @@ static int ltc4261_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, <c4261_group); - kfree(data); - return 0; } @@ -297,19 +290,8 @@ static struct i2c_driver ltc4261_driver = { .id_table = ltc4261_id, }; -static int __init ltc4261_init(void) -{ - return i2c_add_driver(<c4261_driver); -} - -static void __exit ltc4261_exit(void) -{ - i2c_del_driver(<c4261_driver); -} +module_i2c_driver(ltc4261_driver); MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_DESCRIPTION("LTC4261 driver"); MODULE_LICENSE("GPL"); - -module_init(ltc4261_init); -module_exit(ltc4261_exit); diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 482ca901db30..362a40eb6129 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -106,7 +106,8 @@ static ssize_t show_adc(struct device *dev, if (ret < 0) return ret; - /* assume the reference voltage to be 2.048V, with an 8-bit sample, + /* + * assume the reference voltage to be 2.048V, with an 8-bit sample, * the LSB weight is 8mV */ return sprintf(buf, "%d\n", ret * 8); @@ -227,17 +228,7 @@ static struct spi_driver max1111_driver = { .remove = __devexit_p(max1111_remove), }; -static int __init max1111_init(void) -{ - return spi_register_driver(&max1111_driver); -} -module_init(max1111_init); - -static void __exit max1111_exit(void) -{ - spi_unregister_driver(&max1111_driver); -} -module_exit(max1111_exit); +module_spi_driver(max1111_driver); MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); MODULE_DESCRIPTION("MAX1111 ADC Driver"); diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index f8e323ac6cb3..822261be84dd 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -554,7 +554,7 @@ static int max16065_probe(struct i2c_client *client, | I2C_FUNC_SMBUS_READ_WORD_DATA)) return -ENODEV; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (unlikely(!data)) return -ENOMEM; @@ -567,20 +567,16 @@ static int max16065_probe(struct i2c_client *client, if (have_secondary) { val = i2c_smbus_read_byte_data(client, MAX16065_SW_ENABLE); - if (unlikely(val < 0)) { - ret = val; - goto out_free; - } + if (unlikely(val < 0)) + return val; secondary_is_max = val & MAX16065_WARNING_OV; } /* Read scale registers, convert to range */ for (i = 0; i < DIV_ROUND_UP(data->num_adc, 4); i++) { val = i2c_smbus_read_byte_data(client, MAX16065_SCALE(i)); - if (unlikely(val < 0)) { - ret = val; - goto out_free; - } + if (unlikely(val < 0)) + return val; for (j = 0; j < 4 && i * 4 + j < data->num_adc; j++) { data->range[i * 4 + j] = max16065_adc_range[(val >> (j * 2)) & 0x3]; @@ -595,10 +591,8 @@ static int max16065_probe(struct i2c_client *client, for (j = 0; j < data->num_adc; j++) { val = i2c_smbus_read_byte_data(client, MAX16065_LIMIT(i, j)); - if (unlikely(val < 0)) { - ret = val; - goto out_free; - } + if (unlikely(val < 0)) + return val; data->limit[i][j] = LIMIT_TO_MV(val, data->range[j]); } } @@ -661,8 +655,6 @@ static int max16065_probe(struct i2c_client *client, out: max16065_cleanup(client); -out_free: - kfree(data); return ret; } @@ -672,7 +664,6 @@ static int max16065_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); max16065_cleanup(client); - kfree(data); return 0; } @@ -699,19 +690,8 @@ static struct i2c_driver max16065_driver = { .id_table = max16065_id, }; -static int __init max16065_init(void) -{ - return i2c_add_driver(&max16065_driver); -} - -static void __exit max16065_exit(void) -{ - i2c_del_driver(&max16065_driver); -} +module_i2c_driver(max16065_driver); MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_DESCRIPTION("MAX16065 driver"); MODULE_LICENSE("GPL"); - -module_init(max16065_init); -module_exit(max16065_exit); diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 022ded098100..ecac04a7b7d6 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -125,7 +125,7 @@ struct max1619_data { u8 temp_input2, temp_low2, temp_high2; /* remote */ u8 temp_crit2; u8 temp_hyst2; - u8 alarms; + u8 alarms; }; /* @@ -133,7 +133,8 @@ struct max1619_data { */ #define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_##value(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct max1619_data *data = max1619_update_device(dev); \ return sprintf(buf, "%d\n", temp_from_reg(data->value)); \ @@ -146,13 +147,17 @@ show_temp(temp_crit2); show_temp(temp_hyst2); #define set_temp2(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ +static ssize_t set_##value(struct device *dev, struct device_attribute *attr, \ + const char *buf, \ size_t count) \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct max1619_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ + long val; \ + int err = kstrtol(buf, 10, &val); \ + if (err) \ + return err; \ +\ mutex_lock(&data->update_lock); \ data->value = temp_to_reg(val); \ i2c_smbus_write_byte_data(client, reg, data->value); \ @@ -165,7 +170,8 @@ set_temp2(temp_high2, MAX1619_REG_W_REMOTE_HIGH); set_temp2(temp_crit2, MAX1619_REG_W_REMOTE_CRIT); set_temp2(temp_hyst2, MAX1619_REG_W_TCRIT_HYST); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct max1619_data *data = max1619_update_device(dev); return sprintf(buf, "%d\n", data->alarms); @@ -275,7 +281,8 @@ static int max1619_probe(struct i2c_client *new_client, max1619_init_client(new_client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group))) + err = sysfs_create_group(&new_client->dev.kobj, &max1619_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&new_client->dev); @@ -353,20 +360,9 @@ static struct max1619_data *max1619_update_device(struct device *dev) return data; } -static int __init sensors_max1619_init(void) -{ - return i2c_add_driver(&max1619_driver); -} - -static void __exit sensors_max1619_exit(void) -{ - i2c_del_driver(&max1619_driver); -} +module_i2c_driver(max1619_driver); MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and " "Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("MAX1619 sensor driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_max1619_init); -module_exit(sensors_max1619_exit); diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 88953f99e914..335b183d7c02 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -1,23 +1,23 @@ /* - Copyright (c) 2011 David George <david.george@ska.ac.za> - - based on adm1021.c - some credit to Christoph Scheurer, but largely a rewrite - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * Copyright (c) 2011 David George <david.george@ska.ac.za> + * + * based on adm1021.c + * some credit to Christoph Scheurer, but largely a rewrite + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -484,19 +484,8 @@ static struct i2c_driver max1668_driver = { .address_list = max1668_addr_list, }; -static int __init sensors_max1668_init(void) -{ - return i2c_add_driver(&max1668_driver); -} - -static void __exit sensors_max1668_exit(void) -{ - i2c_del_driver(&max1668_driver); -} +module_i2c_driver(max1668_driver); MODULE_AUTHOR("David George <david.george@ska.ac.za>"); MODULE_DESCRIPTION("MAX1668 remote temperature sensor driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_max1668_init) -module_exit(sensors_max1668_exit) diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index a6760bacd915..193067e27b6f 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -637,19 +637,8 @@ static struct i2c_driver max6639_driver = { .address_list = normal_i2c, }; -static int __init max6639_init(void) -{ - return i2c_add_driver(&max6639_driver); -} - -static void __exit max6639_exit(void) -{ - i2c_del_driver(&max6639_driver); -} +module_i2c_driver(max6639_driver); MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); MODULE_DESCRIPTION("max6639 driver"); MODULE_LICENSE("GPL"); - -module_init(max6639_init); -module_exit(max6639_exit); diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 209e8a526eb1..4298909a41fd 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -352,19 +352,8 @@ static struct i2c_driver max6642_driver = { .address_list = normal_i2c, }; -static int __init max6642_init(void) -{ - return i2c_add_driver(&max6642_driver); -} - -static void __exit max6642_exit(void) -{ - i2c_del_driver(&max6642_driver); -} +module_i2c_driver(max6642_driver); MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>"); MODULE_DESCRIPTION("MAX6642 sensor driver"); MODULE_LICENSE("GPL"); - -module_init(max6642_init); -module_exit(max6642_exit); diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 2fc034aeca09..33a8a7f15e18 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -135,8 +135,7 @@ static struct i2c_driver max6650_driver = { * Client data (each client gets its own) */ -struct max6650_data -{ +struct max6650_data { struct device *hwmon_dev; struct mutex update_lock; int nr_fans; @@ -160,13 +159,13 @@ static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, int rpm; /* - * Calculation details: - * - * Each tachometer counts over an interval given by the "count" - * register (0.25, 0.5, 1 or 2 seconds). This module assumes - * that the fans produce two pulses per revolution (this seems - * to be the most common). - */ + * Calculation details: + * + * Each tachometer counts over an interval given by the "count" + * register (0.25, 0.5, 1 or 2 seconds). This module assumes + * that the fans produce two pulses per revolution (this seems + * to be the most common). + */ rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count)); return sprintf(buf, "%d\n", rpm); @@ -220,12 +219,12 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr, int kscale, ktach, rpm; /* - * Use the datasheet equation: - * - * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] - * - * then multiply by 60 to give rpm. - */ + * Use the datasheet equation: + * + * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] + * + * then multiply by 60 to give rpm. + */ kscale = DIV_FROM_REG(data->config); ktach = data->speed; @@ -238,17 +237,22 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr, { struct i2c_client *client = to_i2c_client(dev); struct max6650_data *data = i2c_get_clientdata(client); - int rpm = simple_strtoul(buf, NULL, 10); int kscale, ktach; + unsigned long rpm; + int err; + + err = kstrtoul(buf, 10, &rpm); + if (err) + return err; rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX); /* - * Divide the required speed by 60 to get from rpm to rps, then - * use the datasheet equation: - * - * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 - */ + * Divide the required speed by 60 to get from rpm to rps, then + * use the datasheet equation: + * + * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 + */ mutex_lock(&data->update_lock); @@ -282,8 +286,10 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, int pwm; struct max6650_data *data = max6650_update_device(dev); - /* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans. - Lower DAC values mean higher speeds. */ + /* + * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans. + * Lower DAC values mean higher speeds. + */ if (data->config & MAX6650_CFG_V12) pwm = 255 - (255 * (int)data->dac)/180; else @@ -300,7 +306,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, { struct i2c_client *client = to_i2c_client(dev); struct max6650_data *data = i2c_get_clientdata(client); - int pwm = simple_strtoul(buf, NULL, 10); + unsigned long pwm; + int err; + + err = kstrtoul(buf, 10, &pwm); + if (err) + return err; pwm = SENSORS_LIMIT(pwm, 0, 255); @@ -341,14 +352,16 @@ static ssize_t set_enable(struct device *dev, struct device_attribute *devattr, { struct i2c_client *client = to_i2c_client(dev); struct max6650_data *data = i2c_get_clientdata(client); - int mode = simple_strtoul(buf, NULL, 10); int max6650_modes[3] = {0, 3, 2}; + unsigned long mode; + int err; - if ((mode < 0)||(mode > 2)) { - dev_err(&client->dev, - "illegal value for pwm1_enable (%d)\n", mode); + err = kstrtoul(buf, 10, &mode); + if (err) + return err; + + if (mode > 2) return -EINVAL; - } mutex_lock(&data->update_lock); @@ -389,7 +402,12 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, { struct i2c_client *client = to_i2c_client(dev); struct max6650_data *data = i2c_get_clientdata(client); - int div = simple_strtoul(buf, NULL, 10); + unsigned long div; + int err; + + err = kstrtoul(buf, 10, &div); + if (err) + return err; mutex_lock(&data->update_lock); switch (div) { @@ -407,8 +425,6 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, break; default: mutex_unlock(&data->update_lock); - dev_err(&client->dev, - "illegal value for fan divider (%d)\n", div); return -EINVAL; } @@ -529,7 +545,8 @@ static int max6650_probe(struct i2c_client *client, struct max6650_data *data; int err; - if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL); + if (!data) { dev_err(&client->dev, "out of memory.\n"); return -ENOMEM; } @@ -596,55 +613,54 @@ static int max6650_init_client(struct i2c_client *client) } switch (fan_voltage) { - case 0: - break; - case 5: - config &= ~MAX6650_CFG_V12; - break; - case 12: - config |= MAX6650_CFG_V12; - break; - default: - dev_err(&client->dev, - "illegal value for fan_voltage (%d)\n", - fan_voltage); + case 0: + break; + case 5: + config &= ~MAX6650_CFG_V12; + break; + case 12: + config |= MAX6650_CFG_V12; + break; + default: + dev_err(&client->dev, "illegal value for fan_voltage (%d)\n", + fan_voltage); } dev_info(&client->dev, "Fan voltage is set to %dV.\n", (config & MAX6650_CFG_V12) ? 12 : 5); switch (prescaler) { - case 0: - break; - case 1: - config &= ~MAX6650_CFG_PRESCALER_MASK; - break; - case 2: - config = (config & ~MAX6650_CFG_PRESCALER_MASK) - | MAX6650_CFG_PRESCALER_2; - break; - case 4: - config = (config & ~MAX6650_CFG_PRESCALER_MASK) - | MAX6650_CFG_PRESCALER_4; - break; - case 8: - config = (config & ~MAX6650_CFG_PRESCALER_MASK) - | MAX6650_CFG_PRESCALER_8; - break; - case 16: - config = (config & ~MAX6650_CFG_PRESCALER_MASK) - | MAX6650_CFG_PRESCALER_16; - break; - default: - dev_err(&client->dev, - "illegal value for prescaler (%d)\n", - prescaler); + case 0: + break; + case 1: + config &= ~MAX6650_CFG_PRESCALER_MASK; + break; + case 2: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_2; + break; + case 4: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_4; + break; + case 8: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_8; + break; + case 16: + config = (config & ~MAX6650_CFG_PRESCALER_MASK) + | MAX6650_CFG_PRESCALER_16; + break; + default: + dev_err(&client->dev, "illegal value for prescaler (%d)\n", + prescaler); } dev_info(&client->dev, "Prescaler is set to %d.\n", 1 << (config & MAX6650_CFG_PRESCALER_MASK)); - /* If mode is set to "full off", we change it to "open loop" and + /* + * If mode is set to "full off", we change it to "open loop" and * set DAC to 255, which has the same effect. We do this because * there's no "full off" mode defined in hwmon specifcations. */ @@ -698,9 +714,11 @@ static struct max6650_data *max6650_update_device(struct device *dev) MAX6650_REG_COUNT); data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); - /* Alarms are cleared on read in case the condition that + /* + * Alarms are cleared on read in case the condition that * caused the alarm is removed. Keep the value latched here - * for providing the register through different alarm files. */ + * for providing the register through different alarm files. + */ data->alarm |= i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM); @@ -713,19 +731,8 @@ static struct max6650_data *max6650_update_device(struct device *dev) return data; } -static int __init sensors_max6650_init(void) -{ - return i2c_add_driver(&max6650_driver); -} - -static void __exit sensors_max6650_exit(void) -{ - i2c_del_driver(&max6650_driver); -} +module_i2c_driver(max6650_driver); MODULE_AUTHOR("Hans J. Koch"); MODULE_DESCRIPTION("MAX6650 sensor driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_max6650_init); -module_exit(sensors_max6650_exit); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 3d99b8854d7c..79ba48c8c116 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -56,11 +56,11 @@ static u8 confreg[4]; static int init = 1; module_param(init, int, 0); MODULE_PARM_DESC(init, - "Chip initialization level:\n" - " 0: None\n" - "*1: Forcibly enable internal voltage and temperature channels, except in9\n" - " 2: Forcibly enable all voltage and temperature channels, except in9\n" - " 3: Forcibly enable all voltage and temperature channels, including in9"); +"Chip initialization level:\n" +" 0: None\n" +"*1: Forcibly enable internal voltage and temperature channels, except in9\n" +" 2: Forcibly enable all voltage and temperature channels, except in9\n" +" 3: Forcibly enable all voltage and temperature channels, including in9"); static unsigned short force_id; module_param(force_id, ushort, 0); @@ -88,19 +88,19 @@ static const u8 logdev[LDNI_MAX] = { FSCM, VLM, TMS }; static inline void superio_outb(int sioaddr, int reg, int val) { outb(reg, sioaddr); - outb(val, sioaddr+1); + outb(val, sioaddr + 1); } static inline int superio_inb(int sioaddr, int reg) { outb(reg, sioaddr); - return inb(sioaddr+1); + return inb(sioaddr + 1); } static inline void superio_exit(int sioaddr) { outb(0x02, sioaddr); - outb(0x02, sioaddr+1); + outb(0x02, sioaddr + 1); } /* @@ -122,18 +122,18 @@ static inline void superio_exit(int sioaddr) #define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) #define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) -#define FAN_FROM_REG(val,div) ((val) == 0 ? 0: \ - 480000 / ((val)*(div))) -#define FAN_TO_REG(val,div) ((val) <= 100 ? 0 : \ - 480000 / ((val)*(div))) -#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) +#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : \ + 480000 / ((val) * (div))) +#define FAN_TO_REG(val, div) ((val) <= 100 ? 0 : \ + 480000 / ((val) * (div))) +#define FAN_DIV_FROM_REG(val) (1 << (((val) >> 5) & 0x03)) #define FAN_STATUS_FROM_REG(val) ((val) & 0x07) -#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) -#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) -#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) +#define FAN_CONFIG_MONITOR(val, nr) (((val) >> (2 + (nr) * 3)) & 1) +#define FAN_CONFIG_CONTROL(val, nr) (((val) >> (3 + (nr) * 3)) & 1) +#define FAN_CONFIG_INVERT(val, nr) (((val) >> (4 + (nr) * 3)) & 1) -#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) +#define PWM_FROM_REG(val, inv) ((inv) ? 255 - (val) : (val)) static inline u8 PWM_TO_REG(int val, int inv) { if (inv) @@ -159,10 +159,10 @@ static inline u8 PWM_TO_REG(int val, int inv) #define PC87365_REG_IN_ALARMS2 0x01 #define PC87365_REG_VID 0x06 -#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) -#define IN_TO_REG(val,ref) ((val) < 0 ? 0 : \ - (val)*256 >= (ref)*255 ? 255: \ - ((val) * 256 + (ref)/2) / (ref)) +#define IN_FROM_REG(val, ref) (((val) * (ref) + 128) / 256) +#define IN_TO_REG(val, ref) ((val) < 0 ? 0 : \ + (val) * 256 >= (ref) * 255 ? 255 : \ + ((val) * 256 + (ref) / 2) / (ref)) /* * Temperature registers and conversions @@ -255,43 +255,54 @@ static struct platform_driver pc87360_driver = { * Sysfs stuff */ -static ssize_t show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_fan_input(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index], FAN_DIV_FROM_REG(data->fan_status[attr->index]))); } -static ssize_t show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index], FAN_DIV_FROM_REG(data->fan_status[attr->index]))); } -static ssize_t show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", FAN_DIV_FROM_REG(data->fan_status[attr->index])); } -static ssize_t show_fan_status(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_fan_status(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", FAN_STATUS_FROM_REG(data->fan_status[attr->index])); } -static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, const char *buf, +static ssize_t set_fan_min(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long fan_min = simple_strtol(buf, NULL, 10); + long fan_min; + int err; + + err = kstrtol(buf, 10, &fan_min); + if (err) + return err; mutex_lock(&data->update_lock); - fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[attr->index])); + fan_min = FAN_TO_REG(fan_min, + FAN_DIV_FROM_REG(data->fan_status[attr->index])); /* If it wouldn't fit, change clock divisor */ while (fan_min > 255 @@ -301,11 +312,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr, data->fan_status[attr->index] += 0x20; } data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min; - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(attr->index), + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_MIN(attr->index), data->fan_min[attr->index]); /* Write new divider, preserve alarm bits */ - pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(attr->index), + pc87360_write_value(data, LD_FAN, NO_BANK, + PC87360_REG_FAN_STATUS(attr->index), data->fan_status[attr->index] & 0xF9); mutex_unlock(&data->update_lock); @@ -333,13 +346,16 @@ static struct sensor_device_attribute fan_min[] = { SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), }; -#define FAN_UNIT_ATTRS(X) \ - &fan_input[X].dev_attr.attr, \ +#define FAN_UNIT_ATTRS(X) \ +{ &fan_input[X].dev_attr.attr, \ &fan_status[X].dev_attr.attr, \ &fan_div[X].dev_attr.attr, \ - &fan_min[X].dev_attr.attr + &fan_min[X].dev_attr.attr, \ + NULL \ +} -static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); @@ -348,12 +364,17 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, ch FAN_CONFIG_INVERT(data->fan_conf, attr->index))); } -static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) +static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm[attr->index] = PWM_TO_REG(val, @@ -370,52 +391,60 @@ static struct sensor_device_attribute pwm[] = { SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), }; -static struct attribute * pc8736x_fan_attr_array[] = { +static struct attribute *pc8736x_fan_attr[][5] = { FAN_UNIT_ATTRS(0), FAN_UNIT_ATTRS(1), - FAN_UNIT_ATTRS(2), - &pwm[0].dev_attr.attr, - &pwm[1].dev_attr.attr, - &pwm[2].dev_attr.attr, - NULL + FAN_UNIT_ATTRS(2) }; -static const struct attribute_group pc8736x_fan_group = { - .attrs = pc8736x_fan_attr_array, + +static const struct attribute_group pc8736x_fan_attr_group[] = { + { .attrs = pc8736x_fan_attr[0], }, + { .attrs = pc8736x_fan_attr[1], }, + { .attrs = pc8736x_fan_attr[2], }, }; -static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_in_input(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index], data->in_vref)); } -static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_in_min(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], data->in_vref)); } -static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_in_max(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], data->in_vref)); } -static ssize_t show_in_status(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_in_status(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->in_status[attr->index]); } -static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) +static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[attr->index] = IN_TO_REG(val, data->in_vref); @@ -424,12 +453,17 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, mutex_unlock(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) +static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[attr->index] = IN_TO_REG(val, @@ -498,9 +532,11 @@ static struct sensor_device_attribute in_max[] = { #define CHAN_ALM_MAX 0x04 /* max limit exceeded */ #define TEMP_ALM_CRIT 0x08 /* temp crit exceeded (temp only) */ -/* show_in_min/max_alarm() reads data from the per-channel status - register (sec 11.5.12), not the vin event status registers (sec - 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms) */ +/* + * show_in_min/max_alarm() reads data from the per-channel status + * register (sec 11.5.12), not the vin event status registers (sec + * 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms) + */ static ssize_t show_in_min_alarm(struct device *dev, struct device_attribute *devattr, char *buf) @@ -554,27 +590,38 @@ static struct sensor_device_attribute in_max_alarm[] = { &in_min_alarm[X].dev_attr.attr, \ &in_max_alarm[X].dev_attr.attr -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, + char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, + char *buf) { struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct pc87360_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + data->vrm = val; return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_in_alarms(struct device *dev, + struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->in_alarms); @@ -602,46 +649,58 @@ static const struct attribute_group pc8736x_vin_group = { .attrs = pc8736x_vin_attr_array, }; -static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_therm_input(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index], data->in_vref)); } -static ssize_t show_therm_min(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_therm_min(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], data->in_vref)); } -static ssize_t show_therm_max(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_therm_max(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], data->in_vref)); } -static ssize_t show_therm_crit(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_therm_crit(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11], data->in_vref)); } -static ssize_t show_therm_status(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_therm_status(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->in_status[attr->index]); } -static ssize_t set_therm_min(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) + +static ssize_t set_therm_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[attr->index] = IN_TO_REG(val, data->in_vref); @@ -650,12 +709,19 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt mutex_unlock(&data->update_lock); return count; } -static ssize_t set_therm_max(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) + +static ssize_t set_therm_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[attr->index] = IN_TO_REG(val, data->in_vref); @@ -664,12 +730,18 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt mutex_unlock(&data->update_lock); return count; } -static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) +static ssize_t set_therm_crit(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref); @@ -679,46 +751,49 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat return count; } -/* the +11 term below reflects the fact that VLM units 11,12,13 are - used in the chip to measure voltage across the thermistors -*/ +/* + * the +11 term below reflects the fact that VLM units 11,12,13 are + * used in the chip to measure voltage across the thermistors + */ static struct sensor_device_attribute therm_input[] = { - SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0+11), - SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1+11), - SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2+11), + SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0 + 11), + SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1 + 11), + SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2 + 11), }; static struct sensor_device_attribute therm_status[] = { - SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0+11), - SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1+11), - SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2+11), + SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0 + 11), + SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1 + 11), + SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2 + 11), }; static struct sensor_device_attribute therm_min[] = { SENSOR_ATTR(temp4_min, S_IRUGO | S_IWUSR, - show_therm_min, set_therm_min, 0+11), + show_therm_min, set_therm_min, 0 + 11), SENSOR_ATTR(temp5_min, S_IRUGO | S_IWUSR, - show_therm_min, set_therm_min, 1+11), + show_therm_min, set_therm_min, 1 + 11), SENSOR_ATTR(temp6_min, S_IRUGO | S_IWUSR, - show_therm_min, set_therm_min, 2+11), + show_therm_min, set_therm_min, 2 + 11), }; static struct sensor_device_attribute therm_max[] = { SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, - show_therm_max, set_therm_max, 0+11), + show_therm_max, set_therm_max, 0 + 11), SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, - show_therm_max, set_therm_max, 1+11), + show_therm_max, set_therm_max, 1 + 11), SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, - show_therm_max, set_therm_max, 2+11), + show_therm_max, set_therm_max, 2 + 11), }; static struct sensor_device_attribute therm_crit[] = { SENSOR_ATTR(temp4_crit, S_IRUGO | S_IWUSR, - show_therm_crit, set_therm_crit, 0+11), + show_therm_crit, set_therm_crit, 0 + 11), SENSOR_ATTR(temp5_crit, S_IRUGO | S_IWUSR, - show_therm_crit, set_therm_crit, 1+11), + show_therm_crit, set_therm_crit, 1 + 11), SENSOR_ATTR(temp6_crit, S_IRUGO | S_IWUSR, - show_therm_crit, set_therm_crit, 2+11), + show_therm_crit, set_therm_crit, 2 + 11), }; -/* show_therm_min/max_alarm() reads data from the per-channel voltage - status register (sec 11.5.12) */ +/* + * show_therm_min/max_alarm() reads data from the per-channel voltage + * status register (sec 11.5.12) + */ static ssize_t show_therm_min_alarm(struct device *dev, struct device_attribute *devattr, char *buf) @@ -747,27 +822,27 @@ static ssize_t show_therm_crit_alarm(struct device *dev, static struct sensor_device_attribute therm_min_alarm[] = { SENSOR_ATTR(temp4_min_alarm, S_IRUGO, - show_therm_min_alarm, NULL, 0+11), + show_therm_min_alarm, NULL, 0 + 11), SENSOR_ATTR(temp5_min_alarm, S_IRUGO, - show_therm_min_alarm, NULL, 1+11), + show_therm_min_alarm, NULL, 1 + 11), SENSOR_ATTR(temp6_min_alarm, S_IRUGO, - show_therm_min_alarm, NULL, 2+11), + show_therm_min_alarm, NULL, 2 + 11), }; static struct sensor_device_attribute therm_max_alarm[] = { SENSOR_ATTR(temp4_max_alarm, S_IRUGO, - show_therm_max_alarm, NULL, 0+11), + show_therm_max_alarm, NULL, 0 + 11), SENSOR_ATTR(temp5_max_alarm, S_IRUGO, - show_therm_max_alarm, NULL, 1+11), + show_therm_max_alarm, NULL, 1 + 11), SENSOR_ATTR(temp6_max_alarm, S_IRUGO, - show_therm_max_alarm, NULL, 2+11), + show_therm_max_alarm, NULL, 2 + 11), }; static struct sensor_device_attribute therm_crit_alarm[] = { SENSOR_ATTR(temp4_crit_alarm, S_IRUGO, - show_therm_crit_alarm, NULL, 0+11), + show_therm_crit_alarm, NULL, 0 + 11), SENSOR_ATTR(temp5_crit_alarm, S_IRUGO, - show_therm_crit_alarm, NULL, 1+11), + show_therm_crit_alarm, NULL, 1 + 11), SENSOR_ATTR(temp6_crit_alarm, S_IRUGO, - show_therm_crit_alarm, NULL, 2+11), + show_therm_crit_alarm, NULL, 2 + 11), }; #define THERM_UNIT_ATTRS(X) \ @@ -780,7 +855,7 @@ static struct sensor_device_attribute therm_crit_alarm[] = { &therm_max_alarm[X].dev_attr.attr, \ &therm_crit_alarm[X].dev_attr.attr -static struct attribute * pc8736x_therm_attr_array[] = { +static struct attribute *pc8736x_therm_attr_array[] = { THERM_UNIT_ATTRS(0), THERM_UNIT_ATTRS(1), THERM_UNIT_ATTRS(2), @@ -790,42 +865,59 @@ static const struct attribute_group pc8736x_therm_group = { .attrs = pc8736x_therm_attr_array, }; -static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf) +static ssize_t show_temp_input(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf) + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index])); } -static ssize_t show_temp_max(struct device *dev, struct device_attribute *devattr, char *buf) + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index])); } -static ssize_t show_temp_crit(struct device *dev, struct device_attribute *devattr, char *buf) + +static ssize_t show_temp_crit(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[attr->index])); + return sprintf(buf, "%d\n", + TEMP_FROM_REG(data->temp_crit[attr->index])); } -static ssize_t show_temp_status(struct device *dev, struct device_attribute *devattr, char *buf) + +static ssize_t show_temp_status(struct device *dev, + struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%d\n", data->temp_status[attr->index]); } -static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) + +static ssize_t set_temp_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[attr->index] = TEMP_TO_REG(val); @@ -834,12 +926,19 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr mutex_unlock(&data->update_lock); return count; } -static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) + +static ssize_t set_temp_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[attr->index] = TEMP_TO_REG(val); @@ -848,12 +947,19 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr mutex_unlock(&data->update_lock); return count; } -static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devattr, const char *buf, - size_t count) + +static ssize_t set_temp_crit(struct device *dev, + struct device_attribute *devattr, const char *buf, + size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct pc87360_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_crit[attr->index] = TEMP_TO_REG(val); @@ -898,16 +1004,20 @@ static struct sensor_device_attribute temp_crit[] = { show_temp_crit, set_temp_crit, 2), }; -static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_alarms(struct device *dev, + struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->temp_alarms); } + static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); -/* show_temp_min/max_alarm() reads data from the per-channel status - register (sec 12.3.7), not the temp event status registers (sec - 12.3.2) that show_temp_alarm() reads (via data->temp_alarms) */ +/* + * show_temp_min/max_alarm() reads data from the per-channel status + * register (sec 12.3.7), not the temp event status registers (sec + * 12.3.2) that show_temp_alarm() reads (via data->temp_alarms) + */ static ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute *devattr, char *buf) @@ -917,6 +1027,7 @@ static ssize_t show_temp_min_alarm(struct device *dev, return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN)); } + static ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -925,6 +1036,7 @@ static ssize_t show_temp_max_alarm(struct device *dev, return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX)); } + static ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -939,11 +1051,13 @@ static struct sensor_device_attribute temp_min_alarm[] = { SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 1), SENSOR_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 2), }; + static struct sensor_device_attribute temp_max_alarm[] = { SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 0), SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 1), SENSOR_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 2), }; + static struct sensor_device_attribute temp_crit_alarm[] = { SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 0), SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 1), @@ -965,27 +1079,29 @@ static struct sensor_device_attribute temp_fault[] = { SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2), }; -#define TEMP_UNIT_ATTRS(X) \ - &temp_input[X].dev_attr.attr, \ - &temp_status[X].dev_attr.attr, \ - &temp_min[X].dev_attr.attr, \ - &temp_max[X].dev_attr.attr, \ - &temp_crit[X].dev_attr.attr, \ - &temp_min_alarm[X].dev_attr.attr, \ - &temp_max_alarm[X].dev_attr.attr, \ - &temp_crit_alarm[X].dev_attr.attr, \ - &temp_fault[X].dev_attr.attr - -static struct attribute * pc8736x_temp_attr_array[] = { +#define TEMP_UNIT_ATTRS(X) \ +{ &temp_input[X].dev_attr.attr, \ + &temp_status[X].dev_attr.attr, \ + &temp_min[X].dev_attr.attr, \ + &temp_max[X].dev_attr.attr, \ + &temp_crit[X].dev_attr.attr, \ + &temp_min_alarm[X].dev_attr.attr, \ + &temp_max_alarm[X].dev_attr.attr, \ + &temp_crit_alarm[X].dev_attr.attr, \ + &temp_fault[X].dev_attr.attr, \ + NULL \ +} + +static struct attribute *pc8736x_temp_attr[][10] = { TEMP_UNIT_ATTRS(0), TEMP_UNIT_ATTRS(1), - TEMP_UNIT_ATTRS(2), - /* include the few miscellaneous atts here */ - &dev_attr_alarms_temp.attr, - NULL + TEMP_UNIT_ATTRS(2) }; -static const struct attribute_group pc8736x_temp_group = { - .attrs = pc8736x_temp_attr_array, + +static const struct attribute_group pc8736x_temp_attr_group[] = { + { .attrs = pc8736x_temp_attr[0] }, + { .attrs = pc8736x_temp_attr[1] }, + { .attrs = pc8736x_temp_attr[2] } }; static ssize_t show_name(struct device *dev, @@ -994,13 +1110,15 @@ static ssize_t show_name(struct device *dev, struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } + static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* * Device detection, registration and update */ -static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses) +static int __init pc87360_find(int sioaddr, u8 *devid, + unsigned short *addresses) { u16 val; int i; @@ -1047,7 +1165,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses addresses[i] = val; - if (i==0) { /* Fans */ + if (i == 0) { /* Fans */ confreg[0] = superio_inb(sioaddr, 0xF0); confreg[1] = superio_inb(sioaddr, 0xF1); @@ -1060,12 +1178,14 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3, confreg[1] & 1, (confreg[1] >> 1) & 1, (confreg[1] >> 2) & 1); - } else if (i==1) { /* Voltages */ + } else if (i == 1) { /* Voltages */ /* Are we using thermistors? */ if (*devid == 0xE9) { /* PC87366 */ - /* These registers are not logical-device - specific, just that we won't need them if - we don't use the VLM device */ + /* + * These registers are not logical-device + * specific, just that we won't need them if + * we don't use the VLM device + */ confreg[2] = superio_inb(sioaddr, 0x2B); confreg[3] = superio_inb(sioaddr, 0x25); @@ -1085,6 +1205,22 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses return 0; } +static void pc87360_remove_files(struct device *dev) +{ + int i; + + device_remove_file(dev, &dev_attr_name); + device_remove_file(dev, &dev_attr_alarms_temp); + for (i = 0; i < ARRAY_SIZE(pc8736x_temp_attr_group); i++) + sysfs_remove_group(&dev->kobj, &pc8736x_temp_attr_group[i]); + for (i = 0; i < ARRAY_SIZE(pc8736x_fan_attr_group); i++) { + sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_attr_group[i]); + device_remove_file(dev, &pwm[i].dev_attr); + } + sysfs_remove_group(&dev->kobj, &pc8736x_therm_group); + sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); +} + static int __devinit pc87360_probe(struct platform_device *pdev) { int i; @@ -1094,7 +1230,8 @@ static int __devinit pc87360_probe(struct platform_device *pdev) int use_thermistors = 0; struct device *dev = &pdev->dev; - if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL))) + data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL); + if (!data) return -ENOMEM; data->fannr = 2; @@ -1130,9 +1267,10 @@ static int __devinit pc87360_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); for (i = 0; i < LDNI_MAX; i++) { - if (((data->address[i] = extra_isa[i])) + data->address[i] = extra_isa[i]; + if (data->address[i] && !request_region(extra_isa[i], PC87360_EXTENT, - pc87360_driver.driver.name)) { + pc87360_driver.driver.name)) { dev_err(dev, "Region 0x%x-0x%x already " "in use!\n", extra_isa[i], extra_isa[i]+PC87360_EXTENT-1); @@ -1147,9 +1285,11 @@ static int __devinit pc87360_probe(struct platform_device *pdev) if (data->fannr) data->fan_conf = confreg[0] | (confreg[1] << 8); - /* Use the correct reference voltage - Unless both the VLM and the TMS logical devices agree to - use an external Vref, the internal one is used. */ + /* + * Use the correct reference voltage + * Unless both the VLM and the TMS logical devices agree to + * use an external Vref, the internal one is used. + */ if (data->innr) { i = pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_IN_CONFIG); @@ -1182,62 +1322,48 @@ static int __devinit pc87360_probe(struct platform_device *pdev) /* Register all-or-nothing sysfs groups */ - if (data->innr && - (err = sysfs_create_group(&dev->kobj, - &pc8736x_vin_group))) - goto ERROR3; + if (data->innr) { + err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group); + if (err) + goto ERROR3; + } - if (data->innr == 14 && - (err = sysfs_create_group(&dev->kobj, - &pc8736x_therm_group))) - goto ERROR3; + if (data->innr == 14) { + err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group); + if (err) + goto ERROR3; + } /* create device attr-files for varying sysfs groups */ if (data->tempnr) { for (i = 0; i < data->tempnr; i++) { - if ((err = device_create_file(dev, - &temp_input[i].dev_attr)) - || (err = device_create_file(dev, - &temp_min[i].dev_attr)) - || (err = device_create_file(dev, - &temp_max[i].dev_attr)) - || (err = device_create_file(dev, - &temp_crit[i].dev_attr)) - || (err = device_create_file(dev, - &temp_status[i].dev_attr)) - || (err = device_create_file(dev, - &temp_min_alarm[i].dev_attr)) - || (err = device_create_file(dev, - &temp_max_alarm[i].dev_attr)) - || (err = device_create_file(dev, - &temp_crit_alarm[i].dev_attr)) - || (err = device_create_file(dev, - &temp_fault[i].dev_attr))) + err = sysfs_create_group(&dev->kobj, + &pc8736x_temp_attr_group[i]); + if (err) goto ERROR3; } - if ((err = device_create_file(dev, &dev_attr_alarms_temp))) + err = device_create_file(dev, &dev_attr_alarms_temp); + if (err) goto ERROR3; } for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i) - && ((err = device_create_file(dev, - &fan_input[i].dev_attr)) - || (err = device_create_file(dev, - &fan_min[i].dev_attr)) - || (err = device_create_file(dev, - &fan_div[i].dev_attr)) - || (err = device_create_file(dev, - &fan_status[i].dev_attr)))) - goto ERROR3; - - if (FAN_CONFIG_CONTROL(data->fan_conf, i) - && (err = device_create_file(dev, &pwm[i].dev_attr))) - goto ERROR3; + if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { + err = sysfs_create_group(&dev->kobj, + &pc8736x_fan_attr_group[i]); + if (err) + goto ERROR3; + } + if (FAN_CONFIG_CONTROL(data->fan_conf, i)) { + err = device_create_file(dev, &pwm[i].dev_attr); + if (err) + goto ERROR3; + } } - if ((err = device_create_file(dev, &dev_attr_name))) + err = device_create_file(dev, &dev_attr_name); + if (err) goto ERROR3; data->hwmon_dev = hwmon_device_register(dev); @@ -1248,16 +1374,10 @@ static int __devinit pc87360_probe(struct platform_device *pdev) return 0; ERROR3: - device_remove_file(dev, &dev_attr_name); - /* can still remove groups whose members were added individually */ - sysfs_remove_group(&dev->kobj, &pc8736x_temp_group); - sysfs_remove_group(&dev->kobj, &pc8736x_fan_group); - sysfs_remove_group(&dev->kobj, &pc8736x_therm_group); - sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); + pc87360_remove_files(dev); for (i = 0; i < 3; i++) { - if (data->address[i]) { + if (data->address[i]) release_region(data->address[i], PC87360_EXTENT); - } } ERROR1: kfree(data); @@ -1270,25 +1390,20 @@ static int __devexit pc87360_remove(struct platform_device *pdev) int i; hwmon_device_unregister(data->hwmon_dev); - - device_remove_file(&pdev->dev, &dev_attr_name); - sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group); - sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group); - sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group); - sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group); - + pc87360_remove_files(&pdev->dev); for (i = 0; i < 3; i++) { - if (data->address[i]) { + if (data->address[i]) release_region(data->address[i], PC87360_EXTENT); - } } kfree(data); return 0; } -/* ldi is the logical device index - bank is for voltages and temperatures only */ +/* + * ldi is the logical device index + * bank is for voltages and temperatures only + */ static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, u8 reg) { @@ -1359,8 +1474,10 @@ static void pc87360_init_device(struct platform_device *pdev, } } - /* We can't blindly trust the Super-I/O space configuration bit, - most BIOS won't set it properly */ + /* + * We can't blindly trust the Super-I/O space configuration bit, + * most BIOS won't set it properly + */ dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors); for (i = 11; i < data->innr; i++) { reg = pc87360_read_value(data, LD_IN, i, @@ -1375,12 +1492,12 @@ static void pc87360_init_device(struct platform_device *pdev, for (; i < data->tempnr; i++) { reg = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP_STATUS); - dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i+1, reg); + dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i + 1, reg); if (init >= init_temp[i]) { /* Forcibly enable temperature channel */ if (!(reg & CHAN_ENA)) { - dev_dbg(&pdev->dev, "Forcibly " - "enabling temp%d\n", i+1); + dev_dbg(&pdev->dev, + "Forcibly enabling temp%d\n", i + 1); pc87360_write_value(data, LD_TEMP, i, PC87365_REG_TEMP_STATUS, 0xCF); @@ -1391,14 +1508,16 @@ static void pc87360_init_device(struct platform_device *pdev, if (use_thermistors) { for (i = 11; i < data->innr; i++) { if (init >= init_in[i]) { - /* The pin may already be used by thermal - diodes */ + /* + * The pin may already be used by thermal + * diodes + */ reg = pc87360_read_value(data, LD_TEMP, - (i-11)/2, PC87365_REG_TEMP_STATUS); + (i - 11) / 2, PC87365_REG_TEMP_STATUS); if (reg & CHAN_ENA) { - dev_dbg(&pdev->dev, "Skipping " - "temp%d, pin already in use " - "by temp%d\n", i-7, (i-11)/2); + dev_dbg(&pdev->dev, + "Skipping temp%d, pin already in use by temp%d\n", + i - 7, (i - 11) / 2); continue; } @@ -1406,8 +1525,9 @@ static void pc87360_init_device(struct platform_device *pdev, reg = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN_STATUS); if (!(reg & CHAN_ENA)) { - dev_dbg(&pdev->dev, "Forcibly " - "enabling temp%d\n", i-7); + dev_dbg(&pdev->dev, + "Forcibly enabling temp%d\n", + i - 7); pc87360_write_value(data, LD_IN, i, PC87365_REG_TEMP_STATUS, (reg & 0x60) | 0x8F); @@ -1421,8 +1541,8 @@ static void pc87360_init_device(struct platform_device *pdev, PC87365_REG_IN_CONFIG); dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg); if (reg & CHAN_ENA) { - dev_dbg(&pdev->dev, "Forcibly " - "enabling monitoring (VLM)\n"); + dev_dbg(&pdev->dev, + "Forcibly enabling monitoring (VLM)\n"); pc87360_write_value(data, LD_IN, NO_BANK, PC87365_REG_IN_CONFIG, reg & 0xFE); @@ -1434,8 +1554,8 @@ static void pc87360_init_device(struct platform_device *pdev, PC87365_REG_TEMP_CONFIG); dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg); if (reg & CHAN_ENA) { - dev_dbg(&pdev->dev, "Forcibly enabling " - "monitoring (TMS)\n"); + dev_dbg(&pdev->dev, + "Forcibly enabling monitoring (TMS)\n"); pc87360_write_value(data, LD_TEMP, NO_BANK, PC87365_REG_TEMP_CONFIG, reg & 0xFE); @@ -1444,10 +1564,12 @@ static void pc87360_init_device(struct platform_device *pdev, if (init >= 2) { /* Chip config as documented by National Semi. */ pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); - /* We voluntarily omit the bank here, in case the - sequence itself matters. It shouldn't be a problem, - since nobody else is supposed to access the - device at that point. */ + /* + * We voluntarily omit the bank here, in case the + * sequence itself matters. It shouldn't be a problem, + * since nobody else is supposed to access the + * device at that point. + */ pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); @@ -1470,7 +1592,7 @@ static void pc87360_autodiv(struct device *dev, int nr) data->fan[nr] >>= 1; dev_dbg(dev, "Increasing " "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); + FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1); } } else { /* Decrease clock divider if possible */ @@ -1483,7 +1605,7 @@ static void pc87360_autodiv(struct device *dev, int nr) dev_dbg(dev, "Decreasing " "clock divider to %d for fan %d\n", FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); + nr + 1); } } diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index cb35461d52d9..37059a3755e9 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -46,9 +46,11 @@ static struct platform_device *pdev; #define DRVNAME "pc87427" -/* The lock mutex protects both the I/O accesses (needed because the - device is using banked registers) and the register cache (needed to keep - the data in the registers and the cache in sync at any time). */ +/* + * The lock mutex protects both the I/O accesses (needed because the + * device is using banked registers) and the register cache (needed to keep + * the data in the registers and the cache in sync at any time). + */ struct pc87427_data { struct device *hwmon_dev; struct mutex lock; @@ -173,10 +175,12 @@ static inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi, #define FAN_STATUS_LOSPD (1 << 1) #define FAN_STATUS_MONEN (1 << 0) -/* Dedicated function to read all registers related to a given fan input. - This saves us quite a few locks and bank selections. - Must be called with data->lock held. - nr is from 0 to 7 */ +/* + * Dedicated function to read all registers related to a given fan input. + * This saves us quite a few locks and bank selections. + * Must be called with data->lock held. + * nr is from 0 to 7 + */ static void pc87427_readall_fan(struct pc87427_data *data, u8 nr) { int iobase = data->address[LD_FAN]; @@ -189,8 +193,10 @@ static void pc87427_readall_fan(struct pc87427_data *data, u8 nr) outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS); } -/* The 2 LSB of fan speed registers are used for something different. - The actual 2 LSB of the measurements are not available. */ +/* + * The 2 LSB of fan speed registers are used for something different. + * The actual 2 LSB of the measurements are not available. + */ static inline unsigned long fan_from_reg(u16 reg) { reg &= 0xfffc; @@ -224,10 +230,12 @@ static inline u16 fan_to_reg(unsigned long val) #define PWM_MODE_OFF (2 << 4) #define PWM_MODE_ON (7 << 4) -/* Dedicated function to read all registers related to a given PWM output. - This saves us quite a few locks and bank selections. - Must be called with data->lock held. - nr is from 0 to 3 */ +/* + * Dedicated function to read all registers related to a given PWM output. + * This saves us quite a few locks and bank selections. + * Must be called with data->lock held. + * nr is from 0 to 3 + */ static void pc87427_readall_pwm(struct pc87427_data *data, u8 nr) { int iobase = data->address[LD_FAN]; @@ -286,10 +294,12 @@ static inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval) #define TEMP_TYPE_REMOTE_DIODE (2 << 5) #define TEMP_TYPE_LOCAL_DIODE (3 << 5) -/* Dedicated function to read all registers related to a given temperature - input. This saves us quite a few locks and bank selections. - Must be called with data->lock held. - nr is from 0 to 5 */ +/* + * Dedicated function to read all registers related to a given temperature + * input. This saves us quite a few locks and bank selections. + * Must be called with data->lock held. + * nr is from 0 to 5 + */ static void pc87427_readall_temp(struct pc87427_data *data, u8 nr) { int iobase = data->address[LD_TEMP]; @@ -318,8 +328,10 @@ static inline unsigned int temp_type_from_reg(u8 reg) } } -/* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible - too, but I have no idea how to figure out when they are used. */ +/* + * We assume 8-bit thermal sensors; 9-bit thermal sensors are possible + * too, but I have no idea how to figure out when they are used. + */ static inline long temp_from_reg(s16 reg) { return reg * 1000 / 256; @@ -423,9 +435,11 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute mutex_lock(&data->lock); outb(BANK_FM(nr), iobase + PC87427_REG_BANK); - /* The low speed limit registers are read-only while monitoring - is enabled, so we have to disable monitoring, then change the - limit, and finally enable monitoring again. */ + /* + * The low speed limit registers are read-only while monitoring + * is enabled, so we have to disable monitoring, then change the + * limit, and finally enable monitoring again. + */ outb(0, iobase + PC87427_REG_FAN_STATUS); data->fan_min[nr] = fan_to_reg(val); outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN); @@ -542,8 +556,10 @@ static const struct attribute_group pc87427_group_fan[8] = { { .attrs = pc87427_attributes_fan[7] }, }; -/* Must be called with data->lock held and pc87427_readall_pwm() freshly - called */ +/* + * Must be called with data->lock held and pc87427_readall_pwm() freshly + * called + */ static void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode) { int iobase = data->address[LD_FAN]; @@ -1023,9 +1039,11 @@ static void __devinit pc87427_init_device(struct device *dev) if (reg & PWM_ENABLE_CTLEN) data->pwm_enabled |= (1 << i); - /* We don't expose an interface to reconfigure the automatic - fan control mode, so only allow to return to this mode if - it was originally set. */ + /* + * We don't expose an interface to reconfigure the automatic + * fan control mode, so only allow to return to this mode if + * it was originally set. + */ if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) { dev_dbg(dev, "PWM%d is in automatic control mode\n", i + 1); diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index 731b09af76b9..4174c7463d70 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -1,22 +1,22 @@ /* - Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> - Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with - the help of Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> + * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with + * the help of Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -39,28 +39,34 @@ MODULE_PARM_DESC(input_mode, " 2 = single ended and differential mixed\n" " 3 = two differential inputs\n"); -/* The PCF8591 control byte - 7 6 5 4 3 2 1 0 - | 0 |AOEF| AIP | 0 |AINC| AICH | */ +/* + * The PCF8591 control byte + * 7 6 5 4 3 2 1 0 + * | 0 |AOEF| AIP | 0 |AINC| AICH | + */ /* Analog Output Enable Flag (analog output active if 1) */ #define PCF8591_CONTROL_AOEF 0x40 -/* Analog Input Programming - 0x00 = four single ended inputs - 0x10 = three differential inputs - 0x20 = single ended and differential mixed - 0x30 = two differential inputs */ +/* + * Analog Input Programming + * 0x00 = four single ended inputs + * 0x10 = three differential inputs + * 0x20 = single ended and differential mixed + * 0x30 = two differential inputs + */ #define PCF8591_CONTROL_AIP_MASK 0x30 /* Autoincrement Flag (switch on if 1) */ #define PCF8591_CONTROL_AINC 0x04 -/* Channel selection - 0x00 = channel 0 - 0x01 = channel 1 - 0x02 = channel 2 - 0x03 = channel 3 */ +/* + * Channel selection + * 0x00 = channel 0 + * 0x01 = channel 1 + * 0x02 = channel 2 + * 0x03 = channel 3 + */ #define PCF8591_CONTROL_AICH_MASK 0x03 /* Initial values */ @@ -68,7 +74,7 @@ MODULE_PARM_DESC(input_mode, #define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ /* Conversions */ -#define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg)) +#define REG_TO_SIGNED(reg) (((reg) & 0x80) ? ((reg) - 256) : (reg)) struct pcf8591_data { struct device *hwmon_dev; @@ -83,7 +89,9 @@ static int pcf8591_read_channel(struct device *dev, int channel); /* following are the sysfs callback functions */ #define show_in_channel(channel) \ -static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_in##channel##_input(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ } \ @@ -95,39 +103,57 @@ show_in_channel(1); show_in_channel(2); show_in_channel(3); -static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_out0_ouput(struct device *dev, + struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%d\n", data->aout * 10); } -static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_out0_output(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - unsigned int value; + unsigned long val; struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); - if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) { - data->aout = value; - i2c_smbus_write_byte_data(client, data->control, data->aout); - return count; - } - return -EINVAL; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + val /= 10; + if (val > 255) + return -EINVAL; + + data->aout = val; + i2c_smbus_write_byte_data(client, data->control, data->aout); + return count; } static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, show_out0_ouput, set_out0_output); -static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_out0_enable(struct device *dev, + struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); } -static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_out0_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); if (val) @@ -174,7 +200,8 @@ static int pcf8591_probe(struct i2c_client *client, struct pcf8591_data *data; int err; - if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit; } @@ -192,15 +219,15 @@ static int pcf8591_probe(struct i2c_client *client, /* Register input2 if not in "two differential inputs" mode */ if (input_mode != 3) { - if ((err = device_create_file(&client->dev, - &dev_attr_in2_input))) + err = device_create_file(&client->dev, &dev_attr_in2_input); + if (err) goto exit_sysfs_remove; } /* Register input3 only in "four single ended inputs" mode */ if (input_mode == 0) { - if ((err = device_create_file(&client->dev, - &dev_attr_in3_input))) + err = device_create_file(&client->dev, &dev_attr_in3_input); + if (err) goto exit_sysfs_remove; } @@ -241,8 +268,10 @@ static void pcf8591_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, data->control, data->aout); - /* The first byte transmitted contains the conversion code of the - previous read cycle. FLUSH IT! */ + /* + * The first byte transmitted contains the conversion code of the + * previous read cycle. FLUSH IT! + */ i2c_smbus_read_byte(client); } @@ -259,8 +288,10 @@ static int pcf8591_read_channel(struct device *dev, int channel) | channel; i2c_smbus_write_byte(client, data->control); - /* The first byte transmitted contains the conversion code of - the previous read cycle. FLUSH IT! */ + /* + * The first byte transmitted contains the conversion code of + * the previous read cycle. FLUSH IT! + */ i2c_smbus_read_byte(client); } value = i2c_smbus_read_byte(client); @@ -269,9 +300,9 @@ static int pcf8591_read_channel(struct device *dev, int channel) if ((channel == 2 && input_mode == 2) || (channel != 3 && (input_mode == 1 || input_mode == 3))) - return (10 * REG_TO_SIGNED(value)); + return 10 * REG_TO_SIGNED(value); else - return (10 * value); + return 10 * value; } static const struct i2c_device_id pcf8591_id[] = { diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index cfec923f42b7..2ca6a5a4f5a7 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -20,7 +20,8 @@ config SENSORS_PMBUS help If you say yes here you get hardware monitoring support for generic PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - NCP4200, and NCP4208. + MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, UDT020, TPS40400, + and TPS40422. This driver can also be built as a module. If so, the module will be called pmbus. @@ -30,8 +31,8 @@ config SENSORS_ADM1275 default n help If you say yes here you get hardware monitoring support for Analog - Devices ADM1275 and ADM1276 Hot-Swap Controller and Digital Power - Monitor. + Devices ADM1075, ADM1275, and ADM1276 Hot-Swap Controller and Digital + Power Monitors. This driver can also be built as a module. If so, the module will be called adm1275. @@ -67,11 +68,11 @@ config SENSORS_MAX16064 be called max16064. config SENSORS_MAX34440 - tristate "Maxim MAX34440/MAX34441" + tristate "Maxim MAX34440 and compatibles" default n help If you say yes here you get hardware monitoring support for Maxim - MAX34440 and MAX34441. + MAX34440, MAX34441, and MAX34446. This driver can also be built as a module. If so, the module will be called max34440. @@ -113,9 +114,9 @@ config SENSORS_ZL6100 default n help If you say yes here you get hardware monitoring support for Intersil - ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 - Digital DC/DC Controllers, as well as for Ericsson BMR450, BMR451, - BMR462, BMR463, and BMR464. + ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105, + ZL9101M, and ZL9117M Digital DC/DC Controllers, as well as for + Ericsson BMR450, BMR451, BMR462, BMR463, and BMR464. This driver can also be built as a module. If so, the module will be called zl6100. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 81c7c2ead6f3..60aad9570f01 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -23,7 +23,7 @@ #include <linux/i2c.h> #include "pmbus.h" -enum chips { adm1275, adm1276 }; +enum chips { adm1075, adm1275, adm1276 }; #define ADM1275_PEAK_IOUT 0xd0 #define ADM1275_PEAK_VIN 0xd1 @@ -32,6 +32,9 @@ enum chips { adm1275, adm1276 }; #define ADM1275_VIN_VOUT_SELECT (1 << 6) #define ADM1275_VRANGE (1 << 5) +#define ADM1075_IRANGE_50 (1 << 4) +#define ADM1075_IRANGE_25 (1 << 3) +#define ADM1075_IRANGE_MASK ((1 << 3) | (1 << 4)) #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 @@ -42,6 +45,14 @@ enum chips { adm1275, adm1276 }; #define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0) +#define ADM1075_READ_VAUX 0xdd +#define ADM1075_VAUX_OV_WARN_LIMIT 0xde +#define ADM1075_VAUX_UV_WARN_LIMIT 0xdf +#define ADM1075_VAUX_STATUS 0xf6 + +#define ADM1075_VAUX_OV_WARN (1<<7) +#define ADM1075_VAUX_UV_WARN (1<<6) + struct adm1275_data { int id; bool have_oc_fault; @@ -74,6 +85,29 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) } ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); break; + case PMBUS_VOUT_OV_WARN_LIMIT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = pmbus_read_word_data(client, 0, + ADM1075_VAUX_OV_WARN_LIMIT); + break; + case PMBUS_VOUT_UV_WARN_LIMIT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = pmbus_read_word_data(client, 0, + ADM1075_VAUX_UV_WARN_LIMIT); + break; + case PMBUS_READ_VOUT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); break; @@ -84,7 +118,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; case PMBUS_VIRT_READ_PIN_MAX: - if (data->id != adm1276) { + if (data->id == adm1275) { ret = -ENXIO; break; } @@ -95,7 +129,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_RESET_VIN_HISTORY: break; case PMBUS_VIRT_RESET_PIN_HISTORY: - if (data->id != adm1276) + if (data->id == adm1275) ret = -ENXIO; break; default: @@ -163,6 +197,19 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; } break; + case PMBUS_STATUS_VOUT: + if (data->id != adm1075) { + ret = -ENODATA; + break; + } + ret = 0; + mfr_status = pmbus_read_byte_data(client, 0, + ADM1075_VAUX_STATUS); + if (mfr_status & ADM1075_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1075_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; + break; default: ret = -ENODATA; break; @@ -171,6 +218,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) } static const struct i2c_device_id adm1275_id[] = { + { "adm1075", adm1075 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, { } @@ -229,7 +277,8 @@ static int adm1275_probe(struct i2c_client *client, if (device_config < 0) return device_config; - data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data), + GFP_KERNEL); if (!data) return -ENOMEM; @@ -250,7 +299,14 @@ static int adm1275_probe(struct i2c_client *client, info->read_byte_data = adm1275_read_byte_data; info->write_word_data = adm1275_write_word_data; - if (config & ADM1275_VRANGE) { + if (data->id == adm1075) { + info->m[PSC_VOLTAGE_IN] = 27169; + info->b[PSC_VOLTAGE_IN] = 0; + info->R[PSC_VOLTAGE_IN] = -1; + info->m[PSC_VOLTAGE_OUT] = 27169; + info->b[PSC_VOLTAGE_OUT] = 0; + info->R[PSC_VOLTAGE_OUT] = -1; + } else if (config & ADM1275_VRANGE) { info->m[PSC_VOLTAGE_IN] = 19199; info->b[PSC_VOLTAGE_IN] = 0; info->R[PSC_VOLTAGE_IN] = -2; @@ -270,6 +326,31 @@ static int adm1275_probe(struct i2c_client *client, data->have_oc_fault = true; switch (data->id) { + case adm1075: + info->format[PSC_POWER] = direct; + info->b[PSC_POWER] = 0; + info->R[PSC_POWER] = -1; + switch (config & ADM1075_IRANGE_MASK) { + case ADM1075_IRANGE_25: + info->m[PSC_POWER] = 8549; + info->m[PSC_CURRENT_OUT] = 806; + break; + case ADM1075_IRANGE_50: + info->m[PSC_POWER] = 4279; + info->m[PSC_CURRENT_OUT] = 404; + break; + default: + dev_err(&client->dev, "Invalid input current range"); + info->m[PSC_POWER] = 0; + info->m[PSC_CURRENT_OUT] = 0; + break; + } + info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN + | PMBUS_HAVE_STATUS_INPUT; + if (config & ADM1275_VIN_VOUT_SELECT) + info->func[0] |= + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + break; case adm1275: if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= @@ -297,24 +378,7 @@ static int adm1275_probe(struct i2c_client *client, break; } - ret = pmbus_do_probe(client, id, info); - if (ret) - goto err_mem; - return 0; - -err_mem: - kfree(data); - return ret; -} - -static int adm1275_remove(struct i2c_client *client) -{ - const struct pmbus_driver_info *info = pmbus_get_driver_info(client); - const struct adm1275_data *data = to_adm1275_data(info); - - pmbus_do_remove(client); - kfree(data); - return 0; + return pmbus_do_probe(client, id, info); } static struct i2c_driver adm1275_driver = { @@ -322,22 +386,12 @@ static struct i2c_driver adm1275_driver = { .name = "adm1275", }, .probe = adm1275_probe, - .remove = adm1275_remove, + .remove = pmbus_do_remove, .id_table = adm1275_id, }; -static int __init adm1275_init(void) -{ - return i2c_add_driver(&adm1275_driver); -} - -static void __exit adm1275_exit(void) -{ - i2c_del_driver(&adm1275_driver); -} +module_i2c_driver(adm1275_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); MODULE_LICENSE("GPL"); -module_init(adm1275_init); -module_exit(adm1275_exit); diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 84a37f0c8db6..c299392716af 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -176,7 +176,6 @@ static int lm25066_probe(struct i2c_client *client, const struct i2c_device_id *id) { int config; - int ret; struct lm25066_data *data; struct pmbus_driver_info *info; @@ -184,15 +183,14 @@ static int lm25066_probe(struct i2c_client *client, I2C_FUNC_SMBUS_READ_BYTE_DATA)) return -ENODEV; - data = kzalloc(sizeof(struct lm25066_data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(struct lm25066_data), + GFP_KERNEL); if (!data) return -ENOMEM; config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP); - if (config < 0) { - ret = config; - goto err_mem; - } + if (config < 0) + return config; data->id = id->driver_data; info = &data->info; @@ -291,28 +289,10 @@ static int lm25066_probe(struct i2c_client *client, } break; default: - ret = -ENODEV; - goto err_mem; + return -ENODEV; } - ret = pmbus_do_probe(client, id, info); - if (ret) - goto err_mem; - return 0; - -err_mem: - kfree(data); - return ret; -} - -static int lm25066_remove(struct i2c_client *client) -{ - const struct pmbus_driver_info *info = pmbus_get_driver_info(client); - const struct lm25066_data *data = to_lm25066_data(info); - - pmbus_do_remove(client); - kfree(data); - return 0; + return pmbus_do_probe(client, id, info); } static const struct i2c_device_id lm25066_id[] = { @@ -330,22 +310,12 @@ static struct i2c_driver lm25066_driver = { .name = "lm25066", }, .probe = lm25066_probe, - .remove = lm25066_remove, + .remove = pmbus_do_remove, .id_table = lm25066_id, }; -static int __init lm25066_init(void) -{ - return i2c_add_driver(&lm25066_driver); -} - -static void __exit lm25066_exit(void) -{ - i2c_del_driver(&lm25066_driver); -} +module_i2c_driver(lm25066_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066"); MODULE_LICENSE("GPL"); -module_init(lm25066_init); -module_exit(lm25066_exit); diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 820fff48910b..9652a2c92a24 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -287,7 +287,7 @@ MODULE_DEVICE_TABLE(i2c, ltc2978_id); static int ltc2978_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int chip_id, ret, i; + int chip_id, i; struct ltc2978_data *data; struct pmbus_driver_info *info; @@ -295,15 +295,14 @@ static int ltc2978_probe(struct i2c_client *client, I2C_FUNC_SMBUS_READ_WORD_DATA)) return -ENODEV; - data = kzalloc(sizeof(struct ltc2978_data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(struct ltc2978_data), + GFP_KERNEL); if (!data) return -ENOMEM; chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); - if (chip_id < 0) { - ret = chip_id; - goto err_mem; - } + if (chip_id < 0) + return chip_id; if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { data->id = ltc2978; @@ -311,8 +310,7 @@ static int ltc2978_probe(struct i2c_client *client, data->id = ltc3880; } else { dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); - ret = -ENODEV; - goto err_mem; + return -ENODEV; } if (data->id != id->driver_data) dev_warn(&client->dev, @@ -357,28 +355,10 @@ static int ltc2978_probe(struct i2c_client *client, data->vout_min[1] = 0xffff; break; default: - ret = -ENODEV; - goto err_mem; + return -ENODEV; } - ret = pmbus_do_probe(client, id, info); - if (ret) - goto err_mem; - return 0; - -err_mem: - kfree(data); - return ret; -} - -static int ltc2978_remove(struct i2c_client *client) -{ - const struct pmbus_driver_info *info = pmbus_get_driver_info(client); - const struct ltc2978_data *data = to_ltc2978_data(info); - - pmbus_do_remove(client); - kfree(data); - return 0; + return pmbus_do_probe(client, id, info); } /* This is the driver that will be inserted */ @@ -387,22 +367,12 @@ static struct i2c_driver ltc2978_driver = { .name = "ltc2978", }, .probe = ltc2978_probe, - .remove = ltc2978_remove, + .remove = pmbus_do_remove, .id_table = ltc2978_id, }; -static int __init ltc2978_init(void) -{ - return i2c_add_driver(<c2978_driver); -} - -static void __exit ltc2978_exit(void) -{ - i2c_del_driver(<c2978_driver); -} +module_i2c_driver(ltc2978_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880"); MODULE_LICENSE("GPL"); -module_init(ltc2978_init); -module_exit(ltc2978_exit); diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 1d77cf4d2d44..fa237a3c3291 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -103,12 +103,6 @@ static int max16064_probe(struct i2c_client *client, return pmbus_do_probe(client, id, &max16064_info); } -static int max16064_remove(struct i2c_client *client) -{ - pmbus_do_remove(client); - return 0; -} - static const struct i2c_device_id max16064_id[] = { {"max16064", 0}, {} @@ -122,22 +116,12 @@ static struct i2c_driver max16064_driver = { .name = "max16064", }, .probe = max16064_probe, - .remove = max16064_remove, + .remove = pmbus_do_remove, .id_table = max16064_id, }; -static int __init max16064_init(void) -{ - return i2c_add_driver(&max16064_driver); -} - -static void __exit max16064_exit(void) -{ - i2c_del_driver(&max16064_driver); -} +module_i2c_driver(max16064_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064"); MODULE_LICENSE("GPL"); -module_init(max16064_init); -module_exit(max16064_exit); diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index 9b97a5b3cf3d..2ada7b021fbe 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -25,34 +25,82 @@ #include <linux/i2c.h> #include "pmbus.h" -enum chips { max34440, max34441 }; +enum chips { max34440, max34441, max34446 }; #define MAX34440_MFR_VOUT_PEAK 0xd4 #define MAX34440_MFR_IOUT_PEAK 0xd5 #define MAX34440_MFR_TEMPERATURE_PEAK 0xd6 +#define MAX34440_MFR_VOUT_MIN 0xd7 + +#define MAX34446_MFR_POUT_PEAK 0xe0 +#define MAX34446_MFR_POUT_AVG 0xe1 +#define MAX34446_MFR_IOUT_AVG 0xe2 +#define MAX34446_MFR_TEMPERATURE_AVG 0xe3 #define MAX34440_STATUS_OC_WARN (1 << 0) #define MAX34440_STATUS_OC_FAULT (1 << 1) #define MAX34440_STATUS_OT_FAULT (1 << 5) #define MAX34440_STATUS_OT_WARN (1 << 6) +struct max34440_data { + int id; + struct pmbus_driver_info info; +}; + +#define to_max34440_data(x) container_of(x, struct max34440_data, info) + static int max34440_read_word_data(struct i2c_client *client, int page, int reg) { int ret; + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct max34440_data *data = to_max34440_data(info); switch (reg) { + case PMBUS_VIRT_READ_VOUT_MIN: + ret = pmbus_read_word_data(client, page, + MAX34440_MFR_VOUT_MIN); + break; case PMBUS_VIRT_READ_VOUT_MAX: ret = pmbus_read_word_data(client, page, MAX34440_MFR_VOUT_PEAK); break; + case PMBUS_VIRT_READ_IOUT_AVG: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_IOUT_AVG); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, page, MAX34440_MFR_IOUT_PEAK); break; + case PMBUS_VIRT_READ_POUT_AVG: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_POUT_AVG); + break; + case PMBUS_VIRT_READ_POUT_MAX: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_POUT_PEAK); + break; + case PMBUS_VIRT_READ_TEMP_AVG: + if (data->id != max34446) + return -ENXIO; + ret = pmbus_read_word_data(client, page, + MAX34446_MFR_TEMPERATURE_AVG); + break; case PMBUS_VIRT_READ_TEMP_MAX: ret = pmbus_read_word_data(client, page, MAX34440_MFR_TEMPERATURE_PEAK); break; + case PMBUS_VIRT_RESET_POUT_HISTORY: + if (data->id != max34446) + return -ENXIO; + ret = 0; + break; case PMBUS_VIRT_RESET_VOUT_HISTORY: case PMBUS_VIRT_RESET_IOUT_HISTORY: case PMBUS_VIRT_RESET_TEMP_HISTORY: @@ -68,21 +116,42 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg) static int max34440_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct max34440_data *data = to_max34440_data(info); int ret; switch (reg) { + case PMBUS_VIRT_RESET_POUT_HISTORY: + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_POUT_PEAK, 0); + if (ret) + break; + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_POUT_AVG, 0); + break; case PMBUS_VIRT_RESET_VOUT_HISTORY: ret = pmbus_write_word_data(client, page, + MAX34440_MFR_VOUT_MIN, 0x7fff); + if (ret) + break; + ret = pmbus_write_word_data(client, page, MAX34440_MFR_VOUT_PEAK, 0); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: ret = pmbus_write_word_data(client, page, MAX34440_MFR_IOUT_PEAK, 0); + if (!ret && data->id == max34446) + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_IOUT_AVG, 0); + break; case PMBUS_VIRT_RESET_TEMP_HISTORY: ret = pmbus_write_word_data(client, page, MAX34440_MFR_TEMPERATURE_PEAK, 0x8000); + if (!ret && data->id == max34446) + ret = pmbus_write_word_data(client, page, + MAX34446_MFR_TEMPERATURE_AVG, 0); break; default: ret = -ENODATA; @@ -216,26 +285,66 @@ static struct pmbus_driver_info max34440_info[] = { .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, + [max34446] = { + .pages = 7, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .m[PSC_VOLTAGE_IN] = 1, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = 3, + .m[PSC_VOLTAGE_OUT] = 1, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 3, + .m[PSC_CURRENT_OUT] = 1, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = 3, + .m[PSC_POWER] = 1, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = 3, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 2, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, + .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[4] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[5] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .read_byte_data = max34440_read_byte_data, + .read_word_data = max34440_read_word_data, + .write_word_data = max34440_write_word_data, + }, }; static int max34440_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return pmbus_do_probe(client, id, &max34440_info[id->driver_data]); -} + struct max34440_data *data; -static int max34440_remove(struct i2c_client *client) -{ - pmbus_do_remove(client); - return 0; + data = devm_kzalloc(&client->dev, sizeof(struct max34440_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + data->id = id->driver_data; + data->info = max34440_info[id->driver_data]; + + return pmbus_do_probe(client, id, &data->info); } static const struct i2c_device_id max34440_id[] = { {"max34440", max34440}, {"max34441", max34441}, + {"max34446", max34446}, {} }; - MODULE_DEVICE_TABLE(i2c, max34440_id); /* This is the driver that will be inserted */ @@ -244,22 +353,12 @@ static struct i2c_driver max34440_driver = { .name = "max34440", }, .probe = max34440_probe, - .remove = max34440_remove, + .remove = pmbus_do_remove, .id_table = max34440_id, }; -static int __init max34440_init(void) -{ - return i2c_add_driver(&max34440_driver); -} - -static void __exit max34440_exit(void) -{ - i2c_del_driver(&max34440_driver); -} +module_i2c_driver(max34440_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441"); MODULE_LICENSE("GPL"); -module_init(max34440_init); -module_exit(max34440_exit); diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index e2b74bb399ba..f04454a42fdd 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -180,12 +180,6 @@ static int max8688_probe(struct i2c_client *client, return pmbus_do_probe(client, id, &max8688_info); } -static int max8688_remove(struct i2c_client *client) -{ - pmbus_do_remove(client); - return 0; -} - static const struct i2c_device_id max8688_id[] = { {"max8688", 0}, { } @@ -199,22 +193,12 @@ static struct i2c_driver max8688_driver = { .name = "max8688", }, .probe = max8688_probe, - .remove = max8688_remove, + .remove = pmbus_do_remove, .id_table = max8688_id, }; -static int __init max8688_init(void) -{ - return i2c_add_driver(&max8688_driver); -} - -static void __exit max8688_exit(void) -{ - i2c_del_driver(&max8688_driver); -} +module_i2c_driver(max8688_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688"); MODULE_LICENSE("GPL"); -module_init(max8688_init); -module_exit(max8688_exit); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 18a385e753d7..7e91700131a7 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -166,33 +166,16 @@ static int pmbus_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pmbus_driver_info *info; - int ret; - info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL); + info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info), + GFP_KERNEL); if (!info) return -ENOMEM; info->pages = id->driver_data; info->identify = pmbus_identify; - ret = pmbus_do_probe(client, id, info); - if (ret < 0) - goto out; - return 0; - -out: - kfree(info); - return ret; -} - -static int pmbus_remove(struct i2c_client *client) -{ - const struct pmbus_driver_info *info; - - info = pmbus_get_driver_info(client); - pmbus_do_remove(client); - kfree(info); - return 0; + return pmbus_do_probe(client, id, info); } /* @@ -202,12 +185,15 @@ static const struct i2c_device_id pmbus_id[] = { {"adp4000", 1}, {"bmr453", 1}, {"bmr454", 1}, + {"mdt040", 1}, {"ncp4200", 1}, {"ncp4208", 1}, {"pdt003", 1}, {"pdt006", 1}, {"pdt012", 1}, {"pmbus", 0}, + {"tps40400", 1}, + {"tps40422", 2}, {"udt020", 1}, {} }; @@ -220,22 +206,12 @@ static struct i2c_driver pmbus_driver = { .name = "pmbus", }, .probe = pmbus_probe, - .remove = pmbus_remove, + .remove = pmbus_do_remove, .id_table = pmbus_id, }; -static int __init pmbus_init(void) -{ - return i2c_add_driver(&pmbus_driver); -} - -static void __exit pmbus_exit(void) -{ - i2c_del_driver(&pmbus_driver); -} +module_i2c_driver(pmbus_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("Generic PMBus driver"); MODULE_LICENSE("GPL"); -module_init(pmbus_init); -module_exit(pmbus_exit); diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 5d31d1c2c0f5..3fe03dc47eb7 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -146,31 +146,36 @@ * code when reading or writing virtual registers. */ #define PMBUS_VIRT_BASE 0x100 -#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 0) -#define PMBUS_VIRT_READ_TEMP_MAX (PMBUS_VIRT_BASE + 1) -#define PMBUS_VIRT_RESET_TEMP_HISTORY (PMBUS_VIRT_BASE + 2) -#define PMBUS_VIRT_READ_VIN_AVG (PMBUS_VIRT_BASE + 3) -#define PMBUS_VIRT_READ_VIN_MIN (PMBUS_VIRT_BASE + 4) -#define PMBUS_VIRT_READ_VIN_MAX (PMBUS_VIRT_BASE + 5) -#define PMBUS_VIRT_RESET_VIN_HISTORY (PMBUS_VIRT_BASE + 6) -#define PMBUS_VIRT_READ_IIN_AVG (PMBUS_VIRT_BASE + 7) -#define PMBUS_VIRT_READ_IIN_MIN (PMBUS_VIRT_BASE + 8) -#define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 9) -#define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 10) -#define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 11) -#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 12) -#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 13) -#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 14) -#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 15) -#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 16) -#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 17) -#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 18) -#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 19) -#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 20) -#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 21) -#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 22) -#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 23) -#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 24) +#define PMBUS_VIRT_READ_TEMP_AVG (PMBUS_VIRT_BASE + 0) +#define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 1) +#define PMBUS_VIRT_READ_TEMP_MAX (PMBUS_VIRT_BASE + 2) +#define PMBUS_VIRT_RESET_TEMP_HISTORY (PMBUS_VIRT_BASE + 3) +#define PMBUS_VIRT_READ_VIN_AVG (PMBUS_VIRT_BASE + 4) +#define PMBUS_VIRT_READ_VIN_MIN (PMBUS_VIRT_BASE + 5) +#define PMBUS_VIRT_READ_VIN_MAX (PMBUS_VIRT_BASE + 6) +#define PMBUS_VIRT_RESET_VIN_HISTORY (PMBUS_VIRT_BASE + 7) +#define PMBUS_VIRT_READ_IIN_AVG (PMBUS_VIRT_BASE + 8) +#define PMBUS_VIRT_READ_IIN_MIN (PMBUS_VIRT_BASE + 9) +#define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 10) +#define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 11) +#define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 12) +#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 13) +#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 14) +#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 15) +#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 16) +#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 17) +#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 18) +#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 19) +#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 20) +#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 21) +#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 22) +#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 23) +#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 24) +#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 25) +#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 26) +#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 27) +#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28) +#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29) /* * CAPABILITY @@ -364,7 +369,7 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, struct pmbus_driver_info *info); -void pmbus_do_remove(struct i2c_client *client); +int pmbus_do_remove(struct i2c_client *client); const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index d89b33967a85..be51037363c8 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -40,11 +40,14 @@ #define PMBUS_IOUT_SENSORS_PER_PAGE 8 /* input, min, max, crit, lowest, highest, avg, reset */ -#define PMBUS_POUT_SENSORS_PER_PAGE 4 /* input, cap, max, crit */ +#define PMBUS_POUT_SENSORS_PER_PAGE 7 /* input, cap, max, crit, + * highest, avg, reset + */ #define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */ -#define PMBUS_MAX_SENSORS_PER_TEMP 8 /* input, min, max, lcrit, - crit, lowest, highest, - reset */ +#define PMBUS_MAX_SENSORS_PER_TEMP 9 /* input, min, max, lcrit, + * crit, lowest, highest, avg, + * reset + */ #define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm, lcrit_alarm, crit_alarm; @@ -782,7 +785,7 @@ static ssize_t pmbus_set_sensor(struct device *dev, int ret; u16 regval; - if (strict_strtol(buf, 10, &val) < 0) + if (kstrtol(buf, 10, &val) < 0) return -EINVAL; mutex_lock(&data->update_lock); @@ -1334,6 +1337,17 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { .attr = "crit", .alarm = "crit_alarm", .sbit = PB_POUT_OP_FAULT, + }, { + .reg = PMBUS_VIRT_READ_POUT_AVG, + .update = true, + .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_POUT_MAX, + .update = true, + .attr = "input_highest", + }, { + .reg = PMBUS_VIRT_RESET_POUT_HISTORY, + .attr = "reset_history", } }; @@ -1389,6 +1403,9 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { .reg = PMBUS_VIRT_READ_TEMP_MIN, .attr = "lowest", }, { + .reg = PMBUS_VIRT_READ_TEMP_AVG, + .attr = "average", + }, { .reg = PMBUS_VIRT_READ_TEMP_MAX, .attr = "highest", }, { @@ -1424,6 +1441,9 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { .reg = PMBUS_VIRT_READ_TEMP2_MIN, .attr = "lowest", }, { + .reg = PMBUS_VIRT_READ_TEMP2_AVG, + .attr = "average", + }, { .reg = PMBUS_VIRT_READ_TEMP2_MAX, .attr = "highest", }, { @@ -1676,7 +1696,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(&client->dev, "No memory to allocate driver data\n"); return -ENOMEM; @@ -1688,8 +1708,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, /* Bail out if PMBus status register does not exist. */ if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) { dev_err(&client->dev, "PMBus status register not found\n"); - ret = -ENODEV; - goto out_data; + return -ENODEV; } if (pdata) @@ -1702,50 +1721,49 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, ret = (*info->identify)(client, info); if (ret < 0) { dev_err(&client->dev, "Chip identification failed\n"); - goto out_data; + return ret; } } if (info->pages <= 0 || info->pages > PMBUS_PAGES) { dev_err(&client->dev, "Bad number of PMBus pages: %d\n", info->pages); - ret = -ENODEV; - goto out_data; + return -ENODEV; } ret = pmbus_identify_common(client, data); if (ret < 0) { dev_err(&client->dev, "Failed to identify chip capabilities\n"); - goto out_data; + return ret; } ret = -ENOMEM; - data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors, - GFP_KERNEL); + data->sensors = devm_kzalloc(&client->dev, sizeof(struct pmbus_sensor) + * data->max_sensors, GFP_KERNEL); if (!data->sensors) { dev_err(&client->dev, "No memory to allocate sensor data\n"); - goto out_data; + return -ENOMEM; } - data->booleans = kzalloc(sizeof(struct pmbus_boolean) + data->booleans = devm_kzalloc(&client->dev, sizeof(struct pmbus_boolean) * data->max_booleans, GFP_KERNEL); if (!data->booleans) { dev_err(&client->dev, "No memory to allocate boolean data\n"); - goto out_sensors; + return -ENOMEM; } - data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels, - GFP_KERNEL); + data->labels = devm_kzalloc(&client->dev, sizeof(struct pmbus_label) + * data->max_labels, GFP_KERNEL); if (!data->labels) { dev_err(&client->dev, "No memory to allocate label data\n"); - goto out_booleans; + return -ENOMEM; } - data->attributes = kzalloc(sizeof(struct attribute *) - * data->max_attributes, GFP_KERNEL); + data->attributes = devm_kzalloc(&client->dev, sizeof(struct attribute *) + * data->max_attributes, GFP_KERNEL); if (!data->attributes) { dev_err(&client->dev, "No memory to allocate attribute data\n"); - goto out_labels; + return -ENOMEM; } pmbus_find_attributes(client, data); @@ -1756,8 +1774,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, */ if (!data->num_attributes) { dev_err(&client->dev, "No attributes found\n"); - ret = -ENODEV; - goto out_attributes; + return -ENODEV; } /* Register sysfs hooks */ @@ -1765,7 +1782,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, ret = sysfs_create_group(&client->dev.kobj, &data->group); if (ret) { dev_err(&client->dev, "Failed to create sysfs entries\n"); - goto out_attributes; + return ret; } data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -1777,30 +1794,16 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, out_hwmon_device_register: sysfs_remove_group(&client->dev.kobj, &data->group); -out_attributes: - kfree(data->attributes); -out_labels: - kfree(data->labels); -out_booleans: - kfree(data->booleans); -out_sensors: - kfree(data->sensors); -out_data: - kfree(data); return ret; } EXPORT_SYMBOL_GPL(pmbus_do_probe); -void pmbus_do_remove(struct i2c_client *client) +int pmbus_do_remove(struct i2c_client *client) { struct pmbus_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->group); - kfree(data->attributes); - kfree(data->labels); - kfree(data->booleans); - kfree(data->sensors); - kfree(data); + return 0; } EXPORT_SYMBOL_GPL(pmbus_do_remove); diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 4ff6cf289f85..fbb1479d3ad4 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -155,7 +155,8 @@ static int ucd9000_probe(struct i2c_client *client, "Device mismatch: Configured %s, detected %s\n", id->name, mid->name); - data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), + GFP_KERNEL); if (!data) return -ENOMEM; info = &data->info; @@ -164,13 +165,12 @@ static int ucd9000_probe(struct i2c_client *client, if (ret < 0) { dev_err(&client->dev, "Failed to read number of active pages\n"); - goto out; + return ret; } info->pages = ret; if (!info->pages) { dev_err(&client->dev, "No pages configured\n"); - ret = -ENODEV; - goto out; + return -ENODEV; } /* The internal temperature sensor is always active */ @@ -181,8 +181,7 @@ static int ucd9000_probe(struct i2c_client *client, block_buffer); if (ret <= 0) { dev_err(&client->dev, "Failed to read configuration data\n"); - ret = -ENODEV; - goto out; + return -ENODEV; } for (i = 0; i < ret; i++) { int page = UCD9000_MON_PAGE(block_buffer[i]); @@ -218,7 +217,7 @@ static int ucd9000_probe(struct i2c_client *client, UCD9000_FAN_CONFIG, data->fan_data[i]); if (ret < 0) - goto out; + return ret; } i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); @@ -227,49 +226,21 @@ static int ucd9000_probe(struct i2c_client *client, | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; } - ret = pmbus_do_probe(client, mid, info); - if (ret < 0) - goto out; - return 0; - -out: - kfree(data); - return ret; -} - -static int ucd9000_remove(struct i2c_client *client) -{ - struct ucd9000_data *data; - - data = to_ucd9000_data(pmbus_get_driver_info(client)); - pmbus_do_remove(client); - kfree(data); - return 0; + return pmbus_do_probe(client, mid, info); } - /* This is the driver that will be inserted */ static struct i2c_driver ucd9000_driver = { .driver = { .name = "ucd9000", }, .probe = ucd9000_probe, - .remove = ucd9000_remove, + .remove = pmbus_do_remove, .id_table = ucd9000_id, }; -static int __init ucd9000_init(void) -{ - return i2c_add_driver(&ucd9000_driver); -} - -static void __exit ucd9000_exit(void) -{ - i2c_del_driver(&ucd9000_driver); -} +module_i2c_driver(ucd9000_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); MODULE_LICENSE("GPL"); -module_init(ucd9000_init); -module_exit(ucd9000_exit); diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 6e1c1a80ab85..033d6aca47d3 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -81,7 +81,8 @@ static int ucd9200_probe(struct i2c_client *client, "Device mismatch: Configured %s, detected %s\n", id->name, mid->name); - info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL); + info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info), + GFP_KERNEL); if (!info) return -ENOMEM; @@ -89,7 +90,7 @@ static int ucd9200_probe(struct i2c_client *client, block_buffer); if (ret < 0) { dev_err(&client->dev, "Failed to read phase information\n"); - goto out; + return ret; } /* @@ -106,8 +107,7 @@ static int ucd9200_probe(struct i2c_client *client, } if (!info->pages) { dev_err(&client->dev, "No rails configured\n"); - ret = -ENODEV; - goto out; + return -ENODEV; } dev_info(&client->dev, "%d rails configured\n", info->pages); @@ -137,7 +137,7 @@ static int ucd9200_probe(struct i2c_client *client, if (ret < 0) { dev_err(&client->dev, "Failed to initialize PHASE registers\n"); - goto out; + return ret; } } if (info->pages > 1) @@ -160,48 +160,21 @@ static int ucd9200_probe(struct i2c_client *client, if (mid->driver_data == ucd9240) info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12; - ret = pmbus_do_probe(client, mid, info); - if (ret < 0) - goto out; - return 0; -out: - kfree(info); - return ret; -} - -static int ucd9200_remove(struct i2c_client *client) -{ - const struct pmbus_driver_info *info; - - info = pmbus_get_driver_info(client); - pmbus_do_remove(client); - kfree(info); - return 0; + return pmbus_do_probe(client, mid, info); } - /* This is the driver that will be inserted */ static struct i2c_driver ucd9200_driver = { .driver = { .name = "ucd9200", }, .probe = ucd9200_probe, - .remove = ucd9200_remove, + .remove = pmbus_do_remove, .id_table = ucd9200_id, }; -static int __init ucd9200_init(void) -{ - return i2c_add_driver(&ucd9200_driver); -} - -static void __exit ucd9200_exit(void) -{ - i2c_del_driver(&ucd9200_driver); -} +module_i2c_driver(ucd9200_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x"); MODULE_LICENSE("GPL"); -module_init(ucd9200_init); -module_exit(ucd9200_exit); diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index e3e8420b7b81..fc5eed8e85bb 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -28,7 +28,8 @@ #include <linux/delay.h> #include "pmbus.h" -enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 }; +enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105, + zl9101, zl9117 }; struct zl6100_data { int id; @@ -152,6 +153,8 @@ static const struct i2c_device_id zl6100_id[] = { {"zl2106", zl2106}, {"zl6100", zl6100}, {"zl6105", zl6105}, + {"zl9101", zl9101}, + {"zl9117", zl9117}, { } }; MODULE_DEVICE_TABLE(i2c, zl6100_id); @@ -193,7 +196,8 @@ static int zl6100_probe(struct i2c_client *client, "Device mismatch: Configured %s, detected %s\n", id->name, mid->name); - data = kzalloc(sizeof(struct zl6100_data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data), + GFP_KERNEL); if (!data) return -ENOMEM; @@ -223,7 +227,8 @@ static int zl6100_probe(struct i2c_client *client, ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG); if (ret < 0) - goto err_mem; + return ret; + if (ret & ZL6100_MFR_XTEMP_ENABLE) info->func[0] |= PMBUS_HAVE_TEMP2; @@ -235,24 +240,7 @@ static int zl6100_probe(struct i2c_client *client, info->write_word_data = zl6100_write_word_data; info->write_byte = zl6100_write_byte; - ret = pmbus_do_probe(client, mid, info); - if (ret) - goto err_mem; - return 0; - -err_mem: - kfree(data); - return ret; -} - -static int zl6100_remove(struct i2c_client *client) -{ - const struct pmbus_driver_info *info = pmbus_get_driver_info(client); - const struct zl6100_data *data = to_zl6100_data(info); - - pmbus_do_remove(client); - kfree(data); - return 0; + return pmbus_do_probe(client, mid, info); } static struct i2c_driver zl6100_driver = { @@ -260,22 +248,12 @@ static struct i2c_driver zl6100_driver = { .name = "zl6100", }, .probe = zl6100_probe, - .remove = zl6100_remove, + .remove = pmbus_do_remove, .id_table = zl6100_id, }; -static int __init zl6100_init(void) -{ - return i2c_add_driver(&zl6100_driver); -} - -static void __exit zl6100_exit(void) -{ - i2c_del_driver(&zl6100_driver); -} +module_i2c_driver(zl6100_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles"); MODULE_LICENSE("GPL"); -module_init(zl6100_init); -module_exit(zl6100_exit); diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 79b6dabe3161..8ec6dfbccb64 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com> * + * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -79,6 +79,7 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = { struct sch5627_data { unsigned short addr; struct device *hwmon_dev; + struct sch56xx_watchdog_data *watchdog; u8 control; u8 temp_max[SCH5627_NO_TEMPS]; u8 temp_crit[SCH5627_NO_TEMPS]; @@ -453,6 +454,9 @@ static int sch5627_remove(struct platform_device *pdev) { struct sch5627_data *data = platform_get_drvdata(pdev); + if (data->watchdog) + sch56xx_watchdog_unregister(data->watchdog); + if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); @@ -574,6 +578,11 @@ static int __devinit sch5627_probe(struct platform_device *pdev) goto error; } + /* Note failing to register the watchdog is not a fatal error */ + data->watchdog = sch56xx_watchdog_register(data->addr, + (build_code << 24) | (build_id << 8) | hwmon_rev, + &data->update_lock, 1); + return 0; error: diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 9d5236fb09b4..906d4ed32d81 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com> * + * Copyright (C) 2011-2012 Hans de Goede <hdegoede@redhat.com> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -67,6 +67,7 @@ static const u16 SCH5636_REG_FAN_VAL[SCH5636_NO_FANS] = { struct sch5636_data { unsigned short addr; struct device *hwmon_dev; + struct sch56xx_watchdog_data *watchdog; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -384,6 +385,9 @@ static int sch5636_remove(struct platform_device *pdev) struct sch5636_data *data = platform_get_drvdata(pdev); int i; + if (data->watchdog) + sch56xx_watchdog_unregister(data->watchdog); + if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); @@ -505,6 +509,11 @@ static int __devinit sch5636_probe(struct platform_device *pdev) goto error; } + /* Note failing to register the watchdog is not a fatal error */ + data->watchdog = sch56xx_watchdog_register(data->addr, + (revision[0] << 8) | revision[1], + &data->update_lock, 0); + return 0; error: diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index fac32ee0b10e..ce52fc57d41d 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com> * + * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -26,8 +26,20 @@ #include <linux/io.h> #include <linux/acpi.h> #include <linux/delay.h> +#include <linux/fs.h> +#include <linux/watchdog.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/kref.h> +#include <linux/slab.h> #include "sch56xx-common.h" +/* Insmod parameters */ +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + #define SIO_SCH56XX_LD_EM 0x0C /* Embedded uController Logical Dev */ #define SIO_UNLOCK_KEY 0x55 /* Key to enable Super-I/O */ #define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ @@ -40,13 +52,45 @@ #define SIO_SCH5627_ID 0xC6 /* Chipset ID */ #define SIO_SCH5636_ID 0xC7 /* Chipset ID */ -#define REGION_LENGTH 9 +#define REGION_LENGTH 10 #define SCH56XX_CMD_READ 0x02 #define SCH56XX_CMD_WRITE 0x03 +/* Watchdog registers */ +#define SCH56XX_REG_WDOG_PRESET 0x58B +#define SCH56XX_REG_WDOG_CONTROL 0x58C +#define SCH56XX_WDOG_TIME_BASE_SEC 0x01 +#define SCH56XX_REG_WDOG_OUTPUT_ENABLE 0x58E +#define SCH56XX_WDOG_OUTPUT_ENABLE 0x02 + +struct sch56xx_watchdog_data { + u16 addr; + u32 revision; + struct mutex *io_lock; + struct mutex watchdog_lock; + struct list_head list; /* member of the watchdog_data_list */ + struct kref kref; + struct miscdevice watchdog_miscdev; + unsigned long watchdog_is_open; + char watchdog_name[10]; /* must be unique to avoid sysfs conflict */ + char watchdog_expect_close; + u8 watchdog_preset; + u8 watchdog_control; + u8 watchdog_output_enable; +}; + static struct platform_device *sch56xx_pdev; +/* + * Somewhat ugly :( global data pointer list with all sch56xx devices, so that + * we can find our device data as when using misc_register there is no other + * method to get to ones device data from the open fop. + */ +static LIST_HEAD(watchdog_data_list); +/* Note this lock not only protect list access, but also data.kref access */ +static DEFINE_MUTEX(watchdog_data_mutex); + /* Super I/O functions */ static inline int superio_inb(int base, int reg) { @@ -224,6 +268,477 @@ int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg, } EXPORT_SYMBOL(sch56xx_read_virtual_reg12); +/* + * Watchdog routines + */ + +/* + * Release our data struct when the platform device has been released *and* + * all references to our watchdog device are released. + */ +static void sch56xx_watchdog_release_resources(struct kref *r) +{ + struct sch56xx_watchdog_data *data = + container_of(r, struct sch56xx_watchdog_data, kref); + kfree(data); +} + +static int watchdog_set_timeout(struct sch56xx_watchdog_data *data, + int timeout) +{ + int ret, resolution; + u8 control; + + /* 1 second or 60 second resolution? */ + if (timeout <= 255) + resolution = 1; + else + resolution = 60; + + if (timeout < resolution || timeout > (resolution * 255)) + return -EINVAL; + + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave; + } + + if (resolution == 1) + control = data->watchdog_control | SCH56XX_WDOG_TIME_BASE_SEC; + else + control = data->watchdog_control & ~SCH56XX_WDOG_TIME_BASE_SEC; + + if (data->watchdog_control != control) { + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_CONTROL, + control); + mutex_unlock(data->io_lock); + if (ret) + goto leave; + + data->watchdog_control = control; + } + + /* + * Remember new timeout value, but do not write as that (re)starts + * the watchdog countdown. + */ + data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); + + ret = data->watchdog_preset * resolution; +leave: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_get_timeout(struct sch56xx_watchdog_data *data) +{ + int timeout; + + mutex_lock(&data->watchdog_lock); + if (data->watchdog_control & SCH56XX_WDOG_TIME_BASE_SEC) + timeout = data->watchdog_preset; + else + timeout = data->watchdog_preset * 60; + mutex_unlock(&data->watchdog_lock); + + return timeout; +} + +static int watchdog_start(struct sch56xx_watchdog_data *data) +{ + int ret; + u8 val; + + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave_unlock_watchdog; + } + + /* + * The sch56xx's watchdog cannot really be started / stopped + * it is always running, but we can avoid the timer expiring + * from causing a system reset by clearing the output enable bit. + * + * The sch56xx's watchdog will set the watchdog event bit, bit 0 + * of the second interrupt source register (at base-address + 9), + * when the timer expires. + * + * This will only cause a system reset if the 0-1 flank happens when + * output enable is true. Setting output enable after the flank will + * not cause a reset, nor will the timer expiring a second time. + * This means we must clear the watchdog event bit in case it is set. + * + * The timer may still be running (after a recent watchdog_stop) and + * mere milliseconds away from expiring, so the timer must be reset + * first! + */ + + mutex_lock(data->io_lock); + + /* 1. Reset the watchdog countdown counter */ + ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET, + data->watchdog_preset); + if (ret) + goto leave; + + /* 2. Enable output (if not already enabled) */ + if (!(data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) { + val = data->watchdog_output_enable | + SCH56XX_WDOG_OUTPUT_ENABLE; + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_OUTPUT_ENABLE, + val); + if (ret) + goto leave; + + data->watchdog_output_enable = val; + } + + /* 3. Clear the watchdog event bit if set */ + val = inb(data->addr + 9); + if (val & 0x01) + outb(0x01, data->addr + 9); + +leave: + mutex_unlock(data->io_lock); +leave_unlock_watchdog: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_trigger(struct sch56xx_watchdog_data *data) +{ + int ret; + + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave; + } + + /* Reset the watchdog countdown counter */ + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET, + data->watchdog_preset); + mutex_unlock(data->io_lock); +leave: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_stop_unlocked(struct sch56xx_watchdog_data *data) +{ + int ret = 0; + u8 val; + + if (!data->addr) + return -ENODEV; + + if (data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) { + val = data->watchdog_output_enable & + ~SCH56XX_WDOG_OUTPUT_ENABLE; + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_OUTPUT_ENABLE, + val); + mutex_unlock(data->io_lock); + if (ret) + return ret; + + data->watchdog_output_enable = val; + } + + return ret; +} + +static int watchdog_stop(struct sch56xx_watchdog_data *data) +{ + int ret; + + mutex_lock(&data->watchdog_lock); + ret = watchdog_stop_unlocked(data); + mutex_unlock(&data->watchdog_lock); + + return ret; +} + +static int watchdog_release(struct inode *inode, struct file *filp) +{ + struct sch56xx_watchdog_data *data = filp->private_data; + + if (data->watchdog_expect_close) { + watchdog_stop(data); + data->watchdog_expect_close = 0; + } else { + watchdog_trigger(data); + pr_crit("unexpected close, not stopping watchdog!\n"); + } + + clear_bit(0, &data->watchdog_is_open); + + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, sch56xx_watchdog_release_resources); + mutex_unlock(&watchdog_data_mutex); + + return 0; +} + +static int watchdog_open(struct inode *inode, struct file *filp) +{ + struct sch56xx_watchdog_data *pos, *data = NULL; + int ret, watchdog_is_open; + + /* + * We get called from drivers/char/misc.c with misc_mtx hold, and we + * call misc_register() from sch56xx_watchdog_probe() with + * watchdog_data_mutex hold, as misc_register() takes the misc_mtx + * lock, this is a possible deadlock, so we use mutex_trylock here. + */ + if (!mutex_trylock(&watchdog_data_mutex)) + return -ERESTARTSYS; + list_for_each_entry(pos, &watchdog_data_list, list) { + if (pos->watchdog_miscdev.minor == iminor(inode)) { + data = pos; + break; + } + } + /* Note we can never not have found data, so we don't check for this */ + watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); + if (!watchdog_is_open) + kref_get(&data->kref); + mutex_unlock(&watchdog_data_mutex); + + if (watchdog_is_open) + return -EBUSY; + + filp->private_data = data; + + /* Start the watchdog */ + ret = watchdog_start(data); + if (ret) { + watchdog_release(inode, filp); + return ret; + } + + return nonseekable_open(inode, filp); +} + +static ssize_t watchdog_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret; + struct sch56xx_watchdog_data *data = filp->private_data; + + if (count) { + if (!nowayout) { + size_t i; + + /* Clear it in case it was set with a previous write */ + data->watchdog_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + data->watchdog_expect_close = 1; + } + } + ret = watchdog_trigger(data); + if (ret) + return ret; + } + return count; +} + +static long watchdog_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .identity = "sch56xx watchdog" + }; + int i, ret = 0; + struct sch56xx_watchdog_data *data = filp->private_data; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ident.firmware_version = data->revision; + if (!nowayout) + ident.options |= WDIOF_MAGICCLOSE; + if (copy_to_user((void __user *)arg, &ident, sizeof(ident))) + ret = -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, (int __user *)arg); + break; + + case WDIOC_KEEPALIVE: + ret = watchdog_trigger(data); + break; + + case WDIOC_GETTIMEOUT: + i = watchdog_get_timeout(data); + ret = put_user(i, (int __user *)arg); + break; + + case WDIOC_SETTIMEOUT: + if (get_user(i, (int __user *)arg)) { + ret = -EFAULT; + break; + } + ret = watchdog_set_timeout(data, i); + if (ret >= 0) + ret = put_user(ret, (int __user *)arg); + break; + + case WDIOC_SETOPTIONS: + if (get_user(i, (int __user *)arg)) { + ret = -EFAULT; + break; + } + + if (i & WDIOS_DISABLECARD) + ret = watchdog_stop(data); + else if (i & WDIOS_ENABLECARD) + ret = watchdog_trigger(data); + else + ret = -EINVAL; + break; + + default: + ret = -ENOTTY; + } + return ret; +} + +static const struct file_operations watchdog_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = watchdog_open, + .release = watchdog_release, + .write = watchdog_write, + .unlocked_ioctl = watchdog_ioctl, +}; + +struct sch56xx_watchdog_data *sch56xx_watchdog_register( + u16 addr, u32 revision, struct mutex *io_lock, int check_enabled) +{ + struct sch56xx_watchdog_data *data; + int i, err, control, output_enable; + const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; + + /* Cache the watchdog registers */ + mutex_lock(io_lock); + control = + sch56xx_read_virtual_reg(addr, SCH56XX_REG_WDOG_CONTROL); + output_enable = + sch56xx_read_virtual_reg(addr, SCH56XX_REG_WDOG_OUTPUT_ENABLE); + mutex_unlock(io_lock); + + if (control < 0) + return NULL; + if (output_enable < 0) + return NULL; + if (check_enabled && !(output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) { + pr_warn("Watchdog not enabled by BIOS, not registering\n"); + return NULL; + } + + data = kzalloc(sizeof(struct sch56xx_watchdog_data), GFP_KERNEL); + if (!data) + return NULL; + + data->addr = addr; + data->revision = revision; + data->io_lock = io_lock; + data->watchdog_control = control; + data->watchdog_output_enable = output_enable; + mutex_init(&data->watchdog_lock); + INIT_LIST_HEAD(&data->list); + kref_init(&data->kref); + + err = watchdog_set_timeout(data, 60); + if (err < 0) + goto error; + + /* + * We take the data_mutex lock early so that watchdog_open() cannot + * run when misc_register() has completed, but we've not yet added + * our data to the watchdog_data_list. + */ + mutex_lock(&watchdog_data_mutex); + for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) { + /* Register our watchdog part */ + snprintf(data->watchdog_name, sizeof(data->watchdog_name), + "watchdog%c", (i == 0) ? '\0' : ('0' + i)); + data->watchdog_miscdev.name = data->watchdog_name; + data->watchdog_miscdev.fops = &watchdog_fops; + data->watchdog_miscdev.minor = watchdog_minors[i]; + err = misc_register(&data->watchdog_miscdev); + if (err == -EBUSY) + continue; + if (err) + break; + + list_add(&data->list, &watchdog_data_list); + pr_info("Registered /dev/%s chardev major 10, minor: %d\n", + data->watchdog_name, watchdog_minors[i]); + break; + } + mutex_unlock(&watchdog_data_mutex); + + if (err) { + pr_err("Registering watchdog chardev: %d\n", err); + goto error; + } + if (i == ARRAY_SIZE(watchdog_minors)) { + pr_warn("Couldn't register watchdog (no free minor)\n"); + goto error; + } + + return data; + +error: + kfree(data); + return NULL; +} +EXPORT_SYMBOL(sch56xx_watchdog_register); + +void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data) +{ + mutex_lock(&watchdog_data_mutex); + misc_deregister(&data->watchdog_miscdev); + list_del(&data->list); + mutex_unlock(&watchdog_data_mutex); + + mutex_lock(&data->watchdog_lock); + if (data->watchdog_is_open) { + pr_warn("platform device unregistered with watchdog " + "open! Stopping watchdog.\n"); + watchdog_stop_unlocked(data); + } + /* Tell the wdog start/stop/trigger functions our dev is gone */ + data->addr = 0; + data->io_lock = NULL; + mutex_unlock(&data->watchdog_lock); + + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, sch56xx_watchdog_release_resources); + mutex_unlock(&watchdog_data_mutex); +} +EXPORT_SYMBOL(sch56xx_watchdog_unregister); + +/* + * platform dev find, add and remove functions + */ + static int __init sch56xx_find(int sioaddr, unsigned short *address, const char **name) { diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h index d5eaf3b9ebf5..7475086eb978 100644 --- a/drivers/hwmon/sch56xx-common.h +++ b/drivers/hwmon/sch56xx-common.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com> * + * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -17,8 +17,16 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include <linux/mutex.h> + +struct sch56xx_watchdog_data; + int sch56xx_read_virtual_reg(u16 addr, u16 reg); int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val); int sch56xx_read_virtual_reg16(u16 addr, u16 reg); int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg, int high_nibble); + +struct sch56xx_watchdog_data *sch56xx_watchdog_register( + u16 addr, u32 revision, struct mutex *io_lock, int check_enabled); +void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data); diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 91fdd1fe18b0..8b011d016621 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -806,7 +806,7 @@ static void sht15_bh_read_data(struct work_struct *work_s) */ atomic_set(&data->interrupt_handled, 0); enable_irq(gpio_to_irq(data->pdata->gpio_data)); - /* If still not occurred or another handler has been scheduled */ + /* If still not occurred or another handler was scheduled */ if (gpio_get_value(data->pdata->gpio_data) || atomic_read(&data->interrupt_handled)) return; diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 15398780cc00..6c2dede4b8e7 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -261,28 +261,7 @@ static struct i2c_driver sht21_driver = { .id_table = sht21_id, }; -/** - * sht21_init() - initialize driver - * - * Called when kernel is booted or module is inserted. - * Returns 0 on success. - */ -static int __init sht21_init(void) -{ - return i2c_add_driver(&sht21_driver); -} -module_init(sht21_init); - -/** - * sht21_init() - clean up driver - * - * Called when module is removed. - */ -static void __exit sht21_exit(void) -{ - i2c_del_driver(&sht21_driver); -} -module_exit(sht21_exit); +module_i2c_driver(sht21_driver); MODULE_AUTHOR("Urs Fleisch <urs.fleisch@sensirion.com>"); MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver"); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 47d7ce9af8fb..6c4d8eb9b7ca 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -1,54 +1,54 @@ /* - sis5595.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>, - Kyösti Mälkki <kmalkki@cc.hut.fi>, and - Mark D. Studebaker <mdsxyz123@yahoo.com> - Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with - the help of Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * sis5595.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * + * Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>, + * Kyösti Mälkki <kmalkki@cc.hut.fi>, and + * Mark D. Studebaker <mdsxyz123@yahoo.com> + * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with + * the help of Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - SiS southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 AF or less - 2 1039/0008 B0 or greater - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 -*/ + * SiS southbridge has a LM78-like chip integrated on the same IC. + * This driver is a customized copy of lm78.c + * + * Supports following revisions: + * Version PCI ID PCI Revision + * 1 1039/0008 AF or less + * 2 1039/0008 B0 or greater + * + * Note: these chips contain a 0008 device which is incompatible with the + * 5595. We recognize these by the presence of the listed + * "blacklist" PCI ID and refuse to load. + * + * NOT SUPPORTED PCI ID BLACKLIST PCI ID + * 540 0008 0540 + * 550 0008 0550 + * 5513 0008 5511 + * 5581 0008 5597 + * 5582 0008 5597 + * 5597 0008 5597 + * 5598 0008 5597/5598 + * 630 0008 0630 + * 645 0008 0645 + * 730 0008 0730 + * 735 0008 0735 + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -68,8 +68,10 @@ #include <linux/io.h> -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ +/* + * If force_addr is set to anything different from 0, we forcibly enable + * the device at the given address. + */ static u16 force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, @@ -98,30 +100,36 @@ static struct platform_device *pdev; #define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr)) #define SIS5595_REG_FAN(nr) (0x28 + (nr)) -/* On the first version of the chip, the temp registers are separate. - On the second version, - TEMP pin is shared with IN4, configured in PCI register 0x7A. - The registers are the same as well. - OVER and HYST are really MAX and MIN. */ +/* + * On the first version of the chip, the temp registers are separate. + * On the second version, + * TEMP pin is shared with IN4, configured in PCI register 0x7A. + * The registers are the same as well. + * OVER and HYST are really MAX and MIN. + */ #define REV2MIN 0xb0 -#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN(4) : 0x27 -#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MAX(4) : 0x39 -#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MIN(4) : 0x3a +#define SIS5595_REG_TEMP (((data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN(4) : 0x27) +#define SIS5595_REG_TEMP_OVER (((data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MAX(4) : 0x39) +#define SIS5595_REG_TEMP_HYST (((data->revision) >= REV2MIN) ? \ + SIS5595_REG_IN_MIN(4) : 0x3a) #define SIS5595_REG_CONFIG 0x40 #define SIS5595_REG_ALARM1 0x41 #define SIS5595_REG_ALARM2 0x42 #define SIS5595_REG_FANDIV 0x47 -/* Conversions. Limit checking is only done on the TO_REG - variants. */ +/* + * Conversions. Limit checking is only done on the TO_REG + * variants. + */ -/* IN: mV, (0V to 4.08V) - REG: 16mV/bit */ +/* + * IN: mV, (0V to 4.08V) + * REG: 16mV/bit + */ static inline u8 IN_TO_REG(unsigned long val) { unsigned long nval = SENSORS_LIMIT(val, 0, 4080); @@ -138,11 +146,13 @@ static inline u8 FAN_TO_REG(long rpm, int div) static inline int FAN_FROM_REG(u8 val, int div) { - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); + return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div); } -/* TEMP: mC (-54.12C to +157.53C) - REG: 0.83C/bit + 52.12, two's complement */ +/* + * TEMP: mC (-54.12C to +157.53C) + * REG: 0.83C/bit + 52.12, two's complement + */ static inline int TEMP_FROM_REG(s8 val) { return val * 830 + 52120; @@ -150,19 +160,23 @@ static inline int TEMP_FROM_REG(s8 val) static inline s8 TEMP_TO_REG(int val) { int nval = SENSORS_LIMIT(val, -54120, 157530) ; - return nval<0 ? (nval-5212-415)/830 : (nval-5212+415)/830; + return nval < 0 ? (nval - 5212 - 415) / 830 : (nval - 5212 + 415) / 830; } -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +/* + * FAN DIV: 1, 2, 4, or 8 (defaults to 2) + * REG: 0, 1, 2, or 3 (respectively) (defaults to 1) + */ static inline u8 DIV_TO_REG(int val) { - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; + return val == 8 ? 3 : val == 4 ? 2 : val == 1 ? 0 : 1; } #define DIV_FROM_REG(val) (1 << (val)) -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* + * For each registered chip, we need to keep some data in memory. + * The structure is dynamically allocated. + */ struct sis5595_data { unsigned short addr; const char *name; @@ -240,7 +254,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *da, struct sis5595_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val); @@ -255,7 +274,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *da, struct sis5595_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val); @@ -279,22 +303,30 @@ show_in_offset(3); show_in_offset(4); /* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, + char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct sis5595_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_over = TEMP_TO_REG(val); @@ -303,16 +335,23 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, + char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); } -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct sis5595_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_hyst = TEMP_TO_REG(val); @@ -335,7 +374,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); + DIV_FROM_REG(data->fan_div[nr]))); } static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, @@ -344,8 +383,8 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, struct sis5595_data *data = sis5595_update_device(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])) ); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); } static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, @@ -354,7 +393,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, struct sis5595_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -369,13 +413,15 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, struct sis5595_data *data = sis5595_update_device(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { @@ -383,8 +429,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; unsigned long min; - unsigned long val = simple_strtoul(buf, NULL, 10); int reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], @@ -392,17 +443,25 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, reg = sis5595_read_value(data, SIS5595_REG_FANDIV); switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; + case 1: + data->fan_div[nr] = 0; + break; + case 2: + data->fan_div[nr] = 1; + break; + case 4: + data->fan_div[nr] = 2; + break; + case 8: + data->fan_div[nr] = 3; + break; default: dev_err(dev, "fan_div value %ld not " "supported. Choose one of 1, 2, 4 or 8!\n", val); mutex_unlock(&data->update_lock); return -EINVAL; } - + switch (nr) { case 0: reg = (reg & 0xcf) | (data->fan_div[nr] << 4); @@ -431,7 +490,8 @@ show_fan_offset(1); show_fan_offset(2); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", data->alarms); @@ -521,7 +581,7 @@ static struct attribute *sis5595_attributes_temp1[] = { static const struct attribute_group sis5595_group_temp1 = { .attrs = sis5595_attributes_temp1, }; - + /* This is called when the module is loaded */ static int __devinit sis5595_probe(struct platform_device *pdev) { @@ -539,7 +599,8 @@ static int __devinit sis5595_probe(struct platform_device *pdev) goto exit; } - if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit_release; } @@ -550,7 +611,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev) data->name = "sis5595"; platform_set_drvdata(pdev, data); - /* Check revision and pin registers to determine whether 4 or 5 voltages */ + /* + * Check revision and pin registers to determine whether 4 or 5 voltages + */ data->revision = s_bridge->revision; /* 4 voltages, 1 temp */ data->maxins = 3; @@ -560,7 +623,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev) /* 5 voltages, no temps */ data->maxins = 4; } - + /* Initialize the SIS5595 chip */ sis5595_init_device(data); @@ -571,15 +634,16 @@ static int __devinit sis5595_probe(struct platform_device *pdev) } /* Register sysfs hooks */ - if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group))) + err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group); + if (err) goto exit_free; if (data->maxins == 4) { - if ((err = sysfs_create_group(&pdev->dev.kobj, - &sis5595_group_in4))) + err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_in4); + if (err) goto exit_remove_files; } else { - if ((err = sysfs_create_group(&pdev->dev.kobj, - &sis5595_group_temp1))) + err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group_temp1); + if (err) goto exit_remove_files; } @@ -699,7 +763,7 @@ static struct sis5595_data *sis5595_update_device(struct device *dev) return data; } -static const struct pci_device_id sis5595_pci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(sis5595_pci_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } }; @@ -713,9 +777,11 @@ static int blacklist[] __devinitdata = { PCI_DEVICE_ID_SI_645, PCI_DEVICE_ID_SI_730, PCI_DEVICE_ID_SI_735, - PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but - that ID shows up in other chips so we - use the 5511 ID for recognition */ + PCI_DEVICE_ID_SI_5511, /* + * 5513 chip has the 0008 device but + * that ID shows up in other chips so we + * use the 5511 ID for recognition + */ PCI_DEVICE_ID_SI_5597, PCI_DEVICE_ID_SI_5598, 0 }; @@ -770,13 +836,16 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev, for (i = blacklist; *i != 0; i++) { struct pci_dev *d; - if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) { - dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); + d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); + if (d) { + dev_err(&d->dev, + "Looked for SIS5595 but found unsupported device %.4x\n", + *i); pci_dev_put(d); return -ENODEV; } } - + force_addr &= ~(SIS5595_EXTENT - 1); if (force_addr) { dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr); @@ -788,10 +857,11 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev, dev_err(&dev->dev, "Failed to read ISA address\n"); return -ENODEV; } - + address &= ~(SIS5595_EXTENT - 1); if (!address) { - dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); + dev_err(&dev->dev, + "Base address not set - upgrade BIOS or use force_addr=0xaddr\n"); return -ENODEV; } if (force_addr && address != force_addr) { @@ -828,7 +898,8 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev, if (sis5595_device_add(address)) goto exit_unregister; - /* Always return failure here. This is to allow other drivers to bind + /* + * Always return failure here. This is to allow other drivers to bind * to this pci device. We don't really want to have control over the * pci device, we only wanted to read as few register values from it. */ diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index 411638181fd8..cbc51fb30dba 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -124,9 +124,9 @@ enum chips { smm465, smm665, smm665c, smm764, smm766 }; #define SMM665_AIN_ADC_TO_VOLTS(adc) ((adc) * vref / 512) /* Temp Sensor */ -#define SMM665_TEMP_ADC_TO_CELSIUS(adc) ((adc) <= 511) ? \ +#define SMM665_TEMP_ADC_TO_CELSIUS(adc) (((adc) <= 511) ? \ ((int)(adc) * 1000 / 4) : \ - (((int)(adc) - 0x400) * 1000 / 4) + (((int)(adc) - 0x400) * 1000 / 4)) #define SMM665_NUM_ADC 11 @@ -376,7 +376,7 @@ static ssize_t smm665_show_input(struct device *dev, } #define SMM665_SHOW(what) \ - static ssize_t smm665_show_##what(struct device *dev, \ +static ssize_t smm665_show_##what(struct device *dev, \ struct device_attribute *da, char *buf) \ { \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ @@ -389,7 +389,8 @@ SMM665_SHOW(max); SMM665_SHOW(lcrit); SMM665_SHOW(crit); -/* These macros are used below in constructing device attribute objects +/* + * These macros are used below in constructing device attribute objects * for use with sysfs_create_group() to make a sysfs device file * for each register. */ @@ -583,10 +584,9 @@ static int smm665_probe(struct i2c_client *client, if (i2c_smbus_read_byte_data(client, SMM665_ADOC_ENABLE) < 0) return -ENODEV; - ret = -ENOMEM; - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (!data) - goto out_return; + return -ENOMEM; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -595,7 +595,7 @@ static int smm665_probe(struct i2c_client *client, data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK) | SMM665_CMDREG_BASE); if (!data->cmdreg) - goto out_kfree; + return -ENOMEM; switch (data->type) { case smm465: @@ -678,9 +678,6 @@ out_remove_group: sysfs_remove_group(&client->dev.kobj, &smm665_group); out_unregister: i2c_unregister_device(data->cmdreg); -out_kfree: - kfree(data); -out_return: return ret; } @@ -692,8 +689,6 @@ static int smm665_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &smm665_group); - kfree(data); - return 0; } @@ -718,19 +713,8 @@ static struct i2c_driver smm665_driver = { .id_table = smm665_id, }; -static int __init smm665_init(void) -{ - return i2c_add_driver(&smm665_driver); -} - -static void __exit smm665_exit(void) -{ - i2c_del_driver(&smm665_driver); -} +module_i2c_driver(smm665_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("SMM665 driver"); MODULE_LICENSE("GPL"); - -module_init(smm665_init); -module_exit(smm665_exit); diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 65c88ff5645a..d3b778da3f86 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -1,30 +1,30 @@ /* - smsc47b397.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Supports the SMSC LPC47B397-NC Super-I/O chip. - - Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com> - Copyright (C) 2004 Utilitek Systems, Inc. - - derived in part from smsc47m1.c: - Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * smsc47b397.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * + * Supports the SMSC LPC47B397-NC Super-I/O chip. + * + * Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com> + * Copyright (C) 2004 Utilitek Systems, Inc. + * + * derived in part from smsc47m1.c: + * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> + * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -157,8 +157,10 @@ static struct smsc47b397_data *smsc47b397_update_device(struct device *dev) return data; } -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: 0.001C/bit (-128C to +127C) + * REG: 1C/bit, two's complement + */ static int temp_from_reg(u8 reg) { return (s8)reg * 1000; @@ -177,8 +179,10 @@ static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); -/* FAN: 1 RPM/bit - REG: count of 90kHz pulses / revolution */ +/* + * FAN: 1 RPM/bit + * REG: count of 90kHz pulses / revolution + */ static int fan_from_reg(u16 reg) { if (reg == 0 || reg == 0xffff) diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index f44a89aac381..c590c1469793 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -1,30 +1,30 @@ /* - smsc47m1.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, - LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 - Super-I/O chips. - - Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org> - Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com> - and Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * smsc47m1.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * + * Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x, + * LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997 + * Super-I/O chips. + * + * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> + * Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org> + * Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com> + * and Jean Delvare + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -53,8 +53,8 @@ enum chips { smsc47m1, smsc47m2 }; /* Super-I/0 registers and commands */ -#define REG 0x2e /* The register to read/write */ -#define VAL 0x2f /* The value to read/write */ +#define REG 0x2e /* The register to read/write */ +#define VAL 0x2f /* The value to read/write */ static inline void superio_outb(int reg, int val) @@ -111,10 +111,11 @@ static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 }; #define SMSC47M2_REG_PPIN3 0x2c #define SMSC47M2_REG_FANDIV3 0x6a -#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \ - 983040/((192-(reg))*(div))) -#define FAN_FROM_REG(reg,div,preload) ((reg)<=(preload) || (reg)==255 ? 0 : \ - 983040/(((reg)-(preload))*(div))) +#define MIN_FROM_REG(reg, div) ((reg) >= 192 ? 0 : \ + 983040 / ((192 - (reg)) * (div))) +#define FAN_FROM_REG(reg, div, preload) ((reg) <= (preload) || (reg) == 255 ? \ + 0 : \ + 983040 / (((reg) - (preload)) * (div))) #define DIV_FROM_REG(reg) (1 << (reg)) #define PWM_FROM_REG(reg) (((reg) & 0x7E) << 1) #define PWM_EN_FROM_REG(reg) ((~(reg)) & 0x01) @@ -171,10 +172,12 @@ static ssize_t get_fan(struct device *dev, struct device_attribute struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); int nr = attr->index; - /* This chip (stupidly) stops monitoring fan speed if PWM is - enabled and duty cycle is 0%. This is fine if the monitoring - and control concern the same fan, but troublesome if they are - not (which could as well happen). */ + /* + * This chip (stupidly) stops monitoring fan speed if PWM is + * enabled and duty cycle is 0%. This is fine if the monitoring + * and control concern the same fan, but troublesome if they are + * not (which could as well happen). + */ int rpm = (data->pwm[nr] & 0x7F) == 0x00 ? 0 : FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]), @@ -238,7 +241,13 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = dev_get_drvdata(dev); int nr = attr->index; - long rpmdiv, val = simple_strtol(buf, NULL, 10); + long rpmdiv; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); rpmdiv = val * DIV_FROM_REG(data->fan_div[nr]); @@ -256,28 +265,44 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute return count; } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan clock divider. This follows the principle - of least surprise; the user doesn't expect the fan minimum to change just - because the divider changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan clock divider. This follows the principle + * of least surprise; the user doesn't expect the fan minimum to change just + * because the divider changed. + */ static ssize_t set_fan_div(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = dev_get_drvdata(dev); int nr = attr->index; - long new_div = simple_strtol(buf, NULL, 10), tmp; + long new_div; + int err; + long tmp; u8 old_div = DIV_FROM_REG(data->fan_div[nr]); + err = kstrtol(buf, 10, &new_div); + if (err) + return err; + if (new_div == old_div) /* No change */ return count; mutex_lock(&data->update_lock); switch (new_div) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; + case 1: + data->fan_div[nr] = 0; + break; + case 2: + data->fan_div[nr] = 1; + break; + case 4: + data->fan_div[nr] = 2; + break; + case 8: + data->fan_div[nr] = 3; + break; default: mutex_unlock(&data->update_lock); return -EINVAL; @@ -315,7 +340,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = dev_get_drvdata(dev); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; if (val < 0 || val > 255) return -EINVAL; @@ -336,9 +366,14 @@ static ssize_t set_pwm_en(struct device *dev, struct device_attribute struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct smsc47m1_data *data = dev_get_drvdata(dev); int nr = attr->index; - long val = simple_strtol(buf, NULL, 10); - - if (val != 0 && val != 1) + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (val > 1) return -EINVAL; mutex_lock(&data->update_lock); @@ -380,30 +415,73 @@ static ssize_t show_name(struct device *dev, struct device_attribute } static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -/* Almost all sysfs files may or may not be created depending on the chip - setup so we create them individually. It is still convenient to define a - group to remove them all at once. */ -static struct attribute *smsc47m1_attributes[] = { +static struct attribute *smsc47m1_attributes_fan1[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group_fan1 = { + .attrs = smsc47m1_attributes_fan1, +}; + +static struct attribute *smsc47m1_attributes_fan2[] = { &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group_fan2 = { + .attrs = smsc47m1_attributes_fan2, +}; + +static struct attribute *smsc47m1_attributes_fan3[] = { &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, &sensor_dev_attr_fan3_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group_fan3 = { + .attrs = smsc47m1_attributes_fan3, +}; +static struct attribute *smsc47m1_attributes_pwm1[] = { &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group_pwm1 = { + .attrs = smsc47m1_attributes_pwm1, +}; + +static struct attribute *smsc47m1_attributes_pwm2[] = { &sensor_dev_attr_pwm2.dev_attr.attr, &sensor_dev_attr_pwm2_enable.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group_pwm2 = { + .attrs = smsc47m1_attributes_pwm2, +}; + +static struct attribute *smsc47m1_attributes_pwm3[] = { &sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group_pwm3 = { + .attrs = smsc47m1_attributes_pwm3, +}; +static struct attribute *smsc47m1_attributes[] = { &dev_attr_alarms.attr, &dev_attr_name.attr, NULL @@ -476,8 +554,10 @@ static int __init smsc47m1_find(unsigned short *addr, return -ENODEV; } - /* Enable only if address is set (needed at least on the - * Compaq Presario S4000NX) */ + /* + * Enable only if address is set (needed at least on the + * Compaq Presario S4000NX) + */ sio_data->activate = superio_inb(SUPERIO_REG_ACT); if ((sio_data->activate & 0x01) == 0) { pr_info("Enabling device\n"); @@ -583,6 +663,17 @@ static int smsc47m1_handle_resources(unsigned short address, enum chips type, return 0; } +static void smsc47m1_remove_files(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &smsc47m1_group); + sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan1); + sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan2); + sysfs_remove_group(&dev->kobj, &smsc47m1_group_fan3); + sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm1); + sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm2); + sysfs_remove_group(&dev->kobj, &smsc47m1_group_pwm3); +} + static int __init smsc47m1_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -592,7 +683,7 @@ static int __init smsc47m1_probe(struct platform_device *pdev) int err; int fan1, fan2, fan3, pwm1, pwm2, pwm3; - static const char *names[] = { + static const char * const names[] = { "smsc47m1", "smsc47m2", }; @@ -603,7 +694,8 @@ static int __init smsc47m1_probe(struct platform_device *pdev) if (err < 0) return err; - if (!(data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct smsc47m1_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto error_release; } @@ -614,8 +706,10 @@ static int __init smsc47m1_probe(struct platform_device *pdev) mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); - /* If no function is properly configured, there's no point in - actually registering the chip. */ + /* + * If no function is properly configured, there's no point in + * actually registering the chip. + */ pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05) == 0x04; pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05) @@ -643,84 +737,67 @@ static int __init smsc47m1_probe(struct platform_device *pdev) goto error_free; } - /* Some values (fan min, clock dividers, pwm registers) may be - needed before any update is triggered, so we better read them - at least once here. We don't usually do it that way, but in - this particular case, manually reading 5 registers out of 8 - doesn't make much sense and we're better using the existing - function. */ + /* + * Some values (fan min, clock dividers, pwm registers) may be + * needed before any update is triggered, so we better read them + * at least once here. We don't usually do it that way, but in + * this particular case, manually reading 5 registers out of 8 + * doesn't make much sense and we're better using the existing + * function. + */ smsc47m1_update_device(dev, 1); /* Register sysfs hooks */ if (fan1) { - if ((err = device_create_file(dev, - &sensor_dev_attr_fan1_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan1_min.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan1_div.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan1_alarm.dev_attr))) + err = sysfs_create_group(&dev->kobj, + &smsc47m1_group_fan1); + if (err) goto error_remove_files; } else dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n"); if (fan2) { - if ((err = device_create_file(dev, - &sensor_dev_attr_fan2_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan2_min.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan2_div.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan2_alarm.dev_attr))) + err = sysfs_create_group(&dev->kobj, + &smsc47m1_group_fan2); + if (err) goto error_remove_files; } else dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n"); if (fan3) { - if ((err = device_create_file(dev, - &sensor_dev_attr_fan3_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan3_min.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan3_div.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_fan3_alarm.dev_attr))) + err = sysfs_create_group(&dev->kobj, + &smsc47m1_group_fan3); + if (err) goto error_remove_files; } else if (data->type == smsc47m2) dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n"); if (pwm1) { - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm1.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_pwm1_enable.dev_attr))) + err = sysfs_create_group(&dev->kobj, + &smsc47m1_group_pwm1); + if (err) goto error_remove_files; } else dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n"); if (pwm2) { - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm2.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_pwm2_enable.dev_attr))) + err = sysfs_create_group(&dev->kobj, + &smsc47m1_group_pwm2); + if (err) goto error_remove_files; } else dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n"); if (pwm3) { - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm3.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_pwm3_enable.dev_attr))) + err = sysfs_create_group(&dev->kobj, + &smsc47m1_group_pwm3); + if (err) goto error_remove_files; } else if (data->type == smsc47m2) dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n"); - if ((err = device_create_file(dev, &dev_attr_alarms))) - goto error_remove_files; - if ((err = device_create_file(dev, &dev_attr_name))) + err = sysfs_create_group(&dev->kobj, &smsc47m1_group); + if (err) goto error_remove_files; data->hwmon_dev = hwmon_device_register(dev); @@ -732,7 +809,7 @@ static int __init smsc47m1_probe(struct platform_device *pdev) return 0; error_remove_files: - sysfs_remove_group(&dev->kobj, &smsc47m1_group); + smsc47m1_remove_files(dev); error_free: platform_set_drvdata(pdev, NULL); kfree(data); @@ -747,7 +824,7 @@ static int __exit smsc47m1_remove(struct platform_device *pdev) struct resource *res; hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group); + smsc47m1_remove_files(&pdev->dev); res = platform_get_resource(pdev, IORESOURCE_IO, 0); smsc47m1_handle_resources(res->start, data->type, RELEASE, &pdev->dev); diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 40b26673d87f..4705a8bf11c2 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -1,25 +1,25 @@ /* - smsc47m192.c - Support for hardware monitoring block of - SMSC LPC47M192 and compatible Super I/O chips - - Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de> - - Derived from lm78.c and other chip drivers. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * smsc47m192.c - Support for hardware monitoring block of + * SMSC LPC47M192 and compatible Super I/O chips + * + * Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de> + * + * Derived from lm78.c and other chip drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -37,16 +37,16 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; /* SMSC47M192 registers */ -#define SMSC47M192_REG_IN(nr) ((nr)<6 ? (0x20 + (nr)) : \ +#define SMSC47M192_REG_IN(nr) ((nr) < 6 ? (0x20 + (nr)) : \ (0x50 + (nr) - 6)) -#define SMSC47M192_REG_IN_MAX(nr) ((nr)<6 ? (0x2b + (nr) * 2) : \ +#define SMSC47M192_REG_IN_MAX(nr) ((nr) < 6 ? (0x2b + (nr) * 2) : \ (0x54 + (((nr) - 6) * 2))) -#define SMSC47M192_REG_IN_MIN(nr) ((nr)<6 ? (0x2c + (nr) * 2) : \ +#define SMSC47M192_REG_IN_MIN(nr) ((nr) < 6 ? (0x2c + (nr) * 2) : \ (0x55 + (((nr) - 6) * 2))) static u8 SMSC47M192_REG_TEMP[3] = { 0x27, 0x26, 0x52 }; static u8 SMSC47M192_REG_TEMP_MAX[3] = { 0x39, 0x37, 0x58 }; static u8 SMSC47M192_REG_TEMP_MIN[3] = { 0x3A, 0x38, 0x59 }; -#define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr)==2 ? 0x1e : 0x1f) +#define SMSC47M192_REG_TEMP_OFFSET(nr) ((nr) == 2 ? 0x1e : 0x1f) #define SMSC47M192_REG_ALARM1 0x41 #define SMSC47M192_REG_ALARM2 0x42 #define SMSC47M192_REG_VID 0x47 @@ -80,8 +80,10 @@ static inline u8 IN_TO_REG(unsigned long val, int n) return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255); } -/* TEMP: 0.001 degC units (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: 0.001 degC units (-128C to +127C) + * REG: 1C/bit, two's complement + */ static inline s8 TEMP_TO_REG(int val) { return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000); @@ -170,7 +172,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct smsc47m192_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val, nr); @@ -187,7 +194,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct smsc47m192_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val, nr); @@ -249,7 +261,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct smsc47m192_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); @@ -266,7 +283,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct smsc47m192_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); @@ -293,22 +315,29 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute struct i2c_client *client = to_i2c_client(dev); struct smsc47m192_data *data = i2c_get_clientdata(client); u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_offset[nr] = TEMP_TO_REG(val); - if (nr>1) + if (nr > 1) i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]); else if (data->temp_offset[nr] != 0) { - /* offset[0] and offset[1] share the same register, - SFR bit 4 activates offset[0] */ + /* + * offset[0] and offset[1] share the same register, + * SFR bit 4 activates offset[0] + */ i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR, - (sfr & 0xef) | (nr==0 ? 0x10 : 0)); + (sfr & 0xef) | (nr == 0 ? 0x10 : 0)); data->temp_offset[1-nr] = 0; i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]); - } else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0)) + } else if ((sfr & 0x10) == (nr == 0 ? 0x10 : 0)) i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_OFFSET(nr), 0); mutex_unlock(&data->update_lock); @@ -349,7 +378,14 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct smsc47m192_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + data->vrm = val; return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); @@ -458,13 +494,13 @@ static void smsc47m192_init_client(struct i2c_client *client) (sfr & 0xfd) | 0x02); if (!(config & 0x01)) { /* initialize alarm limits */ - for (i=0; i<8; i++) { + for (i = 0; i < 8; i++) { i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(i), 0); i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(i), 0xff); } - for (i=0; i<3; i++) { + for (i = 0; i < 3; i++) { i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[i], 0x80); i2c_smbus_write_byte_data(client, @@ -532,14 +568,16 @@ static int smsc47m192_probe(struct i2c_client *client, smsc47m192_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group))) + err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group); + if (err) goto exit_free; /* Pin 110 is either in4 (+12V) or VID4 */ config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG); if (!(config & 0x20)) { - if ((err = sysfs_create_group(&client->dev.kobj, - &smsc47m192_group_in4))) + err = sysfs_create_group(&client->dev.kobj, + &smsc47m192_group_in4); + if (err) goto exit_remove_files; } @@ -606,8 +644,10 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev) for (i = 1; i < 3; i++) data->temp_offset[i] = i2c_smbus_read_byte_data(client, SMSC47M192_REG_TEMP_OFFSET(i)); - /* first offset is temp_offset[0] if SFR bit 4 is set, - temp_offset[1] otherwise */ + /* + * first offset is temp_offset[0] if SFR bit 4 is set, + * temp_offset[1] otherwise + */ if (sfr & 0x10) { data->temp_offset[0] = data->temp_offset[1]; data->temp_offset[1] = 0; @@ -624,7 +664,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev) data->alarms = i2c_smbus_read_byte_data(client, SMSC47M192_REG_ALARM1) | (i2c_smbus_read_byte_data(client, - SMSC47M192_REG_ALARM2) << 8); + SMSC47M192_REG_ALARM2) << 8); data->last_updated = jiffies; data->valid = 1; @@ -635,19 +675,8 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev) return data; } -static int __init smsc47m192_init(void) -{ - return i2c_add_driver(&smsc47m192_driver); -} - -static void __exit smsc47m192_exit(void) -{ - i2c_del_driver(&smsc47m192_driver); -} +module_i2c_driver(smsc47m192_driver); MODULE_AUTHOR("Hartmut Rick <linux@rick.claranet.de>"); MODULE_DESCRIPTION("SMSC47M192 driver"); MODULE_LICENSE("GPL"); - -module_init(smsc47m192_init); -module_exit(smsc47m192_exit); diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 7dfb4dec4c5f..add9f019b24f 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -1,24 +1,24 @@ /* - thmc50.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> - Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and - Philip Edelbrock <phil@netroedge.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * thmc50.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> + * Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and + * Philip Edelbrock <phil@netroedge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ #include <linux/module.h> #include <linux/init.h> @@ -124,8 +124,13 @@ static ssize_t set_analog_out(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct thmc50_data *data = i2c_get_clientdata(client); - int tmp = simple_strtoul(buf, NULL, 10); int config; + unsigned long tmp; + int err; + + err = kstrtoul(buf, 10, &tmp); + if (err) + return err; mutex_lock(&data->update_lock); data->analog_out = SENSORS_LIMIT(tmp, 0, 255); @@ -173,7 +178,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct thmc50_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127); @@ -197,7 +207,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct thmc50_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127); @@ -360,14 +375,16 @@ static int thmc50_probe(struct i2c_client *client, thmc50_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group))) + err = sysfs_create_group(&client->dev.kobj, &thmc50_group); + if (err) goto exit_free; /* Register ADM1022 sysfs hooks */ - if (data->has_temp3) - if ((err = sysfs_create_group(&client->dev.kobj, - &temp3_group))) + if (data->has_temp3) { + err = sysfs_create_group(&client->dev.kobj, &temp3_group); + if (err) goto exit_remove_sysfs_thmc50; + } /* Register a new directory entry with module sensors */ data->hwmon_dev = hwmon_device_register(&client->dev); @@ -465,18 +482,7 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) return data; } -static int __init sm_thmc50_init(void) -{ - return i2c_add_driver(&thmc50_driver); -} - -static void __exit sm_thmc50_exit(void) -{ - i2c_del_driver(&thmc50_driver); -} +module_i2c_driver(thmc50_driver); MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); MODULE_DESCRIPTION("THMC50 driver"); - -module_init(sm_thmc50_init); -module_exit(sm_thmc50_exit); diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index c08eee21d76e..0d466b9d8908 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -292,17 +292,7 @@ static struct i2c_driver tmp102_driver = { .id_table = tmp102_id, }; -static int __init tmp102_init(void) -{ - return i2c_add_driver(&tmp102_driver); -} -module_init(tmp102_init); - -static void __exit tmp102_exit(void) -{ - i2c_del_driver(&tmp102_driver); -} -module_exit(tmp102_exit); +module_i2c_driver(tmp102_driver); MODULE_AUTHOR("Steven King <sfking@fdwdc.com>"); MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver"); diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index 951442adc067..ea54c3384671 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -662,19 +662,8 @@ static struct i2c_driver tmp401_driver = { .address_list = normal_i2c, }; -static int __init tmp401_init(void) -{ - return i2c_add_driver(&tmp401_driver); -} - -static void __exit tmp401_exit(void) -{ - i2c_del_driver(&tmp401_driver); -} +module_i2c_driver(tmp401_driver); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); MODULE_LICENSE("GPL"); - -module_init(tmp401_init); -module_exit(tmp401_exit); diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index c48381f2cd02..8fac87a38544 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -324,20 +324,9 @@ static struct i2c_driver tmp421_driver = { .address_list = normal_i2c, }; -static int __init tmp421_init(void) -{ - return i2c_add_driver(&tmp421_driver); -} - -static void __exit tmp421_exit(void) -{ - i2c_del_driver(&tmp421_driver); -} +module_i2c_driver(tmp421_driver); MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>"); MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor" " driver"); MODULE_LICENSE("GPL"); - -module_init(tmp421_init); -module_exit(tmp421_exit); diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index b9a87e89bab4..c315c59f61fe 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -1,4 +1,5 @@ -/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor. +/* + * ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor. * * Copyright (C) 2008 David S. Miller <davem@davemloft.net> */ @@ -82,7 +83,8 @@ static void env_write(struct env *p, u8 ireg, u8 val) spin_unlock(&p->lock); } -/* There seems to be a adr7462 providing these values, thus a lot +/* + * There seems to be a adr7462 providing these values, thus a lot * of these calculations are borrowed from the adt7470 driver. */ #define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) @@ -90,7 +92,8 @@ static void env_write(struct env *p, u8 ireg, u8 val) #define FAN_PERIOD_INVALID (0xff << 8) #define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) -static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, + char *buf) { int fan_nr = to_sensor_dev_attr(attr)->index; struct env *p = dev_get_drvdata(dev); @@ -111,10 +114,15 @@ static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int fan_nr = to_sensor_dev_attr(attr)->index; - int rpm = simple_strtol(buf, NULL, 10); + unsigned long rpm; struct env *p = dev_get_drvdata(dev); int period; u8 val; + int err; + + err = kstrtoul(buf, 10, &rpm); + if (err) + return err; if (!rpm) return -EINVAL; @@ -126,7 +134,8 @@ static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, + char *buf) { int fan_nr = to_sensor_dev_attr(attr)->index; struct env *p = dev_get_drvdata(dev); @@ -148,7 +157,8 @@ fan(4); static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6); -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { int temp_nr = to_sensor_dev_attr(attr)->index; struct env *p = dev_get_drvdata(dev); @@ -168,7 +178,8 @@ static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6); static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7); static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13); -static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, + char *buf) { int index = to_sensor_dev_attr(attr)->index; struct env *p = dev_get_drvdata(dev); @@ -181,9 +192,11 @@ static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0); static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1); static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2); -static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3); +static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, + 3); -static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, + char *buf) { struct env *p = dev_get_drvdata(dev); u8 val; @@ -194,7 +207,8 @@ static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, cha static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0); -static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) { return sprintf(buf, "ultra45\n"); } diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 25e91665a0a2..288135d85e11 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -1,34 +1,35 @@ /* - via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, - Kyösti Mälkki <kmalkki@cc.hut.fi>, - Mark Studebaker <mdsxyz123@yahoo.com>, - and Bob Dougherty <bobd@stanford.edu> - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew - <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * via686a.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * + * Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, + * Kyösti Mälkki <kmalkki@cc.hut.fi>, + * Mark Studebaker <mdsxyz123@yahoo.com>, + * and Bob Dougherty <bobd@stanford.edu> + * + * (Some conversion-factor data were contributed by Jonathan Teh Soon Yew + * <j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - Supports the Via VT82C686A, VT82C686B south bridges. - Reports all as a 686A. - Warning - only supports a single device. -*/ + * Supports the Via VT82C686A, VT82C686B south bridges. + * Reports all as a 686A. + * Warning - only supports a single device. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -47,8 +48,10 @@ #include <linux/io.h> -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ +/* + * If force_addr is set to anything different from 0, we forcibly enable + * the device at the given address. + */ static unsigned short force_addr; module_param(force_addr, ushort, 0); MODULE_PARM_DESC(force_addr, @@ -57,9 +60,9 @@ MODULE_PARM_DESC(force_addr, static struct platform_device *pdev; /* - The Via 686a southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c -*/ + * The Via 686a southbridge has a LM78-like chip integrated on the same IC. + * This driver is a customized copy of lm78.c + */ /* Many VIA686A constants specified below */ @@ -91,40 +94,46 @@ static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e }; #define VIA686A_REG_ALARM2 0x42 #define VIA686A_REG_FANDIV 0x47 #define VIA686A_REG_CONFIG 0x40 -/* The following register sets temp interrupt mode (bits 1-0 for temp1, - 3-2 for temp2, 5-4 for temp3). Modes are: - 00 interrupt stays as long as value is out-of-range - 01 interrupt is cleared once register is read (default) - 10 comparator mode- like 00, but ignores hysteresis - 11 same as 00 */ +/* + * The following register sets temp interrupt mode (bits 1-0 for temp1, + * 3-2 for temp2, 5-4 for temp3). Modes are: + * 00 interrupt stays as long as value is out-of-range + * 01 interrupt is cleared once register is read (default) + * 10 comparator mode- like 00, but ignores hysteresis + * 11 same as 00 + */ #define VIA686A_REG_TEMP_MODE 0x4b /* We'll just assume that you want to set all 3 simultaneously: */ #define VIA686A_TEMP_MODE_MASK 0x3F #define VIA686A_TEMP_MODE_CONTINUOUS 0x00 -/* Conversions. Limit checking is only done on the TO_REG - variants. - -********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** - From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): - voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp - voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V - voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V - voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V - voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V - in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; - That is: - volts = (25*regVal+133)*factor - regVal = (volts/factor-133)/25 - (These conversions were contributed by Jonathan Teh Soon Yew - <j.teh@iname.com>) */ +/* + * Conversions. Limit checking is only done on the TO_REG + * variants. + * + ******** VOLTAGE CONVERSIONS (Bob Dougherty) ******** + * From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): + * voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp + * voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V + * voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V + * voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V + * voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V + * in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; + * That is: + * volts = (25*regVal+133)*factor + * regVal = (volts/factor-133)/25 + * (These conversions were contributed by Jonathan Teh Soon Yew + * <j.teh@iname.com>) + */ static inline u8 IN_TO_REG(long val, int inNum) { - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - Rounding is done (120500 is actually 133000 - 12500). - Remember that val is expressed in 0.001V/bit, which is why we divide - by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) - for the constants. */ + /* + * To avoid floating point, we multiply constants by 10 (100 for +12V). + * Rounding is done (120500 is actually 133000 - 12500). + * Remember that val is expressed in 0.001V/bit, which is why we divide + * by an additional 10000 (100000 for +12V): 1000 for val and 10 (100) + * for the constants. + */ if (inNum <= 1) return (u8) SENSORS_LIMIT((val * 21024 - 1205000) / 250000, 0, 255); @@ -141,9 +150,11 @@ static inline u8 IN_TO_REG(long val, int inNum) static inline long IN_FROM_REG(u8 val, int inNum) { - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - We also multiply them by 1000 because we want 0.001V/bit for the - output value. Rounding is done. */ + /* + * To avoid floating point, we multiply constants by 10 (100 for +12V). + * We also multiply them by 1000 because we want 0.001V/bit for the + * output value. Rounding is done. + */ if (inNum <= 1) return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024); else if (inNum == 2) @@ -155,9 +166,11 @@ static inline long IN_FROM_REG(u8 val, int inNum) } /********* FAN RPM CONVERSIONS ********/ -/* Higher register values = slower fans (the fan's strobe gates a counter). - But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ +/* + * Higher register values = slower fans (the fan's strobe gates a counter). + * But this chip saturates back at 0, not at 255 like all the other chips. + * So, 0 means 0 RPM + */ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) @@ -166,42 +179,45 @@ static inline u8 FAN_TO_REG(long rpm, int div) return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); } -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) +#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (val) == 255 ? 0 : 1350000 / \ + ((val) * (div))) /******** TEMP CONVERSIONS (Bob Dougherty) *********/ -/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) - if(temp<169) - return double(temp)*0.427-32.08; - else if(temp>=169 && temp<=202) - return double(temp)*0.582-58.16; - else - return double(temp)*0.924-127.33; - - A fifth-order polynomial fits the unofficial data (provided by Alex van - Kaam <darkside@chello.nl>) a bit better. It also give more reasonable - numbers on my machine (ie. they agree with what my BIOS tells me). - Here's the fifth-order fit to the 8-bit data: - temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - - 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. - - (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for - finding my typos in this formula!) - - Alas, none of the elegant function-fit solutions will work because we - aren't allowed to use floating point in the kernel and doing it with - integers doesn't provide enough precision. So we'll do boring old - look-up table stuff. The unofficial data (see below) have effectively - 7-bit resolution (they are rounded to the nearest degree). I'm assuming - that the transfer function of the device is monotonic and smooth, so a - smooth function fit to the data will allow us to get better precision. - I used the 5th-order poly fit described above and solved for - VIA register values 0-255. I *10 before rounding, so we get tenth-degree - precision. (I could have done all 1024 values for our 10-bit readings, - but the function is very linear in the useful range (0-80 deg C), so - we'll just use linear interpolation for 10-bit readings.) So, tempLUT - is the temp at via register values 0-255: */ -static const s16 tempLUT[] = -{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, +/* + * linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) + * if(temp<169) + * return double(temp)*0.427-32.08; + * else if(temp>=169 && temp<=202) + * return double(temp)*0.582-58.16; + * else + * return double(temp)*0.924-127.33; + * + * A fifth-order polynomial fits the unofficial data (provided by Alex van + * Kaam <darkside@chello.nl>) a bit better. It also give more reasonable + * numbers on my machine (ie. they agree with what my BIOS tells me). + * Here's the fifth-order fit to the 8-bit data: + * temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - + * 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. + * + * (2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for + * finding my typos in this formula!) + * + * Alas, none of the elegant function-fit solutions will work because we + * aren't allowed to use floating point in the kernel and doing it with + * integers doesn't provide enough precision. So we'll do boring old + * look-up table stuff. The unofficial data (see below) have effectively + * 7-bit resolution (they are rounded to the nearest degree). I'm assuming + * that the transfer function of the device is monotonic and smooth, so a + * smooth function fit to the data will allow us to get better precision. + * I used the 5th-order poly fit described above and solved for + * VIA register values 0-255. I *10 before rounding, so we get tenth-degree + * precision. (I could have done all 1024 values for our 10-bit readings, + * but the function is very linear in the useful range (0-80 deg C), so + * we'll just use linear interpolation for 10-bit readings.) So, tempLUT + * is the temp at via register values 0-255: + */ +static const s16 tempLUT[] = { + -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, @@ -225,29 +241,31 @@ static const s16 tempLUT[] = 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 }; -/* the original LUT values from Alex van Kaam <darkside@chello.nl> - (for via register values 12-240): -{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, --30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, --15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, --3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, -12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, -22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, -33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, -45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, -61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, -85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; - - - Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed - an extra term for a good fit to these inverse data!) and then - solving for each temp value from -50 to 110 (the useable range for - this chip). Here's the fit: - viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 - - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) - Note that n=161: */ -static const u8 viaLUT[] = -{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, +/* + * the original LUT values from Alex van Kaam <darkside@chello.nl> + * (for via register values 12-240): + * {-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, + * -30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, + * -15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, + * -3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, + * 12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, + * 22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, + * 33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, + * 45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, + * 61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, + * 85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; + * + * + * Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed + * an extra term for a good fit to these inverse data!) and then + * solving for each temp value from -50 to 110 (the useable range for + * this chip). Here's the fit: + * viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 + * - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) + * Note that n=161: + */ +static const u8 viaLUT[] = { + 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, @@ -262,9 +280,11 @@ static const u8 viaLUT[] = 239, 240 }; -/* Converting temps to (8-bit) hyst and over registers - No interpolation here. - The +50 is because the temps start at -50 */ +/* + * Converting temps to (8-bit) hyst and over registers + * No interpolation here. + * The +50 is because the temps start at -50 + */ static inline u8 TEMP_TO_REG(long val) { return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 : @@ -290,10 +310,12 @@ static inline long TEMP_FROM_REG10(u16 val) } #define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) +#define DIV_TO_REG(val) ((val) == 8 ? 3 : (val) == 4 ? 2 : (val) == 1 ? 0 : 1) -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* + * For each registered chip, we need to keep some data in memory. + * The structure is dynamically allocated. + */ struct via686a_data { unsigned short addr; const char *name; @@ -365,7 +387,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *da, struct via686a_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val, nr); @@ -379,7 +406,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *da, struct via686a_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val, nr); @@ -429,7 +461,12 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, struct via686a_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_over[nr] = TEMP_TO_REG(val); @@ -443,7 +480,12 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, struct via686a_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_hyst[nr] = TEMP_TO_REG(val); @@ -471,7 +513,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])) ); + DIV_FROM_REG(data->fan_div[nr]))); } static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, char *buf) { @@ -479,21 +521,27 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; return sprintf(buf, "%d\n", - FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) ); + FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); } static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, char *buf) { struct via686a_data *data = via686a_update_device(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); } static ssize_t set_fan_min(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct via686a_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - int val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -506,8 +554,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, struct via686a_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int nr = attr->index; - int val = simple_strtol(buf, NULL, 10); int old; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); old = via686a_read_value(data, VIA686A_REG_FANDIV); @@ -530,10 +583,13 @@ show_fan_offset(1); show_fan_offset(2); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) +{ struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } + static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, @@ -641,7 +697,8 @@ static int __devinit via686a_probe(struct platform_device *pdev) return -ENODEV; } - if (!(data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct via686a_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit_release; } @@ -655,7 +712,8 @@ static int __devinit via686a_probe(struct platform_device *pdev) via686a_init_device(data); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group))) + err = sysfs_create_group(&pdev->dev.kobj, &via686a_group); + if (err) goto exit_free; data->hwmon_dev = hwmon_device_register(&pdev->dev); @@ -748,10 +806,11 @@ static struct via686a_data *via686a_update_device(struct device *dev) via686a_read_value(data, VIA686A_REG_TEMP_HYST[i]); } - /* add in lower 2 bits - temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 - temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 - temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 + /* + * add in lower 2 bits + * temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 + * temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 + * temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 */ data->temp[0] |= (via686a_read_value(data, VIA686A_REG_TEMP_LOW1) @@ -777,11 +836,10 @@ static struct via686a_data *via686a_update_device(struct device *dev) return data; } -static const struct pci_device_id via686a_pci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(via686a_pci_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, - { 0, } + { } }; - MODULE_DEVICE_TABLE(pci, via686a_pci_ids); static int __devinit via686a_device_add(unsigned short address) @@ -872,7 +930,8 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev, if (via686a_device_add(address)) goto exit_unregister; - /* Always return failure here. This is to allow other drivers to bind + /* + * Always return failure here. This is to allow other drivers to bind * to this pci device. We don't really want to have control over the * pci device, we only wanted to read as few register values from it. */ diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 49163d48e966..c2c5c72fb8f0 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -151,8 +151,10 @@ struct vt1211_data { #define ISTEMP(ix, uch_config) ((ix) < 2 ? 1 : \ ((uch_config) >> (ix)) & 1) -/* in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the - driver according to the VT1211 BIOS porting guide */ +/* + * in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the + * driver according to the VT1211 BIOS porting guide + */ #define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \ (((reg) - 3) * 15882 + 479) / 958 : \ (((reg) - 3) * 10000 + 479) / 958) @@ -160,11 +162,13 @@ struct vt1211_data { ((val) * 958 + 7941) / 15882 + 3 : \ ((val) * 958 + 5000) / 10000 + 3, 0, 255)) -/* temp1 (ix = 0) is an intel thermal diode which is scaled in user space. - temp2 (ix = 1) is the internal temp diode so it's scaled in the driver - according to some measurements that I took on an EPIA M10000. - temp3-7 are thermistor based so the driver returns the voltage measured at - the pin (range 0V - 2.2V). */ +/* + * temp1 (ix = 0) is an intel thermal diode which is scaled in user space. + * temp2 (ix = 1) is the internal temp diode so it's scaled in the driver + * according to some measurements that I took on an EPIA M10000. + * temp3-7 are thermistor based so the driver returns the voltage measured at + * the pin (range 0V - 2.2V). + */ #define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \ (ix) == 1 ? (reg) < 51 ? 0 : \ ((reg) - 51) * 1000 : \ @@ -186,8 +190,10 @@ struct vt1211_data { * Super-I/O constants and functions * --------------------------------------------------------------------- */ -/* Configuration index port registers - * The vt1211 can live at 2 different addresses so we need to probe both */ +/* + * Configuration index port registers + * The vt1211 can live at 2 different addresses so we need to probe both + */ #define SIO_REG_CIP1 0x2e #define SIO_REG_CIP2 0x4e @@ -377,7 +383,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -446,7 +457,12 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (fn) { @@ -517,8 +533,13 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); int reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -536,16 +557,23 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, break; case SHOW_SET_FAN_DIV: switch (val) { - case 1: data->fan_div[ix] = 0; break; - case 2: data->fan_div[ix] = 1; break; - case 4: data->fan_div[ix] = 2; break; - case 8: data->fan_div[ix] = 3; break; - default: - count = -EINVAL; - dev_warn(dev, "fan div value %ld not " - "supported. Choose one of 1, 2, " - "4, or 8.\n", val); - goto EXIT; + case 1: + data->fan_div[ix] = 0; + break; + case 2: + data->fan_div[ix] = 1; + break; + case 4: + data->fan_div[ix] = 2; + break; + case 8: + data->fan_div[ix] = 3; + break; + default: + count = -EINVAL; + dev_warn(dev, "fan div value %ld not supported. " + "Choose one of 1, 2, 4, or 8.\n", val); + goto EXIT; } vt1211_write8(data, VT1211_REG_FAN_DIV, ((data->fan_div[1] << 6) | @@ -610,8 +638,13 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); int tmp, reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -628,11 +661,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, switch (val) { case 0: data->pwm_ctl[ix] &= 7; - /* disable SmartGuardian if both PWM outputs are - * disabled */ - if ((data->pwm_ctl[ix ^ 1] & 1) == 0) { + /* + * disable SmartGuardian if both PWM outputs are + * disabled + */ + if ((data->pwm_ctl[ix ^ 1] & 1) == 0) data->fan_ctl &= 0xe; - } break; case 2: data->pwm_ctl[ix] |= 8; @@ -656,16 +690,15 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000); /* calculate tmp = log2(val) */ tmp = 0; - for (val >>= 1; val > 0; val >>= 1) { + for (val >>= 1; val > 0; val >>= 1) tmp++; - } /* sync the data cache */ reg = vt1211_read8(data, VT1211_REG_PWM_CLK); data->pwm_clk = (reg & 0xf8) | tmp; vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk); break; case SHOW_SET_PWM_AUTO_CHANNELS_TEMP: - if ((val < 1) || (val > 7)) { + if (val < 1 || val > 7) { count = -EINVAL; dev_warn(dev, "temp channel %ld not supported. " "Choose a value between 1 and 7.\n", val); @@ -741,8 +774,14 @@ static ssize_t set_pwm_auto_point_temp(struct device *dev, to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int ap = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); int reg; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); @@ -774,7 +813,7 @@ static ssize_t set_pwm_auto_point_temp(struct device *dev, * 1 1 : pwm2 low speed duty cycle (pwm_auto_pwm[1][1]) * 1 2 : pwm2 high speed duty cycle (pwm_auto_pwm[1][2]) * 1 3 : pwm2 full speed (pwm_auto_pwm[1][3], hard-wired to 255) -*/ + */ static ssize_t show_pwm_auto_point_pwm(struct device *dev, struct device_attribute *attr, @@ -798,16 +837,15 @@ static ssize_t set_pwm_auto_point_pwm(struct device *dev, to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; int ap = sensor_attr_2->nr; - long val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; - if ((val < 0) || (val > 255)) { - dev_err(dev, "pwm value %ld is out of range. " - "Choose a value between 0 and 255.\n" , val); - return -EINVAL; - } + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - data->pwm_auto_pwm[ix][ap] = val; + data->pwm_auto_pwm[ix][ap] = SENSORS_LIMIT(val, 0, 255); vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap), data->pwm_auto_pwm[ix][ap]); mutex_unlock(&data->update_lock); @@ -831,7 +869,12 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vt1211_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; data->vrm = val; @@ -866,112 +909,99 @@ static ssize_t show_alarms(struct device *dev, * Device attribute structs * --------------------------------------------------------------------- */ -#define SENSOR_ATTR_IN_INPUT(ix) \ - SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \ - show_in, NULL, SHOW_IN_INPUT, ix) - -static struct sensor_device_attribute_2 vt1211_sysfs_in_input[] = { - SENSOR_ATTR_IN_INPUT(0), - SENSOR_ATTR_IN_INPUT(1), - SENSOR_ATTR_IN_INPUT(2), - SENSOR_ATTR_IN_INPUT(3), - SENSOR_ATTR_IN_INPUT(4), - SENSOR_ATTR_IN_INPUT(5), -}; - -#define SENSOR_ATTR_IN_MIN(ix) \ +#define SENSOR_ATTR_IN(ix) \ +{ SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \ + show_in, NULL, SHOW_IN_INPUT, ix), \ SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \ - show_in, set_in, SHOW_SET_IN_MIN, ix) - -static struct sensor_device_attribute_2 vt1211_sysfs_in_min[] = { - SENSOR_ATTR_IN_MIN(0), - SENSOR_ATTR_IN_MIN(1), - SENSOR_ATTR_IN_MIN(2), - SENSOR_ATTR_IN_MIN(3), - SENSOR_ATTR_IN_MIN(4), - SENSOR_ATTR_IN_MIN(5), -}; - -#define SENSOR_ATTR_IN_MAX(ix) \ + show_in, set_in, SHOW_SET_IN_MIN, ix), \ SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \ - show_in, set_in, SHOW_SET_IN_MAX, ix) - -static struct sensor_device_attribute_2 vt1211_sysfs_in_max[] = { - SENSOR_ATTR_IN_MAX(0), - SENSOR_ATTR_IN_MAX(1), - SENSOR_ATTR_IN_MAX(2), - SENSOR_ATTR_IN_MAX(3), - SENSOR_ATTR_IN_MAX(4), - SENSOR_ATTR_IN_MAX(5), + show_in, set_in, SHOW_SET_IN_MAX, ix), \ + SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \ + show_in, NULL, SHOW_IN_ALARM, ix) \ +} + +static struct sensor_device_attribute_2 vt1211_sysfs_in[][4] = { + SENSOR_ATTR_IN(0), + SENSOR_ATTR_IN(1), + SENSOR_ATTR_IN(2), + SENSOR_ATTR_IN(3), + SENSOR_ATTR_IN(4), + SENSOR_ATTR_IN(5) }; -#define SENSOR_ATTR_IN_ALARM(ix) \ - SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \ - show_in, NULL, SHOW_IN_ALARM, ix) - -static struct sensor_device_attribute_2 vt1211_sysfs_in_alarm[] = { - SENSOR_ATTR_IN_ALARM(0), - SENSOR_ATTR_IN_ALARM(1), - SENSOR_ATTR_IN_ALARM(2), - SENSOR_ATTR_IN_ALARM(3), - SENSOR_ATTR_IN_ALARM(4), - SENSOR_ATTR_IN_ALARM(5), +#define IN_UNIT_ATTRS(X) \ +{ &vt1211_sysfs_in[X][0].dev_attr.attr, \ + &vt1211_sysfs_in[X][1].dev_attr.attr, \ + &vt1211_sysfs_in[X][2].dev_attr.attr, \ + &vt1211_sysfs_in[X][3].dev_attr.attr, \ + NULL \ +} + +static struct attribute *vt1211_in_attr[][5] = { + IN_UNIT_ATTRS(0), + IN_UNIT_ATTRS(1), + IN_UNIT_ATTRS(2), + IN_UNIT_ATTRS(3), + IN_UNIT_ATTRS(4), + IN_UNIT_ATTRS(5) }; -#define SENSOR_ATTR_TEMP_INPUT(ix) \ - SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \ - show_temp, NULL, SHOW_TEMP_INPUT, ix-1) - -static struct sensor_device_attribute_2 vt1211_sysfs_temp_input[] = { - SENSOR_ATTR_TEMP_INPUT(1), - SENSOR_ATTR_TEMP_INPUT(2), - SENSOR_ATTR_TEMP_INPUT(3), - SENSOR_ATTR_TEMP_INPUT(4), - SENSOR_ATTR_TEMP_INPUT(5), - SENSOR_ATTR_TEMP_INPUT(6), - SENSOR_ATTR_TEMP_INPUT(7), +static const struct attribute_group vt1211_in_attr_group[] = { + { .attrs = vt1211_in_attr[0] }, + { .attrs = vt1211_in_attr[1] }, + { .attrs = vt1211_in_attr[2] }, + { .attrs = vt1211_in_attr[3] }, + { .attrs = vt1211_in_attr[4] }, + { .attrs = vt1211_in_attr[5] } }; -#define SENSOR_ATTR_TEMP_MAX(ix) \ +#define SENSOR_ATTR_TEMP(ix) \ +{ SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \ + show_temp, NULL, SHOW_TEMP_INPUT, ix-1), \ SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \ - show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1) - -static struct sensor_device_attribute_2 vt1211_sysfs_temp_max[] = { - SENSOR_ATTR_TEMP_MAX(1), - SENSOR_ATTR_TEMP_MAX(2), - SENSOR_ATTR_TEMP_MAX(3), - SENSOR_ATTR_TEMP_MAX(4), - SENSOR_ATTR_TEMP_MAX(5), - SENSOR_ATTR_TEMP_MAX(6), - SENSOR_ATTR_TEMP_MAX(7), + show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1), \ + SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1), \ + SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \ + show_temp, NULL, SHOW_TEMP_ALARM, ix-1) \ +} + +static struct sensor_device_attribute_2 vt1211_sysfs_temp[][4] = { + SENSOR_ATTR_TEMP(1), + SENSOR_ATTR_TEMP(2), + SENSOR_ATTR_TEMP(3), + SENSOR_ATTR_TEMP(4), + SENSOR_ATTR_TEMP(5), + SENSOR_ATTR_TEMP(6), + SENSOR_ATTR_TEMP(7), }; -#define SENSOR_ATTR_TEMP_MAX_HYST(ix) \ - SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \ - show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1) - -static struct sensor_device_attribute_2 vt1211_sysfs_temp_max_hyst[] = { - SENSOR_ATTR_TEMP_MAX_HYST(1), - SENSOR_ATTR_TEMP_MAX_HYST(2), - SENSOR_ATTR_TEMP_MAX_HYST(3), - SENSOR_ATTR_TEMP_MAX_HYST(4), - SENSOR_ATTR_TEMP_MAX_HYST(5), - SENSOR_ATTR_TEMP_MAX_HYST(6), - SENSOR_ATTR_TEMP_MAX_HYST(7), +#define TEMP_UNIT_ATTRS(X) \ +{ &vt1211_sysfs_temp[X][0].dev_attr.attr, \ + &vt1211_sysfs_temp[X][1].dev_attr.attr, \ + &vt1211_sysfs_temp[X][2].dev_attr.attr, \ + &vt1211_sysfs_temp[X][3].dev_attr.attr, \ + NULL \ +} + +static struct attribute *vt1211_temp_attr[][5] = { + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), + TEMP_UNIT_ATTRS(3), + TEMP_UNIT_ATTRS(4), + TEMP_UNIT_ATTRS(5), + TEMP_UNIT_ATTRS(6) }; -#define SENSOR_ATTR_TEMP_ALARM(ix) \ - SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \ - show_temp, NULL, SHOW_TEMP_ALARM, ix-1) - -static struct sensor_device_attribute_2 vt1211_sysfs_temp_alarm[] = { - SENSOR_ATTR_TEMP_ALARM(1), - SENSOR_ATTR_TEMP_ALARM(2), - SENSOR_ATTR_TEMP_ALARM(3), - SENSOR_ATTR_TEMP_ALARM(4), - SENSOR_ATTR_TEMP_ALARM(5), - SENSOR_ATTR_TEMP_ALARM(6), - SENSOR_ATTR_TEMP_ALARM(7), +static const struct attribute_group vt1211_temp_attr_group[] = { + { .attrs = vt1211_temp_attr[0] }, + { .attrs = vt1211_temp_attr[1] }, + { .attrs = vt1211_temp_attr[2] }, + { .attrs = vt1211_temp_attr[3] }, + { .attrs = vt1211_temp_attr[4] }, + { .attrs = vt1211_temp_attr[5] }, + { .attrs = vt1211_temp_attr[6] } }; #define SENSOR_ATTR_FAN(ix) \ @@ -1069,7 +1099,8 @@ static void __devinit vt1211_init_device(struct vt1211_data *data) vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config); } - /* Initialize the interrupt mode (if request at module load time). + /* + * Initialize the interrupt mode (if request at module load time). * The VT1211 implements 3 different modes for clearing interrupts: * 0: Clear INT when status register is read. Regenerate INT as long * as temp stays above hysteresis limit. @@ -1079,7 +1110,8 @@ static void __devinit vt1211_init_device(struct vt1211_data *data) * 2: Clear INT when temp falls below max limit. * * The driver only allows to force mode 0 since that's the only one - * that makes sense for 'sensors' */ + * that makes sense for 'sensors' + */ if (int_mode == 0) { vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0); vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0); @@ -1095,33 +1127,18 @@ static void vt1211_remove_sysfs(struct platform_device *pdev) struct device *dev = &pdev->dev; int i; - for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) { - device_remove_file(dev, - &vt1211_sysfs_in_input[i].dev_attr); - device_remove_file(dev, - &vt1211_sysfs_in_min[i].dev_attr); - device_remove_file(dev, - &vt1211_sysfs_in_max[i].dev_attr); - device_remove_file(dev, - &vt1211_sysfs_in_alarm[i].dev_attr); - } - for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) { - device_remove_file(dev, - &vt1211_sysfs_temp_input[i].dev_attr); - device_remove_file(dev, - &vt1211_sysfs_temp_max[i].dev_attr); - device_remove_file(dev, - &vt1211_sysfs_temp_max_hyst[i].dev_attr); - device_remove_file(dev, - &vt1211_sysfs_temp_alarm[i].dev_attr); - } + for (i = 0; i < ARRAY_SIZE(vt1211_in_attr_group); i++) + sysfs_remove_group(&dev->kobj, &vt1211_in_attr_group[i]); + + for (i = 0; i < ARRAY_SIZE(vt1211_temp_attr_group); i++) + sysfs_remove_group(&dev->kobj, &vt1211_temp_attr_group[i]); + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) { device_remove_file(dev, &vt1211_sysfs_fan_pwm[i].dev_attr); } - for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) { + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) device_remove_file(dev, &vt1211_sysfs_misc[i]); - } } static int __devinit vt1211_probe(struct platform_device *pdev) @@ -1131,7 +1148,8 @@ static int __devinit vt1211_probe(struct platform_device *pdev) struct resource *res; int i, err; - if (!(data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; dev_err(dev, "Out of memory\n"); goto EXIT; @@ -1154,47 +1172,33 @@ static int __devinit vt1211_probe(struct platform_device *pdev) vt1211_init_device(data); /* Create sysfs interface files */ - for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) { + for (i = 0; i < ARRAY_SIZE(vt1211_in_attr_group); i++) { if (ISVOLT(i, data->uch_config)) { - if ((err = device_create_file(dev, - &vt1211_sysfs_in_input[i].dev_attr)) || - (err = device_create_file(dev, - &vt1211_sysfs_in_min[i].dev_attr)) || - (err = device_create_file(dev, - &vt1211_sysfs_in_max[i].dev_attr)) || - (err = device_create_file(dev, - &vt1211_sysfs_in_alarm[i].dev_attr))) { + err = sysfs_create_group(&dev->kobj, + &vt1211_in_attr_group[i]); + if (err) goto EXIT_DEV_REMOVE; - } } } - for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) { + for (i = 0; i < ARRAY_SIZE(vt1211_temp_attr_group); i++) { if (ISTEMP(i, data->uch_config)) { - if ((err = device_create_file(dev, - &vt1211_sysfs_temp_input[i].dev_attr)) || - (err = device_create_file(dev, - &vt1211_sysfs_temp_max[i].dev_attr)) || - (err = device_create_file(dev, - &vt1211_sysfs_temp_max_hyst[i].dev_attr)) || - (err = device_create_file(dev, - &vt1211_sysfs_temp_alarm[i].dev_attr))) { + err = sysfs_create_group(&dev->kobj, + &vt1211_temp_attr_group[i]); + if (err) goto EXIT_DEV_REMOVE; - } } } for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) { err = device_create_file(dev, &vt1211_sysfs_fan_pwm[i].dev_attr); - if (err) { + if (err) goto EXIT_DEV_REMOVE; - } } for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) { err = device_create_file(dev, &vt1211_sysfs_misc[i]); - if (err) { + if (err) goto EXIT_DEV_REMOVE; - } } /* Register device */ @@ -1293,9 +1297,8 @@ static int __init vt1211_find(int sio_cip, unsigned short *address) superio_enter(sio_cip); devid = force_id ? force_id : superio_inb(sio_cip, SIO_VT1211_DEVID); - if (devid != SIO_VT1211_ID) { + if (devid != SIO_VT1211_ID) goto EXIT; - } superio_select(sio_cip, SIO_VT1211_LDN_HWMON); @@ -1325,35 +1328,35 @@ static int __init vt1211_init(void) int err; unsigned short address = 0; - if ((err = vt1211_find(SIO_REG_CIP1, &address)) && - (err = vt1211_find(SIO_REG_CIP2, &address))) { - goto EXIT; + err = vt1211_find(SIO_REG_CIP1, &address); + if (err) { + err = vt1211_find(SIO_REG_CIP2, &address); + if (err) + goto EXIT; } if ((uch_config < -1) || (uch_config > 31)) { err = -EINVAL; pr_warn("Invalid UCH configuration %d. " "Choose a value between 0 and 31.\n", uch_config); - goto EXIT; + goto EXIT; } if ((int_mode < -1) || (int_mode > 0)) { err = -EINVAL; pr_warn("Invalid interrupt mode %d. " "Only mode 0 is supported.\n", int_mode); - goto EXIT; + goto EXIT; } err = platform_driver_register(&vt1211_driver); - if (err) { + if (err) goto EXIT; - } /* Sets global pdev as a side effect */ err = vt1211_device_add(address); - if (err) { + if (err) goto EXIT_DRV_UNREGISTER; - } return 0; diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index db3b2e8d2a67..386a84538010 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -1,28 +1,29 @@ /* - vt8231.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring + * vt8231.c - Part of lm_sensors, Linux kernel modules + * for hardware monitoring + * + * Copyright (c) 2005 Roger Lucas <vt8231@hiddenengine.co.uk> + * Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> + * Aaron M. Marsh <amarsh@sdf.lonestar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ - Copyright (c) 2005 Roger Lucas <vt8231@hiddenengine.co.uk> - Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> - Aaron M. Marsh <amarsh@sdf.lonestar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports VIA VT8231 South Bridge embedded sensors -*/ +/* + * Supports VIA VT8231 South Bridge embedded sensors + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -50,26 +51,27 @@ static struct platform_device *pdev; #define VT8231_BASE_REG 0x70 #define VT8231_ENABLE_REG 0x74 -/* The VT8231 registers - - The reset value for the input channel configuration is used (Reg 0x4A=0x07) - which sets the selected inputs marked with '*' below if multiple options are - possible: - - Voltage Mode Temperature Mode - Sensor Linux Id Linux Id VIA Id - -------- -------- -------- ------ - CPU Diode N/A temp1 0 - UIC1 in0 temp2 * 1 - UIC2 in1 * temp3 2 - UIC3 in2 * temp4 3 - UIC4 in3 * temp5 4 - UIC5 in4 * temp6 5 - 3.3V in5 N/A - - Note that the BIOS may set the configuration register to a different value - to match the motherboard configuration. -*/ +/* + * The VT8231 registers + * + * The reset value for the input channel configuration is used (Reg 0x4A=0x07) + * which sets the selected inputs marked with '*' below if multiple options are + * possible: + * + * Voltage Mode Temperature Mode + * Sensor Linux Id Linux Id VIA Id + * -------- -------- -------- ------ + * CPU Diode N/A temp1 0 + * UIC1 in0 temp2 * 1 + * UIC2 in1 * temp3 2 + * UIC3 in2 * temp4 3 + * UIC4 in3 * temp5 4 + * UIC5 in4 * temp6 5 + * 3.3V in5 N/A + * + * Note that the BIOS may set the configuration register to a different value + * to match the motherboard configuration. + */ /* fans numbered 0-1 */ #define VT8231_REG_FAN_MIN(nr) (0x3b + (nr)) @@ -81,13 +83,14 @@ static const u8 regvolt[] = { 0x21, 0x22, 0x23, 0x24, 0x25, 0x26 }; static const u8 regvoltmax[] = { 0x3d, 0x2b, 0x2d, 0x2f, 0x31, 0x33 }; static const u8 regvoltmin[] = { 0x3e, 0x2c, 0x2e, 0x30, 0x32, 0x34 }; -/* Temperatures are numbered 1-6 according to the Linux kernel specification. -** -** In the VIA datasheet, however, the temperatures are numbered from zero. -** Since it is important that this driver can easily be compared to the VIA -** datasheet, we will use the VIA numbering within this driver and map the -** kernel sysfs device name to the VIA number in the sysfs callback. -*/ +/* + * Temperatures are numbered 1-6 according to the Linux kernel specification. + * + * In the VIA datasheet, however, the temperatures are numbered from zero. + * Since it is important that this driver can easily be compared to the VIA + * datasheet, we will use the VIA numbering within this driver and map the + * kernel sysfs device name to the VIA number in the sysfs callback. + */ #define VT8231_REG_TEMP_LOW01 0x49 #define VT8231_REG_TEMP_LOW25 0x4d @@ -108,9 +111,10 @@ static const u8 regtempmin[] = { 0x3a, 0x3e, 0x2c, 0x2e, 0x30, 0x32 }; #define VT8231_REG_TEMP1_CONFIG 0x4b #define VT8231_REG_TEMP2_CONFIG 0x4c -/* temps 0-5 as numbered in VIA datasheet - see later for mapping to Linux -** numbering -*/ +/* + * temps 0-5 as numbered in VIA datasheet - see later for mapping to Linux + * numbering + */ #define ISTEMP(i, ch_config) ((i) == 0 ? 1 : \ ((ch_config) >> ((i)+1)) & 0x01) /* voltages 0-5 */ @@ -119,24 +123,26 @@ static const u8 regtempmin[] = { 0x3a, 0x3e, 0x2c, 0x2e, 0x30, 0x32 }; #define DIV_FROM_REG(val) (1 << (val)) -/* NB The values returned here are NOT temperatures. The calibration curves -** for the thermistor curves are board-specific and must go in the -** sensors.conf file. Temperature sensors are actually ten bits, but the -** VIA datasheet only considers the 8 MSBs obtained from the regtemp[] -** register. The temperature value returned should have a magnitude of 3, -** so we use the VIA scaling as the "true" scaling and use the remaining 2 -** LSBs as fractional precision. -** -** All the on-chip hardware temperature comparisons for the alarms are only -** 8-bits wide, and compare against the 8 MSBs of the temperature. The bits -** in the registers VT8231_REG_TEMP_LOW01 and VT8231_REG_TEMP_LOW25 are -** ignored. -*/ - -/******** FAN RPM CONVERSIONS ******** -** This chip saturates back at 0, not at 255 like many the other chips. -** So, 0 means 0 RPM -*/ +/* + * NB The values returned here are NOT temperatures. The calibration curves + * for the thermistor curves are board-specific and must go in the + * sensors.conf file. Temperature sensors are actually ten bits, but the + * VIA datasheet only considers the 8 MSBs obtained from the regtemp[] + * register. The temperature value returned should have a magnitude of 3, + * so we use the VIA scaling as the "true" scaling and use the remaining 2 + * LSBs as fractional precision. + * + * All the on-chip hardware temperature comparisons for the alarms are only + * 8-bits wide, and compare against the 8 MSBs of the temperature. The bits + * in the registers VT8231_REG_TEMP_LOW01 and VT8231_REG_TEMP_LOW25 are + * ignored. + */ + +/* + ****** FAN RPM CONVERSIONS ******** + * This chip saturates back at 0, not at 255 like many the other chips. + * So, 0 means 0 RPM + */ static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) @@ -222,7 +228,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255); @@ -237,7 +248,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255); @@ -278,7 +294,12 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3, @@ -292,7 +313,12 @@ static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3, @@ -346,7 +372,12 @@ static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255); @@ -358,7 +389,12 @@ static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255); @@ -400,7 +436,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = dev_get_drvdata(dev); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255); @@ -414,7 +455,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = dev_get_drvdata(dev); - int val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255); @@ -423,9 +469,10 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, return count; } -/* Note that these map the Linux temperature sensor numbering (1-6) to the VIA -** temperature sensor numbering (0-5) -*/ +/* + * Note that these map the Linux temperature sensor numbering (1-6) to the VIA + * temperature sensor numbering (0-5) + */ #define define_temperature_sysfs(offset) \ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ show_temp, NULL, offset - 1); \ @@ -436,7 +483,8 @@ static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp0, NULL); static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp0_max, set_temp0_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp0_min, set_temp0_min); +static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp0_min, + set_temp0_min); define_temperature_sysfs(2); define_temperature_sysfs(3); @@ -480,7 +528,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = dev_get_drvdata(dev); - int val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -494,21 +547,34 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, { struct vt8231_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; int nr = sensor_attr->index; int old = vt8231_read_value(data, VT8231_REG_FANDIV); long min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); switch (val) { - case 1: data->fan_div[nr] = 0; break; - case 2: data->fan_div[nr] = 1; break; - case 4: data->fan_div[nr] = 2; break; - case 8: data->fan_div[nr] = 3; break; + case 1: + data->fan_div[nr] = 0; + break; + case 2: + data->fan_div[nr] = 1; + break; + case 4: + data->fan_div[nr] = 2; + break; + case 8: + data->fan_div[nr] = 3; + break; default: dev_err(dev, "fan_div value %ld not supported. " - "Choose one of 1, 2, 4 or 8!\n", val); + "Choose one of 1, 2, 4 or 8!\n", val); mutex_unlock(&data->update_lock); return -EINVAL; } @@ -699,7 +765,7 @@ static struct platform_driver vt8231_driver = { .remove = __devexit_p(vt8231_remove), }; -static const struct pci_device_id vt8231_pci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(vt8231_pci_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) }, { 0, } }; @@ -707,7 +773,7 @@ static const struct pci_device_id vt8231_pci_ids[] = { MODULE_DEVICE_TABLE(pci, vt8231_pci_ids); static int __devinit vt8231_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id); + const struct pci_device_id *id); static struct pci_driver vt8231_pci_driver = { .name = "vt8231", @@ -730,7 +796,8 @@ static int vt8231_probe(struct platform_device *pdev) return -ENODEV; } - if (!(data = kzalloc(sizeof(struct vt8231_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct vt8231_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit_release; } @@ -743,7 +810,8 @@ static int vt8231_probe(struct platform_device *pdev) vt8231_init_device(data); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group))) + err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group); + if (err) goto exit_free; /* Must update device information to find out the config field */ @@ -751,16 +819,18 @@ static int vt8231_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) { if (ISTEMP(i, data->uch_config)) { - if ((err = sysfs_create_group(&pdev->dev.kobj, - &vt8231_group_temps[i]))) + err = sysfs_create_group(&pdev->dev.kobj, + &vt8231_group_temps[i]); + if (err) goto exit_remove_files; } } for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) { if (ISVOLT(i, data->uch_config)) { - if ((err = sysfs_create_group(&pdev->dev.kobj, - &vt8231_group_volts[i]))) + err = sysfs_create_group(&pdev->dev.kobj, + &vt8231_group_volts[i]); + if (err) goto exit_remove_files; } } @@ -866,17 +936,15 @@ static struct vt8231_data *vt8231_update_device(struct device *dev) (vt8231_read_value(data, VT8231_REG_ALARM2) << 8); /* Set alarm flags correctly */ - if (!data->fan[0] && data->fan_min[0]) { + if (!data->fan[0] && data->fan_min[0]) data->alarms |= 0x40; - } else if (data->fan[0] && !data->fan_min[0]) { + else if (data->fan[0] && !data->fan_min[0]) data->alarms &= ~0x40; - } - if (!data->fan[1] && data->fan_min[1]) { + if (!data->fan[1] && data->fan_min[1]) data->alarms |= 0x80; - } else if (data->fan[1] && !data->fan_min[1]) { + else if (data->fan[1] && !data->fan_min[1]) data->alarms &= ~0x80; - } data->last_updated = jiffies; data->valid = 1; @@ -971,13 +1039,16 @@ static int __devinit vt8231_pci_probe(struct pci_dev *dev, if (vt8231_device_add(address)) goto exit_unregister; - /* Always return failure here. This is to allow other drivers to bind + /* + * Always return failure here. This is to allow other drivers to bind * to this pci device. We don't really want to have control over the * pci device, we only wanted to read as few register values from it. */ - /* We do, however, mark ourselves as using the PCI device to stop it - getting unloaded. */ + /* + * We do, however, mark ourselves as using the PCI device to stop it + * getting unloaded. + */ s_bridge = pci_dev_get(dev); return -ENODEV; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index a658d62c5e10..a25350cf9554 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1,50 +1,49 @@ /* - w83627ehf - Driver for the hardware monitoring functionality of - the Winbond W83627EHF Super-I/O chip - Copyright (C) 2005-2011 Jean Delvare <khali@linux-fr.org> - Copyright (C) 2006 Yuan Mu (Winbond), - Rudolf Marek <r.marek@assembler.cz> - David Hubbard <david.c.hubbard@gmail.com> - Daniel J Blueman <daniel.blueman@gmail.com> - Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00) - - Shamelessly ripped from the w83627hf driver - Copyright (C) 2003 Mark Studebaker - - Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help - in testing and debugging this driver. - - This driver also supports the W83627EHG, which is the lead-free - version of the W83627EHF. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - - Supports the following chips: - - Chip #vin #fan #pwm #temp chip IDs man ID - w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 - 0x8860 0xa1 - w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 - w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 - w83627uhg 8 2 2 3 0xa230 0xc1 0x5ca3 - w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 - w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 - nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3 - nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3 -*/ + * w83627ehf - Driver for the hardware monitoring functionality of + * the Winbond W83627EHF Super-I/O chip + * Copyright (C) 2005-2011 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2006 Yuan Mu (Winbond), + * Rudolf Marek <r.marek@assembler.cz> + * David Hubbard <david.c.hubbard@gmail.com> + * Daniel J Blueman <daniel.blueman@gmail.com> + * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00) + * + * Shamelessly ripped from the w83627hf driver + * Copyright (C) 2003 Mark Studebaker + * + * Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help + * in testing and debugging this driver. + * + * This driver also supports the W83627EHG, which is the lead-free + * version of the W83627EHF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Supports the following chips: + * + * Chip #vin #fan #pwm #temp chip IDs man ID + * w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 + * 0x8860 0xa1 + * w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 + * w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 + * w83627uhg 8 2 2 3 0xa230 0xc1 0x5ca3 + * w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 + * w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3 + * nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3 + * nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3 + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -164,11 +163,13 @@ superio_exit(int ioreg) #define W83627EHF_REG_BANK 0x4E #define W83627EHF_REG_CONFIG 0x40 -/* Not currently used: +/* + * Not currently used: * REG_MAN_ID has the value 0x5ca3 for all supported chips. * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model. * REG_MAN_ID is at port 0x4f - * REG_CHIP_ID is at port 0x58 */ + * REG_CHIP_ID is at port 0x58 + */ static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 }; static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c }; @@ -239,6 +240,8 @@ static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b }; static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c }; +static const u16 W83627EHF_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 }; + static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 }; static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 }; static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 }; @@ -393,8 +396,10 @@ div_from_reg(u8 reg) return 1 << reg; } -/* Some of the voltage inputs have internal scaling, the tables below - * contain 8 (the ADC LSB in mV) * scaling factor * 100 */ +/* + * Some of the voltage inputs have internal scaling, the tables below + * contain 8 (the ADC LSB in mV) * scaling factor * 100 + */ static const u16 scale_in_common[10] = { 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800 }; @@ -462,6 +467,7 @@ struct w83627ehf_data { u8 has_fan_min; /* some fans don't have min register */ bool has_fan_div; u8 temp_type[3]; + s8 temp_offset[3]; s16 temp[9]; s16 temp_max[9]; s16 temp_max_hyst[9]; @@ -470,12 +476,13 @@ struct w83627ehf_data { u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ u8 pwm_enable[4]; /* 1->manual - 2->thermal cruise mode (also called SmartFan I) - 3->fan speed cruise mode - 4->variable thermal cruise (also called - SmartFan III) - 5->enhanced variable thermal cruise (also called - SmartFan IV) */ + * 2->thermal cruise mode (also called SmartFan I) + * 3->fan speed cruise mode + * 4->variable thermal cruise (also called + * SmartFan III) + * 5->enhanced variable thermal cruise (also called + * SmartFan IV) + */ u8 pwm_enable_orig[4]; /* original value of pwm_enable */ u8 pwm_num; /* number of pwm */ u8 pwm[4]; @@ -492,6 +499,7 @@ struct w83627ehf_data { u8 vrm; u16 have_temp; + u16 have_temp_offset; u8 in6_skip:1; u8 temp3_val_only:1; }; @@ -816,9 +824,11 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) data->fan_min[i] = w83627ehf_read_value(data, data->REG_FAN_MIN[i]); - /* If we failed to measure the fan speed and clock - divider can be increased, let's try that for next - time */ + /* + * If we failed to measure the fan speed and clock + * divider can be increased, let's try that for next + * time + */ if (data->has_fan_div && (reg >= 0xff || (sio_data->kind == nct6775 && reg == 0x00)) @@ -887,6 +897,10 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) data->temp_max_hyst[i] = w83627ehf_read_temp(data, data->reg_temp_hyst[i]); + if (data->have_temp_offset & (1 << i)) + data->temp_offset[i] + = w83627ehf_read_value(data, + W83627EHF_REG_TEMP_OFFSET[i]); } data->alarms = w83627ehf_read_value(data, @@ -1081,25 +1095,31 @@ store_fan_min(struct device *dev, struct device_attribute *attr, new_div = data->fan_div[nr]; /* No change */ dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1); } else if ((reg = 1350000U / val) >= 128 * 255) { - /* Speed below this value cannot possibly be represented, - even with the highest divider (128) */ + /* + * Speed below this value cannot possibly be represented, + * even with the highest divider (128) + */ data->fan_min[nr] = 254; new_div = 7; /* 128 == (1 << 7) */ dev_warn(dev, "fan%u low limit %lu below minimum %u, set to " "minimum\n", nr + 1, val, data->fan_from_reg_min(254, 7)); } else if (!reg) { - /* Speed above this value cannot possibly be represented, - even with the lowest divider (1) */ + /* + * Speed above this value cannot possibly be represented, + * even with the lowest divider (1) + */ data->fan_min[nr] = 1; new_div = 0; /* 1 == (1 << 0) */ dev_warn(dev, "fan%u low limit %lu above maximum %u, set to " "maximum\n", nr + 1, val, data->fan_from_reg_min(1, 0)); } else { - /* Automatically pick the best divider, i.e. the one such - that the min limit will correspond to a register value - in the 96..192 range */ + /* + * Automatically pick the best divider, i.e. the one such + * that the min limit will correspond to a register value + * in the 96..192 range + */ new_div = 0; while (reg > 192 && new_div < 7) { reg >>= 1; @@ -1108,8 +1128,10 @@ store_fan_min(struct device *dev, struct device_attribute *attr, data->fan_min[nr] = reg; } - /* Write both the fan clock divider (if it changed) and the new - fan min (unconditionally) */ + /* + * Write both the fan clock divider (if it changed) and the new + * fan min (unconditionally) + */ if (new_div != data->fan_div[nr]) { dev_dbg(dev, "fan%u clock divider changed from %u to %u\n", nr + 1, div_from_reg(data->fan_div[nr]), @@ -1212,6 +1234,39 @@ store_temp_reg(reg_temp_over, temp_max); store_temp_reg(reg_temp_hyst, temp_max_hyst); static ssize_t +show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct w83627ehf_data *data = w83627ehf_update_device(dev); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + + return sprintf(buf, "%d\n", + data->temp_offset[sensor_attr->index] * 1000); +} + +static ssize_t +store_temp_offset(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w83627ehf_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), -128, 127); + + mutex_lock(&data->update_lock); + data->temp_offset[nr] = val; + w83627ehf_write_value(data, W83627EHF_REG_TEMP_OFFSET[nr], val); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627ehf_data *data = w83627ehf_update_device(dev); @@ -1298,6 +1353,15 @@ static struct sensor_device_attribute sda_temp_type[] = { SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), }; +static struct sensor_device_attribute sda_temp_offset[] = { + SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset, + store_temp_offset, 0), + SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset, + store_temp_offset, 1), + SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset, + store_temp_offset, 2), +}; + #define show_pwm_reg(reg) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -1736,8 +1800,10 @@ static struct sensor_device_attribute_2 sda_caseopen[] = { static void w83627ehf_device_remove_files(struct device *dev) { - /* some entries in the following arrays may not have been used in - * device_create_file(), but device_remove_file() will ignore them */ + /* + * some entries in the following arrays may not have been used in + * device_create_file(), but device_remove_file() will ignore them + */ int i; struct w83627ehf_data *data = dev_get_drvdata(dev); @@ -1788,6 +1854,7 @@ static void w83627ehf_device_remove_files(struct device *dev) continue; device_remove_file(dev, &sda_temp_alarm[i].dev_attr); device_remove_file(dev, &sda_temp_type[i].dev_attr); + device_remove_file(dev, &sda_temp_offset[i].dev_attr); } device_remove_file(dev, &sda_caseopen[0].dev_attr); @@ -2110,6 +2177,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) } else { data->temp_label = nct6775_temp_label; } + data->have_temp_offset = data->have_temp & 0x07; + for (i = 0; i < 3; i++) { + if (data->temp_src[i] > 3) + data->have_temp_offset &= ~(1 << i); + } } else if (sio_data->kind == w83667hg_b) { u8 reg; @@ -2152,6 +2224,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) data->in6_skip = 1; data->temp_label = w83667hg_b_temp_label; + data->have_temp_offset = data->have_temp & 0x07; + for (i = 0; i < 3; i++) { + if (data->temp_src[i] > 2) + data->have_temp_offset &= ~(1 << i); + } } else if (sio_data->kind == w83627uhg) { u8 reg; @@ -2188,6 +2265,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) data->in6_skip = 1; /* No VIN3 */ data->temp_label = w83667hg_b_temp_label; + data->have_temp_offset = data->have_temp & 0x03; + for (i = 0; i < 3; i++) { + if (data->temp_src[i] > 1) + data->have_temp_offset &= ~(1 << i); + } } else { w83627ehf_set_temp_reg_ehf(data, 3); @@ -2207,6 +2289,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) else data->in6_skip = 1; } + data->have_temp_offset = data->have_temp & 0x07; } if (sio_data->kind == nct6775) { @@ -2279,9 +2362,11 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) /* Read VID value */ if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b || sio_data->kind == nct6775 || sio_data->kind == nct6776) { - /* W83667HG has different pins for VID input and output, so - we can get the VID input values directly at logical device D - 0xe3. */ + /* + * W83667HG has different pins for VID input and output, so + * we can get the VID input values directly at logical device D + * 0xe3. + */ superio_select(sio_data->sioreg, W83667HG_LD_VID); data->vid = superio_inb(sio_data->sioreg, 0xe3); err = device_create_file(dev, &dev_attr_cpu0_vid); @@ -2290,11 +2375,13 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) } else if (sio_data->kind != w83627uhg) { superio_select(sio_data->sioreg, W83627EHF_LD_HWM); if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { - /* Set VID input sensibility if needed. In theory the - BIOS should have set it, but in practice it's not - always the case. We only do it for the W83627EHF/EHG - because the W83627DHG is more complex in this - respect. */ + /* + * Set VID input sensibility if needed. In theory the + * BIOS should have set it, but in practice it's not + * always the case. We only do it for the W83627EHF/EHG + * because the W83627DHG is more complex in this + * respect. + */ if (sio_data->kind == w83627ehf) { en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10); @@ -2468,6 +2555,12 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sda_temp_type[i].dev_attr))) goto exit_remove; + if (data->have_temp_offset & (1 << i)) { + err = device_create_file(dev, + &sda_temp_offset[i].dev_attr); + if (err) + goto exit_remove; + } } err = device_create_file(dev, &sda_caseopen[0].dev_attr); @@ -2616,10 +2709,12 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, return 0; } -/* when Super-I/O functions move to a separate file, the Super-I/O +/* + * when Super-I/O functions move to a separate file, the Super-I/O * bus will manage the lifetime of the device and this module will only keep * track of the w83627ehf driver. But since we platform_device_alloc(), we - * must keep track of the device */ + * must keep track of the device + */ static struct platform_device *pdev; static int __init sensors_w83627ehf_init(void) @@ -2629,11 +2724,13 @@ static int __init sensors_w83627ehf_init(void) struct resource res; struct w83627ehf_sio_data sio_data; - /* initialize sio_data->kind and sio_data->sioreg. + /* + * initialize sio_data->kind and sio_data->sioreg. * * when Super-I/O functions move to a separate file, the Super-I/O * driver will probe 0x2e and 0x4e and auto-detect the presence of a - * w83627ehf hardware monitor, and call probe() */ + * w83627ehf hardware monitor, and call probe() + */ if (w83627ehf_find(0x2e, &address, &sio_data) && w83627ehf_find(0x4e, &address, &sio_data)) return -ENODEV; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 374118f2b9f9..5ce54a297249 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1,43 +1,43 @@ /* - w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, - Philip Edelbrock <phil@netroedge.com>, - and Mark Studebaker <mdsxyz123@yahoo.com> - Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org> - Copyright (c) 2007 Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, + * Philip Edelbrock <phil@netroedge.com>, + * and Mark Studebaker <mdsxyz123@yahoo.com> + * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org> + * Copyright (c) 2007 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) - w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) - w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) - - For other winbond chips, and for i2c support in the above chips, - use w83781d.c. - - Note: automatic ("cruise") fan control for 697, 637 & 627thf not - supported yet. -*/ + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) + * w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) + * w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) + * w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) + * w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + * + * For other winbond chips, and for i2c support in the above chips, + * use w83781d.c. + * + * Note: automatic ("cruise") fan control for 697, 637 & 627thf not + * supported yet. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -80,7 +80,7 @@ module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); /* modified from kernel/include/traps.c */ -#define DEV 0x07 /* Register: Logical device select */ +#define DEV 0x07 /* Register: Logical device select */ /* logical device numbers for superio_select (below) */ #define W83627HF_LD_FDC 0x00 @@ -99,7 +99,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); #define W83627HF_LD_ACPI 0x0a #define W83627HF_LD_HWM 0x0b -#define DEVID 0x20 /* Register: Device ID */ +#define DEVID 0x20 /* Register: Device ID */ #define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ #define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ @@ -248,10 +248,12 @@ static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; #define W83781D_DEFAULT_BETA 3435 -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ +/* + * Conversions. Limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + * Fixing this is just not worth it. + */ #define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) #define IN_FROM_REG(val) ((val) * 16) @@ -267,8 +269,10 @@ static inline u8 FAN_TO_REG(long rpm, int div) #define TEMP_MIN (-128000) #define TEMP_MAX ( 127000) -/* TEMP: 0.001C/bit (-128C to +127C) - REG: 1C/bit, two's complement */ +/* + * TEMP: 0.001C/bit (-128C to +127C) + * REG: 1C/bit, two's complement + */ static u8 TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); @@ -294,8 +298,10 @@ static inline unsigned long pwm_freq_from_reg_627hf(u8 reg) static inline u8 pwm_freq_to_reg_627hf(unsigned long val) { u8 i; - /* Only 5 dividers (1 2 4 8 16) - Search for the nearest available frequency */ + /* + * Only 5 dividers (1 2 4 8 16) + * Search for the nearest available frequency + */ for (i = 0; i < 4; i++) { if (val > (((W83627HF_BASE_PWM_FREQ >> i) + (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2)) @@ -313,7 +319,7 @@ static inline unsigned long pwm_freq_from_reg(u8 reg) /* This should not happen but anyway... */ if (reg == 0) reg++; - return (clock / (reg << 8)); + return clock / (reg << 8); } static inline u8 pwm_freq_to_reg(unsigned long val) { @@ -321,11 +327,11 @@ static inline u8 pwm_freq_to_reg(unsigned long val) if (val >= 93750) /* The highest we can do */ return 0x01; if (val >= 720) /* Use 24 MHz clock */ - return (24000000UL / (val << 8)); + return 24000000UL / (val << 8); if (val < 6) /* The lowest we can do */ return 0xFF; else /* Use 180 kHz clock */ - return (0x80 | (180000UL / (val << 8))); + return 0x80 | (180000UL / (val << 8)); } #define BEEP_MASK_FROM_REG(val) ((val) & 0xff7fff) @@ -342,11 +348,13 @@ static inline u8 DIV_TO_REG(long val) break; val >>= 1; } - return ((u8) i); + return (u8)i; } -/* For each registered chip, we need to keep some data in memory. - The structure is dynamically allocated. */ +/* + * For each registered chip, we need to keep some data in memory. + * The structure is dynamically allocated. + */ struct w83627hf_data { unsigned short addr; const char *name; @@ -372,11 +380,13 @@ struct w83627hf_data { u32 beep_mask; /* Register encoding, combined */ u8 pwm[3]; /* Register value */ u8 pwm_enable[3]; /* 1 = manual - 2 = thermal cruise (also called SmartFan I) - 3 = fan speed cruise */ + * 2 = thermal cruise (also called SmartFan I) + * 3 = fan speed cruise + */ u8 pwm_freq[3]; /* Register value */ u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; - 4 = thermistor */ + * 4 = thermistor + */ u8 vrm; u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ }; @@ -427,7 +437,12 @@ store_in_min(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_min[nr] = IN_TO_REG(val); @@ -441,7 +456,12 @@ store_in_max(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->in_max[nr] = IN_TO_REG(val); @@ -506,9 +526,12 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a const char *buf, size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -533,9 +556,12 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a const char *buf, size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -584,7 +610,12 @@ store_fan_min(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); @@ -645,9 +676,15 @@ store_temp_max(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); - u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); + u16 tmp; + long val; + int err; + err = kstrtol(buf, 10, &val); + if (err) + return err; + + tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); mutex_lock(&data->update_lock); data->temp_max[nr] = tmp; w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp); @@ -661,9 +698,15 @@ store_temp_max_hyst(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - long val = simple_strtol(buf, NULL, 10); - u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); + u16 tmp; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val); mutex_lock(&data->update_lock); data->temp_max_hyst[nr] = tmp; w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp); @@ -701,9 +744,12 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; data->vrm = val; return count; @@ -755,8 +801,11 @@ store_beep_mask(struct device *dev, struct device_attribute *attr, { struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -791,10 +840,14 @@ store_beep(struct device *dev, struct device_attribute *attr, { struct w83627hf_data *data = dev_get_drvdata(dev); int bitnr = to_sensor_dev_attr(attr)->index; - unsigned long bit; u8 reg; + unsigned long bit; + int err; + + err = kstrtoul(buf, 10, &bit); + if (err) + return err; - bit = simple_strtoul(buf, NULL, 10); if (bit & ~1) return -EINVAL; @@ -872,10 +925,12 @@ show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) return sprintf(buf, "%ld\n", (long) DIV_FROM_REG(data->fan_div[nr])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) @@ -884,7 +939,12 @@ store_fan_div(struct device *dev, struct device_attribute *devattr, struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long min; u8 reg; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -933,7 +993,12 @@ store_pwm(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -974,10 +1039,15 @@ store_pwm_enable(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - unsigned long val = simple_strtoul(buf, NULL, 10); u8 reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - if (!val || (val > 3)) /* modes 1, 2 and 3 are supported */ + if (!val || val > 3) /* modes 1, 2 and 3 are supported */ return -EINVAL; mutex_lock(&data->update_lock); data->pwm_enable[nr] = val; @@ -1016,9 +1086,12 @@ store_pwm_freq(struct device *dev, struct device_attribute *devattr, int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); static const u8 mask[]={0xF8, 0x8F}; - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -1060,9 +1133,13 @@ store_temp_type(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val, tmp; + unsigned long val; + u32 tmp; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -1290,7 +1367,8 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) goto ERROR0; } - if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto ERROR1; } @@ -1311,7 +1389,8 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) w83627hf_update_fan_div(data); /* Register common device attributes */ - if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group))) + err = sysfs_create_group(&dev->kobj, &w83627hf_group); + if (err) goto ERROR3; /* Register chip-specific device attributes */ @@ -1387,10 +1466,11 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) } if (data->type == w83627thf || data->type == w83637hf - || data->type == w83687thf) - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm3.dev_attr))) + || data->type == w83687thf) { + err = device_create_file(dev, &sensor_dev_attr_pwm3.dev_attr); + if (err) goto ERROR4; + } if (data->type == w83637hf || data->type == w83687thf) if ((err = device_create_file(dev, @@ -1409,10 +1489,12 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) goto ERROR4; if (data->type == w83627thf || data->type == w83637hf - || data->type == w83687thf) - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm3_enable.dev_attr))) + || data->type == w83687thf) { + err = device_create_file(dev, + &sensor_dev_attr_pwm3_enable.dev_attr); + if (err) goto ERROR4; + } data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { @@ -1510,8 +1592,10 @@ static int __devinit w83627thf_read_gpio5(struct platform_device *pdev) goto exit; } - /* Make sure the pins are configured for input - There must be at least five (VRM 9), and possibly 6 (VRM 10) */ + /* + * Make sure the pins are configured for input + * There must be at least five (VRM 9), and possibly 6 (VRM 10) + */ sel = superio_inb(sio_data, W83627THF_GPIO5_IOSR) & 0x3f; if ((sel & 0x1f) != 0x1f) { dev_dbg(&pdev->dev, "GPIO5 not configured for VID " diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 17a8fa2d9ae9..b03d54a799e3 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1,37 +1,37 @@ /* - w83781d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>, - Philip Edelbrock <phil@netroedge.com>, - and Mark Studebaker <mdsxyz123@yahoo.com> - Copyright (c) 2007 - 2008 Jean Delvare <khali@linux-fr.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * w83781d.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>, + * Philip Edelbrock <phil@netroedge.com>, + * and Mark Studebaker <mdsxyz123@yahoo.com> + * Copyright (c) 2007 - 2008 Jean Delvare <khali@linux-fr.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - as99127f 7 3 0 3 0x31 0x12c3 yes no - as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no - w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes - w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes - w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - -*/ + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * as99127f 7 3 0 3 0x31 0x12c3 yes no + * as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no + * w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes + * w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes + * w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no + * + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -145,8 +145,10 @@ static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F }; #define W83781D_REG_I2C_ADDR 0x48 #define W83781D_REG_I2C_SUBADDR 0x4A -/* The following are undocumented in the data sheets however we - received the information in an email from Winbond tech support */ +/* + * The following are undocumented in the data sheets however we + * received the information in an email from Winbond tech support + */ /* Sensor selection - not on 781d */ #define W83781D_REG_SCFG1 0x5D static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; @@ -182,9 +184,9 @@ FAN_FROM_REG(u8 val, int div) #define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128) #define TEMP_FROM_REG(val) ((val) * 1000) -#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ +#define BEEP_MASK_FROM_REG(val, type) ((type) == as99127f ? \ (~(val)) & 0x7fff : (val) & 0xff7fff) -#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ +#define BEEP_MASK_TO_REG(val, type) ((type) == as99127f ? \ (~(val)) & 0x7fff : (val) & 0xff7fff) #define DIV_FROM_REG(val) (1 << (val)) @@ -238,9 +240,11 @@ struct w83781d_data { u32 beep_mask; /* Register encoding, combined */ u8 pwm[4]; /* Register value */ u8 pwm2_enable; /* Boolean */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 4 = thermistor */ + u16 sens[3]; /* + * 782D/783S only. + * 1 = pentium diode; 2 = 3904 diode; + * 4 = thermistor + */ u8 vrm; }; @@ -254,7 +258,7 @@ static void w83781d_init_device(struct device *dev); /* following are the sysfs callback functions */ #define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \ char *buf) \ { \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ @@ -267,20 +271,21 @@ show_in_reg(in_min); show_in_reg(in_max); #define store_in_reg(REG, reg) \ -static ssize_t store_in_##reg (struct device *dev, struct device_attribute \ +static ssize_t store_in_##reg(struct device *dev, struct device_attribute \ *da, const char *buf, size_t count) \ { \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = dev_get_drvdata(dev); \ int nr = attr->index; \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ + unsigned long val; \ + int err = kstrtoul(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ - w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ - \ + w83781d_write_value(data, W83781D_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + \ mutex_unlock(&data->update_lock); \ return count; \ } @@ -306,12 +311,12 @@ sysfs_in_offsets(7); sysfs_in_offsets(8); #define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \ char *buf) \ { \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ - return sprintf(buf,"%ld\n", \ + return sprintf(buf, "%ld\n", \ FAN_FROM_REG(data->reg[attr->index], \ DIV_FROM_REG(data->fan_div[attr->index]))); \ } @@ -325,9 +330,12 @@ store_fan_min(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = dev_get_drvdata(dev); int nr = attr->index; - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = @@ -350,17 +358,17 @@ static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, show_fan_min, store_fan_min, 2); #define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *da, \ char *buf) \ { \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ int nr = attr->index; \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - return sprintf(buf,"%d\n", \ + return sprintf(buf, "%d\n", \ LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ } else { /* TEMP1 */ \ - return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ + return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->reg)); \ } \ } show_temp_reg(temp); @@ -368,16 +376,16 @@ show_temp_reg(temp_max); show_temp_reg(temp_max_hyst); #define store_temp_reg(REG, reg) \ -static ssize_t store_temp_##reg (struct device *dev, \ +static ssize_t store_temp_##reg(struct device *dev, \ struct device_attribute *da, const char *buf, size_t count) \ { \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = dev_get_drvdata(dev); \ int nr = attr->index; \ long val; \ - \ - val = simple_strtol(buf, NULL, 10); \ - \ + int err = kstrtol(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ @@ -425,13 +433,17 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +store_vrm_reg(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct w83781d_data *data = dev_get_drvdata(dev); - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); - data->vrm = val; + err = kstrtoul(buf, 10, &val); + if (err) + return err; + data->vrm = SENSORS_LIMIT(val, 0, 255); return count; } @@ -480,7 +492,8 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0); -static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_beep_mask(struct device *dev, + struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", @@ -492,9 +505,12 @@ store_beep_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w83781d_data *data = dev_get_drvdata(dev); - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->beep_mask &= 0x8000; /* preserve beep enable */ @@ -529,10 +545,14 @@ store_beep(struct device *dev, struct device_attribute *attr, { struct w83781d_data *data = dev_get_drvdata(dev); int bitnr = to_sensor_dev_attr(attr)->index; - unsigned long bit; u8 reg; + unsigned long bit; + int err; + + err = kstrtoul(buf, 10, &bit); + if (err) + return err; - bit = simple_strtoul(buf, NULL, 10); if (bit & ~1) return -EINVAL; @@ -620,10 +640,12 @@ show_fan_div(struct device *dev, struct device_attribute *da, char *buf) (long) DIV_FROM_REG(data->fan_div[attr->index])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *da, const char *buf, size_t count) @@ -633,7 +655,12 @@ store_fan_div(struct device *dev, struct device_attribute *da, unsigned long min; int nr = attr->index; u8 reg; - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -643,10 +670,12 @@ store_fan_div(struct device *dev, struct device_attribute *da, data->fan_div[nr] = DIV_TO_REG(val, data->type); - reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) - & (nr==0 ? 0xcf : 0x3f)) - | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); - w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); + reg = (w83781d_read_value(data, nr == 2 ? + W83781D_REG_PIN : W83781D_REG_VID_FANDIV) + & (nr == 0 ? 0xcf : 0x3f)) + | ((data->fan_div[nr] & 0x03) << (nr == 0 ? 4 : 6)); + w83781d_write_value(data, nr == 2 ? + W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); /* w83781d and as99127f don't have extended divisor bits */ if (data->type != w83781d && data->type != as99127f) { @@ -693,9 +722,12 @@ store_pwm(struct device *dev, struct device_attribute *da, const char *buf, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = dev_get_drvdata(dev); int nr = attr->index; - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); @@ -709,9 +741,13 @@ store_pwm2_enable(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct w83781d_data *data = dev_get_drvdata(dev); - u32 val, reg; + unsigned long val; + u32 reg; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -761,9 +797,13 @@ store_sensor(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = dev_get_drvdata(dev); int nr = attr->index; - u32 val, tmp; + unsigned long val; + u32 tmp; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -813,7 +853,8 @@ static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_sensor, store_sensor, 2); -/* Assumes that adapter is of I2C, not ISA variety. +/* + * Assumes that adapter is of I2C, not ISA variety. * OTHERWISE DON'T CALL THIS */ static int @@ -911,7 +952,7 @@ ERROR_SC_1: &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \ &sensor_dev_attr_temp##X##_beep.dev_attr.attr -static struct attribute* w83781d_attributes[] = { +static struct attribute *w83781d_attributes[] = { IN_UNIT_ATTRS(0), IN_UNIT_ATTRS(2), IN_UNIT_ATTRS(3), @@ -934,23 +975,58 @@ static const struct attribute_group w83781d_group = { .attrs = w83781d_attributes, }; -static struct attribute *w83781d_attributes_opt[] = { +static struct attribute *w83781d_attributes_in1[] = { IN_UNIT_ATTRS(1), + NULL +}; +static const struct attribute_group w83781d_group_in1 = { + .attrs = w83781d_attributes_in1, +}; + +static struct attribute *w83781d_attributes_in78[] = { IN_UNIT_ATTRS(7), IN_UNIT_ATTRS(8), + NULL +}; +static const struct attribute_group w83781d_group_in78 = { + .attrs = w83781d_attributes_in78, +}; + +static struct attribute *w83781d_attributes_temp3[] = { TEMP_UNIT_ATTRS(3), + NULL +}; +static const struct attribute_group w83781d_group_temp3 = { + .attrs = w83781d_attributes_temp3, +}; + +static struct attribute *w83781d_attributes_pwm12[] = { &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, + &dev_attr_pwm2_enable.attr, + NULL +}; +static const struct attribute_group w83781d_group_pwm12 = { + .attrs = w83781d_attributes_pwm12, +}; + +static struct attribute *w83781d_attributes_pwm34[] = { &sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm4.dev_attr.attr, - &dev_attr_pwm2_enable.attr, + NULL +}; +static const struct attribute_group w83781d_group_pwm34 = { + .attrs = w83781d_attributes_pwm34, +}; + +static struct attribute *w83781d_attributes_other[] = { &sensor_dev_attr_temp1_type.dev_attr.attr, &sensor_dev_attr_temp2_type.dev_attr.attr, &sensor_dev_attr_temp3_type.dev_attr.attr, NULL }; -static const struct attribute_group w83781d_group_opt = { - .attrs = w83781d_attributes_opt, +static const struct attribute_group w83781d_group_other = { + .attrs = w83781d_attributes_other, }; /* No clean up is done on error, it's up to the caller */ @@ -959,56 +1035,23 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) { int err; - if ((err = sysfs_create_group(&dev->kobj, &w83781d_group))) + err = sysfs_create_group(&dev->kobj, &w83781d_group); + if (err) return err; if (kind != w83783s) { - if ((err = device_create_file(dev, - &sensor_dev_attr_in1_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in1_min.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in1_max.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in1_alarm.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in1_beep.dev_attr))) + err = sysfs_create_group(&dev->kobj, &w83781d_group_in1); + if (err) return err; } if (kind != as99127f && kind != w83781d && kind != w83783s) { - if ((err = device_create_file(dev, - &sensor_dev_attr_in7_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in7_min.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in7_max.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in7_alarm.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in7_beep.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in8_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in8_min.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in8_max.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in8_alarm.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_in8_beep.dev_attr))) + err = sysfs_create_group(&dev->kobj, &w83781d_group_in78); + if (err) return err; } if (kind != w83783s) { - if ((err = device_create_file(dev, - &sensor_dev_attr_temp3_input.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_temp3_max.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_temp3_max_hyst.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_temp3_alarm.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_temp3_beep.dev_attr))) + err = sysfs_create_group(&dev->kobj, &w83781d_group_temp3); + if (err) return err; if (kind != w83781d) { @@ -1021,30 +1064,29 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) } if (kind != w83781d && kind != as99127f) { - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm1.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_pwm2.dev_attr)) - || (err = device_create_file(dev, &dev_attr_pwm2_enable))) + err = sysfs_create_group(&dev->kobj, &w83781d_group_pwm12); + if (err) return err; } if (kind == w83782d && !is_isa) { - if ((err = device_create_file(dev, - &sensor_dev_attr_pwm3.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_pwm4.dev_attr))) + err = sysfs_create_group(&dev->kobj, &w83781d_group_pwm34); + if (err) return err; } if (kind != as99127f && kind != w83781d) { - if ((err = device_create_file(dev, - &sensor_dev_attr_temp1_type.dev_attr)) - || (err = device_create_file(dev, - &sensor_dev_attr_temp2_type.dev_attr))) + err = device_create_file(dev, + &sensor_dev_attr_temp1_type.dev_attr); + if (err) + return err; + err = device_create_file(dev, + &sensor_dev_attr_temp2_type.dev_attr); + if (err) return err; if (kind != w83783s) { - if ((err = device_create_file(dev, - &sensor_dev_attr_temp3_type.dev_attr))) + err = device_create_file(dev, + &sensor_dev_attr_temp3_type.dev_attr); + if (err) return err; } } @@ -1066,9 +1108,11 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - /* We block updates of the ISA device to minimize the risk of - concurrent access to the same W83781D chip through different - interfaces. */ + /* + * We block updates of the ISA device to minimize the risk of + * concurrent access to the same W83781D chip through different + * interfaces. + */ if (isa) mutex_lock(&isa->update_lock); @@ -1083,15 +1127,17 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info) /* Check for Winbond or Asus ID if in bank 0 */ if (!(val1 & 0x07) && ((!(val1 & 0x80) && val2 != 0xa3 && val2 != 0xc3) || - ( (val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) { + ((val1 & 0x80) && val2 != 0x5c && val2 != 0x12))) { dev_dbg(&adapter->dev, "Detection of w83781d chip failed at step 4\n"); goto err_nodev; } - /* If Winbond SMBus, check address at 0x48. - Asus doesn't support, except for as99127f rev.2 */ + /* + * If Winbond SMBus, check address at 0x48. + * Asus doesn't support, except for as99127f rev.2 + */ if ((!(val1 & 0x80) && val2 == 0xa3) || - ( (val1 & 0x80) && val2 == 0x5c)) { + ((val1 & 0x80) && val2 == 0x5c)) { if (i2c_smbus_read_byte_data(client, W83781D_REG_I2C_ADDR) != address) { dev_dbg(&adapter->dev, @@ -1149,6 +1195,17 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } +static void w83781d_remove_files(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &w83781d_group); + sysfs_remove_group(&dev->kobj, &w83781d_group_in1); + sysfs_remove_group(&dev->kobj, &w83781d_group_in78); + sysfs_remove_group(&dev->kobj, &w83781d_group_temp3); + sysfs_remove_group(&dev->kobj, &w83781d_group_pwm12); + sysfs_remove_group(&dev->kobj, &w83781d_group_pwm34); + sysfs_remove_group(&dev->kobj, &w83781d_group_other); +} + static int w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1191,9 +1248,7 @@ w83781d_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; ERROR4: - sysfs_remove_group(&dev->kobj, &w83781d_group); - sysfs_remove_group(&dev->kobj, &w83781d_group_opt); - + w83781d_remove_files(dev); if (data->lm75[0]) i2c_unregister_device(data->lm75[0]); if (data->lm75[1]) @@ -1211,9 +1266,7 @@ w83781d_remove(struct i2c_client *client) struct device *dev = &client->dev; hwmon_device_unregister(data->hwmon_dev); - - sysfs_remove_group(&dev->kobj, &w83781d_group); - sysfs_remove_group(&dev->kobj, &w83781d_group_opt); + w83781d_remove_files(dev); if (data->lm75[0]) i2c_unregister_device(data->lm75[0]); @@ -1310,35 +1363,47 @@ w83781d_init_device(struct device *dev) int type = data->type; u8 tmp; - if (reset && type != as99127f) { /* this resets registers we don't have - documentation for on the as99127f */ - /* Resetting the chip has been the default for a long time, - but it causes the BIOS initializations (fan clock dividers, - thermal sensor types...) to be lost, so it is now optional. - It might even go away if nobody reports it as being useful, - as I see very little reason why this would be needed at - all. */ + if (reset && type != as99127f) { /* + * this resets registers we don't have + * documentation for on the as99127f + */ + /* + * Resetting the chip has been the default for a long time, + * but it causes the BIOS initializations (fan clock dividers, + * thermal sensor types...) to be lost, so it is now optional. + * It might even go away if nobody reports it as being useful, + * as I see very little reason why this would be needed at + * all. + */ dev_info(dev, "If reset=1 solved a problem you were " "having, please report!\n"); /* save these registers */ i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG); p = w83781d_read_value(data, W83781D_REG_PWMCLK12); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ + /* + * Reset all except Watchdog values and last conversion values + * This sets fan-divs to 2, among others + */ w83781d_write_value(data, W83781D_REG_CONFIG, 0x80); - /* Restore the registers and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ + /* + * Restore the registers and disable power-on abnormal beep. + * This saves FAN 1/2/3 input/output values set by BIOS. + */ w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80); w83781d_write_value(data, W83781D_REG_PWMCLK12, p); - /* Disable master beep-enable (reset turns it on). - Individual beep_mask should be reset to off but for some reason - disabling this bit helps some people not get beeped */ + /* + * Disable master beep-enable (reset turns it on). + * Individual beep_mask should be reset to off but for some + * reason disabling this bit helps some people not get beeped + */ w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0); } - /* Disable power-on abnormal beep, as advised by the datasheet. - Already done if reset=1. */ + /* + * Disable power-on abnormal beep, as advised by the datasheet. + * Already done if reset=1. + */ if (init && !reset && type != as99127f) { i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG); w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80); @@ -1444,7 +1509,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) } /* Only PWM2 can be disabled */ data->pwm2_enable = (w83781d_read_value(data, - W83781D_REG_PWMCLK12) & 0x08) >> 3; + W83781D_REG_PWMCLK12) & 0x08) >> 3; } data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1)); @@ -1495,8 +1560,10 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) | (w83781d_read_value(data, W83782D_REG_ALARM2) << 8); } else { - /* No real-time status registers, fall back to - interrupt status registers */ + /* + * No real-time status registers, fall back to + * interrupt status registers + */ data->alarms = w83781d_read_value(data, W83781D_REG_ALARM1) | (w83781d_read_value(data, @@ -1550,8 +1617,10 @@ static struct platform_device *pdev; static unsigned short isa_address = 0x290; -/* I2C devices get this name attribute automatically, but for ISA devices - we must create it by ourselves. */ +/* + * I2C devices get this name attribute automatically, but for ISA devices + * we must create it by ourselves. + */ static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -1581,8 +1650,10 @@ static int w83781d_alias_detect(struct i2c_client *client, u8 chipid) if (w83781d_read_value(isa, W83781D_REG_WCHIPID) != chipid) return 0; /* Chip type doesn't match */ - /* We compare all the limit registers, the config register and the - * interrupt mask registers */ + /* + * We compare all the limit registers, the config register and the + * interrupt mask registers + */ for (i = 0x2b; i <= 0x3d; i++) { if (w83781d_read_value(isa, i) != i2c_smbus_read_byte_data(client, i)) @@ -1663,12 +1734,14 @@ w83781d_write_value_isa(struct w83781d_data *data, u16 reg, u16 value) } } -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ +/* + * The SMBus locks itself, usually, but nothing may access the Winbond between + * bank switches. ISA access must always be locked explicitly! + * We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, + * would slow down the W83781D access and should not be necessary. + * There are some ugly typecasts here, but the good news is - they should + * nowhere else be necessary! + */ static int w83781d_read_value(struct w83781d_data *data, u16 reg) { @@ -1754,8 +1827,7 @@ w83781d_isa_probe(struct platform_device *pdev) return 0; exit_remove_files: - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); + w83781d_remove_files(&pdev->dev); device_remove_file(&pdev->dev, &dev_attr_name); kfree(data); exit_release_region: @@ -1770,8 +1842,7 @@ w83781d_isa_remove(struct platform_device *pdev) struct w83781d_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); - sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); + w83781d_remove_files(&pdev->dev); device_remove_file(&pdev->dev, &dev_attr_name); release_region(data->isa_addr + W83781D_ADDR_REG_OFFSET, 2); kfree(data); @@ -1795,9 +1866,11 @@ w83781d_isa_found(unsigned short address) int val, save, found = 0; int port; - /* Some boards declare base+0 to base+7 as a PNP device, some base+4 + /* + * Some boards declare base+0 to base+7 as a PNP device, some base+4 * to base+7 and some base+5 to base+6. So we better request each port - * individually for the probing phase. */ + * individually for the probing phase. + */ for (port = address; port < address + W83781D_EXTENT; port++) { if (!request_region(port, 1, "w83781d")) { pr_debug("Failed to request port 0x%x\n", port); @@ -1806,8 +1879,10 @@ w83781d_isa_found(unsigned short address) } #define REALLY_SLOW_IO - /* We need the timeouts for at least some W83781D-like - chips. But only if we read 'undefined' registers. */ + /* + * We need the timeouts for at least some W83781D-like + * chips. But only if we read 'undefined' registers. + */ val = inb_p(address + 1); if (inb_p(address + 2) != val || inb_p(address + 3) != val @@ -1817,8 +1892,10 @@ w83781d_isa_found(unsigned short address) } #undef REALLY_SLOW_IO - /* We should be able to change the 7 LSB of the address port. The - MSB (busy flag) should be clear initially, set after the write. */ + /* + * We should be able to change the 7 LSB of the address port. The + * MSB (busy flag) should be clear initially, set after the write. + */ save = inb_p(address + W83781D_ADDR_REG_OFFSET); if (save & 0x80) { pr_debug("Detection failed at step %d\n", 2); @@ -2004,8 +2081,10 @@ sensors_w83781d_init(void) { int res; - /* We register the ISA device first, so that we can skip the - * registration of an I2C interface to the same device. */ + /* + * We register the ISA device first, so that we can skip the + * registration of an I2C interface to the same device. + */ res = w83781d_isa_register(); if (res) goto exit; diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 35aa5149307a..2f446f92acf2 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1,36 +1,36 @@ /* - w83791d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * w83791d.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * + * Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83791d 10 5 5 3 0x71 0x5ca3 yes no - - The w83791d chip appears to be part way between the 83781d and the - 83792d. Thus, this file is derived from both the w83792d.c and - w83781d.c files. - - The w83791g chip is the same as the w83791d but lead-free. -*/ + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * w83791d 10 5 5 3 0x71 0x5ca3 yes no + * + * The w83791d chip appears to be part way between the 83781d and the + * 83792d. Thus, this file is derived from both the w83792d.c and + * w83781d.c files. + * + * The w83791g chip is the same as the w83791d but lead-free. + */ #include <linux/module.h> #include <linux/init.h> @@ -198,10 +198,12 @@ static const u8 W83791D_REG_BEEP_CTRL[3] = { #define W83791D_REG_VBAT 0x5D #define W83791D_REG_I2C_ADDR 0x48 -/* The SMBus locks itself. The Winbond W83791D has a bank select register - (index 0x4e), but the driver only accesses registers in bank 0. Since - we don't switch banks, we don't need any special code to handle - locking access between bank switches */ +/* + * The SMBus locks itself. The Winbond W83791D has a bank select register + * (index 0x4e), but the driver only accesses registers in bank 0. Since + * we don't switch banks, we don't need any special code to handle + * locking access between bank switches + */ static inline int w83791d_read(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -212,9 +214,11 @@ static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value) return i2c_smbus_write_byte_data(client, reg, value); } -/* The analog voltage inputs have 16mV LSB. Since the sysfs output is - in mV as would be measured on the chip input pin, need to just - multiply/divide by 16 to translate from/to register values. */ +/* + * The analog voltage inputs have 16mV LSB. Since the sysfs output is + * in mV as would be measured on the chip input pin, need to just + * multiply/divide by 16 to translate from/to register values. + */ #define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255)) #define IN_FROM_REG(val) ((val) * 16) @@ -226,7 +230,7 @@ static u8 fan_to_reg(long rpm, int div) return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ +#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ ((val) == 255 ? 0 : \ 1350000 / ((val) * (div)))) @@ -237,10 +241,12 @@ static u8 fan_to_reg(long rpm, int div) (val) < 0 ? ((val) - 500) / 1000 : \ ((val) + 500) / 1000) -/* for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius - Assumes the top 8 bits are the integral amount and the bottom 8 bits - are the fractional amount. Since we only have 0.5 degree resolution, - the bottom 7 bits will always be zero */ +/* + * for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius + * Assumes the top 8 bits are the integral amount and the bottom 8 bits + * are the fractional amount. Since we only have 0.5 degree resolution, + * the bottom 7 bits will always be zero + */ #define TEMP23_FROM_REG(val) ((val) / 128 * 500) #define TEMP23_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ (val) >= 127500 ? 0x7F80 : \ @@ -300,17 +306,19 @@ struct w83791d_data { s8 temp1[3]; /* current, over, thyst */ s16 temp_add[2][3]; /* fixed point value. Top 8 bits are the - integral part, bottom 8 bits are the - fractional part. We only use the top - 9 bits as the resolution is only - to the 0.5 degree C... - two sensors with three values - (cur, over, hyst) */ + * integral part, bottom 8 bits are the + * fractional part. We only use the top + * 9 bits as the resolution is only + * to the 0.5 degree C... + * two sensors with three values + * (cur, over, hyst) + */ /* PWMs */ u8 pwm[5]; /* pwm duty cycle */ u8 pwm_enable[3]; /* pwm enable status for fan 1-3 - (fan 4-5 only support manual mode) */ + * (fan 4-5 only support manual mode) + */ u8 temp_target[3]; /* pwm 1-3 target temperature */ u8 temp_tolerance[3]; /* pwm 1-3 temperature tolerance */ @@ -366,7 +374,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ to_sensor_dev_attr(attr); \ struct w83791d_data *data = w83791d_update_device(dev); \ int nr = sensor_attr->index; \ - return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ } show_in_reg(in); @@ -382,9 +390,11 @@ static ssize_t store_in_##reg(struct device *dev, \ to_sensor_dev_attr(attr); \ struct i2c_client *client = to_i2c_client(dev); \ struct w83791d_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ int nr = sensor_attr->index; \ - \ + unsigned long val; \ + int err = kstrtoul(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ w83791d_write(client, W83791D_REG_IN_##REG[nr], data->in_##reg[nr]); \ @@ -455,7 +465,14 @@ static ssize_t store_beep(struct device *dev, struct device_attribute *attr, struct w83791d_data *data = i2c_get_clientdata(client); int bitnr = sensor_attr->index; int bytenr = bitnr / 8; - long val = simple_strtol(buf, NULL, 10) ? 1 : 0; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + val = val ? 1 : 0; mutex_lock(&data->update_lock); @@ -485,8 +502,10 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); } -/* Note: The bitmask for the beep enable/disable is different than - the bitmask for the alarm. */ +/* + * Note: The bitmask for the beep enable/disable is different than + * the bitmask for the alarm. + */ static struct sensor_device_attribute sda_in_beep[] = { SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0), SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13), @@ -521,7 +540,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ to_sensor_dev_attr(attr); \ struct w83791d_data *data = w83791d_update_device(dev); \ int nr = sensor_attr->index; \ - return sprintf(buf,"%d\n", \ + return sprintf(buf, "%d\n", \ FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } @@ -534,8 +553,13 @@ static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); int nr = sensor_attr->index; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan_min[nr] = fan_to_reg(val, DIV_FROM_REG(data->fan_div[nr])); @@ -554,10 +578,12 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -572,12 +598,18 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, int indx = 0; u8 keep_mask = 0; u8 new_shift = 0; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; /* Save fan_min */ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); mutex_lock(&data->update_lock); - data->fan_div[nr] = div_to_reg(nr, simple_strtoul(buf, NULL, 10)); + data->fan_div[nr] = div_to_reg(nr, val); switch (nr) { case 0: @@ -918,8 +950,13 @@ static ssize_t store_temp1(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); int nr = attr->index; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->temp1[nr] = TEMP1_TO_REG(val); @@ -946,10 +983,15 @@ static ssize_t store_temp23(struct device *dev, struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; int nr = attr->nr; int index = attr->index; + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); data->temp_add[nr][index] = TEMP23_TO_REG(val); w83791d_write(client, W83791D_REG_TEMP_ADD[nr][index * 2], @@ -985,8 +1027,10 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { show_temp23, store_temp23, 1, 2), }; -/* Note: The bitmask for the beep enable/disable is different than - the bitmask for the alarm. */ +/* + * Note: The bitmask for the beep enable/disable is different than + * the bitmask for the alarm. + */ static struct sensor_device_attribute sda_temp_beep[] = { SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4), SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5), @@ -1035,13 +1079,20 @@ static ssize_t store_beep_mask(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); int i; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - /* The beep_enable state overrides any enabling request from - the masks */ + /* + * The beep_enable state overrides any enabling request from + * the masks + */ data->beep_mask = BEEP_MASK_TO_REG(val) & ~GLOBAL_BEEP_ENABLE_MASK; data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT); @@ -1063,7 +1114,12 @@ static ssize_t store_beep_enable(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); @@ -1073,8 +1129,10 @@ static ssize_t store_beep_enable(struct device *dev, data->beep_mask &= ~GLOBAL_BEEP_ENABLE_MASK; data->beep_mask |= (data->beep_enable << GLOBAL_BEEP_ENABLE_SHIFT); - /* The global control is in the second beep control register - so only need to update that register */ + /* + * The global control is in the second beep control register + * so only need to update that register + */ val = (data->beep_mask >> 8) & 0xff; w83791d_write(client, W83791D_REG_BEEP_CTRL[1], val); @@ -1113,36 +1171,44 @@ static ssize_t store_vrm_reg(struct device *dev, const char *buf, size_t count) { struct w83791d_data *data = dev_get_drvdata(dev); + unsigned long val; + int err; + + /* + * No lock needed as vrm is internal to the driver + * (not read from a chip register) and so is not + * updated in w83791d_update_device() + */ - /* No lock needed as vrm is internal to the driver - (not read from a chip register) and so is not - updated in w83791d_update_device() */ - data->vrm = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; + data->vrm = val; return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); #define IN_UNIT_ATTRS(X) \ - &sda_in_input[X].dev_attr.attr, \ - &sda_in_min[X].dev_attr.attr, \ - &sda_in_max[X].dev_attr.attr, \ - &sda_in_beep[X].dev_attr.attr, \ + &sda_in_input[X].dev_attr.attr, \ + &sda_in_min[X].dev_attr.attr, \ + &sda_in_max[X].dev_attr.attr, \ + &sda_in_beep[X].dev_attr.attr, \ &sda_in_alarm[X].dev_attr.attr #define FAN_UNIT_ATTRS(X) \ - &sda_fan_input[X].dev_attr.attr, \ - &sda_fan_min[X].dev_attr.attr, \ - &sda_fan_div[X].dev_attr.attr, \ - &sda_fan_beep[X].dev_attr.attr, \ + &sda_fan_input[X].dev_attr.attr, \ + &sda_fan_min[X].dev_attr.attr, \ + &sda_fan_div[X].dev_attr.attr, \ + &sda_fan_beep[X].dev_attr.attr, \ &sda_fan_alarm[X].dev_attr.attr #define TEMP_UNIT_ATTRS(X) \ - &sda_temp_input[X].dev_attr.attr, \ - &sda_temp_max[X].dev_attr.attr, \ - &sda_temp_max_hyst[X].dev_attr.attr, \ - &sda_temp_beep[X].dev_attr.attr, \ + &sda_temp_input[X].dev_attr.attr, \ + &sda_temp_max[X].dev_attr.attr, \ + &sda_temp_max_hyst[X].dev_attr.attr, \ + &sda_temp_beep[X].dev_attr.attr, \ &sda_temp_alarm[X].dev_attr.attr static struct attribute *w83791d_attributes[] = { @@ -1186,9 +1252,11 @@ static const struct attribute_group w83791d_group = { .attrs = w83791d_attributes, }; -/* Separate group of attributes for fan/pwm 4-5. Their pins can also be - in use for GPIO in which case their sysfs-interface should not be made - available */ +/* + * Separate group of attributes for fan/pwm 4-5. Their pins can also be + * in use for GPIO in which case their sysfs-interface should not be made + * available + */ static struct attribute *w83791d_attributes_fanpwm45[] = { FAN_UNIT_ATTRS(3), FAN_UNIT_ATTRS(4), @@ -1228,9 +1296,8 @@ static int w83791d_detect_subclients(struct i2c_client *client) } val = w83791d_read(client, W83791D_REG_I2C_SUBADDR); - if (!(val & 0x08)) { + if (!(val & 0x08)) data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7)); - } if (!(val & 0x80)) { if ((data->lm75[0] != NULL) && ((val & 0x7) == ((val >> 4) & 0x7))) { @@ -1265,9 +1332,8 @@ static int w83791d_detect(struct i2c_client *client, int val1, val2; unsigned short address = client->addr; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - } if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) return -ENODEV; @@ -1277,12 +1343,14 @@ static int w83791d_detect(struct i2c_client *client, /* Check for Winbond ID if in bank 0 */ if (!(val1 & 0x07)) { if ((!(val1 & 0x80) && val2 != 0xa3) || - ( (val1 & 0x80) && val2 != 0x5c)) { + ((val1 & 0x80) && val2 != 0x5c)) { return -ENODEV; } } - /* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR - should match */ + /* + * If Winbond chip, address of chip and W83791D_REG_I2C_ADDR + * should match + */ if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) return -ENODEV; @@ -1332,14 +1400,16 @@ static int w83791d_probe(struct i2c_client *client, /* Initialize the chip */ w83791d_init_client(client); - /* If the fan_div is changed, make sure there is a rational - fan_min in place */ - for (i = 0; i < NUMBER_OF_FANIN; i++) { + /* + * If the fan_div is changed, make sure there is a rational + * fan_min in place + */ + for (i = 0; i < NUMBER_OF_FANIN; i++) data->fan_min[i] = w83791d_read(client, W83791D_REG_FAN_MIN[i]); - } /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group))) + err = sysfs_create_group(&client->dev.kobj, &w83791d_group); + if (err) goto error3; /* Check if pins of fan/pwm 4-5 are in use as GPIO */ @@ -1398,19 +1468,20 @@ static void w83791d_init_client(struct i2c_client *client) u8 tmp; u8 old_beep; - /* The difference between reset and init is that reset - does a hard reset of the chip via index 0x40, bit 7, - but init simply forces certain registers to have "sane" - values. The hope is that the BIOS has done the right - thing (which is why the default is reset=0, init=0), - but if not, reset is the hard hammer and init - is the soft mallet both of which are trying to whack - things into place... - NOTE: The data sheet makes a distinction between - "power on defaults" and "reset by MR". As far as I can tell, - the hard reset puts everything into a power-on state so I'm - not sure what "reset by MR" means or how it can happen. - */ + /* + * The difference between reset and init is that reset + * does a hard reset of the chip via index 0x40, bit 7, + * but init simply forces certain registers to have "sane" + * values. The hope is that the BIOS has done the right + * thing (which is why the default is reset=0, init=0), + * but if not, reset is the hard hammer and init + * is the soft mallet both of which are trying to whack + * things into place... + * NOTE: The data sheet makes a distinction between + * "power on defaults" and "reset by MR". As far as I can tell, + * the hard reset puts everything into a power-on state so I'm + * not sure what "reset by MR" means or how it can happen. + */ if (reset || init) { /* keep some BIOS settings when we... */ old_beep = w83791d_read(client, W83791D_REG_BEEP_CONFIG); @@ -1494,8 +1565,10 @@ static struct w83791d_data *w83791d_update_device(struct device *dev) data->fan_div[3] = reg_array_tmp[2] & 0x07; data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07; - /* The fan divisor for fans 0-2 get bit 2 from - bits 5-7 respectively of vbat register */ + /* + * The fan divisor for fans 0-2 get bit 2 from + * bits 5-7 respectively of vbat register + */ vbat_reg = w83791d_read(client, W83791D_REG_VBAT); for (i = 0; i < 3; i++) data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04; @@ -1601,12 +1674,13 @@ static void w83791d_print_debug(struct w83791d_data *data, struct device *dev) dev_dbg(dev, "fan_div[%d] is: 0x%02x\n", i, data->fan_div[i]); } - /* temperature math is signed, but only print out the - bits that matter */ + /* + * temperature math is signed, but only print out the + * bits that matter + */ dev_dbg(dev, "%d set of Temperatures: ===>\n", NUMBER_OF_TEMPIN); - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) dev_dbg(dev, "temp1[%d] is: 0x%02x\n", i, (u8) data->temp1[i]); - } for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { dev_dbg(dev, "temp_add[%d][%d] is: 0x%04x\n", i, j, @@ -1625,19 +1699,8 @@ static void w83791d_print_debug(struct w83791d_data *data, struct device *dev) } #endif -static int __init sensors_w83791d_init(void) -{ - return i2c_add_driver(&w83791d_driver); -} - -static void __exit sensors_w83791d_exit(void) -{ - i2c_del_driver(&w83791d_driver); -} +module_i2c_driver(w83791d_driver); MODULE_AUTHOR("Charles Spirakis <bezaur@gmail.com>"); MODULE_DESCRIPTION("W83791D driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_w83791d_init); -module_exit(sensors_w83791d_exit); diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index d3100eab6b2f..ffb5fdfecf0d 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1,39 +1,39 @@ /* - w83792d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2004, 2005 Winbond Electronics Corp. - Chunhao Huang <DZShen@Winbond.com.tw>, - Rudolf Marek <r.marek@assembler.cz> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Note: - 1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver. - 2. This driver is only for Winbond W83792D C version device, there - are also some motherboards with B version W83792D device. The - calculation method to in6-in7(measured value, limits) is a little - different between C and B version. C or B version can be identified - by CR[0x49h]. -*/ + * w83792d.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2004, 2005 Winbond Electronics Corp. + * Chunhao Huang <DZShen@Winbond.com.tw>, + * Rudolf Marek <r.marek@assembler.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: + * 1. This driver is only for 2.6 kernel, 2.4 kernel need a different driver. + * 2. This driver is only for Winbond W83792D C version device, there + * are also some motherboards with B version W83792D device. The + * calculation method to in6-in7(measured value, limits) is a little + * different between C and B version. C or B version can be identified + * by CR[0x49h]. + */ /* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83792d 9 7 7 3 0x7a 0x5ca3 yes no -*/ + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * w83792d 9 7 7 3 0x7a 0x5ca3 yes no + */ #include <linux/module.h> #include <linux/init.h> @@ -218,14 +218,16 @@ static const u8 W83792D_REG_LEVELS[3][4] = { #define W83792D_REG_VBAT 0x5D #define W83792D_REG_I2C_ADDR 0x48 -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \ - ((((nr)==6)||((nr)==7))?(val*6):(val*4))) -#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \ - ((((nr)==6)||((nr)==7))?(val/6):(val/4))) +/* + * Conversions. Rounding and limit checking is only done on the TO_REG + * variants. Note that you should be a bit careful with which arguments + * these macros are called: arguments may be evaluated more than once. + * Fixing this is just not worth it. + */ +#define IN_FROM_REG(nr, val) (((nr) <= 1) ? ((val) * 2) : \ + ((((nr) == 6) || ((nr) == 7)) ? ((val) * 6) : ((val) * 4))) +#define IN_TO_REG(nr, val) (((nr) <= 1) ? ((val) / 2) : \ + ((((nr) == 6) || ((nr) == 7)) ? ((val) / 6) : ((val) / 4))) static inline u8 FAN_TO_REG(long rpm, int div) @@ -236,7 +238,7 @@ FAN_TO_REG(long rpm, int div) return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ +#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ ((val) == 255 ? 0 : \ 1350000 / ((val) * (div)))) @@ -265,7 +267,7 @@ DIV_TO_REG(long val) break; val >>= 1; } - return ((u8) i); + return (u8)i; } struct w83792d_data { @@ -287,8 +289,10 @@ struct w83792d_data { u8 temp1[3]; /* current, over, thyst */ u8 temp_add[2][6]; /* Register value */ u8 fan_div[7]; /* Register encoding, shifted right */ - u8 pwm[7]; /* We only consider the first 3 set of pwm, - although 792 chip has 7 set of pwm. */ + u8 pwm[7]; /* + * We only consider the first 3 set of pwm, + * although 792 chip has 7 set of pwm. + */ u8 pwmenable[3]; u32 alarms; /* realtime status register encoding,combined */ u8 chassis; /* Chassis status */ @@ -333,12 +337,14 @@ static struct i2c_driver w83792d_driver = { static inline long in_count_from_reg(int nr, struct w83792d_data *data) { /* in7 and in8 do not have low bits, but the formula still works */ - return ((data->in[nr] << 2) | ((data->low_bits >> (2 * nr)) & 0x03)); + return (data->in[nr] << 2) | ((data->low_bits >> (2 * nr)) & 0x03); } -/* The SMBus locks itself. The Winbond W83792D chip has a bank register, - but the driver only accesses registers in bank 0, so we don't have - to switch banks and lock access between switches. */ +/* + * The SMBus locks itself. The Winbond W83792D chip has a bank register, + * but the driver only accesses registers in bank 0, so we don't have + * to switch banks and lock access between switches. + */ static inline int w83792d_read_value(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -357,37 +363,43 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct w83792d_data *data = w83792d_update_device(dev); - return sprintf(buf,"%ld\n", IN_FROM_REG(nr,(in_count_from_reg(nr, data)))); + return sprintf(buf, "%ld\n", + IN_FROM_REG(nr, in_count_from_reg(nr, data))); } #define show_in_reg(reg) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + struct sensor_device_attribute *sensor_attr \ + = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ struct w83792d_data *data = w83792d_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)(IN_FROM_REG(nr, (data->reg[nr])*4))); \ + return sprintf(buf, "%ld\n", \ + (long)(IN_FROM_REG(nr, data->reg[nr]) * 4)); \ } show_in_reg(in_min); show_in_reg(in_max); #define store_in_reg(REG, reg) \ -static ssize_t store_in_##reg (struct device *dev, \ +static ssize_t store_in_##reg(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + struct sensor_device_attribute *sensor_attr \ + = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct w83792d_data *data = i2c_get_clientdata(client); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ + unsigned long val; \ + int err = kstrtoul(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ - data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val)/4, 0, 255); \ - w83792d_write_value(client, W83792D_REG_IN_##REG[nr], data->in_##reg[nr]); \ + data->in_##reg[nr] = SENSORS_LIMIT(IN_TO_REG(nr, val) / 4, 0, 255); \ + w83792d_write_value(client, W83792D_REG_IN_##REG[nr], \ + data->in_##reg[nr]); \ mutex_unlock(&data->update_lock); \ \ return count; \ @@ -396,13 +408,14 @@ store_in_reg(MIN, min); store_in_reg(MAX, max); #define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + struct sensor_device_attribute *sensor_attr \ + = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index - 1; \ struct w83792d_data *data = w83792d_update_device(dev); \ - return sprintf(buf,"%d\n", \ + return sprintf(buf, "%d\n", \ FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } @@ -417,9 +430,13 @@ store_fan_min(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index - 1; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], @@ -439,10 +456,12 @@ show_fan_div(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr - 1])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -455,13 +474,19 @@ store_fan_div(struct device *dev, struct device_attribute *attr, /*u8 reg;*/ u8 fan_div_reg = 0; u8 tmp_fan_div; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; /* Save fan_min */ mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + data->fan_div[nr] = DIV_TO_REG(val); fan_div_reg = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]); fan_div_reg &= (nr & 0x01) ? 0x8f : 0xf8; @@ -496,9 +521,13 @@ static ssize_t store_temp1(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - s32 val; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; - val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp1[nr] = TEMP1_TO_REG(val); w83792d_write_value(client, W83792D_REG_TEMP1[nr], @@ -513,11 +542,12 @@ static ssize_t store_temp1(struct device *dev, struct device_attribute *attr, static ssize_t show_temp23(struct device *dev, struct device_attribute *attr, char *buf) { - struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); + struct sensor_device_attribute_2 *sensor_attr + = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83792d_data *data = w83792d_update_device(dev); - return sprintf(buf,"%ld\n", + return sprintf(buf, "%ld\n", (long)TEMP_ADD_FROM_REG(data->temp_add[nr][index], data->temp_add[nr][index+1])); } @@ -525,14 +555,19 @@ static ssize_t show_temp23(struct device *dev, struct device_attribute *attr, static ssize_t store_temp23(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); + struct sensor_device_attribute_2 *sensor_attr + = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - s32 val; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; - val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_add[nr][index] = TEMP_ADD_TO_REG_HIGH(val); data->temp_add[nr][index+1] = TEMP_ADD_TO_REG_LOW(val); @@ -604,7 +639,13 @@ store_pwm(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u8 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255) >> 4; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + val = SENSORS_LIMIT(val, 0, 255) >> 4; mutex_lock(&data->update_lock); val |= w83792d_read_value(client, W83792D_REG_PWM[nr]) & 0xf0; @@ -623,10 +664,14 @@ store_pwmenable(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index - 1; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; u8 fan_cfg_tmp, cfg1_tmp, cfg2_tmp, cfg3_tmp, cfg4_tmp; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); if (val < 1 || val > 3) return -EINVAL; @@ -645,7 +690,7 @@ store_pwmenable(struct device *dev, struct device_attribute *attr, cfg1_tmp = data->pwmenable[0]; cfg2_tmp = (data->pwmenable[1]) << 2; cfg3_tmp = (data->pwmenable[2]) << 4; - cfg4_tmp = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0; + cfg4_tmp = w83792d_read_value(client, W83792D_REG_FAN_CFG) & 0xc0; fan_cfg_tmp = ((cfg4_tmp | cfg3_tmp) | cfg2_tmp) | cfg1_tmp; w83792d_write_value(client, W83792D_REG_FAN_CFG, fan_cfg_tmp); mutex_unlock(&data->update_lock); @@ -671,10 +716,13 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); - if (val != 0 && val != 1) + err = kstrtoul(buf, 10, &val); + if (err) + return err; + if (val > 1) return -EINVAL; mutex_lock(&data->update_lock); @@ -721,16 +769,20 @@ store_chassis_clear_legacy(struct device *dev, struct device_attribute *attr, { struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; + unsigned long val; + int err; u8 temp1 = 0, temp2 = 0; dev_warn(dev, "Attribute %s is deprecated, use intrusion0_alarm instead\n", "chassis_clear"); - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); - data->chassis_clear = SENSORS_LIMIT(val, 0 ,1); + data->chassis_clear = SENSORS_LIMIT(val, 0, 1); temp1 = ((data->chassis_clear) << 7) & 0x80; temp2 = w83792d_read_value(client, W83792D_REG_CHASSIS_CLR) & 0x7f; @@ -780,14 +832,19 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index - 1; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; - u8 target_tmp=0, target_mask=0; + u8 target_tmp = 0, target_mask = 0; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); target_tmp = val; target_tmp = target_tmp & 0x7f; mutex_lock(&data->update_lock); - target_mask = w83792d_read_value(client, W83792D_REG_THERMAL[nr]) & 0x80; + target_mask = w83792d_read_value(client, + W83792D_REG_THERMAL[nr]) & 0x80; data->thermal_cruise[nr] = SENSORS_LIMIT(target_tmp, 0, 255); w83792d_write_value(client, W83792D_REG_THERMAL[nr], (data->thermal_cruise[nr]) | target_mask); @@ -815,19 +872,22 @@ store_tolerance(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->index - 1; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; u8 tol_tmp, tol_mask; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); tol_mask = w83792d_read_value(client, W83792D_REG_TOLERANCE[nr]) & ((nr == 1) ? 0x0f : 0xf0); tol_tmp = SENSORS_LIMIT(val, 0, 15); tol_tmp &= 0x0f; data->tolerance[nr] = tol_tmp; - if (nr == 1) { + if (nr == 1) tol_tmp <<= 4; - } w83792d_write_value(client, W83792D_REG_TOLERANCE[nr], tol_mask | tol_tmp); mutex_unlock(&data->update_lock); @@ -840,7 +900,8 @@ static ssize_t show_sf2_point(struct device *dev, struct device_attribute *attr, char *buf) { - struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); + struct sensor_device_attribute_2 *sensor_attr + = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83792d_data *data = w83792d_update_device(dev); @@ -851,15 +912,20 @@ static ssize_t store_sf2_point(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); + struct sensor_device_attribute_2 *sensor_attr + = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr - 1; int index = sensor_attr->index - 1; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; u8 mask_tmp = 0; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->sf2_points[index][nr] = SENSORS_LIMIT(val, 0, 127); mask_tmp = w83792d_read_value(client, @@ -875,7 +941,8 @@ static ssize_t show_sf2_level(struct device *dev, struct device_attribute *attr, char *buf) { - struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); + struct sensor_device_attribute_2 *sensor_attr + = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83792d_data *data = w83792d_update_device(dev); @@ -887,25 +954,30 @@ static ssize_t store_sf2_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); + struct sensor_device_attribute_2 *sensor_attr + = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index - 1; struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); - u32 val; - u8 mask_tmp=0, level_tmp=0; + u8 mask_tmp = 0, level_tmp = 0; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->sf2_levels[index][nr] = SENSORS_LIMIT((val * 15) / 100, 0, 15); mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[index][nr]) - & ((nr==3) ? 0xf0 : 0x0f); - if (nr==3) { + & ((nr == 3) ? 0xf0 : 0x0f); + if (nr == 3) level_tmp = data->sf2_levels[index][nr]; - } else { + else level_tmp = data->sf2_levels[index][nr] << 4; - } - w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], level_tmp | mask_tmp); + w83792d_write_value(client, W83792D_REG_LEVELS[index][nr], + level_tmp | mask_tmp); mutex_unlock(&data->update_lock); return count; @@ -939,9 +1011,8 @@ w83792d_detect_subclients(struct i2c_client *new_client) } val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR); - if (!(val & 0x08)) { + if (!(val & 0x08)) data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7)); - } if (!(val & 0x80)) { if ((data->lm75[0] != NULL) && ((val & 0x7) == ((val >> 4) & 0x7))) { @@ -1306,9 +1377,8 @@ w83792d_detect(struct i2c_client *client, struct i2c_board_info *info) int val1, val2; unsigned short address = client->addr; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - } if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) return -ENODEV; @@ -1318,11 +1388,13 @@ w83792d_detect(struct i2c_client *client, struct i2c_board_info *info) /* Check for Winbond ID if in bank 0 */ if (!(val1 & 0x07)) { /* is Bank0 */ if ((!(val1 & 0x80) && val2 != 0xa3) || - ( (val1 & 0x80) && val2 != 0x5c)) + ((val1 & 0x80) && val2 != 0x5c)) return -ENODEV; } - /* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR - should match */ + /* + * If Winbond chip, address of chip and W83792D_REG_I2C_ADDR + * should match + */ if (w83792d_read_value(client, W83792D_REG_I2C_ADDR) != address) return -ENODEV; @@ -1374,33 +1446,40 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* Register sysfs hooks */ - if ((err = sysfs_create_group(&dev->kobj, &w83792d_group))) + err = sysfs_create_group(&dev->kobj, &w83792d_group); + if (err) goto ERROR3; - /* Read GPIO enable register to check if pins for fan 4,5 are used as - GPIO */ + /* + * Read GPIO enable register to check if pins for fan 4,5 are used as + * GPIO + */ val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN); - if (!(val1 & 0x40)) - if ((err = sysfs_create_group(&dev->kobj, - &w83792d_group_fan[0]))) + if (!(val1 & 0x40)) { + err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[0]); + if (err) goto exit_remove_files; + } - if (!(val1 & 0x20)) - if ((err = sysfs_create_group(&dev->kobj, - &w83792d_group_fan[1]))) + if (!(val1 & 0x20)) { + err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[1]); + if (err) goto exit_remove_files; + } val1 = w83792d_read_value(client, W83792D_REG_PIN); - if (val1 & 0x40) - if ((err = sysfs_create_group(&dev->kobj, - &w83792d_group_fan[2]))) + if (val1 & 0x40) { + err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[2]); + if (err) goto exit_remove_files; + } - if (val1 & 0x04) - if ((err = sysfs_create_group(&dev->kobj, - &w83792d_group_fan[3]))) + if (val1 & 0x04) { + err = sysfs_create_group(&dev->kobj, &w83792d_group_fan[3]); + if (err) goto exit_remove_files; + } data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { @@ -1451,14 +1530,16 @@ w83792d_init_client(struct i2c_client *client) { u8 temp2_cfg, temp3_cfg, vid_in_b; - if (init) { + if (init) w83792d_write_value(client, W83792D_REG_CONFIG, 0x80); - } - /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0): - W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of - vin0/vin1 can be modified by user; - W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of - vin0/vin1 auto-updated, can NOT be modified by user. */ + + /* + * Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0): + * W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of + * vin0/vin1 can be modified by user; + * W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of + * vin0/vin1 auto-updated, can NOT be modified by user. + */ vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B); w83792d_write_value(client, W83792D_REG_VID_IN_B, vid_in_b & 0xbf); @@ -1527,7 +1608,7 @@ static struct w83792d_data *w83792d_update_device(struct device *dev) for (i = 0; i < 2; i++) { for (j = 0; j < 6; j++) { data->temp_add[i][j] = w83792d_read_value( - client,W83792D_REG_TEMP_ADD[i][j]); + client, W83792D_REG_TEMP_ADD[i][j]); } } @@ -1572,8 +1653,9 @@ static struct w83792d_data *w83792d_update_device(struct device *dev) /* Update Smart Fan II temperature points */ for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { - data->sf2_points[i][j] = w83792d_read_value( - client,W83792D_REG_POINTS[i][j]) & 0x7f; + data->sf2_points[i][j] + = w83792d_read_value(client, + W83792D_REG_POINTS[i][j]) & 0x7f; } } @@ -1605,10 +1687,10 @@ static struct w83792d_data *w83792d_update_device(struct device *dev) #ifdef DEBUG static void w83792d_print_debug(struct w83792d_data *data, struct device *dev) { - int i=0, j=0; + int i = 0, j = 0; dev_dbg(dev, "==========The following is the debug message...========\n"); dev_dbg(dev, "9 set of Voltages: =====>\n"); - for (i=0; i<9; i++) { + for (i = 0; i < 9; i++) { dev_dbg(dev, "vin[%d] is: 0x%x\n", i, data->in[i]); dev_dbg(dev, "vin[%d] max is: 0x%x\n", i, data->in_max[i]); dev_dbg(dev, "vin[%d] min is: 0x%x\n", i, data->in_min[i]); @@ -1616,47 +1698,32 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev) dev_dbg(dev, "Low Bit1 is: 0x%x\n", data->low_bits & 0xff); dev_dbg(dev, "Low Bit2 is: 0x%x\n", data->low_bits >> 8); dev_dbg(dev, "7 set of Fan Counts and Duty Cycles: =====>\n"); - for (i=0; i<7; i++) { + for (i = 0; i < 7; i++) { dev_dbg(dev, "fan[%d] is: 0x%x\n", i, data->fan[i]); dev_dbg(dev, "fan[%d] min is: 0x%x\n", i, data->fan_min[i]); dev_dbg(dev, "pwm[%d] is: 0x%x\n", i, data->pwm[i]); } dev_dbg(dev, "3 set of Temperatures: =====>\n"); - for (i=0; i<3; i++) { + for (i = 0; i < 3; i++) dev_dbg(dev, "temp1[%d] is: 0x%x\n", i, data->temp1[i]); - } - for (i=0; i<2; i++) { - for (j=0; j<6; j++) { + for (i = 0; i < 2; i++) { + for (j = 0; j < 6; j++) { dev_dbg(dev, "temp_add[%d][%d] is: 0x%x\n", i, j, data->temp_add[i][j]); } } - for (i=0; i<7; i++) { + for (i = 0; i < 7; i++) dev_dbg(dev, "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]); - } - dev_dbg(dev, "==========End of the debug message...==================\n"); + + dev_dbg(dev, "==========End of the debug message...================\n"); dev_dbg(dev, "\n"); } #endif -static int __init -sensors_w83792d_init(void) -{ - return i2c_add_driver(&w83792d_driver); -} - -static void __exit -sensors_w83792d_exit(void) -{ - i2c_del_driver(&w83792d_driver); -} +module_i2c_driver(w83792d_driver); MODULE_AUTHOR("Chunhao Huang @ Winbond <DZShen@Winbond.com.tw>"); MODULE_DESCRIPTION("W83792AD/D driver for linux-2.6"); MODULE_LICENSE("GPL"); - -module_init(sensors_w83792d_init); -module_exit(sensors_w83792d_exit); - diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 45ec7e7c3c27..834e49d1827b 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1,34 +1,34 @@ /* - w83793.c - Linux kernel driver for hardware monitoring - Copyright (C) 2006 Winbond Electronics Corp. - Yuan Mu - Rudolf Marek <r.marek@assembler.cz> - Copyright (C) 2009-2010 Sven Anders <anders@anduras.de>, ANDURAS AG. - Watchdog driver part - (Based partially on fschmd driver, - Copyright 2007-2008 by Hans de Goede) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation - version 2. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. -*/ + * w83793.c - Linux kernel driver for hardware monitoring + * Copyright (C) 2006 Winbond Electronics Corp. + * Yuan Mu + * Rudolf Marek <r.marek@assembler.cz> + * Copyright (C) 2009-2010 Sven Anders <anders@anduras.de>, ANDURAS AG. + * Watchdog driver part + * (Based partially on fschmd driver, + * Copyright 2007-2008 by Hans de Goede) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation - version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ /* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83793 10 12 8 6 0x7b 0x5ca3 yes no -*/ + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * w83793 10 12 8 6 0x7b 0x5ca3 yes no + */ #include <linux/module.h> #include <linux/init.h> @@ -78,9 +78,9 @@ MODULE_PARM_DESC(nowayout, __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* - Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved - as ID, Bank Select registers -*/ + * Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved + * as ID, Bank Select registers + */ #define W83793_REG_BANKSEL 0x00 #define W83793_REG_VENDORID 0x0d #define W83793_REG_CHIPID 0x0e @@ -110,8 +110,10 @@ static u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f }; #define TEMP_CRIT_HYST 2 #define TEMP_WARN 3 #define TEMP_WARN_HYST 4 -/* only crit and crit_hyst affect real-time alarm status - current crit crit_hyst warn warn_hyst */ +/* + * only crit and crit_hyst affect real-time alarm status + * current crit crit_hyst warn warn_hyst + */ static u16 W83793_REG_TEMP[][5] = { {0x1c, 0x78, 0x79, 0x7a, 0x7b}, {0x1d, 0x7c, 0x7d, 0x7e, 0x7f}, @@ -181,7 +183,7 @@ static inline unsigned long FAN_FROM_REG(u16 val) { if ((val >= 0xfff) || (val == 0)) return 0; - return (1350000UL / val); + return 1350000UL / val; } static inline u16 FAN_TO_REG(long rpm) @@ -193,7 +195,7 @@ static inline u16 FAN_TO_REG(long rpm) static inline unsigned long TIME_FROM_REG(u8 reg) { - return (reg * 100); + return reg * 100; } static inline u8 TIME_TO_REG(unsigned long val) @@ -203,7 +205,7 @@ static inline u8 TIME_TO_REG(unsigned long val) static inline long TEMP_FROM_REG(s8 reg) { - return (reg * 1000); + return reg * 1000; } static inline s8 TEMP_TO_REG(long val, s8 min, s8 max) @@ -218,7 +220,8 @@ struct w83793_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_nonvolatile; /* In jiffies, last time we update the - nonvolatile registers */ + * nonvolatile registers + */ u8 bank; u8 vrm; @@ -233,7 +236,8 @@ struct w83793_data { s8 temp[6][5]; /* current, crit, crit_hyst,warn, warn_hyst */ u8 temp_low_bits; /* Additional resolution TD1-TD4 */ u8 temp_mode[2]; /* byte 0: Temp D1-D4 mode each has 2 bits - byte 1: Temp R1,R2 mode, each has 1 bit */ + * byte 1: Temp R1,R2 mode, each has 1 bit + */ u8 temp_critical; /* If reached all fan will be at full speed */ u8 temp_fan_map[6]; /* Temp controls which pwm fan, bit field */ @@ -268,17 +272,21 @@ struct w83793_data { int watchdog_timeout; /* watchdog timeout in minutes */ }; -/* Somewhat ugly :( global data pointer list with all devices, so that - we can find our device data as when using misc_register. There is no - other method to get to one's device data from the open file-op and - for usage in the reboot notifier callback. */ +/* + * Somewhat ugly :( global data pointer list with all devices, so that + * we can find our device data as when using misc_register. There is no + * other method to get to one's device data from the open file-op and + * for usage in the reboot notifier callback. + */ static LIST_HEAD(watchdog_data_list); /* Note this lock not only protect list access, but also data.kref access */ static DEFINE_MUTEX(watchdog_data_mutex); -/* Release our data struct when we're detached from the i2c client *and* all - references to our watchdog device are released */ +/* + * Release our data struct when we're detached from the i2c client *and* all + * references to our watchdog device are released + */ static void w83793_release_resources(struct kref *ref) { struct w83793_data *data = container_of(ref, struct w83793_data, kref); @@ -337,7 +345,14 @@ store_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w83793_data *data = dev_get_drvdata(dev); - data->vrm = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + data->vrm = val; return count; } @@ -354,7 +369,7 @@ show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) int bit = sensor_attr->index & 0x07; u8 val; - if (ALARM_STATUS == nr) { + if (nr == ALARM_STATUS) { val = (data->alarms[index] >> (bit)) & 1; } else { /* BEEP_ENABLE */ val = (data->beeps[index] >> (bit)) & 1; @@ -374,10 +389,14 @@ store_beep(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index >> 3; int shift = sensor_attr->index & 0x07; u8 beep_bit = 1 << shift; - u8 val; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); - if (val != 0 && val != 1) + if (val > 1) return -EINVAL; mutex_lock(&data->update_lock); @@ -403,9 +422,14 @@ store_beep_enable(struct device *dev, struct device_attribute *attr, { struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); - u8 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - if (val != 0 && val != 1) + if (val > 1) return -EINVAL; mutex_lock(&data->update_lock); @@ -449,8 +473,12 @@ store_chassis_clear(struct device *dev, struct w83793_data *data = i2c_get_clientdata(client); unsigned long val; u8 reg; + int err; - if (kstrtoul(buf, 10, &val) || val != 0) + err = kstrtoul(buf, 10, &val); + if (err) + return err; + if (val) return -EINVAL; mutex_lock(&data->update_lock); @@ -473,11 +501,10 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf) struct w83793_data *data = w83793_update_device(dev); u16 val; - if (FAN_INPUT == nr) { + if (nr == FAN_INPUT) val = data->fan[index] & 0x0fff; - } else { + else val = data->fan_min[index] & 0x0fff; - } return sprintf(buf, "%lu\n", FAN_FROM_REG(val)); } @@ -491,7 +518,13 @@ store_fan_min(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); - u16 val = FAN_TO_REG(simple_strtoul(buf, NULL, 10)); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + val = FAN_TO_REG(val); mutex_lock(&data->update_lock); data->fan_min[index] = val; @@ -513,7 +546,7 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf) int nr = sensor_attr->nr; int index = sensor_attr->index; - if (PWM_STOP_TIME == nr) + if (nr == PWM_STOP_TIME) val = TIME_FROM_REG(data->pwm_stop_time[index]); else val = (data->pwm[index][nr] & 0x3f) << 2; @@ -531,17 +564,21 @@ store_pwm(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; - u8 val; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - if (PWM_STOP_TIME == nr) { - val = TIME_TO_REG(simple_strtoul(buf, NULL, 10)); + if (nr == PWM_STOP_TIME) { + val = TIME_TO_REG(val); data->pwm_stop_time[index] = val; w83793_write_value(client, W83793_REG_PWM_STOP_TIME(index), val); } else { - val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 0xff) - >> 2; + val = SENSORS_LIMIT(val, 0, 0xff) >> 2; data->pwm[index][nr] = w83793_read_value(client, W83793_REG_PWM(index, nr)) & 0xc0; data->pwm[index][nr] |= val; @@ -563,7 +600,7 @@ show_temp(struct device *dev, struct device_attribute *attr, char *buf) struct w83793_data *data = w83793_update_device(dev); long temp = TEMP_FROM_REG(data->temp[index][nr]); - if (TEMP_READ == nr && index < 4) { /* Only TD1-TD4 have low bits */ + if (nr == TEMP_READ && index < 4) { /* Only TD1-TD4 have low bits */ int low = ((data->temp_low_bits >> (index * 2)) & 0x03) * 250; temp += temp > 0 ? low : -low; } @@ -580,7 +617,12 @@ store_temp(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); - long tmp = simple_strtol(buf, NULL, 10); + long tmp; + int err; + + err = kstrtol(buf, 10, &tmp); + if (err) + return err; mutex_lock(&data->update_lock); data->temp[index][nr] = TEMP_TO_REG(tmp, -128, 127); @@ -591,18 +633,18 @@ store_temp(struct device *dev, struct device_attribute *attr, } /* - TD1-TD4 - each has 4 mode:(2 bits) - 0: Stop monitor - 1: Use internal temp sensor(default) - 2: Reserved - 3: Use sensor in Intel CPU and get result by PECI - - TR1-TR2 - each has 2 mode:(1 bit) - 0: Disable temp sensor monitor - 1: To enable temp sensors monitor -*/ + * TD1-TD4 + * each has 4 mode:(2 bits) + * 0: Stop monitor + * 1: Use internal temp sensor(default) + * 2: Reserved + * 3: Use sensor in Intel CPU and get result by PECI + * + * TR1-TR2 + * each has 2 mode:(1 bit) + * 0: Disable temp sensor monitor + * 1: To enable temp sensors monitor + */ /* 0 disable, 6 PECI */ static u8 TO_TEMP_MODE[] = { 0, 0, 0, 6 }; @@ -622,11 +664,10 @@ show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) tmp = (data->temp_mode[index] >> shift) & mask; /* for the internal sensor, found out if diode or thermistor */ - if (tmp == 1) { + if (tmp == 1) tmp = index == 0 ? 3 : 4; - } else { + else tmp = TO_TEMP_MODE[tmp]; - } return sprintf(buf, "%d\n", tmp); } @@ -642,7 +683,12 @@ store_temp_mode(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index; u8 mask = (index < 4) ? 0x03 : 0x01; u8 shift = (index < 4) ? (2 * index) : (index - 4); - u8 val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; /* transform the sysfs interface values into table above */ if ((val == 6) && (index < 4)) { @@ -681,15 +727,14 @@ show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) struct w83793_data *data = w83793_update_device(dev); u32 val = 0; - if (SETUP_PWM_DEFAULT == nr) { + if (nr == SETUP_PWM_DEFAULT) val = (data->pwm_default & 0x3f) << 2; - } else if (SETUP_PWM_UPTIME == nr) { + else if (nr == SETUP_PWM_UPTIME) val = TIME_FROM_REG(data->pwm_uptime); - } else if (SETUP_PWM_DOWNTIME == nr) { + else if (nr == SETUP_PWM_DOWNTIME) val = TIME_FROM_REG(data->pwm_downtime); - } else if (SETUP_TEMP_CRITICAL == nr) { + else if (nr == SETUP_TEMP_CRITICAL) val = TEMP_FROM_REG(data->temp_critical & 0x7f); - } return sprintf(buf, "%d\n", val); } @@ -703,31 +748,34 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->nr; struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - if (SETUP_PWM_DEFAULT == nr) { + if (nr == SETUP_PWM_DEFAULT) { data->pwm_default = w83793_read_value(client, W83793_REG_PWM_DEFAULT) & 0xc0; - data->pwm_default |= SENSORS_LIMIT(simple_strtoul(buf, NULL, - 10), - 0, 0xff) >> 2; + data->pwm_default |= SENSORS_LIMIT(val, 0, 0xff) >> 2; w83793_write_value(client, W83793_REG_PWM_DEFAULT, data->pwm_default); - } else if (SETUP_PWM_UPTIME == nr) { - data->pwm_uptime = TIME_TO_REG(simple_strtoul(buf, NULL, 10)); + } else if (nr == SETUP_PWM_UPTIME) { + data->pwm_uptime = TIME_TO_REG(val); data->pwm_uptime += data->pwm_uptime == 0 ? 1 : 0; w83793_write_value(client, W83793_REG_PWM_UPTIME, data->pwm_uptime); - } else if (SETUP_PWM_DOWNTIME == nr) { - data->pwm_downtime = TIME_TO_REG(simple_strtoul(buf, NULL, 10)); + } else if (nr == SETUP_PWM_DOWNTIME) { + data->pwm_downtime = TIME_TO_REG(val); data->pwm_downtime += data->pwm_downtime == 0 ? 1 : 0; w83793_write_value(client, W83793_REG_PWM_DOWNTIME, data->pwm_downtime); } else { /* SETUP_TEMP_CRITICAL */ data->temp_critical = w83793_read_value(client, W83793_REG_TEMP_CRITICAL) & 0x80; - data->temp_critical |= TEMP_TO_REG(simple_strtol(buf, NULL, 10), - 0, 0x7f); + data->temp_critical |= TEMP_TO_REG(val, 0, 0x7f); w83793_write_value(client, W83793_REG_TEMP_CRITICAL, data->temp_critical); } @@ -737,31 +785,31 @@ store_sf_setup(struct device *dev, struct device_attribute *attr, } /* - Temp SmartFan control - TEMP_FAN_MAP - Temp channel control which pwm fan, bitfield, bit 0 indicate pwm1... - It's possible two or more temp channels control the same fan, w83793 - always prefers to pick the most critical request and applies it to - the related Fan. - It's possible one fan is not in any mapping of 6 temp channels, this - means the fan is manual mode - - TEMP_PWM_ENABLE - Each temp channel has its own SmartFan mode, and temp channel - control fans that are set by TEMP_FAN_MAP - 0: SmartFanII mode - 1: Thermal Cruise Mode - - TEMP_CRUISE - Target temperature in thermal cruise mode, w83793 will try to turn - fan speed to keep the temperature of target device around this - temperature. - - TEMP_TOLERANCE - If Temp higher or lower than target with this tolerance, w83793 - will take actions to speed up or slow down the fan to keep the - temperature within the tolerance range. -*/ + * Temp SmartFan control + * TEMP_FAN_MAP + * Temp channel control which pwm fan, bitfield, bit 0 indicate pwm1... + * It's possible two or more temp channels control the same fan, w83793 + * always prefers to pick the most critical request and applies it to + * the related Fan. + * It's possible one fan is not in any mapping of 6 temp channels, this + * means the fan is manual mode + * + * TEMP_PWM_ENABLE + * Each temp channel has its own SmartFan mode, and temp channel + * control fans that are set by TEMP_FAN_MAP + * 0: SmartFanII mode + * 1: Thermal Cruise Mode + * + * TEMP_CRUISE + * Target temperature in thermal cruise mode, w83793 will try to turn + * fan speed to keep the temperature of target device around this + * temperature. + * + * TEMP_TOLERANCE + * If Temp higher or lower than target with this tolerance, w83793 + * will take actions to speed up or slow down the fan to keep the + * temperature within the tolerance range. + */ #define TEMP_FAN_MAP 0 #define TEMP_PWM_ENABLE 1 @@ -777,12 +825,12 @@ show_sf_ctrl(struct device *dev, struct device_attribute *attr, char *buf) struct w83793_data *data = w83793_update_device(dev); u32 val; - if (TEMP_FAN_MAP == nr) { + if (nr == TEMP_FAN_MAP) { val = data->temp_fan_map[index]; - } else if (TEMP_PWM_ENABLE == nr) { + } else if (nr == TEMP_PWM_ENABLE) { /* +2 to transfrom into 2 and 3 to conform with sysfs intf */ val = ((data->pwm_enable >> index) & 0x01) + 2; - } else if (TEMP_CRUISE == nr) { + } else if (nr == TEMP_CRUISE) { val = TEMP_FROM_REG(data->temp_cruise[index] & 0x7f); } else { /* TEMP_TOLERANCE */ val = data->tolerance[index >> 1] >> ((index & 0x01) ? 4 : 0); @@ -801,16 +849,20 @@ store_sf_ctrl(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); - u32 val; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - if (TEMP_FAN_MAP == nr) { - val = simple_strtoul(buf, NULL, 10) & 0xff; + if (nr == TEMP_FAN_MAP) { + val = SENSORS_LIMIT(val, 0, 255); w83793_write_value(client, W83793_REG_TEMP_FAN_MAP(index), val); data->temp_fan_map[index] = val; - } else if (TEMP_PWM_ENABLE == nr) { - val = simple_strtoul(buf, NULL, 10); - if (2 == val || 3 == val) { + } else if (nr == TEMP_PWM_ENABLE) { + if (val == 2 || val == 3) { data->pwm_enable = w83793_read_value(client, W83793_REG_PWM_ENABLE); if (val - 2) @@ -823,12 +875,11 @@ store_sf_ctrl(struct device *dev, struct device_attribute *attr, mutex_unlock(&data->update_lock); return -EINVAL; } - } else if (TEMP_CRUISE == nr) { + } else if (nr == TEMP_CRUISE) { data->temp_cruise[index] = w83793_read_value(client, W83793_REG_TEMP_CRUISE(index)); - val = TEMP_TO_REG(simple_strtol(buf, NULL, 10), 0, 0x7f); data->temp_cruise[index] &= 0x80; - data->temp_cruise[index] |= val; + data->temp_cruise[index] |= TEMP_TO_REG(val, 0, 0x7f); w83793_write_value(client, W83793_REG_TEMP_CRUISE(index), data->temp_cruise[index]); @@ -838,9 +889,8 @@ store_sf_ctrl(struct device *dev, struct device_attribute *attr, data->tolerance[i] = w83793_read_value(client, W83793_REG_TEMP_TOL(i)); - val = TEMP_TO_REG(simple_strtol(buf, NULL, 10), 0, 0x0f); data->tolerance[i] &= ~(0x0f << shift); - data->tolerance[i] |= val << shift; + data->tolerance[i] |= TEMP_TO_REG(val, 0, 0x0f) << shift; w83793_write_value(client, W83793_REG_TEMP_TOL(i), data->tolerance[i]); } @@ -871,7 +921,13 @@ store_sf2_pwm(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; - u8 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 0xff) >> 2; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + val = SENSORS_LIMIT(val, 0, 0xff) >> 2; mutex_lock(&data->update_lock); data->sf2_pwm[index][nr] = @@ -906,7 +962,13 @@ store_sf2_temp(struct device *dev, struct device_attribute *attr, to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; - u8 val = TEMP_TO_REG(simple_strtol(buf, NULL, 10), 0, 0x7f); + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; + val = TEMP_TO_REG(val, 0, 0x7f); mutex_lock(&data->update_lock); data->sf2_temp[index][nr] = @@ -948,17 +1010,19 @@ store_in(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); - u32 val; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + val = (val + scale_in[index] / 2) / scale_in[index]; - val = - (simple_strtoul(buf, NULL, 10) + - scale_in[index] / 2) / scale_in[index]; mutex_lock(&data->update_lock); if (index > 2) { /* fix the limit values of 5VDD and 5VSB to ALARM mechanism */ - if (1 == nr || 2 == nr) { + if (nr == 1 || nr == 2) val -= scale_in_add[index] / scale_in[index]; - } val = SENSORS_LIMIT(val, 0, 255); } else { val = SENSORS_LIMIT(val, 0, 0x3FF); @@ -1143,9 +1207,8 @@ static struct sensor_device_attribute_2 sda_single_files[] = { static void w83793_init_client(struct i2c_client *client) { - if (reset) { + if (reset) w83793_write_value(client, W83793_REG_CONFIG, 0x80); - } /* Start monitoring */ w83793_write_value(client, W83793_REG_CONFIG, @@ -1259,10 +1322,12 @@ static int watchdog_open(struct inode *inode, struct file *filp) struct w83793_data *pos, *data = NULL; int watchdog_is_open; - /* We get called from drivers/char/misc.c with misc_mtx hold, and we - call misc_register() from w83793_probe() with watchdog_data_mutex - hold, as misc_register() takes the misc_mtx lock, this is a possible - deadlock, so we use mutex_trylock here. */ + /* + * We get called from drivers/char/misc.c with misc_mtx hold, and we + * call misc_register() from w83793_probe() with watchdog_data_mutex + * hold, as misc_register() takes the misc_mtx lock, this is a possible + * deadlock, so we use mutex_trylock here. + */ if (!mutex_trylock(&watchdog_data_mutex)) return -ERESTARTSYS; list_for_each_entry(pos, &watchdog_data_list, list) { @@ -1275,8 +1340,10 @@ static int watchdog_open(struct inode *inode, struct file *filp) /* Check, if device is already open */ watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); - /* Increase data reference counter (if not already done). - Note we can never not have found data, so we don't check for this */ + /* + * Increase data reference counter (if not already done). + * Note we can never not have found data, so we don't check for this + */ if (!watchdog_is_open) kref_get(&data->kref); @@ -1556,9 +1623,8 @@ w83793_detect_subclients(struct i2c_client *client) } tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR); - if (!(tmp & 0x08)) { + if (!(tmp & 0x08)) data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7)); - } if (!(tmp & 0x80)) { if ((data->lm75[0] != NULL) && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) { @@ -1591,9 +1657,8 @@ static int w83793_detect(struct i2c_client *client, struct i2c_adapter *adapter = client->adapter; unsigned short address = client->addr; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - } bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL); @@ -1604,8 +1669,10 @@ static int w83793_detect(struct i2c_client *client, return -ENODEV; } - /* If Winbond chip, address of chip and W83793_REG_I2C_ADDR - should match */ + /* + * If Winbond chip, address of chip and W83793_REG_I2C_ADDR + * should match + */ if ((bank & 0x07) == 0 && i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) != (address << 1)) { @@ -1647,9 +1714,11 @@ static int w83793_probe(struct i2c_client *client, INIT_LIST_HEAD(&data->list); kref_init(&data->kref); - /* Store client pointer in our data struct for watchdog usage - (where the client is found through a data ptr instead of the - otherway around) */ + /* + * Store client pointer in our data struct for watchdog usage + * (where the client is found through a data ptr instead of the + * otherway around) + */ data->client = client; err = w83793_detect_subclients(client); @@ -1660,8 +1729,8 @@ static int w83793_probe(struct i2c_client *client, w83793_init_client(client); /* - Only fan 1-5 has their own input pins, - Pwm 1-3 has their own pins + * Only fan 1-5 has their own input pins, + * Pwm 1-3 has their own pins */ data->has_fan = 0x1f; data->has_pwm = 0x07; @@ -1723,7 +1792,7 @@ static int w83793_probe(struct i2c_client *client, } /* check the temp1-6 mode, ignore former AMDSI selected inputs */ - tmp = w83793_read_value(client,W83793_REG_TEMP_MODE[0]); + tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[0]); if (tmp & 0x01) data->has_temp |= 0x01; if (tmp & 0x04) @@ -1733,7 +1802,7 @@ static int w83793_probe(struct i2c_client *client, if (tmp & 0x40) data->has_temp |= 0x08; - tmp = w83793_read_value(client,W83793_REG_TEMP_MODE[1]); + tmp = w83793_read_value(client, W83793_REG_TEMP_MODE[1]); if (tmp & 0x01) data->has_temp |= 0x10; if (tmp & 0x02) @@ -1823,9 +1892,11 @@ static int w83793_probe(struct i2c_client *client, goto exit_devunreg; } - /* Enable Watchdog registers. - Set Configuration Register to Enable Watch Dog Registers - (Bit 2) = XXXX, X1XX. */ + /* + * Enable Watchdog registers. + * Set Configuration Register to Enable Watch Dog Registers + * (Bit 2) = XXXX, X1XX. + */ tmp = w83793_read_value(client, W83793_REG_CONFIG); w83793_write_value(client, W83793_REG_CONFIG, tmp | 0x04); @@ -1839,9 +1910,11 @@ static int w83793_probe(struct i2c_client *client, /* Disable Soft Watchdog during initialiation */ watchdog_disable(data); - /* We take the data_mutex lock early so that watchdog_open() cannot - run when misc_register() has completed, but we've not yet added - our data to the watchdog_data_list (and set the default timeout) */ + /* + * We take the data_mutex lock early so that watchdog_open() cannot + * run when misc_register() has completed, but we've not yet added + * our data to the watchdog_data_list (and set the default timeout) + */ mutex_lock(&watchdog_data_mutex); for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) { /* Register our watchdog part */ @@ -1921,9 +1994,9 @@ static void w83793_update_nonvolatile(struct device *dev) struct w83793_data *data = i2c_get_clientdata(client); int i, j; /* - They are somewhat "stable" registers, and to update them every time - takes so much time, it's just not worthy. Update them in a long - interval to avoid exception. + * They are somewhat "stable" registers, and to update them every time + * takes so much time, it's just not worthy. Update them in a long + * interval to avoid exception. */ if (!(time_after(jiffies, data->last_nonvolatile + HZ * 300) || !data->valid)) @@ -1940,9 +2013,8 @@ static void w83793_update_nonvolatile(struct device *dev) for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { /* Update the Fan measured value and limits */ - if (!(data->has_fan & (1 << i))) { + if (!(data->has_fan & (1 << i))) continue; - } data->fan_min[i] = w83793_read_value(client, W83793_REG_FAN_MIN(i)) << 8; data->fan_min[i] |= @@ -1997,9 +2069,8 @@ static void w83793_update_nonvolatile(struct device *dev) w83793_read_value(client, W83793_REG_TEMP_CRITICAL); data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP); - for (i = 0; i < ARRAY_SIZE(data->beeps); i++) { + for (i = 0; i < ARRAY_SIZE(data->beeps); i++) data->beeps[i] = w83793_read_value(client, W83793_REG_BEEP(i)); - } data->last_nonvolatile = jiffies; } @@ -2025,9 +2096,8 @@ static struct w83793_data *w83793_update_device(struct device *dev) w83793_read_value(client, W83793_REG_IN_LOW_BITS[IN_READ]); for (i = 0; i < ARRAY_SIZE(data->fan); i++) { - if (!(data->has_fan & (1 << i))) { + if (!(data->has_fan & (1 << i))) continue; - } data->fan[i] = w83793_read_value(client, W83793_REG_FAN(i)) << 8; data->fan[i] |= @@ -2067,8 +2137,10 @@ END: return data; } -/* Ignore the possibility that somebody change bank outside the driver - Must be called with data->update_lock held, except during initialization */ +/* + * Ignore the possibility that somebody change bank outside the driver + * Must be called with data->update_lock held, except during initialization + */ static u8 w83793_read_value(struct i2c_client *client, u16 reg) { struct w83793_data *data = i2c_get_clientdata(client); @@ -2103,16 +2175,16 @@ static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value) new_bank |= data->bank & 0xfc; if (data->bank != new_bank) { - if ((res = i2c_smbus_write_byte_data - (client, W83793_REG_BANKSEL, new_bank)) >= 0) - data->bank = new_bank; - else { + res = i2c_smbus_write_byte_data(client, W83793_REG_BANKSEL, + new_bank); + if (res < 0) { dev_err(&client->dev, "set bank to %d failed, fall back " "to bank %d, write reg 0x%x error\n", new_bank, data->bank, reg); goto END; } + data->bank = new_bank; } res = i2c_smbus_write_byte_data(client, reg & 0xff, value); @@ -2120,19 +2192,8 @@ END: return res; } -static int __init sensors_w83793_init(void) -{ - return i2c_add_driver(&w83793_driver); -} - -static void __exit sensors_w83793_exit(void) -{ - i2c_del_driver(&w83793_driver); -} +module_i2c_driver(w83793_driver); MODULE_AUTHOR("Yuan Mu, Sven Anders"); MODULE_DESCRIPTION("w83793 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_w83793_init); -module_exit(sensors_w83793_exit); diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index aa58b25565bc..deb12c982800 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -2244,19 +2244,8 @@ static struct i2c_driver w83795_driver = { .address_list = normal_i2c, }; -static int __init sensors_w83795_init(void) -{ - return i2c_add_driver(&w83795_driver); -} - -static void __exit sensors_w83795_exit(void) -{ - i2c_del_driver(&w83795_driver); -} +module_i2c_driver(w83795_driver); MODULE_AUTHOR("Wei Song, Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_w83795_init); -module_exit(sensors_w83795_exit); diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 20781def65ed..5f14e3897058 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -86,7 +86,7 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev); /* * Driver data (common to all clients) */ - + static const struct i2c_device_id w83l785ts_id[] = { { "w83l785ts", 0 }, { } @@ -116,8 +116,7 @@ struct w83l785ts_data { unsigned long last_updated; /* in jiffies */ /* registers values */ - s8 temp[2]; /* 0: input - 1: critical limit */ + s8 temp[2]; /* 0: input, 1: critical limit */ }; /* @@ -250,8 +249,10 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) struct device *dev; const char *prefix; - /* We might be called during detection, at which point the client - isn't yet fully initialized, so we can't use dev_dbg on it */ + /* + * We might be called during detection, at which point the client + * isn't yet fully initialized, so we can't use dev_dbg on it + */ if (i2c_get_clientdata(client)) { dev = &client->dev; prefix = ""; @@ -260,9 +261,11 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) prefix = "w83l785ts: "; } - /* Frequent read errors have been reported on Asus boards, so we + /* + * Frequent read errors have been reported on Asus boards, so we * retry on read errors. If it still fails (unlikely), return the - * default value requested by the caller. */ + * default value requested by the caller. + */ for (i = 1; i <= MAX_RETRIES; i++) { value = i2c_smbus_read_byte_data(client, reg); if (value >= 0) { @@ -302,19 +305,8 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev) return data; } -static int __init sensors_w83l785ts_init(void) -{ - return i2c_add_driver(&w83l785ts_driver); -} - -static void __exit sensors_w83l785ts_exit(void) -{ - i2c_del_driver(&w83l785ts_driver); -} +module_i2c_driver(w83l785ts_driver); MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("W83L785TS-S driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_w83l785ts_init); -module_exit(sensors_w83l785ts_exit); diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 063bd9508d8a..5850b7706088 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -1,28 +1,28 @@ /* - w83l786ng.c - Linux kernel driver for hardware monitoring - Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation - version 2. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA. -*/ + * w83l786ng.c - Linux kernel driver for hardware monitoring + * Copyright (c) 2007 Kevin Lo <kevlo@kevlo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation - version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ /* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no -*/ + * Supports following chips: + * + * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + * w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no + */ #include <linux/module.h> #include <linux/init.h> @@ -52,7 +52,7 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); #define W83L786NG_REG_CONFIG 0x40 #define W83L786NG_REG_ALARM1 0x41 -#define W83L786NG_REG_ALARM2 0x42 +#define W83L786NG_REG_ALARM2 0x42 #define W83L786NG_REG_GPIO_EN 0x47 #define W83L786NG_REG_MAN_ID2 0x4C #define W83L786NG_REG_MAN_ID1 0x4D @@ -89,19 +89,23 @@ FAN_TO_REG(long rpm, int div) return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ +#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ ((val) == 255 ? 0 : \ 1350000 / ((val) * (div)))) /* for temp */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ - : (val)) / 1000, 0, 0xff)) -#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) - -/* The analog voltage inputs have 8mV LSB. Since the sysfs output is - in mV as would be measured on the chip input pin, need to just - multiply/divide by 8 to translate from/to register values. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255)) +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? \ + (val) + 0x100 * 1000 \ + : (val)) / 1000, 0, 0xff)) +#define TEMP_FROM_REG(val) (((val) & 0x80 ? \ + (val) - 0x100 : (val)) * 1000) + +/* + * The analog voltage inputs have 8mV LSB. Since the sysfs output is + * in mV as would be measured on the chip input pin, need to just + * multiply/divide by 8 to translate from/to register values. + */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255)) #define IN_FROM_REG(val) ((val) * 8) #define DIV_FROM_REG(val) (1 << (val)) @@ -116,7 +120,7 @@ DIV_TO_REG(long val) break; val >>= 1; } - return ((u8) i); + return (u8)i; } struct w83l786ng_data { @@ -125,7 +129,7 @@ struct w83l786ng_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_nonvolatile; /* In jiffies, last time we update the - nonvolatile registers */ + * nonvolatile registers */ u8 in[3]; u8 in_max[3]; @@ -137,10 +141,10 @@ struct w83l786ng_data { u8 temp[2][3]; u8 pwm[2]; u8 pwm_mode[2]; /* 0->DC variable voltage - 1->PWM variable duty cycle */ + * 1->PWM variable duty cycle */ u8 pwm_enable[2]; /* 1->manual - 2->thermal cruise (also called SmartFan I) */ + * 2->thermal cruise (also called SmartFan I) */ u8 tolerance[2]; }; @@ -186,11 +190,11 @@ w83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value) #define show_in_reg(reg) \ static ssize_t \ show_##reg(struct device *dev, struct device_attribute *attr, \ - char *buf) \ + char *buf) \ { \ int nr = to_sensor_dev_attr(attr)->index; \ struct w83l786ng_data *data = w83l786ng_update_device(dev); \ - return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[nr])); \ + return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ } show_in_reg(in) @@ -199,13 +203,16 @@ show_in_reg(in_max) #define store_in_reg(REG, reg) \ static ssize_t \ -store_in_##reg (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ +store_in_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ int nr = to_sensor_dev_attr(attr)->index; \ struct i2c_client *client = to_i2c_client(dev); \ struct w83l786ng_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ + unsigned long val; \ + int err = kstrtoul(buf, 10, &val); \ + if (err) \ + return err; \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \ @@ -241,8 +248,8 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ { \ int nr = to_sensor_dev_attr(attr)->index; \ struct w83l786ng_data *data = w83l786ng_update_device(dev); \ - return sprintf(buf,"%d\n", \ - FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \ + return sprintf(buf, "%d\n", \ + FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); @@ -255,9 +262,13 @@ store_fan_min(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct w83l786ng_data *data = i2c_get_clientdata(client); - u32 val; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; - val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), @@ -276,10 +287,12 @@ show_fan_div(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); } -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise; the user doesn't expect the fan minimum to change just - because the divisor changed. */ +/* + * Note: we save and restore the fan minimum here, because its value is + * determined in part by the fan divisor. This follows the principle of + * least surprise; the user doesn't expect the fan minimum to change just + * because the divisor changed. + */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -294,11 +307,18 @@ store_fan_div(struct device *dev, struct device_attribute *attr, u8 keep_mask = 0; u8 new_shift = 0; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + /* Save fan_min */ mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + data->fan_div[nr] = DIV_TO_REG(val); switch (nr) { case 0: @@ -371,16 +391,20 @@ store_temp(struct device *dev, struct device_attribute *attr, int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83l786ng_data *data = i2c_get_clientdata(client); - s32 val; + long val; + int err; + + err = kstrtol(buf, 10, &val); + if (err) + return err; - val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp[nr][index] = TEMP_TO_REG(val); w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index], data->temp[nr][index]); mutex_unlock(&data->update_lock); - return count; + return count; } static struct sensor_device_attribute_2 sda_temp_input[] = { @@ -403,8 +427,8 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { }; #define show_pwm_reg(reg) \ -static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ - char *buf) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct w83l786ng_data *data = w83l786ng_update_device(dev); \ int nr = to_sensor_dev_attr(attr)->index; \ @@ -422,8 +446,13 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct w83l786ng_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); u8 reg; + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; if (val > 1) return -EINVAL; @@ -445,7 +474,13 @@ store_pwm(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct w83l786ng_data *data = i2c_get_clientdata(client); - u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + val = SENSORS_LIMIT(val, 0, 255); mutex_lock(&data->update_lock); data->pwm[nr] = val; @@ -461,11 +496,15 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct w83l786ng_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); - u8 reg; + unsigned long val; + int err; - if (!val || (val > 2)) /* only modes 1 and 2 are supported */ + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (!val || val > 2) /* only modes 1 and 2 are supported */ return -EINVAL; mutex_lock(&data->update_lock); @@ -513,10 +552,13 @@ store_tolerance(struct device *dev, struct device_attribute *attr, int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct w83l786ng_data *data = i2c_get_clientdata(client); - u32 val; u8 tol_tmp, tol_mask; + unsigned long val; + int err; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); tol_mask = w83l786ng_read_value(client, @@ -524,9 +566,8 @@ store_tolerance(struct device *dev, struct device_attribute *attr, tol_tmp = SENSORS_LIMIT(val, 0, 15); tol_tmp &= 0x0f; data->tolerance[nr] = tol_tmp; - if (nr == 1) { + if (nr == 1) tol_tmp <<= 4; - } w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE, tol_mask | tol_tmp); @@ -591,9 +632,8 @@ w83l786ng_detect(struct i2c_client *client, struct i2c_board_info *info) u16 man_id; u8 chip_id; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - } /* Detection */ if ((w83l786ng_read_value(client, W83L786NG_REG_CONFIG) & 0x80)) { @@ -652,7 +692,8 @@ w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id) data->fan_div[1] = (reg_tmp >> 4) & 0x07; /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group))) + err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group); + if (err) goto exit_remove; data->hwmon_dev = hwmon_device_register(dev); @@ -769,21 +810,8 @@ static struct w83l786ng_data *w83l786ng_update_device(struct device *dev) return data; } -static int __init -sensors_w83l786ng_init(void) -{ - return i2c_add_driver(&w83l786ng_driver); -} - -static void __exit -sensors_w83l786ng_exit(void) -{ - i2c_del_driver(&w83l786ng_driver); -} +module_i2c_driver(w83l786ng_driver); MODULE_AUTHOR("Kevin Lo"); MODULE_DESCRIPTION("w83l786ng driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_w83l786ng_init); -module_exit(sensors_w83l786ng_exit); diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c index 9b598ed26020..07cb25ae69be 100644 --- a/drivers/hwmon/wm831x-hwmon.c +++ b/drivers/hwmon/wm831x-hwmon.c @@ -40,7 +40,7 @@ static ssize_t show_name(struct device *dev, return sprintf(buf, "wm831x\n"); } -static const char *input_names[] = { +static const char * const input_names[] = { [WM831X_AUX_SYSVDD] = "SYSVDD", [WM831X_AUX_USB] = "USB", [WM831X_AUX_BKUP_BATT] = "Backup battery", @@ -117,8 +117,10 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_chip_temp, NULL, WM831X_AUX_CHIP_TEMP); static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, WM831X_AUX_CHIP_TEMP); -/* Report as a voltage since conversion depends on external components - * and that's what the ABI wants. */ +/* + * Report as a voltage since conversion depends on external components + * and that's what the ABI wants. + */ static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_voltage, NULL, WM831X_AUX_BATT_TEMP); static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, diff --git a/drivers/hwmon/wm8350-hwmon.c b/drivers/hwmon/wm8350-hwmon.c index 3ff67edbdc44..b955756bdb42 100644 --- a/drivers/hwmon/wm8350-hwmon.c +++ b/drivers/hwmon/wm8350-hwmon.c @@ -34,7 +34,7 @@ static ssize_t show_name(struct device *dev, return sprintf(buf, "wm8350\n"); } -static const char *input_names[] = { +static const char * const input_names[] = { [WM8350_AUXADC_USB] = "USB", [WM8350_AUXADC_LINE] = "Line", [WM8350_AUXADC_BATT] = "Battery", diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 5bc2839ebcfd..729428edeba2 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -253,7 +253,7 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, if (page_is_high) local_irq_save(flags); - buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; + buf = kmap_atomic(page) + offset; cmd->nleft -= nr_bytes; cmd->cursg_ofs += nr_bytes; @@ -269,7 +269,7 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, else hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); - kunmap_atomic(buf, KM_BIO_SRC_IRQ); + kunmap_atomic(buf); if (page_is_high) local_irq_restore(flags); diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 1a696f76b616..0bb99bb38809 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -624,17 +624,6 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv, */ BUG_ON(iw_event->status); - /* - * We could be destroying the listening id. If so, ignore this - * upcall. - */ - spin_lock_irqsave(&listen_id_priv->lock, flags); - if (listen_id_priv->state != IW_CM_STATE_LISTEN) { - spin_unlock_irqrestore(&listen_id_priv->lock, flags); - goto out; - } - spin_unlock_irqrestore(&listen_id_priv->lock, flags); - cm_id = iw_create_cm_id(listen_id_priv->id.device, listen_id_priv->id.cm_handler, listen_id_priv->id.context); @@ -649,6 +638,19 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv, cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); cm_id_priv->state = IW_CM_STATE_CONN_RECV; + /* + * We could be destroying the listening id. If so, ignore this + * upcall. + */ + spin_lock_irqsave(&listen_id_priv->lock, flags); + if (listen_id_priv->state != IW_CM_STATE_LISTEN) { + spin_unlock_irqrestore(&listen_id_priv->lock, flags); + iw_cm_reject(cm_id, NULL, 0); + iw_destroy_cm_id(cm_id); + goto out; + } + spin_unlock_irqrestore(&listen_id_priv->lock, flags); + ret = alloc_work_entries(cm_id_priv, 3); if (ret) { iw_cm_reject(cm_id, NULL, 0); diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 2fe428bba54c..426bb7617ec6 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1842,6 +1842,24 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, } } +static bool generate_unmatched_resp(struct ib_mad_private *recv, + struct ib_mad_private *response) +{ + if (recv->mad.mad.mad_hdr.method == IB_MGMT_METHOD_GET || + recv->mad.mad.mad_hdr.method == IB_MGMT_METHOD_SET) { + memcpy(response, recv, sizeof *response); + response->header.recv_wc.wc = &response->header.wc; + response->header.recv_wc.recv_buf.mad = &response->mad.mad; + response->header.recv_wc.recv_buf.grh = &response->grh; + response->mad.mad.mad_hdr.method = IB_MGMT_METHOD_GET_RESP; + response->mad.mad.mad_hdr.status = + cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB); + + return true; + } else { + return false; + } +} static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, struct ib_wc *wc) { @@ -1963,6 +1981,9 @@ local: * or via recv_handler in ib_mad_complete_recv() */ recv = NULL; + } else if (generate_unmatched_resp(recv, response)) { + agent_send_response(&response->mad.mad, &recv->grh, wc, + port_priv->device, port_num, qp_info->qp->qp_num); } out: diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index c61bca30fd2d..83b720ef6c34 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -179,33 +179,36 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, { struct ib_port_attr attr; char *speed = ""; - int rate; + int rate = -1; /* in deci-Gb/sec */ ssize_t ret; ret = ib_query_port(p->ibdev, p->port_num, &attr); if (ret) return ret; - rate = (25 * attr.active_speed) / 10; - switch (attr.active_speed) { - case 2: + case IB_SPEED_SDR: + rate = 25; + break; + case IB_SPEED_DDR: speed = " DDR"; + rate = 50; break; - case 4: + case IB_SPEED_QDR: speed = " QDR"; + rate = 100; break; - case 8: + case IB_SPEED_FDR10: speed = " FDR10"; - rate = 10; + rate = 100; break; - case 16: + case IB_SPEED_FDR: speed = " FDR"; - rate = 14; + rate = 140; break; - case 32: + case IB_SPEED_EDR: speed = " EDR"; - rate = 25; + rate = 250; break; } @@ -214,7 +217,7 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, return -EINVAL; return sprintf(buf, "%d%s Gb/sec (%dX%s)\n", - rate, (attr.active_speed == 1) ? ".5" : "", + rate / 10, rate % 10 ? ".5" : "", ib_width_enum_to_int(attr.active_width), speed); } diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 5034a87cc72d..5861cdb22b7c 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -449,24 +449,6 @@ static void ucma_cleanup_multicast(struct ucma_context *ctx) mutex_unlock(&mut); } -static void ucma_cleanup_events(struct ucma_context *ctx) -{ - struct ucma_event *uevent, *tmp; - - list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) { - if (uevent->ctx != ctx) - continue; - - list_del(&uevent->list); - - /* clear incoming connections. */ - if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) - rdma_destroy_id(uevent->cm_id); - - kfree(uevent); - } -} - static void ucma_cleanup_mc_events(struct ucma_multicast *mc) { struct ucma_event *uevent, *tmp; @@ -480,9 +462,16 @@ static void ucma_cleanup_mc_events(struct ucma_multicast *mc) } } +/* + * We cannot hold file->mut when calling rdma_destroy_id() or we can + * deadlock. We also acquire file->mut in ucma_event_handler(), and + * rdma_destroy_id() will wait until all callbacks have completed. + */ static int ucma_free_ctx(struct ucma_context *ctx) { int events_reported; + struct ucma_event *uevent, *tmp; + LIST_HEAD(list); /* No new events will be generated after destroying the id. */ rdma_destroy_id(ctx->cm_id); @@ -491,10 +480,20 @@ static int ucma_free_ctx(struct ucma_context *ctx) /* Cleanup events not yet reported to the user. */ mutex_lock(&ctx->file->mut); - ucma_cleanup_events(ctx); + list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) { + if (uevent->ctx == ctx) + list_move_tail(&uevent->list, &list); + } list_del(&ctx->list); mutex_unlock(&ctx->file->mut); + list_for_each_entry_safe(uevent, tmp, &list, list) { + list_del(&uevent->list); + if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) + rdma_destroy_id(uevent->cm_id); + kfree(uevent); + } + events_reported = ctx->events_reported; kfree(ctx); return events_reported; diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 12f923d64e42..07eb3a8067d8 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -94,7 +94,7 @@ static int c2_query_port(struct ib_device *ibdev, props->pkey_tbl_len = 1; props->qkey_viol_cntr = 0; props->active_width = 1; - props->active_speed = 1; + props->active_speed = IB_SPEED_SDR; return 0; } diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 37c224fc3ad9..0bdf09aa6f42 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1227,7 +1227,7 @@ static int iwch_query_port(struct ib_device *ibdev, props->gid_tbl_len = 1; props->pkey_tbl_len = 1; props->active_width = 2; - props->active_speed = 2; + props->active_speed = IB_SPEED_DDR; props->max_msg_sz = -1; return 0; diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index bea5839d89ee..6de8463f453b 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -803,7 +803,7 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg) * Assumes qhp lock is held. */ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp, - struct iwch_cq *schp, unsigned long *flag) + struct iwch_cq *schp) { int count; int flushed; @@ -812,44 +812,44 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp, PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp); /* take a ref on the qhp since we must release the lock */ atomic_inc(&qhp->refcnt); - spin_unlock_irqrestore(&qhp->lock, *flag); + spin_unlock(&qhp->lock); /* locking hierarchy: cq lock first, then qp lock. */ - spin_lock_irqsave(&rchp->lock, *flag); + spin_lock(&rchp->lock); spin_lock(&qhp->lock); cxio_flush_hw_cq(&rchp->cq); cxio_count_rcqes(&rchp->cq, &qhp->wq, &count); flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count); spin_unlock(&qhp->lock); - spin_unlock_irqrestore(&rchp->lock, *flag); + spin_unlock(&rchp->lock); if (flushed) { - spin_lock_irqsave(&rchp->comp_handler_lock, *flag); + spin_lock(&rchp->comp_handler_lock); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); - spin_unlock_irqrestore(&rchp->comp_handler_lock, *flag); + spin_unlock(&rchp->comp_handler_lock); } /* locking hierarchy: cq lock first, then qp lock. */ - spin_lock_irqsave(&schp->lock, *flag); + spin_lock(&schp->lock); spin_lock(&qhp->lock); cxio_flush_hw_cq(&schp->cq); cxio_count_scqes(&schp->cq, &qhp->wq, &count); flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count); spin_unlock(&qhp->lock); - spin_unlock_irqrestore(&schp->lock, *flag); + spin_unlock(&schp->lock); if (flushed) { - spin_lock_irqsave(&schp->comp_handler_lock, *flag); + spin_lock(&schp->comp_handler_lock); (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); - spin_unlock_irqrestore(&schp->comp_handler_lock, *flag); + spin_unlock(&schp->comp_handler_lock); } /* deref */ if (atomic_dec_and_test(&qhp->refcnt)) wake_up(&qhp->wait); - spin_lock_irqsave(&qhp->lock, *flag); + spin_lock(&qhp->lock); } -static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) +static void flush_qp(struct iwch_qp *qhp) { struct iwch_cq *rchp, *schp; @@ -859,19 +859,19 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) if (qhp->ibqp.uobject) { cxio_set_wq_in_error(&qhp->wq); cxio_set_cq_in_error(&rchp->cq); - spin_lock_irqsave(&rchp->comp_handler_lock, *flag); + spin_lock(&rchp->comp_handler_lock); (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); - spin_unlock_irqrestore(&rchp->comp_handler_lock, *flag); + spin_unlock(&rchp->comp_handler_lock); if (schp != rchp) { cxio_set_cq_in_error(&schp->cq); - spin_lock_irqsave(&schp->comp_handler_lock, *flag); + spin_lock(&schp->comp_handler_lock); (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); - spin_unlock_irqrestore(&schp->comp_handler_lock, *flag); + spin_unlock(&schp->comp_handler_lock); } return; } - __flush_qp(qhp, rchp, schp, flag); + __flush_qp(qhp, rchp, schp); } @@ -1030,7 +1030,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, break; case IWCH_QP_STATE_ERROR: qhp->attr.state = IWCH_QP_STATE_ERROR; - flush_qp(qhp, &flag); + flush_qp(qhp); break; default: ret = -EINVAL; @@ -1078,7 +1078,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, } switch (attrs->next_state) { case IWCH_QP_STATE_IDLE: - flush_qp(qhp, &flag); + flush_qp(qhp); qhp->attr.state = IWCH_QP_STATE_IDLE; qhp->attr.llp_stream_handle = NULL; put_ep(&qhp->ep->com); @@ -1132,7 +1132,7 @@ err: free=1; wake_up(&qhp->wait); BUG_ON(!ep); - flush_qp(qhp, &flag); + flush_qp(qhp); out: spin_unlock_irqrestore(&qhp->lock, flag); diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 0cf61554f176..92b4c2b0308b 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1114,7 +1114,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) * generated when moving QP to RTS state. * A TERM message will be sent after QP has moved to RTS state */ - if ((ep->mpa_attr.version == 2) && + if ((ep->mpa_attr.version == 2) && peer2peer && (ep->mpa_attr.p2p_type != p2p_type)) { ep->mpa_attr.p2p_type = FW_RI_INIT_P2PTYPE_DISABLED; rtr_mismatch = 1; diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 247fe706e7fa..be1c18f44400 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -329,7 +329,7 @@ static int c4iw_query_port(struct ib_device *ibdev, u8 port, props->gid_tbl_len = 1; props->pkey_tbl_len = 1; props->active_width = 2; - props->active_speed = 2; + props->active_speed = IB_SPEED_DDR; props->max_msg_sz = -1; return 0; diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index 73edc3668663..9ed4d2588304 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c @@ -233,7 +233,7 @@ int ehca_query_port(struct ib_device *ibdev, props->phys_state = 5; props->state = rblock->state; props->active_width = IB_WIDTH_12X; - props->active_speed = 0x1; + props->active_speed = IB_SPEED_SDR; } query_port1: diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index e571e60ecb88..53589000fd07 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -786,7 +786,8 @@ static struct task_struct *create_comp_task(struct ehca_comp_pool *pool, spin_lock_init(&cct->task_lock); INIT_LIST_HEAD(&cct->cq_list); init_waitqueue_head(&cct->wait_queue); - cct->task = kthread_create(comp_task, cct, "ehca_comp/%d", cpu); + cct->task = kthread_create_on_node(comp_task, cct, cpu_to_node(cpu), + "ehca_comp/%d", cpu); return cct->task; } diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 43cae84005f0..b781b2cb0624 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -112,7 +112,7 @@ static u32 ehca_encode_hwpage_size(u32 pgsize) static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca) { - return 1UL << ilog2(shca->hca_cap_mr_pgsize); + return rounddown_pow_of_two(shca->hca_cap_mr_pgsize); } static struct ehca_mr *ehca_mr_new(void) diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 5ecf38d97269..77c8cb4c5073 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -720,7 +720,8 @@ repoll: wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; - wc->csum_ok = mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum); + wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, + cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; if (rdma_port_get_link_layer(wc->qp->device, (*cur_qp)->port) == IB_LINK_LAYER_ETHERNET) wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; @@ -747,8 +748,7 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) break; } - if (npolled) - mlx4_cq_set_ci(&cq->mcq); + mlx4_cq_set_ci(&cq->mcq); spin_unlock_irqrestore(&cq->lock, flags); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 7b445df6a667..75d305629300 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -163,7 +163,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->max_mcast_qp_attach = dev->dev->caps.num_qp_per_mgm; props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * props->max_mcast_grp; - props->max_map_per_fmr = (1 << (32 - ilog2(dev->dev->caps.num_mpts))) - 1; + props->max_map_per_fmr = dev->dev->caps.max_fmr_maps; out: kfree(in_mad); @@ -182,12 +182,27 @@ mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num) } static int ib_link_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props, - struct ib_smp *in_mad, - struct ib_smp *out_mad) + struct ib_port_attr *props) { + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; int ext_active_speed; - int err; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, + in_mad, out_mad); + if (err) + goto out; + props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); props->lmc = out_mad->data[34] & 0x7; @@ -215,34 +230,33 @@ static int ib_link_query_port(struct ib_device *ibdev, u8 port, switch (ext_active_speed) { case 1: - props->active_speed = 16; /* FDR */ + props->active_speed = IB_SPEED_FDR; break; case 2: - props->active_speed = 32; /* EDR */ + props->active_speed = IB_SPEED_EDR; break; } } /* If reported active speed is QDR, check if is FDR-10 */ - if (props->active_speed == 4) { - if (to_mdev(ibdev)->dev->caps.ext_port_cap[port] & - MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO) { - init_query_mad(in_mad); - in_mad->attr_id = MLX4_ATTR_EXTENDED_PORT_INFO; - in_mad->attr_mod = cpu_to_be32(port); - - err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, - NULL, NULL, in_mad, out_mad); - if (err) - return err; + if (props->active_speed == IB_SPEED_QDR) { + init_query_mad(in_mad); + in_mad->attr_id = MLX4_ATTR_EXTENDED_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); - /* Checking LinkSpeedActive for FDR-10 */ - if (out_mad->data[15] & 0x1) - props->active_speed = 8; - } - } + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, + NULL, NULL, in_mad, out_mad); + if (err) + return err; - return 0; + /* Checking LinkSpeedActive for FDR-10 */ + if (out_mad->data[15] & 0x1) + props->active_speed = IB_SPEED_FDR10; + } +out: + kfree(in_mad); + kfree(out_mad); + return err; } static u8 state_to_phys_state(enum ib_port_state state) @@ -251,32 +265,42 @@ static u8 state_to_phys_state(enum ib_port_state state) } static int eth_link_query_port(struct ib_device *ibdev, u8 port, - struct ib_port_attr *props, - struct ib_smp *out_mad) + struct ib_port_attr *props) { - struct mlx4_ib_iboe *iboe = &to_mdev(ibdev)->iboe; + + struct mlx4_ib_dev *mdev = to_mdev(ibdev); + struct mlx4_ib_iboe *iboe = &mdev->iboe; struct net_device *ndev; enum ib_mtu tmp; + struct mlx4_cmd_mailbox *mailbox; + int err = 0; + + mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0, + MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); + if (err) + goto out; - props->active_width = IB_WIDTH_1X; - props->active_speed = 4; + props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ? + IB_WIDTH_4X : IB_WIDTH_1X; + props->active_speed = IB_SPEED_QDR; props->port_cap_flags = IB_PORT_CM_SUP; - props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; - props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz; + props->gid_tbl_len = mdev->dev->caps.gid_table_len[port]; + props->max_msg_sz = mdev->dev->caps.max_msg_sz; props->pkey_tbl_len = 1; - props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); - props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); props->max_mtu = IB_MTU_4096; - props->subnet_timeout = 0; - props->max_vl_num = out_mad->data[37] >> 4; - props->init_type_reply = 0; + props->max_vl_num = 2; props->state = IB_PORT_DOWN; props->phys_state = state_to_phys_state(props->state); props->active_mtu = IB_MTU_256; spin_lock(&iboe->lock); ndev = iboe->netdevs[port - 1]; if (!ndev) - goto out; + goto out_unlock; tmp = iboe_get_mtu(ndev->mtu); props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256; @@ -284,41 +308,23 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, props->state = (netif_running(ndev) && netif_carrier_ok(ndev)) ? IB_PORT_ACTIVE : IB_PORT_DOWN; props->phys_state = state_to_phys_state(props->state); - -out: +out_unlock: spin_unlock(&iboe->lock); - return 0; +out: + mlx4_free_cmd_mailbox(mdev->dev, mailbox); + return err; } static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props) { - struct ib_smp *in_mad = NULL; - struct ib_smp *out_mad = NULL; - int err = -ENOMEM; - - in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); - out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) - goto out; + int err; memset(props, 0, sizeof *props); - init_query_mad(in_mad); - in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; - in_mad->attr_mod = cpu_to_be32(port); - - err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); - if (err) - goto out; - err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ? - ib_link_query_port(ibdev, port, props, in_mad, out_mad) : - eth_link_query_port(ibdev, port, props, out_mad); - -out: - kfree(in_mad); - kfree(out_mad); + ib_link_query_port(ibdev, port, props) : + eth_link_query_port(ibdev, port, props); return err; } diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index aa2aefa4236c..3a7848966627 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1884,6 +1884,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, wmb(); if (wr->opcode < 0 || wr->opcode >= ARRAY_SIZE(mlx4_ib_opcode)) { + *bad_wr = wr; err = -EINVAL; goto out; } diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 53157b86a1ba..40ba83338155 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -643,7 +643,8 @@ static inline int mthca_poll_one(struct mthca_dev *dev, entry->wc_flags |= cqe->g_mlpath & 0x80 ? IB_WC_GRH : 0; checksum = (be32_to_cpu(cqe->rqpn) >> 24) | ((be32_to_cpu(cqe->my_ee) >> 16) & 0xff00); - entry->csum_ok = (cqe->sl_ipok & 1 && checksum == 0xffff); + entry->wc_flags |= (cqe->sl_ipok & 1 && checksum == 0xffff) ? + IB_WC_IP_CSUM_OK : 0; } entry->status = IB_WC_SUCCESS; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index c5e4cb2d3223..71edfbbcce1c 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -338,18 +338,21 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type, case IETF_MPA_V2: { u16 ird_size; u16 ord_size; + u16 rtr_ctrl_ird; + u16 rtr_ctrl_ord; + mpa_v2_frame = (struct ietf_mpa_v2 *)buffer; mpa_hdr_len += IETF_RTR_MSG_SIZE; cm_node->mpa_frame_size -= IETF_RTR_MSG_SIZE; rtr_msg = &mpa_v2_frame->rtr_msg; /* parse rtr message */ - rtr_msg->ctrl_ird = ntohs(rtr_msg->ctrl_ird); - rtr_msg->ctrl_ord = ntohs(rtr_msg->ctrl_ord); - ird_size = rtr_msg->ctrl_ird & IETF_NO_IRD_ORD; - ord_size = rtr_msg->ctrl_ord & IETF_NO_IRD_ORD; + rtr_ctrl_ird = ntohs(rtr_msg->ctrl_ird); + rtr_ctrl_ord = ntohs(rtr_msg->ctrl_ord); + ird_size = rtr_ctrl_ird & IETF_NO_IRD_ORD; + ord_size = rtr_ctrl_ord & IETF_NO_IRD_ORD; - if (!(rtr_msg->ctrl_ird & IETF_PEER_TO_PEER)) { + if (!(rtr_ctrl_ird & IETF_PEER_TO_PEER)) { /* send reset */ return -EINVAL; } @@ -370,9 +373,9 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type, } } - if (rtr_msg->ctrl_ord & IETF_RDMA0_READ) { + if (rtr_ctrl_ord & IETF_RDMA0_READ) { cm_node->send_rdma0_op = SEND_RDMA_READ_ZERO; - } else if (rtr_msg->ctrl_ord & IETF_RDMA0_WRITE) { + } else if (rtr_ctrl_ord & IETF_RDMA0_WRITE) { cm_node->send_rdma0_op = SEND_RDMA_WRITE_ZERO; } else { /* Not supported RDMA0 operation */ return -EINVAL; @@ -543,6 +546,8 @@ static void build_mpa_v2(struct nes_cm_node *cm_node, { struct ietf_mpa_v2 *mpa_frame = (struct ietf_mpa_v2 *)start_addr; struct ietf_rtr_msg *rtr_msg = &mpa_frame->rtr_msg; + u16 ctrl_ird; + u16 ctrl_ord; /* initialize the upper 5 bytes of the frame */ build_mpa_v1(cm_node, start_addr, mpa_key); @@ -550,31 +555,31 @@ static void build_mpa_v2(struct nes_cm_node *cm_node, mpa_frame->priv_data_len += htons(IETF_RTR_MSG_SIZE); /* initialize RTR msg */ - rtr_msg->ctrl_ird = (cm_node->ird_size > IETF_NO_IRD_ORD) ? + ctrl_ird = (cm_node->ird_size > IETF_NO_IRD_ORD) ? IETF_NO_IRD_ORD : cm_node->ird_size; - rtr_msg->ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ? + ctrl_ord = (cm_node->ord_size > IETF_NO_IRD_ORD) ? IETF_NO_IRD_ORD : cm_node->ord_size; - rtr_msg->ctrl_ird |= IETF_PEER_TO_PEER; - rtr_msg->ctrl_ird |= IETF_FLPDU_ZERO_LEN; + ctrl_ird |= IETF_PEER_TO_PEER; + ctrl_ird |= IETF_FLPDU_ZERO_LEN; switch (mpa_key) { case MPA_KEY_REQUEST: - rtr_msg->ctrl_ord |= IETF_RDMA0_WRITE; - rtr_msg->ctrl_ord |= IETF_RDMA0_READ; + ctrl_ord |= IETF_RDMA0_WRITE; + ctrl_ord |= IETF_RDMA0_READ; break; case MPA_KEY_REPLY: switch (cm_node->send_rdma0_op) { case SEND_RDMA_WRITE_ZERO: - rtr_msg->ctrl_ord |= IETF_RDMA0_WRITE; + ctrl_ord |= IETF_RDMA0_WRITE; break; case SEND_RDMA_READ_ZERO: - rtr_msg->ctrl_ord |= IETF_RDMA0_READ; + ctrl_ord |= IETF_RDMA0_READ; break; } } - rtr_msg->ctrl_ird = htons(rtr_msg->ctrl_ird); - rtr_msg->ctrl_ord = htons(rtr_msg->ctrl_ord); + rtr_msg->ctrl_ird = htons(ctrl_ird); + rtr_msg->ctrl_ord = htons(ctrl_ord); } /** diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 0927b5cc65d3..8b8812de4b5c 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -597,7 +597,7 @@ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr props->pkey_tbl_len = 1; props->qkey_viol_cntr = 0; props->active_width = IB_WIDTH_4X; - props->active_speed = 1; + props->active_speed = IB_SPEED_SDR; props->max_msg_sz = 0x80000000; return 0; diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index b881bdc401f5..6b811e3e8bd1 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -427,6 +427,14 @@ struct qib_verbs_txreq { /* how often we check for packet activity for "power on hours (in seconds) */ #define ACTIVITY_TIMER 5 +#define MAX_NAME_SIZE 64 +struct qib_msix_entry { + struct msix_entry msix; + void *arg; + char name[MAX_NAME_SIZE]; + cpumask_var_t mask; +}; + /* Below is an opaque struct. Each chip (device) can maintain * private data needed for its operation, but not germane to the * rest of the driver. For convenience, we define another that @@ -1355,7 +1363,7 @@ int qib_pcie_init(struct pci_dev *, const struct pci_device_id *); int qib_pcie_ddinit(struct qib_devdata *, struct pci_dev *, const struct pci_device_id *); void qib_pcie_ddcleanup(struct qib_devdata *); -int qib_pcie_params(struct qib_devdata *, u32, u32 *, struct msix_entry *); +int qib_pcie_params(struct qib_devdata *, u32, u32 *, struct qib_msix_entry *); int qib_reinit_intr(struct qib_devdata *); void qib_enable_intx(struct pci_dev *); void qib_nomsi(struct qib_devdata *); diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 41e92089e41b..060b96064469 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -541,8 +541,7 @@ struct qib_chip_specific { u32 lastbuf_for_pio; u32 stay_in_freeze; u32 recovery_ports_initted; - struct msix_entry *msix_entries; - void **msix_arg; + struct qib_msix_entry *msix_entries; unsigned long *sendchkenable; unsigned long *sendgrhchk; unsigned long *sendibchk; @@ -639,24 +638,24 @@ static struct { int lsb; int port; /* 0 if not port-specific, else port # */ } irq_table[] = { - { QIB_DRV_NAME, qib_7322intr, -1, 0 }, - { QIB_DRV_NAME " (buf avail)", qib_7322bufavail, + { "", qib_7322intr, -1, 0 }, + { " (buf avail)", qib_7322bufavail, SYM_LSB(IntStatus, SendBufAvail), 0 }, - { QIB_DRV_NAME " (sdma 0)", sdma_intr, + { " (sdma 0)", sdma_intr, SYM_LSB(IntStatus, SDmaInt_0), 1 }, - { QIB_DRV_NAME " (sdma 1)", sdma_intr, + { " (sdma 1)", sdma_intr, SYM_LSB(IntStatus, SDmaInt_1), 2 }, - { QIB_DRV_NAME " (sdmaI 0)", sdma_idle_intr, + { " (sdmaI 0)", sdma_idle_intr, SYM_LSB(IntStatus, SDmaIdleInt_0), 1 }, - { QIB_DRV_NAME " (sdmaI 1)", sdma_idle_intr, + { " (sdmaI 1)", sdma_idle_intr, SYM_LSB(IntStatus, SDmaIdleInt_1), 2 }, - { QIB_DRV_NAME " (sdmaP 0)", sdma_progress_intr, + { " (sdmaP 0)", sdma_progress_intr, SYM_LSB(IntStatus, SDmaProgressInt_0), 1 }, - { QIB_DRV_NAME " (sdmaP 1)", sdma_progress_intr, + { " (sdmaP 1)", sdma_progress_intr, SYM_LSB(IntStatus, SDmaProgressInt_1), 2 }, - { QIB_DRV_NAME " (sdmaC 0)", sdma_cleanup_intr, + { " (sdmaC 0)", sdma_cleanup_intr, SYM_LSB(IntStatus, SDmaCleanupDone_0), 1 }, - { QIB_DRV_NAME " (sdmaC 1)", sdma_cleanup_intr, + { " (sdmaC 1)", sdma_cleanup_intr, SYM_LSB(IntStatus, SDmaCleanupDone_1), 2 }, }; @@ -2567,9 +2566,13 @@ static void qib_7322_nomsix(struct qib_devdata *dd) int i; dd->cspec->num_msix_entries = 0; - for (i = 0; i < n; i++) - free_irq(dd->cspec->msix_entries[i].vector, - dd->cspec->msix_arg[i]); + for (i = 0; i < n; i++) { + irq_set_affinity_hint( + dd->cspec->msix_entries[i].msix.vector, NULL); + free_cpumask_var(dd->cspec->msix_entries[i].mask); + free_irq(dd->cspec->msix_entries[i].msix.vector, + dd->cspec->msix_entries[i].arg); + } qib_nomsix(dd); } /* make sure no MSIx interrupts are left pending */ @@ -2597,7 +2600,6 @@ static void qib_setup_7322_cleanup(struct qib_devdata *dd) kfree(dd->cspec->sendgrhchk); kfree(dd->cspec->sendibchk); kfree(dd->cspec->msix_entries); - kfree(dd->cspec->msix_arg); for (i = 0; i < dd->num_pports; i++) { unsigned long flags; u32 mask = QSFP_GPIO_MOD_PRS_N | @@ -3070,6 +3072,8 @@ static void qib_setup_7322_interrupt(struct qib_devdata *dd, int clearpend) int ret, i, msixnum; u64 redirect[6]; u64 mask; + const struct cpumask *local_mask; + int firstcpu, secondcpu = 0, currrcvcpu = 0; if (!dd->num_pports) return; @@ -3118,13 +3122,28 @@ try_intx: memset(redirect, 0, sizeof redirect); mask = ~0ULL; msixnum = 0; + local_mask = cpumask_of_pcibus(dd->pcidev->bus); + firstcpu = cpumask_first(local_mask); + if (firstcpu >= nr_cpu_ids || + cpumask_weight(local_mask) == num_online_cpus()) { + local_mask = topology_core_cpumask(0); + firstcpu = cpumask_first(local_mask); + } + if (firstcpu < nr_cpu_ids) { + secondcpu = cpumask_next(firstcpu, local_mask); + if (secondcpu >= nr_cpu_ids) + secondcpu = firstcpu; + currrcvcpu = secondcpu; + } for (i = 0; msixnum < dd->cspec->num_msix_entries; i++) { irq_handler_t handler; - const char *name; void *arg; u64 val; int lsb, reg, sh; + dd->cspec->msix_entries[msixnum]. + name[sizeof(dd->cspec->msix_entries[msixnum].name) - 1] + = '\0'; if (i < ARRAY_SIZE(irq_table)) { if (irq_table[i].port) { /* skip if for a non-configured port */ @@ -3135,7 +3154,11 @@ try_intx: arg = dd; lsb = irq_table[i].lsb; handler = irq_table[i].handler; - name = irq_table[i].name; + snprintf(dd->cspec->msix_entries[msixnum].name, + sizeof(dd->cspec->msix_entries[msixnum].name) + - 1, + QIB_DRV_NAME "%d%s", dd->unit, + irq_table[i].name); } else { unsigned ctxt; @@ -3148,23 +3171,28 @@ try_intx: continue; lsb = QIB_I_RCVAVAIL_LSB + ctxt; handler = qib_7322pintr; - name = QIB_DRV_NAME " (kctx)"; + snprintf(dd->cspec->msix_entries[msixnum].name, + sizeof(dd->cspec->msix_entries[msixnum].name) + - 1, + QIB_DRV_NAME "%d (kctx)", dd->unit); } - ret = request_irq(dd->cspec->msix_entries[msixnum].vector, - handler, 0, name, arg); + ret = request_irq( + dd->cspec->msix_entries[msixnum].msix.vector, + handler, 0, dd->cspec->msix_entries[msixnum].name, + arg); if (ret) { /* * Shouldn't happen since the enable said we could * have as many as we are trying to setup here. */ qib_dev_err(dd, "Couldn't setup MSIx " - "interrupt (vec=%d, irq=%d): %d\n", msixnum, - dd->cspec->msix_entries[msixnum].vector, - ret); + "interrupt (vec=%d, irq=%d): %d\n", msixnum, + dd->cspec->msix_entries[msixnum].msix.vector, + ret); qib_7322_nomsix(dd); goto try_intx; } - dd->cspec->msix_arg[msixnum] = arg; + dd->cspec->msix_entries[msixnum].arg = arg; if (lsb >= 0) { reg = lsb / IBA7322_REDIRECT_VEC_PER_REG; sh = (lsb % IBA7322_REDIRECT_VEC_PER_REG) * @@ -3174,6 +3202,25 @@ try_intx: } val = qib_read_kreg64(dd, 2 * msixnum + 1 + (QIB_7322_MsixTable_OFFS / sizeof(u64))); + if (firstcpu < nr_cpu_ids && + zalloc_cpumask_var( + &dd->cspec->msix_entries[msixnum].mask, + GFP_KERNEL)) { + if (handler == qib_7322pintr) { + cpumask_set_cpu(currrcvcpu, + dd->cspec->msix_entries[msixnum].mask); + currrcvcpu = cpumask_next(currrcvcpu, + local_mask); + if (currrcvcpu >= nr_cpu_ids) + currrcvcpu = secondcpu; + } else { + cpumask_set_cpu(firstcpu, + dd->cspec->msix_entries[msixnum].mask); + } + irq_set_affinity_hint( + dd->cspec->msix_entries[msixnum].msix.vector, + dd->cspec->msix_entries[msixnum].mask); + } msixnum++; } /* Initialize the vector mapping */ @@ -3365,7 +3412,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) if (msix_entries) { /* restore the MSIx vector address and data if saved above */ for (i = 0; i < msix_entries; i++) { - dd->cspec->msix_entries[i].entry = i; + dd->cspec->msix_entries[i].msix.entry = i; if (!msix_vecsave || !msix_vecsave[2 * i]) continue; qib_write_kreg(dd, 2 * i + @@ -6865,15 +6912,13 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev, tabsize = actual_cnt; dd->cspec->msix_entries = kmalloc(tabsize * - sizeof(struct msix_entry), GFP_KERNEL); - dd->cspec->msix_arg = kmalloc(tabsize * - sizeof(void *), GFP_KERNEL); - if (!dd->cspec->msix_entries || !dd->cspec->msix_arg) { + sizeof(struct qib_msix_entry), GFP_KERNEL); + if (!dd->cspec->msix_entries) { qib_dev_err(dd, "No memory for MSIx table\n"); tabsize = 0; } for (i = 0; i < tabsize; i++) - dd->cspec->msix_entries[i].entry = i; + dd->cspec->msix_entries[i].msix.entry = i; if (qib_pcie_params(dd, 8, &tabsize, dd->cspec->msix_entries)) qib_dev_err(dd, "Failed to setup PCIe or interrupts; " diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c index 3b3745f261f0..c4ff788823b5 100644 --- a/drivers/infiniband/hw/qib/qib_mad.c +++ b/drivers/infiniband/hw/qib/qib_mad.c @@ -433,7 +433,6 @@ static int subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev, struct qib_pportdata *ppd; struct qib_ibport *ibp; struct ib_port_info *pip = (struct ib_port_info *)smp->data; - u16 lid; u8 mtu; int ret; u32 state; @@ -469,8 +468,7 @@ static int subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev, ibp->mkeyprot == 1)) pip->mkey = ibp->mkey; pip->gid_prefix = ibp->gid_prefix; - lid = ppd->lid; - pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE; + pip->lid = cpu_to_be16(ppd->lid); pip->sm_lid = cpu_to_be16(ibp->sm_lid); pip->cap_mask = cpu_to_be32(ibp->port_cap_flags); /* pip->diag_code; */ diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index 0fde788e1100..790646ef5106 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -194,11 +194,24 @@ void qib_pcie_ddcleanup(struct qib_devdata *dd) } static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, - struct msix_entry *msix_entry) + struct qib_msix_entry *qib_msix_entry) { int ret; u32 tabsize = 0; u16 msix_flags; + struct msix_entry *msix_entry; + int i; + + /* We can't pass qib_msix_entry array to qib_msix_setup + * so use a dummy msix_entry array and copy the allocated + * irq back to the qib_msix_entry array. */ + msix_entry = kmalloc(*msixcnt * sizeof(*msix_entry), GFP_KERNEL); + if (!msix_entry) { + ret = -ENOMEM; + goto do_intx; + } + for (i = 0; i < *msixcnt; i++) + msix_entry[i] = qib_msix_entry[i].msix; pci_read_config_word(dd->pcidev, pos + PCI_MSIX_FLAGS, &msix_flags); tabsize = 1 + (msix_flags & PCI_MSIX_FLAGS_QSIZE); @@ -209,11 +222,15 @@ static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, tabsize = ret; ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); } +do_intx: if (ret) { qib_dev_err(dd, "pci_enable_msix %d vectors failed: %d, " "falling back to INTx\n", tabsize, ret); tabsize = 0; } + for (i = 0; i < tabsize; i++) + qib_msix_entry[i].msix = msix_entry[i]; + kfree(msix_entry); *msixcnt = tabsize; if (ret) @@ -251,7 +268,7 @@ static int qib_msi_setup(struct qib_devdata *dd, int pos) } int qib_pcie_params(struct qib_devdata *dd, u32 minw, u32 *nent, - struct msix_entry *entry) + struct qib_msix_entry *entry) { u16 linkstat, speed; int pos = 0, pose, ret = 1; diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index 894afac26f3b..765b4cbaa020 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -2048,7 +2048,6 @@ send_last: wc.pkey_index = 0; wc.dlid_path_bits = 0; wc.port_num = 0; - wc.csum_ok = 0; /* Signal completion event if the solicited bit is set. */ qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, (ohdr->bth[0] & diff --git a/drivers/infiniband/hw/qib/qib_uc.c b/drivers/infiniband/hw/qib/qib_uc.c index 847e7afdfd94..7ce2ac2ed219 100644 --- a/drivers/infiniband/hw/qib/qib_uc.c +++ b/drivers/infiniband/hw/qib/qib_uc.c @@ -422,7 +422,6 @@ last_imm: wc.pkey_index = 0; wc.dlid_path_bits = 0; wc.port_num = 0; - wc.csum_ok = 0; /* Signal completion event if the solicited bit is set. */ qib_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, (ohdr->bth[0] & diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 4115be54ba3b..5c1bc995e560 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -296,7 +296,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) dev->stats.rx_bytes += skb->len; skb->dev = dev; - if ((dev->features & NETIF_F_RXCSUM) && likely(wc->csum_ok)) + if ((dev->features & NETIF_F_RXCSUM) && + likely(wc->wc_flags & IB_WC_IP_CSUM_OK)) skb->ip_summed = CHECKSUM_UNNECESSARY; napi_gro_receive(&priv->napi, skb); diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 9a43cb07f294..db43b3117168 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -364,6 +364,9 @@ iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, } ib_conn = ep->dd_data; + if (iser_alloc_rx_descriptors(ib_conn)) + return -ENOMEM; + /* binds the iSER connection retrieved from the previously * connected ep_handle to the iSCSI layer connection. exchanges * connection pointers */ @@ -398,19 +401,6 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) iser_conn->ib_conn = NULL; } -static int -iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - int err; - - err = iser_conn_set_full_featured_mode(conn); - if (err) - return err; - - return iscsi_conn_start(cls_conn); -} - static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) { struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); @@ -724,7 +714,7 @@ static struct iscsi_transport iscsi_iser_transport = { .get_conn_param = iscsi_conn_get_param, .get_ep_param = iscsi_iser_get_ep_param, .get_session_param = iscsi_session_get_param, - .start_conn = iscsi_iser_conn_start, + .start_conn = iscsi_conn_start, .stop_conn = iscsi_iser_conn_stop, /* iscsi host params */ .get_host_param = iscsi_host_get_param, diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index db7ea3704da7..296be431a0e9 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -366,4 +366,5 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task, void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task); int iser_initialize_task_headers(struct iscsi_task *task, struct iser_tx_desc *tx_desc); +int iser_alloc_rx_descriptors(struct iser_conn *ib_conn); #endif diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index a607542fc796..a00ccd1ca333 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -170,7 +170,7 @@ static void iser_create_send_desc(struct iser_conn *ib_conn, } -static int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) +int iser_alloc_rx_descriptors(struct iser_conn *ib_conn) { int i, j; u64 dma_addr; @@ -220,18 +220,6 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn) struct iser_rx_desc *rx_desc; struct iser_device *device = ib_conn->device; - if (ib_conn->login_buf) { - if (ib_conn->login_req_dma) - ib_dma_unmap_single(device->ib_device, - ib_conn->login_req_dma, - ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE); - if (ib_conn->login_resp_dma) - ib_dma_unmap_single(device->ib_device, - ib_conn->login_resp_dma, - ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); - kfree(ib_conn->login_buf); - } - if (!ib_conn->rx_descs) return; @@ -242,23 +230,24 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn) kfree(ib_conn->rx_descs); } -/** - * iser_conn_set_full_featured_mode - (iSER API) - */ -int iser_conn_set_full_featured_mode(struct iscsi_conn *conn) +static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req) { struct iscsi_iser_conn *iser_conn = conn->dd_data; - iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX); - - /* Check that there is no posted recv or send buffers left - */ - /* they must be consumed during the login phase */ - BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0); - BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); + iser_dbg("req op %x flags %x\n", req->opcode, req->flags); + /* check if this is the last login - going to full feature phase */ + if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE) + return 0; - if (iser_alloc_rx_descriptors(iser_conn->ib_conn)) - return -ENOMEM; + /* + * Check that there is one posted recv buffer (for the last login + * response) and no posted send buffers left - they must have been + * consumed during previous login phases. + */ + WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1); + WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0); + iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX); /* Initial post receive buffers */ if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX)) return -ENOMEM; @@ -438,6 +427,9 @@ int iser_send_control(struct iscsi_conn *conn, err = iser_post_recvl(iser_conn->ib_conn); if (err) goto send_control_error; + err = iser_post_rx_bufs(conn, task->hdr); + if (err) + goto send_control_error; } err = iser_post_send(iser_conn->ib_conn, mdesc); diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index fb88d6896b67..2033a928d34d 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -73,11 +73,11 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, p = mem; for_each_sg(sgl, sg, data->size, i) { - from = kmap_atomic(sg_page(sg), KM_USER0); + from = kmap_atomic(sg_page(sg)); memcpy(p, from + sg->offset, sg->length); - kunmap_atomic(from, KM_USER0); + kunmap_atomic(from); p += sg->length; } } @@ -133,11 +133,11 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, p = mem; for_each_sg(sgl, sg, sg_size, i) { - to = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + to = kmap_atomic(sg_page(sg)); memcpy(to + sg->offset, p, sg->length); - kunmap_atomic(to, KM_SOFTIRQ0); + kunmap_atomic(to); p += sg->length; } } diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index e28877c4ce15..14224ba44fd8 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -274,6 +274,18 @@ static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id) ib_conn->cma_id = NULL; kfree(ib_conn->page_vec); + if (ib_conn->login_buf) { + if (ib_conn->login_req_dma) + ib_dma_unmap_single(ib_conn->device->ib_device, + ib_conn->login_req_dma, + ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE); + if (ib_conn->login_resp_dma) + ib_dma_unmap_single(ib_conn->device->ib_device, + ib_conn->login_resp_dma, + ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); + kfree(ib_conn->login_buf); + } + return 0; } diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 0bfa545675b8..bcbf22ee0aa7 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -30,6 +30,8 @@ * SOFTWARE. */ +#define pr_fmt(fmt) PFX fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -165,7 +167,7 @@ static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) static void srp_qp_event(struct ib_event *event, void *context) { - printk(KERN_ERR PFX "QP event %d\n", event->event); + pr_debug("QP event %d\n", event->event); } static int srp_init_qp(struct srp_target_port *target, @@ -472,6 +474,21 @@ static void srp_free_req_data(struct srp_target_port *target) } } +/** + * srp_del_scsi_host_attr() - Remove attributes defined in the host template. + * @shost: SCSI host whose attributes to remove from sysfs. + * + * Note: Any attributes defined in the host template and that did not exist + * before invocation of this function will be ignored. + */ +static void srp_del_scsi_host_attr(struct Scsi_Host *shost) +{ + struct device_attribute **attr; + + for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr) + device_remove_file(&shost->shost_dev, *attr); +} + static void srp_remove_work(struct work_struct *work) { struct srp_target_port *target = @@ -484,6 +501,7 @@ static void srp_remove_work(struct work_struct *work) list_del(&target->list); spin_unlock(&target->srp_host->target_lock); + srp_del_scsi_host_attr(target->scsi_host); srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); ib_destroy_cm_id(target->cm_id); @@ -1676,10 +1694,6 @@ static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "0x%016llx\n", (unsigned long long) be64_to_cpu(target->id_ext)); } @@ -1689,10 +1703,6 @@ static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "0x%016llx\n", (unsigned long long) be64_to_cpu(target->ioc_guid)); } @@ -1702,10 +1712,6 @@ static ssize_t show_service_id(struct device *dev, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "0x%016llx\n", (unsigned long long) be64_to_cpu(target->service_id)); } @@ -1715,10 +1721,6 @@ static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey)); } @@ -1727,10 +1729,6 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "%pI6\n", target->path.dgid.raw); } @@ -1739,10 +1737,6 @@ static ssize_t show_orig_dgid(struct device *dev, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "%pI6\n", target->orig_dgid); } @@ -1751,10 +1745,6 @@ static ssize_t show_req_lim(struct device *dev, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "%d\n", target->req_lim); } @@ -1763,10 +1753,6 @@ static ssize_t show_zero_req_lim(struct device *dev, { struct srp_target_port *target = host_to_target(class_to_shost(dev)); - if (target->state == SRP_TARGET_DEAD || - target->state == SRP_TARGET_REMOVED) - return -ENODEV; - return sprintf(buf, "%d\n", target->zero_req_lim); } @@ -1989,7 +1975,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) goto out; } if (strlen(p) != 32) { - printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); + pr_warn("bad dest GID parameter '%s'\n", p); kfree(p); goto out; } @@ -2004,7 +1990,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_PKEY: if (match_hex(args, &token)) { - printk(KERN_WARNING PFX "bad P_Key parameter '%s'\n", p); + pr_warn("bad P_Key parameter '%s'\n", p); goto out; } target->path.pkey = cpu_to_be16(token); @@ -2023,7 +2009,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_MAX_SECT: if (match_int(args, &token)) { - printk(KERN_WARNING PFX "bad max sect parameter '%s'\n", p); + pr_warn("bad max sect parameter '%s'\n", p); goto out; } target->scsi_host->max_sectors = token; @@ -2031,7 +2017,8 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_MAX_CMD_PER_LUN: if (match_int(args, &token)) { - printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p); + pr_warn("bad max cmd_per_lun parameter '%s'\n", + p); goto out; } target->scsi_host->cmd_per_lun = min(token, SRP_CMD_SQ_SIZE); @@ -2039,14 +2026,14 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_IO_CLASS: if (match_hex(args, &token)) { - printk(KERN_WARNING PFX "bad IO class parameter '%s' \n", p); + pr_warn("bad IO class parameter '%s'\n", p); goto out; } if (token != SRP_REV10_IB_IO_CLASS && token != SRP_REV16A_IB_IO_CLASS) { - printk(KERN_WARNING PFX "unknown IO class parameter value" - " %x specified (use %x or %x).\n", - token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS); + pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n", + token, SRP_REV10_IB_IO_CLASS, + SRP_REV16A_IB_IO_CLASS); goto out; } target->io_class = token; @@ -2064,7 +2051,8 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_CMD_SG_ENTRIES: if (match_int(args, &token) || token < 1 || token > 255) { - printk(KERN_WARNING PFX "bad max cmd_sg_entries parameter '%s'\n", p); + pr_warn("bad max cmd_sg_entries parameter '%s'\n", + p); goto out; } target->cmd_sg_cnt = token; @@ -2072,7 +2060,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_ALLOW_EXT_SG: if (match_int(args, &token)) { - printk(KERN_WARNING PFX "bad allow_ext_sg parameter '%s'\n", p); + pr_warn("bad allow_ext_sg parameter '%s'\n", p); goto out; } target->allow_ext_sg = !!token; @@ -2081,15 +2069,16 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) case SRP_OPT_SG_TABLESIZE: if (match_int(args, &token) || token < 1 || token > SCSI_MAX_SG_CHAIN_SEGMENTS) { - printk(KERN_WARNING PFX "bad max sg_tablesize parameter '%s'\n", p); + pr_warn("bad max sg_tablesize parameter '%s'\n", + p); goto out; } target->sg_tablesize = token; break; default: - printk(KERN_WARNING PFX "unknown parameter or missing value " - "'%s' in target creation request\n", p); + pr_warn("unknown parameter or missing value '%s' in target creation request\n", + p); goto out; } } @@ -2100,9 +2089,8 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i) if ((srp_opt_tokens[i].token & SRP_OPT_ALL) && !(srp_opt_tokens[i].token & opt_mask)) - printk(KERN_WARNING PFX "target creation request is " - "missing parameter '%s'\n", - srp_opt_tokens[i].pattern); + pr_warn("target creation request is missing parameter '%s'\n", + srp_opt_tokens[i].pattern); out: kfree(options); @@ -2149,7 +2137,7 @@ static ssize_t srp_create_target(struct device *dev, if (!host->srp_dev->fmr_pool && !target->allow_ext_sg && target->cmd_sg_cnt < target->sg_tablesize) { - printk(KERN_WARNING PFX "No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); + pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); target->sg_tablesize = target->cmd_sg_cnt; } @@ -2309,8 +2297,7 @@ static void srp_add_one(struct ib_device *device) return; if (ib_query_device(device, dev_attr)) { - printk(KERN_WARNING PFX "Query device failed for %s\n", - device->name); + pr_warn("Query device failed for %s\n", device->name); goto free_attr; } @@ -2429,6 +2416,7 @@ static void srp_remove_one(struct ib_device *device) list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { + srp_del_scsi_host_attr(target->scsi_host); srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); srp_disconnect_target(target); @@ -2459,7 +2447,7 @@ static int __init srp_init_module(void) BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); if (srp_sg_tablesize) { - printk(KERN_WARNING PFX "srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); + pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); if (!cmd_sg_entries) cmd_sg_entries = srp_sg_tablesize; } @@ -2468,14 +2456,15 @@ static int __init srp_init_module(void) cmd_sg_entries = SRP_DEF_SG_TABLESIZE; if (cmd_sg_entries > 255) { - printk(KERN_WARNING PFX "Clamping cmd_sg_entries to 255\n"); + pr_warn("Clamping cmd_sg_entries to 255\n"); cmd_sg_entries = 255; } if (!indirect_sg_entries) indirect_sg_entries = cmd_sg_entries; else if (indirect_sg_entries < cmd_sg_entries) { - printk(KERN_WARNING PFX "Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", cmd_sg_entries); + pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", + cmd_sg_entries); indirect_sg_entries = cmd_sg_entries; } @@ -2486,7 +2475,7 @@ static int __init srp_init_module(void) ret = class_register(&srp_class); if (ret) { - printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); + pr_err("couldn't register class infiniband_srp\n"); srp_release_transport(ib_srp_transport_template); return ret; } @@ -2495,7 +2484,7 @@ static int __init srp_init_module(void) ret = ib_register_client(&srp_client); if (ret) { - printk(KERN_ERR PFX "couldn't register IB client\n"); + pr_err("couldn't register IB client\n"); srp_release_transport(ib_srp_transport_template); ib_sa_unregister_client(&srp_sa_client); class_unregister(&srp_class); diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 4daf9e5a7736..20e5c2cda430 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -137,7 +137,7 @@ extern struct device_attribute macio_dev_attrs[]; struct bus_type macio_bus_type = { .name = "macio", .match = macio_bus_match, - .uevent = of_device_uevent, + .uevent = of_device_uevent_modalias, .probe = macio_device_probe, .remove = macio_device_remove, .shutdown = macio_device_shutdown, diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index cdf36b1e9aa6..045e086144ad 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -457,7 +457,7 @@ void bitmap_update_sb(struct bitmap *bitmap) return; } spin_unlock_irqrestore(&bitmap->lock, flags); - sb = kmap_atomic(bitmap->sb_page, KM_USER0); + sb = kmap_atomic(bitmap->sb_page); sb->events = cpu_to_le64(bitmap->mddev->events); if (bitmap->mddev->events < bitmap->events_cleared) /* rocking back to read-only */ @@ -467,7 +467,7 @@ void bitmap_update_sb(struct bitmap *bitmap) /* Just in case these have been changed via sysfs: */ sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ); sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind); - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); write_page(bitmap, bitmap->sb_page, 1); } @@ -478,7 +478,7 @@ void bitmap_print_sb(struct bitmap *bitmap) if (!bitmap || !bitmap->sb_page) return; - sb = kmap_atomic(bitmap->sb_page, KM_USER0); + sb = kmap_atomic(bitmap->sb_page); printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap)); printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic)); printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version)); @@ -497,7 +497,7 @@ void bitmap_print_sb(struct bitmap *bitmap) printk(KERN_DEBUG " sync size: %llu KB\n", (unsigned long long)le64_to_cpu(sb->sync_size)/2); printk(KERN_DEBUG "max write behind: %d\n", le32_to_cpu(sb->write_behind)); - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); } /* @@ -525,7 +525,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) } bitmap->sb_page->index = 0; - sb = kmap_atomic(bitmap->sb_page, KM_USER0); + sb = kmap_atomic(bitmap->sb_page); sb->magic = cpu_to_le32(BITMAP_MAGIC); sb->version = cpu_to_le32(BITMAP_MAJOR_HI); @@ -533,7 +533,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) chunksize = bitmap->mddev->bitmap_info.chunksize; BUG_ON(!chunksize); if (!is_power_of_2(chunksize)) { - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); printk(KERN_ERR "bitmap chunksize not a power of 2\n"); return -EINVAL; } @@ -571,7 +571,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) bitmap->flags |= BITMAP_HOSTENDIAN; sb->version = cpu_to_le32(BITMAP_MAJOR_HOSTENDIAN); - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); return 0; } @@ -603,7 +603,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) return err; } - sb = kmap_atomic(bitmap->sb_page, KM_USER0); + sb = kmap_atomic(bitmap->sb_page); chunksize = le32_to_cpu(sb->chunksize); daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ; @@ -664,7 +664,7 @@ success: bitmap->events_cleared = bitmap->mddev->events; err = 0; out: - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); if (err) bitmap_print_sb(bitmap); return err; @@ -689,7 +689,7 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, return 0; } spin_unlock_irqrestore(&bitmap->lock, flags); - sb = kmap_atomic(bitmap->sb_page, KM_USER0); + sb = kmap_atomic(bitmap->sb_page); old = le32_to_cpu(sb->state) & bits; switch (op) { case MASK_SET: @@ -703,7 +703,7 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, default: BUG(); } - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); return old; } @@ -881,12 +881,12 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) bit = file_page_offset(bitmap, chunk); /* set the bit */ - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (bitmap->flags & BITMAP_HOSTENDIAN) set_bit(bit, kaddr); else __set_bit_le(bit, kaddr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); pr_debug("set file bit %lu page %lu\n", bit, page->index); /* record page number so it gets flushed to disk when unplug occurs */ set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); @@ -1050,10 +1050,10 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) * if bitmap is out of date, dirty the * whole page and write it out */ - paddr = kmap_atomic(page, KM_USER0); + paddr = kmap_atomic(page); memset(paddr + offset, 0xff, PAGE_SIZE - offset); - kunmap_atomic(paddr, KM_USER0); + kunmap_atomic(paddr); write_page(bitmap, page, 1); ret = -EIO; @@ -1061,12 +1061,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) goto err; } } - paddr = kmap_atomic(page, KM_USER0); + paddr = kmap_atomic(page); if (bitmap->flags & BITMAP_HOSTENDIAN) b = test_bit(bit, paddr); else b = test_bit_le(bit, paddr); - kunmap_atomic(paddr, KM_USER0); + kunmap_atomic(paddr); if (b) { /* if the disk bit is set, set the memory bit */ int needed = ((sector_t)(i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) @@ -1209,10 +1209,10 @@ void bitmap_daemon_work(struct mddev *mddev) mddev->bitmap_info.external == 0) { bitmap_super_t *sb; bitmap->need_sync = 0; - sb = kmap_atomic(bitmap->sb_page, KM_USER0); + sb = kmap_atomic(bitmap->sb_page); sb->events_cleared = cpu_to_le64(bitmap->events_cleared); - kunmap_atomic(sb, KM_USER0); + kunmap_atomic(sb); write_page(bitmap, bitmap->sb_page, 1); } spin_lock_irqsave(&bitmap->lock, flags); @@ -1235,7 +1235,7 @@ void bitmap_daemon_work(struct mddev *mddev) -1); /* clear the bit */ - paddr = kmap_atomic(page, KM_USER0); + paddr = kmap_atomic(page); if (bitmap->flags & BITMAP_HOSTENDIAN) clear_bit(file_page_offset(bitmap, j), paddr); @@ -1244,7 +1244,7 @@ void bitmap_daemon_work(struct mddev *mddev) file_page_offset(bitmap, j), paddr); - kunmap_atomic(paddr, KM_USER0); + kunmap_atomic(paddr); } else if (*bmc <= 2) { *bmc = 1; /* maybe clear the bit next time */ set_page_attr(bitmap, page, BITMAP_PAGE_PENDING); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 8c2a000cf3f5..db6b51639cee 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -590,9 +590,9 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, int r = 0; if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) { - src = kmap_atomic(sg_page(&dmreq->sg_in), KM_USER0); + src = kmap_atomic(sg_page(&dmreq->sg_in)); r = crypt_iv_lmk_one(cc, iv, dmreq, src + dmreq->sg_in.offset); - kunmap_atomic(src, KM_USER0); + kunmap_atomic(src); } else memset(iv, 0, cc->iv_size); @@ -608,14 +608,14 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) return 0; - dst = kmap_atomic(sg_page(&dmreq->sg_out), KM_USER0); + dst = kmap_atomic(sg_page(&dmreq->sg_out)); r = crypt_iv_lmk_one(cc, iv, dmreq, dst + dmreq->sg_out.offset); /* Tweak the first block of plaintext sector */ if (!r) crypto_xor(dst + dmreq->sg_out.offset, iv, cc->iv_size); - kunmap_atomic(dst, KM_USER0); + kunmap_atomic(dst); return r; } diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 69cc8166b20b..7338cb2d0a38 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -57,9 +57,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info if (dma->bouncemap[map_offset] == NULL) return -1; local_irq_save(flags); - src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; + src = kmap_atomic(dma->map[map_offset]) + offset; memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); - kunmap_atomic(src, KM_BOUNCE_READ); + kunmap_atomic(src); local_irq_restore(flags); sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset); } diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 5319e9b65847..c37d3756d8d2 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -325,7 +325,7 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) p_cnt = min(p_cnt, length); local_irq_save(flags); - buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; + buf = kmap_atomic(pg) + p_off; } else { buf = host->req->data + host->block_pos; p_cnt = host->req->data_len - host->block_pos; @@ -341,7 +341,7 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) : jmb38x_ms_read_reg_data(host, buf, p_cnt); if (host->req->long_data) { - kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); + kunmap_atomic(buf - p_off); local_irq_restore(flags); } diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 6902b83eb1b4..7bafa72f8f57 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -210,7 +210,7 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) p_cnt = min(p_cnt, length); local_irq_save(flags); - buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off; + buf = kmap_atomic(pg) + p_off; } else { buf = host->req->data + host->block_pos; p_cnt = host->req->data_len - host->block_pos; @@ -221,7 +221,7 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) : tifm_ms_read_data(host, buf, p_cnt); if (host->req->long_data) { - kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ); + kunmap_atomic(buf - p_off); local_irq_restore(flags); } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f147395bac9a..1489c3540f96 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -201,6 +201,7 @@ config MENELAUS config TWL4030_CORE bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" depends on I2C=y && GENERIC_HARDIRQS + select IRQ_DOMAIN help Say yes here if you have TWL4030 / TWL6030 family chip on your board. This core driver provides register access and IRQ handling diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 8ce3959c6919..806680d1bbb4 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -38,6 +38,7 @@ #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/regulator/machine.h> @@ -149,7 +150,7 @@ #define TWL_MODULE_LAST TWL4030_MODULE_LAST -#define TWL4030_NR_IRQS 8 +#define TWL4030_NR_IRQS 34 /* core:8, power:8, gpio: 18 */ #define TWL6030_NR_IRQS 20 /* Base Address defns for twl4030_map[] */ @@ -263,10 +264,6 @@ struct twl_client { static struct twl_client twl_modules[TWL_NUM_SLAVES]; -#ifdef CONFIG_IRQ_DOMAIN -static struct irq_domain domain; -#endif - /* mapping the module id to slave id and base address */ struct twl_mapping { unsigned char sid; /* Slave ID */ @@ -621,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, unsigned num_consumers, unsigned long features) { unsigned sub_chip_id; + struct twl_regulator_driver_data drv_data; + /* regulator framework demands init_data ... */ if (!pdata) return NULL; @@ -630,7 +629,19 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, pdata->num_consumer_supplies = num_consumers; } - pdata->driver_data = (void *)features; + if (pdata->driver_data) { + /* If we have existing drv_data, just add the flags */ + struct twl_regulator_driver_data *tmp; + tmp = pdata->driver_data; + tmp->features |= features; + } else { + /* add new driver data struct, used only during init */ + drv_data.features = features; + drv_data.set_voltage = NULL; + drv_data.get_voltage = NULL; + drv_data.data = NULL; + pdata->driver_data = &drv_data; + } /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; @@ -753,9 +764,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* we need to connect regulators to this transceiver */ if (twl_has_regulator() && child) { - usb1v5.dev = child; - usb1v8.dev = child; - usb3v1.dev = child; + usb1v5.dev_name = dev_name(child); + usb1v8.dev_name = dev_name(child); + usb3v1.dev_name = dev_name(child); } } if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { @@ -801,7 +812,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) return PTR_ERR(child); /* we need to connect regulators to this transceiver */ if (twl_has_regulator() && child) - usb3v3.dev = child; + usb3v3.dev_name = dev_name(child); } else if (twl_has_regulator() && twl_class_is_6030()) { if (features & TWL6025_SUBCLASS) child = add_regulator(TWL6025_REG_LDOUSB, @@ -937,6 +948,31 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* twl6030 regulators */ if (twl_has_regulator() && twl_class_is_6030() && !(features & TWL6025_SUBCLASS)) { + child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VDD2, pdata->vdd2, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VDD3, pdata->vdd3, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_V1V8, pdata->v1v8, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_V2V1, pdata->v2v1, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc, features); if (IS_ERR(child)) @@ -1227,14 +1263,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) pdata->irq_base = status; pdata->irq_end = pdata->irq_base + nr_irqs; - -#ifdef CONFIG_IRQ_DOMAIN - domain.irq_base = pdata->irq_base; - domain.nr_irq = nr_irqs; - domain.of_node = of_node_get(node); - domain.ops = &irq_domain_simple_ops; - irq_domain_add(&domain); -#endif + irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0, + &irq_domain_simple_ops, NULL); if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); @@ -1315,11 +1345,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); } -#ifdef CONFIG_OF_DEVICE + status = -ENODEV; if (node) status = of_platform_populate(node, NULL, NULL, &client->dev); - else -#endif + if (status) status = add_children(pdata, id->driver_data); fail: diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 352d4797865b..75a485448796 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -56,6 +56,7 @@ #include <linux/mmc/sh_mmcif.h> #include <linux/pagemap.h> #include <linux/platform_device.h> +#include <linux/pm_qos.h> #include <linux/pm_runtime.h> #include <linux/spinlock.h> #include <linux/module.h> @@ -1346,6 +1347,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) if (ret < 0) goto clean_up5; + dev_pm_qos_expose_latency_limit(&pdev->dev, 100); + dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); dev_dbg(&pdev->dev, "chip ver H'%04x\n", sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); @@ -1376,6 +1379,8 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) host->dying = true; pm_runtime_get_sync(&pdev->dev); + dev_pm_qos_hide_latency_limit(&pdev->dev); + mmc_remove_host(host->mmc); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 5f9ad74fbf80..e21988901c36 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -39,6 +39,7 @@ #include <linux/module.h> #include <linux/pagemap.h> #include <linux/platform_device.h> +#include <linux/pm_qos.h> #include <linux/pm_runtime.h> #include <linux/scatterlist.h> #include <linux/spinlock.h> @@ -955,6 +956,8 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc_add_host(mmc); + dev_pm_qos_expose_latency_limit(&pdev->dev, 100); + /* Unmask the IRQs we want to know about */ if (!_host->chan_rx) irq_mask |= TMIO_MASK_READOP; @@ -993,6 +996,8 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) || host->mmc->caps & MMC_CAP_NONREMOVABLE) pm_runtime_get_sync(&pdev->dev); + dev_pm_qos_hide_latency_limit(&pdev->dev); + mmc_remove_host(host->mmc); cancel_work_sync(&host->done); cancel_delayed_work_sync(&host->delayed_reset_work); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0730203a19f2..b920d829692a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2573,12 +2573,16 @@ re_arm: static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan; + struct net_device *vlan_dev; - if (ip == bond->master_ip) + if (ip == bond_confirm_addr(bond->dev, 0, ip)) return 1; list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - if (ip == vlan->vlan_ip) + rcu_read_lock(); + vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id); + rcu_read_unlock(); + if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip)) return 1; } @@ -2620,17 +2624,19 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) int i, vlan_id; __be32 *targets = bond->params.arp_targets; struct vlan_entry *vlan; - struct net_device *vlan_dev; + struct net_device *vlan_dev = NULL; struct rtable *rt; for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { + __be32 addr; if (!targets[i]) break; pr_debug("basa: target %x\n", targets[i]); if (!bond_vlan_used(bond)) { pr_debug("basa: empty vlan: arp_send\n"); + addr = bond_confirm_addr(bond->dev, targets[i], 0); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], - bond->master_ip, 0); + addr, 0); continue; } @@ -2655,8 +2661,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) if (rt->dst.dev == bond->dev) { ip_rt_put(rt); pr_debug("basa: rtdev == bond->dev: arp_send\n"); + addr = bond_confirm_addr(bond->dev, targets[i], 0); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], - bond->master_ip, 0); + addr, 0); continue; } @@ -2674,10 +2681,11 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } } - if (vlan_id) { + if (vlan_id && vlan_dev) { ip_rt_put(rt); + addr = bond_confirm_addr(vlan_dev, targets[i], 0); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], - vlan->vlan_ip, vlan_id); + addr, vlan_id); continue; } @@ -3299,68 +3307,10 @@ static int bond_netdev_event(struct notifier_block *this, return NOTIFY_DONE; } -/* - * bond_inetaddr_event: handle inetaddr notifier chain events. - * - * We keep track of device IPs primarily to use as source addresses in - * ARP monitor probes (rather than spewing out broadcasts all the time). - * - * We track one IP for the main device (if it has one), plus one per VLAN. - */ -static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct in_ifaddr *ifa = ptr; - struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev; - struct bond_net *bn = net_generic(dev_net(event_dev), bond_net_id); - struct bonding *bond; - struct vlan_entry *vlan; - - /* we only care about primary address */ - if(ifa->ifa_flags & IFA_F_SECONDARY) - return NOTIFY_DONE; - - list_for_each_entry(bond, &bn->dev_list, bond_list) { - if (bond->dev == event_dev) { - switch (event) { - case NETDEV_UP: - bond->master_ip = ifa->ifa_local; - return NOTIFY_OK; - case NETDEV_DOWN: - bond->master_ip = 0; - return NOTIFY_OK; - default: - return NOTIFY_DONE; - } - } - - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = __vlan_find_dev_deep(bond->dev, - vlan->vlan_id); - if (vlan_dev == event_dev) { - switch (event) { - case NETDEV_UP: - vlan->vlan_ip = ifa->ifa_local; - return NOTIFY_OK; - case NETDEV_DOWN: - vlan->vlan_ip = 0; - return NOTIFY_OK; - default: - return NOTIFY_DONE; - } - } - } - } - return NOTIFY_DONE; -} - static struct notifier_block bond_netdev_notifier = { .notifier_call = bond_netdev_event, }; -static struct notifier_block bond_inetaddr_notifier = { - .notifier_call = bond_inetaddr_event, -}; - /*---------------------------- Hashing Policies -----------------------------*/ /* @@ -4929,7 +4879,6 @@ static int __init bonding_init(void) } register_netdevice_notifier(&bond_netdev_notifier); - register_inetaddr_notifier(&bond_inetaddr_notifier); out: return res; err: @@ -4943,7 +4892,6 @@ err_link: static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); - unregister_inetaddr_notifier(&bond_inetaddr_notifier); bond_destroy_debugfs(); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 1aecc37e5b4d..9f2bae6616d3 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -21,6 +21,7 @@ #include <linux/cpumask.h> #include <linux/in6.h> #include <linux/netpoll.h> +#include <linux/inetdevice.h> #include "bond_3ad.h" #include "bond_alb.h" @@ -166,7 +167,6 @@ struct bond_parm_tbl { struct vlan_entry { struct list_head vlan_list; - __be32 vlan_ip; unsigned short vlan_id; }; @@ -232,7 +232,6 @@ struct bonding { struct list_head bond_list; struct netdev_hw_addr_list mc_list; int (*xmit_hash_policy)(struct sk_buff *, int); - __be32 master_ip; u16 rr_tx_counter; struct ad_bond_info ad_info; struct alb_bond_info alb_info; @@ -378,6 +377,21 @@ static inline bool bond_is_slave_inactive(struct slave *slave) return slave->inactive; } +static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be32 local) +{ + struct in_device *in_dev; + __be32 addr = 0; + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + + if (in_dev) + addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST); + + rcu_read_unlock(); + return addr; +} + struct bond_net; struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index 7b65716b8734..c95e7b5e2b85 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -47,6 +47,7 @@ #include "bnx2x/bnx2x_hsi.h" #include "../../../scsi/bnx2i/57xx_iscsi_constants.h" #include "../../../scsi/bnx2i/57xx_iscsi_hsi.h" +#include "../../../scsi/bnx2fc/bnx2fc_constants.h" #include "cnic.h" #include "cnic_defs.h" @@ -2547,7 +2548,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe) } kcqe.kcqe_op_flag = kcqe_op << KCQE_FLAGS_OPCODE_SHIFT; kcqe.kcqe_op_flag |= KCQE_FLAGS_LAYER_MASK_L5_FCOE; - kcqe.kcqe_info1 = FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR; + kcqe.kcqe_info1 = FCOE_KCQE_COMPLETION_STATUS_PARITY_ERROR; kcqe.kcqe_info2 = cid; kcqe.kcqe_info0 = l5_cid; @@ -2558,7 +2559,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe) kcqe.kcqe_op_flag = (opcode + 0x10) << KCQE_FLAGS_OPCODE_SHIFT; kcqe.kcqe_op_flag |= KCQE_FLAGS_LAYER_MASK_L5_ISCSI; - kcqe.kcqe_info1 = ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR; + kcqe.kcqe_info1 = ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR; kcqe.kcqe_info2 = cid; cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &kcqe.kcqe_info0); @@ -2577,7 +2578,7 @@ static void cnic_bnx2x_kwqe_err(struct cnic_dev *dev, struct kwqe *kwqe) kcqe.kcqe_op_flag = (kcqe_op << KCQE_FLAGS_OPCODE_SHIFT) | KCQE_FLAGS_LAYER_MASK_L4; - l4kcqe->status = L4_KCQE_COMPLETION_STATUS_NIC_ERROR; + l4kcqe->status = L4_KCQE_COMPLETION_STATUS_PARITY_ERROR; l4kcqe->cid = cid; cnic_get_l5_cid(cp, BNX2X_SW_CID(cid), &l4kcqe->conn_id); } else { @@ -3933,7 +3934,8 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe) case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE: if (l4kcqe->status == 0) set_bit(SK_F_OFFLD_COMPLETE, &csk->flags); - else if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_NIC_ERROR) + else if (l4kcqe->status == + L4_KCQE_COMPLETION_STATUS_PARITY_ERROR) set_bit(SK_F_HW_ERR, &csk->flags); smp_mb__before_clear_bit(); @@ -3946,7 +3948,7 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe) case L4_KCQE_OPCODE_VALUE_RESET_COMP: case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE: case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD: - if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_NIC_ERROR) + if (l4kcqe->status == L4_KCQE_COMPLETION_STATUS_PARITY_ERROR) set_bit(SK_F_HW_ERR, &csk->flags); cp->close_conn(csk, opcode); diff --git a/drivers/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h index 06ca00266d70..382c98b0cc0c 100644 --- a/drivers/net/ethernet/broadcom/cnic_defs.h +++ b/drivers/net/ethernet/broadcom/cnic_defs.h @@ -35,16 +35,6 @@ #define L5CM_RAMROD_CMD_ID_SEARCHER_DELETE (L5CM_RAMROD_CMD_ID_BASE + 14) #define L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD (L5CM_RAMROD_CMD_ID_BASE + 15) -#define FCOE_KCQE_OPCODE_INIT_FUNC (0x10) -#define FCOE_KCQE_OPCODE_DESTROY_FUNC (0x11) -#define FCOE_KCQE_OPCODE_STAT_FUNC (0x12) -#define FCOE_KCQE_OPCODE_OFFLOAD_CONN (0x15) -#define FCOE_KCQE_OPCODE_ENABLE_CONN (0x16) -#define FCOE_KCQE_OPCODE_DISABLE_CONN (0x17) -#define FCOE_KCQE_OPCODE_DESTROY_CONN (0x18) -#define FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20) -#define FCOE_KCQE_OPCODE_FCOE_ERROR (0x21) - #define FCOE_RAMROD_CMD_ID_INIT_FUNC (FCOE_KCQE_OPCODE_INIT_FUNC) #define FCOE_RAMROD_CMD_ID_DESTROY_FUNC (FCOE_KCQE_OPCODE_DESTROY_FUNC) #define FCOE_RAMROD_CMD_ID_STAT_FUNC (FCOE_KCQE_OPCODE_STAT_FUNC) @@ -54,23 +44,6 @@ #define FCOE_RAMROD_CMD_ID_DESTROY_CONN (FCOE_KCQE_OPCODE_DESTROY_CONN) #define FCOE_RAMROD_CMD_ID_TERMINATE_CONN (0x81) -#define FCOE_KWQE_OPCODE_INIT1 (0) -#define FCOE_KWQE_OPCODE_INIT2 (1) -#define FCOE_KWQE_OPCODE_INIT3 (2) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN1 (3) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN2 (4) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN3 (5) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN4 (6) -#define FCOE_KWQE_OPCODE_ENABLE_CONN (7) -#define FCOE_KWQE_OPCODE_DISABLE_CONN (8) -#define FCOE_KWQE_OPCODE_DESTROY_CONN (9) -#define FCOE_KWQE_OPCODE_DESTROY (10) -#define FCOE_KWQE_OPCODE_STAT (11) - -#define FCOE_KCQE_COMPLETION_STATUS_ERROR (0x1) -#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x3) -#define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR (0x5) - /* KCQ (kernel completion queue) response op codes */ #define L4_KCQE_OPCODE_VALUE_CLOSE_COMP (53) #define L4_KCQE_OPCODE_VALUE_RESET_COMP (54) @@ -87,6 +60,7 @@ /* KCQ (kernel completion queue) completion status */ #define L4_KCQE_COMPLETION_STATUS_SUCCESS (0) #define L4_KCQE_COMPLETION_STATUS_NIC_ERROR (4) +#define L4_KCQE_COMPLETION_STATUS_PARITY_ERROR (0x81) #define L4_KCQE_COMPLETION_STATUS_TIMEOUT (0x93) #define L4_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAIL (0x83) diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h index 60deb84d36bd..289274e546be 100644 --- a/drivers/net/ethernet/broadcom/cnic_if.h +++ b/drivers/net/ethernet/broadcom/cnic_if.h @@ -12,8 +12,8 @@ #ifndef CNIC_IF_H #define CNIC_IF_H -#define CNIC_MODULE_VERSION "2.5.9" -#define CNIC_MODULE_RELDATE "Feb 8, 2012" +#define CNIC_MODULE_VERSION "2.5.10" +#define CNIC_MODULE_RELDATE "March 21, 2012" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index b0657466041d..7b71387cf93c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -89,10 +89,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 122 +#define TG3_MIN_NUM 123 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "December 7, 2011" +#define DRV_MODULE_RELDATE "March 21, 2012" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 @@ -5953,8 +5953,10 @@ next_pkt_nopost: tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask; tpr->rx_jmb_prod_idx = jmb_prod_idx & tp->rx_jmb_ring_mask; - if (tnapi != &tp->napi[1]) + if (tnapi != &tp->napi[1]) { + tp->rx_refill = true; napi_schedule(&tp->napi[1].napi); + } } return received; @@ -6134,6 +6136,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) u32 std_prod_idx = dpr->rx_std_prod_idx; u32 jmb_prod_idx = dpr->rx_jmb_prod_idx; + tp->rx_refill = false; for (i = 1; i < tp->irq_cnt; i++) err |= tg3_rx_prodring_xfer(tp, dpr, &tp->napi[i].prodring); @@ -6197,9 +6200,25 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) /* check for RX/TX work to do */ if (likely(sblk->idx[0].tx_consumer == tnapi->tx_cons && *(tnapi->rx_rcb_prod_idx) == tnapi->rx_rcb_ptr)) { + + /* This test here is not race free, but will reduce + * the number of interrupts by looping again. + */ + if (tnapi == &tp->napi[1] && tp->rx_refill) + continue; + napi_complete(napi); /* Reenable interrupts. */ tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24); + + /* This test here is synchronized by napi_schedule() + * and napi_complete() to close the race condition. + */ + if (unlikely(tnapi == &tp->napi[1] && tp->rx_refill)) { + tw32(HOSTCC_MODE, tp->coalesce_mode | + HOSTCC_MODE_ENABLE | + tnapi->coal_now); + } mmiowb(); break; } diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 66bcfca55261..93865f899a4f 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -3007,6 +3007,7 @@ struct tg3 { u32 rx_std_max_post; u32 rx_offset; u32 rx_pkt_map_sz; + bool rx_refill; /* begin "everything else" cacheline(s) section */ diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index d9428f0e738a..e7bed5303997 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -968,7 +968,6 @@ static int gfar_probe(struct platform_device *ofdev) struct gfar_private *priv = NULL; struct gfar __iomem *regs = NULL; int err = 0, i, grp_idx = 0; - int len_devname; u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0; u32 isrg = 0; u32 __iomem *baddr; @@ -1169,40 +1168,16 @@ static int gfar_probe(struct platform_device *ofdev) priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); /* fill out IRQ number and name fields */ - len_devname = strlen(dev->name); for (i = 0; i < priv->num_grps; i++) { - strncpy(&priv->gfargrp[i].int_name_tx[0], dev->name, - len_devname); if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - strncpy(&priv->gfargrp[i].int_name_tx[len_devname], - "_g", sizeof("_g")); - priv->gfargrp[i].int_name_tx[ - strlen(priv->gfargrp[i].int_name_tx)] = i+48; - strncpy(&priv->gfargrp[i].int_name_tx[strlen( - priv->gfargrp[i].int_name_tx)], - "_tx", sizeof("_tx") + 1); - - strncpy(&priv->gfargrp[i].int_name_rx[0], dev->name, - len_devname); - strncpy(&priv->gfargrp[i].int_name_rx[len_devname], - "_g", sizeof("_g")); - priv->gfargrp[i].int_name_rx[ - strlen(priv->gfargrp[i].int_name_rx)] = i+48; - strncpy(&priv->gfargrp[i].int_name_rx[strlen( - priv->gfargrp[i].int_name_rx)], - "_rx", sizeof("_rx") + 1); - - strncpy(&priv->gfargrp[i].int_name_er[0], dev->name, - len_devname); - strncpy(&priv->gfargrp[i].int_name_er[len_devname], - "_g", sizeof("_g")); - priv->gfargrp[i].int_name_er[strlen( - priv->gfargrp[i].int_name_er)] = i+48; - strncpy(&priv->gfargrp[i].int_name_er[strlen(\ - priv->gfargrp[i].int_name_er)], - "_er", sizeof("_er") + 1); + sprintf(priv->gfargrp[i].int_name_tx, "%s%s%c%s", + dev->name, "_g", '0' + i, "_tx"); + sprintf(priv->gfargrp[i].int_name_rx, "%s%s%c%s", + dev->name, "_g", '0' + i, "_rx"); + sprintf(priv->gfargrp[i].int_name_er, "%s%s%c%s", + dev->name, "_g", '0' + i, "_er"); } else - priv->gfargrp[i].int_name_tx[len_devname] = '\0'; + strcpy(priv->gfargrp[i].int_name_tx, dev->name); } /* Initialize the filer table */ diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index fc2488adca36..4c9f8d487dbb 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -517,7 +517,7 @@ extern const char gfar_driver_version[]; #define RXFCB_PERR_MASK 0x000c #define RXFCB_PERR_BADL3 0x0008 -#define GFAR_INT_NAME_MAX IFNAMSIZ + 4 +#define GFAR_INT_NAME_MAX (IFNAMSIZ + 6) /* '_g#_xx' */ struct txbd8 { diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 6419a88a69e6..0e9aec8f6917 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -4101,11 +4101,9 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter, if (length <= copybreak && skb_tailroom(skb) >= length) { u8 *vaddr; - vaddr = kmap_atomic(buffer_info->page, - KM_SKB_DATA_SOFTIRQ); + vaddr = kmap_atomic(buffer_info->page); memcpy(skb_tail_pointer(skb), vaddr, length); - kunmap_atomic(vaddr, - KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(vaddr); /* re-use the page, so don't erase * buffer_info->page */ skb_put(skb, length); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index a9a4ea2c616e..7152eb11b7b9 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1301,10 +1301,9 @@ static bool e1000_clean_rx_irq_ps(struct e1000_ring *rx_ring, int *work_done, ps_page->dma, PAGE_SIZE, DMA_FROM_DEVICE); - vaddr = kmap_atomic(ps_page->page, - KM_SKB_DATA_SOFTIRQ); + vaddr = kmap_atomic(ps_page->page); memcpy(skb_tail_pointer(skb), vaddr, l1); - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(vaddr); dma_sync_single_for_device(&pdev->dev, ps_page->dma, PAGE_SIZE, @@ -1503,12 +1502,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done, if (length <= copybreak && skb_tailroom(skb) >= length) { u8 *vaddr; - vaddr = kmap_atomic(buffer_info->page, - KM_SKB_DATA_SOFTIRQ); + vaddr = kmap_atomic(buffer_info->page); memcpy(skb_tail_pointer(skb), vaddr, length); - kunmap_atomic(vaddr, - KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(vaddr); /* re-use the page, so don't erase * buffer_info->page */ skb_put(skb, length); diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 82c2c86a1951..423a1a2a702e 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -95,6 +95,10 @@ static int disable_msi = 0; module_param(disable_msi, int, 0); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); +static int legacy_pme = 0; +module_param(legacy_pme, int, 0); +MODULE_PARM_DESC(legacy_pme, "Legacy power management"); + static DEFINE_PCI_DEVICE_TABLE(sky2_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */ @@ -867,6 +871,13 @@ static void sky2_wol_init(struct sky2_port *sky2) /* Disable PiG firmware */ sky2_write16(hw, B0_CTST, Y2_HW_WOL_OFF); + /* Needed by some broken BIOSes, use PCI rather than PCI-e for WOL */ + if (legacy_pme) { + u32 reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + reg1 |= PCI_Y2_PME_LEGACY; + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + } + /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_read32(hw, B0_CTST); diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 9129ace02560..3b6f8efbf141 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -79,7 +79,8 @@ enum { (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ (1ull << MLX4_EVENT_TYPE_CMD) | \ (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL) | \ - (1ull << MLX4_EVENT_TYPE_FLR_EVENT)) + (1ull << MLX4_EVENT_TYPE_FLR_EVENT) | \ + (1ull << MLX4_EVENT_TYPE_FATAL_WARNING)) static void eq_set_ci(struct mlx4_eq *eq, int req_not) { @@ -443,6 +444,35 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) queue_work(priv->mfunc.master.comm_wq, &priv->mfunc.master.slave_flr_event_work); break; + + case MLX4_EVENT_TYPE_FATAL_WARNING: + if (eqe->subtype == MLX4_FATAL_WARNING_SUBTYPE_WARMING) { + if (mlx4_is_master(dev)) + for (i = 0; i < dev->num_slaves; i++) { + mlx4_dbg(dev, "%s: Sending " + "MLX4_FATAL_WARNING_SUBTYPE_WARMING" + " to slave: %d\n", __func__, i); + if (i == dev->caps.function) + continue; + mlx4_slave_event(dev, i, eqe); + } + mlx4_err(dev, "Temperature Threshold was reached! " + "Threshold: %d celsius degrees; " + "Current Temperature: %d\n", + be16_to_cpu(eqe->event.warming.warning_threshold), + be16_to_cpu(eqe->event.warming.current_temperature)); + } else + mlx4_warn(dev, "Unhandled event FATAL WARNING (%02x), " + "subtype %02x on EQ %d at index %u. owner=%x, " + "nent=0x%x, slave=%x, ownership=%s\n", + eqe->type, eqe->subtype, eq->eqn, + eq->cons_index, eqe->owner, eq->nent, + eqe->slave_id, + !!(eqe->owner & 0x80) ^ + !!(eq->cons_index & eq->nent) ? "HW" : "SW"); + + break; + case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: case MLX4_EVENT_TYPE_ECC_DETECT: default: diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 5f15014713bc..8bb05b46db86 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -394,7 +394,7 @@ static int mlx4_how_many_lives_vf(struct mlx4_dev *dev) return ret; } -static int mlx4_is_slave_active(struct mlx4_dev *dev, int slave) +int mlx4_is_slave_active(struct mlx4_dev *dev, int slave) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_slave_state *s_slave; @@ -646,6 +646,99 @@ out: return err ? err : count; } +enum ibta_mtu { + IB_MTU_256 = 1, + IB_MTU_512 = 2, + IB_MTU_1024 = 3, + IB_MTU_2048 = 4, + IB_MTU_4096 = 5 +}; + +static inline int int_to_ibta_mtu(int mtu) +{ + switch (mtu) { + case 256: return IB_MTU_256; + case 512: return IB_MTU_512; + case 1024: return IB_MTU_1024; + case 2048: return IB_MTU_2048; + case 4096: return IB_MTU_4096; + default: return -1; + } +} + +static inline int ibta_mtu_to_int(enum ibta_mtu mtu) +{ + switch (mtu) { + case IB_MTU_256: return 256; + case IB_MTU_512: return 512; + case IB_MTU_1024: return 1024; + case IB_MTU_2048: return 2048; + case IB_MTU_4096: return 4096; + default: return -1; + } +} + +static ssize_t show_port_ib_mtu(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, + port_mtu_attr); + struct mlx4_dev *mdev = info->dev; + + if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) + mlx4_warn(mdev, "port level mtu is only used for IB ports\n"); + + sprintf(buf, "%d\n", + ibta_mtu_to_int(mdev->caps.port_ib_mtu[info->port])); + return strlen(buf); +} + +static ssize_t set_port_ib_mtu(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, + port_mtu_attr); + struct mlx4_dev *mdev = info->dev; + struct mlx4_priv *priv = mlx4_priv(mdev); + int err, port, mtu, ibta_mtu = -1; + + if (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_ETH) { + mlx4_warn(mdev, "port level mtu is only used for IB ports\n"); + return -EINVAL; + } + + err = sscanf(buf, "%d", &mtu); + if (err > 0) + ibta_mtu = int_to_ibta_mtu(mtu); + + if (err <= 0 || ibta_mtu < 0) { + mlx4_err(mdev, "%s is invalid IBTA mtu\n", buf); + return -EINVAL; + } + + mdev->caps.port_ib_mtu[info->port] = ibta_mtu; + + mlx4_stop_sense(mdev); + mutex_lock(&priv->port_mutex); + mlx4_unregister_device(mdev); + for (port = 1; port <= mdev->caps.num_ports; port++) { + mlx4_CLOSE_PORT(mdev, port); + err = mlx4_SET_PORT(mdev, port); + if (err) { + mlx4_err(mdev, "Failed to set port %d, " + "aborting\n", port); + goto err_set_port; + } + } + err = mlx4_register_device(mdev); +err_set_port: + mutex_unlock(&priv->port_mutex); + mlx4_start_sense(mdev); + return err ? err : count; +} + static int mlx4_load_fw(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -1133,6 +1226,8 @@ static int mlx4_init_hca(struct mlx4_dev *dev) goto err_stop_fw; } + dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1; + init_hca.log_uar_sz = ilog2(dev->caps.num_uars); init_hca.uar_page_sz = PAGE_SHIFT - 12; @@ -1363,12 +1458,10 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) "with caps = 0\n", port, err); dev->caps.ib_port_def_cap[port] = ib_port_default_caps; - err = mlx4_check_ext_port_caps(dev, port); - if (err) - mlx4_warn(dev, "failed to get port %d extended " - "port capabilities support info (%d)." - " Assuming not supported\n", - port, err); + if (mlx4_is_mfunc(dev)) + dev->caps.port_ib_mtu[port] = IB_MTU_2048; + else + dev->caps.port_ib_mtu[port] = IB_MTU_4096; err = mlx4_SET_PORT(dev, port); if (err) { @@ -1524,6 +1617,24 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port = -1; } + sprintf(info->dev_mtu_name, "mlx4_port%d_mtu", port); + info->port_mtu_attr.attr.name = info->dev_mtu_name; + if (mlx4_is_mfunc(dev)) + info->port_mtu_attr.attr.mode = S_IRUGO; + else { + info->port_mtu_attr.attr.mode = S_IRUGO | S_IWUSR; + info->port_mtu_attr.store = set_port_ib_mtu; + } + info->port_mtu_attr.show = show_port_ib_mtu; + sysfs_attr_init(&info->port_mtu_attr.attr); + + err = device_create_file(&dev->pdev->dev, &info->port_mtu_attr); + if (err) { + mlx4_err(dev, "Failed to create mtu file for port %d\n", port); + device_remove_file(&info->dev->pdev->dev, &info->port_attr); + info->port = -1; + } + return err; } @@ -1533,6 +1644,7 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) return; device_remove_file(&info->dev->pdev->dev, &info->port_attr); + device_remove_file(&info->dev->pdev->dev, &info->port_mtu_attr); } static int mlx4_init_steering(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 5da51b99dbb8..2a0ff2cc7182 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -363,6 +363,10 @@ struct mlx4_eqe { struct { __be32 slave_id; } __packed flr_event; + struct { + __be16 current_temperature; + __be16 warning_threshold; + } __packed warming; } event; u8 slave_id; u8 reserved3[2]; @@ -399,7 +403,7 @@ struct mlx4_profile { int num_cq; int num_mcg; int num_mpt; - int num_mtt; + unsigned num_mtt; }; struct mlx4_fw { @@ -682,6 +686,8 @@ struct mlx4_port_info { char dev_name[16]; struct device_attribute port_attr; enum mlx4_port_type tmp_type; + char dev_mtu_name[16]; + struct device_attribute port_mtu_attr; struct mlx4_mac_table mac_table; struct radix_tree_root mac_tree; struct mlx4_vlan_table vlan_table; @@ -1024,7 +1030,6 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_mailbox *outbox, struct mlx4_cmd_info *cmd); int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); -int mlx4_check_ext_port_caps(struct mlx4_dev *dev, u8 port); int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave, diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c index 32e2b6616f3d..fe2ac8449c19 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mr.c +++ b/drivers/net/ethernet/mellanox/mlx4/mr.c @@ -791,6 +791,9 @@ int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, u64 mtt_offset; int err = -ENOMEM; + if (max_maps > dev->caps.max_fmr_maps) + return -EINVAL; + if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 98e776261ead..77535ff18f1b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -590,49 +590,6 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) return err; } -int mlx4_check_ext_port_caps(struct mlx4_dev *dev, u8 port) -{ - struct mlx4_cmd_mailbox *inmailbox, *outmailbox; - u8 *inbuf, *outbuf; - int err, packet_error; - - inmailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(inmailbox)) - return PTR_ERR(inmailbox); - - outmailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(outmailbox)) { - mlx4_free_cmd_mailbox(dev, inmailbox); - return PTR_ERR(outmailbox); - } - - inbuf = inmailbox->buf; - outbuf = outmailbox->buf; - memset(inbuf, 0, 256); - memset(outbuf, 0, 256); - inbuf[0] = 1; - inbuf[1] = 1; - inbuf[2] = 1; - inbuf[3] = 1; - - *(__be16 *) (&inbuf[16]) = MLX4_ATTR_EXTENDED_PORT_INFO; - *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); - - err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, - MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, - MLX4_CMD_NATIVE); - - packet_error = be16_to_cpu(*(__be16 *) (outbuf + 4)); - - dev->caps.ext_port_cap[port] = (!err && !packet_error) ? - MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO - : 0; - - mlx4_free_cmd_mailbox(dev, inmailbox); - mlx4_free_cmd_mailbox(dev, outmailbox); - return err; -} - static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, u8 op_mod, struct mlx4_cmd_mailbox *inbox) { @@ -766,10 +723,18 @@ int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, vhcr->op_modifier, inbox); } +/* bit locations for set port command with zero op modifier */ +enum { + MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ + MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ + MLX4_CHANGE_PORT_VL_CAP = 21, + MLX4_CHANGE_PORT_MTU_CAP = 22, +}; + int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port) { struct mlx4_cmd_mailbox *mailbox; - int err; + int err, vl_cap; if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) return 0; @@ -781,8 +746,19 @@ int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port) memset(mailbox->buf, 0, 256); ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; - err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + + /* IB VL CAP enum isn't used by the firmware, just numerical values */ + for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { + ((__be32 *) mailbox->buf)[0] = cpu_to_be32( + (1 << MLX4_CHANGE_PORT_MTU_CAP) | + (1 << MLX4_CHANGE_PORT_VL_CAP) | + (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | + (vl_cap << MLX4_SET_PORT_VL_CAP)); + err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + if (err != -ENOMEM) + break; + } mlx4_free_cmd_mailbox(dev, mailbox); return err; diff --git a/drivers/net/ethernet/mellanox/mlx4/profile.c b/drivers/net/ethernet/mellanox/mlx4/profile.c index 1129677daa62..06e5adeb76f7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/profile.c +++ b/drivers/net/ethernet/mellanox/mlx4/profile.c @@ -83,12 +83,31 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, u64 total_size = 0; struct mlx4_resource *profile; struct mlx4_resource tmp; + struct sysinfo si; int i, j; profile = kcalloc(MLX4_RES_NUM, sizeof(*profile), GFP_KERNEL); if (!profile) return -ENOMEM; + /* + * We want to scale the number of MTTs with the size of the + * system memory, since it makes sense to register a lot of + * memory on a system with a lot of memory. As a heuristic, + * make sure we have enough MTTs to cover twice the system + * memory (with PAGE_SIZE entries). + * + * This number has to be a power of two and fit into 32 bits + * due to device limitations, so cap this at 2^31 as well. + * That limits us to 8TB of memory registration per HCA with + * 4KB pages, which is probably OK for the next few months. + */ + si_meminfo(&si); + request->num_mtt = + roundup_pow_of_two(max_t(unsigned, request->num_mtt, + min(1UL << 31, + si.totalram >> (log_mtts_per_seg - 1)))); + profile[MLX4_RES_QP].size = dev_cap->qpc_entry_sz; profile[MLX4_RES_RDMARC].size = dev_cap->rdmarc_entry_sz; profile[MLX4_RES_ALTC].size = dev_cap->altc_entry_sz; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 2b5af22419a5..385a4d5c7c25 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -36,8 +36,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 0 -#define _QLCNIC_LINUX_SUBVERSION 25 -#define QLCNIC_LINUX_VERSIONID "5.0.26" +#define _QLCNIC_LINUX_SUBVERSION 27 +#define QLCNIC_LINUX_VERSIONID "5.0.27" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 81bb1a69e69f..75c32e875fef 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -1458,8 +1458,10 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter) if (netif_running(netdev)) { err = qlcnic_attach(adapter); - if (!err) + if (!err) { __qlcnic_up(adapter, netdev); + qlcnic_restore_indev_addr(netdev, NETDEV_UP); + } } netif_device_attach(netdev); diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index b36edbd625dd..3c2295560732 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -104,8 +104,8 @@ #include <asm/byteorder.h> #include <asm/uaccess.h> -#define cas_page_map(x) kmap_atomic((x), KM_SKB_DATA_SOFTIRQ) -#define cas_page_unmap(x) kunmap_atomic((x), KM_SKB_DATA_SOFTIRQ) +#define cas_page_map(x) kmap_atomic((x)) +#define cas_page_unmap(x) kunmap_atomic((x)) #define CAS_NCPUS num_online_cpus() #define cas_skb_release(x) netif_rx(x) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 58dc117a8d78..0427c6561c84 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/wait.h> #include <linux/cdev.h> +#include <linux/idr.h> #include <linux/fs.h> #include <net/net_namespace.h> diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 50e8e5e74465..7189adf54bd1 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -255,13 +255,13 @@ static inline int __init mdio_ofgpio_init(void) return platform_driver_register(&mdio_ofgpio_driver); } -static inline void __exit mdio_ofgpio_exit(void) +static inline void mdio_ofgpio_exit(void) { platform_driver_unregister(&mdio_ofgpio_driver); } #else static inline int __init mdio_ofgpio_init(void) { return 0; } -static inline void __exit mdio_ofgpio_exit(void) { } +static inline void mdio_ofgpio_exit(void) { } #endif /* CONFIG_OF_GPIO */ static struct platform_driver mdio_gpio_driver = { diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 790cbdea7392..3886b30ed373 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -164,12 +164,14 @@ static void rx_complete(struct urb *req) /* Can't use pskb_pull() on page in IRQ */ memcpy(skb_put(skb, 1), page_address(page), 1); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, 1, req->actual_length); + page, 1, req->actual_length, + req->actual_length); page = NULL; } } else { skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - page, 0, req->actual_length); + page, 0, req->actual_length, + req->actual_length); page = NULL; } if (req->actual_length < PAGE_SIZE) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index aac68f5195c0..552d24bf862e 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -409,6 +409,42 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3565-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0063, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, + { /* ZTE (Vodafone) K3570-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x1008, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, + { /* ZTE (Vodafone) K3571-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x1010, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, + { /* ZTE (Vodafone) K4505-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0104, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 4b8b52ca09d8..b7b3f5b0d406 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -493,6 +493,7 @@ block: if (netif_running (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { rx_submit (dev, urb, GFP_ATOMIC); + usb_mark_last_busy(dev->udev); return; } usb_free_urb (urb); @@ -589,6 +590,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) entry = (struct skb_data *) skb->cb; urb = entry->urb; + /* + * Get reference count of the URB to avoid it to be + * freed during usb_unlink_urb, which may trigger + * use-after-free problem inside usb_unlink_urb since + * usb_unlink_urb is always racing with .complete + * handler(include defer_bh). + */ + usb_get_urb(urb); spin_unlock_irqrestore(&q->lock, flags); // during some PM-driven resume scenarios, // these (async) unlinks complete immediately @@ -597,6 +606,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) netdev_dbg(dev->net, "unlink urb err, %d\n", retval); else count++; + usb_put_urb(urb); spin_lock_irqsave(&q->lock, flags); } spin_unlock_irqrestore (&q->lock, flags); @@ -1028,7 +1038,6 @@ static void tx_complete (struct urb *urb) } usb_autopm_put_interface_async(dev->intf); - urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); } diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index c5b1d199e0bc..b25c01be0d90 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -499,7 +499,8 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb, le32_to_cpu(rx_end->status), stats); skb_add_rx_frag(skb, 0, rxb->page, - (void *)rx_hdr->payload - (void *)pkt, len); + (void *)rx_hdr->payload - (void *)pkt, len, + len); il_update_stats(il, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 7b54dbb338be..17f1c6853182 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -596,7 +596,8 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr, return; } - skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); + skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len, + len); il_update_stats(il, false, fc, len); memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 44c6f712b77d..f4b84d1596e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -796,7 +796,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, offset = (void *)hdr - rxb_addr(rxb); p = rxb_steal_page(rxb); - skb_add_rx_frag(skb, 0, p, offset, len); + skb_add_rx_frag(skb, 0, p, offset, len, len); iwl_update_stats(priv, false, fc, len); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 268163dd71c7..6ea51dcbc728 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -35,9 +35,10 @@ config OF_EARLY_FLATTREE config OF_PROMTREE bool +# Hardly any platforms need this. It is safe to select, but only do so if you +# need it. config OF_DYNAMIC - def_bool y - depends on PPC_OF + bool config OF_ADDRESS def_bool y diff --git a/drivers/of/base.c b/drivers/of/base.c index 133908a6fd8d..580644986945 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -88,7 +88,7 @@ int of_n_size_cells(struct device_node *np) } EXPORT_SYMBOL(of_n_size_cells); -#if !defined(CONFIG_SPARC) /* SPARC doesn't do ref counting (yet) */ +#if defined(CONFIG_OF_DYNAMIC) /** * of_node_get - Increment refcount of a node * @node: Node to inc refcount, NULL is supported to @@ -161,7 +161,7 @@ void of_node_put(struct device_node *node) kref_put(&node->kref, of_node_release); } EXPORT_SYMBOL(of_node_put); -#endif /* !CONFIG_SPARC */ +#endif /* CONFIG_OF_DYNAMIC */ struct property *of_find_property(const struct device_node *np, const char *name, @@ -761,6 +761,42 @@ int of_property_read_string_index(struct device_node *np, const char *propname, } EXPORT_SYMBOL_GPL(of_property_read_string_index); +/** + * of_property_match_string() - Find string in a list and return index + * @np: pointer to node containing string list property + * @propname: string list property name + * @string: pointer to string to search for in string list + * + * This function searches a string list property and returns the index + * of a specific string value. + */ +int of_property_match_string(struct device_node *np, const char *propname, + const char *string) +{ + struct property *prop = of_find_property(np, propname, NULL); + size_t l; + int i; + const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + p = prop->value; + end = p + prop->length; + + for (i = 0; p < end; i++, p += l) { + l = strlen(p) + 1; + if (p + l > end) + return -EILSEQ; + pr_debug("comparing %s with %s\n", string, p); + if (strcmp(string, p) == 0) + return i; /* Found it; return index */ + } + return -ENODATA; +} +EXPORT_SYMBOL_GPL(of_property_match_string); /** * of_property_count_strings - Find and return the number of strings from a diff --git a/drivers/of/device.c b/drivers/of/device.c index 62b4b32ac887..4c74e4fc5a51 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -128,39 +128,41 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) /** * of_device_uevent - Display OF related uevent information */ -int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) +void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) { const char *compat; int seen = 0, cplen, sl; if ((!dev) || (!dev->of_node)) - return -ENODEV; - - if (add_uevent_var(env, "OF_NAME=%s", dev->of_node->name)) - return -ENOMEM; + return; - if (add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type)) - return -ENOMEM; + add_uevent_var(env, "OF_NAME=%s", dev->of_node->name); + add_uevent_var(env, "OF_FULLNAME=%s", dev->of_node->full_name); + if (dev->of_node->type && strcmp("<NULL>", dev->of_node->type) != 0) + add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type); /* Since the compatible field can contain pretty much anything * it's not really legal to split it out with commas. We split it * up using a number of environment variables instead. */ - compat = of_get_property(dev->of_node, "compatible", &cplen); while (compat && *compat && cplen > 0) { - if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) - return -ENOMEM; - + add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); sl = strlen(compat) + 1; compat += sl; cplen -= sl; seen++; } + add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); +} - if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) - return -ENOMEM; +int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +{ + int sl; + + if ((!dev) || (!dev->of_node)) + return -ENODEV; - /* modalias is trickier, we add it in 2 steps */ + /* Devicetree modalias is tricky, we add it in 2 steps */ if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 63b3ec48c203..20fbebd49db3 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -55,7 +55,7 @@ EXPORT_SYMBOL(of_find_device_by_node); #include <asm/dcr.h> #endif -#if !defined(CONFIG_SPARC) +#ifdef CONFIG_OF_ADDRESS /* * The following routines scan a subtree and registers a device for * each applicable node. @@ -462,4 +462,4 @@ int of_platform_populate(struct device_node *root, of_node_put(root); return rc; } -#endif /* !CONFIG_SPARC */ +#endif /* CONFIG_OF_ADDRESS */ diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 9d2b4803a9d6..f24ffd7088d2 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -120,6 +120,34 @@ static void __init of_selftest_parse_phandle_with_args(void) pr_info("end - %s\n", passed_all ? "PASS" : "FAIL"); } +static void __init of_selftest_property_match_string(void) +{ + struct device_node *np; + int rc; + + pr_info("start\n"); + np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); + if (!np) { + pr_err("No testcase data in device tree\n"); + return; + } + + rc = of_property_match_string(np, "phandle-list-names", "first"); + selftest(rc == 0, "first expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "second"); + selftest(rc == 1, "second expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "third"); + selftest(rc == 2, "third expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "fourth"); + selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); + rc = of_property_match_string(np, "missing-property", "blah"); + selftest(rc == -EINVAL, "missing property; rc=%i", rc); + rc = of_property_match_string(np, "empty-property", "blah"); + selftest(rc == -ENODATA, "empty property; rc=%i", rc); + rc = of_property_match_string(np, "unterminated-string", "blah"); + selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); +} + static int __init of_selftest(void) { struct device_node *np; @@ -133,6 +161,7 @@ static int __init of_selftest(void) pr_info("start of selftest - you will see error messages\n"); of_selftest_parse_phandle_with_args(); + of_selftest_property_match_string(); pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL"); return 0; } diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 7a61b17ddd04..a229de98ae6f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -74,13 +74,72 @@ config REGULATOR_GPIO and the platform has to provide a mapping of GPIO-states to target volts/amps. -config REGULATOR_BQ24022 - tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" +config REGULATOR_AD5398 + tristate "Analog Devices AD5398/AD5821 regulators" + depends on I2C help - This driver controls a TI bq24022 Charger attached via - GPIOs. The provided current regulator can enable/disable - charging select between 100 mA and 500 mA charging current - limit. + This driver supports AD5398 and AD5821 current regulator chips. + If building into module, its name is ad5398.ko. + +config REGULATOR_AAT2870 + tristate "AnalogicTech AAT2870 Regulators" + depends on MFD_AAT2870_CORE + help + If you have a AnalogicTech AAT2870 say Y to enable the + regulator driver. + +config REGULATOR_DA903X + tristate "Dialog Semiconductor DA9030/DA9034 regulators" + depends on PMIC_DA903X + help + Say y here to support the BUCKs and LDOs regulators found on + Dialog Semiconductor DA9030/DA9034 PMIC. + +config REGULATOR_DA9052 + tristate "Dialog Semiconductor DA9052/DA9053 regulators" + depends on PMIC_DA9052 + help + This driver supports the voltage regulators of DA9052-BC and + DA9053-AA/Bx PMIC. + +config REGULATOR_ANATOP + tristate "Freescale i.MX on-chip ANATOP LDO regulators" + depends on MFD_ANATOP + help + Say y here to support Freescale i.MX on-chip ANATOP LDOs + regulators. It is recommended that this option be + enabled on i.MX6 platform. + +config REGULATOR_MC13XXX_CORE + tristate + +config REGULATOR_MC13783 + tristate "Freescale MC13783 regulator driver" + depends on MFD_MC13783 + select REGULATOR_MC13XXX_CORE + help + Say y here to support the regulators found on the Freescale MC13783 + PMIC. + +config REGULATOR_MC13892 + tristate "Freescale MC13892 regulator driver" + depends on MFD_MC13XXX + select REGULATOR_MC13XXX_CORE + help + Say y here to support the regulators found on the Freescale MC13892 + PMIC. + +config REGULATOR_ISL6271A + tristate "Intersil ISL6271A Power regulator" + depends on I2C + help + This driver supports ISL6271A voltage regulator chip. + +config REGULATOR_88PM8607 + bool "Marvell 88PM8607 Power regulators" + depends on MFD_88PM860X=y + help + This driver supports 88PM8607 voltage regulator chips. config REGULATOR_MAX1586 tristate "Maxim 1586/1587 voltage regulator" @@ -136,61 +195,12 @@ config REGULATOR_MAX8998 via I2C bus. The provided regulator is suitable for S3C6410 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. -config REGULATOR_TWL4030 - bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" - depends on TWL4030_CORE - help - This driver supports the voltage regulators provided by - this family of companion chips. - -config REGULATOR_WM831X - tristate "Wolfson Microelcronics WM831x PMIC regulators" - depends on MFD_WM831X - help - Support the voltage and current regulators of the WM831x series - of PMIC devices. - -config REGULATOR_WM8350 - tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC" - depends on MFD_WM8350 - help - This driver provides support for the voltage and current regulators - of the WM8350 AudioPlus PMIC. - -config REGULATOR_WM8400 - tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC" - depends on MFD_WM8400 - help - This driver provides support for the voltage regulators of the - WM8400 AudioPlus PMIC. - -config REGULATOR_WM8994 - tristate "Wolfson Microelectronics WM8994 CODEC" - depends on MFD_WM8994 - help - This driver provides support for the voltage regulators on the - WM8994 CODEC. - -config REGULATOR_DA903X - tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC" - depends on PMIC_DA903X - help - Say y here to support the BUCKs and LDOs regulators found on - Dialog Semiconductor DA9030/DA9034 PMIC. - -config REGULATOR_DA9052 - tristate "Dialog DA9052/DA9053 regulators" - depends on PMIC_DA9052 - help - This driver supports the voltage regulators of DA9052-BC and - DA9053-AA/Bx PMIC. - -config REGULATOR_PCF50633 - tristate "PCF50633 regulator driver" - depends on MFD_PCF50633 +config REGULATOR_PCAP + tristate "Motorola PCAP2 regulator driver" + depends on EZX_PCAP help - Say Y here to support the voltage regulators and convertors - on PCF50633 + This driver provides support for the voltage regulators of the + PCAP2 PMIC. config REGULATOR_LP3971 tristate "National Semiconductors LP3971 PMIC regulator driver" @@ -206,31 +216,20 @@ config REGULATOR_LP3972 Say Y here to support the voltage regulators and convertors on National Semiconductors LP3972 PMIC -config REGULATOR_PCAP - tristate "PCAP2 regulator driver" - depends on EZX_PCAP - help - This driver provides support for the voltage regulators of the - PCAP2 PMIC. - -config REGULATOR_MC13XXX_CORE - tristate - -config REGULATOR_MC13783 - tristate "Support regulators on Freescale MC13783 PMIC" - depends on MFD_MC13783 - select REGULATOR_MC13XXX_CORE +config REGULATOR_PCF50633 + tristate "NXP PCF50633 regulator driver" + depends on MFD_PCF50633 help - Say y here to support the regulators found on the Freescale MC13783 - PMIC. + Say Y here to support the voltage regulators and convertors + on PCF50633 -config REGULATOR_MC13892 - tristate "Support regulators on Freescale MC13892 PMIC" - depends on MFD_MC13XXX - select REGULATOR_MC13XXX_CORE +config REGULATOR_S5M8767 + tristate "Samsung S5M8767A voltage regulator" + depends on MFD_S5M_CORE help - Say y here to support the regulators found on the Freescale MC13892 - PMIC. + This driver supports a Samsung S5M8767A voltage output regulator + via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and + supports DVS mode with 8bits of output voltage control. config REGULATOR_AB3100 tristate "ST-Ericsson AB3100 Regulator functions" @@ -241,6 +240,32 @@ config REGULATOR_AB3100 AB3100 analog baseband dealing with power regulators for the system. +config REGULATOR_AB8500 + bool "ST-Ericsson AB8500 Power Regulators" + depends on AB8500_CORE + help + This driver supports the regulators found on the ST-Ericsson mixed + signal AB8500 PMIC + +config REGULATOR_DBX500_PRCMU + bool + +config REGULATOR_DB8500_PRCMU + bool "ST-Ericsson DB8500 Voltage Domain Regulators" + depends on MFD_DB8500_PRCMU + select REGULATOR_DBX500_PRCMU + help + This driver supports the voltage domain regulators controlled by the + DB8500 PRCMU + +config REGULATOR_BQ24022 + tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" + help + This driver controls a TI bq24022 Charger attached via + GPIOs. The provided current regulator can enable/disable + charging select between 100 mA and 500 mA charging current + limit. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X @@ -250,6 +275,16 @@ config REGULATOR_TPS6105X It is a single boost converter primarily for white LEDs and audio amplifiers. +config REGULATOR_TPS62360 + tristate "TI TPS62360 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports TPS62360 voltage regulator chip. This + regulator is meant for processor core supply. This chip is + high-frequency synchronous step down dc-dc converter optimized + for battery-powered portable applications. + config REGULATOR_TPS65023 tristate "TI TPS65023 Power regulators" depends on I2C @@ -267,73 +302,77 @@ config REGULATOR_TPS6507X three step-down converters and two general-purpose LDO voltage regulators. It supports TI's software based Class-2 SmartReflex implementation. -config REGULATOR_TPS65912 - tristate "TI TPS65912 Power regulator" - depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) +config REGULATOR_TPS65217 + tristate "TI TPS65217 Power regulators" + depends on MFD_TPS65217 help - This driver supports TPS65912 voltage regulator chip. + This driver supports TPS65217 voltage regulator chips. TPS65217 + provides three step-down converters and four general-purpose LDO + voltage regulators. It supports software based voltage control + for different voltage domains -config REGULATOR_88PM8607 - bool "Marvell 88PM8607 Power regulators" - depends on MFD_88PM860X=y +config REGULATOR_TPS6524X + tristate "TI TPS6524X Power regulators" + depends on SPI help - This driver supports 88PM8607 voltage regulator chips. + This driver supports TPS6524X voltage regulator chips. TPS6524X + provides three step-down converters and two general-purpose LDO + voltage regulators. This device is interfaced using a customized + serial interface currently supported on the sequencer serial + port controller. -config REGULATOR_ISL6271A - tristate "Intersil ISL6271A Power regulator" - depends on I2C +config REGULATOR_TPS6586X + tristate "TI TPS6586X Power regulators" + depends on MFD_TPS6586X help - This driver supports ISL6271A voltage regulator chip. + This driver supports TPS6586X voltage regulator chips. -config REGULATOR_AD5398 - tristate "Analog Devices AD5398/AD5821 regulators" - depends on I2C +config REGULATOR_TPS65910 + tristate "TI TPS65910/TPS65911 Power Regulators" + depends on MFD_TPS65910 help - This driver supports AD5398 and AD5821 current regulator chips. - If building into module, its name is ad5398.ko. + This driver supports TPS65910/TPS65911 voltage regulator chips. -config REGULATOR_AB8500 - bool "ST-Ericsson AB8500 Power Regulators" - depends on AB8500_CORE +config REGULATOR_TPS65912 + tristate "TI TPS65912 Power regulator" + depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI) help - This driver supports the regulators found on the ST-Ericsson mixed - signal AB8500 PMIC + This driver supports TPS65912 voltage regulator chip. -config REGULATOR_DB8500_PRCMU - bool "ST-Ericsson DB8500 Voltage Domain Regulators" - depends on MFD_DB8500_PRCMU +config REGULATOR_TWL4030 + bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" + depends on TWL4030_CORE help - This driver supports the voltage domain regulators controlled by the - DB8500 PRCMU + This driver supports the voltage regulators provided by + this family of companion chips. -config REGULATOR_TPS6586X - tristate "TI TPS6586X Power regulators" - depends on MFD_TPS6586X +config REGULATOR_WM831X + tristate "Wolfson Microelectronics WM831x PMIC regulators" + depends on MFD_WM831X help - This driver supports TPS6586X voltage regulator chips. + Support the voltage and current regulators of the WM831x series + of PMIC devices. -config REGULATOR_TPS6524X - tristate "TI TPS6524X Power regulators" - depends on SPI +config REGULATOR_WM8350 + tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC" + depends on MFD_WM8350 help - This driver supports TPS6524X voltage regulator chips. TPS6524X - provides three step-down converters and two general-purpose LDO - voltage regulators. This device is interfaced using a customized - serial interface currently supported on the sequencer serial - port controller. + This driver provides support for the voltage and current regulators + of the WM8350 AudioPlus PMIC. -config REGULATOR_TPS65910 - tristate "TI TPS65910 Power Regulator" - depends on MFD_TPS65910 +config REGULATOR_WM8400 + tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC" + depends on MFD_WM8400 help - This driver supports TPS65910 voltage regulator chips. + This driver provides support for the voltage regulators of the + WM8400 AudioPlus PMIC. -config REGULATOR_AAT2870 - tristate "AnalogicTech AAT2870 Regulators" - depends on MFD_AAT2870_CORE +config REGULATOR_WM8994 + tristate "Wolfson Microelectronics WM8994 CODEC" + depends on MFD_WM8994 help - If you have a AnalogicTech AAT2870 say Y to enable the - regulator driver. + This driver provides support for the voltage regulators on the + WM8994 CODEC. endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 503bac87715e..b5042c885d89 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -3,50 +3,56 @@ # -obj-$(CONFIG_REGULATOR) += core.o dummy.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o +obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o +obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o +obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o +obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o +obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o +obj-$(CONFIG_REGULATOR_DA903X) += da903x.o +obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o +obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o +obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o +obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o -obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o -obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o -obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o -obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o -obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o -obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o -obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o -obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o -obj-$(CONFIG_REGULATOR_DA903X) += da903x.o -obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o -obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o -obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o -obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o +obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o +obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o +obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o +obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o +obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o -obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o -obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o -obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o -obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o -obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o +obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o -obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o +obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o +obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o +obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o +obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o +obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o +obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o +obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o +obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 685ad43b0749..9ed5c5d84e12 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -31,7 +31,7 @@ #include <linux/mfd/aat2870.h> struct aat2870_regulator { - struct platform_device *pdev; + struct aat2870_data *aat2870; struct regulator_desc desc; const int *voltages; /* uV */ @@ -60,7 +60,7 @@ static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); + struct aat2870_data *aat2870 = ri->aat2870; return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask, selector << ri->voltage_shift); @@ -69,7 +69,7 @@ static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); + struct aat2870_data *aat2870 = ri->aat2870; u8 val; int ret; @@ -83,7 +83,7 @@ static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev) static int aat2870_ldo_enable(struct regulator_dev *rdev) { struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); + struct aat2870_data *aat2870 = ri->aat2870; return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, ri->enable_mask); @@ -92,7 +92,7 @@ static int aat2870_ldo_enable(struct regulator_dev *rdev) static int aat2870_ldo_disable(struct regulator_dev *rdev) { struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); + struct aat2870_data *aat2870 = ri->aat2870; return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0); } @@ -100,7 +100,7 @@ static int aat2870_ldo_disable(struct regulator_dev *rdev) static int aat2870_ldo_is_enabled(struct regulator_dev *rdev) { struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); + struct aat2870_data *aat2870 = ri->aat2870; u8 val; int ret; @@ -185,7 +185,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id); return -EINVAL; } - ri->pdev = pdev; + ri->aat2870 = dev_get_drvdata(pdev->dev.parent); rdev = regulator_register(&ri->desc, &pdev->dev, pdev->dev.platform_data, ri, NULL); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index c9b92531ae60..c7ee4c15d6f5 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -201,7 +201,7 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) return info->voltages[selector]; } -static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) +static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev) { int ret, val; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); @@ -229,11 +229,9 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) /* vintcore has a different layout */ val = regval & info->voltage_mask; if (info->desc.id == AB8500_LDO_INTCORE) - ret = info->voltages[val >> 0x3]; + return val >> 0x3; else - ret = info->voltages[val]; - - return ret; + return val; } static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, @@ -320,7 +318,7 @@ static struct regulator_ops ab8500_regulator_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, - .get_voltage = ab8500_regulator_get_voltage, + .get_voltage_sel = ab8500_regulator_get_voltage_sel, .set_voltage = ab8500_regulator_set_voltage, .list_voltage = ab8500_list_voltage, .enable_time = ab8500_regulator_enable_time, diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index 483c80930852..26d23adfc66f 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -94,8 +94,8 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int if (max_uA > chip->max_uA || max_uA < chip->min_uA) return -EINVAL; - selector = ((min_uA - chip->min_uA) * chip->current_level + - range_uA - 1) / range_uA; + selector = DIV_ROUND_UP((min_uA - chip->min_uA) * chip->current_level, + range_uA); if (ad5398_calc_current(chip, selector) > max_uA) return -EINVAL; diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c new file mode 100644 index 000000000000..17499a55113d --- /dev/null +++ b/drivers/regulator/anatop-regulator.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/mfd/anatop.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +struct anatop_regulator { + const char *name; + u32 control_reg; + struct anatop *mfd; + int vol_bit_shift; + int vol_bit_width; + int min_bit_val; + int min_voltage; + int max_voltage; + struct regulator_desc rdesc; + struct regulator_init_data *initdata; +}; + +static int anatop_set_voltage(struct regulator_dev *reg, int min_uV, + int max_uV, unsigned *selector) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + u32 val, sel; + int uv; + + uv = min_uV; + dev_dbg(®->dev, "%s: uv %d, min %d, max %d\n", __func__, + uv, anatop_reg->min_voltage, + anatop_reg->max_voltage); + + if (uv < anatop_reg->min_voltage) { + if (max_uV > anatop_reg->min_voltage) + uv = anatop_reg->min_voltage; + else + return -EINVAL; + } + + if (!anatop_reg->control_reg) + return -ENOTSUPP; + + sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000); + if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage) + return -EINVAL; + val = anatop_reg->min_bit_val + sel; + *selector = sel; + dev_dbg(®->dev, "%s: calculated val %d\n", __func__, val); + anatop_set_bits(anatop_reg->mfd, + anatop_reg->control_reg, + anatop_reg->vol_bit_shift, + anatop_reg->vol_bit_width, + val); + + return 0; +} + +static int anatop_get_voltage_sel(struct regulator_dev *reg) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + u32 val; + + if (!anatop_reg->control_reg) + return -ENOTSUPP; + + val = anatop_get_bits(anatop_reg->mfd, + anatop_reg->control_reg, + anatop_reg->vol_bit_shift, + anatop_reg->vol_bit_width); + + return val - anatop_reg->min_bit_val; +} + +static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + int uv; + + uv = anatop_reg->min_voltage + selector * 25000; + dev_dbg(®->dev, "vddio = %d, selector = %u\n", uv, selector); + + return uv; +} + +static struct regulator_ops anatop_rops = { + .set_voltage = anatop_set_voltage, + .get_voltage_sel = anatop_get_voltage_sel, + .list_voltage = anatop_list_voltage, +}; + +static int __devinit anatop_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regulator_desc *rdesc; + struct regulator_dev *rdev; + struct anatop_regulator *sreg; + struct regulator_init_data *initdata; + struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent); + int ret = 0; + + initdata = of_get_regulator_init_data(dev, np); + sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); + if (!sreg) + return -ENOMEM; + sreg->initdata = initdata; + sreg->name = kstrdup(of_get_property(np, "regulator-name", NULL), + GFP_KERNEL); + rdesc = &sreg->rdesc; + memset(rdesc, 0, sizeof(*rdesc)); + rdesc->name = sreg->name; + rdesc->ops = &anatop_rops; + rdesc->type = REGULATOR_VOLTAGE; + rdesc->owner = THIS_MODULE; + sreg->mfd = anatopmfd; + ret = of_property_read_u32(np, "reg", &sreg->control_reg); + if (ret) { + dev_err(dev, "no reg property set\n"); + goto anatop_probe_end; + } + ret = of_property_read_u32(np, "anatop-vol-bit-width", + &sreg->vol_bit_width); + if (ret) { + dev_err(dev, "no anatop-vol-bit-width property set\n"); + goto anatop_probe_end; + } + ret = of_property_read_u32(np, "anatop-vol-bit-shift", + &sreg->vol_bit_shift); + if (ret) { + dev_err(dev, "no anatop-vol-bit-shift property set\n"); + goto anatop_probe_end; + } + ret = of_property_read_u32(np, "anatop-min-bit-val", + &sreg->min_bit_val); + if (ret) { + dev_err(dev, "no anatop-min-bit-val property set\n"); + goto anatop_probe_end; + } + ret = of_property_read_u32(np, "anatop-min-voltage", + &sreg->min_voltage); + if (ret) { + dev_err(dev, "no anatop-min-voltage property set\n"); + goto anatop_probe_end; + } + ret = of_property_read_u32(np, "anatop-max-voltage", + &sreg->max_voltage); + if (ret) { + dev_err(dev, "no anatop-max-voltage property set\n"); + goto anatop_probe_end; + } + + rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) + / 25000 + 1; + + /* register regulator */ + rdev = regulator_register(rdesc, dev, + initdata, sreg, pdev->dev.of_node); + if (IS_ERR(rdev)) { + dev_err(dev, "failed to register %s\n", + rdesc->name); + ret = PTR_ERR(rdev); + goto anatop_probe_end; + } + + platform_set_drvdata(pdev, rdev); + +anatop_probe_end: + if (ret) + kfree(sreg->name); + + return ret; +} + +static int __devexit anatop_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct anatop_regulator *sreg = rdev_get_drvdata(rdev); + const char *name = sreg->name; + + regulator_unregister(rdev); + kfree(name); + + return 0; +} + +static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = { + { .compatible = "fsl,anatop-regulator", }, + { /* end */ } +}; + +static struct platform_driver anatop_regulator = { + .driver = { + .name = "anatop_regulator", + .owner = THIS_MODULE, + .of_match_table = of_anatop_regulator_match_tbl, + }, + .probe = anatop_regulator_probe, + .remove = anatop_regulator_remove, +}; + +static int __init anatop_regulator_init(void) +{ + return platform_driver_register(&anatop_regulator); +} +postcore_initcall(anatop_regulator_init); + +static void __exit anatop_regulator_exit(void) +{ + platform_driver_unregister(&anatop_regulator); +} +module_exit(anatop_regulator_exit); + +MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " + "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); +MODULE_DESCRIPTION("ANATOP Regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fcde037b3461..c056abd7562a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -13,8 +13,6 @@ * */ -#define pr_fmt(fmt) "%s: " fmt, __func__ - #include <linux/kernel.h> #include <linux/init.h> #include <linux/debugfs.h> @@ -54,9 +52,7 @@ static LIST_HEAD(regulator_map_list); static bool has_full_constraints; static bool board_wants_dummy_regulator; -#ifdef CONFIG_DEBUG_FS static struct dentry *debugfs_root; -#endif /* * struct regulator_map @@ -84,9 +80,7 @@ struct regulator { char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; -#ifdef CONFIG_DEBUG_FS struct dentry *debugfs; -#endif }; static int _regulator_is_enabled(struct regulator_dev *rdev); @@ -154,7 +148,7 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp regnode = of_parse_phandle(dev->of_node, prop_name, 0); if (!regnode) { - dev_warn(dev, "%s property in node %s references invalid phandle", + dev_dbg(dev, "Looking up %s property in node %s failed", prop_name, dev->of_node->full_name); return NULL; } @@ -807,6 +801,11 @@ static void print_constraints(struct regulator_dev *rdev) count += sprintf(buf + count, "standby"); rdev_info(rdev, "%s\n", buf); + + if ((constraints->min_uV != constraints->max_uV) && + !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) + rdev_warn(rdev, + "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); } static int machine_constraints_voltage(struct regulator_dev *rdev, @@ -996,7 +995,6 @@ static int set_supply(struct regulator_dev *rdev, /** * set_consumer_device_supply - Bind a regulator to a symbolic supply * @rdev: regulator source - * @consumer_dev: device the supply applies to * @consumer_dev_name: dev_name() string for device supply applies to * @supply: symbolic name for supply * @@ -1004,22 +1002,14 @@ static int set_supply(struct regulator_dev *rdev, * sources to symbolic names for supplies for use by devices. Devices * should use these symbolic names to request regulators, avoiding the * need to provide board-specific regulator names as platform data. - * - * Only one of consumer_dev and consumer_dev_name may be specified. */ static int set_consumer_device_supply(struct regulator_dev *rdev, - struct device *consumer_dev, const char *consumer_dev_name, - const char *supply) + const char *consumer_dev_name, + const char *supply) { struct regulator_map *node; int has_dev; - if (consumer_dev && consumer_dev_name) - return -EINVAL; - - if (!consumer_dev_name && consumer_dev) - consumer_dev_name = dev_name(consumer_dev); - if (supply == NULL) return -EINVAL; @@ -1039,11 +1029,12 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, if (strcmp(node->supply, supply) != 0) continue; - dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n", - dev_name(&node->regulator->dev), - node->regulator->desc->name, - supply, - dev_name(&rdev->dev), rdev_get_name(rdev)); + pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n", + consumer_dev_name, + dev_name(&node->regulator->dev), + node->regulator->desc->name, + supply, + dev_name(&rdev->dev), rdev_get_name(rdev)); return -EBUSY; } @@ -1142,12 +1133,10 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, goto attr_err; } -#ifdef CONFIG_DEBUG_FS regulator->debugfs = debugfs_create_dir(regulator->supply_name, rdev->debugfs); - if (IS_ERR_OR_NULL(regulator->debugfs)) { + if (!regulator->debugfs) { rdev_warn(rdev, "Failed to create debugfs directory\n"); - regulator->debugfs = NULL; } else { debugfs_create_u32("uA_load", 0444, regulator->debugfs, ®ulator->uA_load); @@ -1156,7 +1145,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, debugfs_create_u32("max_uV", 0444, regulator->debugfs, ®ulator->max_uV); } -#endif mutex_unlock(&rdev->mutex); return regulator; @@ -1320,6 +1308,40 @@ struct regulator *regulator_get(struct device *dev, const char *id) } EXPORT_SYMBOL_GPL(regulator_get); +static void devm_regulator_release(struct device *dev, void *res) +{ + regulator_put(*(struct regulator **)res); +} + +/** + * devm_regulator_get - Resource managed regulator_get() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get(). Regulators returned from this function are + * automatically regulator_put() on driver detach. See regulator_get() for more + * information. + */ +struct regulator *devm_regulator_get(struct device *dev, const char *id) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + regulator = regulator_get(dev, id); + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} +EXPORT_SYMBOL_GPL(devm_regulator_get); + /** * regulator_get_exclusive - obtain exclusive access to a regulator. * @dev: device for regulator "consumer" @@ -1365,9 +1387,7 @@ void regulator_put(struct regulator *regulator) mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; -#ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(regulator->debugfs); -#endif /* remove any sysfs entries */ if (regulator->dev) { @@ -1387,6 +1407,34 @@ void regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_put); +static int devm_regulator_match(struct device *dev, void *res, void *data) +{ + struct regulator **r = res; + if (!r || !*r) { + WARN_ON(!r || !*r); + return 0; + } + return *r == data; +} + +/** + * devm_regulator_put - Resource managed regulator_put() + * @regulator: regulator to free + * + * Deallocate a regulator allocated with devm_regulator_get(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_regulator_put(struct regulator *regulator) +{ + int rc; + + rc = devres_destroy(regulator->dev, devm_regulator_release, + devm_regulator_match, regulator); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_put); + static int _regulator_can_change_status(struct regulator_dev *rdev) { if (!rdev->constraints) @@ -1842,8 +1890,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, if (ret < 0) return ret; old_selector = ret; - delay = rdev->desc->ops->set_voltage_time_sel(rdev, + ret = rdev->desc->ops->set_voltage_time_sel(rdev, old_selector, selector); + if (ret < 0) + rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret); + else + delay = ret; } if (best_val != INT_MAX) { @@ -2394,13 +2446,59 @@ int regulator_bulk_get(struct device *dev, int num_consumers, return 0; err: - for (i = 0; i < num_consumers && consumers[i].consumer; i++) + while (--i >= 0) regulator_put(consumers[i].consumer); return ret; } EXPORT_SYMBOL_GPL(regulator_bulk_get); +/** + * devm_regulator_bulk_get - managed get multiple regulator consumers + * + * @dev: Device to supply + * @num_consumers: Number of consumers to register + * @consumers: Configuration of consumers; clients are stored here. + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to get several regulator + * consumers in one operation with management, the regulators will + * automatically be freed when the device is unbound. If any of the + * regulators cannot be acquired then any regulators that were + * allocated will be freed before returning to the caller. + */ +int devm_regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) + consumers[i].consumer = NULL; + + for (i = 0; i < num_consumers; i++) { + consumers[i].consumer = devm_regulator_get(dev, + consumers[i].supply); + if (IS_ERR(consumers[i].consumer)) { + ret = PTR_ERR(consumers[i].consumer); + dev_err(dev, "Failed to get supply '%s': %d\n", + consumers[i].supply, ret); + consumers[i].consumer = NULL; + goto err; + } + } + + return 0; + +err: + for (i = 0; i < num_consumers && consumers[i].consumer; i++) + devm_regulator_put(consumers[i].consumer); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); + static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) { struct regulator_bulk_data *bulk = data; @@ -2444,12 +2542,9 @@ int regulator_bulk_enable(int num_consumers, return 0; err: - for (i = 0; i < num_consumers; i++) - if (consumers[i].ret == 0) - regulator_disable(consumers[i].consumer); - else - pr_err("Failed to enable %s: %d\n", - consumers[i].supply, consumers[i].ret); + pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); + while (--i >= 0) + regulator_disable(consumers[i].consumer); return ret; } @@ -2463,8 +2558,8 @@ EXPORT_SYMBOL_GPL(regulator_bulk_enable); * @return 0 on success, an errno on failure * * This convenience API allows consumers to disable multiple regulator - * clients in a single API call. If any consumers cannot be enabled - * then any others that were disabled will be disabled again prior to + * clients in a single API call. If any consumers cannot be disabled + * then any others that were disabled will be enabled again prior to * return. */ int regulator_bulk_disable(int num_consumers, @@ -2473,7 +2568,7 @@ int regulator_bulk_disable(int num_consumers, int i; int ret; - for (i = 0; i < num_consumers; i++) { + for (i = num_consumers - 1; i >= 0; --i) { ret = regulator_disable(consumers[i].consumer); if (ret != 0) goto err; @@ -2483,7 +2578,7 @@ int regulator_bulk_disable(int num_consumers, err: pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret); - for (--i; i >= 0; --i) + for (++i; i < num_consumers; ++i) regulator_enable(consumers[i].consumer); return ret; @@ -2710,11 +2805,9 @@ static int add_regulator_attributes(struct regulator_dev *rdev) static void rdev_init_debugfs(struct regulator_dev *rdev) { -#ifdef CONFIG_DEBUG_FS rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); - if (IS_ERR(rdev->debugfs) || !rdev->debugfs) { + if (!rdev->debugfs) { rdev_warn(rdev, "Failed to create debugfs directory\n"); - rdev->debugfs = NULL; return; } @@ -2722,7 +2815,6 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) &rdev->use_count); debugfs_create_u32("open_count", 0444, rdev->debugfs, &rdev->open_count); -#endif } /** @@ -2855,7 +2947,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (init_data) { for (i = 0; i < init_data->num_consumer_supplies; i++) { ret = set_consumer_device_supply(rdev, - init_data->consumer_supplies[i].dev, init_data->consumer_supplies[i].dev_name, init_data->consumer_supplies[i].supply); if (ret < 0) { @@ -2902,9 +2993,7 @@ void regulator_unregister(struct regulator_dev *rdev) return; mutex_lock(®ulator_list_mutex); -#ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(rdev->debugfs); -#endif flush_work_sync(&rdev->disable_work.work); WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); @@ -3114,12 +3203,14 @@ static ssize_t supply_map_read_file(struct file *file, char __user *user_buf, return ret; } +#endif static const struct file_operations supply_map_fops = { +#ifdef CONFIG_DEBUG_FS .read = supply_map_read_file, .llseek = default_llseek, -}; #endif +}; static int __init regulator_init(void) { @@ -3127,17 +3218,12 @@ static int __init regulator_init(void) ret = class_register(®ulator_class); -#ifdef CONFIG_DEBUG_FS debugfs_root = debugfs_create_dir("regulator", NULL); - if (IS_ERR(debugfs_root) || !debugfs_root) { + if (!debugfs_root) pr_warn("regulator: Failed to create debugfs directory\n"); - debugfs_root = NULL; - } - if (IS_ERR(debugfs_create_file("supply_map", 0444, debugfs_root, - NULL, &supply_map_fops))) - pr_warn("regulator: Failed to create supplies debugfs\n"); -#endif + debugfs_create_file("supply_map", 0444, debugfs_root, NULL, + &supply_map_fops); regulator_dummy_init(); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 8dbc54da7d70..1851f0929ef0 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -119,7 +119,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, return -EINVAL; } - val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -202,7 +202,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, return -EINVAL; } - val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -233,10 +233,10 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, thresh = (info->max_uV + info->min_uV) / 2; if (min_uV < thresh) { - val = (thresh - min_uV + info->step_uV - 1) / info->step_uV; + val = DIV_ROUND_UP(thresh - min_uV, info->step_uV); val |= 0x4; } else { - val = (min_uV - thresh + info->step_uV - 1) / info->step_uV; + val = DIV_ROUND_UP(min_uV - thresh, info->step_uV); } *selector = val; @@ -281,7 +281,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, return -EINVAL; } - val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -307,7 +307,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, return -EINVAL; } - val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + val = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val); *selector = val; val <<= info->vol_shift; diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 515443fcd26b..4bd25e75efa0 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -18,74 +18,11 @@ #include <linux/regulator/machine.h> #include <linux/regulator/db8500-prcmu.h> #include <linux/module.h> - -/* - * power state reference count - */ -static int power_state_active_cnt; /* will initialize to zero */ -static DEFINE_SPINLOCK(power_state_active_lock); - -static void power_state_active_enable(void) -{ - unsigned long flags; - - spin_lock_irqsave(&power_state_active_lock, flags); - power_state_active_cnt++; - spin_unlock_irqrestore(&power_state_active_lock, flags); -} - -static int power_state_active_disable(void) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&power_state_active_lock, flags); - if (power_state_active_cnt <= 0) { - pr_err("power state: unbalanced enable/disable calls\n"); - ret = -EINVAL; - goto out; - } - - power_state_active_cnt--; -out: - spin_unlock_irqrestore(&power_state_active_lock, flags); - return ret; -} - -/* - * Exported interface for CPUIdle only. This function is called when interrupts - * are turned off. Hence, no locking. - */ -int power_state_active_is_enabled(void) -{ - return (power_state_active_cnt > 0); -} - -/** - * struct db8500_regulator_info - db8500 regulator information - * @dev: device pointer - * @desc: regulator description - * @rdev: regulator device pointer - * @is_enabled: status of the regulator - * @epod_id: id for EPOD (power domain) - * @is_ramret: RAM retention switch for EPOD (power domain) - * @operating_point: operating point (only for vape, to be removed) - * - */ -struct db8500_regulator_info { - struct device *dev; - struct regulator_desc desc; - struct regulator_dev *rdev; - bool is_enabled; - u16 epod_id; - bool is_ramret; - bool exclude_from_power_state; - unsigned int operating_point; -}; +#include "dbx500-prcmu.h" static int db8500_regulator_enable(struct regulator_dev *rdev) { - struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); if (info == NULL) return -EINVAL; @@ -93,16 +30,18 @@ static int db8500_regulator_enable(struct regulator_dev *rdev) dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n", info->desc.name); - info->is_enabled = true; - if (!info->exclude_from_power_state) - power_state_active_enable(); + if (!info->is_enabled) { + info->is_enabled = true; + if (!info->exclude_from_power_state) + power_state_active_enable(); + } return 0; } static int db8500_regulator_disable(struct regulator_dev *rdev) { - struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); int ret = 0; if (info == NULL) @@ -111,16 +50,18 @@ static int db8500_regulator_disable(struct regulator_dev *rdev) dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n", info->desc.name); - info->is_enabled = false; - if (!info->exclude_from_power_state) - ret = power_state_active_disable(); + if (info->is_enabled) { + info->is_enabled = false; + if (!info->exclude_from_power_state) + ret = power_state_active_disable(); + } return ret; } static int db8500_regulator_is_enabled(struct regulator_dev *rdev) { - struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); if (info == NULL) return -EINVAL; @@ -197,7 +138,7 @@ static int disable_epod(u16 epod_id, bool ramret) */ static int db8500_regulator_switch_enable(struct regulator_dev *rdev) { - struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); int ret; if (info == NULL) @@ -221,7 +162,7 @@ out: static int db8500_regulator_switch_disable(struct regulator_dev *rdev) { - struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); int ret; if (info == NULL) @@ -245,7 +186,7 @@ out: static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev) { - struct db8500_regulator_info *info = rdev_get_drvdata(rdev); + struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); if (info == NULL) return -EINVAL; @@ -266,8 +207,8 @@ static struct regulator_ops db8500_regulator_switch_ops = { /* * Regulator information */ -static struct db8500_regulator_info -db8500_regulator_info[DB8500_NUM_REGULATORS] = { +static struct dbx500_regulator_info +dbx500_regulator_info[DB8500_NUM_REGULATORS] = { [DB8500_REGULATOR_VAPE] = { .desc = { .name = "db8500-vape", @@ -476,12 +417,12 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) int i, err; /* register all regulators */ - for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) { - struct db8500_regulator_info *info; + for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { + struct dbx500_regulator_info *info; struct regulator_init_data *init_data = &db8500_init_data[i]; /* assign per-regulator data */ - info = &db8500_regulator_info[i]; + info = &dbx500_regulator_info[i]; info->dev = &pdev->dev; /* register with the regulator framework */ @@ -494,7 +435,7 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) /* if failing, unregister all earlier regulators */ while (--i >= 0) { - info = &db8500_regulator_info[i]; + info = &dbx500_regulator_info[i]; regulator_unregister(info->rdev); } return err; @@ -503,17 +444,22 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) dev_dbg(rdev_get_dev(info->rdev), "regulator-%s-probed\n", info->desc.name); } + err = ux500_regulator_debug_init(pdev, + dbx500_regulator_info, + ARRAY_SIZE(dbx500_regulator_info)); - return 0; + return err; } static int __exit db8500_regulator_remove(struct platform_device *pdev) { int i; - for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) { - struct db8500_regulator_info *info; - info = &db8500_regulator_info[i]; + ux500_regulator_debug_exit(); + + for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { + struct dbx500_regulator_info *info; + info = &dbx500_regulator_info[i]; dev_vdbg(rdev_get_dev(info->rdev), "regulator-%s-remove\n", info->desc.name); diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c new file mode 100644 index 000000000000..f2e5ecdc5864 --- /dev/null +++ b/drivers/regulator/dbx500-prcmu.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson + * + * UX500 common part of Power domain regulators + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/regulator/driver.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/slab.h> + +#include "dbx500-prcmu.h" + +/* + * power state reference count + */ +static int power_state_active_cnt; /* will initialize to zero */ +static DEFINE_SPINLOCK(power_state_active_lock); + +int power_state_active_get(void) +{ + unsigned long flags; + int cnt; + + spin_lock_irqsave(&power_state_active_lock, flags); + cnt = power_state_active_cnt; + spin_unlock_irqrestore(&power_state_active_lock, flags); + + return cnt; +} + +void power_state_active_enable(void) +{ + unsigned long flags; + + spin_lock_irqsave(&power_state_active_lock, flags); + power_state_active_cnt++; + spin_unlock_irqrestore(&power_state_active_lock, flags); +} + +int power_state_active_disable(void) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&power_state_active_lock, flags); + if (power_state_active_cnt <= 0) { + pr_err("power state: unbalanced enable/disable calls\n"); + ret = -EINVAL; + goto out; + } + + power_state_active_cnt--; +out: + spin_unlock_irqrestore(&power_state_active_lock, flags); + return ret; +} + +#ifdef CONFIG_REGULATOR_DEBUG + +static struct ux500_regulator_debug { + struct dentry *dir; + struct dentry *status_file; + struct dentry *power_state_cnt_file; + struct dbx500_regulator_info *regulator_array; + int num_regulators; + u8 *state_before_suspend; + u8 *state_after_suspend; +} rdebug; + +void ux500_regulator_suspend_debug(void) +{ + int i; + for (i = 0; i < rdebug.num_regulators; i++) + rdebug.state_before_suspend[i] = + rdebug.regulator_array[i].is_enabled; +} + +void ux500_regulator_resume_debug(void) +{ + int i; + for (i = 0; i < rdebug.num_regulators; i++) + rdebug.state_after_suspend[i] = + rdebug.regulator_array[i].is_enabled; +} + +static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) +{ + struct device *dev = s->private; + int err; + + /* print power state count */ + err = seq_printf(s, "ux500-regulator power state count: %i\n", + power_state_active_get()); + if (err < 0) + dev_err(dev, "seq_printf overflow\n"); + + return 0; +} + +static int ux500_regulator_power_state_cnt_open(struct inode *inode, + struct file *file) +{ + return single_open(file, ux500_regulator_power_state_cnt_print, + inode->i_private); +} + +static const struct file_operations ux500_regulator_power_state_cnt_fops = { + .open = ux500_regulator_power_state_cnt_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int ux500_regulator_status_print(struct seq_file *s, void *p) +{ + struct device *dev = s->private; + int err; + int i; + + /* print dump header */ + err = seq_printf(s, "ux500-regulator status:\n"); + if (err < 0) + dev_err(dev, "seq_printf overflow\n"); + + err = seq_printf(s, "%31s : %8s : %8s\n", "current", + "before", "after"); + if (err < 0) + dev_err(dev, "seq_printf overflow\n"); + + for (i = 0; i < rdebug.num_regulators; i++) { + struct dbx500_regulator_info *info; + /* Access per-regulator data */ + info = &rdebug.regulator_array[i]; + + /* print status */ + err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name, + info->is_enabled ? "enabled" : "disabled", + rdebug.state_before_suspend[i] ? "enabled" : "disabled", + rdebug.state_after_suspend[i] ? "enabled" : "disabled"); + if (err < 0) + dev_err(dev, "seq_printf overflow\n"); + } + + return 0; +} + +static int ux500_regulator_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, ux500_regulator_status_print, + inode->i_private); +} + +static const struct file_operations ux500_regulator_status_fops = { + .open = ux500_regulator_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +int __attribute__((weak)) dbx500_regulator_testcase( + struct dbx500_regulator_info *regulator_info, + int num_regulators) +{ + return 0; +} + +int __devinit +ux500_regulator_debug_init(struct platform_device *pdev, + struct dbx500_regulator_info *regulator_info, + int num_regulators) +{ + /* create directory */ + rdebug.dir = debugfs_create_dir("ux500-regulator", NULL); + if (!rdebug.dir) + goto exit_no_debugfs; + + /* create "status" file */ + rdebug.status_file = debugfs_create_file("status", + S_IRUGO, rdebug.dir, &pdev->dev, + &ux500_regulator_status_fops); + if (!rdebug.status_file) + goto exit_destroy_dir; + + /* create "power-state-count" file */ + rdebug.power_state_cnt_file = debugfs_create_file("power-state-count", + S_IRUGO, rdebug.dir, &pdev->dev, + &ux500_regulator_power_state_cnt_fops); + if (!rdebug.power_state_cnt_file) + goto exit_destroy_status; + + rdebug.regulator_array = regulator_info; + rdebug.num_regulators = num_regulators; + + rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL); + if (!rdebug.state_before_suspend) { + dev_err(&pdev->dev, + "could not allocate memory for saving state\n"); + goto exit_destroy_power_state; + } + + rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL); + if (!rdebug.state_after_suspend) { + dev_err(&pdev->dev, + "could not allocate memory for saving state\n"); + goto exit_free; + } + + dbx500_regulator_testcase(regulator_info, num_regulators); + return 0; + +exit_free: + kfree(rdebug.state_before_suspend); +exit_destroy_power_state: + debugfs_remove(rdebug.power_state_cnt_file); +exit_destroy_status: + debugfs_remove(rdebug.status_file); +exit_destroy_dir: + debugfs_remove(rdebug.dir); +exit_no_debugfs: + dev_err(&pdev->dev, "failed to create debugfs entries.\n"); + return -ENOMEM; +} + +int __devexit ux500_regulator_debug_exit(void) +{ + debugfs_remove_recursive(rdebug.dir); + kfree(rdebug.state_after_suspend); + kfree(rdebug.state_before_suspend); + + return 0; +} +#endif diff --git a/drivers/regulator/dbx500-prcmu.h b/drivers/regulator/dbx500-prcmu.h new file mode 100644 index 000000000000..e763883a44f4 --- /dev/null +++ b/drivers/regulator/dbx500-prcmu.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson, + * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson + * + * License Terms: GNU General Public License v2 + * + */ + +#ifndef DBX500_REGULATOR_H +#define DBX500_REGULATOR_H + +#include <linux/platform_device.h> + +/** + * struct dbx500_regulator_info - dbx500 regulator information + * @dev: device pointer + * @desc: regulator description + * @rdev: regulator device pointer + * @is_enabled: status of the regulator + * @epod_id: id for EPOD (power domain) + * @is_ramret: RAM retention switch for EPOD (power domain) + * @operating_point: operating point (only for vape, to be removed) + * + */ +struct dbx500_regulator_info { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + bool is_enabled; + u16 epod_id; + bool is_ramret; + bool exclude_from_power_state; + unsigned int operating_point; +}; + +void power_state_active_enable(void); +int power_state_active_disable(void); + + +#ifdef CONFIG_REGULATOR_DEBUG +int ux500_regulator_debug_init(struct platform_device *pdev, + struct dbx500_regulator_info *regulator_info, + int num_regulators); + +int ux500_regulator_debug_exit(void); +#else + +static inline int ux500_regulator_debug_init(struct platform_device *pdev, + struct dbx500_regulator_info *regulator_info, + int num_regulators) +{ + return 0; +} + +static inline int ux500_regulator_debug_exit(void) +{ + return 0; +} + +#endif +#endif diff --git a/drivers/regulator/fixed-helper.c b/drivers/regulator/fixed-helper.c new file mode 100644 index 000000000000..30d0a15b8949 --- /dev/null +++ b/drivers/regulator/fixed-helper.c @@ -0,0 +1,53 @@ +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> + +struct fixed_regulator_data { + struct fixed_voltage_config cfg; + struct regulator_init_data init_data; + struct platform_device pdev; +}; + +static void regulator_fixed_release(struct device *dev) +{ + struct fixed_regulator_data *data = container_of(dev, + struct fixed_regulator_data, pdev.dev); + kfree(data); +} + +/** + * regulator_register_fixed - register a no-op fixed regulator + * @name: supply name + * @id: platform device id + * @supplies: consumers for this regulator + * @num_supplies: number of consumers + */ +struct platform_device *regulator_register_fixed(int id, + struct regulator_consumer_supply *supplies, int num_supplies) +{ + struct fixed_regulator_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return NULL; + + data->cfg.supply_name = "dummy"; + data->cfg.microvolts = 0; + data->cfg.gpio = -EINVAL; + data->cfg.enabled_at_boot = 1; + data->cfg.init_data = &data->init_data; + + data->init_data.constraints.always_on = 1; + data->init_data.consumer_supplies = supplies; + data->init_data.num_consumer_supplies = num_supplies; + + data->pdev.name = "reg-fixed-voltage"; + data->pdev.id = id; + data->pdev.dev.platform_data = &data->cfg; + data->pdev.dev.release = regulator_fixed_release; + + platform_device_register(&data->pdev); + + return &data->pdev; +} diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index e24e3a174c4b..40f38030b394 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -192,7 +192,9 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; drvdata->desc.ops = &fixed_voltage_ops; - drvdata->desc.n_voltages = 1; + + if (config->microvolts) + drvdata->desc.n_voltages = 1; drvdata->microvolts = config->microvolts; drvdata->gpio = config->gpio; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index c1a456c4257c..775f5fd208c3 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -63,23 +63,15 @@ static int isl6271a_set_voltage(struct regulator_dev *dev, unsigned *selector) { struct isl_pmic *pmic = rdev_get_drvdata(dev); - int vsel, err, data; + int err, data; if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX) return -EINVAL; if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX) return -EINVAL; - /* Align to 50000 mV */ - vsel = minuV - (minuV % ISL6271A_VOLTAGE_STEP); - - /* If the result fell out of [minuV,maxuV] range, put it back */ - if (vsel < minuV) - vsel += ISL6271A_VOLTAGE_STEP; - - /* Convert the microvolts to data for the chip */ - data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP; - + data = DIV_ROUND_UP(minuV - ISL6271A_VOLTAGE_MIN, + ISL6271A_VOLTAGE_STEP); *selector = data; mutex_lock(&pmic->mtx); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 40e7a4db2853..282d2ee0604e 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -76,8 +76,8 @@ static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV, if (min_uV < max1586->min_uV) min_uV = max1586->min_uV; - *selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + - range_uV - 1) / range_uV; + *selector = DIV_ROUND_UP((min_uV - max1586->min_uV) * + MAX1586_V3_MAX_VSEL, range_uV); if (max1586_v3_calc_voltage(max1586, *selector) > max_uV) return -EINVAL; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index d0e1180ad961..824c650436ed 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -101,8 +101,7 @@ static int max8649_set_voltage(struct regulator_dev *rdev, min_uV, max_uV); return -EINVAL; } - data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1) - / MAX8649_DCDC_STEP; + data = DIV_ROUND_UP(min_uV - MAX8649_DCDC_VMIN, MAX8649_DCDC_STEP); mask = MAX8649_VOL_MASK; *selector = data & mask; @@ -270,7 +269,7 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, ret); goto out; } - dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", ret); + dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", val); /* enable VID0 & VID1 */ regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0); diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index a838e664569f..4c5b05311f47 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -153,14 +153,15 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV, if (max_uV < MAX8660_DCDC_MIN_UV || max_uV > MAX8660_DCDC_MAX_UV) return -EINVAL; - selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1)) - / MAX8660_DCDC_STEP; - *s = selector; + selector = DIV_ROUND_UP(min_uV - MAX8660_DCDC_MIN_UV, + MAX8660_DCDC_STEP); ret = max8660_dcdc_list(rdev, selector); if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2; ret = max8660_write(max8660, reg, 0, selector); if (ret) @@ -210,8 +211,9 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV, if (max_uV < MAX8660_LDO5_MIN_UV || max_uV > MAX8660_LDO5_MAX_UV) return -EINVAL; - selector = (min_uV - (MAX8660_LDO5_MIN_UV - MAX8660_LDO5_STEP + 1)) - / MAX8660_LDO5_STEP; + selector = DIV_ROUND_UP(min_uV - MAX8660_LDO5_MIN_UV, + MAX8660_LDO5_STEP); + ret = max8660_ldo5_list(rdev, selector); if (ret < 0 || ret > max_uV) return -EINVAL; @@ -287,8 +289,8 @@ static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, if (max_uV < MAX8660_LDO67_MIN_UV || max_uV > MAX8660_LDO67_MAX_UV) return -EINVAL; - selector = (min_uV - (MAX8660_LDO67_MIN_UV - MAX8660_LDO67_STEP + 1)) - / MAX8660_LDO67_STEP; + selector = DIV_ROUND_UP(min_uV - MAX8660_LDO67_MIN_UV, + MAX8660_LDO67_STEP); ret = max8660_ldo67_list(rdev, selector); if (ret < 0 || ret > max_uV) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index cc290d37c463..2f242f43096e 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -73,7 +73,7 @@ static int max8925_set_voltage(struct regulator_dev *rdev, min_uV, max_uV); return -EINVAL; } - data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + data = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); *selector = data; data <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -140,7 +140,7 @@ static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX) return -EINVAL; - data = (uV - SD1_DVM_VMIN + SD1_DVM_STEP - 1) / SD1_DVM_STEP; + data = DIV_ROUND_UP(uV - SD1_DVM_VMIN, SD1_DVM_STEP); data <<= SD1_DVM_SHIFT; mask = 3 << SD1_DVM_SHIFT; diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index d26e8646277b..96579296f04d 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -130,15 +130,10 @@ static const struct voltage_map_desc *reg_voltage_map[] = { [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc, }; -static inline int max8997_get_rid(struct regulator_dev *rdev) -{ - return rdev_get_id(rdev); -} - static int max8997_list_voltage_safeout(struct regulator_dev *rdev, unsigned int selector) { - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) { switch (selector) { @@ -161,7 +156,7 @@ static int max8997_list_voltage_safeout(struct regulator_dev *rdev, static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev, unsigned int selector) { - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); if (rid != MAX8997_CHARGER_CV) goto err; @@ -184,7 +179,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev, unsigned int selector) { const struct voltage_map_desc *desc; - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); int val; if (rid >= ARRAY_SIZE(reg_voltage_map) || @@ -205,7 +200,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev, static int max8997_get_enable_register(struct regulator_dev *rdev, int *reg, int *mask, int *pattern) { - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); switch (rid) { case MAX8997_LDO1 ... MAX8997_LDO21: @@ -325,7 +320,7 @@ static int max8997_reg_disable(struct regulator_dev *rdev) static int max8997_get_voltage_register(struct regulator_dev *rdev, int *_reg, int *_shift, int *_mask) { - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); int reg, shift = 0, mask = 0x3f; switch (rid) { @@ -386,7 +381,7 @@ static int max8997_get_voltage(struct regulator_dev *rdev) struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; int reg, shift, mask, ret; - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); u8 val; ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); @@ -446,7 +441,7 @@ static int max8997_set_voltage_charger_cv(struct regulator_dev *rdev, { struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); int lb, ub; int reg, shift = 0, mask, ret = 0; u8 val = 0x0; @@ -503,7 +498,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, struct i2c_client *i2c = max8997->iodev->i2c; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const struct voltage_map_desc *desc; - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); int reg, shift = 0, mask, ret; int i; u8 org; @@ -564,7 +559,7 @@ static int max8997_assess_side_effect(struct regulator_dev *rdev, u8 new_val, int *best) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); u8 *buckx_val[3]; bool buckx_gpiodvs[3]; int side_effect[8]; @@ -641,7 +636,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct max8997_data *max8997 = rdev_get_drvdata(rdev); - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); const struct voltage_map_desc *desc; int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; bool gpio_dvs_mode = false; @@ -724,7 +719,7 @@ static int max8997_set_voltage_safeout(struct regulator_dev *rdev, { struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); int reg, shift = 0, mask, ret; int i = 0; u8 val; @@ -766,7 +761,7 @@ static int max8997_reg_disable_suspend(struct regulator_dev *rdev) struct max8997_data *max8997 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8997->iodev->i2c; int ret, reg, mask, pattern; - int rid = max8997_get_rid(rdev); + int rid = rdev_get_id(rdev); ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); if (ret) @@ -908,13 +903,13 @@ static struct regulator_desc regulators[] = { }, regulator_desc_buck(7), { - .name = "EN32KHz AP", + .name = "EN32KHz_AP", .id = MAX8997_EN32KHZ_AP, .ops = &max8997_fixedvolt_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "EN32KHz CP", + .name = "EN32KHz_CP", .id = MAX8997_EN32KHZ_CP, .ops = &max8997_fixedvolt_ops, .type = REGULATOR_VOLTAGE, @@ -938,7 +933,7 @@ static struct regulator_desc regulators[] = { .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, }, { - .name = "CHARGER CV", + .name = "CHARGER_CV", .id = MAX8997_CHARGER_CV, .ops = &max8997_fixedstate_ops, .type = REGULATOR_VOLTAGE, @@ -950,7 +945,7 @@ static struct regulator_desc regulators[] = { .type = REGULATOR_CURRENT, .owner = THIS_MODULE, }, { - .name = "CHARGER TOPOFF", + .name = "CHARGER_TOPOFF", .id = MAX8997_CHARGER_TOPOFF, .ops = &max8997_charger_fixedstate_ops, .type = REGULATOR_CURRENT, diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 2d38c2493a07..5890265eeacc 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -112,16 +112,11 @@ static const struct voltage_map_desc *ldo_voltage_map[] = { &buck4_voltage_map_desc, /* BUCK4 */ }; -static inline int max8998_get_ldo(struct regulator_dev *rdev) -{ - return rdev_get_id(rdev); -} - static int max8998_list_voltage(struct regulator_dev *rdev, unsigned int selector) { const struct voltage_map_desc *desc; - int ldo = max8998_get_ldo(rdev); + int ldo = rdev_get_id(rdev); int val; if (ldo >= ARRAY_SIZE(ldo_voltage_map)) @@ -141,7 +136,7 @@ static int max8998_list_voltage(struct regulator_dev *rdev, static int max8998_get_enable_register(struct regulator_dev *rdev, int *reg, int *shift) { - int ldo = max8998_get_ldo(rdev); + int ldo = rdev_get_id(rdev); switch (ldo) { case MAX8998_LDO2 ... MAX8998_LDO5: @@ -222,7 +217,7 @@ static int max8998_ldo_disable(struct regulator_dev *rdev) static int max8998_get_voltage_register(struct regulator_dev *rdev, int *_reg, int *_shift, int *_mask) { - int ldo = max8998_get_ldo(rdev); + int ldo = rdev_get_id(rdev); struct max8998_data *max8998 = rdev_get_drvdata(rdev); int reg, shift = 0, mask = 0xff; @@ -310,7 +305,7 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev, struct i2c_client *i2c = max8998->iodev->i2c; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const struct voltage_map_desc *desc; - int ldo = max8998_get_ldo(rdev); + int ldo = rdev_get_id(rdev); int reg, shift = 0, mask, ret; int i = 0; @@ -362,7 +357,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, struct i2c_client *i2c = max8998->iodev->i2c; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; const struct voltage_map_desc *desc; - int buck = max8998_get_ldo(rdev); + int buck = rdev_get_id(rdev); int reg, shift = 0, mask, ret; int difference = 0, i = 0, j = 0, previous_vol = 0; u8 val = 0; @@ -829,7 +824,6 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) buck12_voltage_map_desc.step*i < (pdata->buck2_voltage2 / 1000)) i++; - printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx); max8998->buck2_vol[1] = i; ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i); if (ret) diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 8e9b90ad88ae..6c0face87ffe 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -344,6 +344,9 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id); + if (!pdata) + return -EINVAL; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + pdata->num_regulators * sizeof(priv->regulators[0]), GFP_KERNEL); diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 1d1c31056297..6db46c632f13 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -142,6 +142,7 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, case PCF50633_REGULATOR_LDO5: case PCF50633_REGULATOR_LDO6: case PCF50633_REGULATOR_HCLDO: + case PCF50633_REGULATOR_MEMLDO: volt_bits = ldo_voltage_bits(millivolts); break; default: @@ -175,6 +176,7 @@ static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id, case PCF50633_REGULATOR_LDO5: case PCF50633_REGULATOR_LDO6: case PCF50633_REGULATOR_HCLDO: + case PCF50633_REGULATOR_MEMLDO: millivolts = ldo_voltage_value(bits); break; default: @@ -217,9 +219,6 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev, case PCF50633_REGULATOR_AUTO: index += 0x2f; break; - case PCF50633_REGULATOR_HCLDO: - index += 0x01; - break; default: break; } @@ -288,27 +287,27 @@ static struct regulator_ops pcf50633_regulator_ops = { static struct regulator_desc regulators[] = { [PCF50633_REGULATOR_AUTO] = - PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 80), + PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 81), [PCF50633_REGULATOR_DOWN1] = - PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 95), + PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 96), [PCF50633_REGULATOR_DOWN2] = - PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 95), + PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 96), [PCF50633_REGULATOR_LDO1] = - PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 27), + PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 28), [PCF50633_REGULATOR_LDO2] = - PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 27), + PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 28), [PCF50633_REGULATOR_LDO3] = - PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 27), + PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 28), [PCF50633_REGULATOR_LDO4] = - PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 27), + PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 28), [PCF50633_REGULATOR_LDO5] = - PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 27), + PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 28), [PCF50633_REGULATOR_LDO6] = - PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 27), + PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 28), [PCF50633_REGULATOR_HCLDO] = - PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 26), + PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 28), [PCF50633_REGULATOR_MEMLDO] = - PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 0), + PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 28), }; static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c new file mode 100644 index 000000000000..58447db15de1 --- /dev/null +++ b/drivers/regulator/s5m8767.c @@ -0,0 +1,790 @@ +/* + * s5m8767.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/s5m87xx/s5m-core.h> +#include <linux/mfd/s5m87xx/s5m-pmic.h> + +struct s5m8767_info { + struct device *dev; + struct s5m87xx_dev *iodev; + int num_regulators; + struct regulator_dev **rdev; + + int ramp_delay; + bool buck2_ramp; + bool buck3_ramp; + bool buck4_ramp; + + bool buck2_gpiodvs; + bool buck3_gpiodvs; + bool buck4_gpiodvs; + u8 buck2_vol[8]; + u8 buck3_vol[8]; + u8 buck4_vol[8]; + int buck_gpios[3]; + int buck_gpioindex; +}; + +struct s5m_voltage_desc { + int max; + int min; + int step; +}; + +static const struct s5m_voltage_desc buck_voltage_val1 = { + .max = 2225000, + .min = 650000, + .step = 6250, +}; + +static const struct s5m_voltage_desc buck_voltage_val2 = { + .max = 1600000, + .min = 600000, + .step = 6250, +}; + +static const struct s5m_voltage_desc buck_voltage_val3 = { + .max = 3000000, + .min = 750000, + .step = 12500, +}; + +static const struct s5m_voltage_desc ldo_voltage_val1 = { + .max = 3950000, + .min = 800000, + .step = 50000, +}; + +static const struct s5m_voltage_desc ldo_voltage_val2 = { + .max = 2375000, + .min = 800000, + .step = 25000, +}; + +static const struct s5m_voltage_desc *reg_voltage_map[] = { + [S5M8767_LDO1] = &ldo_voltage_val2, + [S5M8767_LDO2] = &ldo_voltage_val2, + [S5M8767_LDO3] = &ldo_voltage_val1, + [S5M8767_LDO4] = &ldo_voltage_val1, + [S5M8767_LDO5] = &ldo_voltage_val1, + [S5M8767_LDO6] = &ldo_voltage_val2, + [S5M8767_LDO7] = &ldo_voltage_val2, + [S5M8767_LDO8] = &ldo_voltage_val2, + [S5M8767_LDO9] = &ldo_voltage_val1, + [S5M8767_LDO10] = &ldo_voltage_val1, + [S5M8767_LDO11] = &ldo_voltage_val1, + [S5M8767_LDO12] = &ldo_voltage_val1, + [S5M8767_LDO13] = &ldo_voltage_val1, + [S5M8767_LDO14] = &ldo_voltage_val1, + [S5M8767_LDO15] = &ldo_voltage_val2, + [S5M8767_LDO16] = &ldo_voltage_val1, + [S5M8767_LDO17] = &ldo_voltage_val1, + [S5M8767_LDO18] = &ldo_voltage_val1, + [S5M8767_LDO19] = &ldo_voltage_val1, + [S5M8767_LDO20] = &ldo_voltage_val1, + [S5M8767_LDO21] = &ldo_voltage_val1, + [S5M8767_LDO22] = &ldo_voltage_val1, + [S5M8767_LDO23] = &ldo_voltage_val1, + [S5M8767_LDO24] = &ldo_voltage_val1, + [S5M8767_LDO25] = &ldo_voltage_val1, + [S5M8767_LDO26] = &ldo_voltage_val1, + [S5M8767_LDO27] = &ldo_voltage_val1, + [S5M8767_LDO28] = &ldo_voltage_val1, + [S5M8767_BUCK1] = &buck_voltage_val1, + [S5M8767_BUCK2] = &buck_voltage_val2, + [S5M8767_BUCK3] = &buck_voltage_val2, + [S5M8767_BUCK4] = &buck_voltage_val2, + [S5M8767_BUCK5] = &buck_voltage_val1, + [S5M8767_BUCK6] = &buck_voltage_val1, + [S5M8767_BUCK7] = NULL, + [S5M8767_BUCK8] = NULL, + [S5M8767_BUCK9] = &buck_voltage_val3, +}; + +static int s5m8767_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct s5m_voltage_desc *desc; + int reg_id = rdev_get_id(rdev); + int val; + + if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0) + return -EINVAL; + + desc = reg_voltage_map[reg_id]; + if (desc == NULL) + return -EINVAL; + + val = desc->min + desc->step * selector; + if (val > desc->max) + return -EINVAL; + + return val; +} + +static int s5m8767_get_register(struct regulator_dev *rdev, int *reg) +{ + int reg_id = rdev_get_id(rdev); + + switch (reg_id) { + case S5M8767_LDO1 ... S5M8767_LDO2: + *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); + break; + case S5M8767_LDO3 ... S5M8767_LDO28: + *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); + break; + case S5M8767_BUCK1: + *reg = S5M8767_REG_BUCK1CTRL1; + break; + case S5M8767_BUCK2 ... S5M8767_BUCK4: + *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9; + break; + case S5M8767_BUCK5: + *reg = S5M8767_REG_BUCK5CTRL1; + break; + case S5M8767_BUCK6 ... S5M8767_BUCK9: + *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + int ret, reg; + int mask = 0xc0, pattern = 0xc0; + u8 val; + + ret = s5m8767_get_register(rdev, ®); + if (ret == -EINVAL) + return 1; + else if (ret) + return ret; + + ret = s5m_reg_read(s5m8767->iodev, reg, &val); + if (ret) + return ret; + + return (val & mask) == pattern; +} + +static int s5m8767_reg_enable(struct regulator_dev *rdev) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + int ret, reg; + int mask = 0xc0, pattern = 0xc0; + + ret = s5m8767_get_register(rdev, ®); + if (ret) + return ret; + + return s5m_reg_update(s5m8767->iodev, reg, pattern, mask); +} + +static int s5m8767_reg_disable(struct regulator_dev *rdev) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + int ret, reg; + int mask = 0xc0, pattern = 0xc0; + + ret = s5m8767_get_register(rdev, ®); + if (ret) + return ret; + + return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask); +} + +static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + int reg_id = rdev_get_id(rdev); + int reg; + + switch (reg_id) { + case S5M8767_LDO1 ... S5M8767_LDO2: + reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); + break; + case S5M8767_LDO3 ... S5M8767_LDO28: + reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); + break; + case S5M8767_BUCK1: + reg = S5M8767_REG_BUCK1CTRL2; + break; + case S5M8767_BUCK2: + reg = S5M8767_REG_BUCK2DVS1; + if (s5m8767->buck2_gpiodvs) + reg += s5m8767->buck_gpioindex; + break; + case S5M8767_BUCK3: + reg = S5M8767_REG_BUCK3DVS1; + if (s5m8767->buck3_gpiodvs) + reg += s5m8767->buck_gpioindex; + break; + case S5M8767_BUCK4: + reg = S5M8767_REG_BUCK4DVS1; + if (s5m8767->buck4_gpiodvs) + reg += s5m8767->buck_gpioindex; + break; + case S5M8767_BUCK5: + reg = S5M8767_REG_BUCK5CTRL2; + break; + case S5M8767_BUCK6 ... S5M8767_BUCK9: + reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2; + break; + default: + return -EINVAL; + } + + *_reg = reg; + + return 0; +} + +static int s5m8767_get_voltage_sel(struct regulator_dev *rdev) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + int reg, mask, ret; + int reg_id = rdev_get_id(rdev); + u8 val; + + ret = s5m8767_get_voltage_register(rdev, ®); + if (ret) + return ret; + + mask = (reg_id < S5M8767_BUCK1) ? 0x3f : 0xff; + + ret = s5m_reg_read(s5m8767->iodev, reg, &val); + if (ret) + return ret; + + val &= mask; + + return val; +} + +static int s5m8767_convert_voltage_to_sel( + const struct s5m_voltage_desc *desc, + int min_vol, int max_vol) +{ + int selector = 0; + + if (desc == NULL) + return -EINVAL; + + if (max_vol < desc->min || min_vol > desc->max) + return -EINVAL; + + selector = (min_vol - desc->min) / desc->step; + + if (desc->min + desc->step * selector > max_vol) + return -EINVAL; + + return selector; +} + +static int s5m8767_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + const struct s5m_voltage_desc *desc; + int reg_id = rdev_get_id(rdev); + int reg, mask, ret; + int i; + u8 val; + + switch (reg_id) { + case S5M8767_LDO1 ... S5M8767_LDO28: + mask = 0x3f; + break; + case S5M8767_BUCK1 ... S5M8767_BUCK6: + mask = 0xff; + break; + case S5M8767_BUCK7 ... S5M8767_BUCK8: + return -EINVAL; + case S5M8767_BUCK9: + mask = 0xff; + break; + default: + return -EINVAL; + } + + desc = reg_voltage_map[reg_id]; + + i = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV); + if (i < 0) + return i; + + ret = s5m8767_get_voltage_register(rdev, ®); + if (ret) + return ret; + + s5m_reg_read(s5m8767->iodev, reg, &val); + val = val & mask; + + ret = s5m_reg_write(s5m8767->iodev, reg, val); + *selector = i; + + return ret; +} + +static inline void s5m8767_set_high(struct s5m8767_info *s5m8767) +{ + int temp_index = s5m8767->buck_gpioindex; + + gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); + gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); + gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); +} + +static inline void s5m8767_set_low(struct s5m8767_info *s5m8767) +{ + int temp_index = s5m8767->buck_gpioindex; + + gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); + gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); + gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); +} + +static int s5m8767_set_voltage_buck(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + int reg_id = rdev_get_id(rdev); + const struct s5m_voltage_desc *desc; + int new_val, old_val, i = 0; + + if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6) + return -EINVAL; + + switch (reg_id) { + case S5M8767_BUCK1: + return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); + case S5M8767_BUCK2 ... S5M8767_BUCK4: + break; + case S5M8767_BUCK5 ... S5M8767_BUCK6: + return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); + case S5M8767_BUCK9: + return s5m8767_set_voltage(rdev, min_uV, max_uV, selector); + } + + desc = reg_voltage_map[reg_id]; + new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV); + if (new_val < 0) + return new_val; + + switch (reg_id) { + case S5M8767_BUCK2: + if (s5m8767->buck2_gpiodvs) { + while (s5m8767->buck2_vol[i] != new_val) + i++; + } else + return s5m8767_set_voltage(rdev, min_uV, + max_uV, selector); + break; + case S5M8767_BUCK3: + if (s5m8767->buck3_gpiodvs) { + while (s5m8767->buck3_vol[i] != new_val) + i++; + } else + return s5m8767_set_voltage(rdev, min_uV, + max_uV, selector); + break; + case S5M8767_BUCK4: + if (s5m8767->buck3_gpiodvs) { + while (s5m8767->buck4_vol[i] != new_val) + i++; + } else + return s5m8767_set_voltage(rdev, min_uV, + max_uV, selector); + break; + } + + old_val = s5m8767->buck_gpioindex; + s5m8767->buck_gpioindex = i; + + if (i > old_val) + s5m8767_set_high(s5m8767); + else + s5m8767_set_low(s5m8767); + + *selector = new_val; + return 0; +} + +static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_sel, + unsigned int new_sel) +{ + struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); + const struct s5m_voltage_desc *desc; + int reg_id = rdev_get_id(rdev); + + desc = reg_voltage_map[reg_id]; + + if (old_sel < new_sel) + return DIV_ROUND_UP(desc->step * (new_sel - old_sel), + s5m8767->ramp_delay * 1000); + return 0; +} + +static struct regulator_ops s5m8767_ldo_ops = { + .list_voltage = s5m8767_list_voltage, + .is_enabled = s5m8767_reg_is_enabled, + .enable = s5m8767_reg_enable, + .disable = s5m8767_reg_disable, + .get_voltage_sel = s5m8767_get_voltage_sel, + .set_voltage = s5m8767_set_voltage, + .set_voltage_time_sel = s5m8767_set_voltage_time_sel, +}; + +static struct regulator_ops s5m8767_buck_ops = { + .list_voltage = s5m8767_list_voltage, + .is_enabled = s5m8767_reg_is_enabled, + .enable = s5m8767_reg_enable, + .disable = s5m8767_reg_disable, + .get_voltage_sel = s5m8767_get_voltage_sel, + .set_voltage = s5m8767_set_voltage_buck, + .set_voltage_time_sel = s5m8767_set_voltage_time_sel, +}; + +#define regulator_desc_ldo(num) { \ + .name = "LDO"#num, \ + .id = S5M8767_LDO##num, \ + .ops = &s5m8767_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ +} +#define regulator_desc_buck(num) { \ + .name = "BUCK"#num, \ + .id = S5M8767_BUCK##num, \ + .ops = &s5m8767_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ +} + +static struct regulator_desc regulators[] = { + regulator_desc_ldo(1), + regulator_desc_ldo(2), + regulator_desc_ldo(3), + regulator_desc_ldo(4), + regulator_desc_ldo(5), + regulator_desc_ldo(6), + regulator_desc_ldo(7), + regulator_desc_ldo(8), + regulator_desc_ldo(9), + regulator_desc_ldo(10), + regulator_desc_ldo(11), + regulator_desc_ldo(12), + regulator_desc_ldo(13), + regulator_desc_ldo(14), + regulator_desc_ldo(15), + regulator_desc_ldo(16), + regulator_desc_ldo(17), + regulator_desc_ldo(18), + regulator_desc_ldo(19), + regulator_desc_ldo(20), + regulator_desc_ldo(21), + regulator_desc_ldo(22), + regulator_desc_ldo(23), + regulator_desc_ldo(24), + regulator_desc_ldo(25), + regulator_desc_ldo(26), + regulator_desc_ldo(27), + regulator_desc_ldo(28), + regulator_desc_buck(1), + regulator_desc_buck(2), + regulator_desc_buck(3), + regulator_desc_buck(4), + regulator_desc_buck(5), + regulator_desc_buck(6), + regulator_desc_buck(7), + regulator_desc_buck(8), + regulator_desc_buck(9), +}; + +static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) +{ + struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_dev **rdev; + struct s5m8767_info *s5m8767; + int i, ret, size; + + if (!pdata) { + dev_err(pdev->dev.parent, "Platform data not supplied\n"); + return -ENODEV; + } + + if (pdata->buck2_gpiodvs) { + if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { + dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); + return -EINVAL; + } + } + + if (pdata->buck3_gpiodvs) { + if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) { + dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); + return -EINVAL; + } + } + + if (pdata->buck4_gpiodvs) { + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) { + dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); + return -EINVAL; + } + } + + s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info), + GFP_KERNEL); + if (!s5m8767) + return -ENOMEM; + + size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); + s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!s5m8767->rdev) + return -ENOMEM; + + rdev = s5m8767->rdev; + s5m8767->dev = &pdev->dev; + s5m8767->iodev = iodev; + s5m8767->num_regulators = S5M8767_REG_MAX - 2; + platform_set_drvdata(pdev, s5m8767); + + s5m8767->buck_gpioindex = pdata->buck_default_idx; + s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs; + s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs; + s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs; + s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; + s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; + s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; + s5m8767->ramp_delay = pdata->buck_ramp_delay; + s5m8767->buck2_ramp = pdata->buck2_ramp_enable; + s5m8767->buck3_ramp = pdata->buck3_ramp_enable; + s5m8767->buck4_ramp = pdata->buck4_ramp_enable; + + for (i = 0; i < 8; i++) { + if (s5m8767->buck2_gpiodvs) { + s5m8767->buck2_vol[i] = + s5m8767_convert_voltage_to_sel( + &buck_voltage_val2, + pdata->buck2_voltage[i], + pdata->buck2_voltage[i] + + buck_voltage_val2.step); + } + + if (s5m8767->buck3_gpiodvs) { + s5m8767->buck3_vol[i] = + s5m8767_convert_voltage_to_sel( + &buck_voltage_val2, + pdata->buck3_voltage[i], + pdata->buck3_voltage[i] + + buck_voltage_val2.step); + } + + if (s5m8767->buck4_gpiodvs) { + s5m8767->buck4_vol[i] = + s5m8767_convert_voltage_to_sel( + &buck_voltage_val2, + pdata->buck4_voltage[i], + pdata->buck4_voltage[i] + + buck_voltage_val2.step); + } + } + + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || + pdata->buck4_gpiodvs) { + if (gpio_is_valid(pdata->buck_gpios[0]) && + gpio_is_valid(pdata->buck_gpios[1]) && + gpio_is_valid(pdata->buck_gpios[2])) { + ret = gpio_request(pdata->buck_gpios[0], + "S5M8767 SET1"); + if (ret == -EBUSY) + dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n"); + + ret = gpio_request(pdata->buck_gpios[1], + "S5M8767 SET2"); + if (ret == -EBUSY) + dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n"); + + ret = gpio_request(pdata->buck_gpios[2], + "S5M8767 SET3"); + if (ret == -EBUSY) + dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n"); + /* SET1 GPIO */ + gpio_direction_output(pdata->buck_gpios[0], + (s5m8767->buck_gpioindex >> 2) & 0x1); + /* SET2 GPIO */ + gpio_direction_output(pdata->buck_gpios[1], + (s5m8767->buck_gpioindex >> 1) & 0x1); + /* SET3 GPIO */ + gpio_direction_output(pdata->buck_gpios[2], + (s5m8767->buck_gpioindex >> 0) & 0x1); + ret = 0; + } else { + dev_err(&pdev->dev, "GPIO NOT VALID\n"); + ret = -EINVAL; + return ret; + } + } + + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, + (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, + (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, + (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); + + /* Initialize GPIO DVS registers */ + for (i = 0; i < 8; i++) { + if (s5m8767->buck2_gpiodvs) { + s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i, + s5m8767->buck2_vol[i]); + } + + if (s5m8767->buck3_gpiodvs) { + s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i, + s5m8767->buck3_vol[i]); + } + + if (s5m8767->buck4_gpiodvs) { + s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i, + s5m8767->buck4_vol[i]); + } + } + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff); + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff); + s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff); + + if (s5m8767->buck2_ramp) + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); + + if (s5m8767->buck3_ramp) + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04); + + if (s5m8767->buck4_ramp) + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02); + + if (s5m8767->buck2_ramp || s5m8767->buck3_ramp + || s5m8767->buck4_ramp) { + switch (s5m8767->ramp_delay) { + case 15: + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + 0xc0, 0xf0); + break; + case 25: + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + 0xd0, 0xf0); + break; + case 50: + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + 0xe0, 0xf0); + break; + case 100: + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + 0xf0, 0xf0); + break; + default: + s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + 0x90, 0xf0); + } + } + + for (i = 0; i < pdata->num_regulators; i++) { + const struct s5m_voltage_desc *desc; + int id = pdata->regulators[i].id; + + desc = reg_voltage_map[id]; + if (desc) + regulators[id].n_voltages = + (desc->max - desc->min) / desc->step + 1; + + rdev[i] = regulator_register(®ulators[id], s5m8767->dev, + pdata->regulators[i].initdata, s5m8767, NULL); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(s5m8767->dev, "regulator init failed for %d\n", + id); + rdev[i] = NULL; + goto err; + } + } + + return 0; +err: + for (i = 0; i < s5m8767->num_regulators; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + + return ret; +} + +static int __devexit s5m8767_pmic_remove(struct platform_device *pdev) +{ + struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); + struct regulator_dev **rdev = s5m8767->rdev; + int i; + + for (i = 0; i < s5m8767->num_regulators; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + + return 0; +} + +static const struct platform_device_id s5m8767_pmic_id[] = { + { "s5m8767-pmic", 0}, + { }, +}; +MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); + +static struct platform_driver s5m8767_pmic_driver = { + .driver = { + .name = "s5m8767-pmic", + .owner = THIS_MODULE, + }, + .probe = s5m8767_pmic_probe, + .remove = __devexit_p(s5m8767_pmic_remove), + .id_table = s5m8767_pmic_id, +}; + +static int __init s5m8767_pmic_init(void) +{ + return platform_driver_register(&s5m8767_pmic_driver); +} +subsys_initcall(s5m8767_pmic_init); + +static void __exit s5m8767_pmic_exit(void) +{ + platform_driver_unregister(&s5m8767_pmic_driver); +} +module_exit(s5m8767_pmic_exit); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c new file mode 100644 index 000000000000..e2ec73068ee2 --- /dev/null +++ b/drivers/regulator/tps62360-regulator.c @@ -0,0 +1,472 @@ +/* + * tps62360.c -- TI tps62360 + * + * Driver for processor core supply tps62360 and tps62361B + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/tps62360.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/regmap.h> + +/* Register definitions */ +#define REG_VSET0 0 +#define REG_VSET1 1 +#define REG_VSET2 2 +#define REG_VSET3 3 +#define REG_CONTROL 4 +#define REG_TEMP 5 +#define REG_RAMPCTRL 6 +#define REG_CHIPID 8 + +enum chips {TPS62360, TPS62361}; + +#define TPS62360_BASE_VOLTAGE 770 +#define TPS62360_N_VOLTAGES 64 + +#define TPS62361_BASE_VOLTAGE 500 +#define TPS62361_N_VOLTAGES 128 + +/* tps 62360 chip information */ +struct tps62360_chip { + const char *name; + struct device *dev; + struct regulator_desc desc; + struct i2c_client *client; + struct regulator_dev *rdev; + struct regmap *regmap; + int chip_id; + int vsel0_gpio; + int vsel1_gpio; + int voltage_base; + u8 voltage_reg_mask; + bool en_internal_pulldn; + bool en_force_pwm; + bool en_discharge; + bool valid_gpios; + int lru_index[4]; + int curr_vset_vsel[4]; + int curr_vset_id; +}; + +/* + * find_voltage_set_register: Find new voltage configuration register + * (VSET) id. + * The finding of the new VSET register will be based on the LRU mechanism. + * Each VSET register will have different voltage configured . This + * Function will look if any of the VSET register have requested voltage set + * or not. + * - If it is already there then it will make that register as most + * recently used and return as found so that caller need not to set + * the VSET register but need to set the proper gpios to select this + * VSET register. + * - If requested voltage is not found then it will use the least + * recently mechanism to get new VSET register for new configuration + * and will return not_found so that caller need to set new VSET + * register and then gpios (both). + */ +static bool find_voltage_set_register(struct tps62360_chip *tps, + int req_vsel, int *vset_reg_id) +{ + int i; + bool found = false; + int new_vset_reg = tps->lru_index[3]; + int found_index = 3; + for (i = 0; i < 4; ++i) { + if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) { + new_vset_reg = tps->lru_index[i]; + found_index = i; + found = true; + goto update_lru_index; + } + } + +update_lru_index: + for (i = found_index; i > 0; i--) + tps->lru_index[i] = tps->lru_index[i - 1]; + + tps->lru_index[0] = new_vset_reg; + *vset_reg_id = new_vset_reg; + return found; +} + +static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct tps62360_chip *tps = rdev_get_drvdata(dev); + int vsel; + unsigned int data; + int ret; + + ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); + if (ret < 0) { + dev_err(tps->dev, "%s: Error in reading register %d\n", + __func__, REG_VSET0 + tps->curr_vset_id); + return ret; + } + vsel = (int)data & tps->voltage_reg_mask; + return (tps->voltage_base + vsel * 10) * 1000; +} + +static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV, unsigned *selector) +{ + struct tps62360_chip *tps = rdev_get_drvdata(dev); + int vsel; + int ret; + bool found = false; + int new_vset_id = tps->curr_vset_id; + + if (max_uV < min_uV) + return -EINVAL; + + if (min_uV > + ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000)) + return -EINVAL; + + if (max_uV < tps->voltage_base * 1000) + return -EINVAL; + + vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000); + if (selector) + *selector = (vsel & tps->voltage_reg_mask); + + /* + * If gpios are available to select the VSET register then least + * recently used register for new configuration. + */ + if (tps->valid_gpios) + found = find_voltage_set_register(tps, vsel, &new_vset_id); + + if (!found) { + ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id, + tps->voltage_reg_mask, vsel); + if (ret < 0) { + dev_err(tps->dev, "%s: Error in updating register %d\n", + __func__, REG_VSET0 + new_vset_id); + return ret; + } + tps->curr_vset_id = new_vset_id; + tps->curr_vset_vsel[new_vset_id] = vsel; + } + + /* Select proper VSET register vio gpios */ + if (tps->valid_gpios) { + gpio_set_value_cansleep(tps->vsel0_gpio, + new_vset_id & 0x1); + gpio_set_value_cansleep(tps->vsel1_gpio, + (new_vset_id >> 1) & 0x1); + } + return 0; +} + +static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps62360_chip *tps = rdev_get_drvdata(dev); + + if (selector >= tps->desc.n_voltages) + return -EINVAL; + return (tps->voltage_base + selector * 10) * 1000; +} + +static struct regulator_ops tps62360_dcdc_ops = { + .get_voltage = tps62360_dcdc_get_voltage, + .set_voltage = tps62360_dcdc_set_voltage, + .list_voltage = tps62360_dcdc_list_voltage, +}; + +static int tps62360_init_force_pwm(struct tps62360_chip *tps, + struct tps62360_regulator_platform_data *pdata, + int vset_id) +{ + unsigned int data; + int ret; + ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in writing reg %d\n", + __func__, REG_VSET0 + vset_id); + return ret; + } + tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask; + if (pdata->en_force_pwm) + data |= BIT(7); + else + data &= ~BIT(7); + ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data); + if (ret < 0) + dev_err(tps->dev, "%s() fails in writing reg %d\n", + __func__, REG_VSET0 + vset_id); + return ret; +} + +static int tps62360_init_dcdc(struct tps62360_chip *tps, + struct tps62360_regulator_platform_data *pdata) +{ + int ret; + int i; + + /* Initailize internal pull up/down control */ + if (tps->en_internal_pulldn) + ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0); + else + ret = regmap_write(tps->regmap, REG_CONTROL, 0x0); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in writing reg %d\n", + __func__, REG_CONTROL); + return ret; + } + + /* Initailize force PWM mode */ + if (tps->valid_gpios) { + for (i = 0; i < 4; ++i) { + ret = tps62360_init_force_pwm(tps, pdata, i); + if (ret < 0) + return ret; + } + } else { + ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id); + if (ret < 0) + return ret; + } + + /* Reset output discharge path to reduce power consumption */ + ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); + if (ret < 0) + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_RAMPCTRL); + return ret; +} + +static const struct regmap_config tps62360_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int __devinit tps62360_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps62360_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct tps62360_chip *tps; + int ret; + int i; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "%s() Err: Platform data not found\n", + __func__); + return -EIO; + } + + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) { + dev_err(&client->dev, "%s() Err: Memory allocation fails\n", + __func__); + return -ENOMEM; + } + + tps->en_force_pwm = pdata->en_force_pwm; + tps->en_discharge = pdata->en_discharge; + tps->en_internal_pulldn = pdata->en_internal_pulldn; + tps->vsel0_gpio = pdata->vsel0_gpio; + tps->vsel1_gpio = pdata->vsel1_gpio; + tps->client = client; + tps->dev = &client->dev; + tps->name = id->name; + tps->voltage_base = (id->driver_data == TPS62360) ? + TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE; + tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F; + + tps->desc.name = id->name; + tps->desc.id = 0; + tps->desc.n_voltages = (id->driver_data == TPS62360) ? + TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES; + tps->desc.ops = &tps62360_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config); + if (IS_ERR(tps->regmap)) { + ret = PTR_ERR(tps->regmap); + dev_err(&client->dev, "%s() Err: Failed to allocate register" + "map: %d\n", __func__, ret); + return ret; + } + i2c_set_clientdata(client, tps); + + tps->curr_vset_id = (pdata->vsel1_def_state & 1) * 2 + + (pdata->vsel0_def_state & 1); + tps->lru_index[0] = tps->curr_vset_id; + tps->valid_gpios = false; + + if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) { + ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0"); + if (ret) { + dev_err(&client->dev, + "Err: Could not obtain vsel0 GPIO %d: %d\n", + tps->vsel0_gpio, ret); + goto err_gpio0; + } + ret = gpio_direction_output(tps->vsel0_gpio, + pdata->vsel0_def_state); + if (ret) { + dev_err(&client->dev, "Err: Could not set direction of" + "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret); + gpio_free(tps->vsel0_gpio); + goto err_gpio0; + } + + ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1"); + if (ret) { + dev_err(&client->dev, + "Err: Could not obtain vsel1 GPIO %d: %d\n", + tps->vsel1_gpio, ret); + goto err_gpio1; + } + ret = gpio_direction_output(tps->vsel1_gpio, + pdata->vsel1_def_state); + if (ret) { + dev_err(&client->dev, "Err: Could not set direction of" + "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret); + gpio_free(tps->vsel1_gpio); + goto err_gpio1; + } + tps->valid_gpios = true; + + /* + * Initialize the lru index with vset_reg id + * The index 0 will be most recently used and + * set with the tps->curr_vset_id */ + for (i = 0; i < 4; ++i) + tps->lru_index[i] = i; + tps->lru_index[0] = tps->curr_vset_id; + tps->lru_index[tps->curr_vset_id] = 0; + } + + ret = tps62360_init_dcdc(tps, pdata); + if (ret < 0) { + dev_err(tps->dev, "%s() Err: Init fails with = %d\n", + __func__, ret); + goto err_init; + } + + /* Register the regulators */ + rdev = regulator_register(&tps->desc, &client->dev, + &pdata->reg_init_data, tps, NULL); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "%s() Err: Failed to register %s\n", + __func__, id->name); + ret = PTR_ERR(rdev); + goto err_init; + } + + tps->rdev = rdev; + return 0; + +err_init: + if (gpio_is_valid(tps->vsel1_gpio)) + gpio_free(tps->vsel1_gpio); +err_gpio1: + if (gpio_is_valid(tps->vsel0_gpio)) + gpio_free(tps->vsel0_gpio); +err_gpio0: + regmap_exit(tps->regmap); + return ret; +} + +/** + * tps62360_remove - tps62360 driver i2c remove handler + * @client: i2c driver client device structure + * + * Unregister TPS driver as an i2c client device driver + */ +static int __devexit tps62360_remove(struct i2c_client *client) +{ + struct tps62360_chip *tps = i2c_get_clientdata(client); + + if (gpio_is_valid(tps->vsel1_gpio)) + gpio_free(tps->vsel1_gpio); + + if (gpio_is_valid(tps->vsel0_gpio)) + gpio_free(tps->vsel0_gpio); + + regulator_unregister(tps->rdev); + regmap_exit(tps->regmap); + return 0; +} + +static void tps62360_shutdown(struct i2c_client *client) +{ + struct tps62360_chip *tps = i2c_get_clientdata(client); + int st; + + if (!tps->en_discharge) + return; + + /* Configure the output discharge path */ + st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); + if (st < 0) + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_RAMPCTRL); +} + +static const struct i2c_device_id tps62360_id[] = { + {.name = "tps62360", .driver_data = TPS62360}, + {.name = "tps62361", .driver_data = TPS62361}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tps62360_id); + +static struct i2c_driver tps62360_i2c_driver = { + .driver = { + .name = "tps62360", + .owner = THIS_MODULE, + }, + .probe = tps62360_probe, + .remove = __devexit_p(tps62360_remove), + .shutdown = tps62360_shutdown, + .id_table = tps62360_id, +}; + +static int __init tps62360_init(void) +{ + return i2c_add_driver(&tps62360_i2c_driver); +} +subsys_initcall(tps62360_init); + +static void __exit tps62360_cleanup(void) +{ + i2c_del_driver(&tps62360_i2c_driver); +} +module_exit(tps62360_cleanup); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("TPS62360 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 18d61a0529a9..43e4902d7af8 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -491,10 +491,6 @@ static int __devinit tps_65023_probe(struct i2c_client *client, regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ); - /* Enable setting output voltage by I2C */ - regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, - TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ); - return 0; fail: diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 0b63ef71a5fe..832833fe8aad 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -238,16 +238,16 @@ static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val) return err; } -static int tps6507x_pmic_dcdc_is_enabled(struct regulator_dev *dev) +static int tps6507x_pmic_is_enabled(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int data, dcdc = rdev_get_id(dev); + int data, rid = rdev_get_id(dev); u8 shift; - if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) + if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; - shift = TPS6507X_MAX_REG_ID - dcdc; + shift = TPS6507X_MAX_REG_ID - rid; data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1); if (data < 0) @@ -256,99 +256,65 @@ static int tps6507x_pmic_dcdc_is_enabled(struct regulator_dev *dev) return (data & 1<<shift) ? 1 : 0; } -static int tps6507x_pmic_ldo_is_enabled(struct regulator_dev *dev) +static int tps6507x_pmic_enable(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int data, ldo = rdev_get_id(dev); + int rid = rdev_get_id(dev); u8 shift; - if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; - shift = TPS6507X_MAX_REG_ID - ldo; - data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1); - - if (data < 0) - return data; - else - return (data & 1<<shift) ? 1 : 0; -} - -static int tps6507x_pmic_dcdc_enable(struct regulator_dev *dev) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int dcdc = rdev_get_id(dev); - u8 shift; - - if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) - return -EINVAL; - - shift = TPS6507X_MAX_REG_ID - dcdc; - return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); -} - -static int tps6507x_pmic_dcdc_disable(struct regulator_dev *dev) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int dcdc = rdev_get_id(dev); - u8 shift; - - if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) - return -EINVAL; - - shift = TPS6507X_MAX_REG_ID - dcdc; - return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1, - 1 << shift); -} - -static int tps6507x_pmic_ldo_enable(struct regulator_dev *dev) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); - u8 shift; - - if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) - return -EINVAL; - - shift = TPS6507X_MAX_REG_ID - ldo; + shift = TPS6507X_MAX_REG_ID - rid; return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); } -static int tps6507x_pmic_ldo_disable(struct regulator_dev *dev) +static int tps6507x_pmic_disable(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); + int rid = rdev_get_id(dev); u8 shift; - if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) + if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; - shift = TPS6507X_MAX_REG_ID - ldo; + shift = TPS6507X_MAX_REG_ID - rid; return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); } -static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev) +static int tps6507x_pmic_get_voltage(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int data, dcdc = rdev_get_id(dev); - u8 reg; + int data, rid = rdev_get_id(dev); + u8 reg, mask; - switch (dcdc) { + switch (rid) { case TPS6507X_DCDC_1: reg = TPS6507X_REG_DEFDCDC1; + mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_2: - if (tps->info[dcdc]->defdcdc_default) + if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC2_HIGH; else reg = TPS6507X_REG_DEFDCDC2_LOW; + mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_3: - if (tps->info[dcdc]->defdcdc_default) + if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC3_HIGH; else reg = TPS6507X_REG_DEFDCDC3_LOW; + mask = TPS6507X_DEFDCDCX_DCDC_MASK; + break; + case TPS6507X_LDO_1: + reg = TPS6507X_REG_LDO_CTRL1; + mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; + break; + case TPS6507X_LDO_2: + reg = TPS6507X_REG_DEFLDO2; + mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; break; default: return -EINVAL; @@ -358,193 +324,83 @@ static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev) if (data < 0) return data; - data &= TPS6507X_DEFDCDCX_DCDC_MASK; - return tps->info[dcdc]->table[data] * 1000; + data &= mask; + return tps->info[rid]->table[data] * 1000; } -static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned *selector) +static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int data, vsel, dcdc = rdev_get_id(dev); - u8 reg; + int data, rid = rdev_get_id(dev); + u8 reg, mask; - switch (dcdc) { + switch (rid) { case TPS6507X_DCDC_1: reg = TPS6507X_REG_DEFDCDC1; + mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_2: - if (tps->info[dcdc]->defdcdc_default) + if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC2_HIGH; else reg = TPS6507X_REG_DEFDCDC2_LOW; + mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_3: - if (tps->info[dcdc]->defdcdc_default) + if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC3_HIGH; else reg = TPS6507X_REG_DEFDCDC3_LOW; + mask = TPS6507X_DEFDCDCX_DCDC_MASK; + break; + case TPS6507X_LDO_1: + reg = TPS6507X_REG_LDO_CTRL1; + mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; + break; + case TPS6507X_LDO_2: + reg = TPS6507X_REG_DEFLDO2; + mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; break; default: return -EINVAL; } - if (min_uV < tps->info[dcdc]->min_uV - || min_uV > tps->info[dcdc]->max_uV) - return -EINVAL; - if (max_uV < tps->info[dcdc]->min_uV - || max_uV > tps->info[dcdc]->max_uV) - return -EINVAL; - - for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) { - int mV = tps->info[dcdc]->table[vsel]; - int uV = mV * 1000; - - /* Break at the first in-range value */ - if (min_uV <= uV && uV <= max_uV) - break; - } - - /* write to the register in case we found a match */ - if (vsel == tps->info[dcdc]->table_len) - return -EINVAL; - - *selector = vsel; - - data = tps6507x_pmic_reg_read(tps, reg); - if (data < 0) - return data; - - data &= ~TPS6507X_DEFDCDCX_DCDC_MASK; - data |= vsel; - - return tps6507x_pmic_reg_write(tps, reg, data); -} - -static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int data, ldo = rdev_get_id(dev); - u8 reg, mask; - - if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) - return -EINVAL; - else { - reg = (ldo == TPS6507X_LDO_1 ? - TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2); - mask = (ldo == TPS6507X_LDO_1 ? - TPS6507X_REG_LDO_CTRL1_LDO1_MASK : - TPS6507X_REG_DEFLDO2_LDO2_MASK); - } - - data = tps6507x_pmic_reg_read(tps, reg); - if (data < 0) - return data; - - data &= mask; - return tps->info[ldo]->table[data] * 1000; -} - -static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, - unsigned *selector) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int data, vsel, ldo = rdev_get_id(dev); - u8 reg, mask; - - if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) - return -EINVAL; - else { - reg = (ldo == TPS6507X_LDO_1 ? - TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2); - mask = (ldo == TPS6507X_LDO_1 ? - TPS6507X_REG_LDO_CTRL1_LDO1_MASK : - TPS6507X_REG_DEFLDO2_LDO2_MASK); - } - - if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV) - return -EINVAL; - if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV) - return -EINVAL; - - for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) { - int mV = tps->info[ldo]->table[vsel]; - int uV = mV * 1000; - - /* Break at the first in-range value */ - if (min_uV <= uV && uV <= max_uV) - break; - } - - if (vsel == tps->info[ldo]->table_len) - return -EINVAL; - - *selector = vsel; - data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; data &= ~mask; - data |= vsel; + data |= selector; return tps6507x_pmic_reg_write(tps, reg, data); } -static int tps6507x_pmic_dcdc_list_voltage(struct regulator_dev *dev, +static int tps6507x_pmic_list_voltage(struct regulator_dev *dev, unsigned selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int dcdc = rdev_get_id(dev); + int rid = rdev_get_id(dev); - if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3) + if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; - if (selector >= tps->info[dcdc]->table_len) + if (selector >= tps->info[rid]->table_len) return -EINVAL; else - return tps->info[dcdc]->table[selector] * 1000; + return tps->info[rid]->table[selector] * 1000; } -static int tps6507x_pmic_ldo_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct tps6507x_pmic *tps = rdev_get_drvdata(dev); - int ldo = rdev_get_id(dev); - - if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2) - return -EINVAL; - - if (selector >= tps->info[ldo]->table_len) - return -EINVAL; - else - return tps->info[ldo]->table[selector] * 1000; -} - -/* Operations permitted on VDCDCx */ -static struct regulator_ops tps6507x_pmic_dcdc_ops = { - .is_enabled = tps6507x_pmic_dcdc_is_enabled, - .enable = tps6507x_pmic_dcdc_enable, - .disable = tps6507x_pmic_dcdc_disable, - .get_voltage = tps6507x_pmic_dcdc_get_voltage, - .set_voltage = tps6507x_pmic_dcdc_set_voltage, - .list_voltage = tps6507x_pmic_dcdc_list_voltage, +static struct regulator_ops tps6507x_pmic_ops = { + .is_enabled = tps6507x_pmic_is_enabled, + .enable = tps6507x_pmic_enable, + .disable = tps6507x_pmic_disable, + .get_voltage = tps6507x_pmic_get_voltage, + .set_voltage_sel = tps6507x_pmic_set_voltage_sel, + .list_voltage = tps6507x_pmic_list_voltage, }; -/* Operations permitted on LDOx */ -static struct regulator_ops tps6507x_pmic_ldo_ops = { - .is_enabled = tps6507x_pmic_ldo_is_enabled, - .enable = tps6507x_pmic_ldo_enable, - .disable = tps6507x_pmic_ldo_disable, - .get_voltage = tps6507x_pmic_ldo_get_voltage, - .set_voltage = tps6507x_pmic_ldo_set_voltage, - .list_voltage = tps6507x_pmic_ldo_list_voltage, -}; - -static __devinit -int tps6507x_pmic_probe(struct platform_device *pdev) +static __devinit int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); struct tps_info *info = &tps6507x_pmic_regs[0]; @@ -593,8 +449,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev) tps->desc[i].name = info->name; tps->desc[i].id = i; tps->desc[i].n_voltages = info->table_len; - tps->desc[i].ops = (i > TPS6507X_DCDC_3 ? - &tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops); + tps->desc[i].ops = &tps6507x_pmic_ops; tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].owner = THIS_MODULE; @@ -648,22 +503,12 @@ static struct platform_driver tps6507x_pmic_driver = { .remove = __devexit_p(tps6507x_pmic_remove), }; -/** - * tps6507x_pmic_init - * - * Module init function - */ static int __init tps6507x_pmic_init(void) { return platform_driver_register(&tps6507x_pmic_driver); } subsys_initcall(tps6507x_pmic_init); -/** - * tps6507x_pmic_cleanup - * - * Module exit function - */ static void __exit tps6507x_pmic_cleanup(void) { platform_driver_unregister(&tps6507x_pmic_driver); diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c new file mode 100644 index 000000000000..e39521b42772 --- /dev/null +++ b/drivers/regulator/tps65217-regulator.c @@ -0,0 +1,378 @@ +/* + * tps65217-regulator.c + * + * Regulator driver for TPS65217 PMIC + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> + +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/tps65217.h> + +#define TPS65217_REGULATOR(_name, _id, _ops, _n) \ + { \ + .name = _name, \ + .id = _id, \ + .ops = &_ops, \ + .n_voltages = _n, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } \ + +#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm) \ + { \ + .name = _nm, \ + .min_uV = _min, \ + .max_uV = _max, \ + .vsel_to_uv = _f1, \ + .uv_to_vsel = _f2, \ + .table = _t, \ + .table_len = _n, \ + .enable_mask = _em, \ + .set_vout_reg = _vr, \ + .set_vout_mask = _vm, \ + } + +static const int LDO1_VSEL_table[] = { + 1000000, 1100000, 1200000, 1250000, + 1300000, 1350000, 1400000, 1500000, + 1600000, 1800000, 2500000, 2750000, + 2800000, 3000000, 3100000, 3300000, +}; + +static int tps65217_vsel_to_uv1(unsigned int vsel) +{ + int uV = 0; + + if (vsel > 63) + return -EINVAL; + + if (vsel <= 24) + uV = vsel * 25000 + 900000; + else if (vsel <= 52) + uV = (vsel - 24) * 50000 + 1500000; + else if (vsel < 56) + uV = (vsel - 52) * 100000 + 2900000; + else + uV = 3300000; + + return uV; +} + +static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel) +{ + if ((uV < 0) && (uV > 3300000)) + return -EINVAL; + + if (uV <= 1500000) + *vsel = DIV_ROUND_UP(uV - 900000, 25000); + else if (uV <= 2900000) + *vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000); + else if (uV < 3300000) + *vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000); + else + *vsel = 56; + + return 0; +} + +static int tps65217_vsel_to_uv2(unsigned int vsel) +{ + int uV = 0; + + if (vsel > 31) + return -EINVAL; + + if (vsel <= 8) + uV = vsel * 50000 + 1500000; + else if (vsel <= 13) + uV = (vsel - 8) * 100000 + 1900000; + else + uV = (vsel - 13) * 50000 + 2400000; + + return uV; +} + +static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel) +{ + if ((uV < 0) && (uV > 3300000)) + return -EINVAL; + + if (uV <= 1900000) + *vsel = DIV_ROUND_UP(uV - 1500000, 50000); + else if (uV <= 2400000) + *vsel = 8 + DIV_ROUND_UP(uV - 1900000, 100000); + else + *vsel = 13 + DIV_ROUND_UP(uV - 2400000, 50000); + + return 0; +} + +static struct tps_info tps65217_pmic_regs[] = { + TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1, + tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN, + TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK), + TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1, + tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN, + TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK), + TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1, + tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN, + TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK), + TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table, + 16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1, + TPS65217_DEFLDO1_LDO1_MASK), + TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1, + tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN, + TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK), + TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2, + tps65217_uv_to_vsel2, NULL, 32, + TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN, + TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK), + TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2, + tps65217_uv_to_vsel2, NULL, 32, + TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN, + TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK), +}; + +static int tps65217_pmic_is_enabled(struct regulator_dev *dev) +{ + int ret; + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int data, rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data); + if (ret) + return ret; + + return (data & tps->info[rid]->enable_mask) ? 1 : 0; +} + +static int tps65217_pmic_enable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + /* Enable the regulator and password protection is level 1 */ + return tps65217_set_bits(tps, TPS65217_REG_ENABLE, + tps->info[rid]->enable_mask, + tps->info[rid]->enable_mask, + TPS65217_PROTECT_L1); +} + +static int tps65217_pmic_disable(struct regulator_dev *dev) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + /* Disable the regulator and password protection is level 1 */ + return tps65217_clear_bits(tps, TPS65217_REG_ENABLE, + tps->info[rid]->enable_mask, TPS65217_PROTECT_L1); +} + +static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev) +{ + int ret; + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int selector, rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + ret = tps65217_reg_read(tps, tps->info[rid]->set_vout_reg, &selector); + if (ret) + return ret; + + selector &= tps->info[rid]->set_vout_mask; + + return selector; +} + +static int tps65217_pmic_ldo1_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev); + + if (ldo != TPS65217_LDO_1) + return -EINVAL; + + if (selector >= tps->info[ldo]->table_len) + return -EINVAL; + + /* Set the voltage based on vsel value and write protect level is 2 */ + return tps65217_set_bits(tps, tps->info[ldo]->set_vout_reg, + tps->info[ldo]->set_vout_mask, + selector, TPS65217_PROTECT_L2); +} + +static int tps65217_pmic_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV, unsigned *selector) +{ + int ret; + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + /* LDO1 implements set_voltage_sel callback */ + if (rid == TPS65217_LDO_1) + return -EINVAL; + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + if (min_uV < tps->info[rid]->min_uV + || min_uV > tps->info[rid]->max_uV) + return -EINVAL; + + if (max_uV < tps->info[rid]->min_uV + || max_uV > tps->info[rid]->max_uV) + return -EINVAL; + + ret = tps->info[rid]->uv_to_vsel(min_uV, selector); + if (ret) + return ret; + + /* Set the voltage based on vsel value and write protect level is 2 */ + ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg, + tps->info[rid]->set_vout_mask, + *selector, TPS65217_PROTECT_L2); + + /* Set GO bit for DCDCx to initiate voltage transistion */ + switch (rid) { + case TPS65217_DCDC_1 ... TPS65217_DCDC_3: + ret = tps65217_set_bits(tps, TPS65217_REG_DEFSLEW, + TPS65217_DEFSLEW_GO, TPS65217_DEFSLEW_GO, + TPS65217_PROTECT_L2); + break; + } + + return ret; +} + +static int tps65217_pmic_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps65217 *tps = rdev_get_drvdata(dev); + unsigned int rid = rdev_get_id(dev); + + if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4) + return -EINVAL; + + if (selector >= tps->info[rid]->table_len) + return -EINVAL; + + if (tps->info[rid]->table) + return tps->info[rid]->table[selector]; + + return tps->info[rid]->vsel_to_uv(selector); +} + +/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */ +static struct regulator_ops tps65217_pmic_ops = { + .is_enabled = tps65217_pmic_is_enabled, + .enable = tps65217_pmic_enable, + .disable = tps65217_pmic_disable, + .get_voltage_sel = tps65217_pmic_get_voltage_sel, + .set_voltage = tps65217_pmic_set_voltage, + .list_voltage = tps65217_pmic_list_voltage, +}; + +/* Operations permitted on LDO1 */ +static struct regulator_ops tps65217_pmic_ldo1_ops = { + .is_enabled = tps65217_pmic_is_enabled, + .enable = tps65217_pmic_enable, + .disable = tps65217_pmic_disable, + .get_voltage_sel = tps65217_pmic_get_voltage_sel, + .set_voltage_sel = tps65217_pmic_ldo1_set_voltage_sel, + .list_voltage = tps65217_pmic_list_voltage, +}; + +static struct regulator_desc regulators[] = { + TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64), + TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64), + TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64), + TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16), + TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64), + TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32), + TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32), +}; + +static int __devinit tps65217_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + struct tps65217 *tps; + struct tps_info *info = &tps65217_pmic_regs[pdev->id]; + + /* Already set by core driver */ + tps = dev_to_tps65217(pdev->dev.parent); + tps->info[pdev->id] = info; + + rdev = regulator_register(®ulators[pdev->id], &pdev->dev, + pdev->dev.platform_data, tps, NULL); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + platform_set_drvdata(pdev, rdev); + + return 0; +} + +static int __devexit tps65217_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + regulator_unregister(rdev); + + return 0; +} + +static struct platform_driver tps65217_regulator_driver = { + .driver = { + .name = "tps65217-pmic", + }, + .probe = tps65217_regulator_probe, + .remove = __devexit_p(tps65217_regulator_remove), +}; + +static int __init tps65217_regulator_init(void) +{ + return platform_driver_register(&tps65217_regulator_driver); +} +subsys_initcall(tps65217_regulator_init); + +static void __exit tps65217_regulator_exit(void) +{ + platform_driver_unregister(&tps65217_regulator_driver); +} +module_exit(tps65217_regulator_exit); + +MODULE_AUTHOR("AnilKumar Ch <anilkumar@ti.com>"); +MODULE_DESCRIPTION("TPS65217 voltage regulator driver"); +MODULE_ALIAS("platform:tps65217-pmic"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 2e94686b6fe6..4a421be6d4f2 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -108,9 +108,7 @@ #define N_DCDC 3 #define N_LDO 2 #define N_SWITCH 2 -#define N_REGULATORS (3 /* DCDC */ + \ - 2 /* LDO */ + \ - 2 /* switch */) +#define N_REGULATORS (N_DCDC + N_LDO + N_SWITCH) #define FIXED_ILIMSEL BIT(0) #define FIXED_VOLTAGE BIT(1) diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index c75fb20faa57..29b615ce3aff 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -383,7 +383,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) int id = pdev->id; int err; - dev_dbg(&pdev->dev, "Probing reulator %d\n", id); + dev_dbg(&pdev->dev, "Probing regulator %d\n", id); ri = find_regulator_info(id); if (ri == NULL) { diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 40ecf5165899..4a37c2b6367f 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -26,6 +26,10 @@ #include <linux/mfd/tps65910.h> #define TPS65910_SUPPLY_STATE_ENABLED 0x1 +#define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \ + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \ + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \ + TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) /* supported VIO voltages in milivolts */ static const u16 VIO_VSEL_table[] = { @@ -83,161 +87,235 @@ struct tps_info { const char *name; unsigned min_uV; unsigned max_uV; - u8 table_len; - const u16 *table; + u8 n_voltages; + const u16 *voltage_table; + int enable_time_us; }; static struct tps_info tps65910_regs[] = { { .name = "VRTC", + .enable_time_us = 2200, }, { .name = "VIO", .min_uV = 1500000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VIO_VSEL_table), - .table = VIO_VSEL_table, + .n_voltages = ARRAY_SIZE(VIO_VSEL_table), + .voltage_table = VIO_VSEL_table, + .enable_time_us = 350, }, { .name = "VDD1", .min_uV = 600000, .max_uV = 4500000, + .enable_time_us = 350, }, { .name = "VDD2", .min_uV = 600000, .max_uV = 4500000, + .enable_time_us = 350, }, { .name = "VDD3", .min_uV = 5000000, .max_uV = 5000000, - .table_len = ARRAY_SIZE(VDD3_VSEL_table), - .table = VDD3_VSEL_table, + .n_voltages = ARRAY_SIZE(VDD3_VSEL_table), + .voltage_table = VDD3_VSEL_table, + .enable_time_us = 200, }, { .name = "VDIG1", .min_uV = 1200000, .max_uV = 2700000, - .table_len = ARRAY_SIZE(VDIG1_VSEL_table), - .table = VDIG1_VSEL_table, + .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table), + .voltage_table = VDIG1_VSEL_table, + .enable_time_us = 100, }, { .name = "VDIG2", .min_uV = 1000000, .max_uV = 1800000, - .table_len = ARRAY_SIZE(VDIG2_VSEL_table), - .table = VDIG2_VSEL_table, + .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table), + .voltage_table = VDIG2_VSEL_table, + .enable_time_us = 100, }, { .name = "VPLL", .min_uV = 1000000, .max_uV = 2500000, - .table_len = ARRAY_SIZE(VPLL_VSEL_table), - .table = VPLL_VSEL_table, + .n_voltages = ARRAY_SIZE(VPLL_VSEL_table), + .voltage_table = VPLL_VSEL_table, + .enable_time_us = 100, }, { .name = "VDAC", .min_uV = 1800000, .max_uV = 2850000, - .table_len = ARRAY_SIZE(VDAC_VSEL_table), - .table = VDAC_VSEL_table, + .n_voltages = ARRAY_SIZE(VDAC_VSEL_table), + .voltage_table = VDAC_VSEL_table, + .enable_time_us = 100, }, { .name = "VAUX1", .min_uV = 1800000, .max_uV = 2850000, - .table_len = ARRAY_SIZE(VAUX1_VSEL_table), - .table = VAUX1_VSEL_table, + .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table), + .voltage_table = VAUX1_VSEL_table, + .enable_time_us = 100, }, { .name = "VAUX2", .min_uV = 1800000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VAUX2_VSEL_table), - .table = VAUX2_VSEL_table, + .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table), + .voltage_table = VAUX2_VSEL_table, + .enable_time_us = 100, }, { .name = "VAUX33", .min_uV = 1800000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VAUX33_VSEL_table), - .table = VAUX33_VSEL_table, + .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table), + .voltage_table = VAUX33_VSEL_table, + .enable_time_us = 100, }, { .name = "VMMC", .min_uV = 1800000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VMMC_VSEL_table), - .table = VMMC_VSEL_table, + .n_voltages = ARRAY_SIZE(VMMC_VSEL_table), + .voltage_table = VMMC_VSEL_table, + .enable_time_us = 100, }, }; static struct tps_info tps65911_regs[] = { { + .name = "VRTC", + .enable_time_us = 2200, + }, + { .name = "VIO", .min_uV = 1500000, .max_uV = 3300000, - .table_len = ARRAY_SIZE(VIO_VSEL_table), - .table = VIO_VSEL_table, + .n_voltages = ARRAY_SIZE(VIO_VSEL_table), + .voltage_table = VIO_VSEL_table, + .enable_time_us = 350, }, { .name = "VDD1", .min_uV = 600000, .max_uV = 4500000, + .n_voltages = 73, + .enable_time_us = 350, }, { .name = "VDD2", .min_uV = 600000, .max_uV = 4500000, + .n_voltages = 73, + .enable_time_us = 350, }, { .name = "VDDCTRL", .min_uV = 600000, .max_uV = 1400000, + .n_voltages = 65, + .enable_time_us = 900, }, { .name = "LDO1", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 47, + .enable_time_us = 420, }, { .name = "LDO2", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 47, + .enable_time_us = 420, }, { .name = "LDO3", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO4", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 47, + .enable_time_us = 230, }, { .name = "LDO5", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO6", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO7", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, { .name = "LDO8", .min_uV = 1000000, .max_uV = 3300000, + .n_voltages = 24, + .enable_time_us = 230, }, }; +#define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits)) +static unsigned int tps65910_ext_sleep_control[] = { + 0, + EXT_CONTROL_REG_BITS(VIO, 1, 0), + EXT_CONTROL_REG_BITS(VDD1, 1, 1), + EXT_CONTROL_REG_BITS(VDD2, 1, 2), + EXT_CONTROL_REG_BITS(VDD3, 1, 3), + EXT_CONTROL_REG_BITS(VDIG1, 0, 1), + EXT_CONTROL_REG_BITS(VDIG2, 0, 2), + EXT_CONTROL_REG_BITS(VPLL, 0, 6), + EXT_CONTROL_REG_BITS(VDAC, 0, 7), + EXT_CONTROL_REG_BITS(VAUX1, 0, 3), + EXT_CONTROL_REG_BITS(VAUX2, 0, 4), + EXT_CONTROL_REG_BITS(VAUX33, 0, 5), + EXT_CONTROL_REG_BITS(VMMC, 0, 0), +}; + +static unsigned int tps65911_ext_sleep_control[] = { + 0, + EXT_CONTROL_REG_BITS(VIO, 1, 0), + EXT_CONTROL_REG_BITS(VDD1, 1, 1), + EXT_CONTROL_REG_BITS(VDD2, 1, 2), + EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3), + EXT_CONTROL_REG_BITS(LDO1, 0, 1), + EXT_CONTROL_REG_BITS(LDO2, 0, 2), + EXT_CONTROL_REG_BITS(LDO3, 0, 7), + EXT_CONTROL_REG_BITS(LDO4, 0, 6), + EXT_CONTROL_REG_BITS(LDO5, 0, 3), + EXT_CONTROL_REG_BITS(LDO6, 0, 0), + EXT_CONTROL_REG_BITS(LDO7, 0, 5), + EXT_CONTROL_REG_BITS(LDO8, 0, 4), +}; + struct tps65910_reg { struct regulator_desc *desc; struct tps65910 *mfd; @@ -247,6 +325,8 @@ struct tps65910_reg { int num_regulators; int mode; int (*get_ctrl_reg)(int); + unsigned int *ext_sleep_control; + unsigned int board_ext_control[TPS65910_NUM_REGS]; }; static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) @@ -429,6 +509,12 @@ static int tps65910_disable(struct regulator_dev *dev) return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); } +static int tps65910_enable_time(struct regulator_dev *dev) +{ + struct tps65910_reg *pmic = rdev_get_drvdata(dev); + int id = rdev_get_id(dev); + return pmic->info[id]->enable_time_us; +} static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) { @@ -467,7 +553,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) if (value < 0) return value; - if (value & LDO_ST_ON_BIT) + if (!(value & LDO_ST_ON_BIT)) return REGULATOR_MODE_STANDBY; else if (value & LDO_ST_MODE_BIT) return REGULATOR_MODE_IDLE; @@ -475,10 +561,10 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) return REGULATOR_MODE_NORMAL; } -static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) +static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); - int id = rdev_get_id(dev), voltage = 0; + int id = rdev_get_id(dev); int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0; switch (id) { @@ -522,9 +608,7 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) srvsel = 3; if (srvsel > vselmax) srvsel = vselmax; - srvsel -= 3; - - voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; + return srvsel - 3; } else { /* normalise to valid range*/ @@ -532,14 +616,9 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) opvsel = 3; if (opvsel > vselmax) opvsel = vselmax; - opvsel -= 3; - - voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; + return opvsel - 3; } - - voltage *= mult; - - return voltage; + return -EINVAL; } static int tps65910_get_voltage(struct regulator_dev *dev) @@ -572,7 +651,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) return -EINVAL; } - voltage = pmic->info[id]->table[value] * 1000; + voltage = pmic->info[id]->voltage_table[value] * 1000; return voltage; } @@ -622,8 +701,9 @@ static int tps65911_get_voltage(struct regulator_dev *dev) step_mv = 100; break; case TPS65910_REG_VIO: - return pmic->info[id]->table[value] * 1000; - break; + value &= LDO_SEL_MASK; + value >>= LDO_SEL_SHIFT; + return pmic->info[id]->voltage_table[value] * 1000; default: return -EINVAL; } @@ -631,8 +711,8 @@ static int tps65911_get_voltage(struct regulator_dev *dev) return (LDO_MIN_VOLT + value * step_mv) * 1000; } -static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, - unsigned selector) +static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); int id = rdev_get_id(dev), vsel; @@ -669,7 +749,8 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, return 0; } -static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector) +static int tps65910_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); int reg, id = rdev_get_id(dev); @@ -695,7 +776,8 @@ static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector) return -EINVAL; } -static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector) +static int tps65911_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65910_reg *pmic = rdev_get_drvdata(dev); int reg, id = rdev_get_id(dev); @@ -715,9 +797,11 @@ static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector) case TPS65911_REG_LDO6: case TPS65911_REG_LDO7: case TPS65911_REG_LDO8: - case TPS65910_REG_VIO: return tps65910_modify_bits(pmic, reg, (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK); + case TPS65910_REG_VIO: + return tps65910_modify_bits(pmic, reg, + (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); } return -EINVAL; @@ -756,10 +840,10 @@ static int tps65910_list_voltage(struct regulator_dev *dev, if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) return -EINVAL; - if (selector >= pmic->info[id]->table_len) + if (selector >= pmic->info[id]->n_voltages) return -EINVAL; else - voltage = pmic->info[id]->table[selector] * 1000; + voltage = pmic->info[id]->voltage_table[selector] * 1000; return voltage; } @@ -795,7 +879,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) step_mv = 100; break; case TPS65910_REG_VIO: - return pmic->info[id]->table[selector] * 1000; + return pmic->info[id]->voltage_table[selector] * 1000; default: return -EINVAL; } @@ -803,15 +887,42 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) return (LDO_MIN_VOLT + selector * step_mv) * 1000; } +static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev, + unsigned int old_selector, unsigned int new_selector) +{ + int id = rdev_get_id(dev); + int old_volt, new_volt; + + old_volt = tps65910_list_voltage_dcdc(dev, old_selector); + if (old_volt < 0) + return old_volt; + + new_volt = tps65910_list_voltage_dcdc(dev, new_selector); + if (new_volt < 0) + return new_volt; + + /* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */ + switch (id) { + case TPS65910_REG_VDD1: + case TPS65910_REG_VDD2: + return DIV_ROUND_UP(abs(old_volt - new_volt), 12500); + case TPS65911_REG_VDDCTRL: + return DIV_ROUND_UP(abs(old_volt - new_volt), 5000); + } + return -EINVAL; +} + /* Regulator ops (except VRTC) */ static struct regulator_ops tps65910_ops_dcdc = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, - .get_voltage = tps65910_get_voltage_dcdc, - .set_voltage_sel = tps65910_set_voltage_dcdc, + .get_voltage_sel = tps65910_get_voltage_dcdc_sel, + .set_voltage_sel = tps65910_set_voltage_dcdc_sel, + .set_voltage_time_sel = tps65910_set_voltage_dcdc_time_sel, .list_voltage = tps65910_list_voltage_dcdc, }; @@ -819,6 +930,7 @@ static struct regulator_ops tps65910_ops_vdd3 = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65910_get_voltage_vdd3, @@ -829,10 +941,11 @@ static struct regulator_ops tps65910_ops = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65910_get_voltage, - .set_voltage_sel = tps65910_set_voltage, + .set_voltage_sel = tps65910_set_voltage_sel, .list_voltage = tps65910_list_voltage, }; @@ -840,13 +953,147 @@ static struct regulator_ops tps65911_ops = { .is_enabled = tps65910_is_enabled, .enable = tps65910_enable, .disable = tps65910_disable, + .enable_time = tps65910_enable_time, .set_mode = tps65910_set_mode, .get_mode = tps65910_get_mode, .get_voltage = tps65911_get_voltage, - .set_voltage_sel = tps65911_set_voltage, + .set_voltage_sel = tps65911_set_voltage_sel, .list_voltage = tps65911_list_voltage, }; +static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, + int id, int ext_sleep_config) +{ + struct tps65910 *mfd = pmic->mfd; + u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF; + u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF); + int ret; + + /* + * Regulator can not be control from multiple external input EN1, EN2 + * and EN3 together. + */ + if (ext_sleep_config & EXT_SLEEP_CONTROL) { + int en_count; + en_count = ((ext_sleep_config & + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0); + en_count += ((ext_sleep_config & + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0); + en_count += ((ext_sleep_config & + TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0); + en_count += ((ext_sleep_config & + TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) != 0); + if (en_count > 1) { + dev_err(mfd->dev, + "External sleep control flag is not proper\n"); + return -EINVAL; + } + } + + pmic->board_ext_control[id] = ext_sleep_config; + + /* External EN1 control */ + if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) + ret = tps65910_set_bits(mfd, + TPS65910_EN1_LDO_ASS + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_EN1_LDO_ASS + regoffs, bit_pos); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring external control EN1\n"); + return ret; + } + + /* External EN2 control */ + if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) + ret = tps65910_set_bits(mfd, + TPS65910_EN2_LDO_ASS + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_EN2_LDO_ASS + regoffs, bit_pos); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring external control EN2\n"); + return ret; + } + + /* External EN3 control for TPS65910 LDO only */ + if ((tps65910_chip_id(mfd) == TPS65910) && + (id >= TPS65910_REG_VDIG1)) { + if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) + ret = tps65910_set_bits(mfd, + TPS65910_EN3_LDO_ASS + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_EN3_LDO_ASS + regoffs, bit_pos); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring external control EN3\n"); + return ret; + } + } + + /* Return if no external control is selected */ + if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { + /* Clear all sleep controls */ + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); + if (!ret) + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); + if (ret < 0) + dev_err(mfd->dev, + "Error in configuring SLEEP register\n"); + return ret; + } + + /* + * For regulator that has separate operational and sleep register make + * sure that operational is used and clear sleep register to turn + * regulator off when external control is inactive + */ + if ((id == TPS65910_REG_VDD1) || + (id == TPS65910_REG_VDD2) || + ((id == TPS65911_REG_VDDCTRL) && + (tps65910_chip_id(mfd) == TPS65911))) { + int op_reg_add = pmic->get_ctrl_reg(id) + 1; + int sr_reg_add = pmic->get_ctrl_reg(id) + 2; + int opvsel = tps65910_reg_read(pmic, op_reg_add); + int srvsel = tps65910_reg_read(pmic, sr_reg_add); + if (opvsel & VDD1_OP_CMD_MASK) { + u8 reg_val = srvsel & VDD1_OP_SEL_MASK; + ret = tps65910_reg_write(pmic, op_reg_add, reg_val); + if (ret < 0) { + dev_err(mfd->dev, + "Error in configuring op register\n"); + return ret; + } + } + ret = tps65910_reg_write(pmic, sr_reg_add, 0); + if (ret < 0) { + dev_err(mfd->dev, "Error in settting sr register\n"); + return ret; + } + } + + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); + if (!ret) { + if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) + ret = tps65910_set_bits(mfd, + TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); + else + ret = tps65910_clear_bits(mfd, + TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); + } + if (ret < 0) + dev_err(mfd->dev, + "Error in configuring SLEEP register\n"); + + return ret; +} + static __devinit int tps65910_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); @@ -877,11 +1124,13 @@ static __devinit int tps65910_probe(struct platform_device *pdev) case TPS65910: pmic->get_ctrl_reg = &tps65910_get_ctrl_register; pmic->num_regulators = ARRAY_SIZE(tps65910_regs); + pmic->ext_sleep_control = tps65910_ext_sleep_control; info = tps65910_regs; break; case TPS65911: pmic->get_ctrl_reg = &tps65911_get_ctrl_register; pmic->num_regulators = ARRAY_SIZE(tps65911_regs); + pmic->ext_sleep_control = tps65911_ext_sleep_control; info = tps65911_regs; break; default: @@ -926,7 +1175,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) pmic->desc[i].name = info->name; pmic->desc[i].id = i; - pmic->desc[i].n_voltages = info->table_len; + pmic->desc[i].n_voltages = info->n_voltages; if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { pmic->desc[i].ops = &tps65910_ops_dcdc; @@ -944,6 +1193,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev) pmic->desc[i].ops = &tps65911_ops; } + err = tps65910_set_ext_sleep_config(pmic, i, + pmic_plat_data->regulator_ext_sleep_control[i]); + /* + * Failing on regulator for configuring externally control + * is not a serious issue, just throw warning. + */ + if (err < 0) + dev_warn(tps65910->dev, + "Failed to initialise ext control config\n"); + pmic->desc[i].type = REGULATOR_VOLTAGE; pmic->desc[i].owner = THIS_MODULE; @@ -990,6 +1249,36 @@ static int __devexit tps65910_remove(struct platform_device *pdev) return 0; } +static void tps65910_shutdown(struct platform_device *pdev) +{ + struct tps65910_reg *pmic = platform_get_drvdata(pdev); + int i; + + /* + * Before bootloader jumps to kernel, it makes sure that required + * external control signals are in desired state so that given rails + * can be configure accordingly. + * If rails are configured to be controlled from external control + * then before shutting down/rebooting the system, the external + * control configuration need to be remove from the rails so that + * its output will be available as per register programming even + * if external controls are removed. This is require when the POR + * value of the control signals are not in active state and before + * bootloader initializes it, the system requires the rail output + * to be active for booting. + */ + for (i = 0; i < pmic->num_regulators; i++) { + int err; + if (!pmic->rdev[i]) + continue; + + err = tps65910_set_ext_sleep_config(pmic, i, 0); + if (err < 0) + dev_err(&pdev->dev, + "Error in clearing external control\n"); + } +} + static struct platform_driver tps65910_driver = { .driver = { .name = "tps65910-pmic", @@ -997,6 +1286,7 @@ static struct platform_driver tps65910_driver = { }, .probe = tps65910_probe, .remove = __devexit_p(tps65910_remove), + .shutdown = tps65910_shutdown, }; static int __init tps65910_init(void) @@ -1012,6 +1302,6 @@ static void __exit tps65910_cleanup(void) module_exit(tps65910_cleanup); MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); -MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); +MODULE_DESCRIPTION("TPS65910/TPS65911 voltage regulator driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:tps65910-pmic"); diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index da00d88f94b7..b36799b1f530 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -114,10 +114,7 @@ struct tps65912_reg { struct mutex io_lock; int mode; int (*get_ctrl_reg)(int); - int dcdc1_range; - int dcdc2_range; - int dcdc3_range; - int dcdc4_range; + int dcdc_range[TPS65912_NUM_DCDC]; int pwm_mode_reg; int eco_reg; }; @@ -125,46 +122,31 @@ struct tps65912_reg { static int tps65912_get_range(struct tps65912_reg *pmic, int id) { struct tps65912 *mfd = pmic->mfd; - - if (id > TPS65912_REG_DCDC4) - return 0; + int range; switch (id) { case TPS65912_REG_DCDC1: - pmic->dcdc1_range = tps65912_reg_read(mfd, - TPS65912_DCDC1_LIMIT); - if (pmic->dcdc1_range < 0) - return pmic->dcdc1_range; - pmic->dcdc1_range = (pmic->dcdc1_range & - DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT; - return pmic->dcdc1_range; + range = tps65912_reg_read(mfd, TPS65912_DCDC1_LIMIT); + break; case TPS65912_REG_DCDC2: - pmic->dcdc2_range = tps65912_reg_read(mfd, - TPS65912_DCDC2_LIMIT); - if (pmic->dcdc2_range < 0) - return pmic->dcdc2_range; - pmic->dcdc2_range = (pmic->dcdc2_range & - DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT; - return pmic->dcdc2_range; + range = tps65912_reg_read(mfd, TPS65912_DCDC2_LIMIT); + break; case TPS65912_REG_DCDC3: - pmic->dcdc3_range = tps65912_reg_read(mfd, - TPS65912_DCDC3_LIMIT); - if (pmic->dcdc3_range < 0) - return pmic->dcdc3_range; - pmic->dcdc3_range = (pmic->dcdc3_range & - DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT; - return pmic->dcdc3_range; + range = tps65912_reg_read(mfd, TPS65912_DCDC3_LIMIT); + break; case TPS65912_REG_DCDC4: - pmic->dcdc4_range = tps65912_reg_read(mfd, - TPS65912_DCDC4_LIMIT); - if (pmic->dcdc4_range < 0) - return pmic->dcdc4_range; - pmic->dcdc4_range = (pmic->dcdc4_range & - DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT; - return pmic->dcdc4_range; + range = tps65912_reg_read(mfd, TPS65912_DCDC4_LIMIT); + break; default: return 0; } + + if (range >= 0) + range = (range & DCDC_LIMIT_RANGE_MASK) + >> DCDC_LIMIT_RANGE_SHIFT; + + pmic->dcdc_range[id] = range; + return range; } static unsigned long tps65912_vsel_to_uv_range0(u8 vsel) @@ -219,146 +201,30 @@ static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel) static int tps65912_get_ctrl_register(int id) { - switch (id) { - case TPS65912_REG_DCDC1: - return TPS65912_DCDC1_AVS; - case TPS65912_REG_DCDC2: - return TPS65912_DCDC2_AVS; - case TPS65912_REG_DCDC3: - return TPS65912_DCDC3_AVS; - case TPS65912_REG_DCDC4: - return TPS65912_DCDC4_AVS; - case TPS65912_REG_LDO1: - return TPS65912_LDO1_AVS; - case TPS65912_REG_LDO2: - return TPS65912_LDO2_AVS; - case TPS65912_REG_LDO3: - return TPS65912_LDO3_AVS; - case TPS65912_REG_LDO4: - return TPS65912_LDO4_AVS; - case TPS65912_REG_LDO5: - return TPS65912_LDO5; - case TPS65912_REG_LDO6: - return TPS65912_LDO6; - case TPS65912_REG_LDO7: - return TPS65912_LDO7; - case TPS65912_REG_LDO8: - return TPS65912_LDO8; - case TPS65912_REG_LDO9: - return TPS65912_LDO9; - case TPS65912_REG_LDO10: - return TPS65912_LDO10; - default: + if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4) + return id * 3 + TPS65912_DCDC1_AVS; + else if (id >= TPS65912_REG_LDO5 && id <= TPS65912_REG_LDO10) + return id - TPS65912_REG_LDO5 + TPS65912_LDO5; + else return -EINVAL; - } } -static int tps65912_get_dcdc_sel_register(struct tps65912_reg *pmic, int id) +static int tps65912_get_sel_register(struct tps65912_reg *pmic, int id) { struct tps65912 *mfd = pmic->mfd; - int opvsel = 0, sr = 0; + int opvsel; u8 reg = 0; - if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_DCDC4) - return -EINVAL; - - switch (id) { - case TPS65912_REG_DCDC1: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC1_OP); - sr = ((opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT); - if (sr) - reg = TPS65912_DCDC1_AVS; - else - reg = TPS65912_DCDC1_OP; - break; - case TPS65912_REG_DCDC2: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC2_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_DCDC2_AVS; - else - reg = TPS65912_DCDC2_OP; - break; - case TPS65912_REG_DCDC3: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC3_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_DCDC3_AVS; - else - reg = TPS65912_DCDC3_OP; - break; - case TPS65912_REG_DCDC4: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC4_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_DCDC4_AVS; + if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4) { + opvsel = tps65912_reg_read(mfd, id * 3 + TPS65912_DCDC1_OP); + if (opvsel & OP_SELREG_MASK) + reg = id * 3 + TPS65912_DCDC1_AVS; else - reg = TPS65912_DCDC4_OP; - break; - } - return reg; -} - -static int tps65912_get_ldo_sel_register(struct tps65912_reg *pmic, int id) -{ - struct tps65912 *mfd = pmic->mfd; - int opvsel = 0, sr = 0; - u8 reg = 0; - - if (id < TPS65912_REG_LDO1 || id > TPS65912_REG_LDO10) + reg = id * 3 + TPS65912_DCDC1_OP; + } else if (id >= TPS65912_REG_LDO5 && id <= TPS65912_REG_LDO10) { + reg = id - TPS65912_REG_LDO5 + TPS65912_LDO5; + } else { return -EINVAL; - - switch (id) { - case TPS65912_REG_LDO1: - opvsel = tps65912_reg_read(mfd, TPS65912_LDO1_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_LDO1_AVS; - else - reg = TPS65912_LDO1_OP; - break; - case TPS65912_REG_LDO2: - opvsel = tps65912_reg_read(mfd, TPS65912_LDO2_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_LDO2_AVS; - else - reg = TPS65912_LDO2_OP; - break; - case TPS65912_REG_LDO3: - opvsel = tps65912_reg_read(mfd, TPS65912_LDO3_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_LDO3_AVS; - else - reg = TPS65912_LDO3_OP; - break; - case TPS65912_REG_LDO4: - opvsel = tps65912_reg_read(mfd, TPS65912_LDO4_OP); - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - reg = TPS65912_LDO4_AVS; - else - reg = TPS65912_LDO4_OP; - break; - case TPS65912_REG_LDO5: - reg = TPS65912_LDO5; - break; - case TPS65912_REG_LDO6: - reg = TPS65912_LDO6; - break; - case TPS65912_REG_LDO7: - reg = TPS65912_LDO7; - break; - case TPS65912_REG_LDO8: - reg = TPS65912_LDO8; - break; - case TPS65912_REG_LDO9: - reg = TPS65912_LDO9; - break; - case TPS65912_REG_LDO10: - reg = TPS65912_LDO10; - break; } return reg; @@ -506,151 +372,83 @@ static unsigned int tps65912_get_mode(struct regulator_dev *dev) return mode; } -static int tps65912_get_voltage_dcdc(struct regulator_dev *dev) +static int tps65912_list_voltage_dcdc(struct regulator_dev *dev, + unsigned selector) { struct tps65912_reg *pmic = rdev_get_drvdata(dev); - struct tps65912 *mfd = pmic->mfd; - int id = rdev_get_id(dev), voltage = 0, range; - int opvsel = 0, avsel = 0, sr, vsel; + int range, voltage = 0, id = rdev_get_id(dev); - switch (id) { - case TPS65912_REG_DCDC1: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC1_OP); - avsel = tps65912_reg_read(mfd, TPS65912_DCDC1_AVS); - range = pmic->dcdc1_range; - break; - case TPS65912_REG_DCDC2: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC2_OP); - avsel = tps65912_reg_read(mfd, TPS65912_DCDC2_AVS); - range = pmic->dcdc2_range; - break; - case TPS65912_REG_DCDC3: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC3_OP); - avsel = tps65912_reg_read(mfd, TPS65912_DCDC3_AVS); - range = pmic->dcdc3_range; - break; - case TPS65912_REG_DCDC4: - opvsel = tps65912_reg_read(mfd, TPS65912_DCDC4_OP); - avsel = tps65912_reg_read(mfd, TPS65912_DCDC4_AVS); - range = pmic->dcdc4_range; - break; - default: + if (id > TPS65912_REG_DCDC4) return -EINVAL; - } - sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT; - if (sr) - vsel = avsel; - else - vsel = opvsel; - vsel &= 0x3F; + range = pmic->dcdc_range[id]; switch (range) { case 0: /* 0.5 - 1.2875V in 12.5mV steps */ - voltage = tps65912_vsel_to_uv_range0(vsel); + voltage = tps65912_vsel_to_uv_range0(selector); break; case 1: /* 0.7 - 1.4875V in 12.5mV steps */ - voltage = tps65912_vsel_to_uv_range1(vsel); + voltage = tps65912_vsel_to_uv_range1(selector); break; case 2: /* 0.5 - 2.075V in 25mV steps */ - voltage = tps65912_vsel_to_uv_range2(vsel); + voltage = tps65912_vsel_to_uv_range2(selector); break; case 3: /* 0.5 - 3.8V in 50mV steps */ - voltage = tps65912_vsel_to_uv_range3(vsel); + voltage = tps65912_vsel_to_uv_range3(selector); break; } return voltage; } -static int tps65912_set_voltage_dcdc(struct regulator_dev *dev, - unsigned selector) +static int tps65912_get_voltage_dcdc(struct regulator_dev *dev) { struct tps65912_reg *pmic = rdev_get_drvdata(dev); struct tps65912 *mfd = pmic->mfd; int id = rdev_get_id(dev); - int value; - u8 reg; - - reg = tps65912_get_dcdc_sel_register(pmic, id); - value = tps65912_reg_read(mfd, reg); - value &= 0xC0; - return tps65912_reg_write(mfd, reg, selector | value); -} + int reg, vsel; -static int tps65912_get_voltage_ldo(struct regulator_dev *dev) -{ - struct tps65912_reg *pmic = rdev_get_drvdata(dev); - struct tps65912 *mfd = pmic->mfd; - int id = rdev_get_id(dev); - int vsel = 0; - u8 reg; + reg = tps65912_get_sel_register(pmic, id); + if (reg < 0) + return reg; - reg = tps65912_get_ldo_sel_register(pmic, id); vsel = tps65912_reg_read(mfd, reg); vsel &= 0x3F; - return tps65912_vsel_to_uv_ldo(vsel); + return tps65912_list_voltage_dcdc(dev, vsel); } -static int tps65912_set_voltage_ldo(struct regulator_dev *dev, - unsigned selector) +static int tps65912_set_voltage_sel(struct regulator_dev *dev, + unsigned selector) { struct tps65912_reg *pmic = rdev_get_drvdata(dev); struct tps65912 *mfd = pmic->mfd; - int id = rdev_get_id(dev), reg, value; + int id = rdev_get_id(dev); + int value; + u8 reg; - reg = tps65912_get_ldo_sel_register(pmic, id); + reg = tps65912_get_sel_register(pmic, id); value = tps65912_reg_read(mfd, reg); value &= 0xC0; return tps65912_reg_write(mfd, reg, selector | value); } -static int tps65912_list_voltage_dcdc(struct regulator_dev *dev, - unsigned selector) +static int tps65912_get_voltage_ldo(struct regulator_dev *dev) { struct tps65912_reg *pmic = rdev_get_drvdata(dev); - int range, voltage = 0, id = rdev_get_id(dev); + struct tps65912 *mfd = pmic->mfd; + int id = rdev_get_id(dev); + int vsel = 0; + u8 reg; - switch (id) { - case TPS65912_REG_DCDC1: - range = pmic->dcdc1_range; - break; - case TPS65912_REG_DCDC2: - range = pmic->dcdc2_range; - break; - case TPS65912_REG_DCDC3: - range = pmic->dcdc3_range; - break; - case TPS65912_REG_DCDC4: - range = pmic->dcdc4_range; - break; - default: - return -EINVAL; - } + reg = tps65912_get_sel_register(pmic, id); + vsel = tps65912_reg_read(mfd, reg); + vsel &= 0x3F; - switch (range) { - case 0: - /* 0.5 - 1.2875V in 12.5mV steps */ - voltage = tps65912_vsel_to_uv_range0(selector); - break; - case 1: - /* 0.7 - 1.4875V in 12.5mV steps */ - voltage = tps65912_vsel_to_uv_range1(selector); - break; - case 2: - /* 0.5 - 2.075V in 25mV steps */ - voltage = tps65912_vsel_to_uv_range2(selector); - break; - case 3: - /* 0.5 - 3.8V in 50mV steps */ - voltage = tps65912_vsel_to_uv_range3(selector); - break; - } - return voltage; + return tps65912_vsel_to_uv_ldo(vsel); } static int tps65912_list_voltage_ldo(struct regulator_dev *dev, @@ -672,7 +470,7 @@ static struct regulator_ops tps65912_ops_dcdc = { .set_mode = tps65912_set_mode, .get_mode = tps65912_get_mode, .get_voltage = tps65912_get_voltage_dcdc, - .set_voltage_sel = tps65912_set_voltage_dcdc, + .set_voltage_sel = tps65912_set_voltage_sel, .list_voltage = tps65912_list_voltage_dcdc, }; @@ -682,7 +480,7 @@ static struct regulator_ops tps65912_ops_ldo = { .enable = tps65912_reg_enable, .disable = tps65912_reg_disable, .get_voltage = tps65912_get_voltage_ldo, - .set_voltage_sel = tps65912_set_voltage_ldo, + .set_voltage_sel = tps65912_set_voltage_sel, .list_voltage = tps65912_list_voltage_ldo, }; @@ -770,22 +568,12 @@ static struct platform_driver tps65912_driver = { .remove = __devexit_p(tps65912_remove), }; -/** - * tps65912_init - * - * Module init function - */ static int __init tps65912_init(void) { return platform_driver_register(&tps65912_driver); } subsys_initcall(tps65912_init); -/** - * tps65912_cleanup - * - * Module exit function - */ static void __exit tps65912_cleanup(void) { platform_driver_unregister(&tps65912_driver); diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 181a2cfe180c..9cdfc389ca26 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -14,8 +14,11 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/i2c/twl.h> @@ -58,6 +61,16 @@ struct twlreg_info { /* chip specific features */ unsigned long features; + + /* + * optional override functions for voltage set/get + * these are currently only used for SMPS regulators + */ + int (*get_voltage)(void *data); + int (*set_voltage)(void *data, int target_uV); + + /* data passed from board for external get/set voltage */ + void *data; }; @@ -522,15 +535,25 @@ twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel = DIV_ROUND_UP(min_uV - 600000, 12500); - twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS_4030, - vsel); + if (info->set_voltage) { + return info->set_voltage(info->data, min_uV); + } else { + twlreg_write(info, TWL_MODULE_PM_RECEIVER, + VREG_VOLTAGE_SMPS_4030, vsel); + } + return 0; } static int twl4030smps_get_voltage(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); - int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, + int vsel; + + if (info->get_voltage) + return info->get_voltage(info->data); + + vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS_4030); return vsel * 12500 + 600000; @@ -541,6 +564,32 @@ static struct regulator_ops twl4030smps_ops = { .get_voltage = twl4030smps_get_voltage, }; +static int twl6030coresmps_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + + if (info->set_voltage) + return info->set_voltage(info->data, min_uV); + + return -ENODEV; +} + +static int twl6030coresmps_get_voltage(struct regulator_dev *rdev) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + + if (info->get_voltage) + return info->get_voltage(info->data); + + return -ENODEV; +} + +static struct regulator_ops twl6030coresmps_ops = { + .set_voltage = twl6030coresmps_set_voltage, + .get_voltage = twl6030coresmps_get_voltage, +}; + static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) { struct twlreg_info *info = rdev_get_drvdata(rdev); @@ -755,12 +804,16 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, case 0: if (min_uV == 0) vsel = 0; - else if ((min_uV >= 600000) && (max_uV <= 1300000)) { + else if ((min_uV >= 600000) && (min_uV <= 1300000)) { + int calc_uV; vsel = (min_uV - 600000) / 125; if (vsel % 100) vsel += 100; vsel /= 100; vsel++; + calc_uV = twl6030smps_list_voltage(rdev, vsel); + if (calc_uV > max_uV) + return -EINVAL; } /* Values 1..57 for vsel are linear and can be calculated * values 58..62 are non linear. @@ -781,12 +834,16 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, case SMPS_OFFSET_EN: if (min_uV == 0) vsel = 0; - else if ((min_uV >= 700000) && (max_uV <= 1420000)) { + else if ((min_uV >= 700000) && (min_uV <= 1420000)) { + int calc_uV; vsel = (min_uV - 700000) / 125; if (vsel % 100) vsel += 100; vsel /= 100; vsel++; + calc_uV = twl6030smps_list_voltage(rdev, vsel); + if (calc_uV > max_uV) + return -EINVAL; } /* Values 1..57 for vsel are linear and can be calculated * values 58..62 are non linear. @@ -819,7 +876,7 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, if (min_uV == 0) vsel = 0; else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { - vsel = (min_uV - 1852000) / 386; + vsel = (min_uV - 2161000) / 386; if (vsel % 100) vsel += 100; vsel /= 100; @@ -866,7 +923,8 @@ static struct regulator_ops twlsmps_ops = { TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \ 0x0, TWL6030, twl6030fixed_ops) -#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \ +#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ +static struct twlreg_info TWL4030_INFO_##label = { \ .base = offset, \ .id = num, \ .table_len = ARRAY_SIZE(label##_VSEL_table), \ @@ -884,7 +942,7 @@ static struct regulator_ops twlsmps_ops = { } #define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \ - { \ +static struct twlreg_info TWL4030_INFO_##label = { \ .base = offset, \ .id = num, \ .delay = turnon_delay, \ @@ -898,7 +956,19 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ +#define TWL6030_ADJUSTABLE_SMPS(label) \ +static struct twlreg_info TWL6030_INFO_##label = { \ + .desc = { \ + .name = #label, \ + .id = TWL6030_REG_##label, \ + .ops = &twl6030coresmps_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ +static struct twlreg_info TWL6030_INFO_##label = { \ .base = offset, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ @@ -912,7 +982,8 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ +#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ +static struct twlreg_info TWL6025_INFO_##label = { \ .base = offset, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ @@ -927,7 +998,8 @@ static struct regulator_ops twlsmps_ops = { } #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ - family, operations) { \ + family, operations) \ +static struct twlreg_info TWLFIXED_INFO_##label = { \ .base = offset, \ .id = num, \ .min_mV = mVolts, \ @@ -943,7 +1015,8 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) { \ +#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \ +static struct twlreg_info TWLRES_INFO_##label = { \ .base = offset, \ .delay = turnon_delay, \ .desc = { \ @@ -955,7 +1028,8 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6025_ADJUSTABLE_SMPS(label, offset) { \ +#define TWL6025_ADJUSTABLE_SMPS(label, offset) \ +static struct twlreg_info TWLSMPS_INFO_##label = { \ .base = offset, \ .min_mV = 600, \ .max_mV = 2100, \ @@ -973,59 +1047,59 @@ static struct regulator_ops twlsmps_ops = { * We list regulators here if systems need some level of * software control over them after boot. */ -static struct twlreg_info twl_regs[] = { - TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00), - TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00), - TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08), - TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08), - TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08), - TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08), - TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08), - TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08), - TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08), - TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08), - TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08), - /* VUSBCP is managed *only* by the USB subchip */ - - /* 6030 REG with base as PMC Slave Misc : 0x0030 */ - /* Turnon-delay and remap configuration values for 6030 are not - verified since the specification is not public */ - TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300), - TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300), - TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0), - TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0), - TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0), - TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0), - TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0), - - /* 6025 are renamed compared to 6030 versions */ - TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300), - TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300), - - TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34), - TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10), - TWL6025_ADJUSTABLE_SMPS(VIO, 0x16), -}; +TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00); +TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00); +TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08); +TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08); +TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08); +TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08); +/* VUSBCP is managed *only* by the USB subchip */ +/* 6030 REG with base as PMC Slave Misc : 0x0030 */ +/* Turnon-delay and remap configuration values for 6030 are not + verified since the specification is not public */ +TWL6030_ADJUSTABLE_SMPS(VDD1); +TWL6030_ADJUSTABLE_SMPS(VDD2); +TWL6030_ADJUSTABLE_SMPS(VDD3); +TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300); +TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300); +TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300); +TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300); +TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300); +TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300); +/* 6025 are renamed compared to 6030 versions */ +TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300); +TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300); +TWL4030_FIXED_LDO(VINTANA2, 0x3f, 1500, 11, 100, 0x08); +TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08); +TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08); +TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08); +TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08); +TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0); +TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0); +TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0); +TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0); +TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0); +TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0); +TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0); +TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34); +TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10); +TWL6025_ADJUSTABLE_SMPS(VIO, 0x16); static u8 twl_get_smps_offset(void) { @@ -1045,29 +1119,116 @@ static u8 twl_get_smps_mult(void) return value; } +#define TWL_OF_MATCH(comp, family, label) \ + { \ + .compatible = comp, \ + .data = &family##_INFO_##label, \ + } + +#define TWL4030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL4030, label) +#define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label) +#define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label) +#define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label) +#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label) +#define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label) + +static const struct of_device_id twl_of_match[] __devinitconst = { + TWL4030_OF_MATCH("ti,twl4030-vaux1", VAUX1), + TWL4030_OF_MATCH("ti,twl4030-vaux2", VAUX2_4030), + TWL4030_OF_MATCH("ti,twl5030-vaux2", VAUX2), + TWL4030_OF_MATCH("ti,twl4030-vaux3", VAUX3), + TWL4030_OF_MATCH("ti,twl4030-vaux4", VAUX4), + TWL4030_OF_MATCH("ti,twl4030-vmmc1", VMMC1), + TWL4030_OF_MATCH("ti,twl4030-vmmc2", VMMC2), + TWL4030_OF_MATCH("ti,twl4030-vpll1", VPLL1), + TWL4030_OF_MATCH("ti,twl4030-vpll2", VPLL2), + TWL4030_OF_MATCH("ti,twl4030-vsim", VSIM), + TWL4030_OF_MATCH("ti,twl4030-vdac", VDAC), + TWL4030_OF_MATCH("ti,twl4030-vintana2", VINTANA2), + TWL4030_OF_MATCH("ti,twl4030-vio", VIO), + TWL4030_OF_MATCH("ti,twl4030-vdd1", VDD1), + TWL4030_OF_MATCH("ti,twl4030-vdd2", VDD2), + TWL6030_OF_MATCH("ti,twl6030-vdd1", VDD1), + TWL6030_OF_MATCH("ti,twl6030-vdd2", VDD2), + TWL6030_OF_MATCH("ti,twl6030-vdd3", VDD3), + TWL6030_OF_MATCH("ti,twl6030-vaux1", VAUX1_6030), + TWL6030_OF_MATCH("ti,twl6030-vaux2", VAUX2_6030), + TWL6030_OF_MATCH("ti,twl6030-vaux3", VAUX3_6030), + TWL6030_OF_MATCH("ti,twl6030-vmmc", VMMC), + TWL6030_OF_MATCH("ti,twl6030-vpp", VPP), + TWL6030_OF_MATCH("ti,twl6030-vusim", VUSIM), + TWL6025_OF_MATCH("ti,twl6025-ldo2", LDO2), + TWL6025_OF_MATCH("ti,twl6025-ldo4", LDO4), + TWL6025_OF_MATCH("ti,twl6025-ldo3", LDO3), + TWL6025_OF_MATCH("ti,twl6025-ldo5", LDO5), + TWL6025_OF_MATCH("ti,twl6025-ldo1", LDO1), + TWL6025_OF_MATCH("ti,twl6025-ldo7", LDO7), + TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6), + TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN), + TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB), + TWLFIXED_OF_MATCH("ti,twl4030-vintana2", VINTANA2), + TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG), + TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5), + TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8), + TWLFIXED_OF_MATCH("ti,twl4030-vusb3v1", VUSB3V1), + TWLFIXED_OF_MATCH("ti,twl6030-vana", VANA), + TWLFIXED_OF_MATCH("ti,twl6030-vcxio", VCXIO), + TWLFIXED_OF_MATCH("ti,twl6030-vdac", VDAC), + TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB), + TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8), + TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1), + TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG), + TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3), + TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4), + TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO), + {}, +}; +MODULE_DEVICE_TABLE(of, twl_of_match); + static int __devinit twlreg_probe(struct platform_device *pdev) { - int i; + int i, id; struct twlreg_info *info; struct regulator_init_data *initdata; struct regulation_constraints *c; struct regulator_dev *rdev; - - for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) { - if (twl_regs[i].desc.id != pdev->id) - continue; - info = twl_regs + i; - break; + struct twl_regulator_driver_data *drvdata; + const struct of_device_id *match; + + match = of_match_device(twl_of_match, &pdev->dev); + if (match) { + info = match->data; + id = info->desc.id; + initdata = of_get_regulator_init_data(&pdev->dev, + pdev->dev.of_node); + drvdata = NULL; + } else { + id = pdev->id; + initdata = pdev->dev.platform_data; + for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) { + info = twl_of_match[i].data; + if (!info || info->desc.id != id) + continue; + break; + } + drvdata = initdata->driver_data; + if (!drvdata) + return -EINVAL; } + if (!info) return -ENODEV; - initdata = pdev->dev.platform_data; if (!initdata) return -EINVAL; - /* copy the features into regulator data */ - info->features = (unsigned long)initdata->driver_data; + if (drvdata) { + /* copy the driver data into regulator data */ + info->features = drvdata->features; + info->data = drvdata->data; + info->set_voltage = drvdata->set_voltage; + info->get_voltage = drvdata->get_voltage; + } /* Constrain board-specific capabilities according to what * this driver and the chip itself can actually do. @@ -1077,7 +1238,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS; - switch (pdev->id) { + switch (id) { case TWL4030_REG_VIO: case TWL4030_REG_VDD1: case TWL4030_REG_VDD2: @@ -1091,7 +1252,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) break; } - switch (pdev->id) { + switch (id) { case TWL6025_REG_SMPS3: if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3) info->flags |= SMPS_EXTENDED_EN; @@ -1112,7 +1273,8 @@ static int __devinit twlreg_probe(struct platform_device *pdev) break; } - rdev = regulator_register(&info->desc, &pdev->dev, initdata, info, NULL); + rdev = regulator_register(&info->desc, &pdev->dev, initdata, info, + pdev->dev.of_node); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "can't register %s, %ld\n", info->desc.name, PTR_ERR(rdev)); @@ -1149,8 +1311,11 @@ static struct platform_driver twlreg_driver = { /* NOTE: short name, to work around driver model truncation of * "twl_regulator.12" (and friends) to "twl_regulator.1". */ - .driver.name = "twl_reg", - .driver.owner = THIS_MODULE, + .driver = { + .name = "twl_reg", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl_of_match), + }, }; static int __init twlreg_init(void) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 6894009d815a..ab1e183a74b5 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -186,7 +186,7 @@ static int wm8350_isink_get_current(struct regulator_dev *rdev) return 0; } - return (isink_cur[val] + 50) / 100; + return DIV_ROUND_CLOSEST(isink_cur[val], 100); } /* turn on ISINK followed by DCDC */ @@ -1544,7 +1544,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, return -ENOMEM; } - led->isink_consumer.dev = &pdev->dev; + led->isink_consumer.dev_name = dev_name(&pdev->dev); led->isink_consumer.supply = "led_isink"; led->isink_init.num_consumer_supplies = 1; led->isink_init.consumer_supplies = &led->isink_consumer; @@ -1559,7 +1559,7 @@ int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, return ret; } - led->dcdc_consumer.dev = &pdev->dev; + led->dcdc_consumer.dev_name = dev_name(&pdev->dev); led->dcdc_consumer.supply = "led_vcc"; led->dcdc_init.num_consumer_supplies = 1; led->dcdc_init.consumer_supplies = &led->dcdc_consumer; diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 706f39563a7b..8477153780b6 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -78,14 +78,14 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev, if (min_uV < 1700000) { /* Steps of 50mV from 900mV; */ - val = (min_uV - 850001) / 50000; + val = DIV_ROUND_UP(min_uV - 900000, 50000); if ((val * 50000) + 900000 > max_uV) return -EINVAL; BUG_ON((val * 50000) + 900000 < min_uV); } else { /* Steps of 100mV from 1700mV */ - val = ((min_uV - 1600001) / 100000); + val = DIV_ROUND_UP(min_uV - 1700000, 100000); if ((val * 100000) + 1700000 > max_uV) return -EINVAL; @@ -168,7 +168,7 @@ static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, if (min_uV < 850000) return -EINVAL; - val = (min_uV - 825001) / 25000; + val = DIV_ROUND_UP(min_uV - 850000, 25000); if (850000 + (25000 * val) > max_uV) return -EINVAL; diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 435e335d6e67..75ed402d9f43 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -241,7 +241,7 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev) if (!pdata) return -ENODEV; - ldo = kzalloc(sizeof(struct wm8994_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -285,7 +285,6 @@ err_gpio: if (gpio_is_valid(ldo->enable)) gpio_free(ldo->enable); err: - kfree(ldo); return ret; } @@ -298,7 +297,6 @@ static __devexit int wm8994_ldo_remove(struct platform_device *pdev) regulator_unregister(ldo->regulator); if (gpio_is_valid(ldo->enable)) gpio_free(ldo->enable); - kfree(ldo); return 0; } diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index f980600f78a8..2fe9e90e53d9 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1736,7 +1736,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, (uint32_t ) cmd->cmnd[8]; /* 4 bytes: Areca io control code */ sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; + buffer = kmap_atomic(sg_page(sg)) + sg->offset; if (scsi_sg_count(cmd) > 1) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; @@ -1985,7 +1985,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, } message_out: sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset, KM_IRQ0); + kunmap_atomic(buffer - sg->offset); return retvalue; } @@ -2035,11 +2035,11 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, strncpy(&inqdata[32], "R001", 4); /* Product Revision */ sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; + buffer = kmap_atomic(sg_page(sg)) + sg->offset; memcpy(buffer, inqdata, sizeof(inqdata)); sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset, KM_IRQ0); + kunmap_atomic(buffer - sg->offset); cmd->scsi_done(cmd); } diff --git a/drivers/scsi/bnx2fc/bnx2fc_constants.h b/drivers/scsi/bnx2fc/bnx2fc_constants.h index c12702bb16d6..dad9924abbbb 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_constants.h +++ b/drivers/scsi/bnx2fc/bnx2fc_constants.h @@ -47,6 +47,7 @@ #define FCOE_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE (0x4) #define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR (0x5) #define FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION (0x6) +#define FCOE_KCQE_COMPLETION_STATUS_PARITY_ERROR (0x81) /* CQE type */ #define FCOE_PENDING_CQE_TYPE 0 diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 8c6156a10d90..a9af42e83632 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -322,8 +322,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) return -ENOMEM; } frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ) - + frag->page_offset; + cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; } else { cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); } @@ -332,7 +331,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) cp->fcoe_eof = eof; cp->fcoe_crc32 = cpu_to_le32(~crc); if (skb_is_nonlinear(skb)) { - kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(cp); cp = NULL; } diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h index 57515f1f1690..495a841645f9 100644 --- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h @@ -122,6 +122,7 @@ #define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED (0x51) #define ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY (0x80) +#define ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR (0x81) /* SQ/RQ/CQ DB structure sizes */ #define ISCSI_SQ_DB_SIZE (16) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index d3ff9cd40234..89afd6d21d89 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1956,12 +1956,11 @@ int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset, /* data fits in the skb's headroom */ for (i = 0; i < tdata->nr_frags; i++, frag++) { - char *src = kmap_atomic(frag->page, - KM_SOFTIRQ0); + char *src = kmap_atomic(frag->page); memcpy(dst, src+frag->offset, frag->size); dst += frag->size; - kunmap_atomic(src, KM_SOFTIRQ0); + kunmap_atomic(src); } if (padlen) { memset(dst, 0, padlen); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index c164890224d2..cc75cbea936b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1515,7 +1515,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) return -ENOMEM; } frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ) + cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; } else { cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); @@ -1526,7 +1526,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) cp->fcoe_crc32 = cpu_to_le32(~crc); if (skb_is_nonlinear(skb)) { - kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(cp); cp = NULL; } diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index bd97b2273f20..4d119a326d3b 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -210,10 +210,9 @@ u32 fcoe_fc_crc(struct fc_frame *fp) while (len > 0) { clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); data = kmap_atomic( - skb_frag_page(frag) + (off >> PAGE_SHIFT), - KM_SKB_DATA_SOFTIRQ); + skb_frag_page(frag) + (off >> PAGE_SHIFT)); crc = crc32(crc, data + (off & ~PAGE_MASK), clen); - kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(data); off += clen; len -= clen; } diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 3242bcabad97..d42ec921de46 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -2310,10 +2310,10 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, return; } local_irq_save(flags); - address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset; + address = kmap_atomic(sg_page(sl)) + sl->offset; memcpy(address, buffer, cpnow); flush_dcache_page(sg_page(sl)); - kunmap_atomic(address, KM_BIO_SRC_IRQ); + kunmap_atomic(address); local_irq_restore(flags); if (cpsum == cpcount) break; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index d77891e5683b..b6d7a5c2fc94 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1511,14 +1511,14 @@ static int ips_is_passthru(struct scsi_cmnd *SC) /* kmap_atomic() ensures addressability of the user buffer.*/ /* local_irq_save() protects the KM_IRQ0 address slot. */ local_irq_save(flags); - buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; + buffer = kmap_atomic(sg_page(sg)) + sg->offset; if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && buffer[2] == 'P' && buffer[3] == 'P') { - kunmap_atomic(buffer - sg->offset, KM_IRQ0); + kunmap_atomic(buffer - sg->offset); local_irq_restore(flags); return 1; } - kunmap_atomic(buffer - sg->offset, KM_IRQ0); + kunmap_atomic(buffer - sg->offset); local_irq_restore(flags); } return 0; diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 192cb48d849a..ee0dc05c6269 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1304,9 +1304,9 @@ sci_stp_request_pio_data_in_copy_data_buffer(struct isci_stp_request *stp_req, struct page *page = sg_page(sg); copy_len = min_t(int, total_len, sg_dma_len(sg)); - kaddr = kmap_atomic(page, KM_IRQ0); + kaddr = kmap_atomic(page); memcpy(kaddr + sg->offset, src_addr, copy_len); - kunmap_atomic(kaddr, KM_IRQ0); + kunmap_atomic(kaddr); total_len -= copy_len; src_addr += copy_len; sg = sg_next(sg); @@ -1654,7 +1654,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, sci_unsolicited_frame_control_get_header(&ihost->uf_control, frame_index, &frame_header); - kaddr = kmap_atomic(sg_page(sg), KM_IRQ0); + kaddr = kmap_atomic(sg_page(sg)); rsp = kaddr + sg->offset; sci_swab32_cpy(rsp, frame_header, 1); @@ -1691,7 +1691,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); } - kunmap_atomic(kaddr, KM_IRQ0); + kunmap_atomic(kaddr); sci_controller_release_frame(ihost, frame_index); @@ -3023,10 +3023,10 @@ static void isci_request_io_request_complete(struct isci_host *ihost, dma_unmap_sg(&ihost->pdev->dev, sg, 1, DMA_TO_DEVICE); /* need to swab it back in case the command buffer is re-used */ - kaddr = kmap_atomic(sg_page(sg), KM_IRQ0); + kaddr = kmap_atomic(sg_page(sg)); smp_req = kaddr + sg->offset; sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32)); - kunmap_atomic(kaddr, KM_IRQ0); + kunmap_atomic(kaddr); break; } default: @@ -3311,7 +3311,7 @@ sci_io_request_construct_smp(struct device *dev, u8 req_len; u32 cmd; - kaddr = kmap_atomic(sg_page(sg), KM_IRQ0); + kaddr = kmap_atomic(sg_page(sg)); smp_req = kaddr + sg->offset; /* * Look at the SMP requests' header fields; for certain SAS 1.x SMP @@ -3337,7 +3337,7 @@ sci_io_request_construct_smp(struct device *dev, req_len = smp_req->req_len; sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32)); cmd = *(u32 *) smp_req; - kunmap_atomic(kaddr, KM_IRQ0); + kunmap_atomic(kaddr); if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE)) return SCI_FAILURE; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index f607314810ac..b577c907b318 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -485,11 +485,11 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED)) { copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents, - &offset, KM_SOFTIRQ0, NULL); + &offset, NULL); } else { crc = crc32(~0, (u8 *) fh, sizeof(*fh)); copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents, - &offset, KM_SOFTIRQ0, &crc); + &offset, &crc); buf = fc_frame_payload_get(fp, 0); if (len % 4) crc = crc32(crc, buf + len, 4 - (len % 4)); @@ -650,10 +650,10 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, * The scatterlist item may be bigger than PAGE_SIZE, * but we must not cross pages inside the kmap. */ - page_addr = kmap_atomic(page, KM_SOFTIRQ0); + page_addr = kmap_atomic(page); memcpy(data, (char *)page_addr + (off & ~PAGE_MASK), sg_bytes); - kunmap_atomic(page_addr, KM_SOFTIRQ0); + kunmap_atomic(page_addr); data += sg_bytes; } offset += sg_bytes; diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index 1bf9841ef154..8d65a51a7598 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -105,14 +105,13 @@ module_exit(libfc_exit); * @sg: pointer to the pointer of the SG list. * @nents: pointer to the remaining number of entries in the SG list. * @offset: pointer to the current offset in the SG list. - * @km_type: dedicated page table slot type for kmap_atomic. * @crc: pointer to the 32-bit crc value. * If crc is NULL, CRC is not calculated. */ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, struct scatterlist *sg, u32 *nents, size_t *offset, - enum km_type km_type, u32 *crc) + u32 *crc) { size_t remaining = len; u32 copy_len = 0; @@ -142,12 +141,11 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, off = *offset + sg->offset; sg_bytes = min(sg_bytes, (size_t)(PAGE_SIZE - (off & ~PAGE_MASK))); - page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT), - km_type); + page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT)); if (crc) *crc = crc32(*crc, buf, sg_bytes); memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes); - kunmap_atomic(page_addr, km_type); + kunmap_atomic(page_addr); buf += sg_bytes; *offset += sg_bytes; remaining -= sg_bytes; diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h index c7d071289af5..c2830cc66d6a 100644 --- a/drivers/scsi/libfc/fc_libfc.h +++ b/drivers/scsi/libfc/fc_libfc.h @@ -134,6 +134,6 @@ extern void fc_fc4_conf_lport_params(struct fc_lport *, enum fc_fh_type); u32 fc_copy_buffer_to_sglist(void *buf, size_t len, struct scatterlist *sg, u32 *nents, size_t *offset, - enum km_type km_type, u32 *crc); + u32 *crc); #endif /* _FC_LIBFC_H_ */ diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 83750ebb527f..c1a808cc5920 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1698,7 +1698,7 @@ static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp, job->reply->reply_payload_rcv_len += fc_copy_buffer_to_sglist(buf, len, info->sg, &info->nents, - &info->offset, KM_BIO_SRC_IRQ, NULL); + &info->offset, NULL); if (fr_eof(fp) == FC_EOF_T && (ntoh24(fh->fh_f_ctl) & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 5715a3d0a3d3..7f0465b9623e 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -135,7 +135,7 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) if (recv) { segment->atomic_mapped = true; - segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + segment->sg_mapped = kmap_atomic(sg_page(sg)); } else { segment->atomic_mapped = false; /* the xmit path can sleep with the page mapped so use kmap */ @@ -149,7 +149,7 @@ void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { if (segment->sg_mapped) { if (segment->atomic_mapped) - kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); + kunmap_atomic(segment->sg_mapped); else kunmap(sg_page(segment->sg)); segment->sg_mapped = NULL; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index bb8f49269a68..3814d3eed401 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -246,9 +246,9 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, } local_irq_disable(); - buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio); + buf = kmap_atomic(bio_page(req->bio)); memcpy(req_data, buf, blk_rq_bytes(req)); - kunmap_atomic(buf - bio_offset(req->bio), KM_USER0); + kunmap_atomic(buf - bio_offset(req->bio)); local_irq_enable(); if (req_data[0] != SMP_REQUEST) @@ -361,10 +361,10 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, } local_irq_disable(); - buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio); + buf = kmap_atomic(bio_page(rsp->bio)); memcpy(buf, resp_data, blk_rq_bytes(rsp)); flush_kernel_dcache_page(bio_page(rsp->bio)); - kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0); + kunmap_atomic(buf - bio_offset(rsp->bio)); local_irq_enable(); out: diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 15eefa1d61fd..4d39a9ffc081 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -670,10 +670,10 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) struct scatterlist *sg; sg = scsi_sglist(cmd); - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; + buf = kmap_atomic(sg_page(sg)) + sg->offset; memset(buf, 0, cmd->cmnd[4]); - kunmap_atomic(buf - sg->offset, KM_IRQ0); + kunmap_atomic(buf - sg->offset); cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index a4884a57cf79..01ab9c4d3464 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1885,11 +1885,11 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) case SAS_PROTOCOL_SMP: { struct scatterlist *sg_resp = &task->smp_task.smp_resp; tstat->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); + to = kmap_atomic(sg_page(sg_resp)); memcpy(to + sg_resp->offset, slot->response + sizeof(struct mvs_err_info), sg_dma_len(sg_resp)); - kunmap_atomic(to, KM_IRQ0); + kunmap_atomic(to); break; } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 6888b2ca5bfc..68da6c092f65 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1778,7 +1778,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { int len = min(psgl->length, resid); - paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset; + paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; memcpy(paddr, dif_storep + dif_offset(sector), len); sector += len >> 3; @@ -1788,7 +1788,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, sector = do_div(tmp_sec, sdebug_store_sectors); } resid -= len; - kunmap_atomic(paddr, KM_IRQ0); + kunmap_atomic(paddr); } dix_reads++; @@ -1881,12 +1881,12 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, BUG_ON(scsi_sg_count(SCpnt) == 0); BUG_ON(scsi_prot_sg_count(SCpnt) == 0); - paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset; + paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; ppage_offset = 0; /* For each data page */ scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { - daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset; + daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset; /* For each sector-sized chunk in data page */ for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { @@ -1895,10 +1895,10 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, * protection page advance to the next one */ if (ppage_offset >= psgl->length) { - kunmap_atomic(paddr, KM_IRQ1); + kunmap_atomic(paddr); psgl = sg_next(psgl); BUG_ON(psgl == NULL); - paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; ppage_offset = 0; } @@ -1971,10 +1971,10 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, ppage_offset += sizeof(struct sd_dif_tuple); } - kunmap_atomic(daddr, KM_IRQ0); + kunmap_atomic(daddr); } - kunmap_atomic(paddr, KM_IRQ1); + kunmap_atomic(paddr); dix_writes++; @@ -1982,8 +1982,8 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, out: dif_errors++; - kunmap_atomic(daddr, KM_IRQ0); - kunmap_atomic(paddr, KM_IRQ1); + kunmap_atomic(daddr); + kunmap_atomic(paddr); return ret; } @@ -2303,7 +2303,7 @@ static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, offset = 0; for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { - kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); + kaddr = (unsigned char *)kmap_atomic(sg_page(sg)); if (!kaddr) goto out; @@ -2311,7 +2311,7 @@ static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, *(kaddr + sg->offset + j) ^= *(buf + offset + j); offset += sg->length; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } ret = 0; out: diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b2c95dbe9d65..a33b2b66da67 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2567,7 +2567,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, if (*len > sg_len) *len = sg_len; - return kmap_atomic(page, KM_BIO_SRC_IRQ); + return kmap_atomic(page); } EXPORT_SYMBOL(scsi_kmap_atomic_sg); @@ -2577,6 +2577,6 @@ EXPORT_SYMBOL(scsi_kmap_atomic_sg); */ void scsi_kunmap_atomic_sg(void *virt) { - kunmap_atomic(virt, KM_BIO_SRC_IRQ); + kunmap_atomic(virt); } EXPORT_SYMBOL(scsi_kunmap_atomic_sg); diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index f8fb2d691c0a..e52d5bc42bc4 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -392,7 +392,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s virt = bio->bi_integrity->bip_sector & 0xffffffff; bip_for_each_vec(iv, bio->bi_integrity, i) { - sdt = kmap_atomic(iv->bv_page, KM_USER0) + sdt = kmap_atomic(iv->bv_page) + iv->bv_offset; for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { @@ -405,7 +405,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s phys++; } - kunmap_atomic(sdt, KM_USER0); + kunmap_atomic(sdt); } bio->bi_flags |= (1 << BIO_MAPPED_INTEGRITY); @@ -414,7 +414,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s return 0; error: - kunmap_atomic(sdt, KM_USER0); + kunmap_atomic(sdt); sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u, app %4x\n", __func__, virt, phys, be32_to_cpu(sdt->ref_tag), be16_to_cpu(sdt->app_tag)); @@ -453,13 +453,13 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) virt = bio->bi_integrity->bip_sector & 0xffffffff; bip_for_each_vec(iv, bio->bi_integrity, i) { - sdt = kmap_atomic(iv->bv_page, KM_USER0) + sdt = kmap_atomic(iv->bv_page) + iv->bv_offset; for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { if (sectors == 0) { - kunmap_atomic(sdt, KM_USER0); + kunmap_atomic(sdt); return; } @@ -474,7 +474,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) sectors--; } - kunmap_atomic(sdt, KM_USER0); + kunmap_atomic(sdt); } } } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 695ffc36e02d..83a1972a1999 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -481,6 +481,19 @@ cleanup: return NULL; } +/* Disgusting wrapper functions */ +static inline unsigned long sg_kmap_atomic(struct scatterlist *sgl, int idx) +{ + void *addr = kmap_atomic(sg_page(sgl + idx)); + return (unsigned long)addr; +} + +static inline void sg_kunmap_atomic(unsigned long addr) +{ + kunmap_atomic((void *)addr); +} + + /* Assume the original sgl has enough room */ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, struct scatterlist *bounce_sgl, @@ -499,15 +512,12 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, local_irq_save(flags); for (i = 0; i < orig_sgl_count; i++) { - dest_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])), - KM_IRQ0) + orig_sgl[i].offset; + dest_addr = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset; dest = dest_addr; destlen = orig_sgl[i].length; if (bounce_addr == 0) - bounce_addr = - (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), - KM_IRQ0); + bounce_addr = sg_kmap_atomic(bounce_sgl,j); while (destlen) { src = bounce_addr + bounce_sgl[j].offset; @@ -523,7 +533,7 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, if (bounce_sgl[j].offset == bounce_sgl[j].length) { /* full */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); + sg_kunmap_atomic(bounce_addr); j++; /* @@ -537,26 +547,21 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, /* * We are done; cleanup and return. */ - kunmap_atomic((void *)(dest_addr - - orig_sgl[i].offset), - KM_IRQ0); + sg_kunmap_atomic(dest_addr - orig_sgl[i].offset); local_irq_restore(flags); return total_copied; } /* if we need to use another bounce buffer */ if (destlen || i != orig_sgl_count - 1) - bounce_addr = - (unsigned long)kmap_atomic( - sg_page((&bounce_sgl[j])), KM_IRQ0); + bounce_addr = sg_kmap_atomic(bounce_sgl,j); } else if (destlen == 0 && i == orig_sgl_count - 1) { /* unmap the last bounce that is < PAGE_SIZE */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); + sg_kunmap_atomic(bounce_addr); } } - kunmap_atomic((void *)(dest_addr - orig_sgl[i].offset), - KM_IRQ0); + sg_kunmap_atomic(dest_addr - orig_sgl[i].offset); } local_irq_restore(flags); @@ -581,15 +586,12 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, local_irq_save(flags); for (i = 0; i < orig_sgl_count; i++) { - src_addr = (unsigned long)kmap_atomic(sg_page((&orig_sgl[i])), - KM_IRQ0) + orig_sgl[i].offset; + src_addr = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset; src = src_addr; srclen = orig_sgl[i].length; if (bounce_addr == 0) - bounce_addr = - (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), - KM_IRQ0); + bounce_addr = sg_kmap_atomic(bounce_sgl,j); while (srclen) { /* assume bounce offset always == 0 */ @@ -606,22 +608,20 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, if (bounce_sgl[j].length == PAGE_SIZE) { /* full..move to next entry */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); + sg_kunmap_atomic(bounce_addr); j++; /* if we need to use another bounce buffer */ if (srclen || i != orig_sgl_count - 1) - bounce_addr = - (unsigned long)kmap_atomic( - sg_page((&bounce_sgl[j])), KM_IRQ0); + bounce_addr = sg_kmap_atomic(bounce_sgl,j); } else if (srclen == 0 && i == orig_sgl_count - 1) { /* unmap the last bounce that is < PAGE_SIZE */ - kunmap_atomic((void *)bounce_addr, KM_IRQ0); + sg_kunmap_atomic(bounce_addr); } } - kunmap_atomic((void *)(src_addr - orig_sgl[i].offset), KM_IRQ0); + sg_kunmap_atomic(src_addr - orig_sgl[i].offset); } local_irq_restore(flags); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8293658e7cf9..0b06e360628a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -94,6 +94,12 @@ config SPI_AU1550 If you say yes to this option, support will be included for the PSC SPI controller found on Au1550, Au1200 and Au1300 series. +config SPI_BCM63XX + tristate "Broadcom BCM63xx SPI controller" + depends on BCM63XX + help + Enable support for the SPI controller on the Broadcom BCM63xx SoCs. + config SPI_BITBANG tristate "Utilities for Bitbanging SPI masters" help @@ -126,7 +132,7 @@ config SPI_COLDFIRE_QSPI config SPI_DAVINCI tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller" - depends on SPI_MASTER && ARCH_DAVINCI + depends on ARCH_DAVINCI select SPI_BITBANG help SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules. @@ -188,7 +194,7 @@ config SPI_MPC52xx_PSC config SPI_MPC512x_PSC tristate "Freescale MPC512x PSC SPI controller" - depends on SPI_MASTER && PPC_MPC512x + depends on PPC_MPC512x help This enables using the Freescale MPC5121 Programmable Serial Controller in SPI master mode. @@ -238,7 +244,7 @@ config SPI_OMAP24XX config SPI_OMAP_100K tristate "OMAP SPI 100K" - depends on SPI_MASTER && (ARCH_OMAP850 || ARCH_OMAP730) + depends on ARCH_OMAP850 || ARCH_OMAP730 help OMAP SPI 100K master controller for omap7xx boards. @@ -262,7 +268,7 @@ config SPI_PL022 config SPI_PPC4xx tristate "PPC4xx SPI Controller" - depends on PPC32 && 4xx && SPI_MASTER + depends on PPC32 && 4xx select SPI_BITBANG help This selects a driver for the PPC4xx SPI Controller. @@ -279,6 +285,12 @@ config SPI_PXA2XX config SPI_PXA2XX_PCI def_bool SPI_PXA2XX && X86_32 && PCI +config SPI_RSPI + tristate "Renesas RSPI controller" + depends on SUPERH + help + SPI driver for Renesas RSPI blocks. + config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" depends on ARCH_S3C2410 && EXPERIMENTAL @@ -324,9 +336,22 @@ config SPI_SH_SCI help SPI driver for SuperH SCI blocks. +config SPI_SH_HSPI + tristate "SuperH HSPI controller" + depends on ARCH_SHMOBILE + help + SPI driver for SuperH HSPI blocks. + +config SPI_SIRF + tristate "CSR SiRFprimaII SPI controller" + depends on ARCH_PRIMA2 + select SPI_BITBANG + help + SPI driver for CSR SiRFprimaII SoCs + config SPI_STMP3XXX tristate "Freescale STMP37xx/378x SPI/SSP controller" - depends on ARCH_STMP3XXX && SPI_MASTER + depends on ARCH_STMP3XXX help SPI driver for Freescale STMP37xx/378x SoC SSP interface @@ -384,7 +409,6 @@ config SPI_NUC900 config SPI_DESIGNWARE tristate "DesignWare SPI controller core support" - depends on SPI_MASTER help general driver for SPI controller core from DesignWare diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 61c3261c388c..a1d48e0ba3dc 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera.o obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o +obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.o obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o @@ -44,13 +45,16 @@ obj-$(CONFIG_SPI_PL022) += spi-pl022.o obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o obj-$(CONFIG_SPI_SH) += spi-sh.o +obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o +obj-$(CONFIG_SPI_SIRF) += spi-sirf.o obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c new file mode 100644 index 000000000000..f01b2648452e --- /dev/null +++ b/drivers/spi/spi-bcm63xx.c @@ -0,0 +1,486 @@ +/* + * Broadcom BCM63xx SPI controller support + * + * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/spi/spi.h> +#include <linux/completion.h> +#include <linux/err.h> + +#include <bcm63xx_dev_spi.h> + +#define PFX KBUILD_MODNAME +#define DRV_VER "0.1.2" + +struct bcm63xx_spi { + spinlock_t lock; + int stopping; + struct completion done; + + void __iomem *regs; + int irq; + + /* Platform data */ + u32 speed_hz; + unsigned fifo_size; + + /* Data buffers */ + const unsigned char *tx_ptr; + unsigned char *rx_ptr; + + /* data iomem */ + u8 __iomem *tx_io; + const u8 __iomem *rx_io; + + int remaining_bytes; + + struct clk *clk; + struct platform_device *pdev; +}; + +static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs, + unsigned int offset) +{ + return bcm_readb(bs->regs + bcm63xx_spireg(offset)); +} + +static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs, + unsigned int offset) +{ + return bcm_readw(bs->regs + bcm63xx_spireg(offset)); +} + +static inline void bcm_spi_writeb(struct bcm63xx_spi *bs, + u8 value, unsigned int offset) +{ + bcm_writeb(value, bs->regs + bcm63xx_spireg(offset)); +} + +static inline void bcm_spi_writew(struct bcm63xx_spi *bs, + u16 value, unsigned int offset) +{ + bcm_writew(value, bs->regs + bcm63xx_spireg(offset)); +} + +static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = { + { 20000000, SPI_CLK_20MHZ }, + { 12500000, SPI_CLK_12_50MHZ }, + { 6250000, SPI_CLK_6_250MHZ }, + { 3125000, SPI_CLK_3_125MHZ }, + { 1563000, SPI_CLK_1_563MHZ }, + { 781000, SPI_CLK_0_781MHZ }, + { 391000, SPI_CLK_0_391MHZ } +}; + +static int bcm63xx_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); + u8 bits_per_word; + u8 clk_cfg, reg; + u32 hz; + int i; + + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; + hz = (t) ? t->speed_hz : spi->max_speed_hz; + if (bits_per_word != 8) { + dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", + __func__, bits_per_word); + return -EINVAL; + } + + if (spi->chip_select > spi->master->num_chipselect) { + dev_err(&spi->dev, "%s, unsupported slave %d\n", + __func__, spi->chip_select); + return -EINVAL; + } + + /* Find the closest clock configuration */ + for (i = 0; i < SPI_CLK_MASK; i++) { + if (hz <= bcm63xx_spi_freq_table[i][0]) { + clk_cfg = bcm63xx_spi_freq_table[i][1]; + break; + } + } + + /* No matching configuration found, default to lowest */ + if (i == SPI_CLK_MASK) + clk_cfg = SPI_CLK_0_391MHZ; + + /* clear existing clock configuration bits of the register */ + reg = bcm_spi_readb(bs, SPI_CLK_CFG); + reg &= ~SPI_CLK_MASK; + reg |= clk_cfg; + + bcm_spi_writeb(bs, reg, SPI_CLK_CFG); + dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n", + clk_cfg, hz); + + return 0; +} + +/* the spi->mode bits understood by this driver: */ +#define MODEBITS (SPI_CPOL | SPI_CPHA) + +static int bcm63xx_spi_setup(struct spi_device *spi) +{ + struct bcm63xx_spi *bs; + int ret; + + bs = spi_master_get_devdata(spi->master); + + if (bs->stopping) + return -ESHUTDOWN; + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + if (spi->mode & ~MODEBITS) { + dev_err(&spi->dev, "%s, unsupported mode bits %x\n", + __func__, spi->mode & ~MODEBITS); + return -EINVAL; + } + + ret = bcm63xx_spi_setup_transfer(spi, NULL); + if (ret < 0) { + dev_err(&spi->dev, "setup: unsupported mode bits %x\n", + spi->mode & ~MODEBITS); + return ret; + } + + dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", + __func__, spi->mode & MODEBITS, spi->bits_per_word, 0); + + return 0; +} + +/* Fill the TX FIFO with as many bytes as possible */ +static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) +{ + u8 size; + + /* Fill the Tx FIFO with as many bytes as possible */ + size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes : + bs->fifo_size; + memcpy_toio(bs->tx_io, bs->tx_ptr, size); + bs->remaining_bytes -= size; +} + +static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); + u16 msg_ctl; + u16 cmd; + + dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", + t->tx_buf, t->rx_buf, t->len); + + /* Transmitter is inhibited */ + bs->tx_ptr = t->tx_buf; + bs->rx_ptr = t->rx_buf; + init_completion(&bs->done); + + if (t->tx_buf) { + bs->remaining_bytes = t->len; + bcm63xx_spi_fill_tx_fifo(bs); + } + + /* Enable the command done interrupt which + * we use to determine completion of a command */ + bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); + + /* Fill in the Message control register */ + msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT); + + if (t->rx_buf && t->tx_buf) + msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT); + else if (t->rx_buf) + msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT); + else if (t->tx_buf) + msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT); + + bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL); + + /* Issue the transfer */ + cmd = SPI_CMD_START_IMMEDIATE; + cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); + cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT); + bcm_spi_writew(bs, cmd, SPI_CMD); + wait_for_completion(&bs->done); + + /* Disable the CMD_DONE interrupt */ + bcm_spi_writeb(bs, 0, SPI_INT_MASK); + + return t->len - bs->remaining_bytes; +} + +static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m) +{ + struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); + struct spi_transfer *t; + int ret = 0; + + if (unlikely(list_empty(&m->transfers))) + return -EINVAL; + + if (bs->stopping) + return -ESHUTDOWN; + + list_for_each_entry(t, &m->transfers, transfer_list) { + ret += bcm63xx_txrx_bufs(spi, t); + } + + m->complete(m->context); + + return ret; +} + +/* This driver supports single master mode only. Hence + * CMD_DONE is the only interrupt we care about + */ +static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) +{ + struct spi_master *master = (struct spi_master *)dev_id; + struct bcm63xx_spi *bs = spi_master_get_devdata(master); + u8 intr; + u16 cmd; + + /* Read interupts and clear them immediately */ + intr = bcm_spi_readb(bs, SPI_INT_STATUS); + bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); + bcm_spi_writeb(bs, 0, SPI_INT_MASK); + + /* A tansfer completed */ + if (intr & SPI_INTR_CMD_DONE) { + u8 rx_tail; + + rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL); + + /* Read out all the data */ + if (rx_tail) + memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail); + + /* See if there is more data to send */ + if (bs->remaining_bytes > 0) { + bcm63xx_spi_fill_tx_fifo(bs); + + /* Start the transfer */ + bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT, + SPI_MSG_CTL); + cmd = bcm_spi_readw(bs, SPI_CMD); + cmd |= SPI_CMD_START_IMMEDIATE; + cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); + bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK); + bcm_spi_writew(bs, cmd, SPI_CMD); + } else { + complete(&bs->done); + } + } + + return IRQ_HANDLED; +} + + +static int __devinit bcm63xx_spi_probe(struct platform_device *pdev) +{ + struct resource *r; + struct device *dev = &pdev->dev; + struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data; + int irq; + struct spi_master *master; + struct clk *clk; + struct bcm63xx_spi *bs; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(dev, "no iomem\n"); + ret = -ENXIO; + goto out; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq\n"); + ret = -ENXIO; + goto out; + } + + clk = clk_get(dev, "spi"); + if (IS_ERR(clk)) { + dev_err(dev, "no clock for device\n"); + ret = PTR_ERR(clk); + goto out; + } + + master = spi_alloc_master(dev, sizeof(*bs)); + if (!master) { + dev_err(dev, "out of memory\n"); + ret = -ENOMEM; + goto out_clk; + } + + bs = spi_master_get_devdata(master); + init_completion(&bs->done); + + platform_set_drvdata(pdev, master); + bs->pdev = pdev; + + if (!devm_request_mem_region(&pdev->dev, r->start, + resource_size(r), PFX)) { + dev_err(dev, "iomem request failed\n"); + ret = -ENXIO; + goto out_err; + } + + bs->regs = devm_ioremap_nocache(&pdev->dev, r->start, + resource_size(r)); + if (!bs->regs) { + dev_err(dev, "unable to ioremap regs\n"); + ret = -ENOMEM; + goto out_err; + } + + bs->irq = irq; + bs->clk = clk; + bs->fifo_size = pdata->fifo_size; + + ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0, + pdev->name, master); + if (ret) { + dev_err(dev, "unable to request irq\n"); + goto out_err; + } + + master->bus_num = pdata->bus_num; + master->num_chipselect = pdata->num_chipselect; + master->setup = bcm63xx_spi_setup; + master->transfer = bcm63xx_transfer; + bs->speed_hz = pdata->speed_hz; + bs->stopping = 0; + bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); + bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA)); + spin_lock_init(&bs->lock); + + /* Initialize hardware */ + clk_enable(bs->clk); + bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); + + /* register and we are done */ + ret = spi_register_master(master); + if (ret) { + dev_err(dev, "spi register failed\n"); + goto out_clk_disable; + } + + dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n", + r->start, irq, bs->fifo_size, DRV_VER); + + return 0; + +out_clk_disable: + clk_disable(clk); +out_err: + platform_set_drvdata(pdev, NULL); + spi_master_put(master); +out_clk: + clk_put(clk); +out: + return ret; +} + +static int __devexit bcm63xx_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct bcm63xx_spi *bs = spi_master_get_devdata(master); + + /* reset spi block */ + bcm_spi_writeb(bs, 0, SPI_INT_MASK); + spin_lock(&bs->lock); + bs->stopping = 1; + + /* HW shutdown */ + clk_disable(bs->clk); + clk_put(bs->clk); + + spin_unlock(&bs->lock); + platform_set_drvdata(pdev, 0); + spi_unregister_master(master); + + return 0; +} + +#ifdef CONFIG_PM +static int bcm63xx_spi_suspend(struct device *dev) +{ + struct spi_master *master = + platform_get_drvdata(to_platform_device(dev)); + struct bcm63xx_spi *bs = spi_master_get_devdata(master); + + clk_disable(bs->clk); + + return 0; +} + +static int bcm63xx_spi_resume(struct device *dev) +{ + struct spi_master *master = + platform_get_drvdata(to_platform_device(dev)); + struct bcm63xx_spi *bs = spi_master_get_devdata(master); + + clk_enable(bs->clk); + + return 0; +} + +static const struct dev_pm_ops bcm63xx_spi_pm_ops = { + .suspend = bcm63xx_spi_suspend, + .resume = bcm63xx_spi_resume, +}; + +#define BCM63XX_SPI_PM_OPS (&bcm63xx_spi_pm_ops) +#else +#define BCM63XX_SPI_PM_OPS NULL +#endif + +static struct platform_driver bcm63xx_spi_driver = { + .driver = { + .name = "bcm63xx-spi", + .owner = THIS_MODULE, + .pm = BCM63XX_SPI_PM_OPS, + }, + .probe = bcm63xx_spi_probe, + .remove = __devexit_p(bcm63xx_spi_remove), +}; + +module_platform_driver(bcm63xx_spi_driver); + +MODULE_ALIAS("platform:bcm63xx_spi"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_AUTHOR("Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>"); +MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index f64250ea1611..14f7cc9523f0 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -149,7 +149,7 @@ static int spi_resume(struct pci_dev *pdev) #define spi_resume NULL #endif -static const struct pci_device_id pci_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { /* Intel MID platform SPI controller 0 */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, {}, diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d770f03705c3..7523a2429d09 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -180,18 +180,20 @@ static int fsl_espi_setup_transfer(struct spi_device *spi, if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= CSMODE_DIV16; - pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; + pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 16 * 4); - WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " + WARN_ONCE(pm > 33, "%s: Requested speed is too low: %d Hz. " "Will use %d Hz instead.\n", dev_name(&spi->dev), - hz, mpc8xxx_spi->spibrg / 1024); - if (pm > 16) - pm = 16; + hz, mpc8xxx_spi->spibrg / (4 * 16 * (32 + 1))); + if (pm > 33) + pm = 33; } else { - pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1; + pm = DIV_ROUND_UP(mpc8xxx_spi->spibrg, hz * 4); } if (pm) pm--; + if (pm < 2) + pm = 2; cs->hw_mode |= CSMODE_PM(pm); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index c6e697f5e007..31054e3de4c1 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -793,13 +793,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); if (ret) { - while (i > 0) { - i--; - if (spi_imx->chipselect[i] >= 0) - gpio_free(spi_imx->chipselect[i]); - } dev_err(&pdev->dev, "can't get cs gpios\n"); - goto out_master_put; + goto out_gpio_free; } } @@ -881,10 +876,10 @@ out_iounmap: out_release_mem: release_mem_region(res->start, resource_size(res)); out_gpio_free: - for (i = 0; i < master->num_chipselect; i++) + while (--i >= 0) { if (spi_imx->chipselect[i] >= 0) gpio_free(spi_imx->chipselect[i]); -out_master_put: + } spi_master_put(master); kfree(master); platform_set_drvdata(pdev, NULL); diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 182e9c873822..dae8be229c5d 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -360,8 +360,6 @@ static int __devinit nuc900_spi_probe(struct platform_device *pdev) } hw = spi_master_get_devdata(master); - memset(hw, 0, sizeof(struct nuc900_spi)); - hw->master = spi_master_get(master); hw->pdata = pdev->dev.platform_data; hw->dev = &pdev->dev; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 0b0dfb71c640..bb9274c2526d 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -34,6 +34,8 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/spi/spi.h> @@ -1079,15 +1081,39 @@ static int omap_mcspi_runtime_resume(struct device *dev) return 0; } +static struct omap2_mcspi_platform_config omap2_pdata = { + .regs_offset = 0, +}; + +static struct omap2_mcspi_platform_config omap4_pdata = { + .regs_offset = OMAP4_MCSPI_REG_OFFSET, +}; + +static const struct of_device_id omap_mcspi_of_match[] = { + { + .compatible = "ti,omap2-mcspi", + .data = &omap2_pdata, + }, + { + .compatible = "ti,omap4-mcspi", + .data = &omap4_pdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); static int __init omap2_mcspi_probe(struct platform_device *pdev) { struct spi_master *master; - struct omap2_mcspi_platform_config *pdata = pdev->dev.platform_data; + struct omap2_mcspi_platform_config *pdata; struct omap2_mcspi *mcspi; struct resource *r; int status = 0, i; char wq_name[20]; + u32 regs_offset = 0; + static int bus_num = 1; + struct device_node *node = pdev->dev.of_node; + const struct of_device_id *match; master = spi_alloc_master(&pdev->dev, sizeof *mcspi); if (master == NULL) { @@ -1098,13 +1124,26 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - if (pdev->id != -1) - master->bus_num = pdev->id; - master->setup = omap2_mcspi_setup; master->transfer = omap2_mcspi_transfer; master->cleanup = omap2_mcspi_cleanup; - master->num_chipselect = pdata->num_cs; + master->dev.of_node = node; + + match = of_match_device(omap_mcspi_of_match, &pdev->dev); + if (match) { + u32 num_cs = 1; /* default number of chipselect */ + pdata = match->data; + + of_property_read_u32(node, "ti,spi-num-cs", &num_cs); + master->num_chipselect = num_cs; + master->bus_num = bus_num++; + } else { + pdata = pdev->dev.platform_data; + master->num_chipselect = pdata->num_cs; + if (pdev->id != -1) + master->bus_num = pdev->id; + } + regs_offset = pdata->regs_offset; dev_set_drvdata(&pdev->dev, master); @@ -1124,8 +1163,8 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) goto free_master; } - r->start += pdata->regs_offset; - r->end += pdata->regs_offset; + r->start += regs_offset; + r->end += regs_offset; mcspi->phys = r->start; if (!request_mem_region(r->start, resource_size(r), dev_name(&pdev->dev))) { @@ -1285,7 +1324,8 @@ static struct platform_driver omap2_mcspi_driver = { .driver = { .name = "omap2_mcspi", .owner = THIS_MODULE, - .pm = &omap2_mcspi_pm_ops + .pm = &omap2_mcspi_pm_ops, + .of_match_table = omap_mcspi_of_match, }, .remove = __exit_p(omap2_mcspi_remove), }; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index f37ad2271ad5..dc8485d1e883 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/spi/spi.h> -#include <linux/workqueue.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/err.h> @@ -330,12 +329,13 @@ struct vendor_data { * @clk: outgoing clock "SPICLK" for the SPI bus * @master: SPI framework hookup * @master_info: controller-specific data from machine setup - * @workqueue: a workqueue on which any spi_message request is queued - * @pump_messages: work struct for scheduling work to the workqueue + * @kworker: thread struct for message pump + * @kworker_task: pointer to task for message pump kworker thread + * @pump_messages: work struct for scheduling work to the message pump * @queue_lock: spinlock to syncronise access to message queue * @queue: message queue - * @busy: workqueue is busy - * @running: workqueue is running + * @busy: message pump is busy + * @running: message pump is running * @pump_transfers: Tasklet used in Interrupt Transfer mode * @cur_msg: Pointer to current spi_message being processed * @cur_transfer: Pointer to current spi_transfer @@ -365,14 +365,7 @@ struct pl022 { struct clk *clk; struct spi_master *master; struct pl022_ssp_controller *master_info; - /* Driver message queue */ - struct workqueue_struct *workqueue; - struct work_struct pump_messages; - spinlock_t queue_lock; - struct list_head queue; - bool busy; - bool running; - /* Message transfer pump */ + /* Message per-transfer pump */ struct tasklet_struct pump_transfers; struct spi_message *cur_msg; struct spi_transfer *cur_transfer; @@ -394,6 +387,7 @@ struct pl022 { struct sg_table sgt_rx; struct sg_table sgt_tx; char *dummypage; + bool dma_running; #endif }; @@ -448,8 +442,6 @@ static void null_cs_control(u32 command) static void giveback(struct pl022 *pl022) { struct spi_transfer *last_transfer; - unsigned long flags; - struct spi_message *msg; pl022->next_msg_cs_active = false; last_transfer = list_entry(pl022->cur_msg->transfers.prev, @@ -477,15 +469,8 @@ static void giveback(struct pl022 *pl022) * sent the current message could be unloaded, which * could invalidate the cs_control() callback... */ - /* get a pointer to the next message, if any */ - spin_lock_irqsave(&pl022->queue_lock, flags); - if (list_empty(&pl022->queue)) - next_msg = NULL; - else - next_msg = list_entry(pl022->queue.next, - struct spi_message, queue); - spin_unlock_irqrestore(&pl022->queue_lock, flags); + next_msg = spi_get_next_queued_message(pl022->master); /* * see if the next and current messages point @@ -497,19 +482,13 @@ static void giveback(struct pl022 *pl022) pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); else pl022->next_msg_cs_active = true; + } - spin_lock_irqsave(&pl022->queue_lock, flags); - msg = pl022->cur_msg; pl022->cur_msg = NULL; pl022->cur_transfer = NULL; pl022->cur_chip = NULL; - queue_work(pl022->workqueue, &pl022->pump_messages); - spin_unlock_irqrestore(&pl022->queue_lock, flags); - - msg->state = NULL; - if (msg->complete) - msg->complete(msg->context); + spi_finalize_current_message(pl022->master); } /** @@ -1063,6 +1042,7 @@ static int configure_dma(struct pl022 *pl022) dmaengine_submit(txdesc); dma_async_issue_pending(rxchan); dma_async_issue_pending(txchan); + pl022->dma_running = true; return 0; @@ -1141,11 +1121,12 @@ static void terminate_dma(struct pl022 *pl022) dmaengine_terminate_all(rxchan); dmaengine_terminate_all(txchan); unmap_free_dma_scatter(pl022); + pl022->dma_running = false; } static void pl022_dma_remove(struct pl022 *pl022) { - if (pl022->busy) + if (pl022->dma_running) terminate_dma(pl022); if (pl022->dma_tx_channel) dma_release_channel(pl022->dma_tx_channel); @@ -1493,73 +1474,20 @@ out: return; } -/** - * pump_messages - Workqueue function which processes spi message queue - * @data: pointer to private data of SSP driver - * - * This function checks if there is any spi message in the queue that - * needs processing and delegate control to appropriate function - * do_polling_transfer()/do_interrupt_dma_transfer() - * based on the kind of the transfer - * - */ -static void pump_messages(struct work_struct *work) +static int pl022_transfer_one_message(struct spi_master *master, + struct spi_message *msg) { - struct pl022 *pl022 = - container_of(work, struct pl022, pump_messages); - unsigned long flags; - bool was_busy = false; - - /* Lock queue and check for queue work */ - spin_lock_irqsave(&pl022->queue_lock, flags); - if (list_empty(&pl022->queue) || !pl022->running) { - if (pl022->busy) { - /* nothing more to do - disable spi/ssp and power off */ - writew((readw(SSP_CR1(pl022->virtbase)) & - (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); - - if (pl022->master_info->autosuspend_delay > 0) { - pm_runtime_mark_last_busy(&pl022->adev->dev); - pm_runtime_put_autosuspend(&pl022->adev->dev); - } else { - pm_runtime_put(&pl022->adev->dev); - } - } - pl022->busy = false; - spin_unlock_irqrestore(&pl022->queue_lock, flags); - return; - } - - /* Make sure we are not already running a message */ - if (pl022->cur_msg) { - spin_unlock_irqrestore(&pl022->queue_lock, flags); - return; - } - /* Extract head of queue */ - pl022->cur_msg = - list_entry(pl022->queue.next, struct spi_message, queue); - - list_del_init(&pl022->cur_msg->queue); - if (pl022->busy) - was_busy = true; - else - pl022->busy = true; - spin_unlock_irqrestore(&pl022->queue_lock, flags); + struct pl022 *pl022 = spi_master_get_devdata(master); /* Initial message state */ - pl022->cur_msg->state = STATE_START; - pl022->cur_transfer = list_entry(pl022->cur_msg->transfers.next, - struct spi_transfer, transfer_list); + pl022->cur_msg = msg; + msg->state = STATE_START; + + pl022->cur_transfer = list_entry(msg->transfers.next, + struct spi_transfer, transfer_list); /* Setup the SPI using the per chip configuration */ - pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); - if (!was_busy) - /* - * We enable the core voltage and clocks here, then the clocks - * and core will be disabled when this workqueue is run again - * and there is no more work to be done. - */ - pm_runtime_get_sync(&pl022->adev->dev); + pl022->cur_chip = spi_get_ctldata(msg->spi); restore_state(pl022); flush(pl022); @@ -1568,95 +1496,37 @@ static void pump_messages(struct work_struct *work) do_polling_transfer(pl022); else do_interrupt_dma_transfer(pl022); -} - -static int __init init_queue(struct pl022 *pl022) -{ - INIT_LIST_HEAD(&pl022->queue); - spin_lock_init(&pl022->queue_lock); - - pl022->running = false; - pl022->busy = false; - - tasklet_init(&pl022->pump_transfers, pump_transfers, - (unsigned long)pl022); - - INIT_WORK(&pl022->pump_messages, pump_messages); - pl022->workqueue = create_singlethread_workqueue( - dev_name(pl022->master->dev.parent)); - if (pl022->workqueue == NULL) - return -EBUSY; return 0; } -static int start_queue(struct pl022 *pl022) +static int pl022_prepare_transfer_hardware(struct spi_master *master) { - unsigned long flags; - - spin_lock_irqsave(&pl022->queue_lock, flags); - - if (pl022->running || pl022->busy) { - spin_unlock_irqrestore(&pl022->queue_lock, flags); - return -EBUSY; - } - - pl022->running = true; - pl022->cur_msg = NULL; - pl022->cur_transfer = NULL; - pl022->cur_chip = NULL; - pl022->next_msg_cs_active = false; - spin_unlock_irqrestore(&pl022->queue_lock, flags); - - queue_work(pl022->workqueue, &pl022->pump_messages); + struct pl022 *pl022 = spi_master_get_devdata(master); + /* + * Just make sure we have all we need to run the transfer by syncing + * with the runtime PM framework. + */ + pm_runtime_get_sync(&pl022->adev->dev); return 0; } -static int stop_queue(struct pl022 *pl022) +static int pl022_unprepare_transfer_hardware(struct spi_master *master) { - unsigned long flags; - unsigned limit = 500; - int status = 0; + struct pl022 *pl022 = spi_master_get_devdata(master); - spin_lock_irqsave(&pl022->queue_lock, flags); + /* nothing more to do - disable spi/ssp and power off */ + writew((readw(SSP_CR1(pl022->virtbase)) & + (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); - /* This is a bit lame, but is optimized for the common execution path. - * A wait_queue on the pl022->busy could be used, but then the common - * execution path (pump_messages) would be required to call wake_up or - * friends on every SPI message. Do this instead */ - while ((!list_empty(&pl022->queue) || pl022->busy) && limit--) { - spin_unlock_irqrestore(&pl022->queue_lock, flags); - msleep(10); - spin_lock_irqsave(&pl022->queue_lock, flags); + if (pl022->master_info->autosuspend_delay > 0) { + pm_runtime_mark_last_busy(&pl022->adev->dev); + pm_runtime_put_autosuspend(&pl022->adev->dev); + } else { + pm_runtime_put(&pl022->adev->dev); } - if (!list_empty(&pl022->queue) || pl022->busy) - status = -EBUSY; - else - pl022->running = false; - - spin_unlock_irqrestore(&pl022->queue_lock, flags); - - return status; -} - -static int destroy_queue(struct pl022 *pl022) -{ - int status; - - status = stop_queue(pl022); - /* we are unloading the module or failing to load (only two calls - * to this routine), and neither call can handle a return value. - * However, destroy_workqueue calls flush_workqueue, and that will - * block until all work is done. If the reason that stop_queue - * timed out is that the work will never finish, then it does no - * good to call destroy_workqueue, so return anyway. */ - if (status != 0) - return status; - - destroy_workqueue(pl022->workqueue); - return 0; } @@ -1776,38 +1646,6 @@ static int verify_controller_parameters(struct pl022 *pl022, return 0; } -/** - * pl022_transfer - transfer function registered to SPI master framework - * @spi: spi device which is requesting transfer - * @msg: spi message which is to handled is queued to driver queue - * - * This function is registered to the SPI framework for this SPI master - * controller. It will queue the spi_message in the queue of driver if - * the queue is not stopped and return. - */ -static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) -{ - struct pl022 *pl022 = spi_master_get_devdata(spi->master); - unsigned long flags; - - spin_lock_irqsave(&pl022->queue_lock, flags); - - if (!pl022->running) { - spin_unlock_irqrestore(&pl022->queue_lock, flags); - return -ESHUTDOWN; - } - msg->actual_length = 0; - msg->status = -EINPROGRESS; - msg->state = STATE_START; - - list_add_tail(&msg->queue, &pl022->queue); - if (pl022->running && !pl022->busy) - queue_work(pl022->workqueue, &pl022->pump_messages); - - spin_unlock_irqrestore(&pl022->queue_lock, flags); - return 0; -} - static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr) { return rate / (cpsdvsr * (1 + scr)); @@ -2170,7 +2008,10 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) master->num_chipselect = platform_info->num_chipselect; master->cleanup = pl022_cleanup; master->setup = pl022_setup; - master->transfer = pl022_transfer; + master->prepare_transfer_hardware = pl022_prepare_transfer_hardware; + master->transfer_one_message = pl022_transfer_one_message; + master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; + master->rt = platform_info->rt; /* * Supports mode 0-3, loopback, and active low CS. Transfers are @@ -2214,6 +2055,10 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_clk_en; } + /* Initialize transfer pump */ + tasklet_init(&pl022->pump_transfers, pump_transfers, + (unsigned long)pl022); + /* Disable SSP */ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); @@ -2233,17 +2078,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) platform_info->enable_dma = 0; } - /* Initialize and start queue */ - status = init_queue(pl022); - if (status != 0) { - dev_err(&adev->dev, "probe - problem initializing queue\n"); - goto err_init_queue; - } - status = start_queue(pl022); - if (status != 0) { - dev_err(&adev->dev, "probe - problem starting queue\n"); - goto err_start_queue; - } /* Register with the SPI framework */ amba_set_drvdata(adev, pl022); status = spi_register_master(master); @@ -2269,9 +2103,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) return 0; err_spi_register: - err_start_queue: - err_init_queue: - destroy_queue(pl022); if (platform_info->enable_dma) pl022_dma_remove(pl022); @@ -2307,9 +2138,6 @@ pl022_remove(struct amba_device *adev) */ pm_runtime_get_noresume(&adev->dev); - /* Remove the queue */ - if (destroy_queue(pl022) != 0) - dev_err(&adev->dev, "queue remove failed\n"); load_ssp_default_config(pl022); if (pl022->master_info->enable_dma) pl022_dma_remove(pl022); @@ -2331,12 +2159,12 @@ pl022_remove(struct amba_device *adev) static int pl022_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - int status = 0; + int ret; - status = stop_queue(pl022); - if (status) { - dev_warn(dev, "suspend cannot stop queue\n"); - return status; + ret = spi_master_suspend(pl022->master); + if (ret) { + dev_warn(dev, "cannot suspend master\n"); + return ret; } dev_dbg(dev, "suspended\n"); @@ -2346,16 +2174,16 @@ static int pl022_suspend(struct device *dev) static int pl022_resume(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - int status = 0; + int ret; /* Start the queue running */ - status = start_queue(pl022); - if (status) - dev_err(dev, "problem starting queue (%d)\n", status); + ret = spi_master_resume(pl022->master); + if (ret) + dev_err(dev, "problem starting queue (%d)\n", ret); else dev_dbg(dev, "resumed\n"); - return status; + return ret; } #endif /* CONFIG_PM */ diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 8caa07d58e69..3fb44afe27b4 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -151,7 +151,7 @@ static void __devexit ce4100_spi_remove(struct pci_dev *dev) kfree(spi_info); } -static struct pci_device_id ce4100_spi_devices[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) }, { }, }; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c new file mode 100644 index 000000000000..354f170eab95 --- /dev/null +++ b/drivers/spi/spi-rspi.c @@ -0,0 +1,521 @@ +/* + * SH RSPI driver + * + * Copyright (C) 2012 Renesas Solutions Corp. + * + * Based on spi-sh.c: + * Copyright (C) 2011 Renesas Solutions Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/spi/spi.h> + +#define RSPI_SPCR 0x00 +#define RSPI_SSLP 0x01 +#define RSPI_SPPCR 0x02 +#define RSPI_SPSR 0x03 +#define RSPI_SPDR 0x04 +#define RSPI_SPSCR 0x08 +#define RSPI_SPSSR 0x09 +#define RSPI_SPBR 0x0a +#define RSPI_SPDCR 0x0b +#define RSPI_SPCKD 0x0c +#define RSPI_SSLND 0x0d +#define RSPI_SPND 0x0e +#define RSPI_SPCR2 0x0f +#define RSPI_SPCMD0 0x10 +#define RSPI_SPCMD1 0x12 +#define RSPI_SPCMD2 0x14 +#define RSPI_SPCMD3 0x16 +#define RSPI_SPCMD4 0x18 +#define RSPI_SPCMD5 0x1a +#define RSPI_SPCMD6 0x1c +#define RSPI_SPCMD7 0x1e + +/* SPCR */ +#define SPCR_SPRIE 0x80 +#define SPCR_SPE 0x40 +#define SPCR_SPTIE 0x20 +#define SPCR_SPEIE 0x10 +#define SPCR_MSTR 0x08 +#define SPCR_MODFEN 0x04 +#define SPCR_TXMD 0x02 +#define SPCR_SPMS 0x01 + +/* SSLP */ +#define SSLP_SSL1P 0x02 +#define SSLP_SSL0P 0x01 + +/* SPPCR */ +#define SPPCR_MOIFE 0x20 +#define SPPCR_MOIFV 0x10 +#define SPPCR_SPOM 0x04 +#define SPPCR_SPLP2 0x02 +#define SPPCR_SPLP 0x01 + +/* SPSR */ +#define SPSR_SPRF 0x80 +#define SPSR_SPTEF 0x20 +#define SPSR_PERF 0x08 +#define SPSR_MODF 0x04 +#define SPSR_IDLNF 0x02 +#define SPSR_OVRF 0x01 + +/* SPSCR */ +#define SPSCR_SPSLN_MASK 0x07 + +/* SPSSR */ +#define SPSSR_SPECM_MASK 0x70 +#define SPSSR_SPCP_MASK 0x07 + +/* SPDCR */ +#define SPDCR_SPLW 0x20 +#define SPDCR_SPRDTD 0x10 +#define SPDCR_SLSEL1 0x08 +#define SPDCR_SLSEL0 0x04 +#define SPDCR_SLSEL_MASK 0x0c +#define SPDCR_SPFC1 0x02 +#define SPDCR_SPFC0 0x01 + +/* SPCKD */ +#define SPCKD_SCKDL_MASK 0x07 + +/* SSLND */ +#define SSLND_SLNDL_MASK 0x07 + +/* SPND */ +#define SPND_SPNDL_MASK 0x07 + +/* SPCR2 */ +#define SPCR2_PTE 0x08 +#define SPCR2_SPIE 0x04 +#define SPCR2_SPOE 0x02 +#define SPCR2_SPPE 0x01 + +/* SPCMDn */ +#define SPCMD_SCKDEN 0x8000 +#define SPCMD_SLNDEN 0x4000 +#define SPCMD_SPNDEN 0x2000 +#define SPCMD_LSBF 0x1000 +#define SPCMD_SPB_MASK 0x0f00 +#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) +#define SPCMD_SPB_20BIT 0x0000 +#define SPCMD_SPB_24BIT 0x0100 +#define SPCMD_SPB_32BIT 0x0200 +#define SPCMD_SSLKP 0x0080 +#define SPCMD_SSLA_MASK 0x0030 +#define SPCMD_BRDV_MASK 0x000c +#define SPCMD_CPOL 0x0002 +#define SPCMD_CPHA 0x0001 + +struct rspi_data { + void __iomem *addr; + u32 max_speed_hz; + struct spi_master *master; + struct list_head queue; + struct work_struct ws; + wait_queue_head_t wait; + spinlock_t lock; + struct clk *clk; + unsigned char spsr; +}; + +static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset) +{ + iowrite8(data, rspi->addr + offset); +} + +static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset) +{ + iowrite16(data, rspi->addr + offset); +} + +static u8 rspi_read8(struct rspi_data *rspi, u16 offset) +{ + return ioread8(rspi->addr + offset); +} + +static u16 rspi_read16(struct rspi_data *rspi, u16 offset) +{ + return ioread16(rspi->addr + offset); +} + +static unsigned char rspi_calc_spbr(struct rspi_data *rspi) +{ + int tmp; + unsigned char spbr; + + tmp = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; + spbr = clamp(tmp, 0, 255); + + return spbr; +} + +static void rspi_enable_irq(struct rspi_data *rspi, u8 enable) +{ + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR); +} + +static void rspi_disable_irq(struct rspi_data *rspi, u8 disable) +{ + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~disable, RSPI_SPCR); +} + +static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, + u8 enable_bit) +{ + int ret; + + rspi->spsr = rspi_read8(rspi, RSPI_SPSR); + rspi_enable_irq(rspi, enable_bit); + ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ); + if (ret == 0 && !(rspi->spsr & wait_mask)) + return -ETIMEDOUT; + + return 0; +} + +static void rspi_assert_ssl(struct rspi_data *rspi) +{ + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); +} + +static void rspi_negate_ssl(struct rspi_data *rspi) +{ + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); +} + +static int rspi_set_config_register(struct rspi_data *rspi, int access_size) +{ + /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ + rspi_write8(rspi, 0x00, RSPI_SPPCR); + + /* Sets transfer bit rate */ + rspi_write8(rspi, rspi_calc_spbr(rspi), RSPI_SPBR); + + /* Sets number of frames to be used: 1 frame */ + rspi_write8(rspi, 0x00, RSPI_SPDCR); + + /* Sets RSPCK, SSL, next-access delay value */ + rspi_write8(rspi, 0x00, RSPI_SPCKD); + rspi_write8(rspi, 0x00, RSPI_SSLND); + rspi_write8(rspi, 0x00, RSPI_SPND); + + /* Sets parity, interrupt mask */ + rspi_write8(rspi, 0x00, RSPI_SPCR2); + + /* Sets SPCMD */ + rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP, + RSPI_SPCMD0); + + /* Sets RSPI mode */ + rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); + + return 0; +} + +static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t) +{ + int remain = t->len; + u8 *data; + + data = (u8 *)t->tx_buf; + while (remain > 0) { + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, + RSPI_SPCR); + + if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + dev_err(&rspi->master->dev, + "%s: tx empty timeout\n", __func__); + return -ETIMEDOUT; + } + + rspi_write16(rspi, *data, RSPI_SPDR); + data++; + remain--; + } + + /* Waiting for the last transmition */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + +static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t) +{ + int remain = t->len; + u8 *data; + unsigned char spsr; + + spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPRF) + rspi_read16(rspi, RSPI_SPDR); /* dummy read */ + if (spsr & SPSR_OVRF) + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, + RSPI_SPCR); + + data = (u8 *)t->rx_buf; + while (remain > 0) { + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, + RSPI_SPCR); + + if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + dev_err(&rspi->master->dev, + "%s: tx empty timeout\n", __func__); + return -ETIMEDOUT; + } + /* dummy write for generate clock */ + rspi_write16(rspi, 0x00, RSPI_SPDR); + + if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { + dev_err(&rspi->master->dev, + "%s: receive timeout\n", __func__); + return -ETIMEDOUT; + } + /* SPDR allows 16 or 32-bit access only */ + *data = (u8)rspi_read16(rspi, RSPI_SPDR); + + data++; + remain--; + } + + return 0; +} + +static void rspi_work(struct work_struct *work) +{ + struct rspi_data *rspi = container_of(work, struct rspi_data, ws); + struct spi_message *mesg; + struct spi_transfer *t; + unsigned long flags; + int ret; + + spin_lock_irqsave(&rspi->lock, flags); + while (!list_empty(&rspi->queue)) { + mesg = list_entry(rspi->queue.next, struct spi_message, queue); + list_del_init(&mesg->queue); + spin_unlock_irqrestore(&rspi->lock, flags); + + rspi_assert_ssl(rspi); + + list_for_each_entry(t, &mesg->transfers, transfer_list) { + if (t->tx_buf) { + ret = rspi_send_pio(rspi, mesg, t); + if (ret < 0) + goto error; + } + if (t->rx_buf) { + ret = rspi_receive_pio(rspi, mesg, t); + if (ret < 0) + goto error; + } + mesg->actual_length += t->len; + } + rspi_negate_ssl(rspi); + + mesg->status = 0; + mesg->complete(mesg->context); + + spin_lock_irqsave(&rspi->lock, flags); + } + + return; + +error: + mesg->status = ret; + mesg->complete(mesg->context); +} + +static int rspi_setup(struct spi_device *spi) +{ + struct rspi_data *rspi = spi_master_get_devdata(spi->master); + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + rspi->max_speed_hz = spi->max_speed_hz; + + rspi_set_config_register(rspi, 8); + + return 0; +} + +static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg) +{ + struct rspi_data *rspi = spi_master_get_devdata(spi->master); + unsigned long flags; + + mesg->actual_length = 0; + mesg->status = -EINPROGRESS; + + spin_lock_irqsave(&rspi->lock, flags); + list_add_tail(&mesg->queue, &rspi->queue); + schedule_work(&rspi->ws); + spin_unlock_irqrestore(&rspi->lock, flags); + + return 0; +} + +static void rspi_cleanup(struct spi_device *spi) +{ +} + +static irqreturn_t rspi_irq(int irq, void *_sr) +{ + struct rspi_data *rspi = (struct rspi_data *)_sr; + unsigned long spsr; + irqreturn_t ret = IRQ_NONE; + unsigned char disable_irq = 0; + + rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPRF) + disable_irq |= SPCR_SPRIE; + if (spsr & SPSR_SPTEF) + disable_irq |= SPCR_SPTIE; + + if (disable_irq) { + ret = IRQ_HANDLED; + rspi_disable_irq(rspi, disable_irq); + wake_up(&rspi->wait); + } + + return ret; +} + +static int __devexit rspi_remove(struct platform_device *pdev) +{ + struct rspi_data *rspi = dev_get_drvdata(&pdev->dev); + + spi_unregister_master(rspi->master); + free_irq(platform_get_irq(pdev, 0), rspi); + clk_put(rspi->clk); + iounmap(rspi->addr); + spi_master_put(rspi->master); + + return 0; +} + +static int __devinit rspi_probe(struct platform_device *pdev) +{ + struct resource *res; + struct spi_master *master; + struct rspi_data *rspi; + int ret, irq; + char clk_name[16]; + + /* get base addr */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(res == NULL)) { + dev_err(&pdev->dev, "invalid resource\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "platform_get_irq error\n"); + return -ENODEV; + } + + master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); + if (master == NULL) { + dev_err(&pdev->dev, "spi_alloc_master error.\n"); + return -ENOMEM; + } + + rspi = spi_master_get_devdata(master); + dev_set_drvdata(&pdev->dev, rspi); + + rspi->master = master; + rspi->addr = ioremap(res->start, resource_size(res)); + if (rspi->addr == NULL) { + dev_err(&pdev->dev, "ioremap error.\n"); + ret = -ENOMEM; + goto error1; + } + + snprintf(clk_name, sizeof(clk_name), "rspi%d", pdev->id); + rspi->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(rspi->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + ret = PTR_ERR(rspi->clk); + goto error2; + } + clk_enable(rspi->clk); + + INIT_LIST_HEAD(&rspi->queue); + spin_lock_init(&rspi->lock); + INIT_WORK(&rspi->ws, rspi_work); + init_waitqueue_head(&rspi->wait); + + master->num_chipselect = 2; + master->bus_num = pdev->id; + master->setup = rspi_setup; + master->transfer = rspi_transfer; + master->cleanup = rspi_cleanup; + + ret = request_irq(irq, rspi_irq, 0, dev_name(&pdev->dev), rspi); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq error\n"); + goto error3; + } + + ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto error4; + } + + dev_info(&pdev->dev, "probed\n"); + + return 0; + +error4: + free_irq(irq, rspi); +error3: + clk_put(rspi->clk); +error2: + iounmap(rspi->addr); +error1: + spi_master_put(master); + + return ret; +} + +static struct platform_driver rspi_driver = { + .probe = rspi_probe, + .remove = __devexit_p(rspi_remove), + .driver = { + .name = "rspi", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(rspi_driver); + +MODULE_DESCRIPTION("Renesas RSPI bus driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yoshihiro Shimoda"); +MODULE_ALIAS("platform:rspi"); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index dcf7e1006426..972a94c58be3 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -20,10 +20,12 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/workqueue.h> +#include <linux/interrupt.h> #include <linux/delay.h> #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spi/spi.h> #include <mach/dma.h> @@ -126,8 +128,6 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) -#define SUSPND (1<<0) -#define SPIBUSY (1<<1) #define RXBUSY (1<<2) #define TXBUSY (1<<3) @@ -142,10 +142,8 @@ struct s3c64xx_spi_dma_data { * @clk: Pointer to the spi clock. * @src_clk: Pointer to the clock used to generate SPI signals. * @master: Pointer to the SPI Protocol master. - * @workqueue: Work queue for the SPI xfer requests. * @cntrlr_info: Platform specific data for the controller this driver manages. * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint. - * @work: Work * @queue: To log SPI xfer requests. * @lock: Controller specific lock. * @state: Set of FLAGS to indicate status. @@ -153,6 +151,7 @@ struct s3c64xx_spi_dma_data { * @tx_dmach: Controller's DMA channel for Tx. * @sfr_start: BUS address of SPI controller regs. * @regs: Pointer to ioremap'ed controller registers. + * @irq: interrupt * @xfer_completion: To indicate completion of xfer task. * @cur_mode: Stores the active configuration of the controller. * @cur_bpw: Stores the active bits per word settings. @@ -164,10 +163,8 @@ struct s3c64xx_spi_driver_data { struct clk *src_clk; struct platform_device *pdev; struct spi_master *master; - struct workqueue_struct *workqueue; struct s3c64xx_spi_info *cntrlr_info; struct spi_device *tgl_spi; - struct work_struct work; struct list_head queue; spinlock_t lock; unsigned long sfr_start; @@ -239,7 +236,7 @@ static void s3c64xx_spi_dmacb(void *data) struct s3c64xx_spi_dma_data *dma = data; unsigned long flags; - if (dma->direction == DMA_FROM_DEVICE) + if (dma->direction == DMA_DEV_TO_MEM) sdd = container_of(data, struct s3c64xx_spi_driver_data, rx_dma); else @@ -248,7 +245,7 @@ static void s3c64xx_spi_dmacb(void *data) spin_lock_irqsave(&sdd->lock, flags); - if (dma->direction == DMA_FROM_DEVICE) { + if (dma->direction == DMA_DEV_TO_MEM) { sdd->state &= ~RXBUSY; if (!(sdd->state & TXBUSY)) complete(&sdd->xfer_completion); @@ -267,7 +264,7 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma, struct s3c64xx_spi_driver_data *sdd; struct samsung_dma_prep_info info; - if (dma->direction == DMA_FROM_DEVICE) + if (dma->direction == DMA_DEV_TO_MEM) sdd = container_of((void *)dma, struct s3c64xx_spi_driver_data, rx_dma); else @@ -634,9 +631,10 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, } } -static void handle_msg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) +static int s3c64xx_spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) { + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct s3c64xx_spi_info *sci = sdd->cntrlr_info; struct spi_device *spi = msg->spi; struct s3c64xx_spi_csinfo *cs = spi->controller_data; @@ -766,73 +764,33 @@ out: msg->status = status; - if (msg->complete) - msg->complete(msg->context); + spi_finalize_current_message(master); + + return 0; } -static void s3c64xx_spi_work(struct work_struct *work) +static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) { - struct s3c64xx_spi_driver_data *sdd = container_of(work, - struct s3c64xx_spi_driver_data, work); - unsigned long flags; + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); /* Acquire DMA channels */ while (!acquire_dma(sdd)) msleep(10); - spin_lock_irqsave(&sdd->lock, flags); - - while (!list_empty(&sdd->queue) - && !(sdd->state & SUSPND)) { - - struct spi_message *msg; - - msg = container_of(sdd->queue.next, struct spi_message, queue); - - list_del_init(&msg->queue); - - /* Set Xfer busy flag */ - sdd->state |= SPIBUSY; - - spin_unlock_irqrestore(&sdd->lock, flags); - - handle_msg(sdd, msg); + pm_runtime_get_sync(&sdd->pdev->dev); - spin_lock_irqsave(&sdd->lock, flags); - - sdd->state &= ~SPIBUSY; - } + return 0; +} - spin_unlock_irqrestore(&sdd->lock, flags); +static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) +{ + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); /* Free DMA channels */ sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client); sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client); -} -static int s3c64xx_spi_transfer(struct spi_device *spi, - struct spi_message *msg) -{ - struct s3c64xx_spi_driver_data *sdd; - unsigned long flags; - - sdd = spi_master_get_devdata(spi->master); - - spin_lock_irqsave(&sdd->lock, flags); - - if (sdd->state & SUSPND) { - spin_unlock_irqrestore(&sdd->lock, flags); - return -ESHUTDOWN; - } - - msg->status = -EINPROGRESS; - msg->actual_length = 0; - - list_add_tail(&msg->queue, &sdd->queue); - - queue_work(sdd->workqueue, &sdd->work); - - spin_unlock_irqrestore(&sdd->lock, flags); + pm_runtime_put(&sdd->pdev->dev); return 0; } @@ -872,13 +830,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } } - if (sdd->state & SUSPND) { - spin_unlock_irqrestore(&sdd->lock, flags); - dev_err(&spi->dev, - "setup: SPI-%d not active!\n", spi->master->bus_num); - return -ESHUTDOWN; - } - spin_unlock_irqrestore(&sdd->lock, flags); if (spi->bits_per_word != 8 @@ -890,6 +841,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) goto setup_exit; } + pm_runtime_get_sync(&sdd->pdev->dev); + /* Check if we can provide the requested rate */ if (!sci->clk_from_cmu) { u32 psr, speed; @@ -922,6 +875,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) err = -EINVAL; } + pm_runtime_put(&sdd->pdev->dev); + setup_exit: /* setup() returns with device de-selected */ @@ -930,6 +885,33 @@ setup_exit: return err; } +static irqreturn_t s3c64xx_spi_irq(int irq, void *data) +{ + struct s3c64xx_spi_driver_data *sdd = data; + struct spi_master *spi = sdd->master; + unsigned int val; + + val = readl(sdd->regs + S3C64XX_SPI_PENDING_CLR); + + val &= S3C64XX_SPI_PND_RX_OVERRUN_CLR | + S3C64XX_SPI_PND_RX_UNDERRUN_CLR | + S3C64XX_SPI_PND_TX_OVERRUN_CLR | + S3C64XX_SPI_PND_TX_UNDERRUN_CLR; + + writel(val, sdd->regs + S3C64XX_SPI_PENDING_CLR); + + if (val & S3C64XX_SPI_PND_RX_OVERRUN_CLR) + dev_err(&spi->dev, "RX overrun\n"); + if (val & S3C64XX_SPI_PND_RX_UNDERRUN_CLR) + dev_err(&spi->dev, "RX underrun\n"); + if (val & S3C64XX_SPI_PND_TX_OVERRUN_CLR) + dev_err(&spi->dev, "TX overrun\n"); + if (val & S3C64XX_SPI_PND_TX_UNDERRUN_CLR) + dev_err(&spi->dev, "TX underrun\n"); + + return IRQ_HANDLED; +} + static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) { struct s3c64xx_spi_info *sci = sdd->cntrlr_info; @@ -970,7 +952,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) struct s3c64xx_spi_driver_data *sdd; struct s3c64xx_spi_info *sci; struct spi_master *master; - int ret; + int ret, irq; char clk_name[16]; if (pdev->id < 0) { @@ -1006,6 +988,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) return -ENXIO; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_warn(&pdev->dev, "Failed to get IRQ: %d\n", irq); + return irq; + } + master = spi_alloc_master(&pdev->dev, sizeof(struct s3c64xx_spi_driver_data)); if (master == NULL) { @@ -1021,15 +1009,17 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) sdd->pdev = pdev; sdd->sfr_start = mem_res->start; sdd->tx_dma.dmach = dmatx_res->start; - sdd->tx_dma.direction = DMA_TO_DEVICE; + sdd->tx_dma.direction = DMA_MEM_TO_DEV; sdd->rx_dma.dmach = dmarx_res->start; - sdd->rx_dma.direction = DMA_FROM_DEVICE; + sdd->rx_dma.direction = DMA_DEV_TO_MEM; sdd->cur_bpw = 8; master->bus_num = pdev->id; master->setup = s3c64xx_spi_setup; - master->transfer = s3c64xx_spi_transfer; + master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; + master->transfer_one_message = s3c64xx_spi_transfer_one_message; + master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; /* the spi->mode bits understood by this driver: */ @@ -1084,22 +1074,24 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) goto err6; } - sdd->workqueue = create_singlethread_workqueue( - dev_name(master->dev.parent)); - if (sdd->workqueue == NULL) { - dev_err(&pdev->dev, "Unable to create workqueue\n"); - ret = -ENOMEM; - goto err7; - } - /* Setup Deufult Mode */ s3c64xx_spi_hwinit(sdd, pdev->id); spin_lock_init(&sdd->lock); init_completion(&sdd->xfer_completion); - INIT_WORK(&sdd->work, s3c64xx_spi_work); INIT_LIST_HEAD(&sdd->queue); + ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", + irq, ret); + goto err7; + } + + writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN | + S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, + sdd->regs + S3C64XX_SPI_INT_EN); + if (spi_register_master(master)) { dev_err(&pdev->dev, "cannot register SPI master\n"); ret = -EBUSY; @@ -1113,10 +1105,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) mem_res->end, mem_res->start, sdd->rx_dma.dmach, sdd->tx_dma.dmach); + pm_runtime_enable(&pdev->dev); + return 0; err8: - destroy_workqueue(sdd->workqueue); + free_irq(irq, sdd); err7: clk_disable(sdd->src_clk); err6: @@ -1142,18 +1136,14 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct resource *mem_res; - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - sdd->state |= SUSPND; - spin_unlock_irqrestore(&sdd->lock, flags); - while (sdd->state & SPIBUSY) - msleep(10); + pm_runtime_disable(&pdev->dev); spi_unregister_master(master); - destroy_workqueue(sdd->workqueue); + writel(0, sdd->regs + S3C64XX_SPI_INT_EN); + + free_irq(platform_get_irq(pdev, 0), sdd); clk_disable(sdd->src_clk); clk_put(sdd->src_clk); @@ -1174,18 +1164,12 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) +static int s3c64xx_spi_suspend(struct device *dev) { - struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - unsigned long flags; - - spin_lock_irqsave(&sdd->lock, flags); - sdd->state |= SUSPND; - spin_unlock_irqrestore(&sdd->lock, flags); - while (sdd->state & SPIBUSY) - msleep(10); + spi_master_suspend(master); /* Disable the clock */ clk_disable(sdd->src_clk); @@ -1196,12 +1180,12 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int s3c64xx_spi_resume(struct platform_device *pdev) +static int s3c64xx_spi_resume(struct device *dev) { - struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct s3c64xx_spi_info *sci = sdd->cntrlr_info; - unsigned long flags; sci->cfg_gpio(pdev); @@ -1211,25 +1195,49 @@ static int s3c64xx_spi_resume(struct platform_device *pdev) s3c64xx_spi_hwinit(sdd, pdev->id); - spin_lock_irqsave(&sdd->lock, flags); - sdd->state &= ~SUSPND; - spin_unlock_irqrestore(&sdd->lock, flags); + spi_master_resume(master); return 0; } -#else -#define s3c64xx_spi_suspend NULL -#define s3c64xx_spi_resume NULL #endif /* CONFIG_PM */ +#ifdef CONFIG_PM_RUNTIME +static int s3c64xx_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + + clk_disable(sdd->clk); + clk_disable(sdd->src_clk); + + return 0; +} + +static int s3c64xx_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + + clk_enable(sdd->src_clk); + clk_enable(sdd->clk); + + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +static const struct dev_pm_ops s3c64xx_spi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(s3c64xx_spi_suspend, s3c64xx_spi_resume) + SET_RUNTIME_PM_OPS(s3c64xx_spi_runtime_suspend, + s3c64xx_spi_runtime_resume, NULL) +}; + static struct platform_driver s3c64xx_spi_driver = { .driver = { .name = "s3c64xx-spi", .owner = THIS_MODULE, + .pm = &s3c64xx_spi_pm, }, .remove = s3c64xx_spi_remove, - .suspend = s3c64xx_spi_suspend, - .resume = s3c64xx_spi_resume, }; MODULE_ALIAS("platform:s3c64xx-spi"); diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c new file mode 100644 index 000000000000..934138c7b3d3 --- /dev/null +++ b/drivers/spi/spi-sh-hspi.c @@ -0,0 +1,331 @@ +/* + * SuperH HSPI bus driver + * + * Copyright (C) 2011 Kuninori Morimoto + * + * Based on spi-sh.c: + * Based on pxa2xx_spi.c: + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/spi/sh_hspi.h> + +#define SPCR 0x00 +#define SPSR 0x04 +#define SPSCR 0x08 +#define SPTBR 0x0C +#define SPRBR 0x10 +#define SPCR2 0x14 + +/* SPSR */ +#define RXFL (1 << 2) + +#define hspi2info(h) (h->dev->platform_data) + +struct hspi_priv { + void __iomem *addr; + struct spi_master *master; + struct device *dev; + struct clk *clk; +}; + +/* + * basic function + */ +static void hspi_write(struct hspi_priv *hspi, int reg, u32 val) +{ + iowrite32(val, hspi->addr + reg); +} + +static u32 hspi_read(struct hspi_priv *hspi, int reg) +{ + return ioread32(hspi->addr + reg); +} + +/* + * transfer function + */ +static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) +{ + int t = 256; + + while (t--) { + if ((mask & hspi_read(hspi, SPSR)) == val) + return 0; + + msleep(20); + } + + dev_err(hspi->dev, "timeout\n"); + return -ETIMEDOUT; +} + +/* + * spi master function + */ +static int hspi_prepare_transfer(struct spi_master *master) +{ + struct hspi_priv *hspi = spi_master_get_devdata(master); + + pm_runtime_get_sync(hspi->dev); + return 0; +} + +static int hspi_unprepare_transfer(struct spi_master *master) +{ + struct hspi_priv *hspi = spi_master_get_devdata(master); + + pm_runtime_put_sync(hspi->dev); + return 0; +} + +static void hspi_hw_setup(struct hspi_priv *hspi, + struct spi_message *msg, + struct spi_transfer *t) +{ + struct spi_device *spi = msg->spi; + struct device *dev = hspi->dev; + u32 target_rate; + u32 spcr, idiv_clk; + u32 rate, best_rate, min, tmp; + + target_rate = t ? t->speed_hz : 0; + if (!target_rate) + target_rate = spi->max_speed_hz; + + /* + * find best IDIV/CLKCx settings + */ + min = ~0; + best_rate = 0; + spcr = 0; + for (idiv_clk = 0x00; idiv_clk <= 0x3F; idiv_clk++) { + rate = clk_get_rate(hspi->clk); + + /* IDIV calculation */ + if (idiv_clk & (1 << 5)) + rate /= 128; + else + rate /= 16; + + /* CLKCx calculation */ + rate /= (((idiv_clk & 0x1F) + 1) * 2) ; + + /* save best settings */ + tmp = abs(target_rate - rate); + if (tmp < min) { + min = tmp; + spcr = idiv_clk; + best_rate = rate; + } + } + + if (spi->mode & SPI_CPHA) + spcr |= 1 << 7; + if (spi->mode & SPI_CPOL) + spcr |= 1 << 6; + + dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate); + + hspi_write(hspi, SPCR, spcr); + hspi_write(hspi, SPSR, 0x0); + hspi_write(hspi, SPSCR, 0x1); /* master mode */ +} + +static int hspi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) +{ + struct hspi_priv *hspi = spi_master_get_devdata(master); + struct spi_transfer *t; + u32 tx; + u32 rx; + int ret, i; + + dev_dbg(hspi->dev, "%s\n", __func__); + + ret = 0; + list_for_each_entry(t, &msg->transfers, transfer_list) { + hspi_hw_setup(hspi, msg, t); + + for (i = 0; i < t->len; i++) { + + /* wait remains */ + ret = hspi_status_check_timeout(hspi, 0x1, 0); + if (ret < 0) + break; + + tx = 0; + if (t->tx_buf) + tx = (u32)((u8 *)t->tx_buf)[i]; + + hspi_write(hspi, SPTBR, tx); + + /* wait recive */ + ret = hspi_status_check_timeout(hspi, 0x4, 0x4); + if (ret < 0) + break; + + rx = hspi_read(hspi, SPRBR); + if (t->rx_buf) + ((u8 *)t->rx_buf)[i] = (u8)rx; + + } + + msg->actual_length += t->len; + } + + msg->status = ret; + spi_finalize_current_message(master); + + return ret; +} + +static int hspi_setup(struct spi_device *spi) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + struct device *dev = hspi->dev; + + if (8 != spi->bits_per_word) { + dev_err(dev, "bits_per_word should be 8\n"); + return -EIO; + } + + dev_dbg(dev, "%s setup\n", spi->modalias); + + return 0; +} + +static void hspi_cleanup(struct spi_device *spi) +{ + struct hspi_priv *hspi = spi_master_get_devdata(spi->master); + struct device *dev = hspi->dev; + + dev_dbg(dev, "%s cleanup\n", spi->modalias); +} + +static int __devinit hspi_probe(struct platform_device *pdev) +{ + struct resource *res; + struct spi_master *master; + struct hspi_priv *hspi; + struct clk *clk; + int ret; + + /* get base addr */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid resource\n"); + return -EINVAL; + } + + master = spi_alloc_master(&pdev->dev, sizeof(*hspi)); + if (!master) { + dev_err(&pdev->dev, "spi_alloc_master error.\n"); + return -ENOMEM; + } + + clk = clk_get(NULL, "shyway_clk"); + if (!clk) { + dev_err(&pdev->dev, "shyway_clk is required\n"); + ret = -EINVAL; + goto error0; + } + + hspi = spi_master_get_devdata(master); + dev_set_drvdata(&pdev->dev, hspi); + + /* init hspi */ + hspi->master = master; + hspi->dev = &pdev->dev; + hspi->clk = clk; + hspi->addr = devm_ioremap(hspi->dev, + res->start, resource_size(res)); + if (!hspi->addr) { + dev_err(&pdev->dev, "ioremap error.\n"); + ret = -ENOMEM; + goto error1; + } + + master->num_chipselect = 1; + master->bus_num = pdev->id; + master->setup = hspi_setup; + master->cleanup = hspi_cleanup; + master->mode_bits = SPI_CPOL | SPI_CPHA; + master->prepare_transfer_hardware = hspi_prepare_transfer; + master->transfer_one_message = hspi_transfer_one_message; + master->unprepare_transfer_hardware = hspi_unprepare_transfer; + ret = spi_register_master(master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto error2; + } + + pm_runtime_enable(&pdev->dev); + + dev_info(&pdev->dev, "probed\n"); + + return 0; + + error2: + devm_iounmap(hspi->dev, hspi->addr); + error1: + clk_put(clk); + error0: + spi_master_put(master); + + return ret; +} + +static int __devexit hspi_remove(struct platform_device *pdev) +{ + struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + clk_put(hspi->clk); + spi_unregister_master(hspi->master); + devm_iounmap(hspi->dev, hspi->addr); + + return 0; +} + +static struct platform_driver hspi_driver = { + .probe = hspi_probe, + .remove = __devexit_p(hspi_remove), + .driver = { + .name = "sh-hspi", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(hspi_driver); + +MODULE_DESCRIPTION("SuperH HSPI bus driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); +MODULE_ALIAS("platform:sh_spi"); diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 70c8af9f7ccc..79442c31bcd9 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -92,17 +92,26 @@ struct spi_sh_data { unsigned long cr1; wait_queue_head_t wait; spinlock_t lock; + int width; }; static void spi_sh_write(struct spi_sh_data *ss, unsigned long data, unsigned long offset) { - writel(data, ss->addr + offset); + if (ss->width == 8) + iowrite8(data, ss->addr + (offset >> 2)); + else if (ss->width == 32) + iowrite32(data, ss->addr + offset); } static unsigned long spi_sh_read(struct spi_sh_data *ss, unsigned long offset) { - return readl(ss->addr + offset); + if (ss->width == 8) + return ioread8(ss->addr + (offset >> 2)); + else if (ss->width == 32) + return ioread32(ss->addr + offset); + else + return 0; } static void spi_sh_set_bit(struct spi_sh_data *ss, unsigned long val, @@ -464,6 +473,18 @@ static int __devinit spi_sh_probe(struct platform_device *pdev) ss = spi_master_get_devdata(master); dev_set_drvdata(&pdev->dev, ss); + switch (res->flags & IORESOURCE_MEM_TYPE_MASK) { + case IORESOURCE_MEM_8BIT: + ss->width = 8; + break; + case IORESOURCE_MEM_32BIT: + ss->width = 32; + break; + default: + dev_err(&pdev->dev, "No support width\n"); + ret = -ENODEV; + goto error1; + } ss->irq = irq; ss->master = master; ss->addr = ioremap(res->start, resource_size(res)); diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c new file mode 100644 index 000000000000..52fe495bb32a --- /dev/null +++ b/drivers/spi/spi-sirf.c @@ -0,0 +1,687 @@ +/* + * SPI bus driver for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/of_gpio.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> +#include <linux/pinctrl/pinmux.h> + +#define DRIVER_NAME "sirfsoc_spi" + +#define SIRFSOC_SPI_CTRL 0x0000 +#define SIRFSOC_SPI_CMD 0x0004 +#define SIRFSOC_SPI_TX_RX_EN 0x0008 +#define SIRFSOC_SPI_INT_EN 0x000C +#define SIRFSOC_SPI_INT_STATUS 0x0010 +#define SIRFSOC_SPI_TX_DMA_IO_CTRL 0x0100 +#define SIRFSOC_SPI_TX_DMA_IO_LEN 0x0104 +#define SIRFSOC_SPI_TXFIFO_CTRL 0x0108 +#define SIRFSOC_SPI_TXFIFO_LEVEL_CHK 0x010C +#define SIRFSOC_SPI_TXFIFO_OP 0x0110 +#define SIRFSOC_SPI_TXFIFO_STATUS 0x0114 +#define SIRFSOC_SPI_TXFIFO_DATA 0x0118 +#define SIRFSOC_SPI_RX_DMA_IO_CTRL 0x0120 +#define SIRFSOC_SPI_RX_DMA_IO_LEN 0x0124 +#define SIRFSOC_SPI_RXFIFO_CTRL 0x0128 +#define SIRFSOC_SPI_RXFIFO_LEVEL_CHK 0x012C +#define SIRFSOC_SPI_RXFIFO_OP 0x0130 +#define SIRFSOC_SPI_RXFIFO_STATUS 0x0134 +#define SIRFSOC_SPI_RXFIFO_DATA 0x0138 +#define SIRFSOC_SPI_DUMMY_DELAY_CTL 0x0144 + +/* SPI CTRL register defines */ +#define SIRFSOC_SPI_SLV_MODE BIT(16) +#define SIRFSOC_SPI_CMD_MODE BIT(17) +#define SIRFSOC_SPI_CS_IO_OUT BIT(18) +#define SIRFSOC_SPI_CS_IO_MODE BIT(19) +#define SIRFSOC_SPI_CLK_IDLE_STAT BIT(20) +#define SIRFSOC_SPI_CS_IDLE_STAT BIT(21) +#define SIRFSOC_SPI_TRAN_MSB BIT(22) +#define SIRFSOC_SPI_DRV_POS_EDGE BIT(23) +#define SIRFSOC_SPI_CS_HOLD_TIME BIT(24) +#define SIRFSOC_SPI_CLK_SAMPLE_MODE BIT(25) +#define SIRFSOC_SPI_TRAN_DAT_FORMAT_8 (0 << 26) +#define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26) +#define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26) +#define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26) +#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28) +#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30) +#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31) + +/* Interrupt Enable */ +#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0) +#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1) +#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2) +#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3) +#define SIRFSOC_SPI_RX_IO_DMA_INT_EN BIT(4) +#define SIRFSOC_SPI_TX_IO_DMA_INT_EN BIT(5) +#define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6) +#define SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN BIT(7) +#define SIRFSOC_SPI_RXFIFO_THD_INT_EN BIT(8) +#define SIRFSOC_SPI_TXFIFO_THD_INT_EN BIT(9) +#define SIRFSOC_SPI_FRM_END_INT_EN BIT(10) + +#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF + +/* Interrupt status */ +#define SIRFSOC_SPI_RX_DONE BIT(0) +#define SIRFSOC_SPI_TX_DONE BIT(1) +#define SIRFSOC_SPI_RX_OFLOW BIT(2) +#define SIRFSOC_SPI_TX_UFLOW BIT(3) +#define SIRFSOC_SPI_RX_FIFO_FULL BIT(6) +#define SIRFSOC_SPI_TXFIFO_EMPTY BIT(7) +#define SIRFSOC_SPI_RXFIFO_THD_REACH BIT(8) +#define SIRFSOC_SPI_TXFIFO_THD_REACH BIT(9) +#define SIRFSOC_SPI_FRM_END BIT(10) + +/* TX RX enable */ +#define SIRFSOC_SPI_RX_EN BIT(0) +#define SIRFSOC_SPI_TX_EN BIT(1) +#define SIRFSOC_SPI_CMD_TX_EN BIT(2) + +#define SIRFSOC_SPI_IO_MODE_SEL BIT(0) +#define SIRFSOC_SPI_RX_DMA_FLUSH BIT(2) + +/* FIFO OPs */ +#define SIRFSOC_SPI_FIFO_RESET BIT(0) +#define SIRFSOC_SPI_FIFO_START BIT(1) + +/* FIFO CTRL */ +#define SIRFSOC_SPI_FIFO_WIDTH_BYTE (0 << 0) +#define SIRFSOC_SPI_FIFO_WIDTH_WORD (1 << 0) +#define SIRFSOC_SPI_FIFO_WIDTH_DWORD (2 << 0) + +/* FIFO Status */ +#define SIRFSOC_SPI_FIFO_LEVEL_MASK 0xFF +#define SIRFSOC_SPI_FIFO_FULL BIT(8) +#define SIRFSOC_SPI_FIFO_EMPTY BIT(9) + +/* 256 bytes rx/tx FIFO */ +#define SIRFSOC_SPI_FIFO_SIZE 256 +#define SIRFSOC_SPI_DAT_FRM_LEN_MAX (64 * 1024) + +#define SIRFSOC_SPI_FIFO_SC(x) ((x) & 0x3F) +#define SIRFSOC_SPI_FIFO_LC(x) (((x) & 0x3F) << 10) +#define SIRFSOC_SPI_FIFO_HC(x) (((x) & 0x3F) << 20) +#define SIRFSOC_SPI_FIFO_THD(x) (((x) & 0xFF) << 2) + +struct sirfsoc_spi { + struct spi_bitbang bitbang; + struct completion done; + + void __iomem *base; + u32 ctrl_freq; /* SPI controller clock speed */ + struct clk *clk; + struct pinmux *pmx; + + /* rx & tx bufs from the spi_transfer */ + const void *tx; + void *rx; + + /* place received word into rx buffer */ + void (*rx_word) (struct sirfsoc_spi *); + /* get word from tx buffer for sending */ + void (*tx_word) (struct sirfsoc_spi *); + + /* number of words left to be tranmitted/received */ + unsigned int left_tx_cnt; + unsigned int left_rx_cnt; + + /* tasklet to push tx msg into FIFO */ + struct tasklet_struct tasklet_tx; + + int chipselect[0]; +}; + +static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi) +{ + u32 data; + u8 *rx = sspi->rx; + + data = readl(sspi->base + SIRFSOC_SPI_RXFIFO_DATA); + + if (rx) { + *rx++ = (u8) data; + sspi->rx = rx; + } + + sspi->left_rx_cnt--; +} + +static void spi_sirfsoc_tx_word_u8(struct sirfsoc_spi *sspi) +{ + u32 data = 0; + const u8 *tx = sspi->tx; + + if (tx) { + data = *tx++; + sspi->tx = tx; + } + + writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA); + sspi->left_tx_cnt--; +} + +static void spi_sirfsoc_rx_word_u16(struct sirfsoc_spi *sspi) +{ + u32 data; + u16 *rx = sspi->rx; + + data = readl(sspi->base + SIRFSOC_SPI_RXFIFO_DATA); + + if (rx) { + *rx++ = (u16) data; + sspi->rx = rx; + } + + sspi->left_rx_cnt--; +} + +static void spi_sirfsoc_tx_word_u16(struct sirfsoc_spi *sspi) +{ + u32 data = 0; + const u16 *tx = sspi->tx; + + if (tx) { + data = *tx++; + sspi->tx = tx; + } + + writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA); + sspi->left_tx_cnt--; +} + +static void spi_sirfsoc_rx_word_u32(struct sirfsoc_spi *sspi) +{ + u32 data; + u32 *rx = sspi->rx; + + data = readl(sspi->base + SIRFSOC_SPI_RXFIFO_DATA); + + if (rx) { + *rx++ = (u32) data; + sspi->rx = rx; + } + + sspi->left_rx_cnt--; + +} + +static void spi_sirfsoc_tx_word_u32(struct sirfsoc_spi *sspi) +{ + u32 data = 0; + const u32 *tx = sspi->tx; + + if (tx) { + data = *tx++; + sspi->tx = tx; + } + + writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA); + sspi->left_tx_cnt--; +} + +static void spi_sirfsoc_tasklet_tx(unsigned long arg) +{ + struct sirfsoc_spi *sspi = (struct sirfsoc_spi *)arg; + + /* Fill Tx FIFO while there are left words to be transmitted */ + while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) & + SIRFSOC_SPI_FIFO_FULL)) && + sspi->left_tx_cnt) + sspi->tx_word(sspi); +} + +static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) +{ + struct sirfsoc_spi *sspi = dev_id; + u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS); + + writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); + + /* Error Conditions */ + if (spi_stat & SIRFSOC_SPI_RX_OFLOW || + spi_stat & SIRFSOC_SPI_TX_UFLOW) { + complete(&sspi->done); + writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + } + + if (spi_stat & SIRFSOC_SPI_FRM_END) { + while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) + & SIRFSOC_SPI_FIFO_EMPTY)) && + sspi->left_rx_cnt) + sspi->rx_word(sspi); + + /* Received all words */ + if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) { + complete(&sspi->done); + writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + } + } + + if (spi_stat & SIRFSOC_SPI_RXFIFO_THD_REACH || + spi_stat & SIRFSOC_SPI_TXFIFO_THD_REACH || + spi_stat & SIRFSOC_SPI_RX_FIFO_FULL || + spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY) + tasklet_schedule(&sspi->tasklet_tx); + + return IRQ_HANDLED; +} + +static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + int timeout = t->len * 10; + sspi = spi_master_get_devdata(spi->master); + + sspi->tx = t->tx_buf; + sspi->rx = t->rx_buf; + sspi->left_tx_cnt = sspi->left_rx_cnt = t->len; + INIT_COMPLETION(sspi->done); + + writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + + if (t->len == 1) { + writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | + SIRFSOC_SPI_ENA_AUTO_CLR, + sspi->base + SIRFSOC_SPI_CTRL); + writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); + writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); + } else if ((t->len > 1) && (t->len < SIRFSOC_SPI_DAT_FRM_LEN_MAX)) { + writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | + SIRFSOC_SPI_MUL_DAT_MODE | + SIRFSOC_SPI_ENA_AUTO_CLR, + sspi->base + SIRFSOC_SPI_CTRL); + writel(t->len - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); + writel(t->len - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); + } else { + writel(readl(sspi->base + SIRFSOC_SPI_CTRL), + sspi->base + SIRFSOC_SPI_CTRL); + writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); + writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); + } + + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + + /* Send the first word to trigger the whole tx/rx process */ + sspi->tx_word(sspi); + + writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | + SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN | + SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN | + SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN); + + if (wait_for_completion_timeout(&sspi->done, timeout) == 0) + dev_err(&spi->dev, "transfer timeout\n"); + + /* TX, RX FIFO stop */ + writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); + writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + + return t->len - sspi->left_rx_cnt; +} + +static void spi_sirfsoc_chipselect(struct spi_device *spi, int value) +{ + struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master); + + if (sspi->chipselect[spi->chip_select] == 0) { + u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL); + regval |= SIRFSOC_SPI_CS_IO_OUT; + switch (value) { + case BITBANG_CS_ACTIVE: + if (spi->mode & SPI_CS_HIGH) + regval |= SIRFSOC_SPI_CS_IO_OUT; + else + regval &= ~SIRFSOC_SPI_CS_IO_OUT; + break; + case BITBANG_CS_INACTIVE: + if (spi->mode & SPI_CS_HIGH) + regval &= ~SIRFSOC_SPI_CS_IO_OUT; + else + regval |= SIRFSOC_SPI_CS_IO_OUT; + break; + } + writel(regval, sspi->base + SIRFSOC_SPI_CTRL); + } else { + int gpio = sspi->chipselect[spi->chip_select]; + gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); + } +} + +static int +spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + u8 bits_per_word = 0; + int hz = 0; + u32 regval; + u32 txfifo_ctrl, rxfifo_ctrl; + u32 fifo_size = SIRFSOC_SPI_FIFO_SIZE / 4; + + sspi = spi_master_get_devdata(spi->master); + + bits_per_word = t && t->bits_per_word ? t->bits_per_word : + spi->bits_per_word; + hz = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz; + + /* Enable IO mode for RX, TX */ + writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); + regval = (sspi->ctrl_freq / (2 * hz)) - 1; + + if (regval > 0xFFFF || regval < 0) { + dev_err(&spi->dev, "Speed %d not supported\n", hz); + return -EINVAL; + } + + switch (bits_per_word) { + case 8: + regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8; + sspi->rx_word = spi_sirfsoc_rx_word_u8; + sspi->tx_word = spi_sirfsoc_tx_word_u8; + txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + SIRFSOC_SPI_FIFO_WIDTH_BYTE; + rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + SIRFSOC_SPI_FIFO_WIDTH_BYTE; + break; + case 12: + case 16: + regval |= (bits_per_word == 12) ? SIRFSOC_SPI_TRAN_DAT_FORMAT_12 : + SIRFSOC_SPI_TRAN_DAT_FORMAT_16; + sspi->rx_word = spi_sirfsoc_rx_word_u16; + sspi->tx_word = spi_sirfsoc_tx_word_u16; + txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + SIRFSOC_SPI_FIFO_WIDTH_WORD; + rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + SIRFSOC_SPI_FIFO_WIDTH_WORD; + break; + case 32: + regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32; + sspi->rx_word = spi_sirfsoc_rx_word_u32; + sspi->tx_word = spi_sirfsoc_tx_word_u32; + txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + SIRFSOC_SPI_FIFO_WIDTH_DWORD; + rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + SIRFSOC_SPI_FIFO_WIDTH_DWORD; + break; + default: + dev_err(&spi->dev, "Bits per word %d not supported\n", + bits_per_word); + return -EINVAL; + } + + if (!(spi->mode & SPI_CS_HIGH)) + regval |= SIRFSOC_SPI_CS_IDLE_STAT; + if (!(spi->mode & SPI_LSB_FIRST)) + regval |= SIRFSOC_SPI_TRAN_MSB; + if (spi->mode & SPI_CPOL) + regval |= SIRFSOC_SPI_CLK_IDLE_STAT; + + /* + * Data should be driven at least 1/2 cycle before the fetch edge to make + * sure that data gets stable at the fetch edge. + */ + if (((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA)) || + (!(spi->mode & SPI_CPOL) && !(spi->mode & SPI_CPHA))) + regval &= ~SIRFSOC_SPI_DRV_POS_EDGE; + else + regval |= SIRFSOC_SPI_DRV_POS_EDGE; + + writel(SIRFSOC_SPI_FIFO_SC(fifo_size - 2) | + SIRFSOC_SPI_FIFO_LC(fifo_size / 2) | + SIRFSOC_SPI_FIFO_HC(2), + sspi->base + SIRFSOC_SPI_TXFIFO_LEVEL_CHK); + writel(SIRFSOC_SPI_FIFO_SC(2) | + SIRFSOC_SPI_FIFO_LC(fifo_size / 2) | + SIRFSOC_SPI_FIFO_HC(fifo_size - 2), + sspi->base + SIRFSOC_SPI_RXFIFO_LEVEL_CHK); + writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); + writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); + + writel(regval, sspi->base + SIRFSOC_SPI_CTRL); + return 0; +} + +static int spi_sirfsoc_setup(struct spi_device *spi) +{ + struct sirfsoc_spi *sspi; + + if (!spi->max_speed_hz) + return -EINVAL; + + sspi = spi_master_get_devdata(spi->master); + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + return spi_sirfsoc_setup_transfer(spi, NULL); +} + +static int __devinit spi_sirfsoc_probe(struct platform_device *pdev) +{ + struct sirfsoc_spi *sspi; + struct spi_master *master; + struct resource *mem_res; + int num_cs, cs_gpio, irq; + int i; + int ret; + + ret = of_property_read_u32(pdev->dev.of_node, + "sirf,spi-num-chipselects", &num_cs); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to get chip select number\n"); + goto err_cs; + } + + master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); + if (!master) { + dev_err(&pdev->dev, "Unable to allocate SPI master\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, master); + sspi = spi_master_get_devdata(master); + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + dev_err(&pdev->dev, "Unable to get IO resource\n"); + ret = -ENODEV; + goto free_master; + } + master->num_chipselect = num_cs; + + for (i = 0; i < master->num_chipselect; i++) { + cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i); + if (cs_gpio < 0) { + dev_err(&pdev->dev, "can't get cs gpio from DT\n"); + ret = -ENODEV; + goto free_master; + } + + sspi->chipselect[i] = cs_gpio; + if (cs_gpio == 0) + continue; /* use cs from spi controller */ + + ret = gpio_request(cs_gpio, DRIVER_NAME); + if (ret) { + while (i > 0) { + i--; + if (sspi->chipselect[i] > 0) + gpio_free(sspi->chipselect[i]); + } + dev_err(&pdev->dev, "fail to request cs gpios\n"); + goto free_master; + } + } + + sspi->base = devm_request_and_ioremap(&pdev->dev, mem_res); + if (!sspi->base) { + dev_err(&pdev->dev, "IO remap failed!\n"); + ret = -ENOMEM; + goto free_master; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = -ENXIO; + goto free_master; + } + ret = devm_request_irq(&pdev->dev, irq, spi_sirfsoc_irq, 0, + DRIVER_NAME, sspi); + if (ret) + goto free_master; + + sspi->bitbang.master = spi_master_get(master); + sspi->bitbang.chipselect = spi_sirfsoc_chipselect; + sspi->bitbang.setup_transfer = spi_sirfsoc_setup_transfer; + sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer; + sspi->bitbang.master->setup = spi_sirfsoc_setup; + master->bus_num = pdev->id; + sspi->bitbang.master->dev.of_node = pdev->dev.of_node; + + sspi->pmx = pinmux_get(&pdev->dev, NULL); + ret = IS_ERR(sspi->pmx); + if (ret) + goto free_master; + + pinmux_enable(sspi->pmx); + + sspi->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(sspi->clk)) { + ret = -EINVAL; + goto free_pmx; + } + clk_enable(sspi->clk); + sspi->ctrl_freq = clk_get_rate(sspi->clk); + + init_completion(&sspi->done); + + tasklet_init(&sspi->tasklet_tx, spi_sirfsoc_tasklet_tx, + (unsigned long)sspi); + + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + /* We are not using dummy delay between command and data */ + writel(0, sspi->base + SIRFSOC_SPI_DUMMY_DELAY_CTL); + + ret = spi_bitbang_start(&sspi->bitbang); + if (ret) + goto free_clk; + + dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num); + + return 0; + +free_clk: + clk_disable(sspi->clk); + clk_put(sspi->clk); +free_pmx: + pinmux_disable(sspi->pmx); + pinmux_put(sspi->pmx); +free_master: + spi_master_put(master); +err_cs: + return ret; +} + +static int __devexit spi_sirfsoc_remove(struct platform_device *pdev) +{ + struct spi_master *master; + struct sirfsoc_spi *sspi; + int i; + + master = platform_get_drvdata(pdev); + sspi = spi_master_get_devdata(master); + + spi_bitbang_stop(&sspi->bitbang); + for (i = 0; i < master->num_chipselect; i++) { + if (sspi->chipselect[i] > 0) + gpio_free(sspi->chipselect[i]); + } + clk_disable(sspi->clk); + clk_put(sspi->clk); + pinmux_disable(sspi->pmx); + pinmux_put(sspi->pmx); + spi_master_put(master); + return 0; +} + +#ifdef CONFIG_PM +static int spi_sirfsoc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct sirfsoc_spi *sspi = spi_master_get_devdata(master); + + clk_disable(sspi->clk); + return 0; +} + +static int spi_sirfsoc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct sirfsoc_spi *sspi = spi_master_get_devdata(master); + + clk_enable(sspi->clk); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + + return 0; +} + +static const struct dev_pm_ops spi_sirfsoc_pm_ops = { + .suspend = spi_sirfsoc_suspend, + .resume = spi_sirfsoc_resume, +}; +#endif + +static const struct of_device_id spi_sirfsoc_of_match[] = { + { .compatible = "sirf,prima2-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, sirfsoc_spi_of_match); + +static struct platform_driver spi_sirfsoc_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &spi_sirfsoc_pm_ops, +#endif + .of_match_table = spi_sirfsoc_of_match, + }, + .probe = spi_sirfsoc_probe, + .remove = __devexit_p(spi_sirfsoc_remove), +}; +module_platform_driver(spi_sirfsoc_driver); + +MODULE_DESCRIPTION("SiRF SoC SPI master driver"); +MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, " + "Barry Song <Baohua.Song@csr.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 10182eb50068..5c6fa5ed3366 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -196,6 +196,7 @@ struct pch_spi_data { struct pch_spi_dma_ctrl dma; int use_dma; u8 irq_reg_sts; + int save_total_len; }; /** @@ -216,7 +217,7 @@ struct pch_pd_dev_save { struct pch_spi_board_data *board_dat; }; -static struct pci_device_id pch_spi_pcidev_id[] = { +static DEFINE_PCI_DEVICE_TABLE(pch_spi_pcidev_id) = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, }, @@ -318,22 +319,23 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, data->tx_index = tx_index; data->rx_index = rx_index; - } - - /* if transfer complete interrupt */ - if (reg_spsr_val & SPSR_FI_BIT) { - if ((tx_index == bpw_len) && (rx_index == tx_index)) { - /* disable interrupts */ - pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); - - /* transfer is completed; - inform pch_spi_process_messages */ - data->transfer_complete = true; - data->transfer_active = false; - wake_up(&data->wait); - } else { - dev_err(&data->master->dev, - "%s : Transfer is not completed", __func__); + /* if transfer complete interrupt */ + if (reg_spsr_val & SPSR_FI_BIT) { + if ((tx_index == bpw_len) && (rx_index == tx_index)) { + /* disable interrupts */ + pch_spi_setclr_reg(data->master, PCH_SPCR, 0, + PCH_ALL); + + /* transfer is completed; + inform pch_spi_process_messages */ + data->transfer_complete = true; + data->transfer_active = false; + wake_up(&data->wait); + } else { + dev_err(&data->master->dev, + "%s : Transfer is not completed", + __func__); + } } } } @@ -822,11 +824,13 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) rx_dma_buf = data->dma.rx_buf_virt; for (j = 0; j < data->bpw_len; j++) *rx_buf++ = *rx_dma_buf++ & 0xFF; + data->cur_trans->rx_buf = rx_buf; } else { rx_sbuf = data->cur_trans->rx_buf; rx_dma_sbuf = data->dma.rx_buf_virt; for (j = 0; j < data->bpw_len; j++) *rx_sbuf++ = *rx_dma_sbuf++; + data->cur_trans->rx_buf = rx_sbuf; } } @@ -852,6 +856,9 @@ static int pch_spi_start_transfer(struct pch_spi_data *data) rtn = wait_event_interruptible_timeout(data->wait, data->transfer_complete, msecs_to_jiffies(2 * HZ)); + if (!rtn) + dev_err(&data->master->dev, + "%s wait-event timeout\n", __func__); dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, DMA_FROM_DEVICE); @@ -923,7 +930,8 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) dma_cap_set(DMA_SLAVE, mask); /* Get DMA's dev information */ - dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(12, 0)); + dma_dev = pci_get_bus_and_slot(data->board_dat->pdev->bus->number, + PCI_DEVFN(12, 0)); /* Set Tx DMA */ param = &dma->param_tx; @@ -987,6 +995,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) int i; int size; int rem; + int head; unsigned long flags; struct pch_spi_dma_ctrl *dma; @@ -1015,6 +1024,11 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) } data->bpw_len = data->cur_trans->len / (*bpw / 8); + if (data->bpw_len > PCH_BUF_SIZE) { + data->bpw_len = PCH_BUF_SIZE; + data->cur_trans->len -= PCH_BUF_SIZE; + } + /* copy Tx Data */ if (data->cur_trans->tx_buf != NULL) { if (*bpw == 8) { @@ -1029,10 +1043,17 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) *tx_dma_sbuf++ = *tx_sbuf++; } } + + /* Calculate Rx parameter for DMA transmitting */ if (data->bpw_len > PCH_DMA_TRANS_SIZE) { - num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; + if (data->bpw_len % PCH_DMA_TRANS_SIZE) { + num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; + rem = data->bpw_len % PCH_DMA_TRANS_SIZE; + } else { + num = data->bpw_len / PCH_DMA_TRANS_SIZE; + rem = PCH_DMA_TRANS_SIZE; + } size = PCH_DMA_TRANS_SIZE; - rem = data->bpw_len % PCH_DMA_TRANS_SIZE; } else { num = 1; size = data->bpw_len; @@ -1092,15 +1113,23 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) dma->nent = num; dma->desc_rx = desc_rx; - /* TX */ - if (data->bpw_len > PCH_DMA_TRANS_SIZE) { - num = data->bpw_len / PCH_DMA_TRANS_SIZE; + /* Calculate Tx parameter for DMA transmitting */ + if (data->bpw_len > PCH_MAX_FIFO_DEPTH) { + head = PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE; + if (data->bpw_len % PCH_DMA_TRANS_SIZE > 4) { + num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; + rem = data->bpw_len % PCH_DMA_TRANS_SIZE - head; + } else { + num = data->bpw_len / PCH_DMA_TRANS_SIZE; + rem = data->bpw_len % PCH_DMA_TRANS_SIZE + + PCH_DMA_TRANS_SIZE - head; + } size = PCH_DMA_TRANS_SIZE; - rem = 16; } else { num = 1; size = data->bpw_len; rem = data->bpw_len; + head = 0; } dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); @@ -1110,11 +1139,17 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) for (i = 0; i < num; i++, sg++) { if (i == 0) { sg->offset = 0; + sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size + head, + sg->offset); + sg_dma_len(sg) = size + head; + } else if (i == (num - 1)) { + sg->offset = head + size * i; + sg->offset = sg->offset * (*bpw / 8); sg_set_page(sg, virt_to_page(dma->tx_buf_virt), rem, sg->offset); sg_dma_len(sg) = rem; } else { - sg->offset = rem + size * (i - 1); + sg->offset = head + size * i; sg->offset = sg->offset * (*bpw / 8); sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size, sg->offset); @@ -1202,6 +1237,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) data->current_msg->spi->bits_per_word); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); do { + int cnt; /* If we are already processing a message get the next transfer structure from the message otherwise retrieve the 1st transfer request from the message. */ @@ -1221,11 +1257,28 @@ static void pch_spi_process_messages(struct work_struct *pwork) } spin_unlock(&data->lock); + if (!data->cur_trans->len) + goto out; + cnt = (data->cur_trans->len - 1) / PCH_BUF_SIZE + 1; + data->save_total_len = data->cur_trans->len; if (data->use_dma) { - pch_spi_handle_dma(data, &bpw); - if (!pch_spi_start_transfer(data)) - goto out; - pch_spi_copy_rx_data_for_dma(data, bpw); + int i; + char *save_rx_buf = data->cur_trans->rx_buf; + for (i = 0; i < cnt; i ++) { + pch_spi_handle_dma(data, &bpw); + if (!pch_spi_start_transfer(data)) { + data->transfer_complete = true; + data->current_msg->status = -EIO; + data->current_msg->complete + (data->current_msg->context); + data->bcurrent_msg_processing = false; + data->current_msg = NULL; + data->cur_trans = NULL; + goto out; + } + pch_spi_copy_rx_data_for_dma(data, bpw); + } + data->cur_trans->rx_buf = save_rx_buf; } else { pch_spi_set_tx(data, &bpw); pch_spi_set_ir(data); @@ -1236,6 +1289,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) data->pkt_tx_buff = NULL; } /* increment message count */ + data->cur_trans->len = data->save_total_len; data->current_msg->actual_length += data->cur_trans->len; dev_dbg(&data->master->dev, @@ -1388,6 +1442,7 @@ static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev) master->num_chipselect = PCH_MAX_CS; master->setup = pch_spi_setup; master->transfer = pch_spi_transfer; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; data->board_dat = board_dat; data->plat_dev = plat_dev; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b2ccdea30cb9..3d8f662e4fe9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -30,6 +30,9 @@ #include <linux/of_spi.h> #include <linux/pm_runtime.h> #include <linux/export.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/kthread.h> static void spidev_release(struct device *dev) { @@ -481,7 +484,7 @@ static void spi_match_master_to_boardinfo(struct spi_master *master, * The board info passed can safely be __initdata ... but be careful of * any embedded pointers (platform_data, etc), they're copied as-is. */ -int __init +int __devinit spi_register_board_info(struct spi_board_info const *info, unsigned n) { struct boardinfo *bi; @@ -507,6 +510,294 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) /*-------------------------------------------------------------------------*/ +/** + * spi_pump_messages - kthread work function which processes spi message queue + * @work: pointer to kthread work struct contained in the master struct + * + * This function checks if there is any spi message in the queue that + * needs processing and if so call out to the driver to initialize hardware + * and transfer each message. + * + */ +static void spi_pump_messages(struct kthread_work *work) +{ + struct spi_master *master = + container_of(work, struct spi_master, pump_messages); + unsigned long flags; + bool was_busy = false; + int ret; + + /* Lock queue and check for queue work */ + spin_lock_irqsave(&master->queue_lock, flags); + if (list_empty(&master->queue) || !master->running) { + if (master->busy) { + ret = master->unprepare_transfer_hardware(master); + if (ret) { + spin_unlock_irqrestore(&master->queue_lock, flags); + dev_err(&master->dev, + "failed to unprepare transfer hardware\n"); + return; + } + } + master->busy = false; + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + + /* Make sure we are not already running a message */ + if (master->cur_msg) { + spin_unlock_irqrestore(&master->queue_lock, flags); + return; + } + /* Extract head of queue */ + master->cur_msg = + list_entry(master->queue.next, struct spi_message, queue); + + list_del_init(&master->cur_msg->queue); + if (master->busy) + was_busy = true; + else + master->busy = true; + spin_unlock_irqrestore(&master->queue_lock, flags); + + if (!was_busy) { + ret = master->prepare_transfer_hardware(master); + if (ret) { + dev_err(&master->dev, + "failed to prepare transfer hardware\n"); + return; + } + } + + ret = master->transfer_one_message(master, master->cur_msg); + if (ret) { + dev_err(&master->dev, + "failed to transfer one message from queue\n"); + return; + } +} + +static int spi_init_queue(struct spi_master *master) +{ + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + + INIT_LIST_HEAD(&master->queue); + spin_lock_init(&master->queue_lock); + + master->running = false; + master->busy = false; + + init_kthread_worker(&master->kworker); + master->kworker_task = kthread_run(kthread_worker_fn, + &master->kworker, + dev_name(&master->dev)); + if (IS_ERR(master->kworker_task)) { + dev_err(&master->dev, "failed to create message pump task\n"); + return -ENOMEM; + } + init_kthread_work(&master->pump_messages, spi_pump_messages); + + /* + * Master config will indicate if this controller should run the + * message pump with high (realtime) priority to reduce the transfer + * latency on the bus by minimising the delay between a transfer + * request and the scheduling of the message pump thread. Without this + * setting the message pump thread will remain at default priority. + */ + if (master->rt) { + dev_info(&master->dev, + "will run message pump with realtime priority\n"); + sched_setscheduler(master->kworker_task, SCHED_FIFO, ¶m); + } + + return 0; +} + +/** + * spi_get_next_queued_message() - called by driver to check for queued + * messages + * @master: the master to check for queued messages + * + * If there are more messages in the queue, the next message is returned from + * this call. + */ +struct spi_message *spi_get_next_queued_message(struct spi_master *master) +{ + struct spi_message *next; + unsigned long flags; + + /* get a pointer to the next message, if any */ + spin_lock_irqsave(&master->queue_lock, flags); + if (list_empty(&master->queue)) + next = NULL; + else + next = list_entry(master->queue.next, + struct spi_message, queue); + spin_unlock_irqrestore(&master->queue_lock, flags); + + return next; +} +EXPORT_SYMBOL_GPL(spi_get_next_queued_message); + +/** + * spi_finalize_current_message() - the current message is complete + * @master: the master to return the message to + * + * Called by the driver to notify the core that the message in the front of the + * queue is complete and can be removed from the queue. + */ +void spi_finalize_current_message(struct spi_master *master) +{ + struct spi_message *mesg; + unsigned long flags; + + spin_lock_irqsave(&master->queue_lock, flags); + mesg = master->cur_msg; + master->cur_msg = NULL; + + queue_kthread_work(&master->kworker, &master->pump_messages); + spin_unlock_irqrestore(&master->queue_lock, flags); + + mesg->state = NULL; + if (mesg->complete) + mesg->complete(mesg->context); +} +EXPORT_SYMBOL_GPL(spi_finalize_current_message); + +static int spi_start_queue(struct spi_master *master) +{ + unsigned long flags; + + spin_lock_irqsave(&master->queue_lock, flags); + + if (master->running || master->busy) { + spin_unlock_irqrestore(&master->queue_lock, flags); + return -EBUSY; + } + + master->running = true; + master->cur_msg = NULL; + spin_unlock_irqrestore(&master->queue_lock, flags); + + queue_kthread_work(&master->kworker, &master->pump_messages); + + return 0; +} + +static int spi_stop_queue(struct spi_master *master) +{ + unsigned long flags; + unsigned limit = 500; + int ret = 0; + + spin_lock_irqsave(&master->queue_lock, flags); + + /* + * This is a bit lame, but is optimized for the common execution path. + * A wait_queue on the master->busy could be used, but then the common + * execution path (pump_messages) would be required to call wake_up or + * friends on every SPI message. Do this instead. + */ + while ((!list_empty(&master->queue) || master->busy) && limit--) { + spin_unlock_irqrestore(&master->queue_lock, flags); + msleep(10); + spin_lock_irqsave(&master->queue_lock, flags); + } + + if (!list_empty(&master->queue) || master->busy) + ret = -EBUSY; + else + master->running = false; + + spin_unlock_irqrestore(&master->queue_lock, flags); + + if (ret) { + dev_warn(&master->dev, + "could not stop message queue\n"); + return ret; + } + return ret; +} + +static int spi_destroy_queue(struct spi_master *master) +{ + int ret; + + ret = spi_stop_queue(master); + + /* + * flush_kthread_worker will block until all work is done. + * If the reason that stop_queue timed out is that the work will never + * finish, then it does no good to call flush/stop thread, so + * return anyway. + */ + if (ret) { + dev_err(&master->dev, "problem destroying queue\n"); + return ret; + } + + flush_kthread_worker(&master->kworker); + kthread_stop(master->kworker_task); + + return 0; +} + +/** + * spi_queued_transfer - transfer function for queued transfers + * @spi: spi device which is requesting transfer + * @msg: spi message which is to handled is queued to driver queue + */ +static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct spi_master *master = spi->master; + unsigned long flags; + + spin_lock_irqsave(&master->queue_lock, flags); + + if (!master->running) { + spin_unlock_irqrestore(&master->queue_lock, flags); + return -ESHUTDOWN; + } + msg->actual_length = 0; + msg->status = -EINPROGRESS; + + list_add_tail(&msg->queue, &master->queue); + if (master->running && !master->busy) + queue_kthread_work(&master->kworker, &master->pump_messages); + + spin_unlock_irqrestore(&master->queue_lock, flags); + return 0; +} + +static int spi_master_initialize_queue(struct spi_master *master) +{ + int ret; + + master->queued = true; + master->transfer = spi_queued_transfer; + + /* Initialize and start queue */ + ret = spi_init_queue(master); + if (ret) { + dev_err(&master->dev, "problem initializing queue\n"); + goto err_init_queue; + } + ret = spi_start_queue(master); + if (ret) { + dev_err(&master->dev, "problem starting queue\n"); + goto err_start_queue; + } + + return 0; + +err_start_queue: +err_init_queue: + spi_destroy_queue(master); + return ret; +} + +/*-------------------------------------------------------------------------*/ + static void spi_master_release(struct device *dev) { struct spi_master *master; @@ -522,6 +813,7 @@ static struct class spi_master_class = { }; + /** * spi_alloc_master - allocate SPI master controller * @dev: the controller, possibly using the platform_bus @@ -539,7 +831,8 @@ static struct class spi_master_class = { * * The caller is responsible for assigning the bus number and initializing * the master's methods before calling spi_register_master(); and (after errors - * adding the device) calling spi_master_put() to prevent a memory leak. + * adding the device) calling spi_master_put() and kfree() to prevent a memory + * leak. */ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) { @@ -621,14 +914,23 @@ int spi_register_master(struct spi_master *master) dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), dynamic ? " (dynamic)" : ""); + /* If we're using a queued driver, start the queue */ + if (master->transfer) + dev_info(dev, "master is unqueued, this is deprecated\n"); + else { + status = spi_master_initialize_queue(master); + if (status) { + device_unregister(&master->dev); + goto done; + } + } + mutex_lock(&board_lock); list_add_tail(&master->list, &spi_master_list); list_for_each_entry(bi, &board_list, list) spi_match_master_to_boardinfo(master, &bi->board_info); mutex_unlock(&board_lock); - status = 0; - /* Register devices from the device tree */ of_register_spi_devices(master); done: @@ -636,7 +938,6 @@ done: } EXPORT_SYMBOL_GPL(spi_register_master); - static int __unregister(struct device *dev, void *null) { spi_unregister_device(to_spi_device(dev)); @@ -657,6 +958,11 @@ void spi_unregister_master(struct spi_master *master) { int dummy; + if (master->queued) { + if (spi_destroy_queue(master)) + dev_err(&master->dev, "queue remove failed\n"); + } + mutex_lock(&board_lock); list_del(&master->list); mutex_unlock(&board_lock); @@ -666,6 +972,37 @@ void spi_unregister_master(struct spi_master *master) } EXPORT_SYMBOL_GPL(spi_unregister_master); +int spi_master_suspend(struct spi_master *master) +{ + int ret; + + /* Basically no-ops for non-queued masters */ + if (!master->queued) + return 0; + + ret = spi_stop_queue(master); + if (ret) + dev_err(&master->dev, "queue stop failed\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(spi_master_suspend); + +int spi_master_resume(struct spi_master *master) +{ + int ret; + + if (!master->queued) + return 0; + + ret = spi_start_queue(master); + if (ret) + dev_err(&master->dev, "queue restart failed\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(spi_master_resume); + static int __spi_master_match(struct device *dev, void *data) { struct spi_master *m; diff --git a/drivers/staging/ramster/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c index 1f9c5082b6d5..93ba8e9407aa 100644 --- a/drivers/staging/ramster/xvmalloc.c +++ b/drivers/staging/ramster/xvmalloc.c @@ -56,17 +56,17 @@ static void clear_flag(struct block_header *block, enum blockflags flag) * This is called from xv_malloc/xv_free path, so it * needs to be fast. */ -static void *get_ptr_atomic(struct page *page, u16 offset, enum km_type type) +static void *get_ptr_atomic(struct page *page, u16 offset) { unsigned char *base; - base = kmap_atomic(page, type); + base = kmap_atomic(page); return base + offset; } -static void put_ptr_atomic(void *ptr, enum km_type type) +static void put_ptr_atomic(void *ptr) { - kunmap_atomic(ptr, type); + kunmap_atomic(ptr); } static u32 get_blockprev(struct block_header *block) @@ -202,10 +202,10 @@ static void insert_block(struct xv_pool *pool, struct page *page, u32 offset, if (block->link.next_page) { nextblock = get_ptr_atomic(block->link.next_page, - block->link.next_offset, KM_USER1); + block->link.next_offset); nextblock->link.prev_page = page; nextblock->link.prev_offset = offset; - put_ptr_atomic(nextblock, KM_USER1); + put_ptr_atomic(nextblock); /* If there was a next page then the free bits are set. */ return; } @@ -225,18 +225,18 @@ static void remove_block(struct xv_pool *pool, struct page *page, u32 offset, if (block->link.prev_page) { tmpblock = get_ptr_atomic(block->link.prev_page, - block->link.prev_offset, KM_USER1); + block->link.prev_offset); tmpblock->link.next_page = block->link.next_page; tmpblock->link.next_offset = block->link.next_offset; - put_ptr_atomic(tmpblock, KM_USER1); + put_ptr_atomic(tmpblock); } if (block->link.next_page) { tmpblock = get_ptr_atomic(block->link.next_page, - block->link.next_offset, KM_USER1); + block->link.next_offset); tmpblock->link.prev_page = block->link.prev_page; tmpblock->link.prev_offset = block->link.prev_offset; - put_ptr_atomic(tmpblock, KM_USER1); + put_ptr_atomic(tmpblock); } /* Is this block is at the head of the freelist? */ @@ -249,11 +249,10 @@ static void remove_block(struct xv_pool *pool, struct page *page, u32 offset, if (pool->freelist[slindex].page) { struct block_header *tmpblock; tmpblock = get_ptr_atomic(pool->freelist[slindex].page, - pool->freelist[slindex].offset, - KM_USER1); + pool->freelist[slindex].offset); tmpblock->link.prev_page = NULL; tmpblock->link.prev_offset = 0; - put_ptr_atomic(tmpblock, KM_USER1); + put_ptr_atomic(tmpblock); } else { /* This freelist bucket is empty */ __clear_bit(slindex % BITS_PER_LONG, @@ -284,7 +283,7 @@ static int grow_pool(struct xv_pool *pool, gfp_t flags) stat_inc(&pool->total_pages); spin_lock(&pool->lock); - block = get_ptr_atomic(page, 0, KM_USER0); + block = get_ptr_atomic(page, 0); block->size = PAGE_SIZE - XV_ALIGN; set_flag(block, BLOCK_FREE); @@ -293,7 +292,7 @@ static int grow_pool(struct xv_pool *pool, gfp_t flags) insert_block(pool, page, 0, block); - put_ptr_atomic(block, KM_USER0); + put_ptr_atomic(block); spin_unlock(&pool->lock); return 0; @@ -375,7 +374,7 @@ int xv_malloc(struct xv_pool *pool, u32 size, struct page **page, return -ENOMEM; } - block = get_ptr_atomic(*page, *offset, KM_USER0); + block = get_ptr_atomic(*page, *offset); remove_block(pool, *page, *offset, block, index); @@ -405,7 +404,7 @@ int xv_malloc(struct xv_pool *pool, u32 size, struct page **page, block->size = origsize; clear_flag(block, BLOCK_FREE); - put_ptr_atomic(block, KM_USER0); + put_ptr_atomic(block); spin_unlock(&pool->lock); *offset += XV_ALIGN; @@ -426,7 +425,7 @@ void xv_free(struct xv_pool *pool, struct page *page, u32 offset) spin_lock(&pool->lock); - page_start = get_ptr_atomic(page, 0, KM_USER0); + page_start = get_ptr_atomic(page, 0); block = (struct block_header *)((char *)page_start + offset); /* Catch double free bugs */ @@ -468,7 +467,7 @@ void xv_free(struct xv_pool *pool, struct page *page, u32 offset) /* No used objects in this page. Free it. */ if (block->size == PAGE_SIZE - XV_ALIGN) { - put_ptr_atomic(page_start, KM_USER0); + put_ptr_atomic(page_start); spin_unlock(&pool->lock); __free_page(page); @@ -486,7 +485,7 @@ void xv_free(struct xv_pool *pool, struct page *page, u32 offset) set_blockprev(tmpblock, offset); } - put_ptr_atomic(page_start, KM_USER0); + put_ptr_atomic(page_start); spin_unlock(&pool->lock); } EXPORT_SYMBOL_GPL(xv_free); diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c index 36d53ed9d71a..68b2e053a0e6 100644 --- a/drivers/staging/ramster/zcache-main.c +++ b/drivers/staging/ramster/zcache-main.c @@ -496,13 +496,13 @@ static int zbud_decompress(struct page *page, struct zbud_hdr *zh) } ASSERT_SENTINEL(zh, ZBH); BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size()); - to_va = kmap_atomic(page, KM_USER0); + to_va = kmap_atomic(page); size = zh->size; from_va = zbud_data(zh, size); ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len); BUG_ON(ret != LZO_E_OK); BUG_ON(out_len != PAGE_SIZE); - kunmap_atomic(to_va, KM_USER0); + kunmap_atomic(to_va); out: spin_unlock(&zbpg->lock); return ret; @@ -1109,7 +1109,7 @@ static struct zv_hdr *zv_create(struct zcache_client *cli, uint32_t pool_id, goto out; atomic_inc(&zv_curr_dist_counts[chunks]); atomic_inc(&zv_cumul_dist_counts[chunks]); - zv = kmap_atomic(page, KM_USER0) + offset; + zv = kmap_atomic(page) + offset; zv->index = index; zv->oid = *oid; zv->pool_id = pool_id; @@ -1123,7 +1123,7 @@ static struct zv_hdr *zv_create(struct zcache_client *cli, uint32_t pool_id, spin_unlock(&zcache_rem_op_list_lock); } memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen); - kunmap_atomic(zv, KM_USER0); + kunmap_atomic(zv); out: return zv; } @@ -1145,7 +1145,7 @@ static struct zv_hdr *zv_alloc(struct tmem_pool *pool, &page, &offset, ZCACHE_GFP_MASK); if (unlikely(ret)) goto out; - zv = kmap_atomic(page, KM_USER0) + offset; + zv = kmap_atomic(page) + offset; SET_SENTINEL(zv, ZVH); INIT_LIST_HEAD(&zv->rem_op.list); zv->client_id = LOCAL_CLIENT; @@ -1153,7 +1153,7 @@ static struct zv_hdr *zv_alloc(struct tmem_pool *pool, zv->index = index; zv->oid = *oid; zv->pool_id = pool->pool_id; - kunmap_atomic(zv, KM_USER0); + kunmap_atomic(zv); out: return zv; } @@ -1194,10 +1194,10 @@ static void zv_decompress(struct page *page, struct zv_hdr *zv) ASSERT_SENTINEL(zv, ZVH); size = xv_get_object_size(zv) - sizeof(*zv); BUG_ON(size == 0); - to_va = kmap_atomic(page, KM_USER0); + to_va = kmap_atomic(page); ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv), size, to_va, &clen); - kunmap_atomic(to_va, KM_USER0); + kunmap_atomic(to_va); BUG_ON(ret != LZO_E_OK); BUG_ON(clen != PAGE_SIZE); } @@ -2203,12 +2203,12 @@ static int zcache_compress(struct page *from, void **out_va, size_t *out_len) BUG_ON(!irqs_disabled()); if (unlikely(dmem == NULL || wmem == NULL)) goto out; /* no buffer, so can't compress */ - from_va = kmap_atomic(from, KM_USER0); + from_va = kmap_atomic(from); mb(); ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem); BUG_ON(ret != LZO_E_OK); *out_va = dmem; - kunmap_atomic(from_va, KM_USER0); + kunmap_atomic(from_va); ret = 1; out: return ret; diff --git a/drivers/staging/rtl8192u/ieee80211/cipher.c b/drivers/staging/rtl8192u/ieee80211/cipher.c index 69dcc3176ebc..d47345c4adcf 100644 --- a/drivers/staging/rtl8192u/ieee80211/cipher.c +++ b/drivers/staging/rtl8192u/ieee80211/cipher.c @@ -71,8 +71,8 @@ static int crypt(struct crypto_tfm *tfm, u8 *src_p, *dst_p; int in_place; - scatterwalk_map(&walk_in, 0); - scatterwalk_map(&walk_out, 1); + scatterwalk_map(&walk_in); + scatterwalk_map(&walk_out); src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); in_place = scatterwalk_samebuf(&walk_in, &walk_out, @@ -84,10 +84,10 @@ static int crypt(struct crypto_tfm *tfm, prfn(tfm, dst_p, src_p, crfn, enc, info, in_place); - scatterwalk_done(&walk_in, 0, nbytes); + scatterwalk_done(&walk_in, nbytes); scatterwalk_copychunks(dst_p, &walk_out, bsize, 1); - scatterwalk_done(&walk_out, 1, nbytes); + scatterwalk_done(&walk_out, nbytes); if (!nbytes) return 0; diff --git a/drivers/staging/rtl8192u/ieee80211/digest.c b/drivers/staging/rtl8192u/ieee80211/digest.c index 301ed514ac9e..05e7497fd106 100644 --- a/drivers/staging/rtl8192u/ieee80211/digest.c +++ b/drivers/staging/rtl8192u/ieee80211/digest.c @@ -39,12 +39,12 @@ static void update(struct crypto_tfm *tfm, unsigned int bytes_from_page = min(l, ((unsigned int) (PAGE_SIZE)) - offset); - char *p = crypto_kmap(pg, 0) + offset; + char *p = kmap_atomic(pg) + offset; tfm->__crt_alg->cra_digest.dia_update (crypto_tfm_ctx(tfm), p, bytes_from_page); - crypto_kunmap(p, 0); + kunmap_atomic(p); crypto_yield(tfm); offset = 0; pg++; @@ -75,10 +75,10 @@ static void digest(struct crypto_tfm *tfm, tfm->crt_digest.dit_init(tfm); for (i = 0; i < nsg; i++) { - char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset; + char *p = kmap_atomic(sg[i].page) + sg[i].offset; tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), p, sg[i].length); - crypto_kunmap(p, 0); + kunmap_atomic(p); crypto_yield(tfm); } crypto_digest_final(tfm, out); diff --git a/drivers/staging/rtl8192u/ieee80211/internal.h b/drivers/staging/rtl8192u/ieee80211/internal.h index a7c096eb269f..bebe13ac53b7 100644 --- a/drivers/staging/rtl8192u/ieee80211/internal.h +++ b/drivers/staging/rtl8192u/ieee80211/internal.h @@ -23,23 +23,6 @@ #include <asm/kmap_types.h> -extern enum km_type crypto_km_types[]; - -static inline enum km_type crypto_kmap_type(int out) -{ - return crypto_km_types[(in_softirq() ? 2 : 0) + out]; -} - -static inline void *crypto_kmap(struct page *page, int out) -{ - return kmap_atomic(page, crypto_kmap_type(out)); -} - -static inline void crypto_kunmap(void *vaddr, int out) -{ - kunmap_atomic(vaddr, crypto_kmap_type(out)); -} - static inline void crypto_yield(struct crypto_tfm *tfm) { if (!in_softirq()) diff --git a/drivers/staging/rtl8192u/ieee80211/kmap_types.h b/drivers/staging/rtl8192u/ieee80211/kmap_types.h deleted file mode 100644 index de67bb01b5f5..000000000000 --- a/drivers/staging/rtl8192u/ieee80211/kmap_types.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __KMAP_TYPES_H - -#define __KMAP_TYPES_H - - -enum km_type { - KM_BOUNCE_READ, - KM_SKB_SUNRPC_DATA, - KM_SKB_DATA_SOFTIRQ, - KM_USER0, - KM_USER1, - KM_BH_IRQ, - KM_SOFTIRQ0, - KM_SOFTIRQ1, - KM_TYPE_NR -}; - -#define _ASM_KMAP_TYPES_H - -#endif diff --git a/drivers/staging/rtl8192u/ieee80211/scatterwalk.c b/drivers/staging/rtl8192u/ieee80211/scatterwalk.c index 3543a6145046..8b73f6cefcf9 100644 --- a/drivers/staging/rtl8192u/ieee80211/scatterwalk.c +++ b/drivers/staging/rtl8192u/ieee80211/scatterwalk.c @@ -13,8 +13,6 @@ * any later version. * */ -#include "kmap_types.h" - #include <linux/kernel.h> #include <linux/mm.h> #include <linux/pagemap.h> @@ -23,13 +21,6 @@ #include "internal.h" #include "scatterwalk.h" -enum km_type crypto_km_types[] = { - KM_USER0, - KM_USER1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, -}; - void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) { if (nbytes <= walk->len_this_page && @@ -62,9 +53,9 @@ void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) walk->offset = sg->offset; } -void scatterwalk_map(struct scatter_walk *walk, int out) +void scatterwalk_map(struct scatter_walk *walk) { - walk->data = crypto_kmap(walk->page, out) + walk->offset; + walk->data = kmap_atomic(walk->page) + walk->offset; } static void scatterwalk_pagedone(struct scatter_walk *walk, int out, @@ -103,7 +94,7 @@ void scatterwalk_done(struct scatter_walk *walk, int out, int more) * has been verified as multiple of the block size. */ int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, - size_t nbytes, int out) + size_t nbytes) { if (buf != walk->data) { while (nbytes > walk->len_this_page) { @@ -111,9 +102,9 @@ int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, buf += walk->len_this_page; nbytes -= walk->len_this_page; - crypto_kunmap(walk->data, out); + kunmap_atomic(walk->data); scatterwalk_pagedone(walk, out, 1); - scatterwalk_map(walk, out); + scatterwalk_map(walk); } memcpy_dir(buf, walk->data, nbytes, out); diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index 70734652f724..ed2c800b3a7e 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -455,14 +455,14 @@ static int zbud_decompress(struct page *page, struct zbud_hdr *zh) } ASSERT_SENTINEL(zh, ZBH); BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size()); - to_va = kmap_atomic(page, KM_USER0); + to_va = kmap_atomic(page); size = zh->size; from_va = zbud_data(zh, size); ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size, to_va, &out_len); BUG_ON(ret); BUG_ON(out_len != PAGE_SIZE); - kunmap_atomic(to_va, KM_USER0); + kunmap_atomic(to_va); out: spin_unlock(&zbpg->lock); return ret; @@ -753,10 +753,10 @@ static void zv_decompress(struct page *page, void *handle) zv = zs_map_object(zcache_host.zspool, handle); BUG_ON(zv->size == 0); ASSERT_SENTINEL(zv, ZVH); - to_va = kmap_atomic(page, KM_USER0); + to_va = kmap_atomic(page); ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, (char *)zv + sizeof(*zv), zv->size, to_va, &clen); - kunmap_atomic(to_va, KM_USER0); + kunmap_atomic(to_va); zs_unmap_object(zcache_host.zspool, handle); BUG_ON(ret); BUG_ON(clen != PAGE_SIZE); @@ -1334,13 +1334,13 @@ static int zcache_compress(struct page *from, void **out_va, unsigned *out_len) if (unlikely(dmem == NULL)) goto out; /* no buffer or no compressor so can't compress */ *out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER; - from_va = kmap_atomic(from, KM_USER0); + from_va = kmap_atomic(from); mb(); ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem, out_len); BUG_ON(ret); *out_va = dmem; - kunmap_atomic(from_va, KM_USER0); + kunmap_atomic(from_va); ret = 1; out: return ret; diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 7f138196b3c9..685d612a627b 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -175,9 +175,9 @@ static void handle_zero_page(struct bio_vec *bvec) struct page *page = bvec->bv_page; void *user_mem; - user_mem = kmap_atomic(page, KM_USER0); + user_mem = kmap_atomic(page); memset(user_mem + bvec->bv_offset, 0, bvec->bv_len); - kunmap_atomic(user_mem, KM_USER0); + kunmap_atomic(user_mem); flush_dcache_page(page); } @@ -188,12 +188,12 @@ static void handle_uncompressed_page(struct zram *zram, struct bio_vec *bvec, struct page *page = bvec->bv_page; unsigned char *user_mem, *cmem; - user_mem = kmap_atomic(page, KM_USER0); - cmem = kmap_atomic(zram->table[index].handle, KM_USER1); + user_mem = kmap_atomic(page); + cmem = kmap_atomic(zram->table[index].handle); memcpy(user_mem + bvec->bv_offset, cmem + offset, bvec->bv_len); - kunmap_atomic(cmem, KM_USER1); - kunmap_atomic(user_mem, KM_USER0); + kunmap_atomic(cmem); + kunmap_atomic(user_mem); flush_dcache_page(page); } @@ -242,7 +242,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, } } - user_mem = kmap_atomic(page, KM_USER0); + user_mem = kmap_atomic(page); if (!is_partial_io(bvec)) uncmem = user_mem; clen = PAGE_SIZE; @@ -260,7 +260,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, } zs_unmap_object(zram->mem_pool, zram->table[index].handle); - kunmap_atomic(user_mem, KM_USER0); + kunmap_atomic(user_mem); /* Should NEVER happen. Return bio error if it does. */ if (unlikely(ret != LZO_E_OK)) { @@ -292,7 +292,7 @@ static int zram_read_before_write(struct zram *zram, char *mem, u32 index) /* Page is stored uncompressed since it's incompressible */ if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) { memcpy(mem, cmem, PAGE_SIZE); - kunmap_atomic(cmem, KM_USER0); + kunmap_atomic(cmem); return 0; } @@ -351,7 +351,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, zram_test_flag(zram, index, ZRAM_ZERO)) zram_free_page(zram, index); - user_mem = kmap_atomic(page, KM_USER0); + user_mem = kmap_atomic(page); if (is_partial_io(bvec)) memcpy(uncmem + offset, user_mem + bvec->bv_offset, @@ -360,7 +360,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, uncmem = user_mem; if (page_zero_filled(uncmem)) { - kunmap_atomic(user_mem, KM_USER0); + kunmap_atomic(user_mem); if (is_partial_io(bvec)) kfree(uncmem); zram_stat_inc(&zram->stats.pages_zero); @@ -372,7 +372,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen, zram->compress_workmem); - kunmap_atomic(user_mem, KM_USER0); + kunmap_atomic(user_mem); if (is_partial_io(bvec)) kfree(uncmem); @@ -400,8 +400,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, zram_set_flag(zram, index, ZRAM_UNCOMPRESSED); zram_stat_inc(&zram->stats.pages_expand); handle = page_store; - src = kmap_atomic(page, KM_USER0); - cmem = kmap_atomic(page_store, KM_USER1); + src = kmap_atomic(page); + cmem = kmap_atomic(page_store); goto memstore; } @@ -427,8 +427,8 @@ memstore: memcpy(cmem, src, clen); if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) { - kunmap_atomic(cmem, KM_USER1); - kunmap_atomic(src, KM_USER0); + kunmap_atomic(cmem); + kunmap_atomic(src); } else { zs_unmap_object(zram->mem_pool, handle); } diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 501b27c18145..1c6f700f5faa 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -23,6 +23,7 @@ #include <linux/crypto.h> #include <linux/completion.h> #include <linux/module.h> +#include <linux/idr.h> #include <asm/unaligned.h> #include <scsi/scsi_device.h> #include <scsi/iscsi_proto.h> diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 38cb7ce8469e..1ee33a8c3fab 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -21,6 +21,7 @@ #include <linux/string.h> #include <linux/kthread.h> #include <linux/crypto.h> +#include <linux/idr.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index cd5cd95812bb..929cc9364c8a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2344,7 +2344,7 @@ static void transport_xor_callback(struct se_cmd *cmd) offset = 0; for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { - addr = kmap_atomic(sg_page(sg), KM_USER0); + addr = kmap_atomic(sg_page(sg)); if (!addr) goto out; @@ -2352,7 +2352,7 @@ static void transport_xor_callback(struct se_cmd *cmd) *(addr + sg->offset + i) ^= *(buf + offset + i); offset += sg->length; - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); } out: diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index d8cabc21036d..2b693eefac55 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -146,14 +146,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd) PAGE_SIZE << compound_order(page); } else { BUG_ON(!page); - from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), - KM_SOFTIRQ0); + from = kmap_atomic(page + (mem_off >> PAGE_SHIFT)); page_addr = from; from += mem_off & ~PAGE_MASK; tlen = min(tlen, (size_t)(PAGE_SIZE - (mem_off & ~PAGE_MASK))); memcpy(to, from, tlen); - kunmap_atomic(page_addr, KM_SOFTIRQ0); + kunmap_atomic(page_addr); to += tlen; } @@ -291,14 +290,13 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) tlen = min(mem_len, frame_len); - to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), - KM_SOFTIRQ0); + to = kmap_atomic(page + (mem_off >> PAGE_SHIFT)); page_addr = to; to += mem_off & ~PAGE_MASK; tlen = min(tlen, (size_t)(PAGE_SIZE - (mem_off & ~PAGE_MASK))); memcpy(to, from, tlen); - kunmap_atomic(page_addr, KM_SOFTIRQ0); + kunmap_atomic(page_addr); from += tlen; frame_len -= tlen; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 7cdcb63b21ff..85a5cebe96b3 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -345,7 +345,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) } skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - skb->len <= 1, req->actual); + skb->len <= 1, req->actual, req->actual); page = NULL; if (req->actual < req->length) { /* Last fragment */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6815701cf656..836cfa9a515f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -903,8 +903,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9dab1f51dd43..f0da2c32fbde 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -588,7 +588,7 @@ static int vhost_net_release(struct inode *inode, struct file *f) vhost_net_stop(n, &tx_sock, &rx_sock); vhost_net_flush(n); - vhost_dev_cleanup(&n->dev); + vhost_dev_cleanup(&n->dev, false); if (tx_sock) fput(tx_sock->file); if (rx_sock) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c14c42b95ab8..947f00d8e091 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -222,6 +222,8 @@ static int vhost_worker(void *data) if (work) { __set_current_state(TASK_RUNNING); work->fn(work); + if (need_resched()) + schedule(); } else schedule(); @@ -403,7 +405,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev) if (!memory) return -ENOMEM; - vhost_dev_cleanup(dev); + vhost_dev_cleanup(dev, true); memory->nregions = 0; RCU_INIT_POINTER(dev->memory, memory); @@ -434,8 +436,8 @@ int vhost_zerocopy_signal_used(struct vhost_virtqueue *vq) return j; } -/* Caller should have device mutex */ -void vhost_dev_cleanup(struct vhost_dev *dev) +/* Caller should have device mutex if and only if locked is set */ +void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) { int i; @@ -472,7 +474,8 @@ void vhost_dev_cleanup(struct vhost_dev *dev) dev->log_file = NULL; /* No one will access memory at this point */ kfree(rcu_dereference_protected(dev->memory, - lockdep_is_held(&dev->mutex))); + locked == + lockdep_is_held(&dev->mutex))); RCU_INIT_POINTER(dev->memory, NULL); WARN_ON(!list_empty(&dev->work_list)); if (dev->worker) { @@ -937,9 +940,9 @@ static int set_bit_to_user(int nr, void __user *addr) if (r < 0) return r; BUG_ON(r != 1); - base = kmap_atomic(page, KM_USER0); + base = kmap_atomic(page); set_bit(bit, base); - kunmap_atomic(base, KM_USER0); + kunmap_atomic(base); set_page_dirty_lock(page); put_page(page); return 0; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index a801e2821d03..8dcf4cca6bf2 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -163,7 +163,7 @@ struct vhost_dev { long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs); long vhost_dev_check_owner(struct vhost_dev *); long vhost_dev_reset_owner(struct vhost_dev *); -void vhost_dev_cleanup(struct vhost_dev *); +void vhost_dev_cleanup(struct vhost_dev *, bool locked); long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg); int vhost_vq_access_ok(struct vhost_virtqueue *vq); int vhost_log_access_ok(struct vhost_dev *); diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index ce4fa0831860..9e14ae6cd49c 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -129,9 +129,9 @@ static void do_suspend(void) printk(KERN_DEBUG "suspending xenstore...\n"); xs_suspend(); - err = dpm_suspend_noirq(PMSG_FREEZE); + err = dpm_suspend_end(PMSG_FREEZE); if (err) { - printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err); + printk(KERN_ERR "dpm_suspend_end failed: %d\n", err); goto out_resume; } @@ -149,7 +149,7 @@ static void do_suspend(void) err = stop_machine(xen_suspend, &si, cpumask_of(0)); - dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE); + dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE); if (err) { printk(KERN_ERR "failed to start xen_suspend: %d\n", err); diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 2f213d109c21..b960ff05ea0b 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -365,10 +365,10 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, _debug("extract data"); if (call->count > 0) { page = call->reply3; - buffer = kmap_atomic(page, KM_USER0); + buffer = kmap_atomic(page); ret = afs_extract_data(call, skb, last, buffer, call->count); - kunmap_atomic(buffer, KM_USER0); + kunmap_atomic(buffer); switch (ret) { case 0: break; case -EAGAIN: return 0; @@ -411,9 +411,9 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, if (call->count < PAGE_SIZE) { _debug("clear"); page = call->reply3; - buffer = kmap_atomic(page, KM_USER0); + buffer = kmap_atomic(page); memset(buffer + call->count, 0, PAGE_SIZE - call->count); - kunmap_atomic(buffer, KM_USER0); + kunmap_atomic(buffer); } _leave(" = 0 [done]"); diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 8f4ce2658b7d..298cf8919ec7 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -200,9 +200,9 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) if (PageError(page)) goto error; - buf = kmap_atomic(page, KM_USER0); + buf = kmap_atomic(page); memcpy(devname, buf, size); - kunmap_atomic(buf, KM_USER0); + kunmap_atomic(buf); page_cache_release(page); page = NULL; } @@ -160,7 +160,7 @@ static int aio_setup_ring(struct kioctx *ctx) info->nr = nr_events; /* trusted copy */ - ring = kmap_atomic(info->ring_pages[0], KM_USER0); + ring = kmap_atomic(info->ring_pages[0]); ring->nr = nr_events; /* user copy */ ring->id = ctx->user_id; ring->head = ring->tail = 0; @@ -168,32 +168,32 @@ static int aio_setup_ring(struct kioctx *ctx) ring->compat_features = AIO_RING_COMPAT_FEATURES; ring->incompat_features = AIO_RING_INCOMPAT_FEATURES; ring->header_length = sizeof(struct aio_ring); - kunmap_atomic(ring, KM_USER0); + kunmap_atomic(ring); return 0; } /* aio_ring_event: returns a pointer to the event at the given index from - * kmap_atomic(, km). Release the pointer with put_aio_ring_event(); + * kmap_atomic(). Release the pointer with put_aio_ring_event(); */ #define AIO_EVENTS_PER_PAGE (PAGE_SIZE / sizeof(struct io_event)) #define AIO_EVENTS_FIRST_PAGE ((PAGE_SIZE - sizeof(struct aio_ring)) / sizeof(struct io_event)) #define AIO_EVENTS_OFFSET (AIO_EVENTS_PER_PAGE - AIO_EVENTS_FIRST_PAGE) -#define aio_ring_event(info, nr, km) ({ \ +#define aio_ring_event(info, nr) ({ \ unsigned pos = (nr) + AIO_EVENTS_OFFSET; \ struct io_event *__event; \ __event = kmap_atomic( \ - (info)->ring_pages[pos / AIO_EVENTS_PER_PAGE], km); \ + (info)->ring_pages[pos / AIO_EVENTS_PER_PAGE]); \ __event += pos % AIO_EVENTS_PER_PAGE; \ __event; \ }) -#define put_aio_ring_event(event, km) do { \ +#define put_aio_ring_event(event) do { \ struct io_event *__event = (event); \ (void)__event; \ - kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK), km); \ + kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK)); \ } while(0) static void ctx_rcu_free(struct rcu_head *head) @@ -1019,10 +1019,10 @@ int aio_complete(struct kiocb *iocb, long res, long res2) if (kiocbIsCancelled(iocb)) goto put_rq; - ring = kmap_atomic(info->ring_pages[0], KM_IRQ1); + ring = kmap_atomic(info->ring_pages[0]); tail = info->tail; - event = aio_ring_event(info, tail, KM_IRQ0); + event = aio_ring_event(info, tail); if (++tail >= info->nr) tail = 0; @@ -1043,8 +1043,8 @@ int aio_complete(struct kiocb *iocb, long res, long res2) info->tail = tail; ring->tail = tail; - put_aio_ring_event(event, KM_IRQ0); - kunmap_atomic(ring, KM_IRQ1); + put_aio_ring_event(event); + kunmap_atomic(ring); pr_debug("added to ring %p at [%lu]\n", iocb, tail); @@ -1089,7 +1089,7 @@ static int aio_read_evt(struct kioctx *ioctx, struct io_event *ent) unsigned long head; int ret = 0; - ring = kmap_atomic(info->ring_pages[0], KM_USER0); + ring = kmap_atomic(info->ring_pages[0]); dprintk("in aio_read_evt h%lu t%lu m%lu\n", (unsigned long)ring->head, (unsigned long)ring->tail, (unsigned long)ring->nr); @@ -1101,18 +1101,18 @@ static int aio_read_evt(struct kioctx *ioctx, struct io_event *ent) head = ring->head % info->nr; if (head != ring->tail) { - struct io_event *evp = aio_ring_event(info, head, KM_USER1); + struct io_event *evp = aio_ring_event(info, head); *ent = *evp; head = (head + 1) % info->nr; smp_mb(); /* finish reading the event before updatng the head */ ring->head = head; ret = 1; - put_aio_ring_event(evp, KM_USER1); + put_aio_ring_event(evp); } spin_unlock(&info->ring_lock); out: - kunmap_atomic(ring, KM_USER0); + kunmap_atomic(ring); dprintk("leaving aio_read_evt: %d h%lu t%lu\n", ret, (unsigned long)ring->head, (unsigned long)ring->tail); return ret; diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index c2183f3917cd..e85c04b9f61c 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -357,7 +357,7 @@ static void bio_integrity_generate(struct bio *bio) bix.sector_size = bi->sector_size; bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page, KM_USER0); + void *kaddr = kmap_atomic(bv->bv_page); bix.data_buf = kaddr + bv->bv_offset; bix.data_size = bv->bv_len; bix.prot_buf = prot_buf; @@ -371,7 +371,7 @@ static void bio_integrity_generate(struct bio *bio) total += sectors * bi->tuple_size; BUG_ON(total > bio->bi_integrity->bip_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } } @@ -498,7 +498,7 @@ static int bio_integrity_verify(struct bio *bio) bix.sector_size = bi->sector_size; bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page, KM_USER0); + void *kaddr = kmap_atomic(bv->bv_page); bix.data_buf = kaddr + bv->bv_offset; bix.data_size = bv->bv_len; bix.prot_buf = prot_buf; @@ -507,7 +507,7 @@ static int bio_integrity_verify(struct bio *bio) ret = bi->verify_fn(&bix); if (ret) { - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return ret; } @@ -517,7 +517,7 @@ static int bio_integrity_verify(struct bio *bio) total += sectors * bi->tuple_size; BUG_ON(total > bio->bi_integrity->bip_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } return ret; diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d02c27cd14c7..b805afb37fa8 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -120,10 +120,10 @@ static int check_compressed_csum(struct inode *inode, page = cb->compressed_pages[i]; csum = ~(u32)0; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); csum = btrfs_csum_data(root, kaddr, csum, PAGE_CACHE_SIZE); btrfs_csum_final(csum, (char *)&csum); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (csum != *cb_sum) { printk(KERN_INFO "btrfs csum failed ino %llu " @@ -521,10 +521,10 @@ static noinline int add_ra_bio_pages(struct inode *inode, if (zero_offset) { int zeros; zeros = PAGE_CACHE_SIZE - zero_offset; - userpage = kmap_atomic(page, KM_USER0); + userpage = kmap_atomic(page); memset(userpage + zero_offset, 0, zeros); flush_dcache_page(page); - kunmap_atomic(userpage, KM_USER0); + kunmap_atomic(userpage); } } @@ -993,9 +993,9 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, bytes = min(PAGE_CACHE_SIZE - *pg_offset, PAGE_CACHE_SIZE - buf_offset); bytes = min(bytes, working_bytes); - kaddr = kmap_atomic(page_out, KM_USER0); + kaddr = kmap_atomic(page_out); memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); flush_dcache_page(page_out); *pg_offset += bytes; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index a55fbe6252de..2862454bcdb3 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2546,10 +2546,10 @@ static int __extent_read_full_page(struct extent_io_tree *tree, if (zero_offset) { iosize = PAGE_CACHE_SIZE - zero_offset; - userpage = kmap_atomic(page, KM_USER0); + userpage = kmap_atomic(page); memset(userpage + zero_offset, 0, iosize); flush_dcache_page(page); - kunmap_atomic(userpage, KM_USER0); + kunmap_atomic(userpage); } } while (cur <= end) { @@ -2558,10 +2558,10 @@ static int __extent_read_full_page(struct extent_io_tree *tree, struct extent_state *cached = NULL; iosize = PAGE_CACHE_SIZE - pg_offset; - userpage = kmap_atomic(page, KM_USER0); + userpage = kmap_atomic(page); memset(userpage + pg_offset, 0, iosize); flush_dcache_page(page); - kunmap_atomic(userpage, KM_USER0); + kunmap_atomic(userpage); set_extent_uptodate(tree, cur, cur + iosize - 1, &cached, GFP_NOFS); unlock_extent_cached(tree, cur, cur + iosize - 1, @@ -2607,10 +2607,10 @@ static int __extent_read_full_page(struct extent_io_tree *tree, char *userpage; struct extent_state *cached = NULL; - userpage = kmap_atomic(page, KM_USER0); + userpage = kmap_atomic(page); memset(userpage + pg_offset, 0, iosize); flush_dcache_page(page); - kunmap_atomic(userpage, KM_USER0); + kunmap_atomic(userpage); set_extent_uptodate(tree, cur, cur + iosize - 1, &cached, GFP_NOFS); @@ -2756,10 +2756,10 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, if (page->index == end_index) { char *userpage; - userpage = kmap_atomic(page, KM_USER0); + userpage = kmap_atomic(page); memset(userpage + pg_offset, 0, PAGE_CACHE_SIZE - pg_offset); - kunmap_atomic(userpage, KM_USER0); + kunmap_atomic(userpage); flush_dcache_page(page); } pg_offset = 0; diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index c7fb3a4247d3..078b4fd54500 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -447,13 +447,13 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, sums->bytenr = ordered->start; } - data = kmap_atomic(bvec->bv_page, KM_USER0); + data = kmap_atomic(bvec->bv_page); sector_sum->sum = ~(u32)0; sector_sum->sum = btrfs_csum_data(root, data + bvec->bv_offset, sector_sum->sum, bvec->bv_len); - kunmap_atomic(data, KM_USER0); + kunmap_atomic(data); btrfs_csum_final(sector_sum->sum, (char *)§or_sum->sum); sector_sum->bytenr = disk_bytenr; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 892b34785ccc..3a0b5c1f9d31 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -173,9 +173,9 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, cur_size = min_t(unsigned long, compressed_size, PAGE_CACHE_SIZE); - kaddr = kmap_atomic(cpage, KM_USER0); + kaddr = kmap_atomic(cpage); write_extent_buffer(leaf, kaddr, ptr, cur_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); i++; ptr += cur_size; @@ -187,10 +187,10 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, page = find_get_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT); btrfs_set_file_extent_compression(leaf, ei, 0); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); offset = start & (PAGE_CACHE_SIZE - 1); write_extent_buffer(leaf, kaddr + offset, ptr, size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); page_cache_release(page); } btrfs_mark_buffer_dirty(leaf); @@ -422,10 +422,10 @@ again: * sending it down to disk */ if (offset) { - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } will_compress = 1; } @@ -1873,7 +1873,7 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end, } else { ret = get_state_private(io_tree, start, &private); } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (ret) goto zeroit; @@ -1882,7 +1882,7 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end, if (csum != private) goto zeroit; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); good: return 0; @@ -1894,7 +1894,7 @@ zeroit: (unsigned long long)private); memset(kaddr + offset, 1, end - start + 1); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (private == 0) return 0; return -EIO; @@ -4937,12 +4937,12 @@ static noinline int uncompress_inline(struct btrfs_path *path, ret = btrfs_decompress(compress_type, tmp, page, extent_offset, inline_size, max_size); if (ret) { - char *kaddr = kmap_atomic(page, KM_USER0); + char *kaddr = kmap_atomic(page); unsigned long copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset, max_size - extent_offset); memset(kaddr + pg_offset, 0, copy_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } kfree(tmp); return 0; @@ -5719,11 +5719,11 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) unsigned long flags; local_irq_save(flags); - kaddr = kmap_atomic(page, KM_IRQ0); + kaddr = kmap_atomic(page); csum = btrfs_csum_data(root, kaddr + bvec->bv_offset, csum, bvec->bv_len); btrfs_csum_final(csum, (char *)&csum); - kunmap_atomic(kaddr, KM_IRQ0); + kunmap_atomic(kaddr); local_irq_restore(flags); flush_dcache_page(bvec->bv_page); diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c index a178f5ebea78..743b86fa4fcb 100644 --- a/fs/btrfs/lzo.c +++ b/fs/btrfs/lzo.c @@ -411,9 +411,9 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in, bytes = min_t(unsigned long, destlen, out_len - start_byte); - kaddr = kmap_atomic(dest_page, KM_USER0); + kaddr = kmap_atomic(dest_page); memcpy(kaddr, workspace->buf + start_byte, bytes); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); out: return ret; } diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index abc0fbffa510..390e7102b0ff 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -591,7 +591,7 @@ static int scrub_fixup_check(struct scrub_bio *sbio, int ix) u64 flags = sbio->spag[ix].flags; page = sbio->bio->bi_io_vec[ix].bv_page; - buffer = kmap_atomic(page, KM_USER0); + buffer = kmap_atomic(page); if (flags & BTRFS_EXTENT_FLAG_DATA) { ret = scrub_checksum_data(sbio->sdev, sbio->spag + ix, buffer); @@ -603,7 +603,7 @@ static int scrub_fixup_check(struct scrub_bio *sbio, int ix) } else { WARN_ON(1); } - kunmap_atomic(buffer, KM_USER0); + kunmap_atomic(buffer); return ret; } @@ -792,7 +792,7 @@ static void scrub_checksum(struct btrfs_work *work) } for (i = 0; i < sbio->count; ++i) { page = sbio->bio->bi_io_vec[i].bv_page; - buffer = kmap_atomic(page, KM_USER0); + buffer = kmap_atomic(page); flags = sbio->spag[i].flags; logical = sbio->logical + i * PAGE_SIZE; ret = 0; @@ -807,7 +807,7 @@ static void scrub_checksum(struct btrfs_work *work) } else { WARN_ON(1); } - kunmap_atomic(buffer, KM_USER0); + kunmap_atomic(buffer); if (ret) { ret = scrub_recheck_error(sbio, i); if (!ret) { diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index faccd47c6c46..92c20654cc55 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c @@ -370,9 +370,9 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in, PAGE_CACHE_SIZE - buf_offset); bytes = min(bytes, bytes_left); - kaddr = kmap_atomic(dest_page, KM_USER0); + kaddr = kmap_atomic(dest_page); memcpy(kaddr + pg_offset, workspace->buf + buf_offset, bytes); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); pg_offset += bytes; bytes_left -= bytes; diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c1b254487388..3cc1b251ca08 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -556,6 +556,7 @@ init_cifs_idmap(void) /* instruct request_key() to use this special keyring as a cache for * the results it looks up */ + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; root_cred = cred; diff --git a/fs/exec.c b/fs/exec.c index 95551c6da090..3908544f5d18 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1342,13 +1342,13 @@ int remove_arg_zero(struct linux_binprm *bprm) ret = -EFAULT; goto out; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); for (; offset < PAGE_SIZE && kaddr[offset]; offset++, bprm->p++) ; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); put_arg_page(page); if (offset == PAGE_SIZE) diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index 80405836ba6e..c61e62ac231c 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c @@ -597,7 +597,7 @@ int exofs_make_empty(struct inode *inode, struct inode *parent) goto fail; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); de = (struct exofs_dir_entry *)kaddr; de->name_len = 1; de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1)); @@ -611,7 +611,7 @@ int exofs_make_empty(struct inode *inode, struct inode *parent) de->inode_no = cpu_to_le64(parent->i_ino); memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR)); exofs_set_de_type(de, inode); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); err = exofs_commit_chunk(page, 0, chunk_size); fail: page_cache_release(page); diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index d37df352d324..0f4f5c929257 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -645,7 +645,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent) unlock_page(page); goto fail; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr, 0, chunk_size); de = (struct ext2_dir_entry_2 *)kaddr; de->name_len = 1; @@ -660,7 +660,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent) de->inode = cpu_to_le32(parent->i_ino); memcpy (de->name, "..\0", 4); ext2_set_de_type (de, inode); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); err = ext2_commit_chunk(page, 0, chunk_size); fail: page_cache_release(page); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 5f3368ab0fa9..7df2b5e8fbe1 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -838,10 +838,10 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep, } } if (page) { - void *mapaddr = kmap_atomic(page, KM_USER0); + void *mapaddr = kmap_atomic(page); void *buf = mapaddr + offset; offset += fuse_copy_do(cs, &buf, &count); - kunmap_atomic(mapaddr, KM_USER0); + kunmap_atomic(mapaddr); } else offset += fuse_copy_do(cs, NULL, &count); } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 4a199fd93fbd..a841868bf9ce 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1887,11 +1887,11 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) goto out; - vaddr = kmap_atomic(pages[0], KM_USER0); + vaddr = kmap_atomic(pages[0]); err = fuse_copy_ioctl_iovec(fc, iov_page, vaddr, transferred, in_iovs + out_iovs, (flags & FUSE_IOCTL_COMPAT) != 0); - kunmap_atomic(vaddr, KM_USER0); + kunmap_atomic(vaddr); if (err) goto out; diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 501e5cba09b3..38b7a74a0f91 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -434,12 +434,12 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) if (error) return error; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (dsize > (dibh->b_size - sizeof(struct gfs2_dinode))) dsize = (dibh->b_size - sizeof(struct gfs2_dinode)); memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize); memset(kaddr + dsize, 0, PAGE_CACHE_SIZE - dsize); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); flush_dcache_page(page); brelse(dibh); SetPageUptodate(page); @@ -542,9 +542,9 @@ int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, page = read_cache_page(mapping, index, __gfs2_readpage, NULL); if (IS_ERR(page)) return PTR_ERR(page); - p = kmap_atomic(page, KM_USER0); + p = kmap_atomic(page); memcpy(buf + copied, p + offset, amt); - kunmap_atomic(p, KM_USER0); + kunmap_atomic(p); mark_page_accessed(page); page_cache_release(page); copied += amt; @@ -788,11 +788,11 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode))); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(buf + pos, kaddr + pos, copied); memset(kaddr + pos + copied, 0, len - copied); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (!PageUptodate(page)) SetPageUptodate(page); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 0301be655b12..df7c6e8d0764 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -553,11 +553,11 @@ static void gfs2_check_magic(struct buffer_head *bh) __be32 *ptr; clear_buffer_escaped(bh); - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); ptr = kaddr + bh_offset(bh); if (*ptr == cpu_to_be32(GFS2_MAGIC)) set_buffer_escaped(bh); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh, @@ -594,10 +594,10 @@ static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh, if (buffer_escaped(bd->bd_bh)) { void *kaddr; bh1 = gfs2_log_get_buf(sdp); - kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0); + kaddr = kmap_atomic(bd->bd_bh->b_page); memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh), bh1->b_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); *(__be32 *)bh1->b_data = 0; clear_buffer_escaped(bd->bd_bh); unlock_buffer(bd->bd_bh); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index a45b21b03915..c0f8904f0860 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -720,12 +720,12 @@ get_a_page: gfs2_trans_add_bh(ip->i_gl, bh, 0); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (offset + sizeof(struct gfs2_quota) > PAGE_CACHE_SIZE) nbytes = PAGE_CACHE_SIZE - offset; memcpy(kaddr + offset, ptr, nbytes); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); unlock_page(page); page_cache_release(page); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 59c09f9541b5..0971e9217808 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -129,6 +129,8 @@ static int kjournald(void *arg) setup_timer(&journal->j_commit_timer, commit_timeout, (unsigned long)current); + set_freezable(); + /* Record that the journal thread is running */ journal->j_task = current; wake_up(&journal->j_wait_done_commit); @@ -328,7 +330,7 @@ repeat: new_offset = offset_in_page(jh2bh(jh_in)->b_data); } - mapped_data = kmap_atomic(new_page, KM_USER0); + mapped_data = kmap_atomic(new_page); /* * Check for escaping */ @@ -337,7 +339,7 @@ repeat: need_copy_out = 1; do_escape = 1; } - kunmap_atomic(mapped_data, KM_USER0); + kunmap_atomic(mapped_data); /* * Do we need to do a data copy? @@ -354,9 +356,9 @@ repeat: } jh_in->b_frozen_data = tmp; - mapped_data = kmap_atomic(new_page, KM_USER0); + mapped_data = kmap_atomic(new_page); memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size); - kunmap_atomic(mapped_data, KM_USER0); + kunmap_atomic(mapped_data); new_page = virt_to_page(tmp); new_offset = offset_in_page(tmp); @@ -368,9 +370,9 @@ repeat: * copying, we can finally do so. */ if (do_escape) { - mapped_data = kmap_atomic(new_page, KM_USER0); + mapped_data = kmap_atomic(new_page); *((unsigned int *)(mapped_data + new_offset)) = 0; - kunmap_atomic(mapped_data, KM_USER0); + kunmap_atomic(mapped_data); } set_bh_page(new_bh, new_page, new_offset); diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 7fce94b04bc3..b2a7e5244e39 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -718,9 +718,9 @@ done: "Possible IO failure.\n"); page = jh2bh(jh)->b_page; offset = offset_in_page(jh2bh(jh)->b_data); - source = kmap_atomic(page, KM_USER0); + source = kmap_atomic(page); memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); - kunmap_atomic(source, KM_USER0); + kunmap_atomic(source); } jbd_unlock_bh_state(bh); diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 5069b8475150..c067a8cae63b 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -286,10 +286,10 @@ static __u32 jbd2_checksum_data(__u32 crc32_sum, struct buffer_head *bh) char *addr; __u32 checksum; - addr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page); checksum = crc32_be(crc32_sum, (void *)(addr + offset_in_page(bh->b_data)), bh->b_size); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); return checksum; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index c0a5f9f1b127..839377e3d624 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -139,6 +139,8 @@ static int kjournald2(void *arg) setup_timer(&journal->j_commit_timer, commit_timeout, (unsigned long)current); + set_freezable(); + /* Record that the journal thread is running */ journal->j_task = current; wake_up(&journal->j_wait_done_commit); @@ -345,7 +347,7 @@ repeat: new_offset = offset_in_page(jh2bh(jh_in)->b_data); } - mapped_data = kmap_atomic(new_page, KM_USER0); + mapped_data = kmap_atomic(new_page); /* * Fire data frozen trigger if data already wasn't frozen. Do this * before checking for escaping, as the trigger may modify the magic @@ -364,7 +366,7 @@ repeat: need_copy_out = 1; do_escape = 1; } - kunmap_atomic(mapped_data, KM_USER0); + kunmap_atomic(mapped_data); /* * Do we need to do a data copy? @@ -385,9 +387,9 @@ repeat: } jh_in->b_frozen_data = tmp; - mapped_data = kmap_atomic(new_page, KM_USER0); + mapped_data = kmap_atomic(new_page); memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size); - kunmap_atomic(mapped_data, KM_USER0); + kunmap_atomic(mapped_data); new_page = virt_to_page(tmp); new_offset = offset_in_page(tmp); @@ -406,9 +408,9 @@ repeat: * copying, we can finally do so. */ if (do_escape) { - mapped_data = kmap_atomic(new_page, KM_USER0); + mapped_data = kmap_atomic(new_page); *((unsigned int *)(mapped_data + new_offset)) = 0; - kunmap_atomic(mapped_data, KM_USER0); + kunmap_atomic(mapped_data); } set_bh_page(new_bh, new_page, new_offset); diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 35ae096bed5d..e5aba56e1fd5 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -783,12 +783,12 @@ done: "Possible IO failure.\n"); page = jh2bh(jh)->b_page; offset = offset_in_page(jh2bh(jh)->b_data); - source = kmap_atomic(page, KM_USER0); + source = kmap_atomic(page); /* Fire data frozen trigger just before we copy the data */ jbd2_buffer_frozen_trigger(jh, source + offset, jh->b_triggers); memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); - kunmap_atomic(source, KM_USER0); + kunmap_atomic(source); /* * Now that the frozen data is saved off, we need to store diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 3de7a32cadbe..1b6e21dda286 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -177,17 +177,17 @@ static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry) (filler_t *)logfs_readpage, NULL); if (IS_ERR(page)) return page; - dd = kmap_atomic(page, KM_USER0); + dd = kmap_atomic(page); BUG_ON(dd->namelen == 0); if (name->len != be16_to_cpu(dd->namelen) || memcmp(name->name, dd->name, name->len)) { - kunmap_atomic(dd, KM_USER0); + kunmap_atomic(dd); page_cache_release(page); continue; } - kunmap_atomic(dd, KM_USER0); + kunmap_atomic(dd); return page; } return NULL; @@ -365,9 +365,9 @@ static struct dentry *logfs_lookup(struct inode *dir, struct dentry *dentry, return NULL; } index = page->index; - dd = kmap_atomic(page, KM_USER0); + dd = kmap_atomic(page); ino = be64_to_cpu(dd->ino); - kunmap_atomic(dd, KM_USER0); + kunmap_atomic(dd); page_cache_release(page); inode = logfs_iget(dir->i_sb, ino); @@ -402,12 +402,12 @@ static int logfs_write_dir(struct inode *dir, struct dentry *dentry, if (!page) return -ENOMEM; - dd = kmap_atomic(page, KM_USER0); + dd = kmap_atomic(page); memset(dd, 0, sizeof(*dd)); dd->ino = cpu_to_be64(inode->i_ino); dd->type = logfs_type(inode); logfs_set_name(dd, &dentry->d_name); - kunmap_atomic(dd, KM_USER0); + kunmap_atomic(dd); err = logfs_write_buf(dir, page, WF_LOCK); unlock_page(page); @@ -579,9 +579,9 @@ static int logfs_get_dd(struct inode *dir, struct dentry *dentry, if (IS_ERR(page)) return PTR_ERR(page); *pos = page->index; - map = kmap_atomic(page, KM_USER0); + map = kmap_atomic(page); memcpy(dd, map, sizeof(*dd)); - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page_cache_release(page); return 0; } diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 4153e65b0148..e3ab5e5a904c 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c @@ -517,9 +517,9 @@ static int indirect_write_alias(struct super_block *sb, ino = page->mapping->host->i_ino; logfs_unpack_index(page->index, &bix, &level); - child = kmap_atomic(page, KM_USER0); + child = kmap_atomic(page); val = child[pos]; - kunmap_atomic(child, KM_USER0); + kunmap_atomic(child); err = write_one_alias(sb, ino, bix, level, pos, val); if (err) return err; @@ -673,9 +673,9 @@ static void alloc_indirect_block(struct inode *inode, struct page *page, alloc_data_block(inode, page); block = logfs_block(page); - array = kmap_atomic(page, KM_USER0); + array = kmap_atomic(page); initialize_block_counters(page, block, array, page_is_empty); - kunmap_atomic(array, KM_USER0); + kunmap_atomic(array); } static void block_set_pointer(struct page *page, int index, u64 ptr) @@ -685,10 +685,10 @@ static void block_set_pointer(struct page *page, int index, u64 ptr) u64 oldptr; BUG_ON(!block); - array = kmap_atomic(page, KM_USER0); + array = kmap_atomic(page); oldptr = be64_to_cpu(array[index]); array[index] = cpu_to_be64(ptr); - kunmap_atomic(array, KM_USER0); + kunmap_atomic(array); SetPageUptodate(page); block->full += !!(ptr & LOGFS_FULLY_POPULATED) @@ -701,9 +701,9 @@ static u64 block_get_pointer(struct page *page, int index) __be64 *block; u64 ptr; - block = kmap_atomic(page, KM_USER0); + block = kmap_atomic(page); ptr = be64_to_cpu(block[index]); - kunmap_atomic(block, KM_USER0); + kunmap_atomic(block); return ptr; } @@ -850,7 +850,7 @@ static u64 seek_holedata_loop(struct inode *inode, u64 bix, int data) } slot = get_bits(bix, SUBLEVEL(level)); - rblock = kmap_atomic(page, KM_USER0); + rblock = kmap_atomic(page); while (slot < LOGFS_BLOCK_FACTOR) { if (data && (rblock[slot] != 0)) break; @@ -861,12 +861,12 @@ static u64 seek_holedata_loop(struct inode *inode, u64 bix, int data) bix &= ~(increment - 1); } if (slot >= LOGFS_BLOCK_FACTOR) { - kunmap_atomic(rblock, KM_USER0); + kunmap_atomic(rblock); logfs_put_read_page(page); return bix; } bofs = be64_to_cpu(rblock[slot]); - kunmap_atomic(rblock, KM_USER0); + kunmap_atomic(rblock); logfs_put_read_page(page); if (!bofs) { BUG_ON(data); @@ -1961,9 +1961,9 @@ int logfs_read_inode(struct inode *inode) if (IS_ERR(page)) return PTR_ERR(page); - di = kmap_atomic(page, KM_USER0); + di = kmap_atomic(page); logfs_disk_to_inode(di, inode); - kunmap_atomic(di, KM_USER0); + kunmap_atomic(di); move_page_to_inode(inode, page); page_cache_release(page); return 0; @@ -1982,9 +1982,9 @@ static struct page *inode_to_page(struct inode *inode) if (!page) return NULL; - di = kmap_atomic(page, KM_USER0); + di = kmap_atomic(page); logfs_inode_to_disk(inode, di); - kunmap_atomic(di, KM_USER0); + kunmap_atomic(di); move_inode_to_page(page, inode); return page; } @@ -2041,13 +2041,13 @@ static void logfs_mod_segment_entry(struct super_block *sb, u32 segno, if (write) alloc_indirect_block(inode, page, 0); - se = kmap_atomic(page, KM_USER0); + se = kmap_atomic(page); change_se(se + child_no, arg); if (write) { logfs_set_alias(sb, logfs_block(page), child_no); BUG_ON((int)be32_to_cpu(se[child_no].valid) > super->s_segsize); } - kunmap_atomic(se, KM_USER0); + kunmap_atomic(se); logfs_put_write_page(page); } @@ -2245,10 +2245,10 @@ int logfs_inode_write(struct inode *inode, const void *buf, size_t count, if (!page) return -ENOMEM; - pagebuf = kmap_atomic(page, KM_USER0); + pagebuf = kmap_atomic(page); memcpy(pagebuf, buf, count); flush_dcache_page(page); - kunmap_atomic(pagebuf, KM_USER0); + kunmap_atomic(pagebuf); if (i_size_read(inode) < pos + LOGFS_BLOCKSIZE) i_size_write(inode, pos + LOGFS_BLOCKSIZE); diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index ab798ed1cc88..e28d090c98d6 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c @@ -543,9 +543,9 @@ void move_page_to_btree(struct page *page) BUG_ON(!item); /* mempool empty */ memset(item, 0, sizeof(*item)); - child = kmap_atomic(page, KM_USER0); + child = kmap_atomic(page); item->val = child[pos]; - kunmap_atomic(child, KM_USER0); + kunmap_atomic(child); item->child_no = pos; list_add(&item->list, &block->item_list); } diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 085a9262c692..685b2d981b87 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -335,7 +335,7 @@ int minix_make_empty(struct inode *inode, struct inode *dir) goto fail; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr, 0, PAGE_CACHE_SIZE); if (sbi->s_version == MINIX_V3) { @@ -355,7 +355,7 @@ int minix_make_empty(struct inode *inode, struct inode *dir) de->inode = dir->i_ino; strcpy(de->name, ".."); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize); fail: diff --git a/fs/namei.c b/fs/namei.c index fa96a26d3291..20a4fcf001ec 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3493,9 +3493,9 @@ retry: if (err) goto fail; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(kaddr, symname, len-1); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, page, fsdata); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 31778f74357d..d4f772ebd1ef 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -36,6 +36,7 @@ #include <linux/inet.h> #include <linux/in6.h> #include <linux/slab.h> +#include <linux/idr.h> #include <net/ipv6.h> #include <linux/nfs_xdr.h> #include <linux/sunrpc/bc_xprt.h> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index fd9a872fada0..32aa6917265a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -260,10 +260,10 @@ void nfs_readdir_clear_array(struct page *page) struct nfs_cache_array *array; int i; - array = kmap_atomic(page, KM_USER0); + array = kmap_atomic(page); for (i = 0; i < array->size; i++) kfree(array->array[i].string.name); - kunmap_atomic(array, KM_USER0); + kunmap_atomic(array); } /* @@ -1870,11 +1870,11 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym if (!page) return -ENOMEM; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(kaddr, symname, pathlen); if (pathlen < PAGE_SIZE) memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); if (error != 0) { diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 2c05f1991e1e..a1bbf7780dfc 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -198,6 +198,7 @@ int nfs_idmap_init(void) if (ret < 0) goto failed_put_key; + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; id_resolver_cache = cred; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ec9f6ef6c5dd..caf92d05c3a9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -193,7 +193,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent * when talking to the server, we always send cookie 0 * instead of 1 or 2. */ - start = p = kmap_atomic(*readdir->pages, KM_USER0); + start = p = kmap_atomic(*readdir->pages); if (cookie == 0) { *p++ = xdr_one; /* next */ @@ -221,7 +221,7 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent readdir->pgbase = (char *)p - (char *)start; readdir->count -= readdir->pgbase; - kunmap_atomic(start, KM_USER0); + kunmap_atomic(start); } static int nfs4_wait_clnt_recover(struct nfs_client *clp) diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index c9b342c8b503..dab5c4c6dfaf 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -218,11 +218,11 @@ int nilfs_cpfile_get_checkpoint(struct inode *cpfile, kaddr, 1); mark_buffer_dirty(cp_bh); - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_ncheckpoints, 1); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(header_bh); nilfs_mdt_mark_dirty(cpfile); } @@ -313,7 +313,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, continue; } - kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); + kaddr = kmap_atomic(cp_bh->b_page); cp = nilfs_cpfile_block_get_checkpoint( cpfile, cno, cp_bh, kaddr); nicps = 0; @@ -334,7 +334,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, cpfile, cp_bh, kaddr, nicps); if (count == 0) { /* make hole */ - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(cp_bh); ret = nilfs_cpfile_delete_checkpoint_block( @@ -349,18 +349,18 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, } } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(cp_bh); } if (tnicps > 0) { - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps); mark_buffer_dirty(header_bh); nilfs_mdt_mark_dirty(cpfile); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } brelse(header_bh); @@ -408,7 +408,7 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, continue; /* skip hole */ } - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { if (!nilfs_checkpoint_invalid(cp)) { @@ -418,7 +418,7 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, n++; } } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh); } @@ -451,10 +451,10 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, ret = nilfs_cpfile_get_header_block(cpfile, &bh); if (ret < 0) goto out; - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); curr = le64_to_cpu(header->ch_snapshot_list.ssl_next); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh); if (curr == 0) { ret = 0; @@ -472,7 +472,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, ret = 0; /* No snapshots (started from a hole block) */ goto out; } - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); while (n < nci) { cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr); curr = ~(__u64)0; /* Terminator */ @@ -488,7 +488,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next); if (curr_blkoff != next_blkoff) { - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh); ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0, &bh); @@ -496,12 +496,12 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, WARN_ON(ret == -ENOENT); goto out; } - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); } curr = next; curr_blkoff = next_blkoff; } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh); *cnop = curr; ret = n; @@ -592,24 +592,24 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (ret < 0) goto out_sem; - kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); + kaddr = kmap_atomic(cp_bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); if (nilfs_checkpoint_invalid(cp)) { ret = -ENOENT; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); goto out_cp; } if (nilfs_checkpoint_snapshot(cp)) { ret = 0; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); goto out_cp; } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (ret < 0) goto out_cp; - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); list = &header->ch_snapshot_list; curr_bh = header_bh; @@ -621,13 +621,13 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev); curr = prev; if (curr_blkoff != prev_blkoff) { - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(curr_bh); ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &curr_bh); if (ret < 0) goto out_header; - kaddr = kmap_atomic(curr_bh->b_page, KM_USER0); + kaddr = kmap_atomic(curr_bh->b_page); } curr_blkoff = prev_blkoff; cp = nilfs_cpfile_block_get_checkpoint( @@ -635,7 +635,7 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) list = &cp->cp_snapshot_list; prev = le64_to_cpu(list->ssl_prev); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (prev != 0) { ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0, @@ -647,29 +647,29 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) get_bh(prev_bh); } - kaddr = kmap_atomic(curr_bh->b_page, KM_USER0); + kaddr = kmap_atomic(curr_bh->b_page); list = nilfs_cpfile_block_get_snapshot_list( cpfile, curr, curr_bh, kaddr); list->ssl_prev = cpu_to_le64(cno); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); + kaddr = kmap_atomic(cp_bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr); cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev); nilfs_checkpoint_set_snapshot(cp); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(prev_bh->b_page, KM_USER0); + kaddr = kmap_atomic(prev_bh->b_page); list = nilfs_cpfile_block_get_snapshot_list( cpfile, prev, prev_bh, kaddr); list->ssl_next = cpu_to_le64(cno); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_nsnapshots, 1); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(prev_bh); mark_buffer_dirty(curr_bh); @@ -710,23 +710,23 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno) ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (ret < 0) goto out_sem; - kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); + kaddr = kmap_atomic(cp_bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); if (nilfs_checkpoint_invalid(cp)) { ret = -ENOENT; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); goto out_cp; } if (!nilfs_checkpoint_snapshot(cp)) { ret = 0; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); goto out_cp; } list = &cp->cp_snapshot_list; next = le64_to_cpu(list->ssl_next); prev = le64_to_cpu(list->ssl_prev); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (ret < 0) @@ -750,29 +750,29 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno) get_bh(prev_bh); } - kaddr = kmap_atomic(next_bh->b_page, KM_USER0); + kaddr = kmap_atomic(next_bh->b_page); list = nilfs_cpfile_block_get_snapshot_list( cpfile, next, next_bh, kaddr); list->ssl_prev = cpu_to_le64(prev); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(prev_bh->b_page, KM_USER0); + kaddr = kmap_atomic(prev_bh->b_page); list = nilfs_cpfile_block_get_snapshot_list( cpfile, prev, prev_bh, kaddr); list->ssl_next = cpu_to_le64(next); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); + kaddr = kmap_atomic(cp_bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); cp->cp_snapshot_list.ssl_next = cpu_to_le64(0); cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0); nilfs_checkpoint_clear_snapshot(cp); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); le64_add_cpu(&header->ch_nsnapshots, -1); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(next_bh); mark_buffer_dirty(prev_bh); @@ -829,13 +829,13 @@ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno) ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); if (ret < 0) goto out; - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); if (nilfs_checkpoint_invalid(cp)) ret = -ENOENT; else ret = nilfs_checkpoint_snapshot(cp); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh); out: @@ -912,12 +912,12 @@ int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat) ret = nilfs_cpfile_get_header_block(cpfile, &bh); if (ret < 0) goto out_sem; - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); cpstat->cs_cno = nilfs_mdt_cno(cpfile); cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints); cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh); out_sem: diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index fcc2f869af16..b5c13f3576b9 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -85,13 +85,13 @@ void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req) struct nilfs_dat_entry *entry; void *kaddr; - kaddr = kmap_atomic(req->pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req->pr_entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); entry->de_start = cpu_to_le64(NILFS_CNO_MIN); entry->de_end = cpu_to_le64(NILFS_CNO_MAX); entry->de_blocknr = cpu_to_le64(0); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nilfs_palloc_commit_alloc_entry(dat, req); nilfs_dat_commit_entry(dat, req); @@ -109,13 +109,13 @@ static void nilfs_dat_commit_free(struct inode *dat, struct nilfs_dat_entry *entry; void *kaddr; - kaddr = kmap_atomic(req->pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req->pr_entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); entry->de_start = cpu_to_le64(NILFS_CNO_MIN); entry->de_end = cpu_to_le64(NILFS_CNO_MIN); entry->de_blocknr = cpu_to_le64(0); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nilfs_dat_commit_entry(dat, req); nilfs_palloc_commit_free_entry(dat, req); @@ -136,12 +136,12 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req, struct nilfs_dat_entry *entry; void *kaddr; - kaddr = kmap_atomic(req->pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req->pr_entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat)); entry->de_blocknr = cpu_to_le64(blocknr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nilfs_dat_commit_entry(dat, req); } @@ -160,12 +160,12 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) return ret; } - kaddr = kmap_atomic(req->pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req->pr_entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); start = le64_to_cpu(entry->de_start); blocknr = le64_to_cpu(entry->de_blocknr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (blocknr == 0) { ret = nilfs_palloc_prepare_free_entry(dat, req); @@ -186,7 +186,7 @@ void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req, sector_t blocknr; void *kaddr; - kaddr = kmap_atomic(req->pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req->pr_entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); end = start = le64_to_cpu(entry->de_start); @@ -196,7 +196,7 @@ void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req, } entry->de_end = cpu_to_le64(end); blocknr = le64_to_cpu(entry->de_blocknr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (blocknr == 0) nilfs_dat_commit_free(dat, req); @@ -211,12 +211,12 @@ void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req) sector_t blocknr; void *kaddr; - kaddr = kmap_atomic(req->pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req->pr_entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); start = le64_to_cpu(entry->de_start); blocknr = le64_to_cpu(entry->de_blocknr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (start == nilfs_mdt_cno(dat) && blocknr == 0) nilfs_palloc_abort_free_entry(dat, req); @@ -346,20 +346,20 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) } } - kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); if (unlikely(entry->de_blocknr == cpu_to_le64(0))) { printk(KERN_CRIT "%s: vbn = %llu, [%llu, %llu)\n", __func__, (unsigned long long)vblocknr, (unsigned long long)le64_to_cpu(entry->de_start), (unsigned long long)le64_to_cpu(entry->de_end)); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(entry_bh); return -EINVAL; } WARN_ON(blocknr == 0); entry->de_blocknr = cpu_to_le64(blocknr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(entry_bh); nilfs_mdt_mark_dirty(dat); @@ -409,7 +409,7 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) } } - kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(entry_bh->b_page); entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); blocknr = le64_to_cpu(entry->de_blocknr); if (blocknr == 0) { @@ -419,7 +419,7 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) *blocknrp = blocknr; out: - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(entry_bh); return ret; } @@ -440,7 +440,7 @@ ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, 0, &entry_bh); if (ret < 0) return ret; - kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(entry_bh->b_page); /* last virtual block number in this block */ first = vinfo->vi_vblocknr; do_div(first, entries_per_block); @@ -456,7 +456,7 @@ ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, vinfo->vi_end = le64_to_cpu(entry->de_end); vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(entry_bh); } diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index ca35b3a46d17..df1a7fb238d1 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -602,7 +602,7 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent) unlock_page(page); goto fail; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr, 0, chunk_size); de = (struct nilfs_dir_entry *)kaddr; de->name_len = 1; @@ -617,7 +617,7 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent) de->inode = cpu_to_le64(parent->i_ino); memcpy(de->name, "..\0", 4); nilfs_set_de_type(de, inode); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nilfs_commit_chunk(page, mapping, 0, chunk_size); fail: page_cache_release(page); diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c index 684d76300a80..5a48df79d674 100644 --- a/fs/nilfs2/ifile.c +++ b/fs/nilfs2/ifile.c @@ -122,11 +122,11 @@ int nilfs_ifile_delete_inode(struct inode *ifile, ino_t ino) return ret; } - kaddr = kmap_atomic(req.pr_entry_bh->b_page, KM_USER0); + kaddr = kmap_atomic(req.pr_entry_bh->b_page); raw_inode = nilfs_palloc_block_get_entry(ifile, req.pr_entry_nr, req.pr_entry_bh, kaddr); raw_inode->i_flags = 0; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(req.pr_entry_bh); brelse(req.pr_entry_bh); diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 800e8d78a83b..f9897d09c693 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -58,12 +58,12 @@ nilfs_mdt_insert_new_block(struct inode *inode, unsigned long block, set_buffer_mapped(bh); - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); memset(kaddr + bh_offset(bh), 0, 1 << inode->i_blkbits); if (init_block) init_block(inode, bh, kaddr); flush_dcache_page(bh->b_page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); set_buffer_uptodate(bh); mark_buffer_dirty(bh); diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 65221a04c6f0..3e7b2a0dc0c8 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -119,11 +119,11 @@ void nilfs_copy_buffer(struct buffer_head *dbh, struct buffer_head *sbh) struct page *spage = sbh->b_page, *dpage = dbh->b_page; struct buffer_head *bh; - kaddr0 = kmap_atomic(spage, KM_USER0); - kaddr1 = kmap_atomic(dpage, KM_USER1); + kaddr0 = kmap_atomic(spage); + kaddr1 = kmap_atomic(dpage); memcpy(kaddr1 + bh_offset(dbh), kaddr0 + bh_offset(sbh), sbh->b_size); - kunmap_atomic(kaddr1, KM_USER1); - kunmap_atomic(kaddr0, KM_USER0); + kunmap_atomic(kaddr1); + kunmap_atomic(kaddr0); dbh->b_state = sbh->b_state & NILFS_BUFFER_INHERENT_BITS; dbh->b_blocknr = sbh->b_blocknr; diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index a604ac0331b2..f1626f5011c5 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -493,9 +493,9 @@ static int nilfs_recovery_copy_block(struct the_nilfs *nilfs, if (unlikely(!bh_org)) return -EIO; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(kaddr + bh_offset(bh_org), bh_org->b_data, bh_org->b_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(bh_org); return 0; } diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 850a7c0228fb..dc9a913784ab 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -227,9 +227,9 @@ static void nilfs_segbuf_fill_in_data_crc(struct nilfs_segment_buffer *segbuf, crc = crc32_le(crc, bh->b_data, bh->b_size); } list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) { - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); crc = crc32_le(crc, kaddr + bh_offset(bh), bh->b_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } raw_sum->ss_datasum = cpu_to_le32(crc); } diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 0a0aba617d8a..c5b7653a4391 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c @@ -111,11 +111,11 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, struct nilfs_sufile_header *header; void *kaddr; - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = kaddr + bh_offset(header_bh); le64_add_cpu(&header->sh_ncleansegs, ncleanadd); le64_add_cpu(&header->sh_ndirtysegs, ndirtyadd); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(header_bh); } @@ -319,11 +319,11 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) ret = nilfs_sufile_get_header_block(sufile, &header_bh); if (ret < 0) goto out_sem; - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = kaddr + bh_offset(header_bh); ncleansegs = le64_to_cpu(header->sh_ncleansegs); last_alloc = le64_to_cpu(header->sh_last_alloc); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nsegments = nilfs_sufile_get_nsegments(sufile); maxsegnum = sui->allocmax; @@ -356,7 +356,7 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) &su_bh); if (ret < 0) goto out_header; - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage( sufile, segnum, su_bh, kaddr); @@ -367,14 +367,14 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) continue; /* found a clean segment */ nilfs_segment_usage_set_dirty(su); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = kaddr + bh_offset(header_bh); le64_add_cpu(&header->sh_ncleansegs, -1); le64_add_cpu(&header->sh_ndirtysegs, 1); header->sh_last_alloc = cpu_to_le64(segnum); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); sui->ncleansegs--; mark_buffer_dirty(header_bh); @@ -385,7 +385,7 @@ int nilfs_sufile_alloc(struct inode *sufile, __u64 *segnump) goto out_header; } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(su_bh); } @@ -407,16 +407,16 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum, struct nilfs_segment_usage *su; void *kaddr; - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); if (unlikely(!nilfs_segment_usage_clean(su))) { printk(KERN_WARNING "%s: segment %llu must be clean\n", __func__, (unsigned long long)segnum); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return; } nilfs_segment_usage_set_dirty(su); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nilfs_sufile_mod_counter(header_bh, -1, 1); NILFS_SUI(sufile)->ncleansegs--; @@ -433,11 +433,11 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum, void *kaddr; int clean, dirty; - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); if (su->su_flags == cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY) && su->su_nblocks == cpu_to_le32(0)) { - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return; } clean = nilfs_segment_usage_clean(su); @@ -447,7 +447,7 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum, su->su_lastmod = cpu_to_le64(0); su->su_nblocks = cpu_to_le32(0); su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1); NILFS_SUI(sufile)->ncleansegs -= clean; @@ -464,12 +464,12 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum, void *kaddr; int sudirty; - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); if (nilfs_segment_usage_clean(su)) { printk(KERN_WARNING "%s: segment %llu is already clean\n", __func__, (unsigned long long)segnum); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return; } WARN_ON(nilfs_segment_usage_error(su)); @@ -477,7 +477,7 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum, sudirty = nilfs_segment_usage_dirty(su); nilfs_segment_usage_set_clean(su); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(su_bh); nilfs_sufile_mod_counter(header_bh, 1, sudirty ? (u64)-1 : 0); @@ -525,13 +525,13 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, if (ret < 0) goto out_sem; - kaddr = kmap_atomic(bh->b_page, KM_USER0); + kaddr = kmap_atomic(bh->b_page); su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr); WARN_ON(nilfs_segment_usage_error(su)); if (modtime) su->su_lastmod = cpu_to_le64(modtime); su->su_nblocks = cpu_to_le32(nblocks); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(bh); nilfs_mdt_mark_dirty(sufile); @@ -572,7 +572,7 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) if (ret < 0) goto out_sem; - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = kaddr + bh_offset(header_bh); sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile); sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs); @@ -582,7 +582,7 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) spin_lock(&nilfs->ns_last_segment_lock); sustat->ss_prot_seq = nilfs->ns_prot_seq; spin_unlock(&nilfs->ns_last_segment_lock); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(header_bh); out_sem: @@ -598,15 +598,15 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, void *kaddr; int suclean; - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr); if (nilfs_segment_usage_error(su)) { - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return; } suclean = nilfs_segment_usage_clean(su); nilfs_segment_usage_set_error(su); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (suclean) { nilfs_sufile_mod_counter(header_bh, -1, 0); @@ -675,7 +675,7 @@ static int nilfs_sufile_truncate_range(struct inode *sufile, /* hole */ continue; } - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage( sufile, segnum, su_bh, kaddr); su2 = su; @@ -684,7 +684,7 @@ static int nilfs_sufile_truncate_range(struct inode *sufile, ~(1UL << NILFS_SEGMENT_USAGE_ERROR)) || nilfs_segment_is_active(nilfs, segnum + j)) { ret = -EBUSY; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(su_bh); goto out_header; } @@ -696,7 +696,7 @@ static int nilfs_sufile_truncate_range(struct inode *sufile, nc++; } } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (nc > 0) { mark_buffer_dirty(su_bh); ncleaned += nc; @@ -772,10 +772,10 @@ int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs) sui->ncleansegs -= nsegs - newnsegs; } - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = kaddr + bh_offset(header_bh); header->sh_ncleansegs = cpu_to_le64(sui->ncleansegs); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); mark_buffer_dirty(header_bh); nilfs_mdt_mark_dirty(sufile); @@ -840,7 +840,7 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, continue; } - kaddr = kmap_atomic(su_bh->b_page, KM_USER0); + kaddr = kmap_atomic(su_bh->b_page); su = nilfs_sufile_block_get_segment_usage( sufile, segnum, su_bh, kaddr); for (j = 0; j < n; @@ -853,7 +853,7 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, si->sui_flags |= (1UL << NILFS_SEGMENT_USAGE_ACTIVE); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(su_bh); } ret = nsegs; @@ -902,10 +902,10 @@ int nilfs_sufile_read(struct super_block *sb, size_t susize, goto failed; sui = NILFS_SUI(sufile); - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + kaddr = kmap_atomic(header_bh->b_page); header = kaddr + bh_offset(header_bh); sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); brelse(header_bh); sui->allocmax = nilfs_sufile_get_nsegments(sufile) - 1; diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 0b1e885b8cf8..fa9c05f97af4 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -94,11 +94,11 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) if (file_ofs < init_size) ofs = init_size - file_ofs; local_irq_save(flags); - kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); + kaddr = kmap_atomic(page); memset(kaddr + bh_offset(bh) + ofs, 0, bh->b_size - ofs); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); + kunmap_atomic(kaddr); local_irq_restore(flags); } } else { @@ -147,11 +147,11 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) /* Should have been verified before we got here... */ BUG_ON(!recs); local_irq_save(flags); - kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); + kaddr = kmap_atomic(page); for (i = 0; i < recs; i++) post_read_mst_fixup((NTFS_RECORD*)(kaddr + i * rec_size), rec_size); - kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); + kunmap_atomic(kaddr); local_irq_restore(flags); flush_dcache_page(page); if (likely(page_uptodate && !PageError(page))) @@ -504,7 +504,7 @@ retry_readpage: /* Race with shrinking truncate. */ attr_len = i_size; } - addr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page); /* Copy the data to the page. */ memcpy(addr, (u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), @@ -512,7 +512,7 @@ retry_readpage: /* Zero the remainder of the page. */ memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); flush_dcache_page(page); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); put_unm_err_out: ntfs_attr_put_search_ctx(ctx); unm_err_out: @@ -746,14 +746,14 @@ lock_retry_remap: unsigned long *bpos, *bend; /* Check if the buffer is zero. */ - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); bpos = (unsigned long *)(kaddr + bh_offset(bh)); bend = (unsigned long *)((u8*)bpos + blocksize); do { if (unlikely(*bpos)) break; } while (likely(++bpos < bend)); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (bpos == bend) { /* * Buffer is zero and sparse, no need to write @@ -1495,14 +1495,14 @@ retry_writepage: /* Shrinking cannot fail. */ BUG_ON(err); } - addr = kmap_atomic(page, KM_USER0); + addr = kmap_atomic(page); /* Copy the data from the page to the mft record. */ memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), addr, attr_len); /* Zero out of bounds area in the page cache page. */ memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); flush_dcache_page(page); flush_dcache_mft_record_page(ctx->ntfs_ino); /* We are done with the page. */ diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index e0281992ddc3..a27e3fecefaf 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1656,12 +1656,12 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) attr_size = le32_to_cpu(a->data.resident.value_length); BUG_ON(attr_size != data_size); if (page && !PageUptodate(page)) { - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(kaddr, (u8*)a + le16_to_cpu(a->data.resident.value_offset), attr_size); memset(kaddr + attr_size, 0, PAGE_CACHE_SIZE - attr_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); flush_dcache_page(page); SetPageUptodate(page); } @@ -1806,9 +1806,9 @@ undo_err_out: sizeof(a->data.resident.reserved)); /* Copy the data from the page back to the attribute value. */ if (page) { - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy((u8*)a + mp_ofs, kaddr, attr_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } /* Setup the allocated size in the ntfs inode in case it changed. */ write_lock_irqsave(&ni->size_lock, flags); @@ -2540,10 +2540,10 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) size = PAGE_CACHE_SIZE; if (idx == end) size = end_ofs; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr + start_ofs, val, size - start_ofs); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); set_page_dirty(page); page_cache_release(page); balance_dirty_pages_ratelimited(mapping); @@ -2561,10 +2561,10 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) "page (index 0x%lx).", idx); return -ENOMEM; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr, val, PAGE_CACHE_SIZE); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); /* * If the page has buffers, mark them uptodate since buffer * state and not page state is definitive in 2.6 kernels. @@ -2598,10 +2598,10 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) "(error, index 0x%lx).", idx); return PTR_ERR(page); } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr, val, end_ofs); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); set_page_dirty(page); page_cache_release(page); balance_dirty_pages_ratelimited(mapping); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index c587e2d27183..8639169221c7 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -704,7 +704,7 @@ map_buffer_cached: u8 *kaddr; unsigned pofs; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (bh_pos < pos) { pofs = bh_pos & ~PAGE_CACHE_MASK; memset(kaddr + pofs, 0, pos - bh_pos); @@ -713,7 +713,7 @@ map_buffer_cached: pofs = end & ~PAGE_CACHE_MASK; memset(kaddr + pofs, 0, bh_end - end); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); flush_dcache_page(page); } continue; @@ -1287,9 +1287,9 @@ static inline size_t ntfs_copy_from_user(struct page **pages, len = PAGE_CACHE_SIZE - ofs; if (len > bytes) len = bytes; - addr = kmap_atomic(*pages, KM_USER0); + addr = kmap_atomic(*pages); left = __copy_from_user_inatomic(addr + ofs, buf, len); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); if (unlikely(left)) { /* Do it the slow way. */ addr = kmap(*pages); @@ -1401,10 +1401,10 @@ static inline size_t ntfs_copy_from_user_iovec(struct page **pages, len = PAGE_CACHE_SIZE - ofs; if (len > bytes) len = bytes; - addr = kmap_atomic(*pages, KM_USER0); + addr = kmap_atomic(*pages); copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs, *iov, *iov_ofs, len); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); if (unlikely(copied != len)) { /* Do it the slow way. */ addr = kmap(*pages); @@ -1691,7 +1691,7 @@ static int ntfs_commit_pages_after_write(struct page **pages, BUG_ON(end > le32_to_cpu(a->length) - le16_to_cpu(a->data.resident.value_offset)); kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); /* Copy the received data from the page to the mft record. */ memcpy(kattr + pos, kaddr + pos, bytes); /* Update the attribute length if necessary. */ @@ -1713,7 +1713,7 @@ static int ntfs_commit_pages_after_write(struct page **pages, flush_dcache_page(page); SetPageUptodate(page); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); /* Update initialized_size/i_size if necessary. */ read_lock_irqsave(&ni->size_lock, flags); initialized_size = ni->initialized_size; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index f907611cca73..28d4e6ab6634 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2473,7 +2473,7 @@ static s64 get_nr_free_clusters(ntfs_volume *vol) nr_free -= PAGE_CACHE_SIZE * 8; continue; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); /* * Subtract the number of set bits. If this * is the last page and it is partial we don't really care as @@ -2483,7 +2483,7 @@ static s64 get_nr_free_clusters(ntfs_volume *vol) */ nr_free -= bitmap_weight(kaddr, PAGE_CACHE_SIZE * BITS_PER_BYTE); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); page_cache_release(page); } ntfs_debug("Finished reading $Bitmap, last index = 0x%lx.", index - 1); @@ -2544,7 +2544,7 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol, nr_free -= PAGE_CACHE_SIZE * 8; continue; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); /* * Subtract the number of set bits. If this * is the last page and it is partial we don't really care as @@ -2554,7 +2554,7 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol, */ nr_free -= bitmap_weight(kaddr, PAGE_CACHE_SIZE * BITS_PER_BYTE); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); page_cache_release(page); } ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx.", diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 78b68af3b0e3..657743254eb9 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -102,7 +102,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, * copy, the data is still good. */ if (buffer_jbd(buffer_cache_bh) && ocfs2_inode_is_new(inode)) { - kaddr = kmap_atomic(bh_result->b_page, KM_USER0); + kaddr = kmap_atomic(bh_result->b_page); if (!kaddr) { mlog(ML_ERROR, "couldn't kmap!\n"); goto bail; @@ -110,7 +110,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock, memcpy(kaddr + (bh_result->b_size * iblock), buffer_cache_bh->b_data, bh_result->b_size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); set_buffer_uptodate(bh_result); } brelse(buffer_cache_bh); @@ -236,13 +236,13 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, return -EROFS; } - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (size) memcpy(kaddr, di->id2.i_data.id_data, size); /* Clear the remaining part of the page */ memset(kaddr + size, 0, PAGE_CACHE_SIZE - size); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); SetPageUptodate(page); @@ -689,7 +689,7 @@ static void ocfs2_clear_page_regions(struct page *page, ocfs2_figure_cluster_boundaries(osb, cpos, &cluster_start, &cluster_end); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (from || to) { if (from > cluster_start) @@ -700,7 +700,7 @@ static void ocfs2_clear_page_regions(struct page *page, memset(kaddr + cluster_start, 0, cluster_end - cluster_start); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } /* @@ -1981,9 +1981,9 @@ static void ocfs2_write_end_inline(struct inode *inode, loff_t pos, } } - kaddr = kmap_atomic(wc->w_target_page, KM_USER0); + kaddr = kmap_atomic(wc->w_target_page); memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); trace_ocfs2_write_end_inline( (unsigned long long)OCFS2_I(inode)->ip_blkno, diff --git a/fs/pipe.c b/fs/pipe.c index a932ced92a16..fe0502f9beb2 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -230,7 +230,7 @@ void *generic_pipe_buf_map(struct pipe_inode_info *pipe, { if (atomic) { buf->flags |= PIPE_BUF_FLAG_ATOMIC; - return kmap_atomic(buf->page, KM_USER0); + return kmap_atomic(buf->page); } return kmap(buf->page); @@ -251,7 +251,7 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe, { if (buf->flags & PIPE_BUF_FLAG_ATOMIC) { buf->flags &= ~PIPE_BUF_FLAG_ATOMIC; - kunmap_atomic(map_data, KM_USER0); + kunmap_atomic(map_data); } else kunmap(buf->page); } @@ -565,14 +565,14 @@ redo1: iov_fault_in_pages_read(iov, chars); redo2: if (atomic) - src = kmap_atomic(page, KM_USER0); + src = kmap_atomic(page); else src = kmap(page); error = pipe_iov_copy_from_user(src, iov, chars, atomic); if (atomic) - kunmap_atomic(src, KM_USER0); + kunmap_atomic(src); else kunmap(page); diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index a6b62173d4c3..67bbf6e4e197 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -6,7 +6,9 @@ #include <linux/poll.h> #include <linux/proc_fs.h> #include <linux/security.h> +#include <linux/sched.h> #include <linux/namei.h> +#include <linux/mm.h> #include "internal.h" static const struct dentry_operations proc_sys_dentry_operations; diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 46741970371b..8b4f12b33f57 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -71,6 +71,7 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/security.h> +#include <linux/sched.h> #include <linux/kmod.h> #include <linux/namei.h> #include <linux/capability.h> diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 313d39d639eb..77df82f9e70a 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -1284,12 +1284,12 @@ int reiserfs_delete_item(struct reiserfs_transaction_handle *th, ** -clm */ - data = kmap_atomic(un_bh->b_page, KM_USER0); + data = kmap_atomic(un_bh->b_page); off = ((le_ih_k_offset(&s_ih) - 1) & (PAGE_CACHE_SIZE - 1)); memcpy(data + off, B_I_PITEM(PATH_PLAST_BUFFER(path), &s_ih), ret_value); - kunmap_atomic(data, KM_USER0); + kunmap_atomic(data); } /* Perform balancing after all resources have been collected at once. */ do_balance(&s_del_balance, NULL, NULL, M_DELETE); diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index d7f6e51bef2a..8f546bd473b8 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -128,9 +128,9 @@ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, if (up_to_date_bh) { unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1); - char *kaddr = kmap_atomic(up_to_date_bh->b_page, KM_USER0); + char *kaddr = kmap_atomic(up_to_date_bh->b_page); memset(kaddr + pgoff, 0, blk_size - total_tail); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } REISERFS_I(inode)->i_first_direct_byte = U32_MAX; diff --git a/fs/splice.c b/fs/splice.c index 1ec0493266b3..f16402ed915c 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -737,15 +737,12 @@ int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, goto out; if (buf->page != page) { - /* - * Careful, ->map() uses KM_USER0! - */ char *src = buf->ops->map(pipe, buf, 1); - char *dst = kmap_atomic(page, KM_USER1); + char *dst = kmap_atomic(page); memcpy(dst + offset, src + buf->offset, this_len); flush_dcache_page(page); - kunmap_atomic(dst, KM_USER1); + kunmap_atomic(dst); buf->ops->unmap(pipe, buf, src); } ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len, diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index 38bb1c640559..8ca62c28fe12 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c @@ -464,10 +464,10 @@ static int squashfs_readpage(struct file *file, struct page *page) if (PageUptodate(push_page)) goto skip_page; - pageaddr = kmap_atomic(push_page, KM_USER0); + pageaddr = kmap_atomic(push_page); squashfs_copy_data(pageaddr, buffer, offset, avail); memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); - kunmap_atomic(pageaddr, KM_USER0); + kunmap_atomic(pageaddr); flush_dcache_page(push_page); SetPageUptodate(push_page); skip_page: @@ -484,9 +484,9 @@ skip_page: error_out: SetPageError(page); out: - pageaddr = kmap_atomic(page, KM_USER0); + pageaddr = kmap_atomic(page); memset(pageaddr, 0, PAGE_CACHE_SIZE); - kunmap_atomic(pageaddr, KM_USER0); + kunmap_atomic(pageaddr); flush_dcache_page(page); if (!PageError(page)) SetPageUptodate(page); diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index 1191817264cc..12806dffb345 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c @@ -90,14 +90,14 @@ static int squashfs_symlink_readpage(struct file *file, struct page *page) goto error_out; } - pageaddr = kmap_atomic(page, KM_USER0); + pageaddr = kmap_atomic(page); copied = squashfs_copy_data(pageaddr + bytes, entry, offset, length - bytes); if (copied == length - bytes) memset(pageaddr + length, 0, PAGE_CACHE_SIZE - length); else block = entry->next_index; - kunmap_atomic(pageaddr, KM_USER0); + kunmap_atomic(pageaddr); squashfs_cache_put(entry); } diff --git a/fs/super.c b/fs/super.c index 6277ec6cb60a..d90e900a8a0e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -32,6 +32,7 @@ #include <linux/backing-dev.h> #include <linux/rculist_bl.h> #include <linux/cleancache.h> +#include <linux/fsnotify.h> #include "internal.h" diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index f9c234bf33d3..5c8f6dc1d28b 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1042,10 +1042,10 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc) * the page size, the remaining memory is zeroed when mapped, and * writes to that region are not written out to the file." */ - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memset(kaddr + len, 0, PAGE_CACHE_SIZE - len); flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (i_size > synced_i_size) { err = inode->i_sb->s_op->write_inode(inode, NULL); diff --git a/fs/udf/file.c b/fs/udf/file.c index d567b8448dfc..7f3f7ba3df6e 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -87,10 +87,10 @@ static int udf_adinicb_write_end(struct file *file, char *kaddr; struct udf_inode_info *iinfo = UDF_I(inode); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset, kaddr + offset, copied); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return simple_write_end(file, mapping, pos, len, copied, page, fsdata); } diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index 4fd95a323beb..3744d2a642df 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -25,28 +25,6 @@ #include <linux/scatterlist.h> #include <linux/sched.h> -static inline enum km_type crypto_kmap_type(int out) -{ - enum km_type type; - - if (in_softirq()) - type = out * (KM_SOFTIRQ1 - KM_SOFTIRQ0) + KM_SOFTIRQ0; - else - type = out * (KM_USER1 - KM_USER0) + KM_USER0; - - return type; -} - -static inline void *crypto_kmap(struct page *page, int out) -{ - return kmap_atomic(page, crypto_kmap_type(out)); -} - -static inline void crypto_kunmap(void *vaddr, int out) -{ - kunmap_atomic(vaddr, crypto_kmap_type(out)); -} - static inline void crypto_yield(u32 flags) { if (flags & CRYPTO_TFM_REQ_MAY_SLEEP) @@ -121,15 +99,15 @@ static inline struct page *scatterwalk_page(struct scatter_walk *walk) return sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); } -static inline void scatterwalk_unmap(void *vaddr, int out) +static inline void scatterwalk_unmap(void *vaddr) { - crypto_kunmap(vaddr, out); + kunmap_atomic(vaddr); } void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); -void *scatterwalk_map(struct scatter_walk *walk, int out); +void *scatterwalk_map(struct scatter_walk *walk); void scatterwalk_done(struct scatter_walk *walk, int out, int more); void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h index 572f637299c9..3672f40f3455 100644 --- a/include/linux/amba/pl022.h +++ b/include/linux/amba/pl022.h @@ -241,6 +241,8 @@ struct dma_chan; * @autosuspend_delay: delay in ms following transfer completion before the * runtime power management system suspends the device. A setting of 0 * indicates no delay and the device will be suspended immediately. + * @rt: indicates the controller should run the message pump with realtime + * priority to minimise the transfer latency on the bus. */ struct pl022_ssp_controller { u16 bus_id; @@ -250,6 +252,7 @@ struct pl022_ssp_controller { void *dma_rx_param; void *dma_tx_param; int autosuspend_delay; + bool rt; }; /** diff --git a/include/linux/bio.h b/include/linux/bio.h index 129a9c097958..de5422a57511 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -101,10 +101,10 @@ static inline int bio_has_allocated_vec(struct bio *bio) * I/O completely on that queue (see ide-dma for example) */ #define __bio_kmap_atomic(bio, idx, kmtype) \ - (kmap_atomic(bio_iovec_idx((bio), (idx))->bv_page, kmtype) + \ + (kmap_atomic(bio_iovec_idx((bio), (idx))->bv_page) + \ bio_iovec_idx((bio), (idx))->bv_offset) -#define __bio_kunmap_atomic(addr, kmtype) kunmap_atomic(addr, kmtype) +#define __bio_kunmap_atomic(addr, kmtype) kunmap_atomic(addr) /* * merge helpers etc @@ -317,7 +317,7 @@ static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags) * balancing is a lot nicer this way */ local_irq_save(*flags); - addr = (unsigned long) kmap_atomic(bvec->bv_page, KM_BIO_SRC_IRQ); + addr = (unsigned long) kmap_atomic(bvec->bv_page); BUG_ON(addr & ~PAGE_MASK); @@ -328,7 +328,7 @@ static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) { unsigned long ptr = (unsigned long) buffer & PAGE_MASK; - kunmap_atomic((void *) ptr, KM_BIO_SRC_IRQ); + kunmap_atomic((void *) ptr); local_irq_restore(*flags); } diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 8a94217b298e..48ce5479386c 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -75,6 +75,11 @@ */ #define CRYPTO_ALG_INSTANCE 0x00000800 +/* Set this bit if the algorithm provided is hardware accelerated but + * not available to userspace via instruction set or so. + */ +#define CRYPTO_ALG_KERN_DRIVER_ONLY 0x00001000 + /* * Transform masks and values (for crt_flags). */ @@ -309,6 +314,8 @@ struct crypto_alg { */ int crypto_register_alg(struct crypto_alg *alg); int crypto_unregister_alg(struct crypto_alg *alg); +int crypto_register_algs(struct crypto_alg *algs, int count); +int crypto_unregister_algs(struct crypto_alg *algs, int count); /* * Algorithm query interface. diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index 98ce8124b1cc..281c72a3b9d5 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -44,6 +44,14 @@ struct devfreq_dev_status { void *private_data; }; +/* + * The resulting frequency should be at most this. (this bound is the + * least upper bound; thus, the resulting freq should be lower or same) + * If the flag is not set, the resulting frequency should be at most the + * bound (greatest lower bound) + */ +#define DEVFREQ_FLAG_LEAST_UPPER_BOUND 0x1 + /** * struct devfreq_dev_profile - Devfreq's user device profile * @initial_freq The operating frequency when devfreq_add_device() is @@ -54,6 +62,8 @@ struct devfreq_dev_status { * higher than any operable frequency, set maximum. * Before returning, target function should set * freq at the current frequency. + * The "flags" parameter's possible values are + * explained above with "DEVFREQ_FLAG_*" macros. * @get_dev_status The device should provide the current performance * status to devfreq, which is used by governors. * @exit An optional callback that is called when devfreq @@ -66,7 +76,7 @@ struct devfreq_dev_profile { unsigned long initial_freq; unsigned int polling_ms; - int (*target)(struct device *dev, unsigned long *freq); + int (*target)(struct device *dev, unsigned long *freq, u32 flags); int (*get_dev_status)(struct device *dev, struct devfreq_dev_status *stat); void (*exit)(struct device *dev); @@ -124,6 +134,8 @@ struct devfreq_governor { * touch this. * @being_removed a flag to mark that this object is being removed in * order to prevent trying to remove the object multiple times. + * @min_freq Limit minimum frequency requested by user (0: none) + * @max_freq Limit maximum frequency requested by user (0: none) * * This structure stores the devfreq information for a give device. * @@ -149,6 +161,9 @@ struct devfreq { void *data; /* private data for governors */ bool being_removed; + + unsigned long min_freq; + unsigned long max_freq; }; #if defined(CONFIG_PM_DEVFREQ) @@ -160,7 +175,7 @@ extern int devfreq_remove_device(struct devfreq *devfreq); /* Helper functions for devfreq user device driver with OPP. */ extern struct opp *devfreq_recommended_opp(struct device *dev, - unsigned long *freq); + unsigned long *freq, u32 flags); extern int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq); extern int devfreq_unregister_opp_notifier(struct device *dev, @@ -200,18 +215,18 @@ struct devfreq_simple_ondemand_data { static struct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, struct devfreq_governor *governor, - void *data); + void *data) { return NULL; } -static int devfreq_remove_device(struct devfreq *devfreq); +static int devfreq_remove_device(struct devfreq *devfreq) { return 0; } static struct opp *devfreq_recommended_opp(struct device *dev, - unsigned long *freq) + unsigned long *freq, u32 flags) { return -EINVAL; } diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 3a93f73a8acc..6549ed75e0a7 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -55,12 +55,12 @@ static inline void kunmap(struct page *page) { } -static inline void *__kmap_atomic(struct page *page) +static inline void *kmap_atomic(struct page *page) { pagefault_disable(); return page_address(page); } -#define kmap_atomic_prot(page, prot) __kmap_atomic(page) +#define kmap_atomic_prot(page, prot) kmap_atomic(page) static inline void __kunmap_atomic(void *addr) { @@ -109,27 +109,62 @@ static inline void kmap_atomic_idx_pop(void) #endif /* - * Make both: kmap_atomic(page, idx) and kmap_atomic(page) work. + * NOTE: + * kmap_atomic() and kunmap_atomic() with two arguments are deprecated. + * We only keep them for backward compatibility, any usage of them + * are now warned. */ -#define kmap_atomic(page, args...) __kmap_atomic(page) + +#define PASTE(a, b) a ## b +#define PASTE2(a, b) PASTE(a, b) + +#define NARG_(_2, _1, n, ...) n +#define NARG(...) NARG_(__VA_ARGS__, 2, 1, :) + +static inline void __deprecated *kmap_atomic_deprecated(struct page *page, + enum km_type km) +{ + return kmap_atomic(page); +} + +#define kmap_atomic1(...) kmap_atomic(__VA_ARGS__) +#define kmap_atomic2(...) kmap_atomic_deprecated(__VA_ARGS__) +#define kmap_atomic(...) PASTE2(kmap_atomic, NARG(__VA_ARGS__)(__VA_ARGS__)) + +static inline void __deprecated __kunmap_atomic_deprecated(void *addr, + enum km_type km) +{ + __kunmap_atomic(addr); +} /* * Prevent people trying to call kunmap_atomic() as if it were kunmap() * kunmap_atomic() should get the return value of kmap_atomic, not the page. */ -#define kunmap_atomic(addr, args...) \ -do { \ - BUILD_BUG_ON(__same_type((addr), struct page *)); \ - __kunmap_atomic(addr); \ +#define kunmap_atomic_deprecated(addr, km) \ +do { \ + BUILD_BUG_ON(__same_type((addr), struct page *)); \ + __kunmap_atomic_deprecated(addr, km); \ } while (0) +#define kunmap_atomic_withcheck(addr) \ +do { \ + BUILD_BUG_ON(__same_type((addr), struct page *)); \ + __kunmap_atomic(addr); \ +} while (0) + +#define kunmap_atomic1(...) kunmap_atomic_withcheck(__VA_ARGS__) +#define kunmap_atomic2(...) kunmap_atomic_deprecated(__VA_ARGS__) +#define kunmap_atomic(...) PASTE2(kunmap_atomic, NARG(__VA_ARGS__)(__VA_ARGS__)) +/**** End of C pre-processor tricks for deprecated macros ****/ + /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ #ifndef clear_user_highpage static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { - void *addr = kmap_atomic(page, KM_USER0); + void *addr = kmap_atomic(page); clear_user_page(addr, vaddr, page); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); } #endif @@ -180,16 +215,16 @@ alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma, static inline void clear_highpage(struct page *page) { - void *kaddr = kmap_atomic(page, KM_USER0); + void *kaddr = kmap_atomic(page); clear_page(kaddr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } static inline void zero_user_segments(struct page *page, unsigned start1, unsigned end1, unsigned start2, unsigned end2) { - void *kaddr = kmap_atomic(page, KM_USER0); + void *kaddr = kmap_atomic(page); BUG_ON(end1 > PAGE_SIZE || end2 > PAGE_SIZE); @@ -199,7 +234,7 @@ static inline void zero_user_segments(struct page *page, if (end2 > start2) memset(kaddr + start2, 0, end2 - start2); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); flush_dcache_page(page); } @@ -228,11 +263,11 @@ static inline void copy_user_highpage(struct page *to, struct page *from, { char *vfrom, *vto; - vfrom = kmap_atomic(from, KM_USER0); - vto = kmap_atomic(to, KM_USER1); + vfrom = kmap_atomic(from); + vto = kmap_atomic(to); copy_user_page(vto, vfrom, vaddr, to); - kunmap_atomic(vto, KM_USER1); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vto); + kunmap_atomic(vfrom); } #endif @@ -241,11 +276,11 @@ static inline void copy_highpage(struct page *to, struct page *from) { char *vfrom, *vto; - vfrom = kmap_atomic(from, KM_USER0); - vto = kmap_atomic(to, KM_USER1); + vfrom = kmap_atomic(from); + vto = kmap_atomic(to); copy_page(vto, vfrom); - kunmap_atomic(vto, KM_USER1); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vto); + kunmap_atomic(vfrom); } #endif /* _LINUX_HIGHMEM_H */ diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 78d3465251d6..7fcab23c59ce 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -712,6 +712,9 @@ struct twl4030_platform_data { struct regulator_init_data *vaux1; struct regulator_init_data *vaux2; struct regulator_init_data *vaux3; + struct regulator_init_data *vdd1; + struct regulator_init_data *vdd2; + struct regulator_init_data *vdd3; /* TWL4030 LDO regulators */ struct regulator_init_data *vpll1; struct regulator_init_data *vpll2; @@ -720,8 +723,6 @@ struct twl4030_platform_data { struct regulator_init_data *vsim; struct regulator_init_data *vaux4; struct regulator_init_data *vio; - struct regulator_init_data *vdd1; - struct regulator_init_data *vdd2; struct regulator_init_data *vintana1; struct regulator_init_data *vintana2; struct regulator_init_data *vintdig; @@ -733,6 +734,8 @@ struct twl4030_platform_data { struct regulator_init_data *vcxio; struct regulator_init_data *vusb; struct regulator_init_data *clk32kg; + struct regulator_init_data *v1v8; + struct regulator_init_data *v2v1; /* TWL6025 LDO regulators */ struct regulator_init_data *ldo1; struct regulator_init_data *ldo2; @@ -749,6 +752,13 @@ struct twl4030_platform_data { struct regulator_init_data *vio6025; }; +struct twl_regulator_driver_data { + int (*set_voltage)(void *data, int target_uV); + int (*get_voltage)(void *data); + void *data; + unsigned long features; +}; + /*----------------------------------------------------------------------*/ int twl4030_sih_setup(int module); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index bd4272b61a14..ead4a4215797 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -9,99 +9,182 @@ * representation into a hardware irq number that can be mapped back to a * Linux irq number without any extra platform support code. * - * irq_domain is expected to be embedded in an interrupt controller's private - * data structure. + * Interrupt controller "domain" data structure. This could be defined as a + * irq domain controller. That is, it handles the mapping between hardware + * and virtual interrupt numbers for a given interrupt domain. The domain + * structure is generally created by the PIC code for a given PIC instance + * (though a domain can cover more than one PIC if they have a flat number + * model). It's the domain callbacks that are responsible for setting the + * irq_chip on a given irq_desc after it's been mapped. + * + * The host code and data structures are agnostic to whether or not + * we use an open firmware device-tree. We do have references to struct + * device_node in two places: in irq_find_host() to find the host matching + * a given interrupt controller node, and of course as an argument to its + * counterpart domain->ops->match() callback. However, those are treated as + * generic pointers by the core and the fact that it's actually a device-node + * pointer is purely a convention between callers and implementation. This + * code could thus be used on other architectures by replacing those two + * by some sort of arch-specific void * "token" used to identify interrupt + * controllers. */ + #ifndef _LINUX_IRQDOMAIN_H #define _LINUX_IRQDOMAIN_H -#include <linux/irq.h> -#include <linux/mod_devicetable.h> +#include <linux/types.h> +#include <linux/radix-tree.h> -#ifdef CONFIG_IRQ_DOMAIN struct device_node; struct irq_domain; +struct of_device_id; + +/* Number of irqs reserved for a legacy isa controller */ +#define NUM_ISA_INTERRUPTS 16 + +/* This type is the placeholder for a hardware interrupt number. It has to + * be big enough to enclose whatever representation is used by a given + * platform. + */ +typedef unsigned long irq_hw_number_t; /** * struct irq_domain_ops - Methods for irq_domain objects - * @to_irq: (optional) given a local hardware irq number, return the linux - * irq number. If to_irq is not implemented, then the irq_domain - * will use this translation: irq = (domain->irq_base + hwirq) - * @dt_translate: Given a device tree node and interrupt specifier, decode - * the hardware irq number and linux irq type value. + * @match: Match an interrupt controller device node to a host, returns + * 1 on a match + * @map: Create or update a mapping between a virtual irq number and a hw + * irq number. This is called only once for a given mapping. + * @unmap: Dispose of such a mapping + * @xlate: Given a device tree node and interrupt specifier, decode + * the hardware irq number and linux irq type value. + * + * Functions below are provided by the driver and called whenever a new mapping + * is created or an old mapping is disposed. The driver can then proceed to + * whatever internal data structures management is required. It also needs + * to setup the irq_desc when returning from map(). */ struct irq_domain_ops { - unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq); - -#ifdef CONFIG_OF - int (*dt_translate)(struct irq_domain *d, struct device_node *node, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type); -#endif /* CONFIG_OF */ + int (*match)(struct irq_domain *d, struct device_node *node); + int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); + void (*unmap)(struct irq_domain *d, unsigned int virq); + int (*xlate)(struct irq_domain *d, struct device_node *node, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type); }; /** * struct irq_domain - Hardware interrupt number translation object - * @list: Element in global irq_domain list. + * @link: Element in global irq_domain list. + * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This + * will be one of the IRQ_DOMAIN_MAP_* values. + * @revmap_data: Revmap method specific data. + * @ops: pointer to irq_domain methods + * @host_data: private data pointer for use by owner. Not touched by irq_domain + * core code. * @irq_base: Start of irq_desc range assigned to the irq_domain. The creator * of the irq_domain is responsible for allocating the array of * irq_desc structures. * @nr_irq: Number of irqs managed by the irq domain * @hwirq_base: Starting number for hwirqs managed by the irq domain - * @ops: pointer to irq_domain methods - * @priv: private data pointer for use by owner. Not touched by irq_domain - * core code. * @of_node: (optional) Pointer to device tree nodes associated with the * irq_domain. Used when decoding device tree interrupt specifiers. */ struct irq_domain { - struct list_head list; - unsigned int irq_base; - unsigned int nr_irq; - unsigned int hwirq_base; + struct list_head link; + + /* type of reverse mapping_technique */ + unsigned int revmap_type; + union { + struct { + unsigned int size; + unsigned int first_irq; + irq_hw_number_t first_hwirq; + } legacy; + struct { + unsigned int size; + unsigned int *revmap; + } linear; + struct radix_tree_root tree; + } revmap_data; const struct irq_domain_ops *ops; - void *priv; + void *host_data; + irq_hw_number_t inval_irq; + + /* Optional device node pointer */ struct device_node *of_node; }; -/** - * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number - * - * Returns the linux irq number associated with a hardware irq. By default, - * the mapping is irq == domain->irq_base + hwirq, but this mapping can - * be overridden if the irq_domain implements a .to_irq() hook. - */ -static inline unsigned int irq_domain_to_irq(struct irq_domain *d, - unsigned long hwirq) +#ifdef CONFIG_IRQ_DOMAIN +struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, + unsigned int size, + unsigned int first_irq, + irq_hw_number_t first_hwirq, + const struct irq_domain_ops *ops, + void *host_data); +struct irq_domain *irq_domain_add_linear(struct device_node *of_node, + unsigned int size, + const struct irq_domain_ops *ops, + void *host_data); +struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, + const struct irq_domain_ops *ops, + void *host_data); +struct irq_domain *irq_domain_add_tree(struct device_node *of_node, + const struct irq_domain_ops *ops, + void *host_data); + +extern struct irq_domain *irq_find_host(struct device_node *node); +extern void irq_set_default_host(struct irq_domain *host); +extern void irq_set_virq_count(unsigned int count); + +static inline struct irq_domain *irq_domain_add_legacy_isa( + struct device_node *of_node, + const struct irq_domain_ops *ops, + void *host_data) { - if (d->ops->to_irq) - return d->ops->to_irq(d, hwirq); - if (WARN_ON(hwirq < d->hwirq_base)) - return 0; - return d->irq_base + hwirq - d->hwirq_base; + return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, + host_data); } +extern struct irq_domain *irq_find_host(struct device_node *node); +extern void irq_set_default_host(struct irq_domain *host); +extern void irq_set_virq_count(unsigned int count); -#define irq_domain_for_each_hwirq(d, hw) \ - for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++) -#define irq_domain_for_each_irq(d, hw, irq) \ - for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \ - hw < d->hwirq_base + d->nr_irq; \ - hw++, irq = irq_domain_to_irq(d, hw)) +extern unsigned int irq_create_mapping(struct irq_domain *host, + irq_hw_number_t hwirq); +extern void irq_dispose_mapping(unsigned int virq); +extern unsigned int irq_find_mapping(struct irq_domain *host, + irq_hw_number_t hwirq); +extern unsigned int irq_create_direct_mapping(struct irq_domain *host); +extern void irq_radix_revmap_insert(struct irq_domain *host, unsigned int virq, + irq_hw_number_t hwirq); +extern unsigned int irq_radix_revmap_lookup(struct irq_domain *host, + irq_hw_number_t hwirq); +extern unsigned int irq_linear_revmap(struct irq_domain *host, + irq_hw_number_t hwirq); -extern void irq_domain_add(struct irq_domain *domain); -extern void irq_domain_del(struct irq_domain *domain); +extern const struct irq_domain_ops irq_domain_simple_ops; -extern struct irq_domain_ops irq_domain_simple_ops; -#endif /* CONFIG_IRQ_DOMAIN */ +/* stock xlate functions */ +int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type); +int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type); +int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type); -#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ) -extern void irq_domain_add_simple(struct device_node *controller, int irq_base); +#if defined(CONFIG_OF_IRQ) extern void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start); -#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */ +#else /* CONFIG_OF_IRQ */ static inline void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start) { } -#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */ +#endif /* !CONFIG_OF_IRQ */ + +#else /* CONFIG_IRQ_DOMAIN */ +static inline void irq_dispose_mapping(unsigned int virq) { } +#endif /* !CONFIG_IRQ_DOMAIN */ #endif /* _LINUX_IRQDOMAIN_H */ diff --git a/include/linux/key.h b/include/linux/key.h index 5253471cd2ea..1600ebf717a7 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -155,6 +155,7 @@ struct key { #define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */ #define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ +#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ /* the description string * - this is used to match a key against search criteria diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index d0cb12eba402..76700b5eee92 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -768,6 +768,12 @@ /* Max number of TPS65910/11 regulators */ #define TPS65910_NUM_REGS 13 +/* External sleep controls through EN1/EN2/EN3/SLEEP inputs */ +#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 0x1 +#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 0x2 +#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 0x4 +#define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP 0x8 + /** * struct tps65910_board * Board platform data may be used to initialize regulators. @@ -779,6 +785,7 @@ struct tps65910_board { int irq_base; int vmbch_threshold; int vmbch2_threshold; + unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS]; struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS]; }; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 44d8144e9ae8..834c96c5d879 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -101,10 +101,6 @@ enum { #define MLX4_ATTR_EXTENDED_PORT_INFO cpu_to_be16(0xff90) enum { - MLX_EXT_PORT_CAP_FLAG_EXTENDED_PORT_INFO = 1 << 0 -}; - -enum { MLX4_BMME_FLAG_LOCAL_INV = 1 << 6, MLX4_BMME_FLAG_REMOTE_INV = 1 << 7, MLX4_BMME_FLAG_TYPE_2_WIN = 1 << 9, @@ -133,6 +129,7 @@ enum mlx4_event { MLX4_EVENT_TYPE_CMD = 0x0a, MLX4_EVENT_TYPE_VEP_UPDATE = 0x19, MLX4_EVENT_TYPE_COMM_CHANNEL = 0x18, + MLX4_EVENT_TYPE_FATAL_WARNING = 0x1b, MLX4_EVENT_TYPE_FLR_EVENT = 0x1c, MLX4_EVENT_TYPE_NONE = 0xff, }; @@ -143,6 +140,10 @@ enum { }; enum { + MLX4_FATAL_WARNING_SUBTYPE_WARMING = 0, +}; + +enum { MLX4_PERM_LOCAL_READ = 1 << 10, MLX4_PERM_LOCAL_WRITE = 1 << 11, MLX4_PERM_REMOTE_READ = 1 << 12, @@ -273,6 +274,7 @@ struct mlx4_caps { int num_comp_vectors; int comp_pool; int num_mpts; + int max_fmr_maps; int num_mtts; int fmr_reserved_mtts; int reserved_mtts; @@ -308,7 +310,7 @@ struct mlx4_caps { u32 port_mask[MLX4_MAX_PORTS + 1]; enum mlx4_port_type possible_type[MLX4_MAX_PORTS + 1]; u32 max_counters; - u8 ext_port_cap[MLX4_MAX_PORTS + 1]; + u8 port_ib_mtu[MLX4_MAX_PORTS + 1]; }; struct mlx4_buf_list { diff --git a/include/linux/of.h b/include/linux/of.h index 92cf6ad35e0e..f02d8b2f799d 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -72,19 +72,17 @@ struct of_phandle_args { uint32_t args[MAX_PHANDLE_ARGS]; }; -#if defined(CONFIG_SPARC) || !defined(CONFIG_OF) +#ifdef CONFIG_OF_DYNAMIC +extern struct device_node *of_node_get(struct device_node *node); +extern void of_node_put(struct device_node *node); +#else /* CONFIG_OF_DYNAMIC */ /* Dummy ref counting routines - to be implemented later */ static inline struct device_node *of_node_get(struct device_node *node) { return node; } -static inline void of_node_put(struct device_node *node) -{ -} -#else -extern struct device_node *of_node_get(struct device_node *node); -extern void of_node_put(struct device_node *node); -#endif +static inline void of_node_put(struct device_node *node) { } +#endif /* !CONFIG_OF_DYNAMIC */ #ifdef CONFIG_OF @@ -217,6 +215,9 @@ extern int of_property_read_string(struct device_node *np, extern int of_property_read_string_index(struct device_node *np, const char *propname, int index, const char **output); +extern int of_property_match_string(struct device_node *np, + const char *propname, + const char *string); extern int of_property_count_strings(struct device_node *np, const char *propname); extern int of_device_is_compatible(const struct device_node *device, diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 3118623c2c1f..01b925ad8d78 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h @@ -4,6 +4,7 @@ #include <linux/errno.h> #include <linux/of.h> +#ifdef CONFIG_OF_ADDRESS extern u64 of_translate_address(struct device_node *np, const __be32 *addr); extern int of_address_to_resource(struct device_node *dev, int index, struct resource *r); @@ -25,12 +26,37 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } #define pci_address_to_pio pci_address_to_pio #endif -#ifdef CONFIG_PCI +#else /* CONFIG_OF_ADDRESS */ +static inline int of_address_to_resource(struct device_node *dev, int index, + struct resource *r) +{ + return -EINVAL; +} +static inline struct device_node *of_find_matching_node_by_address( + struct device_node *from, + const struct of_device_id *matches, + u64 base_address) +{ + return NULL; +} +static inline void __iomem *of_iomap(struct device_node *device, int index) +{ + return NULL; +} +static inline const u32 *of_get_address(struct device_node *dev, int index, + u64 *size, unsigned int *flags) +{ + return NULL; +} +#endif /* CONFIG_OF_ADDRESS */ + + +#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI) extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, unsigned int *flags); extern int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r); -#else /* CONFIG_PCI */ +#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ static inline int of_pci_address_to_resource(struct device_node *dev, int bar, struct resource *r) { @@ -42,8 +68,7 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, { return NULL; } -#endif /* CONFIG_PCI */ - +#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */ #endif /* __OF_ADDRESS_H */ diff --git a/include/linux/of_device.h b/include/linux/of_device.h index ae5638480ef2..cbc42143fa5b 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -34,7 +34,8 @@ extern void of_device_unregister(struct platform_device *ofdev); extern ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len); -extern int of_device_uevent(struct device *dev, struct kobj_uevent_env *env); +extern void of_device_uevent(struct device *dev, struct kobj_uevent_env *env); +extern int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env); static inline void of_device_node_put(struct device *dev) { @@ -49,7 +50,10 @@ static inline int of_driver_match_device(struct device *dev, return 0; } -static inline int of_device_uevent(struct device *dev, +static inline void of_device_uevent(struct device *dev, + struct kobj_uevent_env *env) { } + +static inline int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) { return -ENODEV; diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index d0307eed20c9..d229ad3edee0 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -6,6 +6,7 @@ struct of_irq; #include <linux/types.h> #include <linux/errno.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/ioport.h> #include <linux/of.h> @@ -65,9 +66,6 @@ extern int of_irq_map_one(struct device_node *device, int index, extern unsigned int irq_create_of_mapping(struct device_node *controller, const u32 *intspec, unsigned int intsize); -#ifdef CONFIG_IRQ_DOMAIN -extern void irq_dispose_mapping(unsigned int irq); -#endif extern int of_irq_to_resource(struct device_node *dev, int index, struct resource *r); extern int of_irq_count(struct device_node *dev); diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 040ce2f6e8de..b47d2040c9f2 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -81,7 +81,7 @@ extern struct platform_device *of_device_alloc(struct device_node *np, struct device *parent); extern struct platform_device *of_find_device_by_node(struct device_node *np); -#if !defined(CONFIG_SPARC) /* SPARC has its own device registration method */ +#ifdef CONFIG_OF_ADDRESS /* device reg helpers depend on OF_ADDRESS */ /* Platform devices and busses creation */ extern struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, @@ -94,8 +94,19 @@ extern int of_platform_populate(struct device_node *root, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, struct device *parent); -#endif /* !CONFIG_SPARC */ +#endif /* CONFIG_OF_ADDRESS */ #endif /* CONFIG_OF_DEVICE */ +#if !defined(CONFIG_OF_ADDRESS) +struct of_dev_auxdata; +static inline int of_platform_populate(struct device_node *root, + const struct of_device_id *matches, + const struct of_dev_auxdata *lookup, + struct device *parent) +{ + return -ENODEV; +} +#endif /* !CONFIG_OF_ADDRESS */ + #endif /* _LINUX_OF_PLATFORM_H */ diff --git a/include/linux/padata.h b/include/linux/padata.h index 4633b2f726b6..86292beebfe2 100644 --- a/include/linux/padata.h +++ b/include/linux/padata.h @@ -46,7 +46,6 @@ struct padata_priv { struct list_head list; struct parallel_data *pd; int cb_cpu; - int seq_nr; int info; void (*parallel)(struct padata_priv *padata); void (*serial)(struct padata_priv *padata); @@ -116,7 +115,6 @@ struct padata_cpumask { * @pinst: padata instance. * @pqueue: percpu padata queues used for parallelization. * @squeue: percpu padata queues used for serialuzation. - * @seq_nr: The sequence number that will be attached to the next object. * @reorder_objects: Number of objects waiting in the reorder queues. * @refcnt: Number of objects holding a reference on this parallel_data. * @max_seq_nr: Maximal used sequence number. @@ -129,12 +127,12 @@ struct parallel_data { struct padata_instance *pinst; struct padata_parallel_queue __percpu *pqueue; struct padata_serial_queue __percpu *squeue; - atomic_t seq_nr; atomic_t reorder_objects; atomic_t refcnt; - unsigned int max_seq_nr; struct padata_cpumask cpumask; spinlock_t lock ____cacheline_aligned; + spinlock_t seq_lock; + unsigned int seq_nr; unsigned int processed; struct timer_list timer; }; diff --git a/include/linux/pm.h b/include/linux/pm.h index e4982ac3fbbc..715305e05123 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -110,6 +110,10 @@ typedef struct pm_message { * Subsystem-level @suspend() is executed for all devices after invoking * subsystem-level @prepare() for all of them. * + * @suspend_late: Continue operations started by @suspend(). For a number of + * devices @suspend_late() may point to the same callback routine as the + * runtime suspend callback. + * * @resume: Executed after waking the system up from a sleep state in which the * contents of main memory were preserved. The exact action to perform * depends on the device's subsystem, but generally the driver is expected @@ -122,6 +126,10 @@ typedef struct pm_message { * Subsystem-level @resume() is executed for all devices after invoking * subsystem-level @resume_noirq() for all of them. * + * @resume_early: Prepare to execute @resume(). For a number of devices + * @resume_early() may point to the same callback routine as the runtime + * resume callback. + * * @freeze: Hibernation-specific, executed before creating a hibernation image. * Analogous to @suspend(), but it should not enable the device to signal * wakeup events or change its power state. The majority of subsystems @@ -131,6 +139,10 @@ typedef struct pm_message { * Subsystem-level @freeze() is executed for all devices after invoking * subsystem-level @prepare() for all of them. * + * @freeze_late: Continue operations started by @freeze(). Analogous to + * @suspend_late(), but it should not enable the device to signal wakeup + * events or change its power state. + * * @thaw: Hibernation-specific, executed after creating a hibernation image OR * if the creation of an image has failed. Also executed after a failing * attempt to restore the contents of main memory from such an image. @@ -140,15 +152,23 @@ typedef struct pm_message { * subsystem-level @thaw_noirq() for all of them. It also may be executed * directly after @freeze() in case of a transition error. * + * @thaw_early: Prepare to execute @thaw(). Undo the changes made by the + * preceding @freeze_late(). + * * @poweroff: Hibernation-specific, executed after saving a hibernation image. * Analogous to @suspend(), but it need not save the device's settings in * memory. * Subsystem-level @poweroff() is executed for all devices after invoking * subsystem-level @prepare() for all of them. * + * @poweroff_late: Continue operations started by @poweroff(). Analogous to + * @suspend_late(), but it need not save the device's settings in memory. + * * @restore: Hibernation-specific, executed after restoring the contents of main * memory from a hibernation image, analogous to @resume(). * + * @restore_early: Prepare to execute @restore(), analogous to @resume_early(). + * * @suspend_noirq: Complete the actions started by @suspend(). Carry out any * additional operations required for suspending the device that might be * racing with its driver's interrupt handler, which is guaranteed not to @@ -158,9 +178,10 @@ typedef struct pm_message { * @suspend_noirq() has returned successfully. If the device can generate * system wakeup signals and is enabled to wake up the system, it should be * configured to do so at that time. However, depending on the platform - * and device's subsystem, @suspend() may be allowed to put the device into - * the low-power state and configure it to generate wakeup signals, in - * which case it generally is not necessary to define @suspend_noirq(). + * and device's subsystem, @suspend() or @suspend_late() may be allowed to + * put the device into the low-power state and configure it to generate + * wakeup signals, in which case it generally is not necessary to define + * @suspend_noirq(). * * @resume_noirq: Prepare for the execution of @resume() by carrying out any * operations required for resuming the device that might be racing with @@ -171,9 +192,9 @@ typedef struct pm_message { * additional operations required for freezing the device that might be * racing with its driver's interrupt handler, which is guaranteed not to * run while @freeze_noirq() is being executed. - * The power state of the device should not be changed by either @freeze() - * or @freeze_noirq() and it should not be configured to signal system - * wakeup by any of these callbacks. + * The power state of the device should not be changed by either @freeze(), + * or @freeze_late(), or @freeze_noirq() and it should not be configured to + * signal system wakeup by any of these callbacks. * * @thaw_noirq: Prepare for the execution of @thaw() by carrying out any * operations required for thawing the device that might be racing with its @@ -249,6 +270,12 @@ struct dev_pm_ops { int (*thaw)(struct device *dev); int (*poweroff)(struct device *dev); int (*restore)(struct device *dev); + int (*suspend_late)(struct device *dev); + int (*resume_early)(struct device *dev); + int (*freeze_late)(struct device *dev); + int (*thaw_early)(struct device *dev); + int (*poweroff_late)(struct device *dev); + int (*restore_early)(struct device *dev); int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*freeze_noirq)(struct device *dev); @@ -293,6 +320,15 @@ const struct dev_pm_ops name = { \ /* * Use this for defining a set of PM operations to be used in all situations * (sustem suspend, hibernation or runtime PM). + * NOTE: In general, system suspend callbacks, .suspend() and .resume(), should + * be different from the corresponding runtime PM callbacks, .runtime_suspend(), + * and .runtime_resume(), because .runtime_suspend() always works on an already + * quiescent device, while .suspend() should assume that the device may be doing + * something when it is called (it should ensure that the device will be + * quiescent after it has returned). Therefore it's better to point the "late" + * suspend and "early" resume callback pointers, .suspend_late() and + * .resume_early(), to the same routines as .runtime_suspend() and + * .runtime_resume(), respectively (and analogously for hibernation). */ #define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ const struct dev_pm_ops name = { \ @@ -510,6 +546,7 @@ struct dev_pm_info { unsigned long accounting_timestamp; ktime_t suspend_time; s64 max_time_suspended_ns; + struct dev_pm_qos_request *pq_req; #endif struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ struct pm_qos_constraints *constraints; @@ -584,13 +621,13 @@ struct dev_pm_domain { #ifdef CONFIG_PM_SLEEP extern void device_pm_lock(void); -extern void dpm_resume_noirq(pm_message_t state); +extern void dpm_resume_start(pm_message_t state); extern void dpm_resume_end(pm_message_t state); extern void dpm_resume(pm_message_t state); extern void dpm_complete(pm_message_t state); extern void device_pm_unlock(void); -extern int dpm_suspend_noirq(pm_message_t state); +extern int dpm_suspend_end(pm_message_t state); extern int dpm_suspend_start(pm_message_t state); extern int dpm_suspend(pm_message_t state); extern int dpm_prepare(pm_message_t state); @@ -605,17 +642,23 @@ extern void __suspend_report_result(const char *function, void *fn, int ret); extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); extern int pm_generic_prepare(struct device *dev); +extern int pm_generic_suspend_late(struct device *dev); extern int pm_generic_suspend_noirq(struct device *dev); extern int pm_generic_suspend(struct device *dev); +extern int pm_generic_resume_early(struct device *dev); extern int pm_generic_resume_noirq(struct device *dev); extern int pm_generic_resume(struct device *dev); extern int pm_generic_freeze_noirq(struct device *dev); +extern int pm_generic_freeze_late(struct device *dev); extern int pm_generic_freeze(struct device *dev); extern int pm_generic_thaw_noirq(struct device *dev); +extern int pm_generic_thaw_early(struct device *dev); extern int pm_generic_thaw(struct device *dev); extern int pm_generic_restore_noirq(struct device *dev); +extern int pm_generic_restore_early(struct device *dev); extern int pm_generic_restore(struct device *dev); extern int pm_generic_poweroff_noirq(struct device *dev); +extern int pm_generic_poweroff_late(struct device *dev); extern int pm_generic_poweroff(struct device *dev); extern void pm_generic_complete(struct device *dev); diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index a03a0ad998b8..1236d262b3e8 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -11,6 +11,7 @@ #include <linux/device.h> #include <linux/err.h> +#include <linux/of.h> enum gpd_status { GPD_STATE_ACTIVE = 0, /* PM domain is active */ @@ -70,6 +71,7 @@ struct generic_pm_domain { s64 break_even_ns; /* Power break even for the entire domain. */ s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ ktime_t power_off_time; + struct device_node *of_node; /* Node in device tree */ }; static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) @@ -97,14 +99,15 @@ struct generic_pm_domain_data { struct gpd_dev_ops ops; struct gpd_timing_data td; bool need_restore; + bool always_on; }; +#ifdef CONFIG_PM_GENERIC_DOMAINS static inline struct generic_pm_domain_data *to_gpd_data(struct pm_domain_data *pdd) { return container_of(pdd, struct generic_pm_domain_data, base); } -#ifdef CONFIG_PM_GENERIC_DOMAINS static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) { return to_gpd_data(dev->power.subsys_data->domain_data); @@ -117,14 +120,25 @@ extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, struct gpd_timing_data *td); +extern int __pm_genpd_of_add_device(struct device_node *genpd_node, + struct device *dev, + struct gpd_timing_data *td); + static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) { return __pm_genpd_add_device(genpd, dev, NULL); } +static inline int pm_genpd_of_add_device(struct device_node *genpd_node, + struct device *dev) +{ + return __pm_genpd_of_add_device(genpd_node, dev, NULL); +} + extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, struct device *dev); +extern void pm_genpd_dev_always_on(struct device *dev, bool val); extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *new_subdomain); extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, @@ -143,6 +157,10 @@ extern bool default_stop_ok(struct device *dev); extern struct dev_power_governor pm_domain_always_on_gov; #else +static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) +{ + return ERR_PTR(-ENOSYS); +} static inline struct generic_pm_domain *dev_to_genpd(struct device *dev) { return ERR_PTR(-ENOSYS); @@ -163,6 +181,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, { return -ENOSYS; } +static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {} static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, struct generic_pm_domain *new_sd) { @@ -183,7 +202,8 @@ static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td) { return -ENOSYS; } -static inline void pm_genpd_init(struct generic_pm_domain *genpd, bool is_off) +static inline void pm_genpd_init(struct generic_pm_domain *genpd, + struct dev_power_governor *gov, bool is_off) { } static inline int pm_genpd_poweron(struct generic_pm_domain *genpd) @@ -194,6 +214,7 @@ static inline bool default_stop_ok(struct device *dev) { return false; } +#define simple_qos_governor NULL #define pm_domain_always_on_gov NULL #endif diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 4d99e4e6ef83..2e9191a712f3 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -9,12 +9,16 @@ #include <linux/miscdevice.h> #include <linux/device.h> -#define PM_QOS_RESERVED 0 -#define PM_QOS_CPU_DMA_LATENCY 1 -#define PM_QOS_NETWORK_LATENCY 2 -#define PM_QOS_NETWORK_THROUGHPUT 3 +enum { + PM_QOS_RESERVED = 0, + PM_QOS_CPU_DMA_LATENCY, + PM_QOS_NETWORK_LATENCY, + PM_QOS_NETWORK_THROUGHPUT, + + /* insert new class ID */ + PM_QOS_NUM_CLASSES, +}; -#define PM_QOS_NUM_CLASSES 4 #define PM_QOS_DEFAULT_VALUE -1 #define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) @@ -63,7 +67,6 @@ static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req) return req->dev != 0; } -#ifdef CONFIG_PM int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, enum pm_qos_req_action action, int value); void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class, @@ -78,6 +81,7 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier); int pm_qos_request_active(struct pm_qos_request *req); s32 pm_qos_read_value(struct pm_qos_constraints *c); +#ifdef CONFIG_PM s32 __dev_pm_qos_read_value(struct device *dev); s32 dev_pm_qos_read_value(struct device *dev); int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, @@ -95,45 +99,6 @@ void dev_pm_qos_constraints_destroy(struct device *dev); int dev_pm_qos_add_ancestor_request(struct device *dev, struct dev_pm_qos_request *req, s32 value); #else -static inline int pm_qos_update_target(struct pm_qos_constraints *c, - struct plist_node *node, - enum pm_qos_req_action action, - int value) - { return 0; } -static inline void pm_qos_add_request(struct pm_qos_request *req, - int pm_qos_class, s32 value) - { return; } -static inline void pm_qos_update_request(struct pm_qos_request *req, - s32 new_value) - { return; } -static inline void pm_qos_remove_request(struct pm_qos_request *req) - { return; } - -static inline int pm_qos_request(int pm_qos_class) -{ - switch (pm_qos_class) { - case PM_QOS_CPU_DMA_LATENCY: - return PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; - case PM_QOS_NETWORK_LATENCY: - return PM_QOS_NETWORK_LAT_DEFAULT_VALUE; - case PM_QOS_NETWORK_THROUGHPUT: - return PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE; - default: - return PM_QOS_DEFAULT_VALUE; - } -} - -static inline int pm_qos_add_notifier(int pm_qos_class, - struct notifier_block *notifier) - { return 0; } -static inline int pm_qos_remove_notifier(int pm_qos_class, - struct notifier_block *notifier) - { return 0; } -static inline int pm_qos_request_active(struct pm_qos_request *req) - { return 0; } -static inline s32 pm_qos_read_value(struct pm_qos_constraints *c) - { return 0; } - static inline s32 __dev_pm_qos_read_value(struct device *dev) { return 0; } static inline s32 dev_pm_qos_read_value(struct device *dev) @@ -172,4 +137,13 @@ static inline int dev_pm_qos_add_ancestor_request(struct device *dev, { return 0; } #endif +#ifdef CONFIG_PM_RUNTIME +int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value); +void dev_pm_qos_hide_latency_limit(struct device *dev); +#else +static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) + { return 0; } +static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {} +#endif + #endif diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index a32da962d693..d9f05113e5fb 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -41,7 +41,7 @@ * @active: Status of the wakeup source. */ struct wakeup_source { - char *name; + const char *name; struct list_head entry; spinlock_t lock; struct timer_list timer; @@ -73,7 +73,9 @@ static inline bool device_may_wakeup(struct device *dev) } /* drivers/base/power/wakeup.c */ +extern void wakeup_source_prepare(struct wakeup_source *ws, const char *name); extern struct wakeup_source *wakeup_source_create(const char *name); +extern void wakeup_source_drop(struct wakeup_source *ws); extern void wakeup_source_destroy(struct wakeup_source *ws); extern void wakeup_source_add(struct wakeup_source *ws); extern void wakeup_source_remove(struct wakeup_source *ws); @@ -103,11 +105,16 @@ static inline bool device_can_wakeup(struct device *dev) return dev->power.can_wakeup; } +static inline void wakeup_source_prepare(struct wakeup_source *ws, + const char *name) {} + static inline struct wakeup_source *wakeup_source_create(const char *name) { return NULL; } +static inline void wakeup_source_drop(struct wakeup_source *ws) {} + static inline void wakeup_source_destroy(struct wakeup_source *ws) {} static inline void wakeup_source_add(struct wakeup_source *ws) {} @@ -165,4 +172,17 @@ static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {} #endif /* !CONFIG_PM_SLEEP */ +static inline void wakeup_source_init(struct wakeup_source *ws, + const char *name) +{ + wakeup_source_prepare(ws, name); + wakeup_source_add(ws); +} + +static inline void wakeup_source_trash(struct wakeup_source *ws) +{ + wakeup_source_remove(ws); + wakeup_source_drop(ws); +} + #endif /* _LINUX_PM_WAKEUP_H */ diff --git a/include/linux/prctl.h b/include/linux/prctl.h index 7ddc7f1b480f..a0413ac3abe8 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -114,4 +114,11 @@ # define PR_SET_MM_START_BRK 6 # define PR_SET_MM_BRK 7 +/* + * Set specific pid that is allowed to ptrace the current task. + * A value of 0 mean "no process". + */ +#define PR_SET_PTRACER 0x59616d61 +# define PR_SET_PTRACER_ANY ((unsigned long)-1) + #endif /* _LINUX_PRCTL_H */ diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index f2698a0edfc4..b6c8d717c7ec 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -132,9 +132,12 @@ struct regulator_bulk_data { /* regulator get and put */ struct regulator *__must_check regulator_get(struct device *dev, const char *id); +struct regulator *__must_check devm_regulator_get(struct device *dev, + const char *id); struct regulator *__must_check regulator_get_exclusive(struct device *dev, const char *id); void regulator_put(struct regulator *regulator); +void devm_regulator_put(struct regulator *regulator); /* regulator output control and status */ int regulator_enable(struct regulator *regulator); @@ -145,6 +148,8 @@ int regulator_disable_deferred(struct regulator *regulator, int ms); int regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers); +int devm_regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers); int regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers); int regulator_bulk_disable(int num_consumers, @@ -200,10 +205,21 @@ static inline struct regulator *__must_check regulator_get(struct device *dev, */ return NULL; } + +static inline struct regulator *__must_check +devm_regulator_get(struct device *dev, const char *id) +{ + return NULL; +} + static inline void regulator_put(struct regulator *regulator) { } +static inline void devm_regulator_put(struct regulator *regulator) +{ +} + static inline int regulator_enable(struct regulator *regulator) { return 0; @@ -237,6 +253,12 @@ static inline int regulator_bulk_get(struct device *dev, return 0; } +static inline int devm_regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers) +{ + return 0; +} + static inline int regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers) { diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4214b9a9d1c9..fa8b55b8191c 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -104,7 +104,7 @@ struct regulator_ops { int (*disable) (struct regulator_dev *); int (*is_enabled) (struct regulator_dev *); - /* get/set regulator operating mode (defined in regulator.h) */ + /* get/set regulator operating mode (defined in consumer.h) */ int (*set_mode) (struct regulator_dev *, unsigned int mode); unsigned int (*get_mode) (struct regulator_dev *); @@ -135,7 +135,7 @@ struct regulator_ops { int (*set_suspend_enable) (struct regulator_dev *); int (*set_suspend_disable) (struct regulator_dev *); - /* set regulator suspend operating mode (defined in regulator.h) */ + /* set regulator suspend operating mode (defined in consumer.h) */ int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode); }; @@ -207,9 +207,7 @@ struct regulator_dev { void *reg_data; /* regulator_dev data */ -#ifdef CONFIG_DEBUG_FS struct dentry *debugfs; -#endif }; struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h index ffd7d508e726..936a7d8c11a9 100644 --- a/include/linux/regulator/fixed.h +++ b/include/linux/regulator/fixed.h @@ -48,4 +48,17 @@ struct fixed_voltage_config { struct regulator_init_data *init_data; }; +struct regulator_consumer_supply; + +#if IS_ENABLED(CONFIG_REGULATOR) +struct platform_device *regulator_register_fixed(int id, + struct regulator_consumer_supply *supplies, int num_supplies); +#else +static inline struct platform_device *regulator_register_fixed(int id, + struct regulator_consumer_supply *supplies, int num_supplies) +{ + return NULL; +} +#endif + #endif diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index f3f13fd5868f..7abb16093312 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -139,12 +139,10 @@ struct regulation_constraints { * make struct device available late such as I2C and is the preferred * form. * - * @dev: Device structure for the consumer. * @dev_name: Result of dev_name() for the consumer. * @supply: Name for the supply. */ struct regulator_consumer_supply { - struct device *dev; /* consumer */ const char *dev_name; /* dev_name() for consumer */ const char *supply; /* consumer supply - e.g. "vcc" */ }; diff --git a/include/linux/regulator/tps62360.h b/include/linux/regulator/tps62360.h new file mode 100644 index 000000000000..6a5c1b2c751e --- /dev/null +++ b/include/linux/regulator/tps62360.h @@ -0,0 +1,57 @@ +/* + * tps62360.h -- TI tps62360 + * + * Interface for regulator driver for TI TPS62360 Processor core supply + * + * Copyright (C) 2012 NVIDIA Corporation + + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef __LINUX_REGULATOR_TPS62360_H +#define __LINUX_REGULATOR_TPS62360_H + +#include <linux/regulator/machine.h> + +/* + * struct tps62360_regulator_platform_data - tps62360 regulator platform data. + * + * @reg_init_data: The regulator init data. + * @en_force_pwm: Enable force pwm or not. + * @en_discharge: Enable discharge the output capacitor via internal + * register. + * @en_internal_pulldn: internal pull down enable or not. + * @vsel0_gpio: Gpio number for vsel0. It should be -1 if this is tied with + * fixed logic. + * @vsel1_gpio: Gpio number for vsel1. It should be -1 if this is tied with + * fixed logic. + * @vsel0_def_state: Default state of vsel0. 1 if it is high else 0. + * @vsel1_def_state: Default state of vsel1. 1 if it is high else 0. + */ +struct tps62360_regulator_platform_data { + struct regulator_init_data reg_init_data; + bool en_force_pwm; + bool en_discharge; + bool en_internal_pulldn; + int vsel0_gpio; + int vsel1_gpio; + int vsel0_def_state; + int vsel1_def_state; +}; + +#endif /* __LINUX_REGULATOR_TPS62360_H */ diff --git a/include/linux/security.h b/include/linux/security.h index c8949385e56e..673afbb8238a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -22,22 +22,36 @@ #ifndef __LINUX_SECURITY_H #define __LINUX_SECURITY_H -#include <linux/fs.h> -#include <linux/fsnotify.h> -#include <linux/binfmts.h> -#include <linux/dcache.h> -#include <linux/signal.h> -#include <linux/resource.h> -#include <linux/sem.h> -#include <linux/shm.h> -#include <linux/mm.h> /* PAGE_ALIGN */ -#include <linux/msg.h> -#include <linux/sched.h> #include <linux/key.h> -#include <linux/xfrm.h> +#include <linux/capability.h> #include <linux/slab.h> -#include <linux/xattr.h> -#include <net/flow.h> +#include <linux/err.h> + +struct linux_binprm; +struct cred; +struct rlimit; +struct siginfo; +struct sem_array; +struct sembuf; +struct kern_ipc_perm; +struct audit_context; +struct super_block; +struct inode; +struct dentry; +struct file; +struct vfsmount; +struct path; +struct qstr; +struct nameidata; +struct iattr; +struct fown_struct; +struct file_operations; +struct shmid_kernel; +struct msg_msg; +struct msg_queue; +struct xattr; +struct xfrm_sec_ctx; +struct mm_struct; /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 @@ -49,6 +63,7 @@ struct ctl_table; struct audit_krule; struct user_namespace; +struct timezone; /* * These functions are in security/capability.c and are used @@ -131,18 +146,6 @@ struct request_sock; #define LSM_UNSAFE_PTRACE_CAP 4 #ifdef CONFIG_MMU -/* - * If a hint addr is less than mmap_min_addr change hint to be as - * low as possible but still greater than mmap_min_addr - */ -static inline unsigned long round_hint_to_min(unsigned long hint) -{ - hint &= PAGE_MASK; - if (((void *)hint != NULL) && - (hint < mmap_min_addr)) - return PAGE_ALIGN(mmap_min_addr); - return hint; -} extern int mmap_min_addr_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); #endif @@ -651,6 +654,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. + * @task_free: + * @task task being freed + * Handle release of task-related resources. (Note that this can be called + * from interrupt context.) * @cred_alloc_blank: * @cred points to the credentials. * @gfp indicates the atomicity of any memory allocations. @@ -1493,6 +1500,7 @@ struct security_operations { int (*dentry_open) (struct file *file, const struct cred *cred); int (*task_create) (unsigned long clone_flags); + void (*task_free) (struct task_struct *task); int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp); void (*cred_free) (struct cred *cred); int (*cred_prepare)(struct cred *new, const struct cred *old, @@ -1674,9 +1682,7 @@ int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); int security_settime(const struct timespec *ts, const struct timezone *tz); -int security_vm_enough_memory(long pages); int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); -int security_vm_enough_memory_kern(long pages); int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm); void security_bprm_committing_creds(struct linux_binprm *bprm); @@ -1752,6 +1758,7 @@ int security_file_send_sigiotask(struct task_struct *tsk, int security_file_receive(struct file *file); int security_dentry_open(struct file *file, const struct cred *cred); int security_task_create(unsigned long clone_flags); +void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); void security_cred_free(struct cred *cred); int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); @@ -1896,25 +1903,11 @@ static inline int security_settime(const struct timespec *ts, return cap_settime(ts, tz); } -static inline int security_vm_enough_memory(long pages) -{ - WARN_ON(current->mm == NULL); - return cap_vm_enough_memory(current->mm, pages); -} - static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { - WARN_ON(mm == NULL); return cap_vm_enough_memory(mm, pages); } -static inline int security_vm_enough_memory_kern(long pages) -{ - /* If current->mm is a kernel thread then we will pass NULL, - for this specific case that is fine */ - return cap_vm_enough_memory(current->mm, pages); -} - static inline int security_bprm_set_creds(struct linux_binprm *bprm) { return cap_bprm_set_creds(bprm); @@ -2245,6 +2238,9 @@ static inline int security_task_create(unsigned long clone_flags) return 0; } +static inline void security_task_free(struct task_struct *task) +{ } + static inline int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { return 0; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a2b9953b582d..681a18799140 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1244,7 +1244,7 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i, } extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, - int off, int size); + int off, int size, unsigned int truesize); #define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) #define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frag_list(skb)) diff --git a/include/linux/spi/sh_hspi.h b/include/linux/spi/sh_hspi.h new file mode 100644 index 000000000000..a1121f872ac1 --- /dev/null +++ b/include/linux/spi/sh_hspi.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2011 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef SH_HSPI_H +#define SH_HSPI_H + +struct sh_hspi_info { +}; + +#endif diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 176fce9cc6b1..98679b061b63 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -22,6 +22,7 @@ #include <linux/device.h> #include <linux/mod_devicetable.h> #include <linux/slab.h> +#include <linux/kthread.h> /* * INTERFACES between SPI master-side drivers and SPI infrastructure. @@ -235,6 +236,27 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * the device whose settings are being modified. * @transfer: adds a message to the controller's transfer queue. * @cleanup: frees controller-specific state + * @queued: whether this master is providing an internal message queue + * @kworker: thread struct for message pump + * @kworker_task: pointer to task for message pump kworker thread + * @pump_messages: work struct for scheduling work to the message pump + * @queue_lock: spinlock to syncronise access to message queue + * @queue: message queue + * @cur_msg: the currently in-flight message + * @busy: message pump is busy + * @running: message pump is running + * @rt: whether this queue is set to run as a realtime task + * @prepare_transfer_hardware: a message will soon arrive from the queue + * so the subsystem requests the driver to prepare the transfer hardware + * by issuing this call + * @transfer_one_message: the subsystem calls the driver to transfer a single + * message while queuing transfers that arrive in the meantime. When the + * driver is finished with this message, it must call + * spi_finalize_current_message() so the subsystem can issue the next + * transfer + * @prepare_transfer_hardware: there are currently no more messages on the + * queue so the subsystem notifies the driver that it may relax the + * hardware by issuing this call * * Each SPI master controller can communicate with one or more @spi_device * children. These make a small bus, sharing MOSI, MISO and SCK signals @@ -318,6 +340,28 @@ struct spi_master { /* called on release() to free memory provided by spi_master */ void (*cleanup)(struct spi_device *spi); + + /* + * These hooks are for drivers that want to use the generic + * master transfer queueing mechanism. If these are used, the + * transfer() function above must NOT be specified by the driver. + * Over time we expect SPI drivers to be phased over to this API. + */ + bool queued; + struct kthread_worker kworker; + struct task_struct *kworker_task; + struct kthread_work pump_messages; + spinlock_t queue_lock; + struct list_head queue; + struct spi_message *cur_msg; + bool busy; + bool running; + bool rt; + + int (*prepare_transfer_hardware)(struct spi_master *master); + int (*transfer_one_message)(struct spi_master *master, + struct spi_message *mesg); + int (*unprepare_transfer_hardware)(struct spi_master *master); }; static inline void *spi_master_get_devdata(struct spi_master *master) @@ -343,6 +387,13 @@ static inline void spi_master_put(struct spi_master *master) put_device(&master->dev); } +/* PM calls that need to be issued by the driver */ +extern int spi_master_suspend(struct spi_master *master); +extern int spi_master_resume(struct spi_master *master); + +/* Calls the driver make to interact with the message queue */ +extern struct spi_message *spi_get_next_queued_message(struct spi_master *master); +extern void spi_finalize_current_message(struct spi_master *master); /* the spi driver core manages memory for the spi_master classdev */ extern struct spi_master * @@ -549,7 +600,7 @@ static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags + ntrans * sizeof(struct spi_transfer), flags); if (m) { - int i; + unsigned i; struct spi_transfer *t = (struct spi_transfer *)(m + 1); INIT_LIST_HEAD(&m->transfers); diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 91784a4f8608..ac1c114c499d 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -42,8 +42,10 @@ enum suspend_stat_step { SUSPEND_FREEZE = 1, SUSPEND_PREPARE, SUSPEND_SUSPEND, + SUSPEND_SUSPEND_LATE, SUSPEND_SUSPEND_NOIRQ, SUSPEND_RESUME_NOIRQ, + SUSPEND_RESUME_EARLY, SUSPEND_RESUME }; @@ -53,8 +55,10 @@ struct suspend_stats { int failed_freeze; int failed_prepare; int failed_suspend; + int failed_suspend_late; int failed_suspend_noirq; int failed_resume; + int failed_resume_early; int failed_resume_noirq; #define REC_FAILED_NUM 2 int last_failed_dev; diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 90c67c7db7e9..3b572bb20aa2 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -118,6 +118,10 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; extern struct nf_conntrack_l4proto * __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto); +extern struct nf_conntrack_l4proto * +nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto); +extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); + /* Protocol registration. */ extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto); extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h index 0e04db4a0865..34ec89f8dbf9 100644 --- a/include/net/netfilter/nf_conntrack_timeout.h +++ b/include/net/netfilter/nf_conntrack_timeout.h @@ -15,7 +15,7 @@ struct ctnl_timeout { atomic_t refcnt; char name[CTNL_TIMEOUT_NAME_MAX]; __u16 l3num; - __u8 l4num; + struct nf_conntrack_l4proto *l4proto; char data[0]; }; diff --git a/include/net/sock.h b/include/net/sock.h index f84be9ed6110..04bc0b30e9e9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -56,6 +56,8 @@ #include <linux/memcontrol.h> #include <linux/res_counter.h> #include <linux/static_key.h> +#include <linux/aio.h> +#include <linux/sched.h> #include <linux/filter.h> #include <linux/rculist_nulls.h> diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index d3b9401b77b0..b513f57e1725 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -77,6 +77,15 @@ #define IB_MGMT_MAX_METHODS 128 +/* MAD Status field bit masks */ +#define IB_MGMT_MAD_STATUS_SUCCESS 0x0000 +#define IB_MGMT_MAD_STATUS_BUSY 0x0001 +#define IB_MGMT_MAD_STATUS_REDIRECT_REQD 0x0002 +#define IB_MGMT_MAD_STATUS_BAD_VERSION 0x0004 +#define IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD 0x0008 +#define IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB 0x000c +#define IB_MGMT_MAD_STATUS_INVALID_ATTRIB_VALUE 0x001c + /* RMPP information */ #define IB_MGMT_RMPP_VERSION 1 diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index bf5daafe8ecc..c3cca5a4dacd 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -239,6 +239,15 @@ static inline int ib_width_enum_to_int(enum ib_port_width width) } } +enum ib_port_speed { + IB_SPEED_SDR = 1, + IB_SPEED_DDR = 2, + IB_SPEED_QDR = 4, + IB_SPEED_FDR10 = 8, + IB_SPEED_FDR = 16, + IB_SPEED_EDR = 32 +}; + struct ib_protocol_stats { /* TBD... */ }; @@ -509,6 +518,7 @@ enum ib_wc_flags { IB_WC_GRH = 1, IB_WC_WITH_IMM = (1<<1), IB_WC_WITH_INVALIDATE = (1<<2), + IB_WC_IP_CSUM_OK = (1<<3), }; struct ib_wc { @@ -529,7 +539,6 @@ struct ib_wc { u8 sl; u8 dlid_path_bits; u8 port_num; /* valid only for DR SMPs on switches */ - int csum_ok; }; enum ib_cq_notify_flags { diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 5652101cdac0..26143d377c95 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -13,7 +13,9 @@ #include <linux/security.h> #include <linux/slab.h> #include <linux/ipc.h> +#include <linux/msg.h> #include <linux/ipc_namespace.h> +#include <linux/utsname.h> #include <asm/uaccess.h> #include "util.h" diff --git a/kernel/cred.c b/kernel/cred.c index 5791612a4045..97b36eeca4c9 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -16,6 +16,7 @@ #include <linux/keyctl.h> #include <linux/init_task.h> #include <linux/security.h> +#include <linux/binfmts.h> #include <linux/cn_proc.h> #if 0 diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index 7d6fb40d2188..d35cc2d3a4cc 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -384,9 +384,9 @@ static int kdb_getphys(void *res, unsigned long addr, size_t size) if (!pfn_valid(pfn)) return 1; page = pfn_to_page(pfn); - vaddr = kmap_atomic(page, KM_KDB); + vaddr = kmap_atomic(page); memcpy(res, vaddr + (addr & (PAGE_SIZE - 1)), size); - kunmap_atomic(vaddr, KM_KDB); + kunmap_atomic(vaddr); return 0; } diff --git a/kernel/exit.c b/kernel/exit.c index ce5f758f40bd..7ad335c3045a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -52,6 +52,7 @@ #include <linux/hw_breakpoint.h> #include <linux/oom.h> #include <linux/writeback.h> +#include <linux/shm.h> #include <asm/uaccess.h> #include <asm/unistd.h> @@ -424,7 +425,7 @@ void daemonize(const char *name, ...) */ exit_mm(current); /* - * We don't want to have TIF_FREEZE set if the system-wide hibernation + * We don't want to get frozen, in case system-wide hibernation * or suspend transition begins right now. */ current->flags |= (PF_NOFREEZE | PF_KTHREAD); diff --git a/kernel/fork.c b/kernel/fork.c index c4f38a849436..26a7138bb849 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -193,6 +193,7 @@ void __put_task_struct(struct task_struct *tsk) WARN_ON(atomic_read(&tsk->usage)); WARN_ON(tsk == current); + security_task_free(tsk); exit_creds(tsk); delayacct_tsk_free(tsk); put_signal_struct(tsk->signal); @@ -355,7 +356,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; - if (security_vm_enough_memory(len)) + if (security_vm_enough_memory_mm(oldmm, len)) /* sic */ goto fail_nomem; charge = len; } diff --git a/kernel/freezer.c b/kernel/freezer.c index 9815b8d1eed5..11f82a4d4eae 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -99,9 +99,9 @@ static void fake_signal_wake_up(struct task_struct *p) * freeze_task - send a freeze request to given task * @p: task to send the request to * - * If @p is freezing, the freeze request is sent by setting %TIF_FREEZE - * flag and either sending a fake signal to it or waking it up, depending - * on whether it has %PF_FREEZER_NOSIG set. + * If @p is freezing, the freeze request is sent either by sending a fake + * signal (if it's not a kernel thread) or waking it up (if it's a kernel + * thread). * * RETURNS: * %false, if @p is not freezing or already frozen; %true, otherwise diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 1f9e26526b69..af48e59bc2ff 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1,189 +1,793 @@ +#include <linux/debugfs.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqdesc.h> #include <linux/irqdomain.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/smp.h> +#include <linux/fs.h> + +#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs. + * ie. legacy 8259, gets irqs 1..15 */ +#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */ +#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */ +#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */ static LIST_HEAD(irq_domain_list); static DEFINE_MUTEX(irq_domain_mutex); +static DEFINE_MUTEX(revmap_trees_mutex); +static unsigned int irq_virq_count = NR_IRQS; +static struct irq_domain *irq_default_domain; + /** - * irq_domain_add() - Register an irq_domain - * @domain: ptr to initialized irq_domain structure + * irq_domain_alloc() - Allocate a new irq_domain data structure + * @of_node: optional device-tree node of the interrupt controller + * @revmap_type: type of reverse mapping to use + * @ops: map/unmap domain callbacks + * @host_data: Controller private data pointer * - * Registers an irq_domain structure. The irq_domain must at a minimum be - * initialized with an ops structure pointer, and either a ->to_irq hook or - * a valid irq_base value. Everything else is optional. + * Allocates and initialize and irq_domain structure. Caller is expected to + * register allocated irq_domain with irq_domain_register(). Returns pointer + * to IRQ domain, or NULL on failure. */ -void irq_domain_add(struct irq_domain *domain) +static struct irq_domain *irq_domain_alloc(struct device_node *of_node, + unsigned int revmap_type, + const struct irq_domain_ops *ops, + void *host_data) { - struct irq_data *d; - int hwirq, irq; + struct irq_domain *domain; - /* - * This assumes that the irq_domain owner has already allocated - * the irq_descs. This block will be removed when support for dynamic - * allocation of irq_descs is added to irq_domain. - */ - irq_domain_for_each_irq(domain, hwirq, irq) { - d = irq_get_irq_data(irq); - if (!d) { - WARN(1, "error: assigning domain to non existant irq_desc"); - return; - } - if (d->domain) { - /* things are broken; just report, don't clean up */ - WARN(1, "error: irq_desc already assigned to a domain"); - return; + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (WARN_ON(!domain)) + return NULL; + + /* Fill structure */ + domain->revmap_type = revmap_type; + domain->ops = ops; + domain->host_data = host_data; + domain->of_node = of_node_get(of_node); + + return domain; +} + +static void irq_domain_add(struct irq_domain *domain) +{ + mutex_lock(&irq_domain_mutex); + list_add(&domain->link, &irq_domain_list); + mutex_unlock(&irq_domain_mutex); + pr_debug("irq: Allocated domain of type %d @0x%p\n", + domain->revmap_type, domain); +} + +static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, + irq_hw_number_t hwirq) +{ + irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq; + int size = domain->revmap_data.legacy.size; + + if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size)) + return 0; + return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq; +} + +/** + * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain. + * @of_node: pointer to interrupt controller's device tree node. + * @size: total number of irqs in legacy mapping + * @first_irq: first number of irq block assigned to the domain + * @first_hwirq: first hwirq number to use for the translation. Should normally + * be '0', but a positive integer can be used if the effective + * hwirqs numbering does not begin at zero. + * @ops: map/unmap domain callbacks + * @host_data: Controller private data pointer + * + * Note: the map() callback will be called before this function returns + * for all legacy interrupts except 0 (which is always the invalid irq for + * a legacy controller). + */ +struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, + unsigned int size, + unsigned int first_irq, + irq_hw_number_t first_hwirq, + const struct irq_domain_ops *ops, + void *host_data) +{ + struct irq_domain *domain; + unsigned int i; + + domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data); + if (!domain) + return NULL; + + domain->revmap_data.legacy.first_irq = first_irq; + domain->revmap_data.legacy.first_hwirq = first_hwirq; + domain->revmap_data.legacy.size = size; + + mutex_lock(&irq_domain_mutex); + /* Verify that all the irqs are available */ + for (i = 0; i < size; i++) { + int irq = first_irq + i; + struct irq_data *irq_data = irq_get_irq_data(irq); + + if (WARN_ON(!irq_data || irq_data->domain)) { + mutex_unlock(&irq_domain_mutex); + of_node_put(domain->of_node); + kfree(domain); + return NULL; } - d->domain = domain; - d->hwirq = hwirq; } - mutex_lock(&irq_domain_mutex); - list_add(&domain->list, &irq_domain_list); + /* Claim all of the irqs before registering a legacy domain */ + for (i = 0; i < size; i++) { + struct irq_data *irq_data = irq_get_irq_data(first_irq + i); + irq_data->hwirq = first_hwirq + i; + irq_data->domain = domain; + } mutex_unlock(&irq_domain_mutex); + + for (i = 0; i < size; i++) { + int irq = first_irq + i; + int hwirq = first_hwirq + i; + + /* IRQ0 gets ignored */ + if (!irq) + continue; + + /* Legacy flags are left to default at this point, + * one can then use irq_create_mapping() to + * explicitly change them + */ + ops->map(domain, irq, hwirq); + + /* Clear norequest flags */ + irq_clear_status_flags(irq, IRQ_NOREQUEST); + } + + irq_domain_add(domain); + return domain; +} + +/** + * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain. + * @of_node: pointer to interrupt controller's device tree node. + * @ops: map/unmap domain callbacks + * @host_data: Controller private data pointer + */ +struct irq_domain *irq_domain_add_linear(struct device_node *of_node, + unsigned int size, + const struct irq_domain_ops *ops, + void *host_data) +{ + struct irq_domain *domain; + unsigned int *revmap; + + revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL); + if (WARN_ON(!revmap)) + return NULL; + + domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data); + if (!domain) { + kfree(revmap); + return NULL; + } + domain->revmap_data.linear.size = size; + domain->revmap_data.linear.revmap = revmap; + irq_domain_add(domain); + return domain; +} + +struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, + const struct irq_domain_ops *ops, + void *host_data) +{ + struct irq_domain *domain = irq_domain_alloc(of_node, + IRQ_DOMAIN_MAP_NOMAP, ops, host_data); + if (domain) + irq_domain_add(domain); + return domain; +} + +/** + * irq_domain_add_tree() + * @of_node: pointer to interrupt controller's device tree node. + * @ops: map/unmap domain callbacks + * + * Note: The radix tree will be allocated later during boot automatically + * (the reverse mapping will use the slow path until that happens). + */ +struct irq_domain *irq_domain_add_tree(struct device_node *of_node, + const struct irq_domain_ops *ops, + void *host_data) +{ + struct irq_domain *domain = irq_domain_alloc(of_node, + IRQ_DOMAIN_MAP_TREE, ops, host_data); + if (domain) { + INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL); + irq_domain_add(domain); + } + return domain; } /** - * irq_domain_del() - Unregister an irq_domain - * @domain: ptr to registered irq_domain. + * irq_find_host() - Locates a domain for a given device node + * @node: device-tree node of the interrupt controller */ -void irq_domain_del(struct irq_domain *domain) +struct irq_domain *irq_find_host(struct device_node *node) { - struct irq_data *d; - int hwirq, irq; + struct irq_domain *h, *found = NULL; + int rc; + /* We might want to match the legacy controller last since + * it might potentially be set to match all interrupts in + * the absence of a device node. This isn't a problem so far + * yet though... + */ mutex_lock(&irq_domain_mutex); - list_del(&domain->list); + list_for_each_entry(h, &irq_domain_list, link) { + if (h->ops->match) + rc = h->ops->match(h, node); + else + rc = (h->of_node != NULL) && (h->of_node == node); + + if (rc) { + found = h; + break; + } + } mutex_unlock(&irq_domain_mutex); + return found; +} +EXPORT_SYMBOL_GPL(irq_find_host); + +/** + * irq_set_default_host() - Set a "default" irq domain + * @domain: default domain pointer + * + * For convenience, it's possible to set a "default" domain that will be used + * whenever NULL is passed to irq_create_mapping(). It makes life easier for + * platforms that want to manipulate a few hard coded interrupt numbers that + * aren't properly represented in the device-tree. + */ +void irq_set_default_host(struct irq_domain *domain) +{ + pr_debug("irq: Default domain set to @0x%p\n", domain); + + irq_default_domain = domain; +} + +/** + * irq_set_virq_count() - Set the maximum number of linux irqs + * @count: number of linux irqs, capped with NR_IRQS + * + * This is mainly for use by platforms like iSeries who want to program + * the virtual irq number in the controller to avoid the reverse mapping + */ +void irq_set_virq_count(unsigned int count) +{ + pr_debug("irq: Trying to set virq count to %d\n", count); - /* Clear the irq_domain assignments */ - irq_domain_for_each_irq(domain, hwirq, irq) { - d = irq_get_irq_data(irq); - d->domain = NULL; + BUG_ON(count < NUM_ISA_INTERRUPTS); + if (count < NR_IRQS) + irq_virq_count = count; +} + +static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct irq_data *irq_data = irq_get_irq_data(virq); + + irq_data->hwirq = hwirq; + irq_data->domain = domain; + if (domain->ops->map(domain, virq, hwirq)) { + pr_debug("irq: -> mapping failed, freeing\n"); + irq_data->domain = NULL; + irq_data->hwirq = 0; + return -1; } + + irq_clear_status_flags(virq, IRQ_NOREQUEST); + + return 0; } -#if defined(CONFIG_OF_IRQ) /** - * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec + * irq_create_direct_mapping() - Allocate an irq for direct mapping + * @domain: domain to allocate the irq for or NULL for default domain * - * Used by the device tree interrupt mapping code to translate a device tree - * interrupt specifier to a valid linux irq number. Returns either a valid - * linux IRQ number or 0. + * This routine is used for irq controllers which can choose the hardware + * interrupt numbers they generate. In such a case it's simplest to use + * the linux irq as the hardware interrupt number. + */ +unsigned int irq_create_direct_mapping(struct irq_domain *domain) +{ + unsigned int virq; + + if (domain == NULL) + domain = irq_default_domain; + + BUG_ON(domain == NULL); + WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP); + + virq = irq_alloc_desc_from(1, 0); + if (!virq) { + pr_debug("irq: create_direct virq allocation failed\n"); + return 0; + } + if (virq >= irq_virq_count) { + pr_err("ERROR: no free irqs available below %i maximum\n", + irq_virq_count); + irq_free_desc(virq); + return 0; + } + + pr_debug("irq: create_direct obtained virq %d\n", virq); + + if (irq_setup_virq(domain, virq, virq)) { + irq_free_desc(virq); + return 0; + } + + return virq; +} + +/** + * irq_create_mapping() - Map a hardware interrupt into linux irq space + * @domain: domain owning this hardware interrupt or NULL for default domain + * @hwirq: hardware irq number in that domain space * - * When the caller no longer need the irq number returned by this function it - * should arrange to call irq_dispose_mapping(). + * Only one mapping per hardware interrupt is permitted. Returns a linux + * irq number. + * If the sense/trigger is to be specified, set_irq_type() should be called + * on the number returned from that call. */ +unsigned int irq_create_mapping(struct irq_domain *domain, + irq_hw_number_t hwirq) +{ + unsigned int virq, hint; + + pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); + + /* Look for default domain if nececssary */ + if (domain == NULL) + domain = irq_default_domain; + if (domain == NULL) { + printk(KERN_WARNING "irq_create_mapping called for" + " NULL domain, hwirq=%lx\n", hwirq); + WARN_ON(1); + return 0; + } + pr_debug("irq: -> using domain @%p\n", domain); + + /* Check if mapping already exists */ + virq = irq_find_mapping(domain, hwirq); + if (virq) { + pr_debug("irq: -> existing mapping on virq %d\n", virq); + return virq; + } + + /* Get a virtual interrupt number */ + if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) + return irq_domain_legacy_revmap(domain, hwirq); + + /* Allocate a virtual interrupt number */ + hint = hwirq % irq_virq_count; + if (hint == 0) + hint++; + virq = irq_alloc_desc_from(hint, 0); + if (!virq) + virq = irq_alloc_desc_from(1, 0); + if (!virq) { + pr_debug("irq: -> virq allocation failed\n"); + return 0; + } + + if (irq_setup_virq(domain, virq, hwirq)) { + if (domain->revmap_type != IRQ_DOMAIN_MAP_LEGACY) + irq_free_desc(virq); + return 0; + } + + pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n", + hwirq, domain->of_node ? domain->of_node->full_name : "null", virq); + + return virq; +} +EXPORT_SYMBOL_GPL(irq_create_mapping); + unsigned int irq_create_of_mapping(struct device_node *controller, const u32 *intspec, unsigned int intsize) { struct irq_domain *domain; - unsigned long hwirq; - unsigned int irq, type; - int rc = -EINVAL; + irq_hw_number_t hwirq; + unsigned int type = IRQ_TYPE_NONE; + unsigned int virq; - /* Find a domain which can translate the irq spec */ - mutex_lock(&irq_domain_mutex); - list_for_each_entry(domain, &irq_domain_list, list) { - if (!domain->ops->dt_translate) - continue; - rc = domain->ops->dt_translate(domain, controller, - intspec, intsize, &hwirq, &type); - if (rc == 0) - break; + domain = controller ? irq_find_host(controller) : irq_default_domain; + if (!domain) { +#ifdef CONFIG_MIPS + /* + * Workaround to avoid breaking interrupt controller drivers + * that don't yet register an irq_domain. This is temporary + * code. ~~~gcl, Feb 24, 2012 + * + * Scheduled for removal in Linux v3.6. That should be enough + * time. + */ + if (intsize > 0) + return intspec[0]; +#endif + printk(KERN_WARNING "irq: no irq domain found for %s !\n", + controller->full_name); + return 0; } - mutex_unlock(&irq_domain_mutex); - if (rc != 0) - return 0; + /* If domain has no translation, then we assume interrupt line */ + if (domain->ops->xlate == NULL) + hwirq = intspec[0]; + else { + if (domain->ops->xlate(domain, controller, intspec, intsize, + &hwirq, &type)) + return 0; + } + + /* Create mapping */ + virq = irq_create_mapping(domain, hwirq); + if (!virq) + return virq; - irq = irq_domain_to_irq(domain, hwirq); - if (type != IRQ_TYPE_NONE) - irq_set_irq_type(irq, type); - pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n", - controller->full_name, (int)hwirq, irq, type); - return irq; + /* Set type if specified and different than the current one */ + if (type != IRQ_TYPE_NONE && + type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) + irq_set_irq_type(virq, type); + return virq; } EXPORT_SYMBOL_GPL(irq_create_of_mapping); /** - * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping() - * @irq: linux irq number to be discarded + * irq_dispose_mapping() - Unmap an interrupt + * @virq: linux irq number of the interrupt to unmap + */ +void irq_dispose_mapping(unsigned int virq) +{ + struct irq_data *irq_data = irq_get_irq_data(virq); + struct irq_domain *domain; + irq_hw_number_t hwirq; + + if (!virq || !irq_data) + return; + + domain = irq_data->domain; + if (WARN_ON(domain == NULL)) + return; + + /* Never unmap legacy interrupts */ + if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) + return; + + irq_set_status_flags(virq, IRQ_NOREQUEST); + + /* remove chip and handler */ + irq_set_chip_and_handler(virq, NULL, NULL); + + /* Make sure it's completed */ + synchronize_irq(virq); + + /* Tell the PIC about it */ + if (domain->ops->unmap) + domain->ops->unmap(domain, virq); + smp_mb(); + + /* Clear reverse map */ + hwirq = irq_data->hwirq; + switch(domain->revmap_type) { + case IRQ_DOMAIN_MAP_LINEAR: + if (hwirq < domain->revmap_data.linear.size) + domain->revmap_data.linear.revmap[hwirq] = 0; + break; + case IRQ_DOMAIN_MAP_TREE: + mutex_lock(&revmap_trees_mutex); + radix_tree_delete(&domain->revmap_data.tree, hwirq); + mutex_unlock(&revmap_trees_mutex); + break; + } + + irq_free_desc(virq); +} +EXPORT_SYMBOL_GPL(irq_dispose_mapping); + +/** + * irq_find_mapping() - Find a linux irq from an hw irq number. + * @domain: domain owning this hardware interrupt + * @hwirq: hardware irq number in that domain space + * + * This is a slow path, for use by generic code. It's expected that an + * irq controller implementation directly calls the appropriate low level + * mapping function. + */ +unsigned int irq_find_mapping(struct irq_domain *domain, + irq_hw_number_t hwirq) +{ + unsigned int i; + unsigned int hint = hwirq % irq_virq_count; + + /* Look for default domain if nececssary */ + if (domain == NULL) + domain = irq_default_domain; + if (domain == NULL) + return 0; + + /* legacy -> bail early */ + if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) + return irq_domain_legacy_revmap(domain, hwirq); + + /* Slow path does a linear search of the map */ + if (hint == 0) + hint = 1; + i = hint; + do { + struct irq_data *data = irq_get_irq_data(i); + if (data && (data->domain == domain) && (data->hwirq == hwirq)) + return i; + i++; + if (i >= irq_virq_count) + i = 1; + } while(i != hint); + return 0; +} +EXPORT_SYMBOL_GPL(irq_find_mapping); + +/** + * irq_radix_revmap_lookup() - Find a linux irq from a hw irq number. + * @domain: domain owning this hardware interrupt + * @hwirq: hardware irq number in that domain space * - * Calling this function indicates the caller no longer needs a reference to - * the linux irq number returned by a prior call to irq_create_of_mapping(). + * This is a fast path, for use by irq controller code that uses radix tree + * revmaps */ -void irq_dispose_mapping(unsigned int irq) +unsigned int irq_radix_revmap_lookup(struct irq_domain *domain, + irq_hw_number_t hwirq) { + struct irq_data *irq_data; + + if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_TREE)) + return irq_find_mapping(domain, hwirq); + + /* + * Freeing an irq can delete nodes along the path to + * do the lookup via call_rcu. + */ + rcu_read_lock(); + irq_data = radix_tree_lookup(&domain->revmap_data.tree, hwirq); + rcu_read_unlock(); + /* - * nothing yet; will be filled when support for dynamic allocation of - * irq_descs is added to irq_domain + * If found in radix tree, then fine. + * Else fallback to linear lookup - this should not happen in practice + * as it means that we failed to insert the node in the radix tree. */ + return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq); } -EXPORT_SYMBOL_GPL(irq_dispose_mapping); -int irq_domain_simple_dt_translate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type) +/** + * irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping. + * @domain: domain owning this hardware interrupt + * @virq: linux irq number + * @hwirq: hardware irq number in that domain space + * + * This is for use by irq controllers that use a radix tree reverse + * mapping for fast lookup. + */ +void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hwirq) { - if (d->of_node != controller) - return -EINVAL; - if (intsize < 1) - return -EINVAL; - if (d->nr_irq && ((intspec[0] < d->hwirq_base) || - (intspec[0] >= d->hwirq_base + d->nr_irq))) - return -EINVAL; + struct irq_data *irq_data = irq_get_irq_data(virq); + + if (WARN_ON(domain->revmap_type != IRQ_DOMAIN_MAP_TREE)) + return; + + if (virq) { + mutex_lock(&revmap_trees_mutex); + radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data); + mutex_unlock(&revmap_trees_mutex); + } +} + +/** + * irq_linear_revmap() - Find a linux irq from a hw irq number. + * @domain: domain owning this hardware interrupt + * @hwirq: hardware irq number in that domain space + * + * This is a fast path, for use by irq controller code that uses linear + * revmaps. It does fallback to the slow path if the revmap doesn't exist + * yet and will create the revmap entry with appropriate locking + */ +unsigned int irq_linear_revmap(struct irq_domain *domain, + irq_hw_number_t hwirq) +{ + unsigned int *revmap; + + if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) + return irq_find_mapping(domain, hwirq); + + /* Check revmap bounds */ + if (unlikely(hwirq >= domain->revmap_data.linear.size)) + return irq_find_mapping(domain, hwirq); + + /* Check if revmap was allocated */ + revmap = domain->revmap_data.linear.revmap; + if (unlikely(revmap == NULL)) + return irq_find_mapping(domain, hwirq); + + /* Fill up revmap with slow path if no mapping found */ + if (unlikely(!revmap[hwirq])) + revmap[hwirq] = irq_find_mapping(domain, hwirq); + + return revmap[hwirq]; +} + +#ifdef CONFIG_VIRQ_DEBUG +static int virq_debug_show(struct seq_file *m, void *private) +{ + unsigned long flags; + struct irq_desc *desc; + const char *p; + static const char none[] = "none"; + void *data; + int i; + + seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", + "chip name", "chip data", "domain name"); + + for (i = 1; i < nr_irqs; i++) { + desc = irq_to_desc(i); + if (!desc) + continue; + + raw_spin_lock_irqsave(&desc->lock, flags); + + if (desc->action && desc->action->handler) { + struct irq_chip *chip; + + seq_printf(m, "%5d ", i); + seq_printf(m, "0x%05lx ", desc->irq_data.hwirq); + + chip = irq_desc_get_chip(desc); + if (chip && chip->name) + p = chip->name; + else + p = none; + seq_printf(m, "%-15s ", p); + + data = irq_desc_get_chip_data(desc); + seq_printf(m, "0x%16p ", data); + + if (desc->irq_data.domain->of_node) + p = desc->irq_data.domain->of_node->full_name; + else + p = none; + seq_printf(m, "%s\n", p); + } + + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + + return 0; +} +static int virq_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, virq_debug_show, inode->i_private); +} + +static const struct file_operations virq_debug_fops = { + .open = virq_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init irq_debugfs_init(void) +{ + if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, + NULL, &virq_debug_fops) == NULL) + return -ENOMEM; + + return 0; +} +__initcall(irq_debugfs_init); +#endif /* CONFIG_VIRQ_DEBUG */ + +int irq_domain_simple_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + return 0; +} + +/** + * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings + * + * Device Tree IRQ specifier translation function which works with one cell + * bindings where the cell value maps directly to the hwirq number. + */ +int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) +{ + if (WARN_ON(intsize < 1)) + return -EINVAL; *out_hwirq = intspec[0]; *out_type = IRQ_TYPE_NONE; - if (intsize > 1) - *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; return 0; } +EXPORT_SYMBOL_GPL(irq_domain_xlate_onecell); /** - * irq_domain_create_simple() - Set up a 'simple' translation range + * irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings + * + * Device Tree IRQ specifier translation function which works with two cell + * bindings where the cell values map directly to the hwirq number + * and linux irq flags. */ -void irq_domain_add_simple(struct device_node *controller, int irq_base) +int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) { - struct irq_domain *domain; - - domain = kzalloc(sizeof(*domain), GFP_KERNEL); - if (!domain) { - WARN_ON(1); - return; - } + if (WARN_ON(intsize < 2)) + return -EINVAL; + *out_hwirq = intspec[0]; + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; + return 0; +} +EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell); - domain->irq_base = irq_base; - domain->of_node = of_node_get(controller); - domain->ops = &irq_domain_simple_ops; - irq_domain_add(domain); +/** + * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings + * + * Device Tree IRQ specifier translation function which works with either one + * or two cell bindings where the cell values map directly to the hwirq number + * and linux irq flags. + * + * Note: don't use this function unless your interrupt controller explicitly + * supports both one and two cell bindings. For the majority of controllers + * the _onecell() or _twocell() variants above should be used. + */ +int irq_domain_xlate_onetwocell(struct irq_domain *d, + struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, unsigned int *out_type) +{ + if (WARN_ON(intsize < 1)) + return -EINVAL; + *out_hwirq = intspec[0]; + *out_type = (intsize > 1) ? intspec[1] : IRQ_TYPE_NONE; + return 0; } -EXPORT_SYMBOL_GPL(irq_domain_add_simple); +EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell); +const struct irq_domain_ops irq_domain_simple_ops = { + .map = irq_domain_simple_map, + .xlate = irq_domain_xlate_onetwocell, +}; +EXPORT_SYMBOL_GPL(irq_domain_simple_ops); + +#ifdef CONFIG_OF_IRQ void irq_domain_generate_simple(const struct of_device_id *match, u64 phys_base, unsigned int irq_start) { struct device_node *node; - pr_info("looking for phys_base=%llx, irq_start=%i\n", + pr_debug("looking for phys_base=%llx, irq_start=%i\n", (unsigned long long) phys_base, (int) irq_start); node = of_find_matching_node_by_address(NULL, match, phys_base); if (node) - irq_domain_add_simple(node, irq_start); - else - pr_info("no node found\n"); + irq_domain_add_legacy(node, 32, irq_start, 0, + &irq_domain_simple_ops, NULL); } EXPORT_SYMBOL_GPL(irq_domain_generate_simple); -#endif /* CONFIG_OF_IRQ */ - -struct irq_domain_ops irq_domain_simple_ops = { -#ifdef CONFIG_OF_IRQ - .dt_translate = irq_domain_simple_dt_translate, -#endif /* CONFIG_OF_IRQ */ -}; -EXPORT_SYMBOL_GPL(irq_domain_simple_ops); +#endif diff --git a/kernel/kexec.c b/kernel/kexec.c index 7b0886786701..a6a675cb9818 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1546,13 +1546,13 @@ int kernel_kexec(void) if (error) goto Resume_console; /* At this point, dpm_suspend_start() has been called, - * but *not* dpm_suspend_noirq(). We *must* call - * dpm_suspend_noirq() now. Otherwise, drivers for + * but *not* dpm_suspend_end(). We *must* call + * dpm_suspend_end() now. Otherwise, drivers for * some devices (e.g. interrupt controllers) become * desynchronized with the actual state of the * hardware at resume time, and evil weirdness ensues. */ - error = dpm_suspend_noirq(PMSG_FREEZE); + error = dpm_suspend_end(PMSG_FREEZE); if (error) goto Resume_devices; error = disable_nonboot_cpus(); @@ -1579,7 +1579,7 @@ int kernel_kexec(void) local_irq_enable(); Enable_cpus: enable_nonboot_cpus(); - dpm_resume_noirq(PMSG_RESTORE); + dpm_resume_start(PMSG_RESTORE); Resume_devices: dpm_resume_end(PMSG_RESTORE); Resume_console: diff --git a/kernel/padata.c b/kernel/padata.c index b45259931512..6f10eb285ece 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -29,7 +29,6 @@ #include <linux/sysfs.h> #include <linux/rcupdate.h> -#define MAX_SEQ_NR (INT_MAX - NR_CPUS) #define MAX_OBJ_NUM 1000 static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) @@ -43,18 +42,19 @@ static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) return target_cpu; } -static int padata_cpu_hash(struct padata_priv *padata) +static int padata_cpu_hash(struct parallel_data *pd) { int cpu_index; - struct parallel_data *pd; - - pd = padata->pd; /* * Hash the sequence numbers to the cpus by taking * seq_nr mod. number of cpus in use. */ - cpu_index = padata->seq_nr % cpumask_weight(pd->cpumask.pcpu); + + spin_lock(&pd->seq_lock); + cpu_index = pd->seq_nr % cpumask_weight(pd->cpumask.pcpu); + pd->seq_nr++; + spin_unlock(&pd->seq_lock); return padata_index_to_cpu(pd, cpu_index); } @@ -132,12 +132,7 @@ int padata_do_parallel(struct padata_instance *pinst, padata->pd = pd; padata->cb_cpu = cb_cpu; - if (unlikely(atomic_read(&pd->seq_nr) == pd->max_seq_nr)) - atomic_set(&pd->seq_nr, -1); - - padata->seq_nr = atomic_inc_return(&pd->seq_nr); - - target_cpu = padata_cpu_hash(padata); + target_cpu = padata_cpu_hash(pd); queue = per_cpu_ptr(pd->pqueue, target_cpu); spin_lock(&queue->parallel.lock); @@ -173,7 +168,7 @@ EXPORT_SYMBOL(padata_do_parallel); static struct padata_priv *padata_get_next(struct parallel_data *pd) { int cpu, num_cpus; - int next_nr, next_index; + unsigned int next_nr, next_index; struct padata_parallel_queue *queue, *next_queue; struct padata_priv *padata; struct padata_list *reorder; @@ -189,14 +184,6 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd) cpu = padata_index_to_cpu(pd, next_index); next_queue = per_cpu_ptr(pd->pqueue, cpu); - if (unlikely(next_nr > pd->max_seq_nr)) { - next_nr = next_nr - pd->max_seq_nr - 1; - next_index = next_nr % num_cpus; - cpu = padata_index_to_cpu(pd, next_index); - next_queue = per_cpu_ptr(pd->pqueue, cpu); - pd->processed = 0; - } - padata = NULL; reorder = &next_queue->reorder; @@ -205,8 +192,6 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd) padata = list_entry(reorder->list.next, struct padata_priv, list); - BUG_ON(next_nr != padata->seq_nr); - spin_lock(&reorder->lock); list_del_init(&padata->list); atomic_dec(&pd->reorder_objects); @@ -230,6 +215,7 @@ out: static void padata_reorder(struct parallel_data *pd) { + int cb_cpu; struct padata_priv *padata; struct padata_serial_queue *squeue; struct padata_instance *pinst = pd->pinst; @@ -270,13 +256,14 @@ static void padata_reorder(struct parallel_data *pd) return; } - squeue = per_cpu_ptr(pd->squeue, padata->cb_cpu); + cb_cpu = padata->cb_cpu; + squeue = per_cpu_ptr(pd->squeue, cb_cpu); spin_lock(&squeue->serial.lock); list_add_tail(&padata->list, &squeue->serial.list); spin_unlock(&squeue->serial.lock); - queue_work_on(padata->cb_cpu, pinst->wq, &squeue->work); + queue_work_on(cb_cpu, pinst->wq, &squeue->work); } spin_unlock_bh(&pd->lock); @@ -400,7 +387,7 @@ static void padata_init_squeues(struct parallel_data *pd) /* Initialize all percpu queues used by parallel workers */ static void padata_init_pqueues(struct parallel_data *pd) { - int cpu_index, num_cpus, cpu; + int cpu_index, cpu; struct padata_parallel_queue *pqueue; cpu_index = 0; @@ -415,9 +402,6 @@ static void padata_init_pqueues(struct parallel_data *pd) INIT_WORK(&pqueue->work, padata_parallel_worker); atomic_set(&pqueue->num_obj, 0); } - - num_cpus = cpumask_weight(pd->cpumask.pcpu); - pd->max_seq_nr = num_cpus ? (MAX_SEQ_NR / num_cpus) * num_cpus - 1 : 0; } /* Allocate and initialize the internal cpumask dependend resources. */ @@ -444,7 +428,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst, padata_init_pqueues(pd); padata_init_squeues(pd); setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd); - atomic_set(&pd->seq_nr, -1); + pd->seq_nr = 0; atomic_set(&pd->reorder_objects, 0); atomic_set(&pd->refcnt, 0); pd->pinst = pinst; diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 07e0e28ffba7..66d808ec5252 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -1,7 +1,8 @@ ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG -obj-$(CONFIG_PM) += main.o qos.o +obj-y += qos.o +obj-$(CONFIG_PM) += main.o obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o obj-$(CONFIG_FREEZER) += process.o obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 6d6d28870335..0a186cfde788 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -245,8 +245,8 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop, * create_image - Create a hibernation image. * @platform_mode: Whether or not to use the platform driver. * - * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image - * and execute the drivers' .thaw_noirq() callbacks. + * Execute device drivers' "late" and "noirq" freeze callbacks, create a + * hibernation image and run the drivers' "noirq" and "early" thaw callbacks. * * Control reappears in this routine after the subsequent restore. */ @@ -254,7 +254,7 @@ static int create_image(int platform_mode) { int error; - error = dpm_suspend_noirq(PMSG_FREEZE); + error = dpm_suspend_end(PMSG_FREEZE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting hibernation\n"); @@ -306,7 +306,7 @@ static int create_image(int platform_mode) Platform_finish: platform_finish(platform_mode); - dpm_resume_noirq(in_suspend ? + dpm_resume_start(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); return error; @@ -343,13 +343,13 @@ int hibernation_snapshot(int platform_mode) * successful freezer test. */ freezer_test_done = true; - goto Cleanup; + goto Thaw; } error = dpm_prepare(PMSG_FREEZE); if (error) { dpm_complete(PMSG_RECOVER); - goto Cleanup; + goto Thaw; } suspend_console(); @@ -385,6 +385,8 @@ int hibernation_snapshot(int platform_mode) platform_end(platform_mode); return error; + Thaw: + thaw_kernel_threads(); Cleanup: swsusp_free(); goto Close; @@ -394,16 +396,16 @@ int hibernation_snapshot(int platform_mode) * resume_target_kernel - Restore system state from a hibernation image. * @platform_mode: Whether or not to use the platform driver. * - * Execute device drivers' .freeze_noirq() callbacks, restore the contents of - * highmem that have not been restored yet from the image and run the low-level - * code that will restore the remaining contents of memory and switch to the - * just restored target kernel. + * Execute device drivers' "noirq" and "late" freeze callbacks, restore the + * contents of highmem that have not been restored yet from the image and run + * the low-level code that will restore the remaining contents of memory and + * switch to the just restored target kernel. */ static int resume_target_kernel(bool platform_mode) { int error; - error = dpm_suspend_noirq(PMSG_QUIESCE); + error = dpm_suspend_end(PMSG_QUIESCE); if (error) { printk(KERN_ERR "PM: Some devices failed to power down, " "aborting resume\n"); @@ -460,7 +462,7 @@ static int resume_target_kernel(bool platform_mode) Cleanup: platform_restore_cleanup(platform_mode); - dpm_resume_noirq(PMSG_RECOVER); + dpm_resume_start(PMSG_RECOVER); return error; } @@ -518,7 +520,7 @@ int hibernation_platform_enter(void) goto Resume_devices; } - error = dpm_suspend_noirq(PMSG_HIBERNATE); + error = dpm_suspend_end(PMSG_HIBERNATE); if (error) goto Resume_devices; @@ -549,7 +551,7 @@ int hibernation_platform_enter(void) Platform_finish: hibernation_ops->finish(); - dpm_resume_noirq(PMSG_RESTORE); + dpm_resume_start(PMSG_RESTORE); Resume_devices: entering_platform_hibernation = false; @@ -616,7 +618,7 @@ int hibernate(void) /* Allocate memory management structures */ error = create_basic_memory_bitmaps(); if (error) - goto Exit; + goto Enable_umh; printk(KERN_INFO "PM: Syncing filesystems ... "); sys_sync(); @@ -624,15 +626,11 @@ int hibernate(void) error = freeze_processes(); if (error) - goto Finish; + goto Free_bitmaps; error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); - if (error) - goto Thaw; - if (freezer_test_done) { - freezer_test_done = false; + if (error || freezer_test_done) goto Thaw; - } if (in_suspend) { unsigned int flags = 0; @@ -657,8 +655,13 @@ int hibernate(void) Thaw: thaw_processes(); - Finish: + + /* Don't bother checking whether freezer_test_done is true */ + freezer_test_done = false; + + Free_bitmaps: free_basic_memory_bitmaps(); + Enable_umh: usermodehelper_enable(); Exit: pm_notifier_call_chain(PM_POST_HIBERNATION); diff --git a/kernel/power/main.c b/kernel/power/main.c index 9824b41e5a18..1c12581f1c62 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -165,16 +165,20 @@ static int suspend_stats_show(struct seq_file *s, void *unused) last_errno %= REC_FAILED_NUM; last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; last_step %= REC_FAILED_NUM; - seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n" - "%s: %d\n%s: %d\n%s: %d\n%s: %d\n", + seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" + "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", "success", suspend_stats.success, "fail", suspend_stats.fail, "failed_freeze", suspend_stats.failed_freeze, "failed_prepare", suspend_stats.failed_prepare, "failed_suspend", suspend_stats.failed_suspend, + "failed_suspend_late", + suspend_stats.failed_suspend_late, "failed_suspend_noirq", suspend_stats.failed_suspend_noirq, "failed_resume", suspend_stats.failed_resume, + "failed_resume_early", + suspend_stats.failed_resume_early, "failed_resume_noirq", suspend_stats.failed_resume_noirq); seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", @@ -287,16 +291,10 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, #ifdef CONFIG_SUSPEND for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { - if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) + if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { + error = pm_suspend(state); break; - } - if (state < PM_SUSPEND_MAX && *s) { - error = enter_state(state); - if (error) { - suspend_stats.fail++; - dpm_save_failed_errno(error); - } else - suspend_stats.success++; + } } #endif diff --git a/kernel/power/power.h b/kernel/power/power.h index 21724eee5206..98f3622d7407 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -177,13 +177,11 @@ extern const char *const pm_states[]; extern bool valid_state(suspend_state_t state); extern int suspend_devices_and_enter(suspend_state_t state); -extern int enter_state(suspend_state_t state); #else /* !CONFIG_SUSPEND */ static inline int suspend_devices_and_enter(suspend_state_t state) { return -ENOSYS; } -static inline int enter_state(suspend_state_t state) { return -ENOSYS; } static inline bool valid_state(suspend_state_t state) { return false; } #endif /* !CONFIG_SUSPEND */ @@ -234,16 +232,14 @@ static inline int suspend_freeze_processes(void) int error; error = freeze_processes(); - /* * freeze_processes() automatically thaws every task if freezing * fails. So we need not do anything extra upon error. */ if (error) - goto Finish; + return error; error = freeze_kernel_threads(); - /* * freeze_kernel_threads() thaws only kernel threads upon freezing * failure. So we have to thaw the userspace tasks ourselves. @@ -251,7 +247,6 @@ static inline int suspend_freeze_processes(void) if (error) thaw_processes(); - Finish: return error; } diff --git a/kernel/power/process.c b/kernel/power/process.c index 7e426459e60a..0d2aeb226108 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -53,11 +53,9 @@ static int try_to_freeze_tasks(bool user_only) * It is "frozen enough". If the task does wake * up, it will immediately call try_to_freeze. * - * Because freeze_task() goes through p's - * scheduler lock after setting TIF_FREEZE, it's - * guaranteed that either we see TASK_RUNNING or - * try_to_stop() after schedule() in ptrace/signal - * stop sees TIF_FREEZE. + * Because freeze_task() goes through p's scheduler lock, it's + * guaranteed that TASK_STOPPED/TRACED -> TASK_RUNNING + * transition can't race with task state testing here. */ if (!task_is_stopped_or_traced(p) && !freezer_should_skip(p)) @@ -98,13 +96,15 @@ static int try_to_freeze_tasks(bool user_only) elapsed_csecs / 100, elapsed_csecs % 100, todo - wq_busy, wq_busy); - read_lock(&tasklist_lock); - do_each_thread(g, p) { - if (!wakeup && !freezer_should_skip(p) && - p != current && freezing(p) && !frozen(p)) - sched_show_task(p); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); + if (!wakeup) { + read_lock(&tasklist_lock); + do_each_thread(g, p) { + if (p != current && !freezer_should_skip(p) + && freezing(p) && !frozen(p)) + sched_show_task(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); + } } else { printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, elapsed_csecs % 100); diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 995e3bd3417b..d6d6dbd1ecc0 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -469,21 +469,18 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, static int __init pm_qos_power_init(void) { int ret = 0; + int i; - ret = register_pm_qos_misc(&cpu_dma_pm_qos); - if (ret < 0) { - printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n"); - return ret; - } - ret = register_pm_qos_misc(&network_lat_pm_qos); - if (ret < 0) { - printk(KERN_ERR "pm_qos_param: network_latency setup failed\n"); - return ret; + BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); + + for (i = 1; i < PM_QOS_NUM_CLASSES; i++) { + ret = register_pm_qos_misc(pm_qos_array[i]); + if (ret < 0) { + printk(KERN_ERR "pm_qos_param: %s setup failed\n", + pm_qos_array[i]->name); + return ret; + } } - ret = register_pm_qos_misc(&network_throughput_pm_qos); - if (ret < 0) - printk(KERN_ERR - "pm_qos_param: network_throughput setup failed\n"); return ret; } diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 6a768e537001..0de28576807d 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -711,9 +711,10 @@ static void mark_nosave_pages(struct memory_bitmap *bm) list_for_each_entry(region, &nosave_regions, list) { unsigned long pfn; - pr_debug("PM: Marking nosave pages: %016lx - %016lx\n", - region->start_pfn << PAGE_SHIFT, - region->end_pfn << PAGE_SHIFT); + pr_debug("PM: Marking nosave pages: [mem %#010llx-%#010llx]\n", + (unsigned long long) region->start_pfn << PAGE_SHIFT, + ((unsigned long long) region->end_pfn << PAGE_SHIFT) + - 1); for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++) if (pfn_valid(pfn)) { @@ -1000,20 +1001,20 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) s_page = pfn_to_page(src_pfn); d_page = pfn_to_page(dst_pfn); if (PageHighMem(s_page)) { - src = kmap_atomic(s_page, KM_USER0); - dst = kmap_atomic(d_page, KM_USER1); + src = kmap_atomic(s_page); + dst = kmap_atomic(d_page); do_copy_page(dst, src); - kunmap_atomic(dst, KM_USER1); - kunmap_atomic(src, KM_USER0); + kunmap_atomic(dst); + kunmap_atomic(src); } else { if (PageHighMem(d_page)) { /* Page pointed to by src may contain some kernel * data modified by kmap_atomic() */ safe_copy_page(buffer, s_page); - dst = kmap_atomic(d_page, KM_USER0); + dst = kmap_atomic(d_page); copy_page(dst, buffer); - kunmap_atomic(dst, KM_USER0); + kunmap_atomic(dst); } else { safe_copy_page(page_address(d_page), s_page); } @@ -1728,9 +1729,9 @@ int snapshot_read_next(struct snapshot_handle *handle) */ void *kaddr; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); copy_page(buffer, kaddr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); handle->buffer = buffer; } else { handle->buffer = page_address(page); @@ -2014,9 +2015,9 @@ static void copy_last_highmem_page(void) if (last_highmem_page) { void *dst; - dst = kmap_atomic(last_highmem_page, KM_USER0); + dst = kmap_atomic(last_highmem_page); copy_page(dst, buffer); - kunmap_atomic(dst, KM_USER0); + kunmap_atomic(dst); last_highmem_page = NULL; } } @@ -2309,13 +2310,13 @@ swap_two_pages_data(struct page *p1, struct page *p2, void *buf) { void *kaddr1, *kaddr2; - kaddr1 = kmap_atomic(p1, KM_USER0); - kaddr2 = kmap_atomic(p2, KM_USER1); + kaddr1 = kmap_atomic(p1); + kaddr2 = kmap_atomic(p2); copy_page(buf, kaddr1); copy_page(kaddr1, kaddr2); copy_page(kaddr2, buf); - kunmap_atomic(kaddr2, KM_USER1); - kunmap_atomic(kaddr1, KM_USER0); + kunmap_atomic(kaddr2); + kunmap_atomic(kaddr1); } /** diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 4fd51beed879..88e5c967370d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -37,8 +37,8 @@ const char *const pm_states[PM_SUSPEND_MAX] = { static const struct platform_suspend_ops *suspend_ops; /** - * suspend_set_ops - Set the global suspend method table. - * @ops: Pointer to ops structure. + * suspend_set_ops - Set the global suspend method table. + * @ops: Suspend operations to use. */ void suspend_set_ops(const struct platform_suspend_ops *ops) { @@ -58,11 +58,11 @@ bool valid_state(suspend_state_t state) } /** - * suspend_valid_only_mem - generic memory-only valid callback + * suspend_valid_only_mem - Generic memory-only valid callback. * - * Platform drivers that implement mem suspend only and only need - * to check for that in their .valid callback can use this instead - * of rolling their own .valid callback. + * Platform drivers that implement mem suspend only and only need to check for + * that in their .valid() callback can use this instead of rolling their own + * .valid() callback. */ int suspend_valid_only_mem(suspend_state_t state) { @@ -83,10 +83,11 @@ static int suspend_test(int level) } /** - * suspend_prepare - Do prep work before entering low-power state. + * suspend_prepare - Prepare for entering system sleep state. * - * This is common code that is called for each state that we're entering. - * Run suspend notifiers, allocate a console and stop all processes. + * Common code run for every system sleep state that can be entered (except for + * hibernation). Run suspend notifiers, allocate the "suspend" console and + * freeze processes. */ static int suspend_prepare(void) { @@ -131,9 +132,9 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) } /** - * suspend_enter - enter the desired system sleep state. - * @state: State to enter - * @wakeup: Returns information that suspend should not be entered again. + * suspend_enter - Make the system enter the given sleep state. + * @state: System sleep state to enter. + * @wakeup: Returns information that the sleep state should not be re-entered. * * This function should be called after devices have been suspended. */ @@ -147,7 +148,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) goto Platform_finish; } - error = dpm_suspend_noirq(PMSG_SUSPEND); + error = dpm_suspend_end(PMSG_SUSPEND); if (error) { printk(KERN_ERR "PM: Some devices failed to power down\n"); goto Platform_finish; @@ -189,7 +190,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (suspend_ops->wake) suspend_ops->wake(); - dpm_resume_noirq(PMSG_RESUME); + dpm_resume_start(PMSG_RESUME); Platform_finish: if (suspend_ops->finish) @@ -199,9 +200,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) } /** - * suspend_devices_and_enter - suspend devices and enter the desired system - * sleep state. - * @state: state to enter + * suspend_devices_and_enter - Suspend devices and enter system sleep state. + * @state: System sleep state to enter. */ int suspend_devices_and_enter(suspend_state_t state) { @@ -251,10 +251,10 @@ int suspend_devices_and_enter(suspend_state_t state) } /** - * suspend_finish - Do final work before exiting suspend sequence. + * suspend_finish - Clean up before finishing the suspend sequence. * - * Call platform code to clean up, restart processes, and free the - * console that we've allocated. This is not called for suspend-to-disk. + * Call platform code to clean up, restart processes, and free the console that + * we've allocated. This routine is not called for hibernation. */ static void suspend_finish(void) { @@ -265,16 +265,14 @@ static void suspend_finish(void) } /** - * enter_state - Do common work of entering low-power state. - * @state: pm_state structure for state we're entering. + * enter_state - Do common work needed to enter system sleep state. + * @state: System sleep state to enter. * - * Make sure we're the only ones trying to enter a sleep state. Fail - * if someone has beat us to it, since we don't want anything weird to - * happen when we wake up. - * Then, do the setup for suspend, enter the state, and cleaup (after - * we've woken up). + * Make sure that no one else is trying to put the system into a sleep state. + * Fail if that's not the case. Otherwise, prepare for system suspend, make the + * system enter the given sleep state and clean up after wakeup. */ -int enter_state(suspend_state_t state) +static int enter_state(suspend_state_t state) { int error; @@ -310,24 +308,26 @@ int enter_state(suspend_state_t state) } /** - * pm_suspend - Externally visible function for suspending system. - * @state: Enumerated value of state to enter. + * pm_suspend - Externally visible function for suspending the system. + * @state: System sleep state to enter. * - * Determine whether or not value is within range, get state - * structure, and enter (above). + * Check if the value of @state represents one of the supported states, + * execute enter_state() and update system suspend statistics. */ int pm_suspend(suspend_state_t state) { - int ret; - if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) { - ret = enter_state(state); - if (ret) { - suspend_stats.fail++; - dpm_save_failed_errno(ret); - } else - suspend_stats.success++; - return ret; + int error; + + if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) + return -EINVAL; + + error = enter_state(state); + if (error) { + suspend_stats.fail++; + dpm_save_failed_errno(error); + } else { + suspend_stats.success++; } - return -EINVAL; + return error; } EXPORT_SYMBOL(pm_suspend); diff --git a/kernel/power/user.c b/kernel/power/user.c index 3e100075b13c..33c4329205af 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -249,16 +249,10 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, } pm_restore_gfp_mask(); error = hibernation_snapshot(data->platform_support); - if (error) { - thaw_kernel_threads(); - } else { + if (!error) { error = put_user(in_suspend, (int __user *)arg); - if (!error && !freezer_test_done) - data->ready = 1; - if (freezer_test_done) { - freezer_test_done = false; - thaw_kernel_threads(); - } + data->ready = !freezer_test_done && !error; + freezer_test_done = false; } break; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a35cb8dbd8c4..503d6426126d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -71,6 +71,7 @@ #include <linux/ftrace.h> #include <linux/slab.h> #include <linux/init_task.h> +#include <linux/binfmts.h> #include <asm/tlb.h> #include <asm/irq_regs.h> diff --git a/kernel/sysctl.c b/kernel/sysctl.c index f487f257e05e..11d53046b905 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -58,6 +58,7 @@ #include <linux/oom.h> #include <linux/kmod.h> #include <linux/capability.h> +#include <linux/binfmts.h> #include <asm/uaccess.h> #include <asm/processor.h> diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 4ceb05d772ae..33b2cbb97380 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -390,7 +390,7 @@ bool sg_miter_next(struct sg_mapping_iter *miter) miter->consumed = miter->length; if (miter->__flags & SG_MITER_ATOMIC) - miter->addr = kmap_atomic(miter->page, KM_BIO_SRC_IRQ) + off; + miter->addr = kmap_atomic(miter->page) + off; else miter->addr = kmap(miter->page) + off; @@ -424,7 +424,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter) if (miter->__flags & SG_MITER_ATOMIC) { WARN_ON(!irqs_disabled()); - kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ); + kunmap_atomic(miter->addr); } else kunmap(miter->page); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 058935ef3975..d0f6315f4a24 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -349,13 +349,12 @@ void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size, sz = min_t(size_t, PAGE_SIZE - offset, size); local_irq_save(flags); - buffer = kmap_atomic(pfn_to_page(pfn), - KM_BOUNCE_READ); + buffer = kmap_atomic(pfn_to_page(pfn)); if (dir == DMA_TO_DEVICE) memcpy(dma_addr, buffer + offset, sz); else memcpy(buffer + offset, dma_addr, sz); - kunmap_atomic(buffer, KM_BOUNCE_READ); + kunmap_atomic(buffer); local_irq_restore(flags); size -= sz; diff --git a/mm/bounce.c b/mm/bounce.c index 4e9ae722af83..d1be02ca1889 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -50,9 +50,9 @@ static void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom) unsigned char *vto; local_irq_save(flags); - vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ); + vto = kmap_atomic(to->bv_page); memcpy(vto + to->bv_offset, vfrom, to->bv_len); - kunmap_atomic(vto, KM_BOUNCE_READ); + kunmap_atomic(vto); local_irq_restore(flags); } diff --git a/mm/filemap.c b/mm/filemap.c index b66275757c28..2f8165075a5a 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1318,10 +1318,10 @@ int file_read_actor(read_descriptor_t *desc, struct page *page, * taking the kmap. */ if (!fault_in_pages_writeable(desc->arg.buf, size)) { - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); left = __copy_to_user_inatomic(desc->arg.buf, kaddr + offset, size); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); if (left == 0) goto success; } @@ -2045,7 +2045,7 @@ size_t iov_iter_copy_from_user_atomic(struct page *page, size_t copied; BUG_ON(!in_atomic()); - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); if (likely(i->nr_segs == 1)) { int left; char __user *buf = i->iov->iov_base + i->iov_offset; @@ -2055,7 +2055,7 @@ size_t iov_iter_copy_from_user_atomic(struct page *page, copied = __iovec_copy_from_user_inatomic(kaddr + offset, i->iov, i->iov_offset, bytes); } - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); return copied; } @@ -672,9 +672,9 @@ error: static u32 calc_checksum(struct page *page) { u32 checksum; - void *addr = kmap_atomic(page, KM_USER0); + void *addr = kmap_atomic(page); checksum = jhash2(addr, PAGE_SIZE / 4, 17); - kunmap_atomic(addr, KM_USER0); + kunmap_atomic(addr); return checksum; } @@ -683,11 +683,11 @@ static int memcmp_pages(struct page *page1, struct page *page2) char *addr1, *addr2; int ret; - addr1 = kmap_atomic(page1, KM_USER0); - addr2 = kmap_atomic(page2, KM_USER1); + addr1 = kmap_atomic(page1); + addr2 = kmap_atomic(page2); ret = memcmp(addr1, addr2, PAGE_SIZE); - kunmap_atomic(addr2, KM_USER1); - kunmap_atomic(addr1, KM_USER0); + kunmap_atomic(addr2); + kunmap_atomic(addr1); return ret; } diff --git a/mm/memory.c b/mm/memory.c index fa2f04e0337c..347e5fad1cfa 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2447,7 +2447,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo * fails, we just zero-fill it. Live with it. */ if (unlikely(!src)) { - void *kaddr = kmap_atomic(dst, KM_USER0); + void *kaddr = kmap_atomic(dst); void __user *uaddr = (void __user *)(va & PAGE_MASK); /* @@ -2458,7 +2458,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo */ if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) clear_page(kaddr); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); flush_dcache_page(dst); } else copy_user_highpage(dst, src, va, vma); diff --git a/mm/mmap.c b/mm/mmap.c index da15a79b1441..39a68ddf38bd 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -936,6 +936,19 @@ void vm_stat_account(struct mm_struct *mm, unsigned long flags, #endif /* CONFIG_PROC_FS */ /* + * If a hint addr is less than mmap_min_addr change hint to be as + * low as possible but still greater than mmap_min_addr + */ +static inline unsigned long round_hint_to_min(unsigned long hint) +{ + hint &= PAGE_MASK; + if (((void *)hint != NULL) && + (hint < mmap_min_addr)) + return PAGE_ALIGN(mmap_min_addr); + return hint; +} + +/* * The caller must hold down_write(¤t->mm->mmap_sem). */ @@ -1235,7 +1248,7 @@ munmap_back: */ if (accountable_mapping(file, vm_flags)) { charged = len >> PAGE_SHIFT; - if (security_vm_enough_memory(charged)) + if (security_vm_enough_memory_mm(mm, charged)) return -ENOMEM; vm_flags |= VM_ACCOUNT; } @@ -2180,7 +2193,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) if (mm->map_count > sysctl_max_map_count) return -ENOMEM; - if (security_vm_enough_memory(len >> PAGE_SHIFT)) + if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT)) return -ENOMEM; /* Can we just expand an old private anonymous mapping? */ diff --git a/mm/mprotect.c b/mm/mprotect.c index f437d054c3bf..142ef4a1f480 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -168,7 +168,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_HUGETLB| VM_SHARED|VM_NORESERVE))) { charged = nrpages; - if (security_vm_enough_memory(charged)) + if (security_vm_enough_memory_mm(mm, charged)) return -ENOMEM; newflags |= VM_ACCOUNT; } diff --git a/mm/mremap.c b/mm/mremap.c index 87bb8393e7d2..db8d983b5a7d 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -329,7 +329,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, if (vma->vm_flags & VM_ACCOUNT) { unsigned long charged = (new_len - old_len) >> PAGE_SHIFT; - if (security_vm_enough_memory(charged)) + if (security_vm_enough_memory_mm(mm, charged)) goto Efault; *p = charged; } diff --git a/mm/shmem.c b/mm/shmem.c index 269d049294ab..78307d5c5bd9 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -127,7 +127,7 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb) static inline int shmem_acct_size(unsigned long flags, loff_t size) { return (flags & VM_NORESERVE) ? - 0 : security_vm_enough_memory_kern(VM_ACCT(size)); + 0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size)); } static inline void shmem_unacct_size(unsigned long flags, loff_t size) @@ -145,7 +145,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size) static inline int shmem_acct_block(unsigned long flags) { return (flags & VM_NORESERVE) ? - security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0; + security_vm_enough_memory_mm(current->mm, VM_ACCT(PAGE_CACHE_SIZE)) : 0; } static inline void shmem_unacct_blocks(unsigned long flags, long pages) @@ -1656,9 +1656,9 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s } inode->i_mapping->a_ops = &shmem_aops; inode->i_op = &shmem_symlink_inode_operations; - kaddr = kmap_atomic(page, KM_USER0); + kaddr = kmap_atomic(page); memcpy(kaddr, symname, len); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); set_page_dirty(page); unlock_page(page); page_cache_release(page); diff --git a/mm/swapfile.c b/mm/swapfile.c index d999f090dfda..6bf67ab6e469 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1563,6 +1563,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (!capable(CAP_SYS_ADMIN)) return -EPERM; + BUG_ON(!current->mm); + pathname = getname(specialfile); err = PTR_ERR(pathname); if (IS_ERR(pathname)) @@ -1590,7 +1592,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_unlock(&swap_lock); goto out_dput; } - if (!security_vm_enough_memory(p->pages)) + if (!security_vm_enough_memory_mm(current->mm, p->pages)) vm_unacct_memory(p->pages); else { err = -ENOMEM; @@ -2427,9 +2429,9 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask) if (!(count & COUNT_CONTINUED)) goto out; - map = kmap_atomic(list_page, KM_USER0) + offset; + map = kmap_atomic(list_page) + offset; count = *map; - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); /* * If this continuation count now has some space in it, @@ -2472,7 +2474,7 @@ static bool swap_count_continued(struct swap_info_struct *si, offset &= ~PAGE_MASK; page = list_entry(head->lru.next, struct page, lru); - map = kmap_atomic(page, KM_USER0) + offset; + map = kmap_atomic(page) + offset; if (count == SWAP_MAP_MAX) /* initial increment from swap_map */ goto init_map; /* jump over SWAP_CONT_MAX checks */ @@ -2482,26 +2484,26 @@ static bool swap_count_continued(struct swap_info_struct *si, * Think of how you add 1 to 999 */ while (*map == (SWAP_CONT_MAX | COUNT_CONTINUED)) { - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.next, struct page, lru); BUG_ON(page == head); - map = kmap_atomic(page, KM_USER0) + offset; + map = kmap_atomic(page) + offset; } if (*map == SWAP_CONT_MAX) { - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.next, struct page, lru); if (page == head) return false; /* add count continuation */ - map = kmap_atomic(page, KM_USER0) + offset; + map = kmap_atomic(page) + offset; init_map: *map = 0; /* we didn't zero the page */ } *map += 1; - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.prev, struct page, lru); while (page != head) { - map = kmap_atomic(page, KM_USER0) + offset; + map = kmap_atomic(page) + offset; *map = COUNT_CONTINUED; - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.prev, struct page, lru); } return true; /* incremented */ @@ -2512,22 +2514,22 @@ init_map: *map = 0; /* we didn't zero the page */ */ BUG_ON(count != COUNT_CONTINUED); while (*map == COUNT_CONTINUED) { - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.next, struct page, lru); BUG_ON(page == head); - map = kmap_atomic(page, KM_USER0) + offset; + map = kmap_atomic(page) + offset; } BUG_ON(*map == 0); *map -= 1; if (*map == 0) count = 0; - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.prev, struct page, lru); while (page != head) { - map = kmap_atomic(page, KM_USER0) + offset; + map = kmap_atomic(page) + offset; *map = SWAP_CONT_MAX | count; count = COUNT_CONTINUED; - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); page = list_entry(page->lru.prev, struct page, lru); } return count == COUNT_CONTINUED; diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 86ce9a526c17..94dff883b449 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1906,9 +1906,9 @@ static int aligned_vread(char *buf, char *addr, unsigned long count) * we can expect USER0 is not used (see vread/vwrite's * function description) */ - void *map = kmap_atomic(p, KM_USER0); + void *map = kmap_atomic(p); memcpy(buf, map + offset, length); - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); } else memset(buf, 0, length); @@ -1945,9 +1945,9 @@ static int aligned_vwrite(char *buf, char *addr, unsigned long count) * we can expect USER0 is not used (see vread/vwrite's * function description) */ - void *map = kmap_atomic(p, KM_USER0); + void *map = kmap_atomic(p); memcpy(map + offset, buf, length); - kunmap_atomic(map, KM_USER0); + kunmap_atomic(map); } addr += length; buf += length; diff --git a/net/core/dev.c b/net/core/dev.c index 0f3eb7d79a2d..452db7090d18 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3560,7 +3560,8 @@ EXPORT_SYMBOL(napi_gro_receive); static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) { __skb_pull(skb, skb_headlen(skb)); - skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb)); + /* restore the reserve we had after netdev_alloc_skb_ip_align() */ + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb)); skb->vlan_tci = 0; skb->dev = napi->dev; skb->skb_iif = 0; diff --git a/net/core/kmap_skb.h b/net/core/kmap_skb.h index 81e1ed7c8383..52d0a4459041 100644 --- a/net/core/kmap_skb.h +++ b/net/core/kmap_skb.h @@ -7,12 +7,12 @@ static inline void *kmap_skb_frag(const skb_frag_t *frag) local_bh_disable(); #endif - return kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ); + return kmap_atomic(skb_frag_page(frag)); } static inline void kunmap_skb_frag(void *vaddr) { - kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + kunmap_atomic(vaddr); #ifdef CONFIG_HIGHMEM local_bh_enable(); #endif diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6eb656acdfe5..a690cae91cdd 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -321,12 +321,12 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, EXPORT_SYMBOL(__netdev_alloc_skb); void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, - int size) + int size, unsigned int truesize) { skb_fill_page_desc(skb, i, page, off, size); skb->len += size; skb->data_len += size; - skb->truesize += size; + skb->truesize += truesize; } EXPORT_SYMBOL(skb_add_rx_frag); diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index fa000d26dc60..c73bba326d70 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -281,6 +281,7 @@ static int __init init_dns_resolver(void) /* instruct request_key() to use this special keyring as a cache for * the results it looks up */ + set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; dns_resolver_cache = cred; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e41c40f48cfe..d4fad5c77447 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1079,6 +1079,7 @@ __be32 inet_confirm_addr(struct in_device *in_dev, return addr; } +EXPORT_SYMBOL(inet_confirm_addr); /* * Device notifier diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 0e58f09e59fb..851acec852d2 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -52,7 +52,7 @@ iptable_filter_hook(unsigned int hook, struct sk_buff *skb, static struct nf_hook_ops *filter_ops __read_mostly; /* Default to forward because I got too much mail already. */ -static bool forward = NF_ACCEPT; +static bool forward = true; module_param(forward, bool, 0000); static int __net_init iptable_filter_net_init(struct net *net) @@ -64,7 +64,7 @@ static int __net_init iptable_filter_net_init(struct net *net) return -ENOMEM; /* Entry 1 is the FORWARD hook */ ((struct ipt_standard *)repl->entries)[1].target.verdict = - -forward - 1; + forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; net->ipv4.iptable_filter = ipt_register_table(net, &packet_filter, repl); @@ -88,11 +88,6 @@ static int __init iptable_filter_init(void) { int ret; - if (forward < 0 || forward > NF_MAX_VERDICT) { - pr_err("iptables forward must be 0 or 1\n"); - return -EINVAL; - } - ret = register_pernet_subsys(&iptable_filter_net_ops); if (ret < 0) return ret; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index a8f6da97e3b2..325e59a0224f 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -44,7 +44,7 @@ ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, static struct nf_hook_ops *filter_ops __read_mostly; /* Default to forward because I got too much mail already. */ -static bool forward = NF_ACCEPT; +static bool forward = true; module_param(forward, bool, 0000); static int __net_init ip6table_filter_net_init(struct net *net) @@ -56,7 +56,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) return -ENOMEM; /* Entry 1 is the FORWARD hook */ ((struct ip6t_standard *)repl->entries)[1].target.verdict = - -forward - 1; + forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; net->ipv6.ip6table_filter = ip6t_register_table(net, &packet_filter, repl); @@ -80,11 +80,6 @@ static int __init ip6table_filter_init(void) { int ret; - if (forward < 0 || forward > NF_MAX_VERDICT) { - pr_err("iptables forward must be 0 or 1\n"); - return -EINVAL; - } - ret = register_pernet_subsys(&ip6table_filter_net_ops); if (ret < 0) return ret; diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 9b071910b4ba..1addd9f3f40a 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -1845,3 +1845,4 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("PPP over L2TP over UDP"); MODULE_LICENSE("GPL"); MODULE_VERSION(PPPOL2TP_DRV_VERSION); +MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP)); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7b48035826ee..cbdb754dbb10 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -768,8 +768,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, struct sk_buff *skb, - unsigned int dataoff, u32 hash, - unsigned int *timeouts) + unsigned int dataoff, u32 hash) { struct nf_conn *ct; struct nf_conn_help *help; @@ -777,6 +776,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_ecache *ecache; struct nf_conntrack_expect *exp; u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; + struct nf_conn_timeout *timeout_ext; + unsigned int *timeouts; if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { pr_debug("Can't invert tuple.\n"); @@ -788,12 +789,21 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, if (IS_ERR(ct)) return (struct nf_conntrack_tuple_hash *)ct; + timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL; + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + if (!l4proto->new(ct, skb, dataoff, timeouts)) { nf_conntrack_free(ct); pr_debug("init conntrack: can't track with proto module\n"); return NULL; } + if (timeout_ext) + nf_ct_timeout_ext_add(ct, timeout_ext->timeout, GFP_ATOMIC); + nf_ct_acct_ext_add(ct, GFP_ATOMIC); nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); @@ -854,8 +864,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l4proto *l4proto, int *set_reply, - enum ip_conntrack_info *ctinfo, - unsigned int *timeouts) + enum ip_conntrack_info *ctinfo) { struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_hash *h; @@ -875,7 +884,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, h = __nf_conntrack_find_get(net, zone, &tuple, hash); if (!h) { h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, - skb, dataoff, hash, timeouts); + skb, dataoff, hash); if (!h) return NULL; if (IS_ERR(h)) @@ -964,19 +973,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, goto out; } - /* Decide what timeout policy we want to apply to this flow. */ - if (tmpl) { - timeout_ext = nf_ct_timeout_find(tmpl); - if (timeout_ext) - timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); - else - timeouts = l4proto->get_timeouts(net); - } else - timeouts = l4proto->get_timeouts(net); - ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, - l3proto, l4proto, &set_reply, &ctinfo, - timeouts); + l3proto, l4proto, &set_reply, &ctinfo); if (!ct) { /* Not valid part of a connection */ NF_CT_STAT_INC_ATOMIC(net, invalid); @@ -993,6 +991,13 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, NF_CT_ASSERT(skb->nfct); + /* Decide what timeout policy we want to apply to this flow. */ + timeout_ext = nf_ct_timeout_find(ct); + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); if (ret <= 0) { /* Invalid: inverse of the return code tells diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 5701c8dd783c..be3da2c8cdc5 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -127,6 +127,27 @@ void nf_ct_l3proto_module_put(unsigned short l3proto) } EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); +struct nf_conntrack_l4proto * +nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) +{ + struct nf_conntrack_l4proto *p; + + rcu_read_lock(); + p = __nf_ct_l4proto_find(l3num, l4num); + if (!try_module_get(p->me)) + p = &nf_conntrack_l4proto_generic; + rcu_read_unlock(); + + return p; +} +EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); + +void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) +{ + module_put(p->me); +} +EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); + static int kill_l3proto(struct nf_conn *i, void *data) { return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index fec29a43de4d..2b9e79f5ef05 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c @@ -98,11 +98,13 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, break; } - l4proto = __nf_ct_l4proto_find(l3num, l4num); + l4proto = nf_ct_l4proto_find_get(l3num, l4num); /* This protocol is not supportted, skip. */ - if (l4proto->l4proto != l4num) - return -EOPNOTSUPP; + if (l4proto->l4proto != l4num) { + ret = -EOPNOTSUPP; + goto err_proto_put; + } if (matching) { if (nlh->nlmsg_flags & NLM_F_REPLACE) { @@ -110,20 +112,25 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, * different kind, sorry. */ if (matching->l3num != l3num || - matching->l4num != l4num) - return -EINVAL; + matching->l4proto->l4proto != l4num) { + ret = -EINVAL; + goto err_proto_put; + } ret = ctnl_timeout_parse_policy(matching, l4proto, cda[CTA_TIMEOUT_DATA]); return ret; } - return -EBUSY; + ret = -EBUSY; + goto err_proto_put; } timeout = kzalloc(sizeof(struct ctnl_timeout) + l4proto->ctnl_timeout.obj_size, GFP_KERNEL); - if (timeout == NULL) - return -ENOMEM; + if (timeout == NULL) { + ret = -ENOMEM; + goto err_proto_put; + } ret = ctnl_timeout_parse_policy(timeout, l4proto, cda[CTA_TIMEOUT_DATA]); @@ -132,13 +139,15 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); timeout->l3num = l3num; - timeout->l4num = l4num; + timeout->l4proto = l4proto; atomic_set(&timeout->refcnt, 1); list_add_tail_rcu(&timeout->head, &cttimeout_list); return 0; err: kfree(timeout); +err_proto_put: + nf_ct_l4proto_put(l4proto); return ret; } @@ -149,7 +158,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; unsigned int flags = pid ? NLM_F_MULTI : 0; - struct nf_conntrack_l4proto *l4proto; + struct nf_conntrack_l4proto *l4proto = timeout->l4proto; event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); @@ -163,20 +172,10 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); - NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); + NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4proto->l4proto); NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, htonl(atomic_read(&timeout->refcnt))); - l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); - - /* If the timeout object does not match the layer 4 protocol tracker, - * then skip dumping the data part since we don't know how to - * interpret it. This may happen for UPDlite, SCTP and DCCP since - * you can unload the module. - */ - if (timeout->l4num != l4proto->l4proto) - goto out; - if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { struct nlattr *nest_parms; int ret; @@ -192,7 +191,7 @@ ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, nla_nest_end(skb, nest_parms); } -out: + nlmsg_end(skb, nlh); return skb->len; @@ -293,6 +292,7 @@ static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) if (atomic_dec_and_test(&timeout->refcnt)) { /* We are protected by nfnl mutex. */ list_del_rcu(&timeout->head); + nf_ct_l4proto_put(timeout->l4proto); kfree_rcu(timeout, rcu_head); } else { /* still in use, restore reference counter. */ @@ -417,6 +417,7 @@ static void __exit cttimeout_exit(void) /* We are sure that our objects have no clients at this point, * it's safe to release them all without checking refcnt. */ + nf_ct_l4proto_put(cur->l4proto); kfree_rcu(cur, rcu_head); } #ifdef CONFIG_NF_CONNTRACK_TIMEOUT diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index b873445df444..0c8e43810ce3 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -14,8 +14,10 @@ #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_CT.h> #include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_conntrack_ecache.h> +#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_timeout.h> #include <net/netfilter/nf_conntrack_zones.h> @@ -217,50 +219,59 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) struct ctnl_timeout *timeout; struct nf_conn_timeout *timeout_ext; + rcu_read_lock(); timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook); if (timeout_find_get) { const struct ipt_entry *e = par->entryinfo; + struct nf_conntrack_l4proto *l4proto; if (e->ip.invflags & IPT_INV_PROTO) { ret = -EINVAL; pr_info("You cannot use inversion on " "L4 protocol\n"); - goto err3; + goto err4; } timeout = timeout_find_get(info->timeout); if (timeout == NULL) { ret = -ENOENT; pr_info("No such timeout policy \"%s\"\n", info->timeout); - goto err3; + goto err4; } if (timeout->l3num != par->family) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L3 protocol number %d\n", info->timeout, timeout->l3num); - goto err3; + goto err4; } - if (timeout->l4num != e->ip.proto) { + /* Make sure the timeout policy matches any existing + * protocol tracker, otherwise default to generic. + */ + l4proto = __nf_ct_l4proto_find(par->family, + e->ip.proto); + if (timeout->l4proto->l4proto != l4proto->l4proto) { ret = -EINVAL; pr_info("Timeout policy `%s' can only be " "used by L4 protocol number %d\n", - info->timeout, timeout->l4num); - goto err3; + info->timeout, + timeout->l4proto->l4proto); + goto err4; } timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_KERNEL); if (timeout_ext == NULL) { ret = -ENOMEM; - goto err3; + goto err4; } } else { ret = -ENOENT; pr_info("Timeout policy base is empty\n"); - goto err3; + goto err4; } + rcu_read_unlock(); } #endif @@ -270,6 +281,8 @@ out: info->ct = ct; return 0; +err4: + rcu_read_unlock(); err3: nf_conntrack_free(ct); err2: @@ -311,6 +324,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) nf_ct_l3proto_module_put(par->family); #ifdef CONFIG_NF_CONNTRACK_TIMEOUT + rcu_read_lock(); timeout_put = rcu_dereference(nf_ct_timeout_put_hook); if (timeout_put) { @@ -318,6 +332,7 @@ static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) if (timeout_ext) timeout_put(timeout_ext->timeout); } + rcu_read_unlock(); #endif } nf_ct_put(info->ct); diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c index f99f8dee238b..ff5f75fddb15 100644 --- a/net/netfilter/xt_LOG.c +++ b/net/netfilter/xt_LOG.c @@ -480,7 +480,7 @@ ipt_log_packet(u_int8_t pf, sb_close(m); } -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) /* One level of recursion won't kill us */ static void dump_ipv6_packet(struct sbuff *m, const struct nf_loginfo *info, @@ -824,7 +824,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par) if (par->family == NFPROTO_IPV4) ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li, loginfo->prefix); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) else if (par->family == NFPROTO_IPV6) ip6t_log_packet(NFPROTO_IPV6, par->hooknum, skb, par->in, par->out, &li, loginfo->prefix); @@ -864,7 +864,7 @@ static struct xt_target log_tg_regs[] __read_mostly = { .checkentry = log_tg_check, .me = THIS_MODULE, }, -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) { .name = "LOG", .family = NFPROTO_IPV6, @@ -882,7 +882,7 @@ static struct nf_logger ipt_log_logger __read_mostly = { .me = THIS_MODULE, }; -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) static struct nf_logger ip6t_log_logger __read_mostly = { .name = "ip6t_LOG", .logfn = &ip6t_log_packet, @@ -899,7 +899,7 @@ static int __init log_tg_init(void) return ret; nf_log_register(NFPROTO_IPV4, &ipt_log_logger); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) nf_log_register(NFPROTO_IPV6, &ip6t_log_logger); #endif return 0; @@ -908,7 +908,7 @@ static int __init log_tg_init(void) static void __exit log_tg_exit(void) { nf_log_unregister(&ipt_log_logger); -#if IS_ENABLED(CONFIG_IPV6) +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) nf_log_unregister(&ip6t_log_logger); #endif xt_unregister_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs)); diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 2560e7b441c6..7c94aedd0912 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -597,7 +597,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, iter = iter->next; iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; } - ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC); + ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags); } return ret_val; diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 51c868923f64..a1e116277477 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -749,7 +749,7 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp) int ret; /* XXX too lazy? */ - ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL); + ic = kzalloc(sizeof(struct rds_ib_connection), gfp); if (!ic) return -ENOMEM; diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 8d6d9702d1ec..8d194912c695 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -763,7 +763,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off); BUG_ON(to_copy & 7); /* Must be 64bit aligned. */ - addr = kmap_atomic(sg_page(&frag->f_sg), KM_SOFTIRQ0); + addr = kmap_atomic(sg_page(&frag->f_sg)); src = addr + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; @@ -773,7 +773,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, uncongested |= ~(*src) & *dst; *dst++ = *src++; } - kunmap_atomic(addr, KM_SOFTIRQ0); + kunmap_atomic(addr); copied += to_copy; @@ -919,8 +919,7 @@ static void rds_ib_process_recv(struct rds_connection *conn, rds_ib_cong_recv(conn, ibinc); else { rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr, - &ibinc->ii_inc, GFP_ATOMIC, - KM_SOFTIRQ0); + &ibinc->ii_inc, GFP_ATOMIC); state->ack_next = be64_to_cpu(hdr->h_sequence); state->ack_next_valid = 1; } diff --git a/net/rds/info.c b/net/rds/info.c index f1c016c4146e..9a6b4f66187c 100644 --- a/net/rds/info.c +++ b/net/rds/info.c @@ -104,7 +104,7 @@ EXPORT_SYMBOL_GPL(rds_info_deregister_func); void rds_info_iter_unmap(struct rds_info_iterator *iter) { if (iter->addr) { - kunmap_atomic(iter->addr, KM_USER0); + kunmap_atomic(iter->addr); iter->addr = NULL; } } @@ -119,7 +119,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data, while (bytes) { if (!iter->addr) - iter->addr = kmap_atomic(*iter->pages, KM_USER0); + iter->addr = kmap_atomic(*iter->pages); this = min(bytes, PAGE_SIZE - iter->offset); @@ -134,7 +134,7 @@ void rds_info_copy(struct rds_info_iterator *iter, void *data, iter->offset += this; if (iter->offset == PAGE_SIZE) { - kunmap_atomic(iter->addr, KM_USER0); + kunmap_atomic(iter->addr); iter->addr = NULL; iter->offset = 0; iter->pages++; diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c index 9556d2895f7a..a91e1db62ee6 100644 --- a/net/rds/iw_cm.c +++ b/net/rds/iw_cm.c @@ -694,7 +694,7 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp) unsigned long flags; /* XXX too lazy? */ - ic = kzalloc(sizeof(struct rds_iw_connection), GFP_KERNEL); + ic = kzalloc(sizeof(struct rds_iw_connection), gfp); if (!ic) return -ENOMEM; diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 3c8717005018..45033358358e 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c @@ -598,7 +598,7 @@ static void rds_iw_cong_recv(struct rds_connection *conn, to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off); BUG_ON(to_copy & 7); /* Must be 64bit aligned. */ - addr = kmap_atomic(frag->f_page, KM_SOFTIRQ0); + addr = kmap_atomic(frag->f_page); src = addr + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; @@ -608,7 +608,7 @@ static void rds_iw_cong_recv(struct rds_connection *conn, uncongested |= ~(*src) & *dst; *dst++ = *src++; } - kunmap_atomic(addr, KM_SOFTIRQ0); + kunmap_atomic(addr); copied += to_copy; @@ -754,8 +754,7 @@ static void rds_iw_process_recv(struct rds_connection *conn, rds_iw_cong_recv(conn, iwinc); else { rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr, - &iwinc->ii_inc, GFP_ATOMIC, - KM_SOFTIRQ0); + &iwinc->ii_inc, GFP_ATOMIC); state->ack_next = be64_to_cpu(hdr->h_sequence); state->ack_next_valid = 1; } diff --git a/net/rds/loop.c b/net/rds/loop.c index bca6761a3ca2..6b12b68541ae 100644 --- a/net/rds/loop.c +++ b/net/rds/loop.c @@ -79,7 +79,7 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm, rds_message_addref(rm); rds_recv_incoming(conn, conn->c_laddr, conn->c_faddr, &rm->m_inc, - GFP_KERNEL, KM_USER0); + GFP_KERNEL); rds_send_drop_acked(conn, be64_to_cpu(rm->m_inc.i_hdr.h_sequence), NULL); @@ -121,7 +121,7 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp) struct rds_loop_connection *lc; unsigned long flags; - lc = kzalloc(sizeof(struct rds_loop_connection), GFP_KERNEL); + lc = kzalloc(sizeof(struct rds_loop_connection), gfp); if (!lc) return -ENOMEM; diff --git a/net/rds/rds.h b/net/rds/rds.h index 7eaba1831f0d..ec1d731ecff0 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -704,7 +704,7 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn, __be32 saddr); void rds_inc_put(struct rds_incoming *inc); void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr, - struct rds_incoming *inc, gfp_t gfp, enum km_type km); + struct rds_incoming *inc, gfp_t gfp); int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int msg_flags); void rds_clear_recv_queue(struct rds_sock *rs); diff --git a/net/rds/recv.c b/net/rds/recv.c index bc3f8cd6d070..5c6e9f132026 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -155,7 +155,7 @@ static void rds_recv_incoming_exthdrs(struct rds_incoming *inc, struct rds_sock * tell us which roles the addrs in the conn are playing for this message. */ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr, - struct rds_incoming *inc, gfp_t gfp, enum km_type km) + struct rds_incoming *inc, gfp_t gfp) { struct rds_sock *rs = NULL; struct sock *sk; diff --git a/net/rds/tcp_recv.c b/net/rds/tcp_recv.c index 78205e25500a..6243258f840f 100644 --- a/net/rds/tcp_recv.c +++ b/net/rds/tcp_recv.c @@ -169,7 +169,6 @@ static void rds_tcp_cong_recv(struct rds_connection *conn, struct rds_tcp_desc_arg { struct rds_connection *conn; gfp_t gfp; - enum km_type km; }; static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb, @@ -255,7 +254,7 @@ static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb, else rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr, &tinc->ti_inc, - arg->gfp, arg->km); + arg->gfp); tc->t_tinc_hdr_rem = sizeof(struct rds_header); tc->t_tinc_data_rem = 0; @@ -272,8 +271,7 @@ out: } /* the caller has to hold the sock lock */ -static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp, - enum km_type km) +static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp) { struct rds_tcp_connection *tc = conn->c_transport_data; struct socket *sock = tc->t_sock; @@ -283,7 +281,6 @@ static int rds_tcp_read_sock(struct rds_connection *conn, gfp_t gfp, /* It's like glib in the kernel! */ arg.conn = conn; arg.gfp = gfp; - arg.km = km; desc.arg.data = &arg; desc.error = 0; desc.count = 1; /* give more than one skb per call */ @@ -311,7 +308,7 @@ int rds_tcp_recv(struct rds_connection *conn) rdsdebug("recv worker conn %p tc %p sock %p\n", conn, tc, sock); lock_sock(sock->sk); - ret = rds_tcp_read_sock(conn, GFP_KERNEL, KM_USER0); + ret = rds_tcp_read_sock(conn, GFP_KERNEL); release_sock(sock->sk); return ret; @@ -336,7 +333,7 @@ void rds_tcp_data_ready(struct sock *sk, int bytes) ready = tc->t_orig_data_ready; rds_tcp_stats_inc(s_tcp_data_ready_calls); - if (rds_tcp_read_sock(conn, GFP_ATOMIC, KM_SOFTIRQ0) == -ENOMEM) + if (rds_tcp_read_sock(conn, GFP_ATOMIC) == -ENOMEM) queue_delayed_work(rds_wq, &conn->c_recv_w, 0); out: read_unlock_bh(&sk->sk_callback_lock); diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 2763e3e48db4..38f388c39dce 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c @@ -82,9 +82,9 @@ gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize) >>PAGE_CACHE_SHIFT; unsigned int offset = (buf->page_base + len - 1) & (PAGE_CACHE_SIZE - 1); - ptr = kmap_atomic(buf->pages[last], KM_USER0); + ptr = kmap_atomic(buf->pages[last]); pad = *(ptr + offset); - kunmap_atomic(ptr, KM_USER0); + kunmap_atomic(ptr); goto out; } else len -= buf->page_len; diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 145e6784f508..0a648c502fc3 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c @@ -114,7 +114,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct } len = PAGE_CACHE_SIZE; - kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); + kaddr = kmap_atomic(*ppage); if (base) { len -= base; if (pglen < len) @@ -127,7 +127,7 @@ ssize_t xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, struct ret = copy_actor(desc, kaddr, len); } flush_dcache_page(*ppage); - kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); + kunmap_atomic(kaddr); copied += ret; if (ret != len || !desc->count) goto out; diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 593f4c605305..b97a3dd9a60a 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -122,9 +122,9 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len) { char *kaddr; - kaddr = kmap_atomic(buf->pages[0], KM_USER0); + kaddr = kmap_atomic(buf->pages[0]); kaddr[buf->page_base + len] = '\0'; - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } EXPORT_SYMBOL_GPL(xdr_terminate_string); @@ -232,12 +232,12 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base, pgto_base -= copy; pgfrom_base -= copy; - vto = kmap_atomic(*pgto, KM_USER0); - vfrom = kmap_atomic(*pgfrom, KM_USER1); + vto = kmap_atomic(*pgto); + vfrom = kmap_atomic(*pgfrom); memmove(vto + pgto_base, vfrom + pgfrom_base, copy); flush_dcache_page(*pgto); - kunmap_atomic(vfrom, KM_USER1); - kunmap_atomic(vto, KM_USER0); + kunmap_atomic(vfrom); + kunmap_atomic(vto); } while ((len -= copy) != 0); } @@ -267,9 +267,9 @@ _copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len) if (copy > len) copy = len; - vto = kmap_atomic(*pgto, KM_USER0); + vto = kmap_atomic(*pgto); memcpy(vto + pgbase, p, copy); - kunmap_atomic(vto, KM_USER0); + kunmap_atomic(vto); len -= copy; if (len == 0) @@ -311,9 +311,9 @@ _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len) if (copy > len) copy = len; - vfrom = kmap_atomic(*pgfrom, KM_USER0); + vfrom = kmap_atomic(*pgfrom); memcpy(p, vfrom + pgbase, copy); - kunmap_atomic(vfrom, KM_USER0); + kunmap_atomic(vfrom); pgbase += copy; if (pgbase == PAGE_CACHE_SIZE) { diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 554d0814c875..1776e5731dcf 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -338,9 +338,9 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) curlen = copy_len; dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n", __func__, i, destp, copy_len, curlen); - srcp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); + srcp = kmap_atomic(ppages[i]); memcpy(destp, srcp+page_base, curlen); - kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA); + kunmap_atomic(srcp); rqst->rq_svec[0].iov_len += curlen; destp += curlen; copy_len -= curlen; @@ -639,10 +639,10 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) dprintk("RPC: %s: page %d" " srcp 0x%p len %d curlen %d\n", __func__, i, srcp, copy_len, curlen); - destp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); + destp = kmap_atomic(ppages[i]); memcpy(destp + page_base, srcp, curlen); flush_dcache_page(ppages[i]); - kunmap_atomic(destp, KM_SKB_SUNRPC_DATA); + kunmap_atomic(destp); srcp += curlen; copy_len -= curlen; if (copy_len == 0) diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 47bacd8c0250..95a338c89f99 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -21,7 +21,7 @@ static int xfrm_output2(struct sk_buff *skb); -static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) +static int xfrm_skb_check_space(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev) @@ -48,7 +48,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) goto resume; do { - err = xfrm_state_check_space(x, skb); + err = xfrm_skb_check_space(skb); if (err) { XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); goto error_nolock; diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c index 39e02c54ed26..2f6d11d04a2b 100644 --- a/net/xfrm/xfrm_replay.c +++ b/net/xfrm/xfrm_replay.c @@ -167,7 +167,7 @@ static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) } if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb) @@ -279,7 +279,7 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq) replay_esn->bmp[nr] |= (1U << bitnr); if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event) @@ -473,7 +473,7 @@ static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) replay_esn->bmp[nr] |= (1U << bitnr); if (xfrm_aevent_is_on(xs_net(x))) - xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); + x->repl->notify(x, XFRM_REPLAY_UPDATE); } static struct xfrm_replay xfrm_replay_legacy = { diff --git a/security/Kconfig b/security/Kconfig index 51bd5a0b69ae..ccc61f8006b2 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -187,6 +187,7 @@ source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig source security/apparmor/Kconfig +source security/yama/Kconfig source security/integrity/Kconfig @@ -196,6 +197,7 @@ choice default DEFAULT_SECURITY_SMACK if SECURITY_SMACK default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR + default DEFAULT_SECURITY_YAMA if SECURITY_YAMA default DEFAULT_SECURITY_DAC help @@ -214,6 +216,9 @@ choice config DEFAULT_SECURITY_APPARMOR bool "AppArmor" if SECURITY_APPARMOR=y + config DEFAULT_SECURITY_YAMA + bool "Yama" if SECURITY_YAMA=y + config DEFAULT_SECURITY_DAC bool "Unix Discretionary Access Controls" @@ -225,6 +230,7 @@ config DEFAULT_SECURITY default "smack" if DEFAULT_SECURITY_SMACK default "tomoyo" if DEFAULT_SECURITY_TOMOYO default "apparmor" if DEFAULT_SECURITY_APPARMOR + default "yama" if DEFAULT_SECURITY_YAMA default "" if DEFAULT_SECURITY_DAC endmenu diff --git a/security/Makefile b/security/Makefile index a5e502f8a05b..c26c81e92571 100644 --- a/security/Makefile +++ b/security/Makefile @@ -7,6 +7,7 @@ subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_SECURITY_SMACK) += smack subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor +subdir-$(CONFIG_SECURITY_YAMA) += yama # always enable default capabilities obj-y += commoncap.o @@ -21,6 +22,7 @@ obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o +obj-$(CONFIG_SECURITY_YAMA) += yama/built-in.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index 2dafe50a2e25..806bd19af7f2 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -15,7 +15,7 @@ clean-files := capability_names.h rlim_names.h # to # [1] = "dac_override", quiet_cmd_make-caps = GEN $@ -cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\ +cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\ sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \ -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\ echo "};" >> $@ @@ -28,25 +28,38 @@ cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\ # [RLIMIT_STACK] = "stack", # # and build a second integer table (with the second sed cmd), that maps -# RLIMIT defines to the order defined in asm-generic/resource.h Thi is +# RLIMIT defines to the order defined in asm-generic/resource.h This is # required by policy load to map policy ordering of RLIMITs to internal # ordering for architectures that redefine an RLIMIT. # Transforms lines from # #define RLIMIT_STACK 3 /* max stack size */ # to # RLIMIT_STACK, +# +# and build the securityfs entries for the mapping. +# Transforms lines from +# #define RLIMIT_FSIZE 1 /* Maximum filesize */ +# #define RLIMIT_STACK 3 /* max stack size */ +# to +# #define AA_FS_RLIMIT_MASK "fsize stack" quiet_cmd_make-rlim = GEN $@ -cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\ +cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ + > $@ ;\ sed $< >> $@ -r -n \ -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\ echo "};" >> $@ ;\ - echo "static const int rlim_map[] = {" >> $@ ;\ + echo "static const int rlim_map[RLIM_NLIMITS] = {" >> $@ ;\ sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ - echo "};" >> $@ + echo "};" >> $@ ; \ + echo -n '\#define AA_FS_RLIMIT_MASK "' >> $@ ;\ + sed -r -n 's/^\# ?define[ \t]+RLIMIT_([A-Z0-9_]+).*/\L\1/p' $< | \ + tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ $(obj)/capability.o : $(obj)/capability_names.h $(obj)/resource.o : $(obj)/rlim_names.h -$(obj)/capability_names.h : $(srctree)/include/linux/capability.h +$(obj)/capability_names.h : $(srctree)/include/linux/capability.h \ + $(src)/Makefile $(call cmd,make-caps) -$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h +$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \ + $(src)/Makefile $(call cmd,make-rlim) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index e39df6d43779..16c15ec6f670 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -18,12 +18,14 @@ #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/namei.h> +#include <linux/capability.h> #include "include/apparmor.h" #include "include/apparmorfs.h" #include "include/audit.h" #include "include/context.h" #include "include/policy.h" +#include "include/resource.h" /** * aa_simple_write_to_buffer - common routine for getting policy from user @@ -142,38 +144,166 @@ static const struct file_operations aa_fs_profile_remove = { .llseek = default_llseek, }; -/** Base file system setup **/ +static int aa_fs_seq_show(struct seq_file *seq, void *v) +{ + struct aa_fs_entry *fs_file = seq->private; + + if (!fs_file) + return 0; -static struct dentry *aa_fs_dentry __initdata; + switch (fs_file->v_type) { + case AA_FS_TYPE_BOOLEAN: + seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no"); + break; + case AA_FS_TYPE_STRING: + seq_printf(seq, "%s\n", fs_file->v.string); + break; + case AA_FS_TYPE_U64: + seq_printf(seq, "%#08lx\n", fs_file->v.u64); + break; + default: + /* Ignore unpritable entry types. */ + break; + } + + return 0; +} -static void __init aafs_remove(const char *name) +static int aa_fs_seq_open(struct inode *inode, struct file *file) { - struct dentry *dentry; + return single_open(file, aa_fs_seq_show, inode->i_private); +} + +const struct file_operations aa_fs_seq_file_ops = { + .owner = THIS_MODULE, + .open = aa_fs_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** Base file system setup **/ + +static struct aa_fs_entry aa_fs_entry_file[] = { + AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \ + "link lock"), + { } +}; - dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); - if (!IS_ERR(dentry)) { - securityfs_remove(dentry); - dput(dentry); +static struct aa_fs_entry aa_fs_entry_domain[] = { + AA_FS_FILE_BOOLEAN("change_hat", 1), + AA_FS_FILE_BOOLEAN("change_hatv", 1), + AA_FS_FILE_BOOLEAN("change_onexec", 1), + AA_FS_FILE_BOOLEAN("change_profile", 1), + { } +}; + +static struct aa_fs_entry aa_fs_entry_features[] = { + AA_FS_DIR("domain", aa_fs_entry_domain), + AA_FS_DIR("file", aa_fs_entry_file), + AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), + AA_FS_DIR("rlimit", aa_fs_entry_rlimit), + { } +}; + +static struct aa_fs_entry aa_fs_entry_apparmor[] = { + AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), + AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), + AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), + AA_FS_DIR("features", aa_fs_entry_features), + { } +}; + +static struct aa_fs_entry aa_fs_entry = + AA_FS_DIR("apparmor", aa_fs_entry_apparmor); + +/** + * aafs_create_file - create a file entry in the apparmor securityfs + * @fs_file: aa_fs_entry to build an entry for (NOT NULL) + * @parent: the parent dentry in the securityfs + * + * Use aafs_remove_file to remove entries created with this fn. + */ +static int __init aafs_create_file(struct aa_fs_entry *fs_file, + struct dentry *parent) +{ + int error = 0; + + fs_file->dentry = securityfs_create_file(fs_file->name, + S_IFREG | fs_file->mode, + parent, fs_file, + fs_file->file_ops); + if (IS_ERR(fs_file->dentry)) { + error = PTR_ERR(fs_file->dentry); + fs_file->dentry = NULL; } + return error; } /** - * aafs_create - create an entry in the apparmor filesystem - * @name: name of the entry (NOT NULL) - * @mask: file permission mask of the file - * @fops: file operations for the file (NOT NULL) + * aafs_create_dir - recursively create a directory entry in the securityfs + * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL) + * @parent: the parent dentry in the securityfs * - * Used aafs_remove to remove entries created with this fn. + * Use aafs_remove_dir to remove entries created with this fn. */ -static int __init aafs_create(const char *name, umode_t mask, - const struct file_operations *fops) +static int __init aafs_create_dir(struct aa_fs_entry *fs_dir, + struct dentry *parent) { - struct dentry *dentry; + int error; + struct aa_fs_entry *fs_file; - dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, - NULL, fops); + fs_dir->dentry = securityfs_create_dir(fs_dir->name, parent); + if (IS_ERR(fs_dir->dentry)) { + error = PTR_ERR(fs_dir->dentry); + fs_dir->dentry = NULL; + goto failed; + } - return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; + for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { + if (fs_file->v_type == AA_FS_TYPE_DIR) + error = aafs_create_dir(fs_file, fs_dir->dentry); + else + error = aafs_create_file(fs_file, fs_dir->dentry); + if (error) + goto failed; + } + + return 0; + +failed: + return error; +} + +/** + * aafs_remove_file - drop a single file entry in the apparmor securityfs + * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL) + */ +static void __init aafs_remove_file(struct aa_fs_entry *fs_file) +{ + if (!fs_file->dentry) + return; + + securityfs_remove(fs_file->dentry); + fs_file->dentry = NULL; +} + +/** + * aafs_remove_dir - recursively drop a directory entry from the securityfs + * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL) + */ +static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir) +{ + struct aa_fs_entry *fs_file; + + for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { + if (fs_file->v_type == AA_FS_TYPE_DIR) + aafs_remove_dir(fs_file); + else + aafs_remove_file(fs_file); + } + + aafs_remove_file(fs_dir); } /** @@ -183,14 +313,7 @@ static int __init aafs_create(const char *name, umode_t mask, */ void __init aa_destroy_aafs(void) { - if (aa_fs_dentry) { - aafs_remove(".remove"); - aafs_remove(".replace"); - aafs_remove(".load"); - - securityfs_remove(aa_fs_dentry); - aa_fs_dentry = NULL; - } + aafs_remove_dir(&aa_fs_entry); } /** @@ -207,25 +330,13 @@ static int __init aa_create_aafs(void) if (!apparmor_initialized) return 0; - if (aa_fs_dentry) { + if (aa_fs_entry.dentry) { AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); return -EEXIST; } - aa_fs_dentry = securityfs_create_dir("apparmor", NULL); - if (IS_ERR(aa_fs_dentry)) { - error = PTR_ERR(aa_fs_dentry); - aa_fs_dentry = NULL; - goto error; - } - - error = aafs_create(".load", 0640, &aa_fs_profile_load); - if (error) - goto error; - error = aafs_create(".replace", 0640, &aa_fs_profile_replace); - if (error) - goto error; - error = aafs_create(".remove", 0640, &aa_fs_profile_remove); + /* Populate fs tree. */ + error = aafs_create_dir(&aa_fs_entry, NULL); if (error) goto error; diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index f3fafedd798a..5ff67776a5ad 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -19,7 +19,7 @@ #include "include/audit.h" #include "include/policy.h" -const char *op_table[] = { +const char *const op_table[] = { "null", "sysctl", @@ -73,7 +73,7 @@ const char *op_table[] = { "profile_remove" }; -const char *audit_mode_names[] = { +const char *const audit_mode_names[] = { "normal", "quiet_denied", "quiet", @@ -81,7 +81,7 @@ const char *audit_mode_names[] = { "all" }; -static char *aa_audit_type[] = { +static const char *const aa_audit_type[] = { "AUDIT", "ALLOWED", "DENIED", @@ -89,6 +89,7 @@ static char *aa_audit_type[] = { "STATUS", "ERROR", "KILLED" + "AUTO" }; /* diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index c1e18ba5bdc0..7c69599a69e1 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -372,13 +372,12 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) state = profile->file.start; /* buffer freed below, name is pointer into buffer */ - error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer, - &name); + error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer, + &name, &info); if (error) { if (profile->flags & (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED)) error = 0; - info = "Exec failed name resolution"; name = bprm->filename; goto audit; } diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 7312db741219..3022c0f4f0db 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -173,8 +173,6 @@ static u32 map_old_perms(u32 old) if (old & 0x40) /* AA_EXEC_MMAP */ new |= AA_EXEC_MMAP; - new |= AA_MAY_META_READ; - return new; } @@ -212,6 +210,7 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state, perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); perms.xindex = dfa_other_xindex(dfa, state); } + perms.allow |= AA_MAY_META_READ; /* change_profile wasn't determined by ownership in old mapping */ if (ACCEPT_TABLE(dfa)[state] & 0x80000000) @@ -279,22 +278,16 @@ int aa_path_perm(int op, struct aa_profile *profile, struct path *path, int error; flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0); - error = aa_get_name(path, flags, &buffer, &name); + error = aa_path_name(path, flags, &buffer, &name, &info); if (error) { if (error == -ENOENT && is_deleted(path->dentry)) { /* Access to open files that are deleted are * give a pass (implicit delegation) */ error = 0; + info = NULL; perms.allow = request; - } else if (error == -ENOENT) - info = "Failed name lookup - deleted entry"; - else if (error == -ESTALE) - info = "Failed name lookup - disconnected path"; - else if (error == -ENAMETOOLONG) - info = "Failed name lookup - name too long"; - else - info = "Failed name lookup"; + } } else { aa_str_perms(profile->file.dfa, profile->file.start, name, cond, &perms); @@ -365,12 +358,14 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, lperms = nullperms; /* buffer freed below, lname is pointer in buffer */ - error = aa_get_name(&link, profile->path_flags, &buffer, &lname); + error = aa_path_name(&link, profile->path_flags, &buffer, &lname, + &info); if (error) goto audit; /* buffer2 freed below, tname is pointer in buffer2 */ - error = aa_get_name(&target, profile->path_flags, &buffer2, &tname); + error = aa_path_name(&target, profile->path_flags, &buffer2, &tname, + &info); if (error) goto audit; diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index df3649560818..40aedd9f73ea 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -19,6 +19,19 @@ #include "match.h" +/* + * Class of mediation types in the AppArmor policy db + */ +#define AA_CLASS_ENTRY 0 +#define AA_CLASS_UNKNOWN 1 +#define AA_CLASS_FILE 2 +#define AA_CLASS_CAP 3 +#define AA_CLASS_NET 4 +#define AA_CLASS_RLIMITS 5 +#define AA_CLASS_DOMAIN 6 + +#define AA_CLASS_LAST AA_CLASS_DOMAIN + /* Control parameters settable through module/boot flags */ extern enum audit_mode aa_g_audit; extern bool aa_g_audit_header; @@ -81,7 +94,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start) { /* the null transition only needs the string's null terminator byte */ - return aa_dfa_match_len(dfa, start, "", 1); + return aa_dfa_next(dfa, start, 0); } static inline bool mediated_filesystem(struct inode *inode) diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index cb1e93a114d7..7ea4769fab3f 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -15,6 +15,50 @@ #ifndef __AA_APPARMORFS_H #define __AA_APPARMORFS_H +enum aa_fs_type { + AA_FS_TYPE_BOOLEAN, + AA_FS_TYPE_STRING, + AA_FS_TYPE_U64, + AA_FS_TYPE_FOPS, + AA_FS_TYPE_DIR, +}; + +struct aa_fs_entry; + +struct aa_fs_entry { + const char *name; + struct dentry *dentry; + umode_t mode; + enum aa_fs_type v_type; + union { + bool boolean; + char *string; + unsigned long u64; + struct aa_fs_entry *files; + } v; + const struct file_operations *file_ops; +}; + +extern const struct file_operations aa_fs_seq_file_ops; + +#define AA_FS_FILE_BOOLEAN(_name, _value) \ + { .name = (_name), .mode = 0444, \ + .v_type = AA_FS_TYPE_BOOLEAN, .v.boolean = (_value), \ + .file_ops = &aa_fs_seq_file_ops } +#define AA_FS_FILE_STRING(_name, _value) \ + { .name = (_name), .mode = 0444, \ + .v_type = AA_FS_TYPE_STRING, .v.string = (_value), \ + .file_ops = &aa_fs_seq_file_ops } +#define AA_FS_FILE_U64(_name, _value) \ + { .name = (_name), .mode = 0444, \ + .v_type = AA_FS_TYPE_U64, .v.u64 = (_value), \ + .file_ops = &aa_fs_seq_file_ops } +#define AA_FS_FILE_FOPS(_name, _mode, _fops) \ + { .name = (_name), .v_type = AA_FS_TYPE_FOPS, \ + .mode = (_mode), .file_ops = (_fops) } +#define AA_FS_DIR(_name, _value) \ + { .name = (_name), .v_type = AA_FS_TYPE_DIR, .v.files = (_value) } + extern void __init aa_destroy_aafs(void); #endif /* __AA_APPARMORFS_H */ diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 1951786d32e9..4ba78c203af1 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -25,11 +25,9 @@ struct aa_profile; -extern const char *audit_mode_names[]; +extern const char *const audit_mode_names[]; #define AUDIT_MAX_INDEX 5 -#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */ - enum audit_mode { AUDIT_NORMAL, /* follow normal auditing of accesses */ AUDIT_QUIET_DENIED, /* quiet all denied access messages */ @@ -45,10 +43,11 @@ enum audit_type { AUDIT_APPARMOR_HINT, AUDIT_APPARMOR_STATUS, AUDIT_APPARMOR_ERROR, - AUDIT_APPARMOR_KILL + AUDIT_APPARMOR_KILL, + AUDIT_APPARMOR_AUTO }; -extern const char *op_table[]; +extern const char *const op_table[]; enum aa_ops { OP_NULL, diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index ab8c6d87f758..f98fd4701d80 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -117,7 +117,7 @@ static inline u16 dfa_map_xindex(u16 mask) index |= AA_X_NAME; } else if (old_index == 3) { index |= AA_X_NAME | AA_X_CHILD; - } else { + } else if (old_index) { index |= AA_X_TABLE; index |= old_index - 4; } diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index a4a863997bd5..775843e7f984 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -116,6 +116,9 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, const char *str, int len); unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, const char *str); +unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, + const char c); + void aa_dfa_free_kref(struct kref *kref); /** diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h index 27b327a7fae5..286ac75dc88b 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h @@ -26,6 +26,7 @@ enum path_flags { PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ }; -int aa_get_name(struct path *path, int flags, char **buffer, const char **name); +int aa_path_name(struct path *path, int flags, char **buffer, + const char **name, const char **info); #endif /* __AA_PATH_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index aeda5cf56904..bda4569fdd83 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -29,7 +29,7 @@ #include "file.h" #include "resource.h" -extern const char *profile_mode_names[]; +extern const char *const profile_mode_names[]; #define APPARMOR_NAMES_MAX_INDEX 3 #define COMPLAIN_MODE(_profile) \ @@ -129,6 +129,17 @@ struct aa_namespace { struct list_head sub_ns; }; +/* struct aa_policydb - match engine for a policy + * dfa: dfa pattern match + * start: set of start states for the different classes of data + */ +struct aa_policydb { + /* Generic policy DFA specific rule types will be subsections of it */ + struct aa_dfa *dfa; + unsigned int start[AA_CLASS_LAST + 1]; + +}; + /* struct aa_profile - basic confinement data * @base - base components of the profile (name, refcount, lists, lock ...) * @parent: parent of profile @@ -143,6 +154,7 @@ struct aa_namespace { * @flags: flags controlling profile behavior * @path_flags: flags controlling path generation behavior * @size: the memory consumed by this profiles rules + * @policy: general match rules governing policy * @file: The set of rules governing basic file access and domain transitions * @caps: capabilities for the profile * @rlimits: rlimits for the profile @@ -179,6 +191,7 @@ struct aa_profile { u32 path_flags; int size; + struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; struct aa_rlimit rlimits; diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h index 02baec732bb5..d3f4cf027957 100644 --- a/security/apparmor/include/resource.h +++ b/security/apparmor/include/resource.h @@ -18,6 +18,8 @@ #include <linux/resource.h> #include <linux/sched.h> +#include "apparmorfs.h" + struct aa_profile; /* struct aa_rlimit - rlimit settings for the profile @@ -32,6 +34,8 @@ struct aa_rlimit { struct rlimit limits[RLIM_NLIMITS]; }; +extern struct aa_fs_entry aa_fs_entry_rlimit[]; + int aa_map_resource(int resource); int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, unsigned int resource, struct rlimit *new_rlim); diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 94de6b4907c8..90971a8c3789 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -335,12 +335,12 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, } /** - * aa_dfa_next_state - traverse @dfa to find state @str stops at + * aa_dfa_match - traverse @dfa to find state @str stops at * @dfa: the dfa to match @str against (NOT NULL) * @start: the state of the dfa to start matching in * @str: the null terminated string of bytes to match against the dfa (NOT NULL) * - * aa_dfa_next_state will match @str against the dfa and return the state it + * aa_dfa_match will match @str against the dfa and return the state it * finished matching in. The final state can be used to look up the accepting * label, or as the start state of a continuing match. * @@ -349,5 +349,79 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, const char *str) { - return aa_dfa_match_len(dfa, start, str, strlen(str)); + u16 *def = DEFAULT_TABLE(dfa); + u32 *base = BASE_TABLE(dfa); + u16 *next = NEXT_TABLE(dfa); + u16 *check = CHECK_TABLE(dfa); + unsigned int state = start, pos; + + if (state == 0) + return 0; + + /* current state is <state>, matching character *str */ + if (dfa->tables[YYTD_ID_EC]) { + /* Equivalence class table defined */ + u8 *equiv = EQUIV_TABLE(dfa); + /* default is direct to next state */ + while (*str) { + pos = base[state] + equiv[(u8) *str++]; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + } else { + /* default is direct to next state */ + while (*str) { + pos = base[state] + (u8) *str++; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + } + + return state; +} + +/** + * aa_dfa_next - step one character to the next state in the dfa + * @dfa: the dfa to tranverse (NOT NULL) + * @state: the state to start in + * @c: the input character to transition on + * + * aa_dfa_match will step through the dfa by one input character @c + * + * Returns: state reach after input @c + */ +unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, + const char c) +{ + u16 *def = DEFAULT_TABLE(dfa); + u32 *base = BASE_TABLE(dfa); + u16 *next = NEXT_TABLE(dfa); + u16 *check = CHECK_TABLE(dfa); + unsigned int pos; + + /* current state is <state>, matching character *str */ + if (dfa->tables[YYTD_ID_EC]) { + /* Equivalence class table defined */ + u8 *equiv = EQUIV_TABLE(dfa); + /* default is direct to next state */ + + pos = base[state] + equiv[(u8) c]; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } else { + /* default is direct to next state */ + pos = base[state] + (u8) c; + if (check[pos] == state) + state = next[pos]; + else + state = def[state]; + } + + return state; } diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 9d070a7c3ffc..2daeea4f9266 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -83,31 +83,29 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, struct path root; get_fs_root(current->fs, &root); res = __d_path(path, &root, buf, buflen); - if (res && !IS_ERR(res)) { - /* everything's fine */ - *name = res; - path_put(&root); - goto ok; - } path_put(&root); - connected = 0; + } else { + res = d_absolute_path(path, buf, buflen); + if (!our_mnt(path->mnt)) + connected = 0; } - res = d_absolute_path(path, buf, buflen); - - *name = res; /* handle error conditions - and still allow a partial path to * be returned. */ - if (IS_ERR(res)) { - error = PTR_ERR(res); - *name = buf; - goto out; - } - if (!our_mnt(path->mnt)) + if (!res || IS_ERR(res)) { connected = 0; + res = dentry_path_raw(path->dentry, buf, buflen); + if (IS_ERR(res)) { + error = PTR_ERR(res); + *name = buf; + goto out; + }; + } else if (!our_mnt(path->mnt)) + connected = 0; + + *name = res; -ok: /* Handle two cases: * 1. A deleted dentry && profile is not allowing mediation of deleted * 2. On some filesystems, newly allocated dentries appear to the @@ -138,7 +136,7 @@ ok: /* disconnected path, don't return pathname starting * with '/' */ - error = -ESTALE; + error = -EACCES; if (*res == '/') *name = res + 1; } @@ -159,7 +157,7 @@ out: * Returns: %0 else error on failure */ static int get_name_to_buffer(struct path *path, int flags, char *buffer, - int size, char **name) + int size, char **name, const char **info) { int adjust = (flags & PATH_IS_DIR) ? 1 : 0; int error = d_namespace_path(path, buffer, size - adjust, name, flags); @@ -171,15 +169,27 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, */ strcpy(&buffer[size - 2], "/"); + if (info && error) { + if (error == -ENOENT) + *info = "Failed name lookup - deleted entry"; + else if (error == -ESTALE) + *info = "Failed name lookup - disconnected path"; + else if (error == -ENAMETOOLONG) + *info = "Failed name lookup - name too long"; + else + *info = "Failed name lookup"; + } + return error; } /** - * aa_get_name - compute the pathname of a file + * aa_path_name - compute the pathname of a file * @path: path the file (NOT NULL) * @flags: flags controlling path name generation * @buffer: buffer that aa_get_name() allocated (NOT NULL) * @name: Returns - the generated path name if !error (NOT NULL) + * @info: Returns - information on why the path lookup failed (MAYBE NULL) * * @name is a pointer to the beginning of the pathname (which usually differs * from the beginning of the buffer), or NULL. If there is an error @name @@ -192,7 +202,8 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, * * Returns: %0 else error code if could retrieve name */ -int aa_get_name(struct path *path, int flags, char **buffer, const char **name) +int aa_path_name(struct path *path, int flags, char **buffer, const char **name, + const char **info) { char *buf, *str = NULL; int size = 256; @@ -206,7 +217,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name) if (!buf) return -ENOMEM; - error = get_name_to_buffer(path, flags, buf, size, &str); + error = get_name_to_buffer(path, flags, buf, size, &str, info); if (error != -ENAMETOOLONG) break; @@ -214,6 +225,7 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name) size <<= 1; if (size > aa_g_path_max) return -ENAMETOOLONG; + *info = NULL; } *buffer = buf; *name = str; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4f0eadee78b8..906414383022 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -93,7 +93,7 @@ /* root profile namespace */ struct aa_namespace *root_ns; -const char *profile_mode_names[] = { +const char *const profile_mode_names[] = { "enforce", "complain", "kill", @@ -749,6 +749,7 @@ static void free_profile(struct aa_profile *profile) aa_free_sid(profile->sid); aa_put_dfa(profile->xmatch); + aa_put_dfa(profile->policy.dfa); aa_put_profile(profile->replacedby); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 741dd13e089b..25fd51edc8da 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -84,7 +84,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) * @new: profile if it has been allocated (MAYBE NULL) * @name: name of the profile being manipulated (MAYBE NULL) * @info: any extra info about the failure (MAYBE NULL) - * @e: buffer position info (NOT NULL) + * @e: buffer position info * @error: error code * * Returns: %0 or error @@ -95,7 +95,8 @@ static int audit_iface(struct aa_profile *new, const char *name, struct aa_profile *profile = __aa_current_profile(); struct common_audit_data sa; COMMON_AUDIT_DATA_INIT(&sa, NONE); - sa.aad.iface.pos = e->pos - e->start; + if (e) + sa.aad.iface.pos = e->pos - e->start; sa.aad.iface.target = new; sa.aad.name = name; sa.aad.info = info; @@ -468,7 +469,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) { struct aa_profile *profile = NULL; const char *name = NULL; - int error = -EPROTO; + int i, error = -EPROTO; kernel_cap_t tmpcap; u32 tmp; @@ -554,11 +555,35 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) goto fail; if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL)) goto fail; + if (!unpack_nameX(e, AA_STRUCTEND, NULL)) + goto fail; } if (!unpack_rlimits(e, profile)) goto fail; + if (unpack_nameX(e, AA_STRUCT, "policydb")) { + /* generic policy dfa - optional and may be NULL */ + profile->policy.dfa = unpack_dfa(e); + if (IS_ERR(profile->policy.dfa)) { + error = PTR_ERR(profile->policy.dfa); + profile->policy.dfa = NULL; + goto fail; + } + if (!unpack_u32(e, &profile->policy.start[0], "start")) + /* default start state */ + profile->policy.start[0] = DFA_START; + /* setup class index */ + for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) { + profile->policy.start[i] = + aa_dfa_next(profile->policy.dfa, + profile->policy.start[0], + i); + } + if (!unpack_nameX(e, AA_STRUCTEND, NULL)) + goto fail; + } + /* get file rules */ profile->file.dfa = unpack_dfa(e); if (IS_ERR(profile->file.dfa)) { diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index a4136c10b1c6..72c25a4f2cfd 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -23,6 +23,11 @@ */ #include "rlim_names.h" +struct aa_fs_entry aa_fs_entry_rlimit[] = { + AA_FS_FILE_STRING("mask", AA_FS_RLIMIT_MASK), + { } +}; + /* audit callback for resource specific fields */ static void audit_cb(struct audit_buffer *ab, void *va) { diff --git a/security/capability.c b/security/capability.c index 2f680eb02b59..5bb21b1c448c 100644 --- a/security/capability.c +++ b/security/capability.c @@ -358,6 +358,10 @@ static int cap_task_create(unsigned long clone_flags) return 0; } +static void cap_task_free(struct task_struct *task) +{ +} + static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) { return 0; @@ -954,6 +958,7 @@ void __init security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, file_receive); set_to_cap_if_null(ops, dentry_open); set_to_cap_if_null(ops, task_create); + set_to_cap_if_null(ops, task_free); set_to_cap_if_null(ops, cred_alloc_blank); set_to_cap_if_null(ops, cred_free); set_to_cap_if_null(ops, cred_prepare); diff --git a/security/commoncap.c b/security/commoncap.c index 7ce191ea29a0..0cf4b53480a7 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -28,6 +28,7 @@ #include <linux/prctl.h> #include <linux/securebits.h> #include <linux/user_namespace.h> +#include <linux/binfmts.h> /* * If a non-root user executes a setuid-root binary in diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 4f554f20dc97..35664fe6daa1 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -9,8 +9,8 @@ config IMA select CRYPTO_HMAC select CRYPTO_MD5 select CRYPTO_SHA1 - select TCG_TPM if !S390 && !UML - select TCG_TIS if TCG_TPM + select TCG_TPM if HAS_IOMEM && !UML + select TCG_TIS if TCG_TPM && X86 help The Trusted Computing Group(TCG) runtime Integrity Measurement Architecture(IMA) maintains a list of hash diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 2ad942fb1e23..21e96bf188df 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c @@ -61,6 +61,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, audit_log_untrustedstring(ab, inode->i_sb->s_id); audit_log_format(ab, " ino=%lu", inode->i_ino); } - audit_log_format(ab, " res=%d", !result ? 0 : 1); + audit_log_format(ab, " res=%d", !result); audit_log_end(ab); } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index d45061d02fee..d8edff209bf3 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -62,6 +62,7 @@ static struct ima_measure_rule_entry default_rules[] = { {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, + {.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, @@ -417,7 +418,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) if (!result && (entry->action == UNKNOWN)) result = -EINVAL; - audit_log_format(ab, "res=%d", !!result); + audit_log_format(ab, "res=%d", !result); audit_log_end(ab); return result; } diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 0b3f5d72af1c..6523599e9ac0 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -388,11 +388,24 @@ long keyctl_keyring_clear(key_serial_t ringid) keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); + + /* Root is permitted to invalidate certain special keyrings */ + if (capable(CAP_SYS_ADMIN)) { + keyring_ref = lookup_user_key(ringid, 0, 0); + if (IS_ERR(keyring_ref)) + goto error; + if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR, + &key_ref_to_ptr(keyring_ref)->flags)) + goto clear; + goto error_put; + } + goto error; } +clear: ret = keyring_clear(key_ref_to_ptr(keyring_ref)); - +error_put: key_ref_put(keyring_ref); error: return ret; diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 1068cb1939b3..be7ecb2018dd 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -657,7 +657,8 @@ try_again: goto error; down_read(&cred->request_key_auth->sem); - if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { + if (test_bit(KEY_FLAG_REVOKED, + &cred->request_key_auth->flags)) { key_ref = ERR_PTR(-EKEYREVOKED); key = NULL; } else { diff --git a/security/security.c b/security/security.c index d7542493454d..bf619ffc9a4d 100644 --- a/security/security.c +++ b/security/security.c @@ -19,6 +19,8 @@ #include <linux/integrity.h> #include <linux/ima.h> #include <linux/evm.h> +#include <linux/fsnotify.h> +#include <net/flow.h> #define MAX_LSM_EVM_XATTR 2 @@ -187,25 +189,11 @@ int security_settime(const struct timespec *ts, const struct timezone *tz) return security_ops->settime(ts, tz); } -int security_vm_enough_memory(long pages) -{ - WARN_ON(current->mm == NULL); - return security_ops->vm_enough_memory(current->mm, pages); -} - int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { - WARN_ON(mm == NULL); return security_ops->vm_enough_memory(mm, pages); } -int security_vm_enough_memory_kern(long pages) -{ - /* If current->mm is a kernel thread then we will pass NULL, - for this specific case that is fine */ - return security_ops->vm_enough_memory(current->mm, pages); -} - int security_bprm_set_creds(struct linux_binprm *bprm) { return security_ops->bprm_set_creds(bprm); @@ -729,6 +717,11 @@ int security_task_create(unsigned long clone_flags) return security_ops->task_create(clone_flags); } +void security_task_free(struct task_struct *task) +{ + security_ops->task_free(task); +} + int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { return security_ops->cred_alloc_blank(cred, gfp); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6a3683e28426..304929909375 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -81,6 +81,8 @@ #include <linux/syslog.h> #include <linux/user_namespace.h> #include <linux/export.h> +#include <linux/msg.h> +#include <linux/shm.h> #include "avc.h" #include "objsec.h" diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index e8af5b0ba80f..cd667b4089a5 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -36,6 +36,9 @@ #include <linux/magic.h> #include <linux/dcache.h> #include <linux/personality.h> +#include <linux/msg.h> +#include <linux/shm.h> +#include <linux/binfmts.h> #include "smack.h" #define task_security(task) (task_cred_xxx((task), security)) diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 5ca47ea3049f..7ef9fa3e37e0 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c @@ -446,11 +446,11 @@ void tomoyo_read_log(struct tomoyo_io_buffer *head) * tomoyo_poll_log - Wait for an audit log. * * @file: Pointer to "struct file". - * @wait: Pointer to "poll_table". + * @wait: Pointer to "poll_table". Maybe NULL. * * Returns POLLIN | POLLRDNORM when ready to read an audit log. */ -int tomoyo_poll_log(struct file *file, poll_table *wait) +unsigned int tomoyo_poll_log(struct file *file, poll_table *wait) { if (tomoyo_log_count) return POLLIN | POLLRDNORM; diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index c47d3ce6c733..8656b16eef7b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1069,7 +1069,7 @@ static int tomoyo_write_task(struct tomoyo_acl_param *param) * * @domainname: The name of domain. * - * Returns 0. + * Returns 0 on success, negative value otherwise. * * Caller holds tomoyo_read_lock(). */ @@ -1081,7 +1081,7 @@ static int tomoyo_delete_domain(char *domainname) name.name = domainname; tomoyo_fill_path_info(&name); if (mutex_lock_interruptible(&tomoyo_policy_lock)) - return 0; + return -EINTR; /* Is there an active domain? */ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { /* Never delete tomoyo_kernel_domain */ @@ -1164,15 +1164,16 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); unsigned int profile; if (*data == '<') { + int ret = 0; domain = NULL; if (is_delete) - tomoyo_delete_domain(data); + ret = tomoyo_delete_domain(data); else if (is_select) domain = tomoyo_find_domain(data); else domain = tomoyo_assign_domain(data, false); head->w.domain = domain; - return 0; + return ret; } if (!domain) return -EINVAL; @@ -2111,7 +2112,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid struct tomoyo_domain_info *domain = NULL; spin_lock(&tomoyo_query_list_lock); list_for_each_entry(ptr, &tomoyo_query_list, list) { - if (ptr->serial != serial || ptr->answer) + if (ptr->serial != serial) continue; domain = ptr->domain; break; @@ -2130,28 +2131,13 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid * * Waits for access requests which violated policy in enforcing mode. */ -static int tomoyo_poll_query(struct file *file, poll_table *wait) +static unsigned int tomoyo_poll_query(struct file *file, poll_table *wait) { - struct list_head *tmp; - bool found = false; - u8 i; - for (i = 0; i < 2; i++) { - spin_lock(&tomoyo_query_list_lock); - list_for_each(tmp, &tomoyo_query_list) { - struct tomoyo_query *ptr = - list_entry(tmp, typeof(*ptr), list); - if (ptr->answer) - continue; - found = true; - break; - } - spin_unlock(&tomoyo_query_list_lock); - if (found) - return POLLIN | POLLRDNORM; - if (i) - break; - poll_wait(file, &tomoyo_query_wait, wait); - } + if (!list_empty(&tomoyo_query_list)) + return POLLIN | POLLRDNORM; + poll_wait(file, &tomoyo_query_wait, wait); + if (!list_empty(&tomoyo_query_list)) + return POLLIN | POLLRDNORM; return 0; } @@ -2175,8 +2161,6 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) spin_lock(&tomoyo_query_list_lock); list_for_each(tmp, &tomoyo_query_list) { struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); - if (ptr->answer) - continue; if (pos++ != head->r.query_index) continue; len = ptr->query_len; @@ -2194,8 +2178,6 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) spin_lock(&tomoyo_query_list_lock); list_for_each(tmp, &tomoyo_query_list) { struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); - if (ptr->answer) - continue; if (pos++ != head->r.query_index) continue; /* @@ -2243,8 +2225,10 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); if (ptr->serial != serial) continue; - if (!ptr->answer) - ptr->answer = answer; + ptr->answer = answer; + /* Remove from tomoyo_query_list. */ + if (ptr->answer) + list_del_init(&ptr->list); break; } spin_unlock(&tomoyo_query_list_lock); @@ -2477,18 +2461,17 @@ int tomoyo_open_control(const u8 type, struct file *file) * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. * * @file: Pointer to "struct file". - * @wait: Pointer to "poll_table". + * @wait: Pointer to "poll_table". Maybe NULL. * - * Waits for read readiness. - * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and - * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd. + * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, + * POLLOUT | POLLWRNORM otherwise. */ -int tomoyo_poll_control(struct file *file, poll_table *wait) +unsigned int tomoyo_poll_control(struct file *file, poll_table *wait) { struct tomoyo_io_buffer *head = file->private_data; - if (!head->poll) - return -ENOSYS; - return head->poll(file, wait); + if (head->poll) + return head->poll(file, wait) | POLLOUT | POLLWRNORM; + return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; } /** diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 9512222d5581..30fd98369700 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -788,7 +788,7 @@ struct tomoyo_acl_param { struct tomoyo_io_buffer { void (*read) (struct tomoyo_io_buffer *); int (*write) (struct tomoyo_io_buffer *); - int (*poll) (struct file *file, poll_table *wait); + unsigned int (*poll) (struct file *file, poll_table *wait); /* Exclusive lock for this structure. */ struct mutex io_sem; char __user *read_user_buf; @@ -981,8 +981,8 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path, unsigned long number); int tomoyo_path_perm(const u8 operation, struct path *path, const char *target); -int tomoyo_poll_control(struct file *file, poll_table *wait); -int tomoyo_poll_log(struct file *file, poll_table *wait); +unsigned int tomoyo_poll_control(struct file *file, poll_table *wait); +unsigned int tomoyo_poll_log(struct file *file, poll_table *wait); int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, int addr_len); int tomoyo_socket_connect_permission(struct socket *sock, diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 9027ac1534af..38651454ed08 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -886,12 +886,12 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic(). * So do I. */ - char *kaddr = kmap_atomic(page, KM_USER0); + char *kaddr = kmap_atomic(page); dump->page = page; memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset); - kunmap_atomic(kaddr, KM_USER0); + kunmap_atomic(kaddr); } /* Same with put_arg_page(page) in fs/exec.c */ #ifdef CONFIG_MMU diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index bee09d062057..fe00cdfd0267 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -199,30 +199,32 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, if (flags & MS_REMOUNT) { type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; flags &= ~MS_REMOUNT; - } - if (flags & MS_MOVE) { - type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; - flags &= ~MS_MOVE; - } - if (flags & MS_BIND) { + } else if (flags & MS_BIND) { type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; flags &= ~MS_BIND; - } - if (flags & MS_UNBINDABLE) { - type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; - flags &= ~MS_UNBINDABLE; - } - if (flags & MS_PRIVATE) { + } else if (flags & MS_SHARED) { + if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) + return -EINVAL; + type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; + flags &= ~MS_SHARED; + } else if (flags & MS_PRIVATE) { + if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE)) + return -EINVAL; type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; flags &= ~MS_PRIVATE; - } - if (flags & MS_SLAVE) { + } else if (flags & MS_SLAVE) { + if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE)) + return -EINVAL; type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; flags &= ~MS_SLAVE; - } - if (flags & MS_SHARED) { - type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; - flags &= ~MS_SHARED; + } else if (flags & MS_UNBINDABLE) { + if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE)) + return -EINVAL; + type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; + flags &= ~MS_UNBINDABLE; + } else if (flags & MS_MOVE) { + type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; + flags &= ~MS_MOVE; } if (!type) type = "<NULL>"; diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index 482b2a5f48f0..8592f2fc6ebb 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -157,9 +157,10 @@ static int tomoyo_release(struct inode *inode, struct file *file) * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. * * @file: Pointer to "struct file". - * @wait: Pointer to "poll_table". + * @wait: Pointer to "poll_table". Maybe NULL. * - * Returns 0 on success, negative value otherwise. + * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, + * POLLOUT | POLLWRNORM otherwise. */ static unsigned int tomoyo_poll(struct file *file, poll_table *wait) { diff --git a/security/yama/Kconfig b/security/yama/Kconfig new file mode 100644 index 000000000000..51d6709d8bbd --- /dev/null +++ b/security/yama/Kconfig @@ -0,0 +1,13 @@ +config SECURITY_YAMA + bool "Yama support" + depends on SECURITY + select SECURITYFS + select SECURITY_PATH + default n + help + This selects Yama, which extends DAC support with additional + system-wide security settings beyond regular Linux discretionary + access controls. Currently available is ptrace scope restriction. + Further information can be found in Documentation/security/Yama.txt. + + If you are unsure how to answer this question, answer N. diff --git a/security/yama/Makefile b/security/yama/Makefile new file mode 100644 index 000000000000..8b5e06588456 --- /dev/null +++ b/security/yama/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SECURITY_YAMA) := yama.o + +yama-y := yama_lsm.o diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c new file mode 100644 index 000000000000..573723843a04 --- /dev/null +++ b/security/yama/yama_lsm.c @@ -0,0 +1,323 @@ +/* + * Yama Linux Security Module + * + * Author: Kees Cook <keescook@chromium.org> + * + * Copyright (C) 2010 Canonical, Ltd. + * Copyright (C) 2011 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include <linux/security.h> +#include <linux/sysctl.h> +#include <linux/ptrace.h> +#include <linux/prctl.h> +#include <linux/ratelimit.h> + +static int ptrace_scope = 1; + +/* describe a ptrace relationship for potential exception */ +struct ptrace_relation { + struct task_struct *tracer; + struct task_struct *tracee; + struct list_head node; +}; + +static LIST_HEAD(ptracer_relations); +static DEFINE_SPINLOCK(ptracer_relations_lock); + +/** + * yama_ptracer_add - add/replace an exception for this tracer/tracee pair + * @tracer: the task_struct of the process doing the ptrace + * @tracee: the task_struct of the process to be ptraced + * + * Each tracee can have, at most, one tracer registered. Each time this + * is called, the prior registered tracer will be replaced for the tracee. + * + * Returns 0 if relationship was added, -ve on error. + */ +static int yama_ptracer_add(struct task_struct *tracer, + struct task_struct *tracee) +{ + int rc = 0; + struct ptrace_relation *added; + struct ptrace_relation *entry, *relation = NULL; + + added = kmalloc(sizeof(*added), GFP_KERNEL); + if (!added) + return -ENOMEM; + + spin_lock_bh(&ptracer_relations_lock); + list_for_each_entry(entry, &ptracer_relations, node) + if (entry->tracee == tracee) { + relation = entry; + break; + } + if (!relation) { + relation = added; + relation->tracee = tracee; + list_add(&relation->node, &ptracer_relations); + } + relation->tracer = tracer; + + spin_unlock_bh(&ptracer_relations_lock); + if (added != relation) + kfree(added); + + return rc; +} + +/** + * yama_ptracer_del - remove exceptions related to the given tasks + * @tracer: remove any relation where tracer task matches + * @tracee: remove any relation where tracee task matches + */ +static void yama_ptracer_del(struct task_struct *tracer, + struct task_struct *tracee) +{ + struct ptrace_relation *relation, *safe; + + spin_lock_bh(&ptracer_relations_lock); + list_for_each_entry_safe(relation, safe, &ptracer_relations, node) + if (relation->tracee == tracee || + (tracer && relation->tracer == tracer)) { + list_del(&relation->node); + kfree(relation); + } + spin_unlock_bh(&ptracer_relations_lock); +} + +/** + * yama_task_free - check for task_pid to remove from exception list + * @task: task being removed + */ +static void yama_task_free(struct task_struct *task) +{ + yama_ptracer_del(task, task); +} + +/** + * yama_task_prctl - check for Yama-specific prctl operations + * @option: operation + * @arg2: argument + * @arg3: argument + * @arg4: argument + * @arg5: argument + * + * Return 0 on success, -ve on error. -ENOSYS is returned when Yama + * does not handle the given option. + */ +static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + int rc; + struct task_struct *myself = current; + + rc = cap_task_prctl(option, arg2, arg3, arg4, arg5); + if (rc != -ENOSYS) + return rc; + + switch (option) { + case PR_SET_PTRACER: + /* Since a thread can call prctl(), find the group leader + * before calling _add() or _del() on it, since we want + * process-level granularity of control. The tracer group + * leader checking is handled later when walking the ancestry + * at the time of PTRACE_ATTACH check. + */ + rcu_read_lock(); + if (!thread_group_leader(myself)) + myself = rcu_dereference(myself->group_leader); + get_task_struct(myself); + rcu_read_unlock(); + + if (arg2 == 0) { + yama_ptracer_del(NULL, myself); + rc = 0; + } else if (arg2 == PR_SET_PTRACER_ANY) { + rc = yama_ptracer_add(NULL, myself); + } else { + struct task_struct *tracer; + + rcu_read_lock(); + tracer = find_task_by_vpid(arg2); + if (tracer) + get_task_struct(tracer); + else + rc = -EINVAL; + rcu_read_unlock(); + + if (tracer) { + rc = yama_ptracer_add(tracer, myself); + put_task_struct(tracer); + } + } + + put_task_struct(myself); + break; + } + + return rc; +} + +/** + * task_is_descendant - walk up a process family tree looking for a match + * @parent: the process to compare against while walking up from child + * @child: the process to start from while looking upwards for parent + * + * Returns 1 if child is a descendant of parent, 0 if not. + */ +static int task_is_descendant(struct task_struct *parent, + struct task_struct *child) +{ + int rc = 0; + struct task_struct *walker = child; + + if (!parent || !child) + return 0; + + rcu_read_lock(); + if (!thread_group_leader(parent)) + parent = rcu_dereference(parent->group_leader); + while (walker->pid > 0) { + if (!thread_group_leader(walker)) + walker = rcu_dereference(walker->group_leader); + if (walker == parent) { + rc = 1; + break; + } + walker = rcu_dereference(walker->real_parent); + } + rcu_read_unlock(); + + return rc; +} + +/** + * ptracer_exception_found - tracer registered as exception for this tracee + * @tracer: the task_struct of the process attempting ptrace + * @tracee: the task_struct of the process to be ptraced + * + * Returns 1 if tracer has is ptracer exception ancestor for tracee. + */ +static int ptracer_exception_found(struct task_struct *tracer, + struct task_struct *tracee) +{ + int rc = 0; + struct ptrace_relation *relation; + struct task_struct *parent = NULL; + bool found = false; + + spin_lock_bh(&ptracer_relations_lock); + rcu_read_lock(); + if (!thread_group_leader(tracee)) + tracee = rcu_dereference(tracee->group_leader); + list_for_each_entry(relation, &ptracer_relations, node) + if (relation->tracee == tracee) { + parent = relation->tracer; + found = true; + break; + } + + if (found && (parent == NULL || task_is_descendant(parent, tracer))) + rc = 1; + rcu_read_unlock(); + spin_unlock_bh(&ptracer_relations_lock); + + return rc; +} + +/** + * yama_ptrace_access_check - validate PTRACE_ATTACH calls + * @child: task that current task is attempting to ptrace + * @mode: ptrace attach mode + * + * Returns 0 if following the ptrace is allowed, -ve on error. + */ +static int yama_ptrace_access_check(struct task_struct *child, + unsigned int mode) +{ + int rc; + + /* If standard caps disallows it, so does Yama. We should + * only tighten restrictions further. + */ + rc = cap_ptrace_access_check(child, mode); + if (rc) + return rc; + + /* require ptrace target be a child of ptracer on attach */ + if (mode == PTRACE_MODE_ATTACH && + ptrace_scope && + !task_is_descendant(current, child) && + !ptracer_exception_found(current, child) && + !capable(CAP_SYS_PTRACE)) + rc = -EPERM; + + if (rc) { + char name[sizeof(current->comm)]; + printk_ratelimited(KERN_NOTICE "ptrace of non-child" + " pid %d was attempted by: %s (pid %d)\n", + child->pid, + get_task_comm(name, current), + current->pid); + } + + return rc; +} + +static struct security_operations yama_ops = { + .name = "yama", + + .ptrace_access_check = yama_ptrace_access_check, + .task_prctl = yama_task_prctl, + .task_free = yama_task_free, +}; + +#ifdef CONFIG_SYSCTL +static int zero; +static int one = 1; + +struct ctl_path yama_sysctl_path[] = { + { .procname = "kernel", }, + { .procname = "yama", }, + { } +}; + +static struct ctl_table yama_sysctl_table[] = { + { + .procname = "ptrace_scope", + .data = &ptrace_scope, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, + { } +}; +#endif /* CONFIG_SYSCTL */ + +static __init int yama_init(void) +{ + if (!security_module_enable(&yama_ops)) + return 0; + + printk(KERN_INFO "Yama: becoming mindful.\n"); + + if (register_security(&yama_ops)) + panic("Yama: kernel registration failed.\n"); + +#ifdef CONFIG_SYSCTL + if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) + panic("Yama: sysctl registration failed.\n"); +#endif + + return 0; +} + +security_initcall(yama_init); diff --git a/tools/virtio/linux/hrtimer.h b/tools/virtio/linux/hrtimer.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/virtio/linux/hrtimer.h diff --git a/tools/virtio/linux/module.h b/tools/virtio/linux/module.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/virtio/linux/module.h diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index b4fbc91c41b4..7579f19e61e0 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -181,6 +181,9 @@ struct virtqueue { #define smp_mb() mb() # define smp_rmb() barrier() # define smp_wmb() barrier() +/* Weak barriers should be used. If not - it's a bug */ +# define rmb() abort() +# define wmb() abort() #else #error Please fill in barrier macros #endif |