diff options
907 files changed, 38457 insertions, 11725 deletions
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index cb9258b8fd35..495e5ba1634c 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -454,6 +454,16 @@ The preferred style for long (multi-line) comments is: * with beginning and ending almost-blank lines. */ +For files in net/ and drivers/net/ the preferred style for long (multi-line) +comments is a little different. + + /* The preferred comment style for files in net/ and drivers/net + * looks like this. + * + * It is nearly the same as the generally preferred comment style, + * but there is no initial almost-blank line. + */ + It's also important to comment data, whether they are basic types or derived types. To this end, use just one data declaration per line (no commas for multiple data declarations). This leaves you room for a small comment on each diff --git a/Documentation/aoe/aoe.txt b/Documentation/aoe/aoe.txt index 5f5aa16047ff..bfc9cb19abcd 100644 --- a/Documentation/aoe/aoe.txt +++ b/Documentation/aoe/aoe.txt @@ -1,8 +1,16 @@ -The EtherDrive (R) HOWTO for users of 2.6 kernels is found at ... +ATA over Ethernet is a network protocol that provides simple access to +block storage on the LAN. - http://www.coraid.com/SUPPORT/EtherDrive-HBA + http://support.coraid.com/documents/AoEr11.txt - It has many tips and hints! +The EtherDrive (R) HOWTO for 2.6 and 3.x kernels is found at ... + + http://support.coraid.com/support/linux/EtherDrive-2.6-HOWTO.html + +It has many tips and hints! Please see, especially, recommended +tunings for virtual memory: + + http://support.coraid.com/support/linux/EtherDrive-2.6-HOWTO-5.html#ss5.19 The aoetools are userland programs that are designed to work with this driver. The aoetools are on sourceforge. @@ -23,20 +31,12 @@ CREATING DEVICE NODES There is a udev-install.sh script that shows how to install these rules on your system. - If you are not using udev, two scripts are provided in - Documentation/aoe as examples of static device node creation for - using the aoe driver. - - rm -rf /dev/etherd - sh Documentation/aoe/mkdevs.sh /dev/etherd - - ... or to make just one shelf's worth of block device nodes ... - - sh Documentation/aoe/mkshelf.sh /dev/etherd 0 - There is also an autoload script that shows how to edit /etc/modprobe.d/aoe.conf to ensure that the aoe module is loaded when - necessary. + necessary. Preloading the aoe module is preferable to autoloading, + however, because AoE discovery takes a few seconds. It can be + confusing when an AoE device is not present the first time the a + command is run but appears a second later. USING DEVICE NODES @@ -51,9 +51,9 @@ USING DEVICE NODES "echo > /dev/etherd/discover" tells the driver to find out what AoE devices are available. - These character devices may disappear and be replaced by sysfs - counterparts. Using the commands in aoetools insulates users from - these implementation details. + In the future these character devices may disappear and be replaced + by sysfs counterparts. Using the commands in aoetools insulates + users from these implementation details. The block devices are named like this: @@ -76,8 +76,8 @@ USING SYSFS The netif attribute is the network interface on the localhost through which we are communicating with the remote AoE device. - There is a script in this directory that formats this information - in a convenient way. Users with aoetools can use the aoe-stat + There is a script in this directory that formats this information in + a convenient way. Users with aoetools should use the aoe-stat command. root@makki root# sh Documentation/aoe/status.sh @@ -121,3 +121,21 @@ DRIVER OPTIONS usage example for the module parameter. modprobe aoe_iflist="eth1 eth3" + + The aoe_deadsecs module parameter determines the maximum number of + seconds that the driver will wait for an AoE device to provide a + response to an AoE command. After aoe_deadsecs seconds have + elapsed, the AoE device will be marked as "down". + + The aoe_maxout module parameter has a default of 128. This is the + maximum number of unresponded packets that will be sent to an AoE + target at one time. + + The aoe_dyndevs module parameter defaults to 1, meaning that the + driver will assign a block device minor number to a discovered AoE + target based on the order of its discovery. With dynamic minor + device numbers in use, a greater range of AoE shelf and slot + addresses can be supported. Users with udev will never have to + think about minor numbers. Using aoe_dyndevs=0 allows device nodes + to be pre-created using a static minor-number scheme with the + aoe-mkshelf script in the aoetools. diff --git a/Documentation/aoe/mkdevs.sh b/Documentation/aoe/mkdevs.sh deleted file mode 100644 index 44c0ab702432..000000000000 --- a/Documentation/aoe/mkdevs.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -n_shelves=${n_shelves:-10} -n_partitions=${n_partitions:-16} - -if test "$#" != "1"; then - echo "Usage: sh `basename $0` {dir}" 1>&2 - echo " n_partitions=16 sh `basename $0` {dir}" 1>&2 - exit 1 -fi -dir=$1 - -MAJOR=152 - -echo "Creating AoE devnode files in $dir ..." - -set -e - -mkdir -p $dir - -# (Status info is in sysfs. See status.sh.) -# rm -f $dir/stat -# mknod -m 0400 $dir/stat c $MAJOR 1 -rm -f $dir/err -mknod -m 0400 $dir/err c $MAJOR 2 -rm -f $dir/discover -mknod -m 0200 $dir/discover c $MAJOR 3 -rm -f $dir/interfaces -mknod -m 0200 $dir/interfaces c $MAJOR 4 -rm -f $dir/revalidate -mknod -m 0200 $dir/revalidate c $MAJOR 5 -rm -f $dir/flush -mknod -m 0200 $dir/flush c $MAJOR 6 - -export n_partitions -mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'` -i=0 -while test $i -lt $n_shelves; do - sh -xc "sh $mkshelf $dir $i" - i=`expr $i + 1` -done diff --git a/Documentation/aoe/mkshelf.sh b/Documentation/aoe/mkshelf.sh deleted file mode 100644 index 32615814271c..000000000000 --- a/Documentation/aoe/mkshelf.sh +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/sh - -if test "$#" != "2"; then - echo "Usage: sh `basename $0` {dir} {shelfaddress}" 1>&2 - echo " n_partitions=16 sh `basename $0` {dir} {shelfaddress}" 1>&2 - exit 1 -fi -n_partitions=${n_partitions:-16} -dir=$1 -shelf=$2 -nslots=16 -maxslot=`echo $nslots 1 - p | dc` -MAJOR=152 - -set -e - -minor=`echo $nslots \* $shelf \* $n_partitions | bc` -endp=`echo $n_partitions - 1 | bc` -for slot in `seq 0 $maxslot`; do - for part in `seq 0 $endp`; do - name=e$shelf.$slot - test "$part" != "0" && name=${name}p$part - rm -f $dir/$name - mknod -m 0660 $dir/$name b $MAJOR $minor - - minor=`expr $minor + 1` - done -done diff --git a/Documentation/aoe/status.sh b/Documentation/aoe/status.sh index 751f3be514b8..eeec7baae57a 100644 --- a/Documentation/aoe/status.sh +++ b/Documentation/aoe/status.sh @@ -1,5 +1,8 @@ #! /bin/sh # collate and present sysfs information about AoE storage +# +# A more complete version of this script is aoe-stat, in the +# aoetools. set -e format="%8s\t%8s\t%8s\n" diff --git a/Documentation/devicetree/bindings/arm/xen.txt b/Documentation/devicetree/bindings/arm/xen.txt new file mode 100644 index 000000000000..0f7b9c2109f8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/xen.txt @@ -0,0 +1,25 @@ +* Xen hypervisor device tree bindings + +Xen ARM virtual platforms shall have a top-level "hypervisor" node with +the following properties: + +- compatible: + compatible = "xen,xen-<version>", "xen,xen"; + where <version> is the version of the Xen ABI of the platform. + +- reg: specifies the base physical address and size of a region in + memory where the grant table should be mapped to, using an + HYPERVISOR_memory_op hypercall. The memory region is large enough to map + the whole grant table (it is larger or equal to gnttab_max_grant_frames()). + +- interrupts: the interrupt used by Xen to inject event notifications. + A GIC node is also required. + + +Example (assuming #address-cells = <2> and #size-cells = <2>): + +hypervisor { + compatible = "xen,xen-4.3", "xen,xen"; + reg = <0 0xb0000000 0 0x20000>; + interrupts = <1 15 0xf08>; +}; diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index bf57ecd5d73a..bd7ce120bc13 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -9,6 +9,7 @@ Copyright (C) 2008-2011 Freescale Semiconductor Inc. -Run Time Integrity Check (RTIC) Node -Run Time Integrity Check (RTIC) Memory Node -Secure Non-Volatile Storage (SNVS) Node + -Secure Non-Volatile Storage (SNVS) Low Power (LP) RTC Node -Full Example NOTE: the SEC 4 is also known as Freescale's Cryptographic Accelerator @@ -294,6 +295,27 @@ Secure Non-Volatile Storage (SNVS) Node address and length of the SEC4 configuration registers. + - #address-cells + Usage: required + Value type: <u32> + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. Must + have a value of 1. + + - #size-cells + Usage: required + Value type: <u32> + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. Must have a value of 1. + + - ranges + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies the physical address + range of the SNVS register space. A triplet that includes + the child address, parent address, & length. + - interrupts Usage: required Value type: <prop_encoded-array> @@ -314,11 +336,34 @@ EXAMPLE sec_mon@314000 { compatible = "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; + ranges = <0 0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; }; ===================================================================== +Secure Non-Volatile Storage (SNVS) Low Power (LP) RTC Node + + A SNVS child node that defines SNVS LP RTC. + + - compatible + Usage: required + Value type: <string> + Definition: Must include "fsl,sec-v4.0-mon-rtc-lp". + + - reg + Usage: required + Value type: <prop-encoded-array> + Definition: A standard property. Specifies the physical + address and length of the SNVS LP configuration registers. + +EXAMPLE + sec_mon_rtc_lp@314000 { + compatible = "fsl,sec-v4.0-mon-rtc-lp"; + reg = <0x34 0x58>; + }; + +===================================================================== FULL EXAMPLE crypto: crypto@300000 { @@ -390,8 +435,14 @@ FULL EXAMPLE sec_mon: sec_mon@314000 { compatible = "fsl,sec-v4.0-mon"; reg = <0x314000 0x1000>; + ranges = <0 0x314000 0x1000>; interrupt-parent = <&mpic>; interrupts = <93 2>; + + sec_mon_rtc_lp@34 { + compatible = "fsl,sec-v4.0-mon-rtc-lp"; + reg = <0x34 0x58>; + }; }; ===================================================================== diff --git a/Documentation/devicetree/bindings/mfd/88pm860x.txt b/Documentation/devicetree/bindings/mfd/88pm860x.txt new file mode 100644 index 000000000000..63f3ee33759c --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/88pm860x.txt @@ -0,0 +1,85 @@ +* Marvell 88PM860x Power Management IC + +Required parent device properties: +- compatible : "marvell,88pm860x" +- reg : the I2C slave address for the 88pm860x chip +- interrupts : IRQ line for the 88pm860x chip +- interrupt-controller: describes the 88pm860x as an interrupt controller (has its own domain) +- #interrupt-cells : should be 1. + - The cell is the 88pm860x local IRQ number + +Optional parent device properties: +- marvell,88pm860x-irq-read-clr: inicates whether interrupt status is cleared by read +- marvell,88pm860x-slave-addr: 88pm860x are two chips solution. <reg> stores the I2C address + of one chip, and this property stores the I2C address of + another chip. + +88pm860x consists of a large and varied group of sub-devices: + +Device Supply Names Description +------ ------------ ----------- +88pm860x-onkey : : On key +88pm860x-rtc : : RTC +88pm8607 : : Regulators +88pm860x-backlight : : Backlight +88pm860x-led : : Led +88pm860x-touch : : Touchscreen + +Example: + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + interrupts = <4>; + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <1>; + + marvell,88pm860x-irq-read-clr; + marvell,88pm860x-slave-addr = <0x11>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + LDO1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + rtc { + marvell,88pm860x-vrtc = <1>; + }; + touch { + marvell,88pm860x-gpadc-prebias = <1>; + marvell,88pm860x-gpadc-slot-cycle = <1>; + marvell,88pm860x-tsi-prebias = <6>; + marvell,88pm860x-pen-prebias = <16>; + marvell,88pm860x-pen-prechg = <2>; + marvell,88pm860x-resistor-X = <300>; + }; + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; + }; + leds { + led0-red { + marvell,88pm860x-iset = <12>; + }; + led0-green { + marvell,88pm860x-iset = <12>; + }; + led0-blue { + marvell,88pm860x-iset = <12>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/syscon.txt b/Documentation/devicetree/bindings/mfd/syscon.txt new file mode 100644 index 000000000000..fe8150bb3248 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/syscon.txt @@ -0,0 +1,20 @@ +* System Controller Registers R/W driver + +System controller node represents a register region containing a set +of miscellaneous registers. The registers are not cohesive enough to +represent as any specific type of device. The typical use-case is for +some other node's driver, or platform-specific code, to acquire a +reference to the syscon node (e.g. by phandle, node path, or search +using a specific compatible value), interrogate the node (or associated +OS driver) to determine the location of the registers, and access the +registers directly. + +Required properties: +- compatible: Should contain "syscon". +- reg: the register region can be accessed from syscon + +Examples: +gpr: iomuxc-gpr@020e0000 { + compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; + reg = <0x020e0000 0x38>; +}; diff --git a/Documentation/devicetree/bindings/mfd/tps65910.txt b/Documentation/devicetree/bindings/mfd/tps65910.txt index db03599ae4dc..2e3304888ffc 100644 --- a/Documentation/devicetree/bindings/mfd/tps65910.txt +++ b/Documentation/devicetree/bindings/mfd/tps65910.txt @@ -59,6 +59,8 @@ Optional properties: in TPS6591X datasheet) - ti,en-gpio-sleep: enable sleep control for gpios There should be 9 entries here, one for each gpio. +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. Regulator Optional properties: - ti,regulator-ext-sleep-control: enable external sleep @@ -79,6 +81,8 @@ Example: #interrupt-cells = <2>; interrupt-controller; + ti,system-power-controller; + ti,vmbch-threshold = 0; ti,vmbch2-threshold = 0; ti,en-ck32k-xtal; diff --git a/Documentation/devicetree/bindings/mfd/twl4030-audio.txt b/Documentation/devicetree/bindings/mfd/twl4030-audio.txt new file mode 100644 index 000000000000..414d2ae0adf6 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/twl4030-audio.txt @@ -0,0 +1,46 @@ +Texas Instruments TWL family (twl4030) audio module + +The audio module inside the TWL family consist of an audio codec and a vibra +driver. + +Required properties: +- compatible : must be "ti,twl4030-audio" + +Optional properties, nodes: + +Audio functionality: +- codec { }: Need to be present if the audio functionality is used. Within this + section the following options can be used: +- ti,digimic_delay: Delay need after enabling the digimic to reduce artifacts + from the start of the recorded sample (in ms) +-ti,ramp_delay_value: HS ramp delay configuration to reduce pop noise +-ti,hs_extmute: Use external mute for HS pop reduction +-ti,hs_extmute_gpio: Use external GPIO to control the external mute +-ti,offset_cncl_path: Offset cancellation path selection, refer to TRM for the + valid values. + +Vibra functionality +- ti,enable-vibra: Need to be set to <1> if the vibra functionality is used. if + missing or it is 0, the vibra functionality is disabled. + +Example: +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + + ti,enable-vibra = <1>; + + codec { + ti,ramp_delay_value = <3>; + }; + + }; + }; +}; diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt index c855240f3a0e..0f5dd709d752 100644 --- a/Documentation/devicetree/bindings/mfd/twl6040.txt +++ b/Documentation/devicetree/bindings/mfd/twl6040.txt @@ -1,7 +1,7 @@ Texas Instruments TWL6040 family -The TWL6040s are 8-channel high quality low-power audio codecs providing audio -and vibra functionality on OMAP4+ platforms. +The TWL6040s are 8-channel high quality low-power audio codecs providing audio, +vibra and GPO functionality on OMAP4+ platforms. They are connected ot the host processor via i2c for commands, McPDM for audio data and commands. @@ -10,6 +10,8 @@ Required properties: - reg: must be 0x4b for i2c address - interrupts: twl6040 has one interrupt line connecteded to the main SoC - interrupt-parent: The parent interrupt controller +- gpio-controller: +- #gpio-cells = <1>: twl6040 provides GPO lines. - twl6040,audpwron-gpio: Power on GPIO line for the twl6040 - vio-supply: Regulator for the twl6040 VIO supply @@ -37,7 +39,6 @@ Example: &i2c1 { twl6040: twl@4b { compatible = "ti,twl6040"; - reg = <0x4b>; interrupts = <0 119 4>; interrupt-parent = <&gic>; @@ -60,3 +61,5 @@ Example: }; }; }; + +/include/ "twl6040.dtsi" diff --git a/Documentation/devicetree/bindings/misc/ifm-csi.txt b/Documentation/devicetree/bindings/misc/ifm-csi.txt new file mode 100644 index 000000000000..5bdfffb0b9f7 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/ifm-csi.txt @@ -0,0 +1,41 @@ +IFM camera sensor interface on mpc5200 LocalPlus bus + +Required properties: +- compatible: "ifm,o2d-csi" +- reg: specifies sensor chip select number and associated address range +- interrupts: external interrupt line number and interrupt sense mode + of the interrupt line signaling frame valid events +- gpios: three gpio-specifiers for "capture", "reset" and "master enable" + GPIOs (strictly in this order). +- ifm,csi-clk-handle: the phandle to a node in the DT describing the sensor + clock generator. This node is usually a general purpose timer controller. +- ifm,csi-addr-bus-width: address bus width (valid values are 16, 24, 25) +- ifm,csi-data-bus-width: data bus width (valid values are 8 and 16) +- ifm,csi-wait-cycles: sensor bus wait cycles + +Optional properties: +- ifm,csi-byte-swap: if this property is present, the byte swapping on + the bus will be enabled. + +Example: + + csi@3,0 { + compatible = "ifm,o2d-csi"; + reg = <3 0 0x00100000>; /* CS 3, 1 MiB range */ + interrupts = <1 1 2>; /* IRQ1, edge falling */ + + ifm,csi-clk-handle = <&timer7>; + gpios = <&gpio_simple 23 0 /* image_capture */ + &gpio_simple 26 0 /* image_reset */ + &gpio_simple 29 0>; /* image_master_en */ + + ifm,csi-addr-bus-width = <24>; + ifm,csi-data-bus-width = <8>; + ifm,csi-wait-cycles = <0>; + }; + +The base address of the used chip select is specified in the +ranges property of the parent localbus node, for example: + + ranges = <0 0 0xff000000 0x01000000 + 3 0 0xe3000000 0x00100000>; diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt index 939a26d541f6..d5e370450ac0 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt @@ -12,9 +12,12 @@ Properties: - #size-cells : Either one or two, depending on how large each chipselect can be. - reg : Offset and length of the register set for the device -- interrupts : IFC has two interrupts. The first one is the "common" - interrupt(CM_EVTER_STAT), and second is the NAND interrupt - (NAND_EVTER_STAT). +- interrupts: IFC may have one or two interrupts. If two interrupt + specifiers are present, the first is the "common" + interrupt (CM_EVTER_STAT), and the second is the NAND + interrupt (NAND_EVTER_STAT). If there is only one, + that interrupt reports both types of event. + - ranges : Each range corresponds to a single chipselect, and covers the entire access window as configured. diff --git a/Documentation/devicetree/bindings/regulator/88pm860x.txt b/Documentation/devicetree/bindings/regulator/88pm860x.txt new file mode 100644 index 000000000000..1267b3e1a2cc --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/88pm860x.txt @@ -0,0 +1,30 @@ +Marvell 88PM860x regulator + +Required properties: +- compatible: "marvell,88pm860x" +- reg: I2C slave address +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the regulator-compatible + property, with valid values listed below. + +Example: + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + BUCK3 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/max8907.txt b/Documentation/devicetree/bindings/regulator/max8907.txt new file mode 100644 index 000000000000..371eccd1cd68 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8907.txt @@ -0,0 +1,69 @@ +MAX8907 regulator + +Required properties: +- compatible: "maxim,max8907" +- reg: I2C slave address +- interrupts: The interrupt output of the controller +- mbatt-supply: The input supply for MBATT, BBAT, SDBY, VRTC. +- in-v1-supply: The input supply for SD1. +- in-v2-supply: The input supply for SD2. +- in-v3-supply: The input supply for SD3. +- in1-supply: The input supply for LDO1. +... +- in20-supply: The input supply for LDO20. +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name (or the deprecated + regulator-compatible property if present), with valid values listed below. + The content of each sub-node is defined by the standard binding for + regulators; see regulator.txt. + +Optional properties: +- maxim,system-power-controller: Boolean property indicating that the PMIC + controls the overall system power. + +The valid names for regulators are: + + sd1, sd2, sd3, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, ldo8, ldo9, ldo10, + ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19, ldo20, out5v, + out33v, bbat, sdby, vrtc. + +Example: + + max8907@3c { + compatible = "maxim,max8907"; + reg = <0x3c>; + interrupts = <0 86 0x4>; + + maxim,system-power-controller; + + mbatt-supply = <&some_reg>; + in-v1-supply = <&mbatt_reg>; + ... + in1-supply = <&mbatt_reg>; + ... + + regulators { + mbatt_reg: mbatt { + regulator-name = "vbat_pmu"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + sd1 { + regulator-name = "nvvdd_sv1,vdd_cpu_pmu"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + sd2 { + regulator-name = "nvvdd_sv2,vdd_core"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; +... + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/tps6586x.txt b/Documentation/devicetree/bindings/regulator/tps6586x.txt index 07b9ef6e49d5..8b40cac24d93 100644 --- a/Documentation/devicetree/bindings/regulator/tps6586x.txt +++ b/Documentation/devicetree/bindings/regulator/tps6586x.txt @@ -22,6 +22,10 @@ Required properties: - vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8 - vinldo9-supply: The input supply for the LDO9 +Optional properties: +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. + Each regulator is defined using the standard binding for regulators. Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver @@ -37,6 +41,8 @@ Example: #gpio-cells = <2>; gpio-controller; + ti,system-power-controller; + sys-supply = <&some_reg>; vin-sm0-supply = <&some_reg>; vin-sm1-supply = <&some_reg>; diff --git a/Documentation/devicetree/bindings/rtc/snvs-rtc.txt b/Documentation/devicetree/bindings/rtc/snvs-rtc.txt new file mode 100644 index 000000000000..fb61ed77ada3 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/snvs-rtc.txt @@ -0,0 +1 @@ +See Documentation/devicetree/bindings/crypto/fsl-sec4.txt for details. diff --git a/Documentation/devicetree/bindings/video/backlight/88pm860x.txt b/Documentation/devicetree/bindings/video/backlight/88pm860x.txt new file mode 100644 index 000000000000..261df2799315 --- /dev/null +++ b/Documentation/devicetree/bindings/video/backlight/88pm860x.txt @@ -0,0 +1,15 @@ +88pm860x-backlight bindings + +Optional properties: + - marvell,88pm860x-iset: Current supplies on backlight device. + - marvell,88pm860x-pwm: PWM frequency on backlight device. + +Example: + + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 7561d7ed8e11..8ffb274367c7 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -69,6 +69,7 @@ MAC/FDDI addresses: %pMR 05:04:03:02:01:00 %pMF 00-01-02-03-04-05 %pm 000102030405 + %pmR 050403020100 For printing 6-byte MAC/FDDI addresses in hex notation. The 'M' and 'm' specifiers result in a printed address with ('M') or without ('m') byte diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt index 23a09b884bc7..e6469fdcf89a 100644 --- a/Documentation/remoteproc.txt +++ b/Documentation/remoteproc.txt @@ -129,6 +129,13 @@ int dummy_rproc_example(struct rproc *my_rproc) Returns 0 on success and -EINVAL if @rproc isn't valid. + void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) + - Report a crash in a remoteproc + This function must be called every time a crash is detected by the + platform specific rproc implementation. This should not be called from a + non-remoteproc driver. This function can be called from atomic/interrupt + context. + 5. Implementation callbacks These callbacks should be provided by platform-specific remoteproc diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 250160469d83..32aa4002de4a 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -119,8 +119,9 @@ three different userspace interfaces: * /sys/class/rtc/rtcN ... sysfs attributes support readonly access to some RTC attributes. - * /proc/driver/rtc ... the first RTC (rtc0) may expose itself - using a procfs interface. More information is (currently) shown + * /proc/driver/rtc ... the system clock RTC may expose itself + using a procfs interface. If there is no RTC for the system clock, + rtc0 is used by default. More information is (currently) shown here than through sysfs. The RTC Class framework supports a wide variety of RTCs, ranging from those diff --git a/Documentation/smsc_ece1099.txt b/Documentation/smsc_ece1099.txt new file mode 100644 index 000000000000..6b492e82b43d --- /dev/null +++ b/Documentation/smsc_ece1099.txt @@ -0,0 +1,56 @@ +What is smsc-ece1099? +---------------------- + +The ECE1099 is a 40-Pin 3.3V Keyboard Scan Expansion +or GPIO Expansion device. The device supports a keyboard +scan matrix of 23x8. The device is connected to a Master +via the SMSC BC-Link interface or via the SMBus. +Keypad scan Input(KSI) and Keypad Scan Output(KSO) signals +are multiplexed with GPIOs. + +Interrupt generation +-------------------- + +Interrupts can be generated by an edge detection on a GPIO +pin or an edge detection on one of the bus interface pins. +Interrupts can also be detected on the keyboard scan interface. +The bus interrupt pin (BC_INT# or SMBUS_INT#) is asserted if +any bit in one of the Interrupt Status registers is 1 and +the corresponding Interrupt Mask bit is also 1. + +In order for software to determine which device is the source +of an interrupt, it should first read the Group Interrupt Status Register +to determine which Status register group is a source for the interrupt. +Software should read both the Status register and the associated Mask register, +then AND the two values together. Bits that are 1 in the result of the AND +are active interrupts. Software clears an interrupt by writing a 1 to the +corresponding bit in the Status register. + +Communication Protocol +---------------------- + +- SMbus slave Interface + The host processor communicates with the ECE1099 device + through a series of read/write registers via the SMBus + interface. SMBus is a serial communication protocol between + a computer host and its peripheral devices. The SMBus data + rate is 10KHz minimum to 400 KHz maximum + +- Slave Bus Interface + The ECE1099 device SMBus implementation is a subset of the + SMBus interface to the host. The device is a slave-only SMBus device. + The implementation in the device is a subset of SMBus since it + only supports four protocols. + + The Write Byte, Read Byte, Send Byte, and Receive Byte protocols are the + only valid SMBus protocols for the device. + +- BC-LinkTM Interface + The BC-Link is a proprietary bus that allows communication + between a Master device and a Companion device. The Master + device uses this serial bus to read and write registers + located on the Companion device. The bus comprises three signals, + BC_CLK, BC_DAT and BC_INT#. The Master device always provides the + clock, BC_CLK, and the Companion device is the source for an + independent asynchronous interrupt signal, BC_INT#. The ECE1099 + supports BC-Link speeds up to 24MHz. diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 6d78841fd416..2907ba6c3607 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -181,6 +181,8 @@ core_pattern is used to specify a core dumpfile pattern name. %p pid %u uid %g gid + %d dump mode, matches PR_SET_DUMPABLE and + /proc/sys/fs/suid_dumpable %s signal number %t UNIX time of dump %h hostname diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index bf33aaa4c59f..f6ec3a92e621 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -857,7 +857,8 @@ struct kvm_userspace_memory_region { }; /* for kvm_memory_region::flags */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL +#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) +#define KVM_MEM_READONLY (1UL << 1) This ioctl allows the user to create or modify a guest physical memory slot. When changing an existing slot, it may be moved in the guest @@ -873,14 +874,17 @@ It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr be identical. This allows large pages in the guest to be backed by large pages in the host. -The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which -instructs kvm to keep track of writes to memory within the slot. See -the KVM_GET_DIRTY_LOG ioctl. +The flags field supports two flag, KVM_MEM_LOG_DIRTY_PAGES, which instructs +kvm to keep track of writes to memory within the slot. See KVM_GET_DIRTY_LOG +ioctl. The KVM_CAP_READONLY_MEM capability indicates the availability of the +KVM_MEM_READONLY flag. When this flag is set for a memory region, KVM only +allows read accesses. Writes will be posted to userspace as KVM_EXIT_MMIO +exits. -When the KVM_CAP_SYNC_MMU capability, changes in the backing of the memory -region are automatically reflected into the guest. For example, an mmap() -that affects the region will be made visible immediately. Another example -is madvise(MADV_DROP). +When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of +the memory region are automatically reflected into the guest. For example, an +mmap() that affects the region will be made visible immediately. Another +example is madvise(MADV_DROP). It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl. The KVM_SET_MEMORY_REGION does not allow fine grained control over memory @@ -1946,6 +1950,19 @@ the guest using the specified gsi pin. The irqfd is removed using the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd and kvm_irqfd.gsi. +With KVM_CAP_IRQFD_RESAMPLE, KVM_IRQFD supports a de-assert and notify +mechanism allowing emulation of level-triggered, irqfd-based +interrupts. When KVM_IRQFD_FLAG_RESAMPLE is set the user must pass an +additional eventfd in the kvm_irqfd.resamplefd field. When operating +in resample mode, posting of an interrupt through kvm_irq.fd asserts +the specified gsi in the irqchip. When the irqchip is resampled, such +as from an EOI, the gsi is de-asserted and the user is notifed via +kvm_irqfd.resamplefd. It is the user's responsibility to re-queue +the interrupt if the device making use of it still requires service. +Note that closing the resamplefd is not sufficient to disable the +irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment +and need not be specified with KVM_IRQFD_FLAG_DEASSIGN. + 4.76 KVM_PPC_ALLOCATE_HTAB Capability: KVM_CAP_PPC_ALLOC_HTAB diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt new file mode 100644 index 000000000000..ea113b5d87a4 --- /dev/null +++ b/Documentation/virtual/kvm/hypercalls.txt @@ -0,0 +1,66 @@ +Linux KVM Hypercall: +=================== +X86: + KVM Hypercalls have a three-byte sequence of either the vmcall or the vmmcall + instruction. The hypervisor can replace it with instructions that are + guaranteed to be supported. + + Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively. + The hypercall number should be placed in rax and the return value will be + placed in rax. No other registers will be clobbered unless explicitly stated + by the particular hypercall. + +S390: + R2-R7 are used for parameters 1-6. In addition, R1 is used for hypercall + number. The return value is written to R2. + + S390 uses diagnose instruction as hypercall (0x500) along with hypercall + number in R1. + + PowerPC: + It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers. + Return value is placed in R3. + + KVM hypercalls uses 4 byte opcode, that are patched with 'hypercall-instructions' + property inside the device tree's /hypervisor node. + For more information refer to Documentation/virtual/kvm/ppc-pv.txt + +KVM Hypercalls Documentation +=========================== +The template for each hypercall is: +1. Hypercall name. +2. Architecture(s) +3. Status (deprecated, obsolete, active) +4. Purpose + +1. KVM_HC_VAPIC_POLL_IRQ +------------------------ +Architecture: x86 +Status: active +Purpose: Trigger guest exit so that the host can check for pending +interrupts on reentry. + +2. KVM_HC_MMU_OP +------------------------ +Architecture: x86 +Status: deprecated. +Purpose: Support MMU operations such as writing to PTE, +flushing TLB, release PT. + +3. KVM_HC_FEATURES +------------------------ +Architecture: PPC +Status: active +Purpose: Expose hypercall availability to the guest. On x86 platforms, cpuid +used to enumerate which hypercalls are available. On PPC, either device tree +based lookup ( which is also what EPAPR dictates) OR KVM specific enumeration +mechanism (which is this hypercall) can be used. + +4. KVM_HC_PPC_MAP_MAGIC_PAGE +------------------------ +Architecture: PPC +Status: active +Purpose: To enable communication between the hypervisor and guest there is a +shared page that contains parts of supervisor visible register state. +The guest can map this shared page to access its supervisor register through +memory using this hypercall. diff --git a/Documentation/virtual/kvm/msr.txt b/Documentation/virtual/kvm/msr.txt index 730471048583..6d470ae7b073 100644 --- a/Documentation/virtual/kvm/msr.txt +++ b/Documentation/virtual/kvm/msr.txt @@ -34,9 +34,12 @@ MSR_KVM_WALL_CLOCK_NEW: 0x4b564d00 time information and check that they are both equal and even. An odd version indicates an in-progress update. - sec: number of seconds for wallclock. + sec: number of seconds for wallclock at time of boot. - nsec: number of nanoseconds for wallclock. + nsec: number of nanoseconds for wallclock at time of boot. + + In order to get the current wallclock time, the system_time from + MSR_KVM_SYSTEM_TIME_NEW needs to be added. Note that although MSRs are per-CPU entities, the effect of this particular MSR is global. @@ -82,20 +85,25 @@ MSR_KVM_SYSTEM_TIME_NEW: 0x4b564d01 time at the time this structure was last updated. Unit is nanoseconds. - tsc_to_system_mul: a function of the tsc frequency. One has - to multiply any tsc-related quantity by this value to get - a value in nanoseconds, besides dividing by 2^tsc_shift + tsc_to_system_mul: multiplier to be used when converting + tsc-related quantity to nanoseconds - tsc_shift: cycle to nanosecond divider, as a power of two, to - allow for shift rights. One has to shift right any tsc-related - quantity by this value to get a value in nanoseconds, besides - multiplying by tsc_to_system_mul. + tsc_shift: shift to be used when converting tsc-related + quantity to nanoseconds. This shift will ensure that + multiplication with tsc_to_system_mul does not overflow. + A positive value denotes a left shift, a negative value + a right shift. - With this information, guests can derive per-CPU time by - doing: + The conversion from tsc to nanoseconds involves an additional + right shift by 32 bits. With this information, guests can + derive per-CPU time by doing: time = (current_tsc - tsc_timestamp) - time = (time * tsc_to_system_mul) >> tsc_shift + if (tsc_shift >= 0) + time <<= tsc_shift; + else + time >>= -tsc_shift; + time = (time * tsc_to_system_mul) >> 32 time = time + system_time flags: bits in this field indicate extended capabilities diff --git a/Documentation/virtual/kvm/ppc-pv.txt b/Documentation/virtual/kvm/ppc-pv.txt index 4911cf95c67e..4cd076febb02 100644 --- a/Documentation/virtual/kvm/ppc-pv.txt +++ b/Documentation/virtual/kvm/ppc-pv.txt @@ -174,3 +174,25 @@ following: That way we can inject an arbitrary amount of code as replacement for a single instruction. This allows us to check for pending interrupts when setting EE=1 for example. + +Hypercall ABIs in KVM on PowerPC +================================= +1) KVM hypercalls (ePAPR) + +These are ePAPR compliant hypercall implementation (mentioned above). Even +generic hypercalls are implemented here, like the ePAPR idle hcall. These are +available on all targets. + +2) PAPR hypercalls + +PAPR hypercalls are needed to run server PowerPC PAPR guests (-M pseries in QEMU). +These are the same hypercalls that pHyp, the POWER hypervisor implements. Some of +them are handled in the kernel, some are handled in user space. This is only +available on book3s_64. + +3) OSI hypercalls + +Mac-on-Linux is another user of KVM on PowerPC, which has its own hypercall (long +before KVM). This is supported to maintain compatibility. All these hypercalls get +forwarded to user space. This is only useful on book3s_32, but can be used with +book3s_64 as well. diff --git a/MAINTAINERS b/MAINTAINERS index d919e3d4a0db..42c2264a154c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -572,7 +572,7 @@ F: drivers/net/appletalk/ F: net/appletalk/ ARASAN COMPACT FLASH PATA CONTROLLER -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> L: linux-ide@vger.kernel.org S: Maintained F: include/linux/pata_arasan_cf_data.h @@ -760,6 +760,7 @@ S: Maintained T: git git://git.pengutronix.de/git/imx/linux-2.6.git F: arch/arm/mach-imx/ F: arch/arm/plat-mxc/ +F: arch/arm/configs/imx*_defconfig ARM/FREESCALE IMX6 M: Shawn Guo <shawn.guo@linaro.org> @@ -1245,7 +1246,7 @@ F: include/linux/i2c/at24.h ATA OVER ETHERNET (AOE) DRIVER M: "Ed L. Cashin" <ecashin@coraid.com> -W: http://www.coraid.com/support/linux +W: http://support.coraid.com/support/linux S: Supported F: Documentation/aoe/ F: drivers/block/aoe/ @@ -3123,6 +3124,7 @@ T: git git://git.secretlab.ca/git/linux-2.6.git F: Documentation/gpio.txt F: drivers/gpio/ F: include/linux/gpio* +F: include/asm-generic/gpio.h GRE DEMULTIPLEXER DRIVER M: Dmitry Kozlov <xeb@mail.ru> @@ -3438,6 +3440,18 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git S: Maintained F: arch/ia64/ +IBM Power in-Nest Crypto Acceleration +M: Kent Yoder <key@linux.vnet.ibm.com> +L: linux-crypto@vger.kernel.org +S: Supported +F: drivers/crypto/nx/ + +IBM Power 842 compression accelerator +M: Robert Jennings <rcj@linux.vnet.ibm.com> +S: Supported +F: drivers/crypto/nx/nx-842.c +F: include/linux/nx842.h + IBM Power Linux RAID adapter M: Brian King <brking@us.ibm.com> S: Supported @@ -5253,7 +5267,7 @@ F: include/linux/i2c-algo-pca.h F: include/linux/i2c-pca-platform.h PCDP - PRIMARY CONSOLE AND DEBUG PORT -M: Khalid Aziz <khalid.aziz@hp.com> +M: Khalid Aziz <khalid@gonehiking.org> S: Maintained F: drivers/firmware/pcdp.* @@ -5542,7 +5556,7 @@ S: Maintained W: http://linuxptp.sourceforge.net/ F: Documentation/ABI/testing/sysfs-ptp F: Documentation/ptp/* -F: drivers/net/gianfar_ptp.c +F: drivers/net/ethernet/freescale/gianfar_ptp.c F: drivers/net/phy/dp83640* F: drivers/ptp/* F: include/linux/ptp_cl* @@ -5974,7 +5988,7 @@ S: Maintained F: drivers/tty/serial SYNOPSYS DESIGNWARE DMAC DRIVER -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> S: Maintained F: include/linux/dw_dmac.h F: drivers/dma/dw_dmac_regs.h @@ -6122,7 +6136,7 @@ S: Maintained F: drivers/mmc/host/sdhci-s3c.c SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> L: spear-devel@list.st.com L: linux-mmc@vger.kernel.org S: Maintained @@ -6487,7 +6501,7 @@ S: Maintained F: include/linux/compiler.h SPEAR PLATFORM SUPPORT -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> M: Shiraz Hashim <shiraz.hashim@st.com> L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -6496,7 +6510,7 @@ S: Maintained F: arch/arm/plat-spear/ SPEAR13XX MACHINE SUPPORT -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> M: Shiraz Hashim <shiraz.hashim@st.com> L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -6505,7 +6519,7 @@ S: Maintained F: arch/arm/mach-spear13xx/ SPEAR3XX MACHINE SUPPORT -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> M: Shiraz Hashim <shiraz.hashim@st.com> L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@ -6516,7 +6530,7 @@ F: arch/arm/mach-spear3xx/ SPEAR6XX MACHINE SUPPORT M: Rajeev Kumar <rajeev-dlh.kumar@st.com> M: Shiraz Hashim <shiraz.hashim@st.com> -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.st.com/spear @@ -6524,7 +6538,7 @@ S: Maintained F: arch/arm/mach-spear6xx/ SPEAR CLOCK FRAMEWORK SUPPORT -M: Viresh Kumar <viresh.linux@gmail.com> +M: Viresh Kumar <viresh.linux@gmail.com> L: spear-devel@list.st.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.st.com/spear @@ -7789,6 +7803,13 @@ F: drivers/xen/ F: arch/x86/include/asm/xen/ F: include/xen/ +XEN HYPERVISOR ARM +M: Stefano Stabellini <stefano.stabellini@eu.citrix.com> +L: xen-devel@lists.xensource.com (moderated for non-subscribers) +S: Supported +F: arch/arm/xen/ +F: arch/arm/include/asm/xen/ + XEN NETWORK BACKEND DRIVER M: Ian Campbell <ian.campbell@citrix.com> L: xen-devel@lists.xensource.com (moderated for non-subscribers) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7bab17ed2972..3975d10cb3ed 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1829,6 +1829,16 @@ config DEPRECATED_PARAM_STRUCT This was deprecated in 2001 and announced to live on for 5 years. Some old boot loaders still use this way. +config XEN_DOM0 + def_bool y + depends on XEN + +config XEN + bool "Xen guest support on ARM (EXPERIMENTAL)" + depends on EXPERIMENTAL && ARM && OF + help + Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. + endmenu menu "Boot options" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 770da51242c4..40ea991b6782 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -250,10 +250,12 @@ endif core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_VFP) += arch/arm/vfp/ +core-$(CONFIG_XEN) += arch/arm/xen/ # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += arch/arm/net/ +core-y += arch/arm/crypto/ core-y += $(machdirs) $(platdirs) drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 43c084c2cd66..4745c1f68b49 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -96,6 +96,7 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ vexpress-v2p-ca9.dtb \ vexpress-v2p-ca15-tc1.dtb \ - vexpress-v2p-ca15_a7.dtb + vexpress-v2p-ca15_a7.dtb \ + xenvm-4.2.dtb endif diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 35e5895ba3df..f3990b04fecf 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -400,8 +400,8 @@ #clock-cells = <1>; }; - anatop@020c8000 { - compatible = "fsl,imx6q-anatop"; + anatop: anatop@020c8000 { + compatible = "fsl,imx6q-anatop", "syscon", "simple-bus"; reg = <0x020c8000 0x1000>; interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; @@ -531,6 +531,11 @@ interrupts = <0 89 0x04 0 90 0x04>; }; + gpr: iomuxc-gpr@020e0000 { + compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; + reg = <0x020e0000 0x38>; + }; + iomuxc@020e0000 { compatible = "fsl,imx6q-iomuxc"; reg = <0x020e0000 0x4000>; diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts index e92be5a474e7..595492aa5053 100644 --- a/arch/arm/boot/dts/pxa910-dkb.dts +++ b/arch/arm/boot/dts/pxa910-dkb.dts @@ -29,6 +29,143 @@ }; twsi1: i2c@d4011000 { status = "okay"; + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + interrupts = <4>; + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <1>; + + marvell,88pm860x-irq-read-clr; + marvell,88pm860x-slave-addr = <0x11>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + BUCK2 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + BUCK3 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + LDO1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2800000>; + regulator-boot-on; + regulator-always-on; + }; + LDO2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + LDO3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + LDO4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + LDO5 { + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + LDO6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + LDO7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-boot-on; + regulator-always-on; + }; + LDO8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-boot-on; + regulator-always-on; + }; + LDO9 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + LDO10 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + LDO12 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + LDO13 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + LDO14 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + rtc { + marvell,88pm860x-vrtc = <1>; + }; + touch { + marvell,88pm860x-gpadc-prebias = <1>; + marvell,88pm860x-gpadc-slot-cycle = <1>; + marvell,88pm860x-tsi-prebias = <6>; + marvell,88pm860x-pen-prebias = <16>; + marvell,88pm860x-pen-prechg = <2>; + marvell,88pm860x-resistor-X = <300>; + }; + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; + }; + leds { + led0-red { + marvell,88pm860x-iset = <12>; + }; + led0-green { + marvell,88pm860x-iset = <12>; + }; + led0-blue { + marvell,88pm860x-iset = <12>; + }; + }; + }; }; rtc: rtc@d4010000 { status = "okay"; diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi index a3be44d86bcd..825aaca33034 100644 --- a/arch/arm/boot/dts/pxa910.dtsi +++ b/arch/arm/boot/dts/pxa910.dtsi @@ -120,6 +120,8 @@ twsi1: i2c@d4011000 { compatible = "mrvl,mmp-twsi"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xd4011000 0x1000>; interrupts = <7>; mrvl,i2c-fast-mode; @@ -128,6 +130,8 @@ twsi2: i2c@d4037000 { compatible = "mrvl,mmp-twsi"; + #address-cells = <1>; + #size-cells = <0>; reg = <0xd4037000 0x1000>; interrupts = <54>; status = "disabled"; diff --git a/arch/arm/boot/dts/xenvm-4.2.dts b/arch/arm/boot/dts/xenvm-4.2.dts new file mode 100644 index 000000000000..ec3f9528e180 --- /dev/null +++ b/arch/arm/boot/dts/xenvm-4.2.dts @@ -0,0 +1,68 @@ +/* + * Xen Virtual Machine for unprivileged guests + * + * Based on ARM Ltd. Versatile Express CoreTile Express (single CPU) + * Cortex-A15 MPCore (V2P-CA15) + * + */ + +/dts-v1/; + +/ { + model = "XENVM-4.2"; + compatible = "xen,xenvm-4.2", "xen,xenvm"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + /* this field is going to be adjusted by the hypervisor */ + bootargs = "console=hvc0 root=/dev/xvda"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0>; + }; + }; + + memory@80000000 { + device_type = "memory"; + /* this field is going to be adjusted by the hypervisor */ + reg = <0 0x80000000 0 0x08000000>; + }; + + gic: interrupt-controller@2c001000 { + compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0x2c001000 0 0x1000>, + <0 0x2c002000 0 0x100>; + }; + + timer { + compatible = "arm,armv7-timer"; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>, + <1 10 0xf08>; + }; + + hypervisor { + compatible = "xen,xen-4.2", "xen,xen"; + /* this field is going to be adjusted by the hypervisor */ + reg = <0 0xb0000000 0 0x20000>; + /* this field is going to be adjusted by the hypervisor */ + interrupts = <1 15 0xf08>; + }; + + motherboard { + arm,v2m-memory-map = "rs1"; + }; +}; diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile new file mode 100644 index 000000000000..a2c83851bc90 --- /dev/null +++ b/arch/arm/crypto/Makefile @@ -0,0 +1,9 @@ +# +# Arch-specific CryptoAPI modules. +# + +obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o +obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o + +aes-arm-y := aes-armv4.o aes_glue.o +sha1-arm-y := sha1-armv4-large.o sha1_glue.o diff --git a/arch/arm/crypto/aes-armv4.S b/arch/arm/crypto/aes-armv4.S new file mode 100644 index 000000000000..e59b1d505d6c --- /dev/null +++ b/arch/arm/crypto/aes-armv4.S @@ -0,0 +1,1112 @@ +#define __ARM_ARCH__ __LINUX_ARM_ARCH__ +@ ==================================================================== +@ Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL +@ project. The module is, however, dual licensed under OpenSSL and +@ CRYPTOGAMS licenses depending on where you obtain it. For further +@ details see http://www.openssl.org/~appro/cryptogams/. +@ ==================================================================== + +@ AES for ARMv4 + +@ January 2007. +@ +@ Code uses single 1K S-box and is >2 times faster than code generated +@ by gcc-3.4.1. This is thanks to unique feature of ARMv4 ISA, which +@ allows to merge logical or arithmetic operation with shift or rotate +@ in one instruction and emit combined result every cycle. The module +@ is endian-neutral. The performance is ~42 cycles/byte for 128-bit +@ key [on single-issue Xscale PXA250 core]. + +@ May 2007. +@ +@ AES_set_[en|de]crypt_key is added. + +@ July 2010. +@ +@ Rescheduling for dual-issue pipeline resulted in 12% improvement on +@ Cortex A8 core and ~25 cycles per byte processed with 128-bit key. + +@ February 2011. +@ +@ Profiler-assisted and platform-specific optimization resulted in 16% +@ improvement on Cortex A8 core and ~21.5 cycles per byte. + +@ A little glue here to select the correct code below for the ARM CPU +@ that is being targetted. + +.text +.code 32 + +.type AES_Te,%object +.align 5 +AES_Te: +.word 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d +.word 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554 +.word 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d +.word 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a +.word 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87 +.word 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b +.word 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea +.word 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b +.word 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a +.word 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f +.word 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108 +.word 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f +.word 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e +.word 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5 +.word 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d +.word 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f +.word 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e +.word 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb +.word 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce +.word 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497 +.word 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c +.word 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed +.word 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b +.word 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a +.word 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16 +.word 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594 +.word 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81 +.word 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3 +.word 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a +.word 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504 +.word 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163 +.word 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d +.word 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f +.word 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739 +.word 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47 +.word 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395 +.word 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f +.word 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883 +.word 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c +.word 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76 +.word 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e +.word 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4 +.word 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6 +.word 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b +.word 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7 +.word 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0 +.word 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25 +.word 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818 +.word 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72 +.word 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651 +.word 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21 +.word 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85 +.word 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa +.word 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12 +.word 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0 +.word 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9 +.word 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133 +.word 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7 +.word 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920 +.word 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a +.word 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17 +.word 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8 +.word 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11 +.word 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +@ Te4[256] +.byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 +.byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 +.byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 +.byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 +.byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc +.byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 +.byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a +.byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 +.byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 +.byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 +.byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b +.byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf +.byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 +.byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 +.byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 +.byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 +.byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 +.byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 +.byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 +.byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb +.byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c +.byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 +.byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 +.byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 +.byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 +.byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a +.byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e +.byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e +.byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 +.byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf +.byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 +.byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +@ rcon[] +.word 0x01000000, 0x02000000, 0x04000000, 0x08000000 +.word 0x10000000, 0x20000000, 0x40000000, 0x80000000 +.word 0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0 +.size AES_Te,.-AES_Te + +@ void AES_encrypt(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.global AES_encrypt +.type AES_encrypt,%function +.align 5 +AES_encrypt: + sub r3,pc,#8 @ AES_encrypt + stmdb sp!,{r1,r4-r12,lr} + mov r12,r0 @ inp + mov r11,r2 + sub r10,r3,#AES_encrypt-AES_Te @ Te +#if __ARM_ARCH__<7 + ldrb r0,[r12,#3] @ load input data in endian-neutral + ldrb r4,[r12,#2] @ manner... + ldrb r5,[r12,#1] + ldrb r6,[r12,#0] + orr r0,r0,r4,lsl#8 + ldrb r1,[r12,#7] + orr r0,r0,r5,lsl#16 + ldrb r4,[r12,#6] + orr r0,r0,r6,lsl#24 + ldrb r5,[r12,#5] + ldrb r6,[r12,#4] + orr r1,r1,r4,lsl#8 + ldrb r2,[r12,#11] + orr r1,r1,r5,lsl#16 + ldrb r4,[r12,#10] + orr r1,r1,r6,lsl#24 + ldrb r5,[r12,#9] + ldrb r6,[r12,#8] + orr r2,r2,r4,lsl#8 + ldrb r3,[r12,#15] + orr r2,r2,r5,lsl#16 + ldrb r4,[r12,#14] + orr r2,r2,r6,lsl#24 + ldrb r5,[r12,#13] + ldrb r6,[r12,#12] + orr r3,r3,r4,lsl#8 + orr r3,r3,r5,lsl#16 + orr r3,r3,r6,lsl#24 +#else + ldr r0,[r12,#0] + ldr r1,[r12,#4] + ldr r2,[r12,#8] + ldr r3,[r12,#12] +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif +#endif + bl _armv4_AES_encrypt + + ldr r12,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif + str r0,[r12,#0] + str r1,[r12,#4] + str r2,[r12,#8] + str r3,[r12,#12] +#else + mov r4,r0,lsr#24 @ write output in endian-neutral + mov r5,r0,lsr#16 @ manner... + mov r6,r0,lsr#8 + strb r4,[r12,#0] + strb r5,[r12,#1] + mov r4,r1,lsr#24 + strb r6,[r12,#2] + mov r5,r1,lsr#16 + strb r0,[r12,#3] + mov r6,r1,lsr#8 + strb r4,[r12,#4] + strb r5,[r12,#5] + mov r4,r2,lsr#24 + strb r6,[r12,#6] + mov r5,r2,lsr#16 + strb r1,[r12,#7] + mov r6,r2,lsr#8 + strb r4,[r12,#8] + strb r5,[r12,#9] + mov r4,r3,lsr#24 + strb r6,[r12,#10] + mov r5,r3,lsr#16 + strb r2,[r12,#11] + mov r6,r3,lsr#8 + strb r4,[r12,#12] + strb r5,[r12,#13] + strb r6,[r12,#14] + strb r3,[r12,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + .word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size AES_encrypt,.-AES_encrypt + +.type _armv4_AES_encrypt,%function +.align 2 +_armv4_AES_encrypt: + str lr,[sp,#-4]! @ push lr + ldmia r11!,{r4-r7} + eor r0,r0,r4 + ldr r12,[r11,#240-16] + eor r1,r1,r5 + eor r2,r2,r6 + eor r3,r3,r7 + sub r12,r12,#1 + mov lr,#255 + + and r7,lr,r0 + and r8,lr,r0,lsr#8 + and r9,lr,r0,lsr#16 + mov r0,r0,lsr#24 +.Lenc_loop: + ldr r4,[r10,r7,lsl#2] @ Te3[s0>>0] + and r7,lr,r1,lsr#16 @ i0 + ldr r5,[r10,r8,lsl#2] @ Te2[s0>>8] + and r8,lr,r1 + ldr r6,[r10,r9,lsl#2] @ Te1[s0>>16] + and r9,lr,r1,lsr#8 + ldr r0,[r10,r0,lsl#2] @ Te0[s0>>24] + mov r1,r1,lsr#24 + + ldr r7,[r10,r7,lsl#2] @ Te1[s1>>16] + ldr r8,[r10,r8,lsl#2] @ Te3[s1>>0] + ldr r9,[r10,r9,lsl#2] @ Te2[s1>>8] + eor r0,r0,r7,ror#8 + ldr r1,[r10,r1,lsl#2] @ Te0[s1>>24] + and r7,lr,r2,lsr#8 @ i0 + eor r5,r5,r8,ror#8 + and r8,lr,r2,lsr#16 @ i1 + eor r6,r6,r9,ror#8 + and r9,lr,r2 + ldr r7,[r10,r7,lsl#2] @ Te2[s2>>8] + eor r1,r1,r4,ror#24 + ldr r8,[r10,r8,lsl#2] @ Te1[s2>>16] + mov r2,r2,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Te3[s2>>0] + eor r0,r0,r7,ror#16 + ldr r2,[r10,r2,lsl#2] @ Te0[s2>>24] + and r7,lr,r3 @ i0 + eor r1,r1,r8,ror#8 + and r8,lr,r3,lsr#8 @ i1 + eor r6,r6,r9,ror#16 + and r9,lr,r3,lsr#16 @ i2 + ldr r7,[r10,r7,lsl#2] @ Te3[s3>>0] + eor r2,r2,r5,ror#16 + ldr r8,[r10,r8,lsl#2] @ Te2[s3>>8] + mov r3,r3,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Te1[s3>>16] + eor r0,r0,r7,ror#24 + ldr r7,[r11],#16 + eor r1,r1,r8,ror#16 + ldr r3,[r10,r3,lsl#2] @ Te0[s3>>24] + eor r2,r2,r9,ror#8 + ldr r4,[r11,#-12] + eor r3,r3,r6,ror#8 + + ldr r5,[r11,#-8] + eor r0,r0,r7 + ldr r6,[r11,#-4] + and r7,lr,r0 + eor r1,r1,r4 + and r8,lr,r0,lsr#8 + eor r2,r2,r5 + and r9,lr,r0,lsr#16 + eor r3,r3,r6 + mov r0,r0,lsr#24 + + subs r12,r12,#1 + bne .Lenc_loop + + add r10,r10,#2 + + ldrb r4,[r10,r7,lsl#2] @ Te4[s0>>0] + and r7,lr,r1,lsr#16 @ i0 + ldrb r5,[r10,r8,lsl#2] @ Te4[s0>>8] + and r8,lr,r1 + ldrb r6,[r10,r9,lsl#2] @ Te4[s0>>16] + and r9,lr,r1,lsr#8 + ldrb r0,[r10,r0,lsl#2] @ Te4[s0>>24] + mov r1,r1,lsr#24 + + ldrb r7,[r10,r7,lsl#2] @ Te4[s1>>16] + ldrb r8,[r10,r8,lsl#2] @ Te4[s1>>0] + ldrb r9,[r10,r9,lsl#2] @ Te4[s1>>8] + eor r0,r7,r0,lsl#8 + ldrb r1,[r10,r1,lsl#2] @ Te4[s1>>24] + and r7,lr,r2,lsr#8 @ i0 + eor r5,r8,r5,lsl#8 + and r8,lr,r2,lsr#16 @ i1 + eor r6,r9,r6,lsl#8 + and r9,lr,r2 + ldrb r7,[r10,r7,lsl#2] @ Te4[s2>>8] + eor r1,r4,r1,lsl#24 + ldrb r8,[r10,r8,lsl#2] @ Te4[s2>>16] + mov r2,r2,lsr#24 + + ldrb r9,[r10,r9,lsl#2] @ Te4[s2>>0] + eor r0,r7,r0,lsl#8 + ldrb r2,[r10,r2,lsl#2] @ Te4[s2>>24] + and r7,lr,r3 @ i0 + eor r1,r1,r8,lsl#16 + and r8,lr,r3,lsr#8 @ i1 + eor r6,r9,r6,lsl#8 + and r9,lr,r3,lsr#16 @ i2 + ldrb r7,[r10,r7,lsl#2] @ Te4[s3>>0] + eor r2,r5,r2,lsl#24 + ldrb r8,[r10,r8,lsl#2] @ Te4[s3>>8] + mov r3,r3,lsr#24 + + ldrb r9,[r10,r9,lsl#2] @ Te4[s3>>16] + eor r0,r7,r0,lsl#8 + ldr r7,[r11,#0] + ldrb r3,[r10,r3,lsl#2] @ Te4[s3>>24] + eor r1,r1,r8,lsl#8 + ldr r4,[r11,#4] + eor r2,r2,r9,lsl#16 + ldr r5,[r11,#8] + eor r3,r6,r3,lsl#24 + ldr r6,[r11,#12] + + eor r0,r0,r7 + eor r1,r1,r4 + eor r2,r2,r5 + eor r3,r3,r6 + + sub r10,r10,#2 + ldr pc,[sp],#4 @ pop and return +.size _armv4_AES_encrypt,.-_armv4_AES_encrypt + +.global private_AES_set_encrypt_key +.type private_AES_set_encrypt_key,%function +.align 5 +private_AES_set_encrypt_key: +_armv4_AES_set_encrypt_key: + sub r3,pc,#8 @ AES_set_encrypt_key + teq r0,#0 + moveq r0,#-1 + beq .Labrt + teq r2,#0 + moveq r0,#-1 + beq .Labrt + + teq r1,#128 + beq .Lok + teq r1,#192 + beq .Lok + teq r1,#256 + movne r0,#-1 + bne .Labrt + +.Lok: stmdb sp!,{r4-r12,lr} + sub r10,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4 + + mov r12,r0 @ inp + mov lr,r1 @ bits + mov r11,r2 @ key + +#if __ARM_ARCH__<7 + ldrb r0,[r12,#3] @ load input data in endian-neutral + ldrb r4,[r12,#2] @ manner... + ldrb r5,[r12,#1] + ldrb r6,[r12,#0] + orr r0,r0,r4,lsl#8 + ldrb r1,[r12,#7] + orr r0,r0,r5,lsl#16 + ldrb r4,[r12,#6] + orr r0,r0,r6,lsl#24 + ldrb r5,[r12,#5] + ldrb r6,[r12,#4] + orr r1,r1,r4,lsl#8 + ldrb r2,[r12,#11] + orr r1,r1,r5,lsl#16 + ldrb r4,[r12,#10] + orr r1,r1,r6,lsl#24 + ldrb r5,[r12,#9] + ldrb r6,[r12,#8] + orr r2,r2,r4,lsl#8 + ldrb r3,[r12,#15] + orr r2,r2,r5,lsl#16 + ldrb r4,[r12,#14] + orr r2,r2,r6,lsl#24 + ldrb r5,[r12,#13] + ldrb r6,[r12,#12] + orr r3,r3,r4,lsl#8 + str r0,[r11],#16 + orr r3,r3,r5,lsl#16 + str r1,[r11,#-12] + orr r3,r3,r6,lsl#24 + str r2,[r11,#-8] + str r3,[r11,#-4] +#else + ldr r0,[r12,#0] + ldr r1,[r12,#4] + ldr r2,[r12,#8] + ldr r3,[r12,#12] +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif + str r0,[r11],#16 + str r1,[r11,#-12] + str r2,[r11,#-8] + str r3,[r11,#-4] +#endif + + teq lr,#128 + bne .Lnot128 + mov r12,#10 + str r12,[r11,#240-16] + add r6,r10,#256 @ rcon + mov lr,#255 + +.L128_loop: + and r5,lr,r3,lsr#24 + and r7,lr,r3,lsr#16 + ldrb r5,[r10,r5] + and r8,lr,r3,lsr#8 + ldrb r7,[r10,r7] + and r9,lr,r3 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#24 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r6],#4 @ rcon[i++] + orr r5,r5,r9,lsl#8 + eor r5,r5,r4 + eor r0,r0,r5 @ rk[4]=rk[0]^... + eor r1,r1,r0 @ rk[5]=rk[1]^rk[4] + str r0,[r11],#16 + eor r2,r2,r1 @ rk[6]=rk[2]^rk[5] + str r1,[r11,#-12] + eor r3,r3,r2 @ rk[7]=rk[3]^rk[6] + str r2,[r11,#-8] + subs r12,r12,#1 + str r3,[r11,#-4] + bne .L128_loop + sub r2,r11,#176 + b .Ldone + +.Lnot128: +#if __ARM_ARCH__<7 + ldrb r8,[r12,#19] + ldrb r4,[r12,#18] + ldrb r5,[r12,#17] + ldrb r6,[r12,#16] + orr r8,r8,r4,lsl#8 + ldrb r9,[r12,#23] + orr r8,r8,r5,lsl#16 + ldrb r4,[r12,#22] + orr r8,r8,r6,lsl#24 + ldrb r5,[r12,#21] + ldrb r6,[r12,#20] + orr r9,r9,r4,lsl#8 + orr r9,r9,r5,lsl#16 + str r8,[r11],#8 + orr r9,r9,r6,lsl#24 + str r9,[r11,#-4] +#else + ldr r8,[r12,#16] + ldr r9,[r12,#20] +#ifdef __ARMEL__ + rev r8,r8 + rev r9,r9 +#endif + str r8,[r11],#8 + str r9,[r11,#-4] +#endif + + teq lr,#192 + bne .Lnot192 + mov r12,#12 + str r12,[r11,#240-24] + add r6,r10,#256 @ rcon + mov lr,#255 + mov r12,#8 + +.L192_loop: + and r5,lr,r9,lsr#24 + and r7,lr,r9,lsr#16 + ldrb r5,[r10,r5] + and r8,lr,r9,lsr#8 + ldrb r7,[r10,r7] + and r9,lr,r9 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#24 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r6],#4 @ rcon[i++] + orr r5,r5,r9,lsl#8 + eor r9,r5,r4 + eor r0,r0,r9 @ rk[6]=rk[0]^... + eor r1,r1,r0 @ rk[7]=rk[1]^rk[6] + str r0,[r11],#24 + eor r2,r2,r1 @ rk[8]=rk[2]^rk[7] + str r1,[r11,#-20] + eor r3,r3,r2 @ rk[9]=rk[3]^rk[8] + str r2,[r11,#-16] + subs r12,r12,#1 + str r3,[r11,#-12] + subeq r2,r11,#216 + beq .Ldone + + ldr r7,[r11,#-32] + ldr r8,[r11,#-28] + eor r7,r7,r3 @ rk[10]=rk[4]^rk[9] + eor r9,r8,r7 @ rk[11]=rk[5]^rk[10] + str r7,[r11,#-8] + str r9,[r11,#-4] + b .L192_loop + +.Lnot192: +#if __ARM_ARCH__<7 + ldrb r8,[r12,#27] + ldrb r4,[r12,#26] + ldrb r5,[r12,#25] + ldrb r6,[r12,#24] + orr r8,r8,r4,lsl#8 + ldrb r9,[r12,#31] + orr r8,r8,r5,lsl#16 + ldrb r4,[r12,#30] + orr r8,r8,r6,lsl#24 + ldrb r5,[r12,#29] + ldrb r6,[r12,#28] + orr r9,r9,r4,lsl#8 + orr r9,r9,r5,lsl#16 + str r8,[r11],#8 + orr r9,r9,r6,lsl#24 + str r9,[r11,#-4] +#else + ldr r8,[r12,#24] + ldr r9,[r12,#28] +#ifdef __ARMEL__ + rev r8,r8 + rev r9,r9 +#endif + str r8,[r11],#8 + str r9,[r11,#-4] +#endif + + mov r12,#14 + str r12,[r11,#240-32] + add r6,r10,#256 @ rcon + mov lr,#255 + mov r12,#7 + +.L256_loop: + and r5,lr,r9,lsr#24 + and r7,lr,r9,lsr#16 + ldrb r5,[r10,r5] + and r8,lr,r9,lsr#8 + ldrb r7,[r10,r7] + and r9,lr,r9 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#24 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r6],#4 @ rcon[i++] + orr r5,r5,r9,lsl#8 + eor r9,r5,r4 + eor r0,r0,r9 @ rk[8]=rk[0]^... + eor r1,r1,r0 @ rk[9]=rk[1]^rk[8] + str r0,[r11],#32 + eor r2,r2,r1 @ rk[10]=rk[2]^rk[9] + str r1,[r11,#-28] + eor r3,r3,r2 @ rk[11]=rk[3]^rk[10] + str r2,[r11,#-24] + subs r12,r12,#1 + str r3,[r11,#-20] + subeq r2,r11,#256 + beq .Ldone + + and r5,lr,r3 + and r7,lr,r3,lsr#8 + ldrb r5,[r10,r5] + and r8,lr,r3,lsr#16 + ldrb r7,[r10,r7] + and r9,lr,r3,lsr#24 + ldrb r8,[r10,r8] + orr r5,r5,r7,lsl#8 + ldrb r9,[r10,r9] + orr r5,r5,r8,lsl#16 + ldr r4,[r11,#-48] + orr r5,r5,r9,lsl#24 + + ldr r7,[r11,#-44] + ldr r8,[r11,#-40] + eor r4,r4,r5 @ rk[12]=rk[4]^... + ldr r9,[r11,#-36] + eor r7,r7,r4 @ rk[13]=rk[5]^rk[12] + str r4,[r11,#-16] + eor r8,r8,r7 @ rk[14]=rk[6]^rk[13] + str r7,[r11,#-12] + eor r9,r9,r8 @ rk[15]=rk[7]^rk[14] + str r8,[r11,#-8] + str r9,[r11,#-4] + b .L256_loop + +.Ldone: mov r0,#0 + ldmia sp!,{r4-r12,lr} +.Labrt: tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + .word 0xe12fff1e @ interoperable with Thumb ISA:-) +.size private_AES_set_encrypt_key,.-private_AES_set_encrypt_key + +.global private_AES_set_decrypt_key +.type private_AES_set_decrypt_key,%function +.align 5 +private_AES_set_decrypt_key: + str lr,[sp,#-4]! @ push lr +#if 0 + @ kernel does both of these in setkey so optimise this bit out by + @ expecting the key to already have the enc_key work done (see aes_glue.c) + bl _armv4_AES_set_encrypt_key +#else + mov r0,#0 +#endif + teq r0,#0 + ldrne lr,[sp],#4 @ pop lr + bne .Labrt + + stmdb sp!,{r4-r12} + + ldr r12,[r2,#240] @ AES_set_encrypt_key preserves r2, + mov r11,r2 @ which is AES_KEY *key + mov r7,r2 + add r8,r2,r12,lsl#4 + +.Linv: ldr r0,[r7] + ldr r1,[r7,#4] + ldr r2,[r7,#8] + ldr r3,[r7,#12] + ldr r4,[r8] + ldr r5,[r8,#4] + ldr r6,[r8,#8] + ldr r9,[r8,#12] + str r0,[r8],#-16 + str r1,[r8,#16+4] + str r2,[r8,#16+8] + str r3,[r8,#16+12] + str r4,[r7],#16 + str r5,[r7,#-12] + str r6,[r7,#-8] + str r9,[r7,#-4] + teq r7,r8 + bne .Linv + ldr r0,[r11,#16]! @ prefetch tp1 + mov r7,#0x80 + mov r8,#0x1b + orr r7,r7,#0x8000 + orr r8,r8,#0x1b00 + orr r7,r7,r7,lsl#16 + orr r8,r8,r8,lsl#16 + sub r12,r12,#1 + mvn r9,r7 + mov r12,r12,lsl#2 @ (rounds-1)*4 + +.Lmix: and r4,r0,r7 + and r1,r0,r9 + sub r4,r4,r4,lsr#7 + and r4,r4,r8 + eor r1,r4,r1,lsl#1 @ tp2 + + and r4,r1,r7 + and r2,r1,r9 + sub r4,r4,r4,lsr#7 + and r4,r4,r8 + eor r2,r4,r2,lsl#1 @ tp4 + + and r4,r2,r7 + and r3,r2,r9 + sub r4,r4,r4,lsr#7 + and r4,r4,r8 + eor r3,r4,r3,lsl#1 @ tp8 + + eor r4,r1,r2 + eor r5,r0,r3 @ tp9 + eor r4,r4,r3 @ tpe + eor r4,r4,r1,ror#24 + eor r4,r4,r5,ror#24 @ ^= ROTATE(tpb=tp9^tp2,8) + eor r4,r4,r2,ror#16 + eor r4,r4,r5,ror#16 @ ^= ROTATE(tpd=tp9^tp4,16) + eor r4,r4,r5,ror#8 @ ^= ROTATE(tp9,24) + + ldr r0,[r11,#4] @ prefetch tp1 + str r4,[r11],#4 + subs r12,r12,#1 + bne .Lmix + + mov r0,#0 +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + .word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size private_AES_set_decrypt_key,.-private_AES_set_decrypt_key + +.type AES_Td,%object +.align 5 +AES_Td: +.word 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96 +.word 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393 +.word 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25 +.word 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f +.word 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1 +.word 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6 +.word 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da +.word 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844 +.word 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd +.word 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4 +.word 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45 +.word 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94 +.word 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7 +.word 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a +.word 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5 +.word 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c +.word 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1 +.word 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a +.word 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75 +.word 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051 +.word 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46 +.word 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff +.word 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77 +.word 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb +.word 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000 +.word 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e +.word 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927 +.word 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a +.word 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e +.word 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16 +.word 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d +.word 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8 +.word 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd +.word 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34 +.word 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163 +.word 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120 +.word 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d +.word 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0 +.word 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422 +.word 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef +.word 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36 +.word 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4 +.word 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662 +.word 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5 +.word 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3 +.word 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b +.word 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8 +.word 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6 +.word 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6 +.word 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0 +.word 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815 +.word 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f +.word 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df +.word 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f +.word 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e +.word 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713 +.word 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89 +.word 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c +.word 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf +.word 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86 +.word 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f +.word 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541 +.word 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190 +.word 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +@ Td4[256] +.byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 +.byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb +.byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 +.byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb +.byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d +.byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e +.byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 +.byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 +.byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 +.byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 +.byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda +.byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 +.byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a +.byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 +.byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 +.byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b +.byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea +.byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 +.byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 +.byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e +.byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 +.byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b +.byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 +.byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 +.byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 +.byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f +.byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d +.byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef +.byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 +.byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 +.byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 +.byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +.size AES_Td,.-AES_Td + +@ void AES_decrypt(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.global AES_decrypt +.type AES_decrypt,%function +.align 5 +AES_decrypt: + sub r3,pc,#8 @ AES_decrypt + stmdb sp!,{r1,r4-r12,lr} + mov r12,r0 @ inp + mov r11,r2 + sub r10,r3,#AES_decrypt-AES_Td @ Td +#if __ARM_ARCH__<7 + ldrb r0,[r12,#3] @ load input data in endian-neutral + ldrb r4,[r12,#2] @ manner... + ldrb r5,[r12,#1] + ldrb r6,[r12,#0] + orr r0,r0,r4,lsl#8 + ldrb r1,[r12,#7] + orr r0,r0,r5,lsl#16 + ldrb r4,[r12,#6] + orr r0,r0,r6,lsl#24 + ldrb r5,[r12,#5] + ldrb r6,[r12,#4] + orr r1,r1,r4,lsl#8 + ldrb r2,[r12,#11] + orr r1,r1,r5,lsl#16 + ldrb r4,[r12,#10] + orr r1,r1,r6,lsl#24 + ldrb r5,[r12,#9] + ldrb r6,[r12,#8] + orr r2,r2,r4,lsl#8 + ldrb r3,[r12,#15] + orr r2,r2,r5,lsl#16 + ldrb r4,[r12,#14] + orr r2,r2,r6,lsl#24 + ldrb r5,[r12,#13] + ldrb r6,[r12,#12] + orr r3,r3,r4,lsl#8 + orr r3,r3,r5,lsl#16 + orr r3,r3,r6,lsl#24 +#else + ldr r0,[r12,#0] + ldr r1,[r12,#4] + ldr r2,[r12,#8] + ldr r3,[r12,#12] +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif +#endif + bl _armv4_AES_decrypt + + ldr r12,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev r0,r0 + rev r1,r1 + rev r2,r2 + rev r3,r3 +#endif + str r0,[r12,#0] + str r1,[r12,#4] + str r2,[r12,#8] + str r3,[r12,#12] +#else + mov r4,r0,lsr#24 @ write output in endian-neutral + mov r5,r0,lsr#16 @ manner... + mov r6,r0,lsr#8 + strb r4,[r12,#0] + strb r5,[r12,#1] + mov r4,r1,lsr#24 + strb r6,[r12,#2] + mov r5,r1,lsr#16 + strb r0,[r12,#3] + mov r6,r1,lsr#8 + strb r4,[r12,#4] + strb r5,[r12,#5] + mov r4,r2,lsr#24 + strb r6,[r12,#6] + mov r5,r2,lsr#16 + strb r1,[r12,#7] + mov r6,r2,lsr#8 + strb r4,[r12,#8] + strb r5,[r12,#9] + mov r4,r3,lsr#24 + strb r6,[r12,#10] + mov r5,r3,lsr#16 + strb r2,[r12,#11] + mov r6,r3,lsr#8 + strb r4,[r12,#12] + strb r5,[r12,#13] + strb r6,[r12,#14] + strb r3,[r12,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + .word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.size AES_decrypt,.-AES_decrypt + +.type _armv4_AES_decrypt,%function +.align 2 +_armv4_AES_decrypt: + str lr,[sp,#-4]! @ push lr + ldmia r11!,{r4-r7} + eor r0,r0,r4 + ldr r12,[r11,#240-16] + eor r1,r1,r5 + eor r2,r2,r6 + eor r3,r3,r7 + sub r12,r12,#1 + mov lr,#255 + + and r7,lr,r0,lsr#16 + and r8,lr,r0,lsr#8 + and r9,lr,r0 + mov r0,r0,lsr#24 +.Ldec_loop: + ldr r4,[r10,r7,lsl#2] @ Td1[s0>>16] + and r7,lr,r1 @ i0 + ldr r5,[r10,r8,lsl#2] @ Td2[s0>>8] + and r8,lr,r1,lsr#16 + ldr r6,[r10,r9,lsl#2] @ Td3[s0>>0] + and r9,lr,r1,lsr#8 + ldr r0,[r10,r0,lsl#2] @ Td0[s0>>24] + mov r1,r1,lsr#24 + + ldr r7,[r10,r7,lsl#2] @ Td3[s1>>0] + ldr r8,[r10,r8,lsl#2] @ Td1[s1>>16] + ldr r9,[r10,r9,lsl#2] @ Td2[s1>>8] + eor r0,r0,r7,ror#24 + ldr r1,[r10,r1,lsl#2] @ Td0[s1>>24] + and r7,lr,r2,lsr#8 @ i0 + eor r5,r8,r5,ror#8 + and r8,lr,r2 @ i1 + eor r6,r9,r6,ror#8 + and r9,lr,r2,lsr#16 + ldr r7,[r10,r7,lsl#2] @ Td2[s2>>8] + eor r1,r1,r4,ror#8 + ldr r8,[r10,r8,lsl#2] @ Td3[s2>>0] + mov r2,r2,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Td1[s2>>16] + eor r0,r0,r7,ror#16 + ldr r2,[r10,r2,lsl#2] @ Td0[s2>>24] + and r7,lr,r3,lsr#16 @ i0 + eor r1,r1,r8,ror#24 + and r8,lr,r3,lsr#8 @ i1 + eor r6,r9,r6,ror#8 + and r9,lr,r3 @ i2 + ldr r7,[r10,r7,lsl#2] @ Td1[s3>>16] + eor r2,r2,r5,ror#8 + ldr r8,[r10,r8,lsl#2] @ Td2[s3>>8] + mov r3,r3,lsr#24 + + ldr r9,[r10,r9,lsl#2] @ Td3[s3>>0] + eor r0,r0,r7,ror#8 + ldr r7,[r11],#16 + eor r1,r1,r8,ror#16 + ldr r3,[r10,r3,lsl#2] @ Td0[s3>>24] + eor r2,r2,r9,ror#24 + + ldr r4,[r11,#-12] + eor r0,r0,r7 + ldr r5,[r11,#-8] + eor r3,r3,r6,ror#8 + ldr r6,[r11,#-4] + and r7,lr,r0,lsr#16 + eor r1,r1,r4 + and r8,lr,r0,lsr#8 + eor r2,r2,r5 + and r9,lr,r0 + eor r3,r3,r6 + mov r0,r0,lsr#24 + + subs r12,r12,#1 + bne .Ldec_loop + + add r10,r10,#1024 + + ldr r5,[r10,#0] @ prefetch Td4 + ldr r6,[r10,#32] + ldr r4,[r10,#64] + ldr r5,[r10,#96] + ldr r6,[r10,#128] + ldr r4,[r10,#160] + ldr r5,[r10,#192] + ldr r6,[r10,#224] + + ldrb r0,[r10,r0] @ Td4[s0>>24] + ldrb r4,[r10,r7] @ Td4[s0>>16] + and r7,lr,r1 @ i0 + ldrb r5,[r10,r8] @ Td4[s0>>8] + and r8,lr,r1,lsr#16 + ldrb r6,[r10,r9] @ Td4[s0>>0] + and r9,lr,r1,lsr#8 + + ldrb r7,[r10,r7] @ Td4[s1>>0] + ldrb r1,[r10,r1,lsr#24] @ Td4[s1>>24] + ldrb r8,[r10,r8] @ Td4[s1>>16] + eor r0,r7,r0,lsl#24 + ldrb r9,[r10,r9] @ Td4[s1>>8] + eor r1,r4,r1,lsl#8 + and r7,lr,r2,lsr#8 @ i0 + eor r5,r5,r8,lsl#8 + and r8,lr,r2 @ i1 + ldrb r7,[r10,r7] @ Td4[s2>>8] + eor r6,r6,r9,lsl#8 + ldrb r8,[r10,r8] @ Td4[s2>>0] + and r9,lr,r2,lsr#16 + + ldrb r2,[r10,r2,lsr#24] @ Td4[s2>>24] + eor r0,r0,r7,lsl#8 + ldrb r9,[r10,r9] @ Td4[s2>>16] + eor r1,r8,r1,lsl#16 + and r7,lr,r3,lsr#16 @ i0 + eor r2,r5,r2,lsl#16 + and r8,lr,r3,lsr#8 @ i1 + ldrb r7,[r10,r7] @ Td4[s3>>16] + eor r6,r6,r9,lsl#16 + ldrb r8,[r10,r8] @ Td4[s3>>8] + and r9,lr,r3 @ i2 + + ldrb r9,[r10,r9] @ Td4[s3>>0] + ldrb r3,[r10,r3,lsr#24] @ Td4[s3>>24] + eor r0,r0,r7,lsl#16 + ldr r7,[r11,#0] + eor r1,r1,r8,lsl#8 + ldr r4,[r11,#4] + eor r2,r9,r2,lsl#8 + ldr r5,[r11,#8] + eor r3,r6,r3,lsl#24 + ldr r6,[r11,#12] + + eor r0,r0,r7 + eor r1,r1,r4 + eor r2,r2,r5 + eor r3,r3,r6 + + sub r10,r10,#1024 + ldr pc,[sp],#4 @ pop and return +.size _armv4_AES_decrypt,.-_armv4_AES_decrypt +.asciz "AES for ARMv4, CRYPTOGAMS by <appro@openssl.org>" +.align 2 diff --git a/arch/arm/crypto/aes_glue.c b/arch/arm/crypto/aes_glue.c new file mode 100644 index 000000000000..59f7877ead6a --- /dev/null +++ b/arch/arm/crypto/aes_glue.c @@ -0,0 +1,108 @@ +/* + * Glue Code for the asm optimized version of the AES Cipher Algorithm + */ + +#include <linux/module.h> +#include <linux/crypto.h> +#include <crypto/aes.h> + +#define AES_MAXNR 14 + +typedef struct { + unsigned int rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +} AES_KEY; + +struct AES_CTX { + AES_KEY enc_key; + AES_KEY dec_key; +}; + +asmlinkage void AES_encrypt(const u8 *in, u8 *out, AES_KEY *ctx); +asmlinkage void AES_decrypt(const u8 *in, u8 *out, AES_KEY *ctx); +asmlinkage int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); +asmlinkage int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); + +static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct AES_CTX *ctx = crypto_tfm_ctx(tfm); + AES_encrypt(src, dst, &ctx->enc_key); +} + +static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) +{ + struct AES_CTX *ctx = crypto_tfm_ctx(tfm); + AES_decrypt(src, dst, &ctx->dec_key); +} + +static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct AES_CTX *ctx = crypto_tfm_ctx(tfm); + + switch (key_len) { + case AES_KEYSIZE_128: + key_len = 128; + break; + case AES_KEYSIZE_192: + key_len = 192; + break; + case AES_KEYSIZE_256: + key_len = 256; + break; + default: + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + if (private_AES_set_encrypt_key(in_key, key_len, &ctx->enc_key) == -1) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + /* private_AES_set_decrypt_key expects an encryption key as input */ + ctx->dec_key = ctx->enc_key; + if (private_AES_set_decrypt_key(in_key, key_len, &ctx->dec_key) == -1) { + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + return 0; +} + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct AES_CTX), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm (ASM)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("aes"); +MODULE_ALIAS("aes-asm"); +MODULE_AUTHOR("David McCullough <ucdevel@gmail.com>"); diff --git a/arch/arm/crypto/sha1-armv4-large.S b/arch/arm/crypto/sha1-armv4-large.S new file mode 100644 index 000000000000..7050ab133b9d --- /dev/null +++ b/arch/arm/crypto/sha1-armv4-large.S @@ -0,0 +1,503 @@ +#define __ARM_ARCH__ __LINUX_ARM_ARCH__ +@ ==================================================================== +@ Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL +@ project. The module is, however, dual licensed under OpenSSL and +@ CRYPTOGAMS licenses depending on where you obtain it. For further +@ details see http://www.openssl.org/~appro/cryptogams/. +@ ==================================================================== + +@ sha1_block procedure for ARMv4. +@ +@ January 2007. + +@ Size/performance trade-off +@ ==================================================================== +@ impl size in bytes comp cycles[*] measured performance +@ ==================================================================== +@ thumb 304 3212 4420 +@ armv4-small 392/+29% 1958/+64% 2250/+96% +@ armv4-compact 740/+89% 1552/+26% 1840/+22% +@ armv4-large 1420/+92% 1307/+19% 1370/+34%[***] +@ full unroll ~5100/+260% ~1260/+4% ~1300/+5% +@ ==================================================================== +@ thumb = same as 'small' but in Thumb instructions[**] and +@ with recurring code in two private functions; +@ small = detached Xload/update, loops are folded; +@ compact = detached Xload/update, 5x unroll; +@ large = interleaved Xload/update, 5x unroll; +@ full unroll = interleaved Xload/update, full unroll, estimated[!]; +@ +@ [*] Manually counted instructions in "grand" loop body. Measured +@ performance is affected by prologue and epilogue overhead, +@ i-cache availability, branch penalties, etc. +@ [**] While each Thumb instruction is twice smaller, they are not as +@ diverse as ARM ones: e.g., there are only two arithmetic +@ instructions with 3 arguments, no [fixed] rotate, addressing +@ modes are limited. As result it takes more instructions to do +@ the same job in Thumb, therefore the code is never twice as +@ small and always slower. +@ [***] which is also ~35% better than compiler generated code. Dual- +@ issue Cortex A8 core was measured to process input block in +@ ~990 cycles. + +@ August 2010. +@ +@ Rescheduling for dual-issue pipeline resulted in 13% improvement on +@ Cortex A8 core and in absolute terms ~870 cycles per input block +@ [or 13.6 cycles per byte]. + +@ February 2011. +@ +@ Profiler-assisted and platform-specific optimization resulted in 10% +@ improvement on Cortex A8 core and 12.2 cycles per byte. + +.text + +.global sha1_block_data_order +.type sha1_block_data_order,%function + +.align 2 +sha1_block_data_order: + stmdb sp!,{r4-r12,lr} + add r2,r1,r2,lsl#6 @ r2 to point at the end of r1 + ldmia r0,{r3,r4,r5,r6,r7} +.Lloop: + ldr r8,.LK_00_19 + mov r14,sp + sub sp,sp,#15*4 + mov r5,r5,ror#30 + mov r6,r6,ror#30 + mov r7,r7,ror#30 @ [6] +.L_00_15: +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r7,r8,r7,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r5,r6 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r7,r8,r7,ror#2 @ E+=K_00_19 + eor r10,r5,r6 @ F_xx_xx + add r7,r7,r3,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r4,r10,ror#2 + add r7,r7,r9 @ E+=X[i] + eor r10,r10,r6,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r7,r7,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r6,r8,r6,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r4,r5 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r6,r8,r6,ror#2 @ E+=K_00_19 + eor r10,r4,r5 @ F_xx_xx + add r6,r6,r7,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r3,r10,ror#2 + add r6,r6,r9 @ E+=X[i] + eor r10,r10,r5,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r6,r6,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r5,r8,r5,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r3,r4 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r5,r8,r5,ror#2 @ E+=K_00_19 + eor r10,r3,r4 @ F_xx_xx + add r5,r5,r6,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r7,r10,ror#2 + add r5,r5,r9 @ E+=X[i] + eor r10,r10,r4,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r5,r5,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r4,r8,r4,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r7,r3 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r4,r8,r4,ror#2 @ E+=K_00_19 + eor r10,r7,r3 @ F_xx_xx + add r4,r4,r5,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r6,r10,ror#2 + add r4,r4,r9 @ E+=X[i] + eor r10,r10,r3,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r4,r4,r10 @ E+=F_00_19(B,C,D) +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r3,r8,r3,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r6,r7 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r3,r8,r3,ror#2 @ E+=K_00_19 + eor r10,r6,r7 @ F_xx_xx + add r3,r3,r4,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r5,r10,ror#2 + add r3,r3,r9 @ E+=X[i] + eor r10,r10,r7,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r3,r3,r10 @ E+=F_00_19(B,C,D) + teq r14,sp + bne .L_00_15 @ [((11+4)*5+2)*3] +#if __ARM_ARCH__<7 + ldrb r10,[r1,#2] + ldrb r9,[r1,#3] + ldrb r11,[r1,#1] + add r7,r8,r7,ror#2 @ E+=K_00_19 + ldrb r12,[r1],#4 + orr r9,r9,r10,lsl#8 + eor r10,r5,r6 @ F_xx_xx + orr r9,r9,r11,lsl#16 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + orr r9,r9,r12,lsl#24 +#else + ldr r9,[r1],#4 @ handles unaligned + add r7,r8,r7,ror#2 @ E+=K_00_19 + eor r10,r5,r6 @ F_xx_xx + add r7,r7,r3,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev r9,r9 @ byte swap +#endif +#endif + and r10,r4,r10,ror#2 + add r7,r7,r9 @ E+=X[i] + eor r10,r10,r6,ror#2 @ F_00_19(B,C,D) + str r9,[r14,#-4]! + add r7,r7,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r6,r8,r6,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r4,r5 @ F_xx_xx + mov r9,r9,ror#31 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r3,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r6,r6,r9 @ E+=X[i] + eor r10,r10,r5,ror#2 @ F_00_19(B,C,D) + add r6,r6,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r5,r8,r5,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r3,r4 @ F_xx_xx + mov r9,r9,ror#31 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r7,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r5,r5,r9 @ E+=X[i] + eor r10,r10,r4,ror#2 @ F_00_19(B,C,D) + add r5,r5,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r4,r8,r4,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r7,r3 @ F_xx_xx + mov r9,r9,ror#31 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r6,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r4,r4,r9 @ E+=X[i] + eor r10,r10,r3,ror#2 @ F_00_19(B,C,D) + add r4,r4,r10 @ E+=F_00_19(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r3,r8,r3,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r6,r7 @ F_xx_xx + mov r9,r9,ror#31 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r5,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r3,r3,r9 @ E+=X[i] + eor r10,r10,r7,ror#2 @ F_00_19(B,C,D) + add r3,r3,r10 @ E+=F_00_19(B,C,D) + + ldr r8,.LK_20_39 @ [+15+16*4] + sub sp,sp,#25*4 + cmn sp,#0 @ [+3], clear carry to denote 20_39 +.L_20_39_or_60_79: + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r7,r8,r7,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r5,r6 @ F_xx_xx + mov r9,r9,ror#31 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r4,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r7,r7,r9 @ E+=X[i] + add r7,r7,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r6,r8,r6,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r4,r5 @ F_xx_xx + mov r9,r9,ror#31 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r3,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r6,r6,r9 @ E+=X[i] + add r6,r6,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r5,r8,r5,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r3,r4 @ F_xx_xx + mov r9,r9,ror#31 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r7,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r5,r5,r9 @ E+=X[i] + add r5,r5,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r4,r8,r4,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r7,r3 @ F_xx_xx + mov r9,r9,ror#31 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r6,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r4,r4,r9 @ E+=X[i] + add r4,r4,r10 @ E+=F_20_39(B,C,D) + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r3,r8,r3,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r6,r7 @ F_xx_xx + mov r9,r9,ror#31 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + eor r10,r5,r10,ror#2 @ F_xx_xx + @ F_xx_xx + add r3,r3,r9 @ E+=X[i] + add r3,r3,r10 @ E+=F_20_39(B,C,D) + teq r14,sp @ preserve carry + bne .L_20_39_or_60_79 @ [+((12+3)*5+2)*4] + bcs .L_done @ [+((12+3)*5+2)*4], spare 300 bytes + + ldr r8,.LK_40_59 + sub sp,sp,#20*4 @ [+2] +.L_40_59: + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r7,r8,r7,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r5,r6 @ F_xx_xx + mov r9,r9,ror#31 + add r7,r7,r3,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r4,r10,ror#2 @ F_xx_xx + and r11,r5,r6 @ F_xx_xx + add r7,r7,r9 @ E+=X[i] + add r7,r7,r10 @ E+=F_40_59(B,C,D) + add r7,r7,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r6,r8,r6,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r4,r5 @ F_xx_xx + mov r9,r9,ror#31 + add r6,r6,r7,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r3,r10,ror#2 @ F_xx_xx + and r11,r4,r5 @ F_xx_xx + add r6,r6,r9 @ E+=X[i] + add r6,r6,r10 @ E+=F_40_59(B,C,D) + add r6,r6,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r5,r8,r5,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r3,r4 @ F_xx_xx + mov r9,r9,ror#31 + add r5,r5,r6,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r7,r10,ror#2 @ F_xx_xx + and r11,r3,r4 @ F_xx_xx + add r5,r5,r9 @ E+=X[i] + add r5,r5,r10 @ E+=F_40_59(B,C,D) + add r5,r5,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r4,r8,r4,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r7,r3 @ F_xx_xx + mov r9,r9,ror#31 + add r4,r4,r5,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r6,r10,ror#2 @ F_xx_xx + and r11,r7,r3 @ F_xx_xx + add r4,r4,r9 @ E+=X[i] + add r4,r4,r10 @ E+=F_40_59(B,C,D) + add r4,r4,r11,ror#2 + ldr r9,[r14,#15*4] + ldr r10,[r14,#13*4] + ldr r11,[r14,#7*4] + add r3,r8,r3,ror#2 @ E+=K_xx_xx + ldr r12,[r14,#2*4] + eor r9,r9,r10 + eor r11,r11,r12 @ 1 cycle stall + eor r10,r6,r7 @ F_xx_xx + mov r9,r9,ror#31 + add r3,r3,r4,ror#27 @ E+=ROR(A,27) + eor r9,r9,r11,ror#31 + str r9,[r14,#-4]! + and r10,r5,r10,ror#2 @ F_xx_xx + and r11,r6,r7 @ F_xx_xx + add r3,r3,r9 @ E+=X[i] + add r3,r3,r10 @ E+=F_40_59(B,C,D) + add r3,r3,r11,ror#2 + teq r14,sp + bne .L_40_59 @ [+((12+5)*5+2)*4] + + ldr r8,.LK_60_79 + sub sp,sp,#20*4 + cmp sp,#0 @ set carry to denote 60_79 + b .L_20_39_or_60_79 @ [+4], spare 300 bytes +.L_done: + add sp,sp,#80*4 @ "deallocate" stack frame + ldmia r0,{r8,r9,r10,r11,r12} + add r3,r8,r3 + add r4,r9,r4 + add r5,r10,r5,ror#2 + add r6,r11,r6,ror#2 + add r7,r12,r7,ror#2 + stmia r0,{r3,r4,r5,r6,r7} + teq r1,r2 + bne .Lloop @ [+18], total 1307 + +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + .word 0xe12fff1e @ interoperable with Thumb ISA:-) +#endif +.align 2 +.LK_00_19: .word 0x5a827999 +.LK_20_39: .word 0x6ed9eba1 +.LK_40_59: .word 0x8f1bbcdc +.LK_60_79: .word 0xca62c1d6 +.size sha1_block_data_order,.-sha1_block_data_order +.asciz "SHA1 block transform for ARMv4, CRYPTOGAMS by <appro@openssl.org>" +.align 2 diff --git a/arch/arm/crypto/sha1_glue.c b/arch/arm/crypto/sha1_glue.c new file mode 100644 index 000000000000..76cd976230bc --- /dev/null +++ b/arch/arm/crypto/sha1_glue.c @@ -0,0 +1,179 @@ +/* + * Cryptographic API. + * Glue code for the SHA1 Secure Hash Algorithm assembler implementation + * + * This file is based on sha1_generic.c and sha1_ssse3_glue.c + * + * Copyright (c) Alan Smithee. + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> + * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> + * Copyright (c) Mathias Krause <minipli@googlemail.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 <crypto/internal/hash.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/cryptohash.h> +#include <linux/types.h> +#include <crypto/sha.h> +#include <asm/byteorder.h> + +struct SHA1_CTX { + uint32_t h0,h1,h2,h3,h4; + u64 count; + u8 data[SHA1_BLOCK_SIZE]; +}; + +asmlinkage void sha1_block_data_order(struct SHA1_CTX *digest, + const unsigned char *data, unsigned int rounds); + + +static int sha1_init(struct shash_desc *desc) +{ + struct SHA1_CTX *sctx = shash_desc_ctx(desc); + memset(sctx, 0, sizeof(*sctx)); + sctx->h0 = SHA1_H0; + sctx->h1 = SHA1_H1; + sctx->h2 = SHA1_H2; + sctx->h3 = SHA1_H3; + sctx->h4 = SHA1_H4; + return 0; +} + + +static int __sha1_update(struct SHA1_CTX *sctx, const u8 *data, + unsigned int len, unsigned int partial) +{ + unsigned int done = 0; + + sctx->count += len; + + if (partial) { + done = SHA1_BLOCK_SIZE - partial; + memcpy(sctx->data + partial, data, done); + sha1_block_data_order(sctx, sctx->data, 1); + } + + if (len - done >= SHA1_BLOCK_SIZE) { + const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE; + sha1_block_data_order(sctx, data + done, rounds); + done += rounds * SHA1_BLOCK_SIZE; + } + + memcpy(sctx->data, data + done, len - done); + return 0; +} + + +static int sha1_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct SHA1_CTX *sctx = shash_desc_ctx(desc); + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; + int res; + + /* Handle the fast case right here */ + if (partial + len < SHA1_BLOCK_SIZE) { + sctx->count += len; + memcpy(sctx->data + partial, data, len); + return 0; + } + res = __sha1_update(sctx, data, len, partial); + return res; +} + + +/* Add padding and return the message digest. */ +static int sha1_final(struct shash_desc *desc, u8 *out) +{ + struct SHA1_CTX *sctx = shash_desc_ctx(desc); + unsigned int i, index, padlen; + __be32 *dst = (__be32 *)out; + __be64 bits; + static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; + + bits = cpu_to_be64(sctx->count << 3); + + /* Pad out to 56 mod 64 and append length */ + index = sctx->count % SHA1_BLOCK_SIZE; + padlen = (index < 56) ? (56 - index) : ((SHA1_BLOCK_SIZE+56) - index); + /* We need to fill a whole block for __sha1_update() */ + if (padlen <= 56) { + sctx->count += padlen; + memcpy(sctx->data + index, padding, padlen); + } else { + __sha1_update(sctx, padding, padlen, index); + } + __sha1_update(sctx, (const u8 *)&bits, sizeof(bits), 56); + + /* Store state in digest */ + for (i = 0; i < 5; i++) + dst[i] = cpu_to_be32(((u32 *)sctx)[i]); + + /* Wipe context */ + memset(sctx, 0, sizeof(*sctx)); + return 0; +} + + +static int sha1_export(struct shash_desc *desc, void *out) +{ + struct SHA1_CTX *sctx = shash_desc_ctx(desc); + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + + +static int sha1_import(struct shash_desc *desc, const void *in) +{ + struct SHA1_CTX *sctx = shash_desc_ctx(desc); + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + + +static struct shash_alg alg = { + .digestsize = SHA1_DIGEST_SIZE, + .init = sha1_init, + .update = sha1_update, + .final = sha1_final, + .export = sha1_export, + .import = sha1_import, + .descsize = sizeof(struct SHA1_CTX), + .statesize = sizeof(struct SHA1_CTX), + .base = { + .cra_name = "sha1", + .cra_driver_name= "sha1-asm", + .cra_priority = 150, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + + +static int __init sha1_mod_init(void) +{ + return crypto_register_shash(&alg); +} + + +static void __exit sha1_mod_fini(void) +{ + crypto_unregister_shash(&alg); +} + + +module_init(sha1_mod_init); +module_exit(sha1_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm (ARM)"); +MODULE_ALIAS("sha1"); +MODULE_AUTHOR("David McCullough <ucdevel@gmail.com>"); diff --git a/arch/arm/include/asm/hypervisor.h b/arch/arm/include/asm/hypervisor.h new file mode 100644 index 000000000000..b90d9e523d6f --- /dev/null +++ b/arch/arm/include/asm/hypervisor.h @@ -0,0 +1,6 @@ +#ifndef _ASM_ARM_HYPERVISOR_H +#define _ASM_ARM_HYPERVISOR_H + +#include <asm/xen/hypervisor.h> + +#endif diff --git a/arch/arm/include/asm/sync_bitops.h b/arch/arm/include/asm/sync_bitops.h new file mode 100644 index 000000000000..63479eecbf76 --- /dev/null +++ b/arch/arm/include/asm/sync_bitops.h @@ -0,0 +1,27 @@ +#ifndef __ASM_SYNC_BITOPS_H__ +#define __ASM_SYNC_BITOPS_H__ + +#include <asm/bitops.h> +#include <asm/system.h> + +/* sync_bitops functions are equivalent to the SMP implementation of the + * original functions, independently from CONFIG_SMP being defined. + * + * We need them because _set_bit etc are not SMP safe if !CONFIG_SMP. But + * under Xen you might be communicating with a completely external entity + * who might be on another CPU (e.g. two uniprocessor guests communicating + * via event channels and grant tables). So we need a variant of the bit + * ops which are SMP safe even on a UP kernel. + */ + +#define sync_set_bit(nr, p) _set_bit(nr, p) +#define sync_clear_bit(nr, p) _clear_bit(nr, p) +#define sync_change_bit(nr, p) _change_bit(nr, p) +#define sync_test_and_set_bit(nr, p) _test_and_set_bit(nr, p) +#define sync_test_and_clear_bit(nr, p) _test_and_clear_bit(nr, p) +#define sync_test_and_change_bit(nr, p) _test_and_change_bit(nr, p) +#define sync_test_bit(nr, addr) test_bit(nr, addr) +#define sync_cmpxchg cmpxchg + + +#endif diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h new file mode 100644 index 000000000000..94b4e9020b02 --- /dev/null +++ b/arch/arm/include/asm/xen/events.h @@ -0,0 +1,18 @@ +#ifndef _ASM_ARM_XEN_EVENTS_H +#define _ASM_ARM_XEN_EVENTS_H + +#include <asm/ptrace.h> + +enum ipi_vector { + XEN_PLACEHOLDER_VECTOR, + + /* Xen IPIs go here */ + XEN_NR_IPIS, +}; + +static inline int xen_irqs_disabled(struct pt_regs *regs) +{ + return raw_irqs_disabled_flags(regs->ARM_cpsr); +} + +#endif /* _ASM_ARM_XEN_EVENTS_H */ diff --git a/arch/arm/include/asm/xen/hypercall.h b/arch/arm/include/asm/xen/hypercall.h new file mode 100644 index 000000000000..8a823253d775 --- /dev/null +++ b/arch/arm/include/asm/xen/hypercall.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * hypercall.h + * + * Linux-specific hypervisor handling. + * + * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012 + * + * 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; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _ASM_ARM_XEN_HYPERCALL_H +#define _ASM_ARM_XEN_HYPERCALL_H + +#include <xen/interface/xen.h> + +long privcmd_call(unsigned call, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5); +int HYPERVISOR_xen_version(int cmd, void *arg); +int HYPERVISOR_console_io(int cmd, int count, char *str); +int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count); +int HYPERVISOR_sched_op(int cmd, void *arg); +int HYPERVISOR_event_channel_op(int cmd, void *arg); +unsigned long HYPERVISOR_hvm_op(int op, void *arg); +int HYPERVISOR_memory_op(unsigned int cmd, void *arg); +int HYPERVISOR_physdev_op(int cmd, void *arg); + +static inline void +MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va, + unsigned int new_val, unsigned long flags) +{ + BUG(); +} + +static inline void +MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req, + int count, int *success_count, domid_t domid) +{ + BUG(); +} + +static inline int +HYPERVISOR_multicall(void *call_list, int nr_calls) +{ + BUG(); +} +#endif /* _ASM_ARM_XEN_HYPERCALL_H */ diff --git a/arch/arm/include/asm/xen/hypervisor.h b/arch/arm/include/asm/xen/hypervisor.h new file mode 100644 index 000000000000..d7ab99a0c9eb --- /dev/null +++ b/arch/arm/include/asm/xen/hypervisor.h @@ -0,0 +1,19 @@ +#ifndef _ASM_ARM_XEN_HYPERVISOR_H +#define _ASM_ARM_XEN_HYPERVISOR_H + +extern struct shared_info *HYPERVISOR_shared_info; +extern struct start_info *xen_start_info; + +/* Lazy mode for batching updates / context switch */ +enum paravirt_lazy_mode { + PARAVIRT_LAZY_NONE, + PARAVIRT_LAZY_MMU, + PARAVIRT_LAZY_CPU, +}; + +static inline enum paravirt_lazy_mode paravirt_get_lazy_mode(void) +{ + return PARAVIRT_LAZY_NONE; +} + +#endif /* _ASM_ARM_XEN_HYPERVISOR_H */ diff --git a/arch/arm/include/asm/xen/interface.h b/arch/arm/include/asm/xen/interface.h new file mode 100644 index 000000000000..ae05e56dd17d --- /dev/null +++ b/arch/arm/include/asm/xen/interface.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * Guest OS interface to ARM Xen. + * + * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012 + */ + +#ifndef _ASM_ARM_XEN_INTERFACE_H +#define _ASM_ARM_XEN_INTERFACE_H + +#include <linux/types.h> + +#define uint64_aligned_t uint64_t __attribute__((aligned(8))) + +#define __DEFINE_GUEST_HANDLE(name, type) \ + typedef struct { union { type *p; uint64_aligned_t q; }; } \ + __guest_handle_ ## name + +#define DEFINE_GUEST_HANDLE_STRUCT(name) \ + __DEFINE_GUEST_HANDLE(name, struct name) +#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name) +#define GUEST_HANDLE(name) __guest_handle_ ## name + +#define set_xen_guest_handle(hnd, val) \ + do { \ + if (sizeof(hnd) == 8) \ + *(uint64_t *)&(hnd) = 0; \ + (hnd).p = val; \ + } while (0) + +#ifndef __ASSEMBLY__ +/* Explicitly size integers that represent pfns in the interface with + * Xen so that we can have one ABI that works for 32 and 64 bit guests. */ +typedef uint64_t xen_pfn_t; +typedef uint64_t xen_ulong_t; +/* Guest handles for primitive C types. */ +__DEFINE_GUEST_HANDLE(uchar, unsigned char); +__DEFINE_GUEST_HANDLE(uint, unsigned int); +__DEFINE_GUEST_HANDLE(ulong, unsigned long); +DEFINE_GUEST_HANDLE(char); +DEFINE_GUEST_HANDLE(int); +DEFINE_GUEST_HANDLE(long); +DEFINE_GUEST_HANDLE(void); +DEFINE_GUEST_HANDLE(uint64_t); +DEFINE_GUEST_HANDLE(uint32_t); +DEFINE_GUEST_HANDLE(xen_pfn_t); + +/* Maximum number of virtual CPUs in multi-processor guests. */ +#define MAX_VIRT_CPUS 1 + +struct arch_vcpu_info { }; +struct arch_shared_info { }; + +/* TODO: Move pvclock definitions some place arch independent */ +struct pvclock_vcpu_time_info { + u32 version; + u32 pad0; + u64 tsc_timestamp; + u64 system_time; + u32 tsc_to_system_mul; + s8 tsc_shift; + u8 flags; + u8 pad[2]; +} __attribute__((__packed__)); /* 32 bytes */ + +/* It is OK to have a 12 bytes struct with no padding because it is packed */ +struct pvclock_wall_clock { + u32 version; + u32 sec; + u32 nsec; +} __attribute__((__packed__)); +#endif + +#endif /* _ASM_ARM_XEN_INTERFACE_H */ diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h new file mode 100644 index 000000000000..174202318dff --- /dev/null +++ b/arch/arm/include/asm/xen/page.h @@ -0,0 +1,82 @@ +#ifndef _ASM_ARM_XEN_PAGE_H +#define _ASM_ARM_XEN_PAGE_H + +#include <asm/page.h> +#include <asm/pgtable.h> + +#include <linux/pfn.h> +#include <linux/types.h> + +#include <xen/interface/grant_table.h> + +#define pfn_to_mfn(pfn) (pfn) +#define phys_to_machine_mapping_valid (1) +#define mfn_to_pfn(mfn) (mfn) +#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) + +#define pte_mfn pte_pfn +#define mfn_pte pfn_pte + +/* Xen machine address */ +typedef struct xmaddr { + phys_addr_t maddr; +} xmaddr_t; + +/* Xen pseudo-physical address */ +typedef struct xpaddr { + phys_addr_t paddr; +} xpaddr_t; + +#define XMADDR(x) ((xmaddr_t) { .maddr = (x) }) +#define XPADDR(x) ((xpaddr_t) { .paddr = (x) }) + +static inline xmaddr_t phys_to_machine(xpaddr_t phys) +{ + unsigned offset = phys.paddr & ~PAGE_MASK; + return XMADDR(PFN_PHYS(pfn_to_mfn(PFN_DOWN(phys.paddr))) | offset); +} + +static inline xpaddr_t machine_to_phys(xmaddr_t machine) +{ + unsigned offset = machine.maddr & ~PAGE_MASK; + return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset); +} +/* VIRT <-> MACHINE conversion */ +#define virt_to_machine(v) (phys_to_machine(XPADDR(__pa(v)))) +#define virt_to_pfn(v) (PFN_DOWN(__pa(v))) +#define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v))) +#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) + +static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr) +{ + /* TODO: assuming it is mapped in the kernel 1:1 */ + return virt_to_machine(vaddr); +} + +/* TODO: this shouldn't be here but it is because the frontend drivers + * are using it (its rolled in headers) even though we won't hit the code path. + * So for right now just punt with this. + */ +static inline pte_t *lookup_address(unsigned long address, unsigned int *level) +{ + BUG(); + return NULL; +} + +static inline int m2p_add_override(unsigned long mfn, struct page *page, + struct gnttab_map_grant_ref *kmap_op) +{ + return 0; +} + +static inline int m2p_remove_override(struct page *page, bool clear_pte) +{ + return 0; +} + +static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) +{ + BUG(); + return false; +} +#endif /* _ASM_ARM_XEN_PAGE_H */ diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 188c82971ebd..33361505c0cd 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -625,7 +625,7 @@ fail: return 0; } -static struct clk *const standard_pmc_clocks[] __initdata = { +static struct clk *const standard_pmc_clocks[] __initconst = { /* four primary clocks */ &clk32k, &main_clk, diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index ac4e003ad863..be3099733b1f 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -88,7 +88,7 @@ static struct davinci_mmc_config mmc_config = { .version = MMC_CTLR_VERSION_1, }; -static const short sdio1_pins[] __initdata = { +static const short sdio1_pins[] __initconst = { TNETV107X_SDIO1_CLK_1, TNETV107X_SDIO1_CMD_1, TNETV107X_SDIO1_DATA0_1, TNETV107X_SDIO1_DATA1_1, TNETV107X_SDIO1_DATA2_1, TNETV107X_SDIO1_DATA3_1, @@ -96,12 +96,12 @@ static const short sdio1_pins[] __initdata = { -1 }; -static const short uart1_pins[] __initdata = { +static const short uart1_pins[] __initconst = { TNETV107X_UART1_RD, TNETV107X_UART1_TD, -1 }; -static const short ssp_pins[] __initdata = { +static const short ssp_pins[] __initconst = { TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2, TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2, TNETV107X_SSP1_3, -1 diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index deee5c2da754..510648e0394b 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -838,7 +838,7 @@ static const struct mux_config da830_pins[] = { #endif }; -const short da830_emif25_pins[] __initdata = { +const short da830_emif25_pins[] __initconst = { DA830_EMA_D_0, DA830_EMA_D_1, DA830_EMA_D_2, DA830_EMA_D_3, DA830_EMA_D_4, DA830_EMA_D_5, DA830_EMA_D_6, DA830_EMA_D_7, DA830_EMA_D_8, DA830_EMA_D_9, DA830_EMA_D_10, DA830_EMA_D_11, @@ -853,19 +853,19 @@ const short da830_emif25_pins[] __initdata = { -1 }; -const short da830_spi0_pins[] __initdata = { +const short da830_spi0_pins[] __initconst = { DA830_SPI0_SOMI_0, DA830_SPI0_SIMO_0, DA830_SPI0_CLK, DA830_NSPI0_ENA, DA830_NSPI0_SCS_0, -1 }; -const short da830_spi1_pins[] __initdata = { +const short da830_spi1_pins[] __initconst = { DA830_SPI1_SOMI_0, DA830_SPI1_SIMO_0, DA830_SPI1_CLK, DA830_NSPI1_ENA, DA830_NSPI1_SCS_0, -1 }; -const short da830_mmc_sd_pins[] __initdata = { +const short da830_mmc_sd_pins[] __initconst = { DA830_MMCSD_DAT_0, DA830_MMCSD_DAT_1, DA830_MMCSD_DAT_2, DA830_MMCSD_DAT_3, DA830_MMCSD_DAT_4, DA830_MMCSD_DAT_5, DA830_MMCSD_DAT_6, DA830_MMCSD_DAT_7, DA830_MMCSD_CLK, @@ -873,32 +873,32 @@ const short da830_mmc_sd_pins[] __initdata = { -1 }; -const short da830_uart0_pins[] __initdata = { +const short da830_uart0_pins[] __initconst = { DA830_NUART0_CTS, DA830_NUART0_RTS, DA830_UART0_RXD, DA830_UART0_TXD, -1 }; -const short da830_uart1_pins[] __initdata = { +const short da830_uart1_pins[] __initconst = { DA830_UART1_RXD, DA830_UART1_TXD, -1 }; -const short da830_uart2_pins[] __initdata = { +const short da830_uart2_pins[] __initconst = { DA830_UART2_RXD, DA830_UART2_TXD, -1 }; -const short da830_usb20_pins[] __initdata = { +const short da830_usb20_pins[] __initconst = { DA830_USB0_DRVVBUS, DA830_USB_REFCLKIN, -1 }; -const short da830_usb11_pins[] __initdata = { +const short da830_usb11_pins[] __initconst = { DA830_USB_REFCLKIN, -1 }; -const short da830_uhpi_pins[] __initdata = { +const short da830_uhpi_pins[] __initconst = { DA830_UHPI_HD_0, DA830_UHPI_HD_1, DA830_UHPI_HD_2, DA830_UHPI_HD_3, DA830_UHPI_HD_4, DA830_UHPI_HD_5, DA830_UHPI_HD_6, DA830_UHPI_HD_7, DA830_UHPI_HD_8, DA830_UHPI_HD_9, DA830_UHPI_HD_10, DA830_UHPI_HD_11, @@ -909,14 +909,14 @@ const short da830_uhpi_pins[] __initdata = { -1 }; -const short da830_cpgmac_pins[] __initdata = { +const short da830_cpgmac_pins[] __initconst = { DA830_RMII_TXD_0, DA830_RMII_TXD_1, DA830_RMII_TXEN, DA830_RMII_CRS_DV, DA830_RMII_RXD_0, DA830_RMII_RXD_1, DA830_RMII_RXER, DA830_MDIO_CLK, DA830_MDIO_D, -1 }; -const short da830_emif3c_pins[] __initdata = { +const short da830_emif3c_pins[] __initconst = { DA830_EMB_SDCKE, DA830_EMB_CLK_GLUE, DA830_EMB_CLK, DA830_NEMB_CS_0, DA830_NEMB_CAS, DA830_NEMB_RAS, DA830_NEMB_WE, DA830_EMB_BA_1, DA830_EMB_BA_0, DA830_EMB_A_0, DA830_EMB_A_1, DA830_EMB_A_2, @@ -935,7 +935,7 @@ const short da830_emif3c_pins[] __initdata = { -1 }; -const short da830_mcasp0_pins[] __initdata = { +const short da830_mcasp0_pins[] __initconst = { DA830_AHCLKX0, DA830_ACLKX0, DA830_AFSX0, DA830_AHCLKR0, DA830_ACLKR0, DA830_AFSR0, DA830_AMUTE0, DA830_AXR0_0, DA830_AXR0_1, DA830_AXR0_2, DA830_AXR0_3, @@ -945,7 +945,7 @@ const short da830_mcasp0_pins[] __initdata = { -1 }; -const short da830_mcasp1_pins[] __initdata = { +const short da830_mcasp1_pins[] __initconst = { DA830_AHCLKX1, DA830_ACLKX1, DA830_AFSX1, DA830_AHCLKR1, DA830_ACLKR1, DA830_AFSR1, DA830_AMUTE1, DA830_AXR1_0, DA830_AXR1_1, DA830_AXR1_2, DA830_AXR1_3, @@ -954,24 +954,24 @@ const short da830_mcasp1_pins[] __initdata = { -1 }; -const short da830_mcasp2_pins[] __initdata = { +const short da830_mcasp2_pins[] __initconst = { DA830_AHCLKX2, DA830_ACLKX2, DA830_AFSX2, DA830_AHCLKR2, DA830_ACLKR2, DA830_AFSR2, DA830_AMUTE2, DA830_AXR2_0, DA830_AXR2_1, DA830_AXR2_2, DA830_AXR2_3, -1 }; -const short da830_i2c0_pins[] __initdata = { +const short da830_i2c0_pins[] __initconst = { DA830_I2C0_SDA, DA830_I2C0_SCL, -1 }; -const short da830_i2c1_pins[] __initdata = { +const short da830_i2c1_pins[] __initconst = { DA830_I2C1_SCL, DA830_I2C1_SDA, -1 }; -const short da830_lcdcntl_pins[] __initdata = { +const short da830_lcdcntl_pins[] __initconst = { DA830_LCD_D_0, DA830_LCD_D_1, DA830_LCD_D_2, DA830_LCD_D_3, DA830_LCD_D_4, DA830_LCD_D_5, DA830_LCD_D_6, DA830_LCD_D_7, DA830_LCD_D_8, DA830_LCD_D_9, DA830_LCD_D_10, DA830_LCD_D_11, @@ -981,34 +981,34 @@ const short da830_lcdcntl_pins[] __initdata = { -1 }; -const short da830_pwm_pins[] __initdata = { +const short da830_pwm_pins[] __initconst = { DA830_ECAP0_APWM0, DA830_ECAP1_APWM1, DA830_EPWM0B, DA830_EPWM0A, DA830_EPWMSYNCI, DA830_EPWMSYNC0, DA830_ECAP2_APWM2, DA830_EHRPWMGLUETZ, DA830_EPWM2B, DA830_EPWM2A, DA830_EPWM1B, DA830_EPWM1A, -1 }; -const short da830_ecap0_pins[] __initdata = { +const short da830_ecap0_pins[] __initconst = { DA830_ECAP0_APWM0, -1 }; -const short da830_ecap1_pins[] __initdata = { +const short da830_ecap1_pins[] __initconst = { DA830_ECAP1_APWM1, -1 }; -const short da830_ecap2_pins[] __initdata = { +const short da830_ecap2_pins[] __initconst = { DA830_ECAP2_APWM2, -1 }; -const short da830_eqep0_pins[] __initdata = { +const short da830_eqep0_pins[] __initconst = { DA830_EQEP0I, DA830_EQEP0S, DA830_EQEP0A, DA830_EQEP0B, -1 }; -const short da830_eqep1_pins[] __initdata = { +const short da830_eqep1_pins[] __initconst = { DA830_EQEP1I, DA830_EQEP1S, DA830_EQEP1A, DA830_EQEP1B, -1 }; diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index b44dc844e15e..6676dee7104e 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -576,17 +576,17 @@ static const struct mux_config da850_pins[] = { #endif }; -const short da850_i2c0_pins[] __initdata = { +const short da850_i2c0_pins[] __initconst = { DA850_I2C0_SDA, DA850_I2C0_SCL, -1 }; -const short da850_i2c1_pins[] __initdata = { +const short da850_i2c1_pins[] __initconst = { DA850_I2C1_SCL, DA850_I2C1_SDA, -1 }; -const short da850_lcdcntl_pins[] __initdata = { +const short da850_lcdcntl_pins[] __initconst = { DA850_LCD_D_0, DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3, DA850_LCD_D_4, DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7, DA850_LCD_D_8, DA850_LCD_D_9, DA850_LCD_D_10, DA850_LCD_D_11, diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 3a2042fb9712..32197c117afe 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -758,7 +758,7 @@ config SOC_IMX6Q select HAVE_IMX_MMDC select HAVE_IMX_SRC select HAVE_SMP - select MFD_ANATOP + select MFD_SYSCON select PINCTRL select PINCTRL_IMX6Q diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 36979d3dfe34..47c91f7185d2 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -23,8 +23,9 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/phy.h> +#include <linux/regmap.h> #include <linux/micrel_phy.h> -#include <linux/mfd/anatop.h> +#include <linux/mfd/syscon.h> #include <asm/cpuidle.h> #include <asm/smp_twd.h> #include <asm/hardware/cache-l2x0.h> @@ -118,20 +119,7 @@ static void __init imx6q_sabrelite_init(void) static void __init imx6q_usb_init(void) { - struct device_node *np; - struct platform_device *pdev = NULL; - struct anatop *adata = NULL; - - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); - if (np) - pdev = of_find_device_by_node(np); - if (pdev) - adata = platform_get_drvdata(pdev); - if (!adata) { - if (np) - of_node_put(np); - return; - } + struct regmap *anatop; #define HW_ANADIG_USB1_CHRG_DETECT 0x000001b0 #define HW_ANADIG_USB2_CHRG_DETECT 0x00000210 @@ -139,20 +127,21 @@ static void __init imx6q_usb_init(void) #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x00100000 #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x00080000 - /* - * The external charger detector needs to be disabled, - * or the signal at DP will be poor - */ - anatop_write_reg(adata, HW_ANADIG_USB1_CHRG_DETECT, - BM_ANADIG_USB_CHRG_DETECT_EN_B - | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B, - ~0); - anatop_write_reg(adata, HW_ANADIG_USB2_CHRG_DETECT, - BM_ANADIG_USB_CHRG_DETECT_EN_B | - BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B, - ~0); - - of_node_put(np); + anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop"); + if (!IS_ERR(anatop)) { + /* + * The external charger detector needs to be disabled, + * or the signal at DP will be poor + */ + regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT, + BM_ANADIG_USB_CHRG_DETECT_EN_B + | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); + regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT, + BM_ANADIG_USB_CHRG_DETECT_EN_B | + BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); + } else { + pr_warn("failed to find fsl,imx6q-anatop regmap\n"); + } } static void __init imx6q_init_machine(void) diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index a344a373928b..2448fcf09eb1 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -37,8 +37,8 @@ #include "devices.h" #include "common.h" -static const resource_size_t qsd8x50_surf_smc91x_base __initdata = 0x70000300; -static const unsigned qsd8x50_surf_smc91x_gpio __initdata = 156; +static const resource_size_t qsd8x50_surf_smc91x_base __initconst = 0x70000300; +static const unsigned qsd8x50_surf_smc91x_gpio __initconst = 156; /* Leave smc91x resources empty here, as we'll fill them in * at run-time: they vary from board to board, and the true diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index af1ed7d24a1f..e470c6e50acd 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -76,14 +76,14 @@ struct omap_dss_hwmod_data { const int id; }; -static const struct omap_dss_hwmod_data omap2_dss_hwmod_data[] __initdata = { +static const struct omap_dss_hwmod_data omap2_dss_hwmod_data[] __initconst = { { "dss_core", "omapdss_dss", -1 }, { "dss_dispc", "omapdss_dispc", -1 }, { "dss_rfbi", "omapdss_rfbi", -1 }, { "dss_venc", "omapdss_venc", -1 }, }; -static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = { +static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initconst = { { "dss_core", "omapdss_dss", -1 }, { "dss_dispc", "omapdss_dispc", -1 }, { "dss_rfbi", "omapdss_rfbi", -1 }, @@ -91,7 +91,7 @@ static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = { { "dss_dsi1", "omapdss_dsi", 0 }, }; -static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = { +static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initconst = { { "dss_core", "omapdss_dss", -1 }, { "dss_dispc", "omapdss_dispc", -1 }, { "dss_rfbi", "omapdss_rfbi", -1 }, diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index ac95daaa4702..3c434498e12e 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -33,10 +33,12 @@ #ifdef CONFIG_MFD_OMAP_USB_HOST #define OMAP_USBHS_DEVICE "usbhs_omap" +#define OMAP_USBTLL_DEVICE "usbhs_tll" #define USBHS_UHH_HWMODNAME "usb_host_hs" #define USBHS_TLL_HWMODNAME "usb_tll_hs" static struct usbhs_omap_platform_data usbhs_data; +static struct usbtll_omap_platform_data usbtll_data; static struct ehci_hcd_omap_platform_data ehci_data; static struct ohci_hcd_omap_platform_data ohci_data; @@ -485,13 +487,14 @@ void __init setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode) void __init usbhs_init(const struct usbhs_omap_board_data *pdata) { - struct omap_hwmod *oh[2]; + struct omap_hwmod *uhh_hwm, *tll_hwm; struct platform_device *pdev; int bus_id = -1; int i; for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { usbhs_data.port_mode[i] = pdata->port_mode[i]; + usbtll_data.port_mode[i] = pdata->port_mode[i]; ohci_data.port_mode[i] = pdata->port_mode[i]; ehci_data.port_mode[i] = pdata->port_mode[i]; ehci_data.reset_gpio_port[i] = pdata->reset_gpio_port[i]; @@ -510,25 +513,35 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) setup_4430ohci_io_mux(pdata->port_mode); } - oh[0] = omap_hwmod_lookup(USBHS_UHH_HWMODNAME); - if (!oh[0]) { + uhh_hwm = omap_hwmod_lookup(USBHS_UHH_HWMODNAME); + if (!uhh_hwm) { pr_err("Could not look up %s\n", USBHS_UHH_HWMODNAME); return; } - oh[1] = omap_hwmod_lookup(USBHS_TLL_HWMODNAME); - if (!oh[1]) { + tll_hwm = omap_hwmod_lookup(USBHS_TLL_HWMODNAME); + if (!tll_hwm) { pr_err("Could not look up %s\n", USBHS_TLL_HWMODNAME); return; } - pdev = omap_device_build_ss(OMAP_USBHS_DEVICE, bus_id, oh, 2, - (void *)&usbhs_data, sizeof(usbhs_data), + pdev = omap_device_build(OMAP_USBTLL_DEVICE, bus_id, tll_hwm, + &usbtll_data, sizeof(usbtll_data), omap_uhhtll_latency, ARRAY_SIZE(omap_uhhtll_latency), false); if (IS_ERR(pdev)) { - pr_err("Could not build hwmod devices %s,%s\n", - USBHS_UHH_HWMODNAME, USBHS_TLL_HWMODNAME); + pr_err("Could not build hwmod device %s\n", + USBHS_TLL_HWMODNAME); + return; + } + + pdev = omap_device_build(OMAP_USBHS_DEVICE, bus_id, uhh_hwm, + &usbhs_data, sizeof(usbhs_data), + omap_uhhtll_latency, + ARRAY_SIZE(omap_uhhtll_latency), false); + if (IS_ERR(pdev)) { + pr_err("Could not build hwmod devices %s\n", + USBHS_UHH_HWMODNAME); return; } } diff --git a/arch/arm/mach-u300/i2c.c b/arch/arm/mach-u300/i2c.c index 0d4620ed853c..96800aa1316d 100644 --- a/arch/arm/mach-u300/i2c.c +++ b/arch/arm/mach-u300/i2c.c @@ -9,7 +9,7 @@ */ #include <linux/kernel.h> #include <linux/i2c.h> -#include <linux/mfd/abx500.h> +#include <linux/mfd/ab3100.h> #include <linux/regulator/machine.h> #include <linux/amba/bus.h> #include <mach/irqs.h> diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 5f6b7d543e55..560e0df728f8 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -659,6 +659,7 @@ static void __init v2m_dt_init(void) const static char *v2m_dt_match[] __initconst = { "arm,vexpress", + "xen,xenvm", NULL, }; diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h index bd20588c356b..87ee140fefaa 100644 --- a/arch/arm/plat-omap/include/plat/usb.h +++ b/arch/arm/plat-omap/include/plat/usb.h @@ -4,6 +4,7 @@ #define __ASM_ARCH_OMAP_USB_H #include <linux/io.h> +#include <linux/platform_device.h> #include <linux/usb/musb.h> #define OMAP3_HS_USB_PORTS 3 @@ -63,6 +64,10 @@ struct usbhs_omap_platform_data { struct ehci_hcd_omap_platform_data *ehci_data; struct ohci_hcd_omap_platform_data *ohci_data; }; + +struct usbtll_omap_platform_data { + enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; +}; /*-------------------------------------------------------------------------*/ struct omap_musb_board_data { @@ -81,6 +86,8 @@ enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI}; extern void usb_musb_init(struct omap_musb_board_data *board_data); extern void usbhs_init(const struct usbhs_omap_board_data *pdata); +extern int omap_tll_enable(void); +extern int omap_tll_disable(void); extern int omap4430_phy_power(struct device *dev, int ID, int on); extern int omap4430_phy_set_clk(struct device *dev, int on); diff --git a/arch/arm/xen/Makefile b/arch/arm/xen/Makefile new file mode 100644 index 000000000000..43841033afd3 --- /dev/null +++ b/arch/arm/xen/Makefile @@ -0,0 +1 @@ +obj-y := enlighten.o hypercall.o grant-table.o diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c new file mode 100644 index 000000000000..59bcb96ac369 --- /dev/null +++ b/arch/arm/xen/enlighten.c @@ -0,0 +1,168 @@ +#include <xen/xen.h> +#include <xen/events.h> +#include <xen/grant_table.h> +#include <xen/hvm.h> +#include <xen/interface/xen.h> +#include <xen/interface/memory.h> +#include <xen/interface/hvm/params.h> +#include <xen/features.h> +#include <xen/platform_pci.h> +#include <xen/xenbus.h> +#include <asm/xen/hypervisor.h> +#include <asm/xen/hypercall.h> +#include <linux/interrupt.h> +#include <linux/irqreturn.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +struct start_info _xen_start_info; +struct start_info *xen_start_info = &_xen_start_info; +EXPORT_SYMBOL_GPL(xen_start_info); + +enum xen_domain_type xen_domain_type = XEN_NATIVE; +EXPORT_SYMBOL_GPL(xen_domain_type); + +struct shared_info xen_dummy_shared_info; +struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; + +DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); + +/* TODO: to be removed */ +__read_mostly int xen_have_vector_callback; +EXPORT_SYMBOL_GPL(xen_have_vector_callback); + +int xen_platform_pci_unplug = XEN_UNPLUG_ALL; +EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); + +static __read_mostly int xen_events_irq = -1; + +int xen_remap_domain_mfn_range(struct vm_area_struct *vma, + unsigned long addr, + unsigned long mfn, int nr, + pgprot_t prot, unsigned domid) +{ + return -ENOSYS; +} +EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); + +/* + * see Documentation/devicetree/bindings/arm/xen.txt for the + * documentation of the Xen Device Tree format. + */ +#define GRANT_TABLE_PHYSADDR 0 +static int __init xen_guest_init(void) +{ + struct xen_add_to_physmap xatp; + static struct shared_info *shared_info_page = 0; + struct device_node *node; + int len; + const char *s = NULL; + const char *version = NULL; + const char *xen_prefix = "xen,xen-"; + struct resource res; + + node = of_find_compatible_node(NULL, NULL, "xen,xen"); + if (!node) { + pr_debug("No Xen support\n"); + return 0; + } + s = of_get_property(node, "compatible", &len); + if (strlen(xen_prefix) + 3 < len && + !strncmp(xen_prefix, s, strlen(xen_prefix))) + version = s + strlen(xen_prefix); + if (version == NULL) { + pr_debug("Xen version not found\n"); + return 0; + } + if (of_address_to_resource(node, GRANT_TABLE_PHYSADDR, &res)) + return 0; + xen_hvm_resume_frames = res.start >> PAGE_SHIFT; + xen_events_irq = irq_of_parse_and_map(node, 0); + pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n", + version, xen_events_irq, xen_hvm_resume_frames); + xen_domain_type = XEN_HVM_DOMAIN; + + xen_setup_features(); + if (xen_feature(XENFEAT_dom0)) + xen_start_info->flags |= SIF_INITDOMAIN|SIF_PRIVILEGED; + else + xen_start_info->flags &= ~(SIF_INITDOMAIN|SIF_PRIVILEGED); + + if (!shared_info_page) + shared_info_page = (struct shared_info *) + get_zeroed_page(GFP_KERNEL); + if (!shared_info_page) { + pr_err("not enough memory\n"); + return -ENOMEM; + } + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; + if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) + BUG(); + + HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; + + /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info + * page, we use it in the event channel upcall and in some pvclock + * related functions. We don't need the vcpu_info placement + * optimizations because we don't use any pv_mmu or pv_irq op on + * HVM. + * The shared info contains exactly 1 CPU (the boot CPU). The guest + * is required to use VCPUOP_register_vcpu_info to place vcpu info + * for secondary CPUs as they are brought up. */ + per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; + + gnttab_init(); + if (!xen_initial_domain()) + xenbus_probe(NULL); + + return 0; +} +core_initcall(xen_guest_init); + +static irqreturn_t xen_arm_callback(int irq, void *arg) +{ + xen_hvm_evtchn_do_upcall(); + return IRQ_HANDLED; +} + +static int __init xen_init_events(void) +{ + if (!xen_domain() || xen_events_irq < 0) + return -ENODEV; + + xen_init_IRQ(); + + if (request_percpu_irq(xen_events_irq, xen_arm_callback, + "events", xen_vcpu)) { + pr_err("Error requesting IRQ %d\n", xen_events_irq); + return -EINVAL; + } + + enable_percpu_irq(xen_events_irq, 0); + + return 0; +} +postcore_initcall(xen_init_events); + +/* XXX: only until balloon is properly working */ +int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) +{ + *pages = alloc_pages(highmem ? GFP_HIGHUSER : GFP_KERNEL, + get_order(nr_pages)); + if (*pages == NULL) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL_GPL(alloc_xenballooned_pages); + +void free_xenballooned_pages(int nr_pages, struct page **pages) +{ + kfree(*pages); + *pages = NULL; +} +EXPORT_SYMBOL_GPL(free_xenballooned_pages); diff --git a/arch/arm/xen/grant-table.c b/arch/arm/xen/grant-table.c new file mode 100644 index 000000000000..dbd1330c0196 --- /dev/null +++ b/arch/arm/xen/grant-table.c @@ -0,0 +1,53 @@ +/****************************************************************************** + * grant_table.c + * ARM specific part + * + * Granting foreign access to our memory reservation. + * + * 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; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <xen/interface/xen.h> +#include <xen/page.h> +#include <xen/grant_table.h> + +int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, + unsigned long max_nr_gframes, + void **__shared) +{ + return -ENOSYS; +} + +void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) +{ + return; +} + +int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes, + unsigned long max_nr_gframes, + grant_status_t **__shared) +{ + return -ENOSYS; +} diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S new file mode 100644 index 000000000000..074f5ed101b9 --- /dev/null +++ b/arch/arm/xen/hypercall.S @@ -0,0 +1,106 @@ +/****************************************************************************** + * hypercall.S + * + * Xen hypercall wrappers + * + * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012 + * + * 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; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * The Xen hypercall calling convention is very similar to the ARM + * procedure calling convention: the first paramter is passed in r0, the + * second in r1, the third in r2 and the fourth in r3. Considering that + * Xen hypercalls have 5 arguments at most, the fifth paramter is passed + * in r4, differently from the procedure calling convention of using the + * stack for that case. + * + * The hypercall number is passed in r12. + * + * The return value is in r0. + * + * The hvc ISS is required to be 0xEA1, that is the Xen specific ARM + * hypercall tag. + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <xen/interface/xen.h> + + +/* HVC 0xEA1 */ +#ifdef CONFIG_THUMB2_KERNEL +#define xen_hvc .word 0xf7e08ea1 +#else +#define xen_hvc .word 0xe140ea71 +#endif + +#define HYPERCALL_SIMPLE(hypercall) \ +ENTRY(HYPERVISOR_##hypercall) \ + mov r12, #__HYPERVISOR_##hypercall; \ + xen_hvc; \ + mov pc, lr; \ +ENDPROC(HYPERVISOR_##hypercall) + +#define HYPERCALL0 HYPERCALL_SIMPLE +#define HYPERCALL1 HYPERCALL_SIMPLE +#define HYPERCALL2 HYPERCALL_SIMPLE +#define HYPERCALL3 HYPERCALL_SIMPLE +#define HYPERCALL4 HYPERCALL_SIMPLE + +#define HYPERCALL5(hypercall) \ +ENTRY(HYPERVISOR_##hypercall) \ + stmdb sp!, {r4} \ + ldr r4, [sp, #4] \ + mov r12, #__HYPERVISOR_##hypercall; \ + xen_hvc \ + ldm sp!, {r4} \ + mov pc, lr \ +ENDPROC(HYPERVISOR_##hypercall) + + .text + +HYPERCALL2(xen_version); +HYPERCALL3(console_io); +HYPERCALL3(grant_table_op); +HYPERCALL2(sched_op); +HYPERCALL2(event_channel_op); +HYPERCALL2(hvm_op); +HYPERCALL2(memory_op); +HYPERCALL2(physdev_op); + +ENTRY(privcmd_call) + stmdb sp!, {r4} + mov r12, r0 + mov r0, r1 + mov r1, r2 + mov r2, r3 + ldr r3, [sp, #8] + ldr r4, [sp, #4] + xen_hvc + ldm sp!, {r4} + mov pc, lr +ENDPROC(privcmd_call); diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index a670a33ad736..37e610dc084e 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -55,6 +55,7 @@ typedef s64 compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -130,6 +131,64 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + /* The padding is the same size as AArch64. */ + int _pad[128/sizeof(int) - 3]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid32_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid32_t _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + __compat_uid32_t _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + compat_uptr_t _addr; /* faulting insn/memory ref. */ + short _addr_lsb; /* LSB of the reported address */ + } _sigfault; + + /* SIGPOLL */ + struct { + compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -139,7 +198,6 @@ typedef u32 compat_sigset_word; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index ac74c2f261e3..0790a87a4346 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -30,59 +30,6 @@ #include <asm/uaccess.h> #include <asm/unistd.h> -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - /* The padding is the same size as AArch64. */ - int _pad[SI_PAD_SIZE]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid32_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - __compat_uid32_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - __compat_uid32_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - compat_uptr_t _addr; /* faulting insn/memory ref. */ - short _addr_lsb; /* LSB of the reported address */ - } _sigfault; - - /* SIGPOLL */ - struct { - compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - struct compat_sigaction { compat_uptr_t sa_handler; compat_ulong_t sa_flags; diff --git a/arch/avr32/include/asm/elf.h b/arch/avr32/include/asm/elf.h index 3b3159b710d4..e2c328739808 100644 --- a/arch/avr32/include/asm/elf.h +++ b/arch/avr32/include/asm/elf.h @@ -102,6 +102,7 @@ typedef struct user_fpu_struct elf_fpregset_t; #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX_32BIT | (current->personality & (~PER_MASK))) #endif /* __ASM_AVR32_ELF_H */ diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h index e6c6812a9abd..14bc98ff668f 100644 --- a/arch/blackfin/include/asm/elf.h +++ b/arch/blackfin/include/asm/elf.h @@ -132,6 +132,7 @@ do { \ #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif diff --git a/arch/c6x/include/asm/elf.h b/arch/c6x/include/asm/elf.h index f4552db20b4a..32b997126adf 100644 --- a/arch/c6x/include/asm/elf.h +++ b/arch/c6x/include/asm/elf.h @@ -77,7 +77,8 @@ do { \ #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) /* C6X specific section types */ #define SHT_C6000_UNWIND 0x70000001 diff --git a/arch/cris/include/asm/elf.h b/arch/cris/include/asm/elf.h index 8a3d8e2b33c1..8182f2dc89d0 100644 --- a/arch/cris/include/asm/elf.h +++ b/arch/cris/include/asm/elf.h @@ -86,6 +86,7 @@ typedef unsigned long elf_fpregset_t; #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif diff --git a/arch/frv/include/asm/elf.h b/arch/frv/include/asm/elf.h index c3819804a74b..9ccbc80f0b11 100644 --- a/arch/frv/include/asm/elf.h +++ b/arch/frv/include/asm/elf.h @@ -137,6 +137,7 @@ do { \ #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index 5fa3889d858b..0b579927439d 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -153,23 +153,22 @@ static int user_atoi(char __user *ubuf, size_t len) static int sysctl_pm_do_suspend(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *fpos) { - int retval, mode; + int mode; if (*lenp <= 0) return -EIO; mode = user_atoi(buffer, *lenp); - if ((mode != 1) && (mode != 5)) - return -EINVAL; + switch (mode) { + case 1: + return pm_do_suspend(); - if (retval == 0) { - if (mode == 5) - retval = pm_do_bus_sleep(); - else - retval = pm_do_suspend(); - } + case 5: + return pm_do_bus_sleep(); - return retval; + default: + return -EINVAL; + } } static int try_set_cmode(int new_cmode) diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index 75cf7f4b2fa8..1f1e5efb3385 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c @@ -184,7 +184,7 @@ static struct clock_cmode __pminitdata clock_cmodes_fr555[16] = { [6] = { _x1, _x1_5, _x1_5, _x4_5, _x0_375 }, }; -static const struct clock_cmode __pminitdata *clock_cmodes; +static const struct clock_cmode __pminitconst *clock_cmodes; static int __pminitdata clock_doubled; static struct uart_port __pminitdata __frv_uart0 = { diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c index 20f6497b2cd5..c677b9d81d30 100644 --- a/arch/frv/mb93090-mb00/pci-irq.c +++ b/arch/frv/mb93090-mb00/pci-irq.c @@ -28,7 +28,7 @@ * */ -static const uint8_t __initdata pci_bus0_irq_routing[32][4] = { +static const uint8_t __initconst pci_bus0_irq_routing[32][4] = { [0 ] = { IRQ_FPGA_MB86943_PCI_INTA }, [16] = { IRQ_FPGA_RTL8029_INTA }, [17] = { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB }, diff --git a/arch/h8300/include/asm/elf.h b/arch/h8300/include/asm/elf.h index c24fa250d653..41193c396bff 100644 --- a/arch/h8300/include/asm/elf.h +++ b/arch/h8300/include/asm/elf.h @@ -54,7 +54,8 @@ typedef unsigned long elf_fpregset_t; #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #define R_H8_NONE 0 #define R_H8_DIR32 1 diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index aaf5e5a48f93..4bdc7311784e 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c @@ -51,6 +51,7 @@ asmlinkage void syscall_print(void *dummy,...) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ +asmlinkage int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]) diff --git a/arch/h8300/kernel/timer/itu.c b/arch/h8300/kernel/timer/itu.c index a2ae5e952137..0a8b5cd5bf38 100644 --- a/arch/h8300/kernel/timer/itu.c +++ b/arch/h8300/kernel/timer/itu.c @@ -62,7 +62,7 @@ static struct irqaction itu_irq = { .flags = IRQF_DISABLED | IRQF_TIMER, }; -static const int __initdata divide_rate[] = {1, 2, 4, 8}; +static const int __initconst divide_rate[] = {1, 2, 4, 8}; void __init h8300_timer_setup(void) { diff --git a/arch/h8300/kernel/timer/timer16.c b/arch/h8300/kernel/timer/timer16.c index ae0d38161139..462d9f581719 100644 --- a/arch/h8300/kernel/timer/timer16.c +++ b/arch/h8300/kernel/timer/timer16.c @@ -57,7 +57,7 @@ static struct irqaction timer16_irq = { .flags = IRQF_DISABLED | IRQF_TIMER, }; -static const int __initdata divide_rate[] = {1, 2, 4, 8}; +static const int __initconst divide_rate[] = {1, 2, 4, 8}; void __init h8300_timer_setup(void) { diff --git a/arch/h8300/kernel/timer/timer8.c b/arch/h8300/kernel/timer/timer8.c index 7a1533fad47d..505f3415b40f 100644 --- a/arch/h8300/kernel/timer/timer8.c +++ b/arch/h8300/kernel/timer/timer8.c @@ -77,7 +77,7 @@ static struct irqaction timer8_irq = { .flags = IRQF_DISABLED | IRQF_TIMER, }; -static const int __initdata divide_rate[] = {8, 64, 8192}; +static const int __initconst divide_rate[] = {8, 64, 8192}; void __init h8300_timer_setup(void) { diff --git a/arch/h8300/kernel/timer/tpu.c b/arch/h8300/kernel/timer/tpu.c index 2193a2e2859a..0350f6204ecf 100644 --- a/arch/h8300/kernel/timer/tpu.c +++ b/arch/h8300/kernel/timer/tpu.c @@ -66,7 +66,7 @@ static struct irqaction tpu_irq = { .flags = IRQF_DISABLED | IRQF_TIMER, }; -static const int __initdata divide_rate[] = { +static const int __initconst divide_rate[] = { #if CONFIG_H8300_TPU_CH == 0 1,4,16,64,0,0,0,0, #elif (CONFIG_H8300_TPU_CH == 1) || (CONFIG_H8300_TPU_CH == 5) diff --git a/arch/h8300/platform/h8300h/irq.c b/arch/h8300/platform/h8300h/irq.c index bc4f51bceef5..0a50353e09d5 100644 --- a/arch/h8300/platform/h8300h/irq.c +++ b/arch/h8300/platform/h8300h/irq.c @@ -14,14 +14,14 @@ #include <asm/gpio-internal.h> #include <asm/regs306x.h> -const int __initdata h8300_saved_vectors[] = { +const int __initconst h8300_saved_vectors[] = { #if defined(CONFIG_GDB_DEBUG) TRAP3_VEC, /* TRAPA #3 is GDB breakpoint */ #endif -1, }; -const h8300_vector __initdata h8300_trap_table[] = { +const h8300_vector __initconst h8300_trap_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, system_call, 0, diff --git a/arch/h8300/platform/h8s/irq.c b/arch/h8300/platform/h8s/irq.c index 7b5f29febc07..f3a5511c16b1 100644 --- a/arch/h8300/platform/h8s/irq.c +++ b/arch/h8300/platform/h8s/irq.c @@ -18,7 +18,7 @@ #include <asm/regs267x.h> /* saved vector list */ -const int __initdata h8300_saved_vectors[]={ +const int __initconst h8300_saved_vectors[] = { #if defined(CONFIG_GDB_DEBUG) TRACE_VEC, TRAP3_VEC, @@ -27,7 +27,7 @@ const int __initdata h8300_saved_vectors[]={ }; /* trap entry table */ -const H8300_VECTOR __initdata h8300_trap_table[] = { +const H8300_VECTOR __initconst h8300_trap_table[] = { 0,0,0,0,0, trace_break, /* TRACE */ 0,0, diff --git a/arch/hexagon/include/asm/elf.h b/arch/hexagon/include/asm/elf.h index 37976a0d3650..82b499621e05 100644 --- a/arch/hexagon/include/asm/elf.h +++ b/arch/hexagon/include/asm/elf.h @@ -217,7 +217,8 @@ do { \ #define ELF_PLATFORM (NULL) #ifdef __KERNEL__ -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 diff --git a/arch/ia64/include/asm/xen/interface.h b/arch/ia64/include/asm/xen/interface.h index 3d52a5bbd857..e88c5de27410 100644 --- a/arch/ia64/include/asm/xen/interface.h +++ b/arch/ia64/include/asm/xen/interface.h @@ -71,6 +71,7 @@ * with Xen so that we could have one ABI that works for 32 and 64 bit * guests. */ typedef unsigned long xen_pfn_t; +typedef unsigned long xen_ulong_t; /* Guest handles for primitive C types. */ __DEFINE_GUEST_HANDLE(uchar, unsigned char); __DEFINE_GUEST_HANDLE(uint, unsigned int); diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index bd77cb507c1c..8b3a9c0e771d 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -924,6 +924,16 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return 0; } +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) +{ + if (!irqchip_in_kernel(kvm)) + return -ENXIO; + + irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, + irq_event->irq, irq_event->level); + return 0; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -963,29 +973,6 @@ long kvm_arch_vm_ioctl(struct file *filp, goto out; } break; - case KVM_IRQ_LINE_STATUS: - case KVM_IRQ_LINE: { - struct kvm_irq_level irq_event; - - r = -EFAULT; - if (copy_from_user(&irq_event, argp, sizeof irq_event)) - goto out; - r = -ENXIO; - if (irqchip_in_kernel(kvm)) { - __s32 status; - status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event.irq, irq_event.level); - if (ioctl == KVM_IRQ_LINE_STATUS) { - r = -EFAULT; - irq_event.status = status; - if (copy_to_user(argp, &irq_event, - sizeof irq_event)) - goto out; - } - r = 0; - } - break; - } case KVM_GET_IRQCHIP: { /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ struct kvm_irqchip chip; @@ -1626,11 +1613,17 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, return; } -void kvm_arch_flush_shadow(struct kvm *kvm) +void kvm_arch_flush_shadow_all(struct kvm *kvm) { kvm_flush_remote_tlbs(kvm); } +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot) +{ + kvm_arch_flush_shadow_all(); +} + long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/ia64/xen/irq_xen.c b/arch/ia64/xen/irq_xen.c index 3bb12230721f..01f479ee1c43 100644 --- a/arch/ia64/xen/irq_xen.c +++ b/arch/ia64/xen/irq_xen.c @@ -433,7 +433,7 @@ xen_resend_irq(unsigned int vector) (void)resend_irq_on_evtchn(vector); } -const struct pv_irq_ops xen_irq_ops __initdata = { +const struct pv_irq_ops xen_irq_ops __initconst = { .register_ipi = xen_register_ipi, .assign_irq_vector = xen_assign_irq_vector, diff --git a/arch/ia64/xen/irq_xen.h b/arch/ia64/xen/irq_xen.h index 26110f330c87..1778517b90fe 100644 --- a/arch/ia64/xen/irq_xen.h +++ b/arch/ia64/xen/irq_xen.h @@ -27,7 +27,7 @@ extern void (*late_time_init)(void); extern char xen_event_callback; void __init xen_init_IRQ(void); -extern const struct pv_irq_ops xen_irq_ops __initdata; +extern const struct pv_irq_ops xen_irq_ops __initconst; extern void xen_smp_intr_init(void); extern void xen_send_ipi(int cpu, int vec); diff --git a/arch/m32r/include/asm/elf.h b/arch/m32r/include/asm/elf.h index b8da7d0574d2..70896161c636 100644 --- a/arch/m32r/include/asm/elf.h +++ b/arch/m32r/include/asm/elf.h @@ -128,6 +128,7 @@ typedef elf_fpreg_t elf_fpregset_t; intent than poking at uname or /proc/cpuinfo. */ #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif /* _ASM_M32R__ELF_H */ diff --git a/arch/m68k/include/asm/elf.h b/arch/m68k/include/asm/elf.h index e9b7cda59744..f83c1d0a87cf 100644 --- a/arch/m68k/include/asm/elf.h +++ b/arch/m68k/include/asm/elf.h @@ -113,6 +113,7 @@ typedef struct user_m68kfp_struct elf_fpregset_t; #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h index 834849f59ae8..640ddd4b6a9b 100644 --- a/arch/microblaze/include/asm/elf.h +++ b/arch/microblaze/include/asm/elf.h @@ -116,7 +116,8 @@ do { \ } while (0) #ifdef __KERNEL__ -#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX_32BIT | (current->personality & (~PER_MASK))) #endif #endif /* __uClinux__ */ diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index feb05258a4d1..dd18e4b761a8 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -632,7 +632,7 @@ static struct board_info __initdata board_DWVS0 = { /* * all boards */ -static const struct board_info __initdata *bcm963xx_boards[] = { +static const struct board_info __initconst *bcm963xx_boards[] = { #ifdef CONFIG_BCM63XX_CPU_6328 &board_96328avng, #endif diff --git a/arch/mips/include/asm/compat-signal.h b/arch/mips/include/asm/compat-signal.h index 368a99e5c3e1..6599a901b63e 100644 --- a/arch/mips/include/asm/compat-signal.h +++ b/arch/mips/include/asm/compat-signal.h @@ -10,68 +10,6 @@ #include <asm/uaccess.h> -#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) - -typedef struct compat_siginfo { - int si_signo; - int si_code; - int si_errno; - - union { - int _pad[SI_PAD_SIZE32]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - compat_uid_t _uid; /* sender's uid */ - } _kill; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - compat_uid_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* IRIX SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - compat_clock_t _utime; - int _status; /* exit code */ - compat_clock_t _stime; - } _irix_sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - s32 _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL, SIGXFSZ (To do ...) */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* POSIX.1b timers */ - struct { - timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval;/* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - compat_uid_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - } _sifields; -} compat_siginfo_t; - static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d, const sigset_t *s) { diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index b77df0366ee6..58277e0e9cd4 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -43,6 +43,7 @@ typedef s64 compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -124,6 +125,73 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +#define SI_PAD_SIZE32 (128/sizeof(int) - 3) + +typedef struct compat_siginfo { + int si_signo; + int si_code; + int si_errno; + + union { + int _pad[SI_PAD_SIZE32]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid_t _uid; /* sender's uid */ + } _kill; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + __compat_uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* IRIX SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + compat_clock_t _utime; + int _status; /* exit code */ + compat_clock_t _stime; + } _irix_sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + s32 _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL, SIGXFSZ (To do ...) */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + + /* POSIX.1b timers */ + struct { + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval;/* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid_t _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -133,7 +201,6 @@ typedef u32 compat_sigset_word; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index c5dfb2c87d44..4b0c347d7a82 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -58,7 +58,7 @@ union octeon_pci_address { } s; }; -int __initdata (*octeon_pcibios_map_irq)(const struct pci_dev *dev, +int __initconst (*octeon_pcibios_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); enum octeon_dma_bar_type octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_INVALID; diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile index 33188b6e81e4..a3d0fef3b126 100644 --- a/arch/mn10300/Makefile +++ b/arch/mn10300/Makefile @@ -26,7 +26,7 @@ CHECKFLAGS += PROCESSOR := unset UNIT := unset -KBUILD_CFLAGS += -mam33 -mmem-funcs -DCPU=AM33 +KBUILD_CFLAGS += -mam33 -DCPU=AM33 $(call cc-option,-mmem-funcs,) KBUILD_AFLAGS += -mam33 -DCPU=AM33 ifeq ($(CONFIG_MN10300_CURRENT_IN_E2),y) diff --git a/arch/mn10300/include/asm/elf.h b/arch/mn10300/include/asm/elf.h index 8157c9267f42..4ebd6b3a0a1e 100644 --- a/arch/mn10300/include/asm/elf.h +++ b/arch/mn10300/include/asm/elf.h @@ -151,7 +151,8 @@ do { \ #define ELF_PLATFORM (NULL) #ifdef __KERNEL__ -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif #endif /* _ASM_ELF_H */ diff --git a/arch/openrisc/include/asm/elf.h b/arch/openrisc/include/asm/elf.h index a8fe2c513070..225a7ff320ad 100644 --- a/arch/openrisc/include/asm/elf.h +++ b/arch/openrisc/include/asm/elf.h @@ -110,7 +110,8 @@ extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt); #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif /* __KERNEL__ */ #endif diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 3ff21b536f28..b87438bb3384 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -13,6 +13,7 @@ config PARISC select HAVE_PERF_EVENTS select GENERIC_ATOMIC64 if !64BIT select HAVE_GENERIC_HARDIRQS + select BROKEN_RODATA select GENERIC_IRQ_PROBE select GENERIC_PCI_IOMAP select IRQ_PER_CPU diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index 760f331d4fa3..db7a662691a8 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -36,6 +36,7 @@ typedef s64 compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -127,6 +128,63 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[128/sizeof(int) - 3]; + + /* kill() */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + char _pad[sizeof(unsigned int) - sizeof(int)]; + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + unsigned int _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + unsigned int _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -136,7 +194,6 @@ typedef u32 compat_sigset_word; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h index c7800846422c..08a88b5349a2 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -55,58 +55,6 @@ struct k_sigaction32 { struct compat_sigaction sa; }; -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[((128/sizeof(int)) - 3)]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof(unsigned int) - sizeof(int)]; - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from); int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 352f416269ce..4ce0be32d153 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -215,7 +215,8 @@ config ARCH_HIBERNATION_POSSIBLE config ARCH_SUSPEND_POSSIBLE def_bool y depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ - (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x + (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \ + || 44x || 40x config PPC_DCR_NATIVE bool @@ -239,6 +240,9 @@ config PPC_OF_PLATFORM_PCI config ARCH_SUPPORTS_DEBUG_PAGEALLOC def_bool y +config ARCH_SUPPORTS_UPROBES + def_bool y + config PPC_ADV_DEBUG_REGS bool depends on 40x || BOOKE @@ -325,7 +329,8 @@ config SWIOTLB config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" - depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV) + depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \ + PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC)) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. @@ -557,6 +562,14 @@ config SCHED_SMT when dealing with POWER5 cpus at a cost of slightly increased overhead in some places. If unsure say N here. +config PPC_DENORMALISATION + bool "PowerPC denormalisation exception handling" + depends on PPC_BOOK3S_64 + default "n" + ---help--- + Add support for handling denormalisation of single precision + values. Useful for bare metal only. If unsure say Y here. + config CMDLINE_BOOL bool "Default bootloader kernel arguments" diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index b7d833382be4..6a15c968d214 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -107,6 +107,7 @@ src-boot := $(addprefix $(obj)/, $(src-boot)) obj-boot := $(addsuffix .o, $(basename $(src-boot))) obj-wlib := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-wlib)))) obj-plat := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-plat)))) +obj-plat: $(libfdt) quiet_cmd_copy_zlib = COPY $@ cmd_copy_zlib = sed "s@__used@@;s@<linux/\([^>]*\).*@\"\1\"@" $< > $@ diff --git a/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi new file mode 100644 index 000000000000..870c6535a053 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi @@ -0,0 +1,58 @@ +/* + * e500mc Power ISA Device Tree Source (include) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/ { + cpus { + power-isa-version = "2.06"; + power-isa-b; // Base + power-isa-e; // Embedded + power-isa-atb; // Alternate Time Base + power-isa-cs; // Cache Specification + power-isa-ds; // Decorated Storage + power-isa-e.ed; // Embedded.Enhanced Debug + power-isa-e.pd; // Embedded.External PID + power-isa-e.hv; // Embedded.Hypervisor + power-isa-e.le; // Embedded.Little-Endian + power-isa-e.pm; // Embedded.Performance Monitor + power-isa-e.pc; // Embedded.Processor Control + power-isa-ecl; // Embedded Cache Locking + power-isa-exp; // External Proxy + power-isa-fp; // Floating Point + power-isa-fp.r; // Floating Point.Record + power-isa-mmc; // Memory Coherence + power-isa-scpm; // Store Conditional Page Mobility + power-isa-wt; // Wait + mmu-type = "power-embedded"; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi new file mode 100644 index 000000000000..f4928144d2c8 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi @@ -0,0 +1,52 @@ +/* + * e500v2 Power ISA Device Tree Source (include) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/ { + cpus { + power-isa-version = "2.03"; + power-isa-b; // Base + power-isa-e; // Embedded + power-isa-atb; // Alternate Time Base + power-isa-cs; // Cache Specification + power-isa-e.le; // Embedded.Little-Endian + power-isa-e.pm; // Embedded.Performance Monitor + power-isa-ecl; // Embedded Cache Locking + power-isa-mmc; // Memory Coherence + power-isa-sp; // Signal Processing Engine + power-isa-sp.fd; // SPE.Embedded Float Scalar Double + power-isa-sp.fs; // SPE.Embedded Float Scalar Single + power-isa-sp.fv; // SPE.Embedded Float Vector + mmu-type = "power-embedded"; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi new file mode 100644 index 000000000000..3230212f7ad5 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi @@ -0,0 +1,59 @@ +/* + * e5500 Power ISA Device Tree Source (include) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/ { + cpus { + power-isa-version = "2.06"; + power-isa-b; // Base + power-isa-e; // Embedded + power-isa-atb; // Alternate Time Base + power-isa-cs; // Cache Specification + power-isa-ds; // Decorated Storage + power-isa-e.ed; // Embedded.Enhanced Debug + power-isa-e.pd; // Embedded.External PID + power-isa-e.hv; // Embedded.Hypervisor + power-isa-e.le; // Embedded.Little-Endian + power-isa-e.pm; // Embedded.Performance Monitor + power-isa-e.pc; // Embedded.Processor Control + power-isa-ecl; // Embedded Cache Locking + power-isa-exp; // External Proxy + power-isa-fp; // Floating Point + power-isa-fp.r; // Floating Point.Record + power-isa-mmc; // Memory Coherence + power-isa-scpm; // Store Conditional Page Mobility + power-isa-wt; // Wait + power-isa-64; // 64-bit + mmu-type = "power-embedded"; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi index 7de45a784df6..152906f98a0f 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,MPC8536"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi index 8777f9239d9e..5a69bafb652a 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,MPC8544"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi index 720422d83529..fc1ce977422b 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,MPC8548"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi index eacd62c5fe6c..122ca3bd0b03 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,MPC8568"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi index b07064d11930..2cd15a2a0422 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,MPC8569"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi index ca188326c2ca..28c2a862be96 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,MPC8572"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi index 7354a8f90ea5..6e76f9b282a1 100644 --- a/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,P1010"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi index 6f0376e554eb..fed9c4c8d962 100644 --- a/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,P1020"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi index 4abd54bc3308..36161b500176 100644 --- a/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,P1021"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi index e930f4f7ca89..1956dea040cc 100644 --- a/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,P1022"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi index ac45f6d93385..132a1521921a 100644 --- a/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,P1023"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi index 3213288641d1..42bf3c6d25ca 100644 --- a/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500v2_power_isa.dtsi" + / { compatible = "fsl,P2020"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi index 2d0a40d6b10f..7a2697d04549 100644 --- a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500mc_power_isa.dtsi" + / { compatible = "fsl,P2041"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi index 136def3536b6..c9ca2c305cfe 100644 --- a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500mc_power_isa.dtsi" + / { compatible = "fsl,P3041"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi index b9556ee3a639..493d9a056b5c 100644 --- a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e500mc_power_isa.dtsi" + / { compatible = "fsl,P4080"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi index ae823a47584e..0a198b0a77e5 100644 --- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi @@ -33,6 +33,9 @@ */ /dts-v1/; + +/include/ "e5500_power_isa.dtsi" + / { compatible = "fsl,P5020"; #address-cells = <2>; diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi new file mode 100644 index 000000000000..db2c9a7b3a0e --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi @@ -0,0 +1,320 @@ +/* + * P5040 Silicon/SoC Device Tree Source (post include) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * This software is provided by Freescale Semiconductor "as is" and any + * express or implied warranties, including, but not limited to, the implied + * warranties of merchantability and fitness for a particular purpose are + * disclaimed. In no event shall Freescale Semiconductor be liable for any + * direct, indirect, incidental, special, exemplary, or consequential damages + * (including, but not limited to, procurement of substitute goods or services; + * loss of use, data, or profits; or business interruption) however caused and + * on any theory of liability, whether in contract, strict liability, or tort + * (including negligence or otherwise) arising in any way out of the use of this + * software, even if advised of the possibility of such damage. + */ + +&lbc { + compatible = "fsl,p5040-elbc", "fsl,elbc", "simple-bus"; + interrupts = <25 2 0 0>; + #address-cells = <2>; + #size-cells = <1>; +}; + +/* controller at 0x200000 */ +&pci0 { + compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4"; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + bus-range = <0x0 0xff>; + clock-frequency = <33333333>; + interrupts = <16 2 1 15>; + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + interrupts = <16 2 1 15>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 40 1 0 0 + 0000 0 0 2 &mpic 1 1 0 0 + 0000 0 0 3 &mpic 2 1 0 0 + 0000 0 0 4 &mpic 3 1 0 0 + >; + }; +}; + +/* controller at 0x201000 */ +&pci1 { + compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4"; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + bus-range = <0 0xff>; + clock-frequency = <33333333>; + interrupts = <16 2 1 14>; + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + interrupts = <16 2 1 14>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 41 1 0 0 + 0000 0 0 2 &mpic 5 1 0 0 + 0000 0 0 3 &mpic 6 1 0 0 + 0000 0 0 4 &mpic 7 1 0 0 + >; + }; +}; + +/* controller at 0x202000 */ +&pci2 { + compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4"; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + bus-range = <0x0 0xff>; + clock-frequency = <33333333>; + interrupts = <16 2 1 13>; + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + interrupts = <16 2 1 13>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 0x0 */ + 0000 0 0 1 &mpic 42 1 0 0 + 0000 0 0 2 &mpic 9 1 0 0 + 0000 0 0 3 &mpic 10 1 0 0 + 0000 0 0 4 &mpic 11 1 0 0 + >; + }; +}; + +&dcsr { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,dcsr", "simple-bus"; + + dcsr-epu@0 { + compatible = "fsl,dcsr-epu"; + interrupts = <52 2 0 0 + 84 2 0 0 + 85 2 0 0>; + reg = <0x0 0x1000>; + }; + dcsr-npc { + compatible = "fsl,dcsr-npc"; + reg = <0x1000 0x1000 0x1000000 0x8000>; + }; + dcsr-nxc@2000 { + compatible = "fsl,dcsr-nxc"; + reg = <0x2000 0x1000>; + }; + dcsr-corenet { + compatible = "fsl,dcsr-corenet"; + reg = <0x8000 0x1000 0xB0000 0x1000>; + }; + dcsr-dpaa@9000 { + compatible = "fsl,p5040-dcsr-dpaa", "fsl,dcsr-dpaa"; + reg = <0x9000 0x1000>; + }; + dcsr-ocn@11000 { + compatible = "fsl,p5040-dcsr-ocn", "fsl,dcsr-ocn"; + reg = <0x11000 0x1000>; + }; + dcsr-ddr@12000 { + compatible = "fsl,dcsr-ddr"; + dev-handle = <&ddr1>; + reg = <0x12000 0x1000>; + }; + dcsr-ddr@13000 { + compatible = "fsl,dcsr-ddr"; + dev-handle = <&ddr2>; + reg = <0x13000 0x1000>; + }; + dcsr-nal@18000 { + compatible = "fsl,p5040-dcsr-nal", "fsl,dcsr-nal"; + reg = <0x18000 0x1000>; + }; + dcsr-rcpm@22000 { + compatible = "fsl,p5040-dcsr-rcpm", "fsl,dcsr-rcpm"; + reg = <0x22000 0x1000>; + }; + dcsr-cpu-sb-proxy@40000 { + compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy"; + cpu-handle = <&cpu0>; + reg = <0x40000 0x1000>; + }; + dcsr-cpu-sb-proxy@41000 { + compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy"; + cpu-handle = <&cpu1>; + reg = <0x41000 0x1000>; + }; + dcsr-cpu-sb-proxy@42000 { + compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy"; + cpu-handle = <&cpu2>; + reg = <0x42000 0x1000>; + }; + dcsr-cpu-sb-proxy@43000 { + compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy"; + cpu-handle = <&cpu3>; + reg = <0x43000 0x1000>; + }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + device_type = "soc"; + compatible = "simple-bus"; + + soc-sram-error { + compatible = "fsl,soc-sram-error"; + interrupts = <16 2 1 29>; + }; + + corenet-law@0 { + compatible = "fsl,corenet-law"; + reg = <0x0 0x1000>; + fsl,num-laws = <32>; + }; + + ddr1: memory-controller@8000 { + compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller"; + reg = <0x8000 0x1000>; + interrupts = <16 2 1 23>; + }; + + ddr2: memory-controller@9000 { + compatible = "fsl,qoriq-memory-controller-v4.5","fsl,qoriq-memory-controller"; + reg = <0x9000 0x1000>; + interrupts = <16 2 1 22>; + }; + + cpc: l3-cache-controller@10000 { + compatible = "fsl,p5040-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache"; + reg = <0x10000 0x1000 + 0x11000 0x1000>; + interrupts = <16 2 1 27 + 16 2 1 26>; + }; + + corenet-cf@18000 { + compatible = "fsl,corenet-cf"; + reg = <0x18000 0x1000>; + interrupts = <16 2 1 31>; + fsl,ccf-num-csdids = <32>; + fsl,ccf-num-snoopids = <32>; + }; + + iommu@20000 { + compatible = "fsl,pamu-v1.0", "fsl,pamu"; + reg = <0x20000 0x5000>; + interrupts = < + 24 2 0 0 + 16 2 1 30>; + }; + +/include/ "qoriq-mpic.dtsi" + + guts: global-utilities@e0000 { + compatible = "fsl,p5040-device-config", "fsl,qoriq-device-config-1.0"; + reg = <0xe0000 0xe00>; + fsl,has-rstcr; + #sleep-cells = <1>; + fsl,liodn-bits = <12>; + }; + + pins: global-utilities@e0e00 { + compatible = "fsl,p5040-pin-control", "fsl,qoriq-pin-control-1.0"; + reg = <0xe0e00 0x200>; + #sleep-cells = <2>; + }; + + clockgen: global-utilities@e1000 { + compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0"; + reg = <0xe1000 0x1000>; + clock-frequency = <0>; + }; + + rcpm: global-utilities@e2000 { + compatible = "fsl,p5040-rcpm", "fsl,qoriq-rcpm-1.0"; + reg = <0xe2000 0x1000>; + #sleep-cells = <1>; + }; + + sfp: sfp@e8000 { + compatible = "fsl,p5040-sfp", "fsl,qoriq-sfp-1.0"; + reg = <0xe8000 0x1000>; + }; + + serdes: serdes@ea000 { + compatible = "fsl,p5040-serdes"; + reg = <0xea000 0x1000>; + }; + +/include/ "qoriq-dma-0.dtsi" +/include/ "qoriq-dma-1.dtsi" +/include/ "qoriq-espi-0.dtsi" + spi@110000 { + fsl,espi-num-chipselects = <4>; + }; + +/include/ "qoriq-esdhc-0.dtsi" + sdhc@114000 { + sdhci,auto-cmd12; + }; + +/include/ "qoriq-i2c-0.dtsi" +/include/ "qoriq-i2c-1.dtsi" +/include/ "qoriq-duart-0.dtsi" +/include/ "qoriq-duart-1.dtsi" +/include/ "qoriq-gpio-0.dtsi" +/include/ "qoriq-usb2-mph-0.dtsi" + usb0: usb@210000 { + compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; + phy_type = "utmi"; + port0; + }; + +/include/ "qoriq-usb2-dr-0.dtsi" + usb1: usb@211000 { + compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; + dr_mode = "host"; + phy_type = "utmi"; + }; + +/include/ "qoriq-sata2-0.dtsi" +/include/ "qoriq-sata2-1.dtsi" +/include/ "qoriq-sec5.2-0.dtsi" +}; diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi new file mode 100644 index 000000000000..40ca943f5d1c --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi @@ -0,0 +1,114 @@ +/* + * P5040 Silicon/SoC Device Tree Source (pre include) + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * This software is provided by Freescale Semiconductor "as is" and any + * express or implied warranties, including, but not limited to, the implied + * warranties of merchantability and fitness for a particular purpose are + * disclaimed. In no event shall Freescale Semiconductor be liable for any + * direct, indirect, incidental, special, exemplary, or consequential damages + * (including, but not limited to, procurement of substitute goods or services; + * loss of use, data, or profits; or business interruption) however caused and + * on any theory of liability, whether in contract, strict liability, or tort + * (including negligence or otherwise) arising in any way out of the use of this + * software, even if advised of the possibility of such damage. + */ + +/dts-v1/; + +/include/ "e5500_power_isa.dtsi" + +/ { + compatible = "fsl,P5040"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&mpic>; + + aliases { + ccsr = &soc; + dcsr = &dcsr; + + serial0 = &serial0; + serial1 = &serial1; + serial2 = &serial2; + serial3 = &serial3; + pci0 = &pci0; + pci1 = &pci1; + pci2 = &pci2; + usb0 = &usb0; + usb1 = &usb1; + dma0 = &dma0; + dma1 = &dma1; + sdhc = &sdhc; + msi0 = &msi0; + msi1 = &msi1; + msi2 = &msi2; + + crypto = &crypto; + sec_jr0 = &sec_jr0; + sec_jr1 = &sec_jr1; + sec_jr2 = &sec_jr2; + sec_jr3 = &sec_jr3; + rtic_a = &rtic_a; + rtic_b = &rtic_b; + rtic_c = &rtic_c; + rtic_d = &rtic_d; + sec_mon = &sec_mon; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: PowerPC,e5500@0 { + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2_0>; + L2_0: l2-cache { + next-level-cache = <&cpc>; + }; + }; + cpu1: PowerPC,e5500@1 { + device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2_1>; + L2_1: l2-cache { + next-level-cache = <&cpc>; + }; + }; + cpu2: PowerPC,e5500@2 { + device_type = "cpu"; + reg = <2>; + next-level-cache = <&L2_2>; + L2_2: l2-cache { + next-level-cache = <&cpc>; + }; + }; + cpu3: PowerPC,e5500@3 { + device_type = "cpu"; + reg = <3>; + next-level-cache = <&L2_3>; + L2_3: l2-cache { + next-level-cache = <&cpc>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi new file mode 100644 index 000000000000..7b2ab8a8c1f4 --- /dev/null +++ b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi @@ -0,0 +1,118 @@ +/* + * QorIQ Sec/Crypto 5.2 device tree stub [ controller @ offset 0x300000 ] + * + * Copyright 2011-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +crypto: crypto@300000 { + compatible = "fsl,sec-v5.2", "fsl,sec-v5.0", "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + interrupts = <92 2 0 0>; + + sec_jr0: jr@1000 { + compatible = "fsl,sec-v5.2-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + interrupts = <88 2 0 0>; + }; + + sec_jr1: jr@2000 { + compatible = "fsl,sec-v5.2-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + interrupts = <89 2 0 0>; + }; + + sec_jr2: jr@3000 { + compatible = "fsl,sec-v5.2-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x3000 0x1000>; + interrupts = <90 2 0 0>; + }; + + sec_jr3: jr@4000 { + compatible = "fsl,sec-v5.2-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x4000 0x1000>; + interrupts = <91 2 0 0>; + }; + + rtic@6000 { + compatible = "fsl,sec-v5.2-rtic", + "fsl,sec-v5.0-rtic", + "fsl,sec-v4.0-rtic"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x6000 0x100>; + ranges = <0x0 0x6100 0xe00>; + + rtic_a: rtic-a@0 { + compatible = "fsl,sec-v5.2-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x00 0x20 0x100 0x80>; + }; + + rtic_b: rtic-b@20 { + compatible = "fsl,sec-v5.2-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x20 0x20 0x200 0x80>; + }; + + rtic_c: rtic-c@40 { + compatible = "fsl,sec-v5.2-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x40 0x20 0x300 0x80>; + }; + + rtic_d: rtic-d@60 { + compatible = "fsl,sec-v5.2-rtic-memory", + "fsl,sec-v5.0-rtic-memory", + "fsl,sec-v4.0-rtic-memory"; + reg = <0x60 0x20 0x500 0x80>; + }; + }; +}; + +sec_mon: sec_mon@314000 { + compatible = "fsl,sec-v5.2-mon", "fsl,sec-v5.0-mon", "fsl,sec-v4.0-mon"; + reg = <0x314000 0x1000>; + interrupts = <93 2 0 0>; +}; diff --git a/arch/powerpc/boot/dts/mpc8536ds.dtsi b/arch/powerpc/boot/dts/mpc8536ds.dtsi index d304a2d68c62..7c3dde84d193 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8536ds.dtsi @@ -132,6 +132,10 @@ reg = <0x68>; interrupts = <0 0x1 0 0>; }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; }; spi@7000 { diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index f99fb110c97f..2d31863accf5 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -11,6 +11,8 @@ /dts-v1/; +/include/ "fsl/e500v2_power_isa.dtsi" + / { model = "MPC8540ADS"; compatible = "MPC8540ADS", "MPC85xxADS"; diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 0f5e93912799..1c03c2667373 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -11,6 +11,8 @@ /dts-v1/; +/include/ "fsl/e500v2_power_isa.dtsi" + / { model = "MPC8541CDS"; compatible = "MPC8541CDS", "MPC85xxCDS"; diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index e934987e882b..ed38874c3a36 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts @@ -20,8 +20,10 @@ reg = <0 0 0 0>; // Filled by U-Boot }; - lbc: localbus@e0005000 { + board_lbc: lbc: localbus@e0005000 { reg = <0 0xe0005000 0 0x1000>; + + ranges = <0x0 0x0 0x0 0xff800000 0x800000>; }; board_soc: soc: soc8544@e0000000 { diff --git a/arch/powerpc/boot/dts/mpc8544ds.dtsi b/arch/powerpc/boot/dts/mpc8544ds.dtsi index 77ebc9f1d37c..b219d035d794 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8544ds.dtsi @@ -32,6 +32,45 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +&board_lbc { + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x800000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + reg = <0x0 0x10000>; + label = "dtb-nor"; + }; + + partition@20000 { + reg = <0x20000 0x30000>; + label = "diagnostic-nor"; + read-only; + }; + + partition@200000 { + reg = <0x200000 0x200000>; + label = "dink-nor"; + read-only; + }; + + partition@400000 { + reg = <0x400000 0x380000>; + label = "kernel-nor"; + }; + + partition@780000 { + reg = <0x780000 0x80000>; + label = "u-boot-nor"; + read-only; + }; + }; +}; + &board_soc { enet0: ethernet@24000 { phy-handle = <&phy0>; diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index fe10438613d6..36a7ea138c2f 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -11,6 +11,8 @@ /dts-v1/; +/include/ "fsl/e500v2_power_isa.dtsi" + / { model = "MPC8555CDS"; compatible = "MPC8555CDS", "MPC85xxCDS"; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 6e85e1ba0851..1a43f5a968f5 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -11,6 +11,8 @@ /dts-v1/; +/include/ "fsl/e500v2_power_isa.dtsi" + / { model = "MPC8560ADS"; compatible = "MPC8560ADS", "MPC85xxADS"; diff --git a/arch/powerpc/boot/dts/o2d.dts b/arch/powerpc/boot/dts/o2d.dts new file mode 100644 index 000000000000..9f6dd4d889b3 --- /dev/null +++ b/arch/powerpc/boot/dts/o2d.dts @@ -0,0 +1,47 @@ +/* + * O2D Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "o2d.dtsi" + +/ { + model = "ifm,o2d"; + compatible = "ifm,o2d"; + + memory { + reg = <0x00000000 0x08000000>; // 128MB + }; + + localbus { + ranges = <0 0 0xfc000000 0x02000000 + 3 0 0xe3000000 0x00100000>; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x02000000>; + bank-width = <2>; + device-width = <2>; + #size-cells = <1>; + #address-cells = <1>; + + partition@60000 { + label = "kernel"; + reg = <0x00060000 0x00260000>; + read-only; + }; + /* o2d specific partitions */ + partition@2c0000 { + label = "o2d user defined"; + reg = <0x002c0000 0x01d40000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi new file mode 100644 index 000000000000..3444eb8f0ade --- /dev/null +++ b/arch/powerpc/boot/dts/o2d.dtsi @@ -0,0 +1,139 @@ +/* + * O2D base Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "mpc5200b.dtsi" + +/ { + model = "ifm,o2d"; + compatible = "ifm,o2d"; + + memory { + reg = <0x00000000 0x04000000>; // 64MB + }; + + soc5200@f0000000 { + + gpio_simple: gpio@b00 { + }; + + timer@600 { // General Purpose Timer + #gpio-cells = <2>; + gpio-controller; + fsl,has-wdt; + fsl,wdt-on-boot = <0>; + }; + + timer@610 { + #gpio-cells = <2>; + gpio-controller; + }; + + timer7: timer@670 { + }; + + rtc@800 { + status = "disabled"; + }; + + psc@2000 { // PSC1 + compatible = "fsl,mpc5200b-psc-spi","fsl,mpc5200-psc-spi"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <250000>; + reg = <0>; + }; + }; + + psc@2200 { // PSC2 + status = "disabled"; + }; + + psc@2400 { // PSC3 + status = "disabled"; + }; + + psc@2600 { // PSC4 + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + }; + + psc@2800 { // PSC5 + compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; + }; + + psc@2c00 { // PSC6 + status = "disabled"; + }; + + ethernet@3000 { + phy-handle = <&phy0>; + }; + + mdio@3000 { + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; + + sclpc@3c00 { + compatible = "fsl,mpc5200-lpbfifo"; + reg = <0x3c00 0x60>; + interrupts = <3 23 0>; + }; + }; + + localbus { + ranges = <0 0 0xff000000 0x01000000 + 3 0 0xe3000000 0x00100000>; + + // flash device at LocalPlus Bus CS0 + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x01000000>; + bank-width = <1>; + device-width = <2>; + #size-cells = <1>; + #address-cells = <1>; + no-unaligned-direct-access; + + /* common layout for all machines */ + partition@0 { + label = "u-boot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@40000 { + label = "env"; + reg = <0x00040000 0x00020000>; + read-only; + }; + }; + + csi@3,0 { + compatible = "ifm,o2d-csi"; + reg = <3 0 0x00100000>; + ifm,csi-clk-handle = <&timer7>; + gpios = <&gpio_simple 23 0 /* imag_capture */ + &gpio_simple 26 0 /* imag_reset */ + &gpio_simple 29 0>; /* imag_master_en */ + + interrupts = <1 1 2>; /* IRQ1, edge falling */ + + ifm,csi-addr-bus-width = <24>; + ifm,csi-data-bus-width = <8>; + ifm,csi-wait-cycles = <0>; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/o2d300.dts b/arch/powerpc/boot/dts/o2d300.dts new file mode 100644 index 000000000000..29affe0f0da3 --- /dev/null +++ b/arch/powerpc/boot/dts/o2d300.dts @@ -0,0 +1,52 @@ +/* + * O2D300 Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "o2d.dtsi" + +/ { + model = "ifm,o2d300"; + compatible = "ifm,o2d"; + + localbus { + ranges = <0 0 0xfc000000 0x02000000 + 3 0 0xe3000000 0x00100000>; + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x02000000>; + bank-width = <2>; + device-width = <2>; + #size-cells = <1>; + #address-cells = <1>; + + partition@40000 { + label = "env_1"; + reg = <0x00040000 0x00020000>; + read-only; + }; + partition@60000 { + label = "env_2"; + reg = <0x00060000 0x00020000>; + read-only; + }; + partition@80000 { + label = "kernel"; + reg = <0x00080000 0x00260000>; + read-only; + }; + /* o2d300 specific partitions */ + partition@2e0000 { + label = "o2d300 user defined"; + reg = <0x002e0000 0x01d20000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/o2dnt2.dts b/arch/powerpc/boot/dts/o2dnt2.dts new file mode 100644 index 000000000000..a0f5b97a4f06 --- /dev/null +++ b/arch/powerpc/boot/dts/o2dnt2.dts @@ -0,0 +1,48 @@ +/* + * O2DNT2 Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "o2d.dtsi" + +/ { + model = "ifm,o2dnt2"; + compatible = "ifm,o2d"; + + memory { + reg = <0x00000000 0x08000000>; // 128MB + }; + + localbus { + ranges = <0 0 0xfc000000 0x02000000 + 3 0 0xe3000000 0x00100000>; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x02000000>; + bank-width = <2>; + device-width = <2>; + #size-cells = <1>; + #address-cells = <1>; + + partition@60000 { + label = "kernel"; + reg = <0x00060000 0x00260000>; + read-only; + }; + + /* o2dnt2 specific partitions */ + partition@2c0000 { + label = "o2dnt2 user defined"; + reg = <0x002c0000 0x01d40000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/o2i.dts b/arch/powerpc/boot/dts/o2i.dts new file mode 100644 index 000000000000..e3cc99d1360b --- /dev/null +++ b/arch/powerpc/boot/dts/o2i.dts @@ -0,0 +1,33 @@ +/* + * O2I Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "o2d.dtsi" + +/ { + model = "ifm,o2i"; + compatible = "ifm,o2d"; + + localbus { + flash@0,0 { + partition@60000 { + label = "kernel"; + reg = <0x00060000 0x00260000>; + read-only; + }; + /* o2i specific partitions */ + partition@2c0000 { + label = "o2i user defined"; + reg = <0x002c0000 0x00d40000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/o2mnt.dts b/arch/powerpc/boot/dts/o2mnt.dts new file mode 100644 index 000000000000..d91859a9e940 --- /dev/null +++ b/arch/powerpc/boot/dts/o2mnt.dts @@ -0,0 +1,33 @@ +/* + * O2MNT Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "o2d.dtsi" + +/ { + model = "ifm,o2mnt"; + compatible = "ifm,o2d"; + + localbus { + flash@0,0 { + partition@60000 { + label = "kernel"; + reg = <0x00060000 0x00260000>; + read-only; + }; + /* add o2mnt specific partitions */ + partition@2c0000 { + label = "o2mnt user defined"; + reg = <0x002c0000 0x00d40000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/o3dnt.dts b/arch/powerpc/boot/dts/o3dnt.dts new file mode 100644 index 000000000000..acce49326491 --- /dev/null +++ b/arch/powerpc/boot/dts/o3dnt.dts @@ -0,0 +1,48 @@ +/* + * O3DNT Device Tree Source + * + * Copyright (C) 2012 DENX Software Engineering + * Anatolij Gustschin <agust@denx.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. + */ + +/include/ "o2d.dtsi" + +/ { + model = "ifm,o3dnt"; + compatible = "ifm,o2d"; + + memory { + reg = <0x00000000 0x04000000>; // 64MB + }; + + localbus { + ranges = <0 0 0xfc000000 0x01000000 + 3 0 0xe3000000 0x00100000>; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x01000000>; + bank-width = <2>; + device-width = <2>; + #size-cells = <1>; + #address-cells = <1>; + + partition@60000 { + label = "kernel"; + reg = <0x00060000 0x00260000>; + read-only; + }; + + /* o3dnt specific partitions */ + partition@2c0000 { + label = "o3dnt user defined"; + reg = <0x002c0000 0x00d40000>; + }; + }; + }; +}; diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts deleted file mode 100644 index 41b4585c5da8..000000000000 --- a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * P1020 RDB Core0 Device Tree Source in CAMP mode. - * - * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache - * can be shared, all the other devices must be assigned to one core only. - * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb, - * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. - * - * Please note to add "-b 0" for core0's dts compiling. - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * 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/ "p1020rdb.dts" - -/ { - model = "fsl,P1020RDB"; - compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP"; - - aliases { - ethernet1 = &enet1; - ethernet2 = &enet2; - serial0 = &serial0; - pci0 = &pci0; - pci1 = &pci1; - }; - - cpus { - PowerPC,P1020@1 { - status = "disabled"; - }; - }; - - memory { - device_type = "memory"; - }; - - localbus@ffe05000 { - status = "disabled"; - }; - - soc@ffe00000 { - serial1: serial@4600 { - status = "disabled"; - }; - - enet0: ethernet@b0000 { - status = "disabled"; - }; - - mpic: pic@40000 { - protected-sources = < - 42 29 30 34 /* serial1, enet0-queue-group0 */ - 17 18 24 45 /* enet0-queue-group1, crypto */ - >; - }; - }; -}; diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts deleted file mode 100644 index 517453821884..000000000000 --- a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * P1020 RDB Core1 Device Tree Source in CAMP mode. - * - * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache - * can be shared, all the other devices must be assigned to one core only. - * This dts allows core1 to have l2, eth0, crypto. - * - * Please note to add "-b 1" for core1's dts compiling. - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * 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/ "p1020rdb.dts" - -/ { - model = "fsl,P1020RDB"; - compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP"; - - aliases { - ethernet0 = &enet0; - serial0 = &serial1; - }; - - cpus { - PowerPC,P1020@0 { - status = "disabled"; - }; - }; - - memory { - device_type = "memory"; - }; - - localbus@ffe05000 { - status = "disabled"; - }; - - soc@ffe00000 { - ecm-law@0 { - status = "disabled"; - }; - - ecm@1000 { - status = "disabled"; - }; - - memory-controller@2000 { - status = "disabled"; - }; - - i2c@3000 { - status = "disabled"; - }; - - i2c@3100 { - status = "disabled"; - }; - - serial0: serial@4500 { - status = "disabled"; - }; - - spi@7000 { - status = "disabled"; - }; - - gpio: gpio-controller@f000 { - status = "disabled"; - }; - - dma@21300 { - status = "disabled"; - }; - - mdio@24000 { - status = "disabled"; - }; - - mdio@25000 { - status = "disabled"; - }; - - enet1: ethernet@b1000 { - status = "disabled"; - }; - - enet2: ethernet@b2000 { - status = "disabled"; - }; - - usb@22000 { - status = "disabled"; - }; - - sdhci@2e000 { - status = "disabled"; - }; - - mpic: pic@40000 { - protected-sources = < - 16 /* ecm, mem, L2, pci0, pci1 */ - 43 42 59 /* i2c, serial0, spi */ - 47 63 62 /* gpio, tdm */ - 20 21 22 23 /* dma */ - 03 02 /* mdio */ - 35 36 40 /* enet1-queue-group0 */ - 51 52 67 /* enet1-queue-group1 */ - 31 32 33 /* enet2-queue-group0 */ - 25 26 27 /* enet2-queue-group1 */ - 28 72 58 /* usb, sdhci, crypto */ - 0xb0 0xb1 0xb2 /* message */ - 0xb3 0xb4 0xb5 - 0xb6 0xb7 - 0xe0 0xe1 0xe2 /* msi */ - 0xe3 0xe4 0xe5 - 0xe6 0xe7 /* sdhci, crypto , pci */ - >; - }; - - msi@41600 { - status = "disabled"; - }; - - global-utilities@e0000 { //global utilities block - status = "disabled"; - }; - }; - - pci0: pcie@ffe09000 { - status = "disabled"; - }; - - pci1: pcie@ffe0a000 { - status = "disabled"; - }; -}; diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi index c3344b04d8ff..873da350d01b 100644 --- a/arch/powerpc/boot/dts/p1022ds.dtsi +++ b/arch/powerpc/boot/dts/p1022ds.dtsi @@ -149,6 +149,10 @@ compatible = "dallas,ds1339"; reg = <0x68>; }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; }; spi@7000 { diff --git a/arch/powerpc/boot/dts/p1022rdk.dts b/arch/powerpc/boot/dts/p1022rdk.dts new file mode 100644 index 000000000000..51d82de223f3 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022rdk.dts @@ -0,0 +1,188 @@ +/* + * P1022 RDK 32-bit Physical Address Map Device Tree Source + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/include/ "fsl/p1022si-pre.dtsi" +/ { + model = "fsl,P1022RDK"; + compatible = "fsl,P1022RDK"; + + memory { + device_type = "memory"; + }; + + board_lbc: lbc: localbus@ffe05000 { + /* The P1022 RDK does not have any localbus devices */ + status = "disabled"; + }; + + board_soc: soc: soc@ffe00000 { + ranges = <0x0 0x0 0xffe00000 0x100000>; + + i2c@3100 { + wm8960:codec@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + /* MCLK source is a stand-alone oscillator */ + clock-frequency = <12288000>; + }; + rtc@68 { + compatible = "stm,m41t62"; + reg = <0x68>; + }; + adt7461@4c{ + compatible = "adi,adt7461"; + reg = <0x4c>; + }; + zl6100@21{ + compatible = "isil,zl6100"; + reg = <0x21>; + }; + zl6100@24{ + compatible = "isil,zl6100"; + reg = <0x24>; + }; + zl6100@26{ + compatible = "isil,zl6100"; + reg = <0x26>; + }; + zl6100@29{ + compatible = "isil,zl6100"; + reg = <0x29>; + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,m25p80"; + reg = <0>; + spi-max-frequency = <1000000>; + partition@0 { + label = "full-spi-flash"; + reg = <0x00000000 0x00100000>; + }; + }; + }; + + ssi@15000 { + fsl,mode = "i2s-slave"; + codec-handle = <&wm8960>; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + usb@23000 { + phy_type = "ulpi"; + }; + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupts = <3 1 0 0>; + reg = <0x1>; + }; + phy1: ethernet-phy@1 { + interrupts = <9 1 0 0>; + reg = <0x2>; + }; + }; + + mdio@25000 { + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + ethernet@b0000 { + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + }; + + ethernet@b1000 { + phy-handle = <&phy1>; + tbi-handle = <&tbi0>; + phy-connection-type = "sgmii"; + }; + }; + + pci0: pcie@ffe09000 { + ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; + reg = <0x0 0xffe09000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@ffe0a000 { + ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; + reg = <0 0xffe0a000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci2: pcie@ffe0b000 { + ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; + reg = <0 0xffe0b000 0 0x1000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "fsl/p1022si-post.dtsi" diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts deleted file mode 100644 index 66aac864c4cc..000000000000 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * P2020 RDB Core0 Device Tree Source in CAMP mode. - * - * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache - * can be shared, all the other devices must be assigned to one core only. - * This dts file allows core0 to have memory, l2, i2c, spi, gpio, dma1, usb, - * eth1, eth2, sdhc, crypto, global-util, pci0. - * - * Copyright 2009-2011 Freescale Semiconductor Inc. - * - * 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/ "p2020rdb.dts" - -/ { - model = "fsl,P2020RDB"; - compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; - - cpus { - PowerPC,P2020@1 { - status = "disabled"; - }; - }; - - localbus@ffe05000 { - status = "disabled"; - }; - - soc@ffe00000 { - serial1: serial@4600 { - status = "disabled"; - }; - - dma@c300 { - status = "disabled"; - }; - - enet0: ethernet@24000 { - status = "disabled"; - }; - - mpic: pic@40000 { - protected-sources = < - 42 76 77 78 79 /* serial1 , dma2 */ - 29 30 34 26 /* enet0, pci1 */ - 0xe0 0xe1 0xe2 0xe3 /* msi */ - 0xe4 0xe5 0xe6 0xe7 - >; - }; - - msi@41600 { - status = "disabled"; - }; - }; - - pci0: pcie@ffe08000 { - status = "disabled"; - }; - - pci2: pcie@ffe0a000 { - status = "disabled"; - }; -}; diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts deleted file mode 100644 index 9bd8ef493dd2..000000000000 --- a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts +++ /dev/null @@ -1,125 +0,0 @@ -/* - * P2020 RDB Core1 Device Tree Source in CAMP mode. - * - * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache - * can be shared, all the other devices must be assigned to one core only. - * This dts allows core1 to have l2, dma2, eth0, pci1, msi. - * - * Please note to add "-b 1" for core1's dts compiling. - * - * Copyright 2009-2011 Freescale Semiconductor Inc. - * - * 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/ "p2020rdb.dts" - -/ { - model = "fsl,P2020RDB"; - compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; - - cpus { - PowerPC,P2020@0 { - status = "disabled"; - }; - }; - - localbus@ffe05000 { - status = "disabled"; - }; - - soc@ffe00000 { - ecm-law@0 { - status = "disabled"; - }; - - ecm@1000 { - status = "disabled"; - }; - - memory-controller@2000 { - status = "disabled"; - }; - - i2c@3000 { - status = "disabled"; - }; - - i2c@3100 { - status = "disabled"; - }; - - serial0: serial@4500 { - status = "disabled"; - }; - - spi@7000 { - status = "disabled"; - }; - - gpio: gpio-controller@f000 { - status = "disabled"; - }; - - dma@21300 { - status = "disabled"; - }; - - usb@22000 { - status = "disabled"; - }; - - mdio@24520 { - status = "disabled"; - }; - - mdio@25520 { - status = "disabled"; - }; - - mdio@26520 { - status = "disabled"; - }; - - enet1: ethernet@25000 { - status = "disabled"; - }; - - enet2: ethernet@26000 { - status = "disabled"; - }; - - sdhci@2e000 { - status = "disabled"; - }; - - crypto@30000 { - status = "disabled"; - }; - - mpic: pic@40000 { - protected-sources = < - 17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */ - 16 20 21 22 23 28 /* L2, dma1, USB */ - 03 35 36 40 31 32 33 /* mdio, enet1, enet2 */ - 72 45 58 25 /* sdhci, crypto , pci */ - >; - }; - - global-utilities@e0000 { //global utilities block - status = "disabled"; - }; - - }; - - pci0: pcie@ffe08000 { - status = "disabled"; - }; - - pci1: pcie@ffe09000 { - status = "disabled"; - }; -}; diff --git a/arch/powerpc/boot/dts/p2041rdb.dts b/arch/powerpc/boot/dts/p2041rdb.dts index baab0347dab0..d97ad74c7279 100644 --- a/arch/powerpc/boot/dts/p2041rdb.dts +++ b/arch/powerpc/boot/dts/p2041rdb.dts @@ -94,6 +94,10 @@ compatible = "pericom,pt7c4338"; reg = <0x68>; }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; }; i2c@118100 { diff --git a/arch/powerpc/boot/dts/p3041ds.dts b/arch/powerpc/boot/dts/p3041ds.dts index 6cdcadc80c30..2fed3bc0b990 100644 --- a/arch/powerpc/boot/dts/p3041ds.dts +++ b/arch/powerpc/boot/dts/p3041ds.dts @@ -98,6 +98,10 @@ reg = <0x68>; interrupts = <0x1 0x1 0 0>; }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; }; }; diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts index 3e204609d02e..1cf6148b8b05 100644 --- a/arch/powerpc/boot/dts/p4080ds.dts +++ b/arch/powerpc/boot/dts/p4080ds.dts @@ -96,6 +96,10 @@ reg = <0x68>; interrupts = <0x1 0x1 0 0>; }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; }; usb0: usb@210000 { diff --git a/arch/powerpc/boot/dts/p5020ds.dts b/arch/powerpc/boot/dts/p5020ds.dts index 27c07ed6adc1..2869fea717dd 100644 --- a/arch/powerpc/boot/dts/p5020ds.dts +++ b/arch/powerpc/boot/dts/p5020ds.dts @@ -98,6 +98,10 @@ reg = <0x68>; interrupts = <0x1 0x1 0 0>; }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; }; }; diff --git a/arch/powerpc/boot/dts/p5040ds.dts b/arch/powerpc/boot/dts/p5040ds.dts new file mode 100644 index 000000000000..860b5ccf76c0 --- /dev/null +++ b/arch/powerpc/boot/dts/p5040ds.dts @@ -0,0 +1,207 @@ +/* + * P5040DS Device Tree Source + * + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * This software is provided by Freescale Semiconductor "as is" and any + * express or implied warranties, including, but not limited to, the implied + * warranties of merchantability and fitness for a particular purpose are + * disclaimed. In no event shall Freescale Semiconductor be liable for any + * direct, indirect, incidental, special, exemplary, or consequential damages + * (including, but not limited to, procurement of substitute goods or services; + * loss of use, data, or profits; or business interruption) however caused and + * on any theory of liability, whether in contract, strict liability, or tort + * (including negligence or otherwise) arising in any way out of the use of this + * software, even if advised of the possibility of such damage. + */ + +/include/ "fsl/p5040si-pre.dtsi" + +/ { + model = "fsl,P5040DS"; + compatible = "fsl,P5040DS"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&mpic>; + + memory { + device_type = "memory"; + }; + + dcsr: dcsr@f00000000 { + ranges = <0x00000000 0xf 0x00000000 0x01008000>; + }; + + soc: soc@ffe000000 { + ranges = <0x00000000 0xf 0xfe000000 0x1000000>; + reg = <0xf 0xfe000000 0 0x00001000>; + spi@110000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl12801"; + reg = <0>; + spi-max-frequency = <40000000>; /* input clock */ + partition@u-boot { + label = "u-boot"; + reg = <0x00000000 0x00100000>; + }; + partition@kernel { + label = "kernel"; + reg = <0x00100000 0x00500000>; + }; + partition@dtb { + label = "dtb"; + reg = <0x00600000 0x00100000>; + }; + partition@fs { + label = "file system"; + reg = <0x00700000 0x00900000>; + }; + }; + }; + + i2c@118100 { + eeprom@51 { + compatible = "at24,24c256"; + reg = <0x51>; + }; + eeprom@52 { + compatible = "at24,24c256"; + reg = <0x52>; + }; + }; + + i2c@119100 { + rtc@68 { + compatible = "dallas,ds3232"; + reg = <0x68>; + interrupts = <0x1 0x1 0 0>; + }; + adt7461@4c { + compatible = "adi,adt7461"; + reg = <0x4c>; + }; + }; + }; + + lbc: localbus@ffe124000 { + reg = <0xf 0xfe124000 0 0x1000>; + ranges = <0 0 0xf 0xe8000000 0x08000000 + 2 0 0xf 0xffa00000 0x00040000 + 3 0 0xf 0xffdf0000 0x00008000>; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x08000000>; + bank-width = <2>; + device-width = <2>; + }; + + nand@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elbc-fcm-nand"; + reg = <0x2 0x0 0x40000>; + + partition@0 { + label = "NAND U-Boot Image"; + reg = <0x0 0x02000000>; + }; + + partition@2000000 { + label = "NAND Root File System"; + reg = <0x02000000 0x10000000>; + }; + + partition@12000000 { + label = "NAND Compressed RFS Image"; + reg = <0x12000000 0x08000000>; + }; + + partition@1a000000 { + label = "NAND Linux Kernel Image"; + reg = <0x1a000000 0x04000000>; + }; + + partition@1e000000 { + label = "NAND DTB Image"; + reg = <0x1e000000 0x01000000>; + }; + + partition@1f000000 { + label = "NAND Writable User area"; + reg = <0x1f000000 0x01000000>; + }; + }; + + board-control@3,0 { + compatible = "fsl,p5040ds-fpga", "fsl,fpga-ngpixis"; + reg = <3 0 0x40>; + }; + }; + + pci0: pcie@ffe200000 { + reg = <0xf 0xfe200000 0 0x1000>; + ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000 + 0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>; + pcie@0 { + ranges = <0x02000000 0 0xe0000000 + 0x02000000 0 0xe0000000 + 0 0x20000000 + + 0x01000000 0 0x00000000 + 0x01000000 0 0x00000000 + 0 0x00010000>; + }; + }; + + pci1: pcie@ffe201000 { + reg = <0xf 0xfe201000 0 0x1000>; + ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 + 0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>; + pcie@0 { + ranges = <0x02000000 0 0xe0000000 + 0x02000000 0 0xe0000000 + 0 0x20000000 + + 0x01000000 0 0x00000000 + 0x01000000 0 0x00000000 + 0 0x00010000>; + }; + }; + + pci2: pcie@ffe202000 { + reg = <0xf 0xfe202000 0 0x1000>; + ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000 + 0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>; + pcie@0 { + ranges = <0x02000000 0 0xe0000000 + 0x02000000 0 0xe0000000 + 0 0x20000000 + + 0x01000000 0 0x00000000 + 0x01000000 0 0x00000000 + 0 0x00010000>; + }; + }; +}; + +/include/ "fsl/p5040si-post.dtsi" diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig index 26e541c4662b..b80bcc69d1f7 100644 --- a/arch/powerpc/configs/85xx/p1023rds_defconfig +++ b/arch/powerpc/configs/85xx/p1023rds_defconfig @@ -112,6 +112,12 @@ CONFIG_SND=y CONFIG_SND_MIXER_OSS=y CONFIG_SND_PCM_OSS=y # CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_USB=y +CONFIG_USB_DEVICEFS=y +CONFIG_USB_MON=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_FSL=y +CONFIG_USB_STORAGE=y CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig index 8b3d57c1ebe8..1c0f2432ecdb 100644 --- a/arch/powerpc/configs/corenet32_smp_defconfig +++ b/arch/powerpc/configs/corenet32_smp_defconfig @@ -27,6 +27,7 @@ CONFIG_P2041_RDB=y CONFIG_P3041_DS=y CONFIG_P4080_DS=y CONFIG_P5020_DS=y +CONFIG_P5040_DS=y CONFIG_HIGHMEM=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_MISC=m diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig index 0516e22ca3de..88fa5c46f66f 100644 --- a/arch/powerpc/configs/corenet64_smp_defconfig +++ b/arch/powerpc/configs/corenet64_smp_defconfig @@ -23,6 +23,7 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_MAC_PARTITION=y CONFIG_P5020_DS=y +CONFIG_P5040_DS=y # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set CONFIG_BINFMT_MISC=m CONFIG_IRQ_ALL_CPUS=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index 8b5bda27d248..cf815e847cdc 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -30,6 +30,7 @@ CONFIG_MPC85xx_DS=y CONFIG_MPC85xx_RDB=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y +CONFIG_P1022_RDK=y CONFIG_P1023_RDS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index b0974e7e98ae..502cd9e027e4 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -32,6 +32,7 @@ CONFIG_MPC85xx_DS=y CONFIG_MPC85xx_RDB=y CONFIG_P1010_RDB=y CONFIG_P1022_DS=y +CONFIG_P1022_RDK=y CONFIG_P1023_RDS=y CONFIG_SOCRATES=y CONFIG_KSI8560=y diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 06b56245d78c..6d03530b7506 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -51,6 +51,7 @@ CONFIG_KEXEC=y CONFIG_IRQ_ALL_CPUS=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_SCHED_SMT=y +CONFIG_PPC_DENORMALISATION=y CONFIG_PCCARD=y CONFIG_ELECTRA_CF=y CONFIG_HOTPLUG_PCI=m @@ -486,7 +487,8 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_HW=y -CONFIG_CRYPTO_DEV_NX=m +CONFIG_CRYPTO_DEV_NX=y +CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 1f65b3c9b59a..1f710a32ffae 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -48,6 +48,7 @@ CONFIG_MEMORY_HOTREMOVE=y CONFIG_PPC_64K_PAGES=y CONFIG_PPC_SUBPAGE_PROT=y CONFIG_SCHED_SMT=y +CONFIG_PPC_DENORMALISATION=y CONFIG_HOTPLUG_PCI=m CONFIG_HOTPLUG_PCI_RPA=m CONFIG_HOTPLUG_PCI_RPA_DLPAR=m @@ -369,7 +370,8 @@ CONFIG_CRYPTO_TWOFISH=m CONFIG_CRYPTO_LZO=m # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_HW=y -CONFIG_CRYPTO_DEV_NX=m +CONFIG_CRYPTO_DEV_NX=y +CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h deleted file mode 100644 index 9d92ba04b033..000000000000 --- a/arch/powerpc/include/asm/abs_addr.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _ASM_POWERPC_ABS_ADDR_H -#define _ASM_POWERPC_ABS_ADDR_H -#ifdef __KERNEL__ - - -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/memblock.h> - -#include <asm/types.h> -#include <asm/page.h> -#include <asm/prom.h> - -struct mschunks_map { - unsigned long num_chunks; - unsigned long chunk_size; - unsigned long chunk_shift; - unsigned long chunk_mask; - u32 *mapping; -}; - -extern struct mschunks_map mschunks_map; - -/* Chunks are 256 KB */ -#define MSCHUNKS_CHUNK_SHIFT (18) -#define MSCHUNKS_CHUNK_SIZE (1UL << MSCHUNKS_CHUNK_SHIFT) -#define MSCHUNKS_OFFSET_MASK (MSCHUNKS_CHUNK_SIZE - 1) - -static inline unsigned long chunk_to_addr(unsigned long chunk) -{ - return chunk << MSCHUNKS_CHUNK_SHIFT; -} - -static inline unsigned long addr_to_chunk(unsigned long addr) -{ - return addr >> MSCHUNKS_CHUNK_SHIFT; -} - -static inline unsigned long phys_to_abs(unsigned long pa) -{ - return pa; -} - -/* Convenience macros */ -#define virt_to_abs(va) phys_to_abs(__pa(va)) -#define abs_to_virt(aa) __va(aa) - -#endif /* __KERNEL__ */ -#endif /* _ASM_POWERPC_ABS_ADDR_H */ diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h index efdc92618b38..dc2cf9c6d9e6 100644 --- a/arch/powerpc/include/asm/bitops.h +++ b/arch/powerpc/include/asm/bitops.h @@ -288,6 +288,16 @@ static __inline__ int test_bit_le(unsigned long nr, return (tmp[nr >> 3] >> (nr & 7)) & 1; } +static inline void set_bit_le(int nr, void *addr) +{ + set_bit(nr ^ BITOP_LE_SWIZZLE, addr); +} + +static inline void clear_bit_le(int nr, void *addr) +{ + clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); +} + static inline void __set_bit_le(int nr, void *addr) { __set_bit(nr ^ BITOP_LE_SWIZZLE, addr); diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index ab9e402518e8..b843e35122e8 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -30,6 +30,8 @@ extern void flush_dcache_page(struct page *page); #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) +extern void __flush_disable_L1(void); + extern void __flush_icache_range(unsigned long, unsigned long); static inline void flush_icache_range(unsigned long start, unsigned long stop) { diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 88e602f6430d..84fdf6857c31 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -38,6 +38,7 @@ typedef s64 compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -114,6 +115,64 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +#define SI_PAD_SIZE32 (128/sizeof(int) - 3) + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE32]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + __compat_uid_t _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + __compat_uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ + struct { + unsigned int _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -123,7 +182,6 @@ typedef u32 compat_sigset_word; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h index 716d2f089eb6..32de2577bb6d 100644 --- a/arch/powerpc/include/asm/debug.h +++ b/arch/powerpc/include/asm/debug.h @@ -44,7 +44,7 @@ static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } #endif -extern int set_dabr(unsigned long dabr); +extern int set_dabr(unsigned long dabr, unsigned long dabrx); #ifdef CONFIG_PPC_ADV_DEBUG_REGS extern void do_send_trap(struct pt_regs *regs, unsigned long address, unsigned long error_code, int signal_code, int brkpt); diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index d60f99814ffb..b0ef73882b38 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -32,27 +32,62 @@ struct device_node; #ifdef CONFIG_EEH /* + * The struct is used to trace PE related EEH functionality. + * In theory, there will have one instance of the struct to + * be created against particular PE. In nature, PEs corelate + * to each other. the struct has to reflect that hierarchy in + * order to easily pick up those affected PEs when one particular + * PE has EEH errors. + * + * Also, one particular PE might be composed of PCI device, PCI + * bus and its subordinate components. The struct also need ship + * the information. Further more, one particular PE is only meaingful + * in the corresponding PHB. Therefore, the root PEs should be created + * against existing PHBs in on-to-one fashion. + */ +#define EEH_PE_INVALID (1 << 0) /* Invalid */ +#define EEH_PE_PHB (1 << 1) /* PHB PE */ +#define EEH_PE_DEVICE (1 << 2) /* Device PE */ +#define EEH_PE_BUS (1 << 3) /* Bus PE */ + +#define EEH_PE_ISOLATED (1 << 0) /* Isolated PE */ +#define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ + +struct eeh_pe { + int type; /* PE type: PHB/Bus/Device */ + int state; /* PE EEH dependent mode */ + int config_addr; /* Traditional PCI address */ + int addr; /* PE configuration address */ + struct pci_controller *phb; /* Associated PHB */ + int check_count; /* Times of ignored error */ + int freeze_count; /* Times of froze up */ + int false_positives; /* Times of reported #ff's */ + struct eeh_pe *parent; /* Parent PE */ + struct list_head child_list; /* Link PE to the child list */ + struct list_head edevs; /* Link list of EEH devices */ + struct list_head child; /* Child PEs */ +}; + +#define eeh_pe_for_each_dev(pe, edev) \ + list_for_each_entry(edev, &pe->edevs, list) + +/* * The struct is used to trace EEH state for the associated * PCI device node or PCI device. In future, it might * represent PE as well so that the EEH device to form * another tree except the currently existing tree of PCI * buses and PCI devices */ -#define EEH_MODE_SUPPORTED (1<<0) /* EEH supported on the device */ -#define EEH_MODE_NOCHECK (1<<1) /* EEH check should be skipped */ -#define EEH_MODE_ISOLATED (1<<2) /* The device has been isolated */ -#define EEH_MODE_RECOVERING (1<<3) /* Recovering the device */ -#define EEH_MODE_IRQ_DISABLED (1<<4) /* Interrupt disabled */ +#define EEH_DEV_IRQ_DISABLED (1<<0) /* Interrupt disabled */ struct eeh_dev { int mode; /* EEH mode */ int class_code; /* Class code of the device */ int config_addr; /* Config address */ int pe_config_addr; /* PE config address */ - int check_count; /* Times of ignored error */ - int freeze_count; /* Times of froze up */ - int false_positives; /* Times of reported #ff's */ u32 config_space[16]; /* Saved PCI config space */ + struct eeh_pe *pe; /* Associated PE */ + struct list_head list; /* Form link list in the PE */ struct pci_controller *phb; /* Associated PHB */ struct device_node *dn; /* Associated device node */ struct pci_dev *pdev; /* Associated PCI device */ @@ -95,19 +130,51 @@ static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) struct eeh_ops { char *name; int (*init)(void); - int (*set_option)(struct device_node *dn, int option); - int (*get_pe_addr)(struct device_node *dn); - int (*get_state)(struct device_node *dn, int *state); - int (*reset)(struct device_node *dn, int option); - int (*wait_state)(struct device_node *dn, int max_wait); - int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len); - int (*configure_bridge)(struct device_node *dn); + void* (*of_probe)(struct device_node *dn, void *flag); + void* (*dev_probe)(struct pci_dev *dev, void *flag); + int (*set_option)(struct eeh_pe *pe, int option); + int (*get_pe_addr)(struct eeh_pe *pe); + int (*get_state)(struct eeh_pe *pe, int *state); + int (*reset)(struct eeh_pe *pe, int option); + int (*wait_state)(struct eeh_pe *pe, int max_wait); + int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len); + int (*configure_bridge)(struct eeh_pe *pe); int (*read_config)(struct device_node *dn, int where, int size, u32 *val); int (*write_config)(struct device_node *dn, int where, int size, u32 val); }; extern struct eeh_ops *eeh_ops; extern int eeh_subsystem_enabled; +extern struct mutex eeh_mutex; +extern int eeh_probe_mode; + +#define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */ +#define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */ + +static inline void eeh_probe_mode_set(int flag) +{ + eeh_probe_mode = flag; +} + +static inline int eeh_probe_mode_devtree(void) +{ + return (eeh_probe_mode == EEH_PROBE_MODE_DEVTREE); +} + +static inline int eeh_probe_mode_dev(void) +{ + return (eeh_probe_mode == EEH_PROBE_MODE_DEV); +} + +static inline void eeh_lock(void) +{ + mutex_lock(&eeh_mutex); +} + +static inline void eeh_unlock(void) +{ + mutex_unlock(&eeh_mutex); +} /* * Max number of EEH freezes allowed before we consider the device @@ -115,22 +182,26 @@ extern int eeh_subsystem_enabled; */ #define EEH_MAX_ALLOWED_FREEZES 5 +typedef void *(*eeh_traverse_func)(void *data, void *flag); +int __devinit eeh_phb_pe_create(struct pci_controller *phb); +int eeh_add_to_parent_pe(struct eeh_dev *edev); +int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe); +void *eeh_pe_dev_traverse(struct eeh_pe *root, + eeh_traverse_func fn, void *flag); +void eeh_pe_restore_bars(struct eeh_pe *pe); +struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); + void * __devinit eeh_dev_init(struct device_node *dn, void *data); void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); -void __init eeh_dev_phb_init(void); -void __init eeh_init(void); -#ifdef CONFIG_PPC_PSERIES -int __init eeh_pseries_init(void); -#endif int __init eeh_ops_register(struct eeh_ops *ops); int __exit eeh_ops_unregister(const char *name); unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val); -int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); -void __init pci_addr_cache_build(void); +int eeh_dev_check_failure(struct eeh_dev *edev); +void __init eeh_addr_cache_build(void); void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_tree_late(struct pci_bus *); -void eeh_remove_bus_device(struct pci_dev *); +void eeh_remove_bus_device(struct pci_dev *, int); /** * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. @@ -156,34 +227,24 @@ static inline void *eeh_dev_init(struct device_node *dn, void *data) static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } -static inline void eeh_dev_phb_init(void) { } - -static inline void eeh_init(void) { } - -#ifdef CONFIG_PPC_PSERIES -static inline int eeh_pseries_init(void) -{ - return 0; -} -#endif /* CONFIG_PPC_PSERIES */ - static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) { return val; } -static inline int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) -{ - return 0; -} +#define eeh_dev_check_failure(x) (0) -static inline void pci_addr_cache_build(void) { } +static inline void eeh_addr_cache_build(void) { } static inline void eeh_add_device_tree_early(struct device_node *dn) { } static inline void eeh_add_device_tree_late(struct pci_bus *bus) { } -static inline void eeh_remove_bus_device(struct pci_dev *dev) { } +static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { } + +static inline void eeh_lock(void) { } +static inline void eeh_unlock(void) { } + #define EEH_POSSIBLE_ERROR(val, type) (0) #define EEH_IO_ERROR_VALUE(size) (-1UL) #endif /* CONFIG_EEH */ diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h index c68b012b7797..de67d830151b 100644 --- a/arch/powerpc/include/asm/eeh_event.h +++ b/arch/powerpc/include/asm/eeh_event.h @@ -28,11 +28,11 @@ */ struct eeh_event { struct list_head list; /* to form event queue */ - struct eeh_dev *edev; /* EEH device */ + struct eeh_pe *pe; /* EEH PE */ }; -int eeh_send_failure_event(struct eeh_dev *edev); -struct eeh_dev *handle_eeh_events(struct eeh_event *); +int eeh_send_failure_event(struct eeh_pe *pe); +void eeh_handle_event(struct eeh_pe *pe); #endif /* __KERNEL__ */ #endif /* ASM_POWERPC_EEH_EVENT_H */ diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h index ac13addb8495..51fa43e536b9 100644 --- a/arch/powerpc/include/asm/exception-64e.h +++ b/arch/powerpc/include/asm/exception-64e.h @@ -37,6 +37,7 @@ * critical data */ +#define PACA_EXGDBELL PACA_EXGEN /* We are out of SPRGs so we save some things in the PACA. The normal * exception frame is smaller than the CRIT or MC one though @@ -45,8 +46,9 @@ #define EX_CR (1 * 8) #define EX_R10 (2 * 8) #define EX_R11 (3 * 8) -#define EX_R14 (4 * 8) -#define EX_R15 (5 * 8) +#define EX_R13 (4 * 8) +#define EX_R14 (5 * 8) +#define EX_R15 (6 * 8) /* * The TLB miss exception uses different slots. diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index aa4c488589ce..dd5ba2c22771 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -48,6 +48,8 @@ struct ccsr_guts { __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */ u8 res06c[0x70 - 0x6c]; __be32 devdisr; /* 0x.0070 - Device Disable Control */ +#define CCSR_GUTS_DEVDISR_TB1 0x00001000 +#define CCSR_GUTS_DEVDISR_TB0 0x00004000 __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ u8 res078[0x7c - 0x78]; __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */ diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h index b955012939a2..b8a4b9bc50b3 100644 --- a/arch/powerpc/include/asm/fsl_ifc.h +++ b/arch/powerpc/include/asm/fsl_ifc.h @@ -768,22 +768,24 @@ struct fsl_ifc_gpcm { */ struct fsl_ifc_regs { __be32 ifc_rev; - u32 res1[0x3]; + u32 res1[0x2]; struct { + __be32 cspr_ext; __be32 cspr; - u32 res2[0x2]; + u32 res2; } cspr_cs[FSL_IFC_BANK_COUNT]; - u32 res3[0x18]; + u32 res3[0x19]; struct { __be32 amask; u32 res4[0x2]; } amask_cs[FSL_IFC_BANK_COUNT]; - u32 res5[0x18]; + u32 res5[0x17]; struct { + __be32 csor_ext; __be32 csor; - u32 res6[0x2]; + u32 res6; } csor_cs[FSL_IFC_BANK_COUNT]; - u32 res7[0x18]; + u32 res7[0x19]; struct { __be32 ftim[4]; u32 res8[0x8]; diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 423cf9eaf4a4..7a867065db79 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -152,11 +152,6 @@ #define H_VASI_RESUMED 5 #define H_VASI_COMPLETED 6 -/* DABRX flags */ -#define H_DABRX_HYPERVISOR (1UL<<(63-61)) -#define H_DABRX_KERNEL (1UL<<(63-62)) -#define H_DABRX_USER (1UL<<(63-63)) - /* Each control block has to be on a 4K boundary */ #define H_CB_ALIGNMENT 4096 diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h index be04330af751..423424599dad 100644 --- a/arch/powerpc/include/asm/hw_breakpoint.h +++ b/arch/powerpc/include/asm/hw_breakpoint.h @@ -27,10 +27,11 @@ #ifdef CONFIG_HAVE_HW_BREAKPOINT struct arch_hw_breakpoint { - bool extraneous_interrupt; - u8 len; /* length of the target data symbol */ - int type; unsigned long address; + unsigned long dabrx; + int type; + u8 len; /* length of the target data symbol */ + bool extraneous_interrupt; }; #include <linux/kdebug.h> @@ -61,7 +62,7 @@ extern void ptrace_triggered(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs); static inline void hw_breakpoint_disable(void) { - set_dabr(0); + set_dabr(0, 0); } extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/kprobes.h b/arch/powerpc/include/asm/kprobes.h index be0171afdc0f..7b6feab6fd26 100644 --- a/arch/powerpc/include/asm/kprobes.h +++ b/arch/powerpc/include/asm/kprobes.h @@ -29,21 +29,16 @@ #include <linux/types.h> #include <linux/ptrace.h> #include <linux/percpu.h> +#include <asm/probes.h> #define __ARCH_WANT_KPROBES_INSN_SLOT struct pt_regs; struct kprobe; -typedef unsigned int kprobe_opcode_t; -#define BREAKPOINT_INSTRUCTION 0x7fe00008 /* trap */ +typedef ppc_opcode_t kprobe_opcode_t; #define MAX_INSN_SIZE 1 -#define IS_TW(instr) (((instr) & 0xfc0007fe) == 0x7c000008) -#define IS_TD(instr) (((instr) & 0xfc0007fe) == 0x7c000088) -#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) -#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) - #ifdef CONFIG_PPC64 /* * 64bit powerpc uses function descriptors. @@ -72,12 +67,6 @@ typedef unsigned int kprobe_opcode_t; addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \ } \ } - -#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ - IS_TWI(instr) || IS_TDI(instr)) -#else -/* Use stock kprobe_lookup_name since ppc32 doesn't use function descriptors */ -#define is_trap(instr) (IS_TW(instr) || IS_TWI(instr)) #endif #define flush_insn_slot(p) do { } while (0) diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index f0e0c6a66d97..7aefdb3e1ce4 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -59,7 +59,7 @@ struct hpte_cache { struct hlist_node list_vpte; struct hlist_node list_vpte_long; struct rcu_head rcu_head; - u64 host_va; + u64 host_vpn; u64 pfn; ulong slot; struct kvmppc_pte pte; diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h index bfcd00c1485d..88609b23b775 100644 --- a/arch/powerpc/include/asm/kvm_book3s_asm.h +++ b/arch/powerpc/include/asm/kvm_book3s_asm.h @@ -74,7 +74,6 @@ struct kvmppc_host_state { ulong vmhandler; ulong scratch0; ulong scratch1; - ulong sprg3; u8 in_guest; u8 restore_hid5; u8 napping; diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index a8bf5c673a3c..28e8f5e5c63e 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -53,6 +53,8 @@ struct kvm; extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); +extern int kvm_unmap_hva_range(struct kvm *kvm, + unsigned long start, unsigned long end); extern int kvm_age_hva(struct kvm *kvm, unsigned long hva); extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); @@ -220,6 +222,7 @@ struct revmap_entry { #define KVMPPC_GOT_PAGE 0x80 struct kvm_arch_memory_slot { + unsigned long *rmap; }; struct kvm_arch { diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index f7706d722b39..c4231973edd3 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -34,19 +34,19 @@ struct machdep_calls { char *name; #ifdef CONFIG_PPC64 void (*hpte_invalidate)(unsigned long slot, - unsigned long va, + unsigned long vpn, int psize, int ssize, int local); long (*hpte_updatepp)(unsigned long slot, unsigned long newpp, - unsigned long va, + unsigned long vpn, int psize, int ssize, int local); void (*hpte_updateboltedpp)(unsigned long newpp, unsigned long ea, int psize, int ssize); long (*hpte_insert)(unsigned long hpte_group, - unsigned long va, + unsigned long vpn, unsigned long prpn, unsigned long rflags, unsigned long vflags, @@ -180,7 +180,8 @@ struct machdep_calls { void (*enable_pmcs)(void); /* Set DABR for this platform, leave empty for default implemenation */ - int (*set_dabr)(unsigned long dabr); + int (*set_dabr)(unsigned long dabr, + unsigned long dabrx); #ifdef CONFIG_PPC32 /* XXX for now */ /* A general init function, called by ppc_init in init/main.c. diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 1c65a59881ea..9673f73eb8db 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -16,6 +16,13 @@ #include <asm/page.h> /* + * This is necessary to get the definition of PGTABLE_RANGE which we + * need for various slices related matters. Note that this isn't the + * complete pgtable.h but only a portion of it. + */ +#include <asm/pgtable-ppc64.h> + +/* * Segment table */ @@ -154,9 +161,25 @@ struct mmu_psize_def #define MMU_SEGSIZE_256M 0 #define MMU_SEGSIZE_1T 1 +/* + * encode page number shift. + * in order to fit the 78 bit va in a 64 bit variable we shift the va by + * 12 bits. This enable us to address upto 76 bit va. + * For hpt hash from a va we can ignore the page size bits of va and for + * hpte encoding we ignore up to 23 bits of va. So ignoring lower 12 bits ensure + * we work in all cases including 4k page size. + */ +#define VPN_SHIFT 12 #ifndef __ASSEMBLY__ +static inline int segment_shift(int ssize) +{ + if (ssize == MMU_SEGSIZE_256M) + return SID_SHIFT; + return SID_SHIFT_1T; +} + /* * The current system page and segment sizes */ @@ -180,18 +203,39 @@ extern unsigned long tce_alloc_start, tce_alloc_end; extern int mmu_ci_restrictions; /* + * This computes the AVPN and B fields of the first dword of a HPTE, + * for use when we want to match an existing PTE. The bottom 7 bits + * of the returned value are zero. + */ +static inline unsigned long hpte_encode_avpn(unsigned long vpn, int psize, + int ssize) +{ + unsigned long v; + /* + * The AVA field omits the low-order 23 bits of the 78 bits VA. + * These bits are not needed in the PTE, because the + * low-order b of these bits are part of the byte offset + * into the virtual page and, if b < 23, the high-order + * 23-b of these bits are always used in selecting the + * PTEGs to be searched + */ + v = (vpn >> (23 - VPN_SHIFT)) & ~(mmu_psize_defs[psize].avpnm); + v <<= HPTE_V_AVPN_SHIFT; + v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; + return v; +} + +/* * This function sets the AVPN and L fields of the HPTE appropriately * for the page size */ -static inline unsigned long hpte_encode_v(unsigned long va, int psize, - int ssize) +static inline unsigned long hpte_encode_v(unsigned long vpn, + int psize, int ssize) { unsigned long v; - v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm); - v <<= HPTE_V_AVPN_SHIFT; + v = hpte_encode_avpn(vpn, psize, ssize); if (psize != MMU_PAGE_4K) v |= HPTE_V_LARGE; - v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; return v; } @@ -216,30 +260,37 @@ static inline unsigned long hpte_encode_r(unsigned long pa, int psize) } /* - * Build a VA given VSID, EA and segment size + * Build a VPN_SHIFT bit shifted va given VSID, EA and segment size. */ -static inline unsigned long hpt_va(unsigned long ea, unsigned long vsid, - int ssize) +static inline unsigned long hpt_vpn(unsigned long ea, + unsigned long vsid, int ssize) { - if (ssize == MMU_SEGSIZE_256M) - return (vsid << 28) | (ea & 0xfffffffUL); - return (vsid << 40) | (ea & 0xffffffffffUL); + unsigned long mask; + int s_shift = segment_shift(ssize); + + mask = (1ul << (s_shift - VPN_SHIFT)) - 1; + return (vsid << (s_shift - VPN_SHIFT)) | ((ea >> VPN_SHIFT) & mask); } /* * This hashes a virtual address */ - -static inline unsigned long hpt_hash(unsigned long va, unsigned int shift, - int ssize) +static inline unsigned long hpt_hash(unsigned long vpn, + unsigned int shift, int ssize) { + int mask; unsigned long hash, vsid; + /* VPN_SHIFT can be atmost 12 */ if (ssize == MMU_SEGSIZE_256M) { - hash = (va >> 28) ^ ((va & 0x0fffffffUL) >> shift); + mask = (1ul << (SID_SHIFT - VPN_SHIFT)) - 1; + hash = (vpn >> (SID_SHIFT - VPN_SHIFT)) ^ + ((vpn & mask) >> (shift - VPN_SHIFT)); } else { - vsid = va >> 40; - hash = vsid ^ (vsid << 25) ^ ((va & 0xffffffffffUL) >> shift); + mask = (1ul << (SID_SHIFT_1T - VPN_SHIFT)) - 1; + vsid = vpn >> (SID_SHIFT_1T - VPN_SHIFT); + hash = vsid ^ (vsid << 25) ^ + ((vpn & mask) >> (shift - VPN_SHIFT)) ; } return hash & 0x7fffffffffUL; } @@ -280,63 +331,61 @@ extern void slb_set_size(u16 size); #endif /* __ASSEMBLY__ */ /* - * VSID allocation + * VSID allocation (256MB segment) + * + * We first generate a 38-bit "proto-VSID". For kernel addresses this + * is equal to the ESID | 1 << 37, for user addresses it is: + * (context << USER_ESID_BITS) | (esid & ((1U << USER_ESID_BITS) - 1) * - * We first generate a 36-bit "proto-VSID". For kernel addresses this - * is equal to the ESID, for user addresses it is: - * (context << 15) | (esid & 0x7fff) + * This splits the proto-VSID into the below range + * 0 - (2^(CONTEXT_BITS + USER_ESID_BITS) - 1) : User proto-VSID range + * 2^(CONTEXT_BITS + USER_ESID_BITS) - 2^(VSID_BITS) : Kernel proto-VSID range * - * The two forms are distinguishable because the top bit is 0 for user - * addresses, whereas the top two bits are 1 for kernel addresses. - * Proto-VSIDs with the top two bits equal to 0b10 are reserved for - * now. + * We also have CONTEXT_BITS + USER_ESID_BITS = VSID_BITS - 1 + * That is, we assign half of the space to user processes and half + * to the kernel. * * The proto-VSIDs are then scrambled into real VSIDs with the * multiplicative hash: * * VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS - * where VSID_MULTIPLIER = 268435399 = 0xFFFFFC7 - * VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF * - * This scramble is only well defined for proto-VSIDs below - * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are - * reserved. VSID_MULTIPLIER is prime, so in particular it is + * VSID_MULTIPLIER is prime, so in particular it is * co-prime to VSID_MODULUS, making this a 1:1 scrambling function. * Because the modulus is 2^n-1 we can compute it efficiently without * a divide or extra multiply (see below). * * This scheme has several advantages over older methods: * - * - We have VSIDs allocated for every kernel address + * - We have VSIDs allocated for every kernel address * (i.e. everything above 0xC000000000000000), except the very top * segment, which simplifies several things. * - * - We allow for 16 significant bits of ESID and 19 bits of - * context for user addresses. i.e. 16T (44 bits) of address space for - * up to half a million contexts. + * - We allow for USER_ESID_BITS significant bits of ESID and + * CONTEXT_BITS bits of context for user addresses. + * i.e. 64T (46 bits) of address space for up to half a million contexts. * - * - The scramble function gives robust scattering in the hash + * - The scramble function gives robust scattering in the hash * table (at least based on some initial results). The previous * method was more susceptible to pathological cases giving excessive * hash collisions. */ + /* - * WARNING - If you change these you must make sure the asm - * implementations in slb_allocate (slb_low.S), do_stab_bolted - * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly. + * This should be computed such that protovosid * vsid_mulitplier + * doesn't overflow 64 bits. It should also be co-prime to vsid_modulus */ - -#define VSID_MULTIPLIER_256M ASM_CONST(200730139) /* 28-bit prime */ -#define VSID_BITS_256M 36 +#define VSID_MULTIPLIER_256M ASM_CONST(12538073) /* 24-bit prime */ +#define VSID_BITS_256M 38 #define VSID_MODULUS_256M ((1UL<<VSID_BITS_256M)-1) #define VSID_MULTIPLIER_1T ASM_CONST(12538073) /* 24-bit prime */ -#define VSID_BITS_1T 24 +#define VSID_BITS_1T 26 #define VSID_MODULUS_1T ((1UL<<VSID_BITS_1T)-1) #define CONTEXT_BITS 19 -#define USER_ESID_BITS 16 -#define USER_ESID_BITS_1T 4 +#define USER_ESID_BITS 18 +#define USER_ESID_BITS_1T 6 #define USER_VSID_RANGE (1UL << (USER_ESID_BITS + SID_SHIFT)) @@ -372,6 +421,8 @@ extern void slb_set_size(u16 size); srdi rx,rx,VSID_BITS_##size; /* extract 2^VSID_BITS bit */ \ add rt,rt,rx +/* 4 bits per slice and we have one slice per 1TB */ +#define SLICE_ARRAY_SIZE (PGTABLE_RANGE >> 41) #ifndef __ASSEMBLY__ @@ -416,7 +467,7 @@ typedef struct { #ifdef CONFIG_PPC_MM_SLICES u64 low_slices_psize; /* SLB page size encodings */ - u64 high_slices_psize; /* 4 bits per slice for now */ + unsigned char high_slices_psize[SLICE_ARRAY_SIZE]; #else u16 sllp; /* SLB page size encoding */ #endif @@ -452,12 +503,32 @@ typedef struct { }) #endif /* 1 */ -/* This is only valid for addresses >= PAGE_OFFSET */ +/* + * This is only valid for addresses >= PAGE_OFFSET + * The proto-VSID space is divided into two class + * User: 0 to 2^(CONTEXT_BITS + USER_ESID_BITS) -1 + * kernel: 2^(CONTEXT_BITS + USER_ESID_BITS) to 2^(VSID_BITS) - 1 + * + * With KERNEL_START at 0xc000000000000000, the proto vsid for + * the kernel ends up with 0xc00000000 (36 bits). With 64TB + * support we need to have kernel proto-VSID in the + * [2^37 to 2^38 - 1] range due to the increased USER_ESID_BITS. + */ static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize) { - if (ssize == MMU_SEGSIZE_256M) - return vsid_scramble(ea >> SID_SHIFT, 256M); - return vsid_scramble(ea >> SID_SHIFT_1T, 1T); + unsigned long proto_vsid; + /* + * We need to make sure proto_vsid for the kernel is + * >= 2^(CONTEXT_BITS + USER_ESID_BITS[_1T]) + */ + if (ssize == MMU_SEGSIZE_256M) { + proto_vsid = ea >> SID_SHIFT; + proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS)); + return vsid_scramble(proto_vsid, 256M); + } + proto_vsid = ea >> SID_SHIFT_1T; + proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS_1T)); + return vsid_scramble(proto_vsid, 1T); } /* Returns the segment size indicator for a user address */ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index e8a26db2e8f3..5e38eedea218 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -146,6 +146,15 @@ extern void setup_initial_memory_limit(phys_addr_t first_memblock_base, extern u64 ppc64_rma_size; #endif /* CONFIG_PPC64 */ +struct mm_struct; +#ifdef CONFIG_DEBUG_VM +extern void assert_pte_locked(struct mm_struct *mm, unsigned long addr); +#else /* CONFIG_DEBUG_VM */ +static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr) +{ +} +#endif /* !CONFIG_DEBUG_VM */ + #endif /* !__ASSEMBLY__ */ /* The kernel use the constants below to index in the page sizes array. diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h index 1f41382eda38..0acc7c7c28d1 100644 --- a/arch/powerpc/include/asm/mpc52xx.h +++ b/arch/powerpc/include/asm/mpc52xx.h @@ -307,6 +307,7 @@ struct mpc52xx_lpbfifo_request { size_t size; size_t pos; /* current position of transfer */ int flags; + int defer_xfer_start; /* What to do when finished */ void (*callback)(struct mpc52xx_lpbfifo_request *); @@ -323,6 +324,7 @@ struct mpc52xx_lpbfifo_request { extern int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req); extern void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req); extern void mpc52xx_lpbfifo_poll(void); +extern int mpc52xx_lpbfifo_start_xfer(struct mpc52xx_lpbfifo_request *req); /* mpc52xx_pic.c */ extern void mpc52xx_init_irq(void); diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index c9f698a994be..c0f9ef90f0b8 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -63,6 +63,7 @@ */ #define MPIC_TIMER_BASE 0x01100 #define MPIC_TIMER_STRIDE 0x40 +#define MPIC_TIMER_GROUP_STRIDE 0x1000 #define MPIC_TIMER_CURRENT_CNT 0x00000 #define MPIC_TIMER_BASE_CNT 0x00010 @@ -110,10 +111,16 @@ #define MPIC_VECPRI_SENSE_MASK 0x00400000 #define MPIC_IRQ_DESTINATION 0x00010 +#define MPIC_FSL_BRR1 0x00000 +#define MPIC_FSL_BRR1_VER 0x0000ffff + #define MPIC_MAX_IRQ_SOURCES 2048 #define MPIC_MAX_CPUS 32 #define MPIC_MAX_ISU 32 +#define MPIC_MAX_ERR 32 +#define MPIC_FSL_ERR_INT 16 + /* * Tsi108 implementation of MPIC has many differences from the original one */ @@ -266,6 +273,7 @@ struct mpic struct irq_chip hc_ipi; #endif struct irq_chip hc_tm; + struct irq_chip hc_err; const char *name; /* Flags */ unsigned int flags; @@ -279,6 +287,8 @@ struct mpic /* vector numbers used for internal sources (ipi/timers) */ unsigned int ipi_vecs[4]; unsigned int timer_vecs[8]; + /* vector numbers used for FSL MPIC error interrupts */ + unsigned int err_int_vecs[MPIC_MAX_ERR]; /* Spurious vector to program into unused sources */ unsigned int spurious_vec; @@ -296,11 +306,15 @@ struct mpic phys_addr_t paddr; /* The various ioremap'ed bases */ + struct mpic_reg_bank thiscpuregs; struct mpic_reg_bank gregs; struct mpic_reg_bank tmregs; struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS]; struct mpic_reg_bank isus[MPIC_MAX_ISU]; + /* ioremap'ed base for error interrupt registers */ + u32 __iomem *err_regs; + /* Protected sources */ unsigned long *protected; @@ -365,6 +379,11 @@ struct mpic #define MPIC_NO_RESET 0x00004000 /* Freescale MPIC (compatible includes "fsl,mpic") */ #define MPIC_FSL 0x00008000 +/* Freescale MPIC supports EIMR (error interrupt mask register). + * This flag is set for MPIC version >= 4.1 (version determined + * from the BRR1 register). +*/ +#define MPIC_FSL_HAS_EIMR 0x00010000 /* MPIC HW modification ID */ #define MPIC_REGSET_MASK 0xf0000000 diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index daf813fea91f..e9e7a6999bb8 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h @@ -100,7 +100,7 @@ struct paca_struct { /* SLB related definitions */ u16 vmalloc_sllp; u16 slb_cache_ptr; - u16 slb_cache[SLB_CACHE_ENTRIES]; + u32 slb_cache[SLB_CACHE_ENTRIES]; #endif /* CONFIG_PPC_STD_MMU_64 */ #ifdef CONFIG_PPC_BOOK3E @@ -136,6 +136,7 @@ struct paca_struct { u8 io_sync; /* writel() needs spin_unlock sync */ u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ u8 nap_state_lost; /* NV GPR values lost in power7_idle */ + u64 sprg3; /* Saved user-visible sprg */ #ifdef CONFIG_PPC_POWERNV /* Pointer to OPAL machine check event structure set by the diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index fed85e6290e1..cd915d6b093d 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h @@ -78,11 +78,19 @@ extern u64 ppc64_pft_size; #define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT) #define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT) +/* + * 1 bit per slice and we have one slice per 1TB + * Right now we support only 64TB. + * IF we change this we will have to change the type + * of high_slices + */ +#define SLICE_MASK_SIZE 8 + #ifndef __ASSEMBLY__ struct slice_mask { u16 low_slices; - u16 high_slices; + u64 high_slices; }; struct mm_struct; diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 8cccbee61519..025a130729bc 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -182,14 +182,25 @@ static inline int pci_device_from_OF_node(struct device_node *np, #if defined(CONFIG_EEH) static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) { + /* + * For those OF nodes whose parent isn't PCI bridge, they + * don't have PCI_DN actually. So we have to skip them for + * any EEH operations. + */ + if (!dn || !PCI_DN(dn)) + return NULL; + return PCI_DN(dn)->edev; } +#else +#define of_node_to_eeh_dev(x) (NULL) #endif /** Find the bus corresponding to the indicated device node */ extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn); /** Remove all of the PCI devices under this bus */ +extern void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe); extern void pcibios_remove_pci_devices(struct pci_bus *bus); /** Discover new pci devices under this bus, and add them */ diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index 078019b5b353..9710be3a2d17 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -49,6 +49,7 @@ struct power_pmu { #define PPMU_ALT_SIPR 2 /* uses alternate posn for SIPR/HV */ #define PPMU_NO_SIPR 4 /* no SIPR/HV in MMCRA at all */ #define PPMU_NO_CONT_SAMPLING 8 /* no continuous sampling */ +#define PPMU_SIAR_VALID 16 /* Processor has SIAR Valid bit */ /* * Values for flags to get_alternatives() diff --git a/arch/powerpc/include/asm/pgtable-ppc64-4k.h b/arch/powerpc/include/asm/pgtable-ppc64-4k.h index 6eefdcffa359..12798c9d4b4b 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64-4k.h +++ b/arch/powerpc/include/asm/pgtable-ppc64-4k.h @@ -7,7 +7,7 @@ */ #define PTE_INDEX_SIZE 9 #define PMD_INDEX_SIZE 7 -#define PUD_INDEX_SIZE 7 +#define PUD_INDEX_SIZE 9 #define PGD_INDEX_SIZE 9 #ifndef __ASSEMBLY__ @@ -19,7 +19,7 @@ #define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) #define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) -#define PTRS_PER_PUD (1 << PMD_INDEX_SIZE) +#define PTRS_PER_PUD (1 << PUD_INDEX_SIZE) #define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) /* PMD_SHIFT determines what a second-level page table entry can map */ diff --git a/arch/powerpc/include/asm/pgtable-ppc64-64k.h b/arch/powerpc/include/asm/pgtable-ppc64-64k.h index 90533ddcd703..be4e2878fbc0 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64-64k.h +++ b/arch/powerpc/include/asm/pgtable-ppc64-64k.h @@ -7,7 +7,7 @@ #define PTE_INDEX_SIZE 12 #define PMD_INDEX_SIZE 12 #define PUD_INDEX_SIZE 0 -#define PGD_INDEX_SIZE 4 +#define PGD_INDEX_SIZE 6 #ifndef __ASSEMBLY__ #define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE) diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index c4205616dfb5..0182c203e411 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -21,17 +21,6 @@ #define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE) -/* Some sanity checking */ -#if TASK_SIZE_USER64 > PGTABLE_RANGE -#error TASK_SIZE_USER64 exceeds pagetable range -#endif - -#ifdef CONFIG_PPC_STD_MMU_64 -#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT)) -#error TASK_SIZE_USER64 exceeds user VSID range -#endif -#endif - /* * Define the address range of the kernel non-linear virtual area */ @@ -41,7 +30,7 @@ #else #define KERN_VIRT_START ASM_CONST(0xD000000000000000) #endif -#define KERN_VIRT_SIZE PGTABLE_RANGE +#define KERN_VIRT_SIZE ASM_CONST(0x0000100000000000) /* * The vmalloc space starts at the beginning of that region, and @@ -117,9 +106,6 @@ #ifndef __ASSEMBLY__ -#include <linux/stddef.h> -#include <asm/tlbflush.h> - /* * This is the default implementation of various PTE accessors, it's * used in all cases except Book3S with 64K pages where we have a @@ -198,7 +184,8 @@ /* to find an entry in a kernel page-table-directory */ /* This now only contains the vmalloc pages */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) - +extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, unsigned long pte, int huge); /* Atomic PTE updates */ static inline unsigned long pte_update(struct mm_struct *mm, diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 2e0e4110f7ae..a9cbd3ba5c33 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -9,14 +9,6 @@ struct mm_struct; -#ifdef CONFIG_DEBUG_VM -extern void assert_pte_locked(struct mm_struct *mm, unsigned long addr); -#else /* CONFIG_DEBUG_VM */ -static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr) -{ -} -#endif /* !CONFIG_DEBUG_VM */ - #endif /* !__ASSEMBLY__ */ #if defined(CONFIG_PPC64) @@ -27,6 +19,8 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr) #ifndef __ASSEMBLY__ +#include <asm/tlbflush.h> + /* Generic accessors to PTE bits */ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 4c25319f2fbc..5f73ce63fcae 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -126,6 +126,7 @@ #define PPC_INST_TLBIVAX 0x7c000624 #define PPC_INST_TLBSRX_DOT 0x7c0006a5 #define PPC_INST_XXLOR 0xf0000510 +#define PPC_INST_XVCPSGNDP 0xf0000780 #define PPC_INST_NAP 0x4c000364 #define PPC_INST_SLEEP 0x4c0003a4 @@ -277,6 +278,8 @@ VSX_XX1((s), a, b)) #define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \ VSX_XX3((t), a, b)) +#define XVCPSGNDP(t, a, b) stringify_in_c(.long (PPC_INST_XVCPSGNDP | \ + VSX_XX3((t), (a), (b)))) #define PPC_NAP stringify_in_c(.long PPC_INST_NAP) #define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP) diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 80fa704d410f..ed57fa7920c8 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -47,19 +47,17 @@ extern int rtas_setup_phb(struct pci_controller *phb); #ifdef CONFIG_EEH -void pci_addr_cache_build(void); -void pci_addr_cache_insert_device(struct pci_dev *dev); -void pci_addr_cache_remove_device(struct pci_dev *dev); -struct pci_dev *pci_addr_cache_get_device(unsigned long addr); -void eeh_slot_error_detail(struct eeh_dev *edev, int severity); -int eeh_pci_enable(struct eeh_dev *edev, int function); -int eeh_reset_pe(struct eeh_dev *); -void eeh_restore_bars(struct eeh_dev *); +void eeh_addr_cache_insert_dev(struct pci_dev *dev); +void eeh_addr_cache_rmv_dev(struct pci_dev *dev); +struct eeh_dev *eeh_addr_cache_get_dev(unsigned long addr); +void eeh_slot_error_detail(struct eeh_pe *pe, int severity); +int eeh_pci_enable(struct eeh_pe *pe, int function); +int eeh_reset_pe(struct eeh_pe *); +void eeh_save_bars(struct eeh_dev *edev); int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); -void eeh_mark_slot(struct device_node *dn, int mode_flag); -void eeh_clear_slot(struct device_node *dn, int mode_flag); -struct device_node *eeh_find_device_pe(struct device_node *dn); +void eeh_pe_state_mark(struct eeh_pe *pe, int state); +void eeh_pe_state_clear(struct eeh_pe *pe, int state); void eeh_sysfs_add_device(struct pci_dev *pdev); void eeh_sysfs_remove_device(struct pci_dev *pdev); diff --git a/arch/powerpc/include/asm/probes.h b/arch/powerpc/include/asm/probes.h new file mode 100644 index 000000000000..5f1e15b68704 --- /dev/null +++ b/arch/powerpc/include/asm/probes.h @@ -0,0 +1,42 @@ +#ifndef _ASM_POWERPC_PROBES_H +#define _ASM_POWERPC_PROBES_H +#ifdef __KERNEL__ +/* + * Definitions common to probes files + * + * 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. + * + * Copyright IBM Corporation, 2012 + */ +#include <linux/types.h> + +typedef u32 ppc_opcode_t; +#define BREAKPOINT_INSTRUCTION 0x7fe00008 /* trap */ + +/* Trap definitions per ISA */ +#define IS_TW(instr) (((instr) & 0xfc0007fe) == 0x7c000008) +#define IS_TD(instr) (((instr) & 0xfc0007fe) == 0x7c000088) +#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) +#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) + +#ifdef CONFIG_PPC64 +#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ + IS_TWI(instr) || IS_TDI(instr)) +#else +#define is_trap(instr) (IS_TW(instr) || IS_TWI(instr)) +#endif /* CONFIG_PPC64 */ + +#endif /* __KERNEL__ */ +#endif /* _ASM_POWERPC_PROBES_H */ diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 54b73a28c205..9dc5cd1fde1a 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -97,8 +97,8 @@ extern struct task_struct *last_task_used_spe; #endif #ifdef CONFIG_PPC64 -/* 64-bit user address space is 44-bits (16TB user VM) */ -#define TASK_SIZE_USER64 (0x0000100000000000UL) +/* 64-bit user address space is 46-bits (64TB user VM) */ +#define TASK_SIZE_USER64 (0x0000400000000000UL) /* * 32-bit user address space is 4GB - 1 page @@ -219,6 +219,8 @@ struct thread_struct { #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif unsigned long dabr; /* Data address breakpoint register */ + unsigned long dabrx; /* ... extension */ + unsigned long trap_nr; /* last trap # on this thread */ #ifdef CONFIG_ALTIVEC /* Complete AltiVec register set */ vector128 vr[32] __attribute__((aligned(16))); diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h index 59247e816ac5..eedf427c9124 100644 --- a/arch/powerpc/include/asm/pte-hash64-64k.h +++ b/arch/powerpc/include/asm/pte-hash64-64k.h @@ -58,14 +58,16 @@ /* Trick: we set __end to va + 64k, which happens works for * a 16M page as well as we want only one iteration */ -#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \ - do { \ - unsigned long __end = va + PAGE_SIZE; \ - unsigned __split = (psize == MMU_PAGE_4K || \ - psize == MMU_PAGE_64K_AP); \ - shift = mmu_psize_defs[psize].shift; \ - for (index = 0; va < __end; index++, va += (1L << shift)) { \ - if (!__split || __rpte_sub_valid(rpte, index)) do { \ +#define pte_iterate_hashed_subpages(rpte, psize, vpn, index, shift) \ + do { \ + unsigned long __end = vpn + (1UL << (PAGE_SHIFT - VPN_SHIFT)); \ + unsigned __split = (psize == MMU_PAGE_4K || \ + psize == MMU_PAGE_64K_AP); \ + shift = mmu_psize_defs[psize].shift; \ + for (index = 0; vpn < __end; index++, \ + vpn += (1L << (shift - VPN_SHIFT))) { \ + if (!__split || __rpte_sub_valid(rpte, index)) \ + do { #define pte_iterate_hashed_end() } while(0); } } while(0) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 638608677e2a..d24c14163966 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -208,6 +208,9 @@ #define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ #define DABRX_USER (1UL << 0) #define DABRX_KERNEL (1UL << 1) +#define DABRX_HYP (1UL << 2) +#define DABRX_BTI (1UL << 3) +#define DABRX_ALL (DABRX_BTI | DABRX_HYP | DABRX_KERNEL | DABRX_USER) #define SPRN_DAR 0x013 /* Data Address Register */ #define SPRN_DBCR 0x136 /* e300 Data Breakpoint Control Reg */ #define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */ @@ -521,6 +524,7 @@ #define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */ #define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */ +#define HSRR1_DENORM 0x00100000 /* Denorm exception */ #define SPRN_TBCTL 0x35f /* PA6T Timebase control register */ #define TBCTL_FREEZE 0x0000000000000000ull /* Freeze all tbs */ @@ -602,6 +606,10 @@ #define POWER6_MMCRA_SIPR 0x0000020000000000ULL #define POWER6_MMCRA_THRM 0x00000020UL #define POWER6_MMCRA_OTHER 0x0000000EUL + +#define POWER7P_MMCRA_SIAR_VALID 0x10000000 /* P7+ SIAR contents valid */ +#define POWER7P_MMCRA_SDAR_VALID 0x08000000 /* P7+ SDAR contents valid */ + #define SPRN_PMC1 787 #define SPRN_PMC2 788 #define SPRN_PMC3 789 @@ -761,7 +769,8 @@ * 64-bit embedded * - SPRG0 generic exception scratch * - SPRG2 TLB exception stack - * - SPRG3 CPU and NUMA node for VDSO getcpu (user visible) + * - SPRG3 critical exception scratch and + * CPU and NUMA node for VDSO getcpu (user visible) * - SPRG4 unused (user visible) * - SPRG6 TLB miss scratch (user visible, sorry !) * - SPRG7 critical exception scratch @@ -858,11 +867,12 @@ #ifdef CONFIG_PPC_BOOK3E_64 #define SPRN_SPRG_MC_SCRATCH SPRN_SPRG8 -#define SPRN_SPRG_CRIT_SCRATCH SPRN_SPRG7 +#define SPRN_SPRG_CRIT_SCRATCH SPRN_SPRG3 #define SPRN_SPRG_DBG_SCRATCH SPRN_SPRG9 #define SPRN_SPRG_TLB_EXFRAME SPRN_SPRG2 #define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6 #define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0 +#define SPRN_SPRG_GDBELL_SCRATCH SPRN_SPRG_GEN_SCRATCH #define SET_PACA(rX) mtspr SPRN_SPRG_PACA,rX #define GET_PACA(rX) mfspr rX,SPRN_SPRG_PACA @@ -937,7 +947,7 @@ #define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ #define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ -#define __is_processor(pv) (PVR_VER(mfspr(SPRN_PVR)) == (pv)) +#define pvr_version_is(pvr) (PVR_VER(mfspr(SPRN_PVR)) == (pvr)) /* * IBM has further subdivided the standard PowerPC 16-bit version and @@ -1002,25 +1012,25 @@ #define PVR_476_ISS 0x00052000 /* 64-bit processors */ -/* XXX the prefix should be PVR_, we'll do a global sweep to fix it one day */ -#define PV_NORTHSTAR 0x0033 -#define PV_PULSAR 0x0034 -#define PV_POWER4 0x0035 -#define PV_ICESTAR 0x0036 -#define PV_SSTAR 0x0037 -#define PV_POWER4p 0x0038 -#define PV_970 0x0039 -#define PV_POWER5 0x003A -#define PV_POWER5p 0x003B -#define PV_970FX 0x003C -#define PV_POWER6 0x003E -#define PV_POWER7 0x003F -#define PV_630 0x0040 -#define PV_630p 0x0041 -#define PV_970MP 0x0044 -#define PV_970GX 0x0045 -#define PV_BE 0x0070 -#define PV_PA6T 0x0090 +#define PVR_NORTHSTAR 0x0033 +#define PVR_PULSAR 0x0034 +#define PVR_POWER4 0x0035 +#define PVR_ICESTAR 0x0036 +#define PVR_SSTAR 0x0037 +#define PVR_POWER4p 0x0038 +#define PVR_970 0x0039 +#define PVR_POWER5 0x003A +#define PVR_POWER5p 0x003B +#define PVR_970FX 0x003C +#define PVR_POWER6 0x003E +#define PVR_POWER7 0x003F +#define PVR_630 0x0040 +#define PVR_630p 0x0041 +#define PVR_970MP 0x0044 +#define PVR_970GX 0x0045 +#define PVR_POWER7p 0x004A +#define PVR_BE 0x0070 +#define PVR_PA6T 0x0090 /* Macros for setting and retrieving special purpose registers */ #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index d084ce195fc3..8b9a306260b2 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -9,7 +9,7 @@ extern void ppc_printk_progress(char *s, unsigned short hex); extern unsigned int rtas_data; extern int mem_init_done; /* set on boot once kmalloc can be called */ extern int init_bootmem_done; /* set once bootmem is available */ -extern phys_addr_t memory_limit; +extern unsigned long long memory_limit; extern unsigned long klimit; extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); diff --git a/arch/powerpc/include/asm/siginfo.h b/arch/powerpc/include/asm/siginfo.h index 49495b0534ed..ccce3ef5cd86 100644 --- a/arch/powerpc/include/asm/siginfo.h +++ b/arch/powerpc/include/asm/siginfo.h @@ -10,7 +10,6 @@ #ifdef __powerpc64__ # define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -# define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) #endif #include <asm-generic/siginfo.h> diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index ebc24dc5b1a1..e807e9d8e3f7 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -65,6 +65,7 @@ int generic_cpu_disable(void); void generic_cpu_die(unsigned int cpu); void generic_mach_cpu_die(void); void generic_set_cpu_dead(unsigned int cpu); +void generic_set_cpu_up(unsigned int cpu); int generic_check_cpu_restart(unsigned int cpu); #endif @@ -190,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop; extern unsigned long __secondary_hold_acknowledge; extern char __secondary_hold; +extern void __early_start(void); #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 0c5fa3145615..f6fc0ee813d7 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -10,8 +10,8 @@ */ #define SECTION_SIZE_BITS 24 -#define MAX_PHYSADDR_BITS 44 -#define MAX_PHYSMEM_BITS 44 +#define MAX_PHYSADDR_BITS 46 +#define MAX_PHYSMEM_BITS 46 #endif /* CONFIG_SPARSEMEM */ diff --git a/arch/powerpc/include/asm/swiotlb.h b/arch/powerpc/include/asm/swiotlb.h index 8979d4cd3d70..de99d6e29430 100644 --- a/arch/powerpc/include/asm/swiotlb.h +++ b/arch/powerpc/include/asm/swiotlb.h @@ -22,4 +22,10 @@ int __init swiotlb_setup_bus_notifier(void); extern void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev); +#ifdef CONFIG_SWIOTLB +void swiotlb_detect_4g(void); +#else +static inline void swiotlb_detect_4g(void) {} +#endif + #endif /* __ASM_SWIOTLB_H */ diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index faf93529cbf0..8ceea14d6fe4 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -102,7 +102,10 @@ static inline struct thread_info *current_thread_info(void) #define TIF_RESTOREALL 11 /* Restore all regs (implies NOERROR) */ #define TIF_NOERROR 12 /* Force successful syscall return */ #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ +#define TIF_UPROBE 14 /* breakpointed or single-stepping */ #define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */ +#define TIF_EMULATE_STACK_STORE 16 /* Is an instruction emulation + for stack store? */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) @@ -118,12 +121,14 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_RESTOREALL (1<<TIF_RESTOREALL) #define _TIF_NOERROR (1<<TIF_NOERROR) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) +#define _TIF_UPROBE (1<<TIF_UPROBE) #define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT) +#define _TIF_EMULATE_STACK_STORE (1<<TIF_EMULATE_STACK_STORE) #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT) #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ - _TIF_NOTIFY_RESUME) + _TIF_NOTIFY_RESUME | _TIF_UPROBE) #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR) /* Bits in local_flags */ diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h index 81143fcbd113..61a59271665b 100644 --- a/arch/powerpc/include/asm/tlbflush.h +++ b/arch/powerpc/include/asm/tlbflush.h @@ -95,7 +95,7 @@ struct ppc64_tlb_batch { unsigned long index; struct mm_struct *mm; real_pte_t pte[PPC64_TLB_BATCH_NR]; - unsigned long vaddr[PPC64_TLB_BATCH_NR]; + unsigned long vpn[PPC64_TLB_BATCH_NR]; unsigned int psize; int ssize; }; @@ -103,9 +103,6 @@ DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch); -extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, unsigned long pte, int huge); - #define __HAVE_ARCH_ENTER_LAZY_MMU_MODE static inline void arch_enter_lazy_mmu_mode(void) @@ -127,7 +124,7 @@ static inline void arch_leave_lazy_mmu_mode(void) #define arch_flush_lazy_mmu_mode() do {} while (0) -extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize, +extern void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, int local); extern void flush_hash_range(unsigned long number, int local); diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 17bb40cad5bf..4db49590acf5 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -98,11 +98,6 @@ struct exception_table_entry { * PowerPC, we can just do these as direct assignments. (Of course, the * exception handling means that it's no longer "just"...) * - * The "user64" versions of the user access functions are versions that - * allow access of 64-bit data. The "get_user" functions do not - * properly handle 64-bit data because the value gets down cast to a long. - * The "put_user" functions already handle 64-bit data properly but we add - * "user64" versions for completeness */ #define get_user(x, ptr) \ __get_user_check((x), (ptr), sizeof(*(ptr))) @@ -114,12 +109,6 @@ struct exception_table_entry { #define __put_user(x, ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) -#ifndef __powerpc64__ -#define __get_user64(x, ptr) \ - __get_user64_nocheck((x), (ptr), sizeof(*(ptr))) -#define __put_user64(x, ptr) __put_user(x, ptr) -#endif - #define __get_user_inatomic(x, ptr) \ __get_user_nosleep((x), (ptr), sizeof(*(ptr))) #define __put_user_inatomic(x, ptr) \ diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h new file mode 100644 index 000000000000..b532060d0916 --- /dev/null +++ b/arch/powerpc/include/asm/uprobes.h @@ -0,0 +1,54 @@ +#ifndef _ASM_UPROBES_H +#define _ASM_UPROBES_H +/* + * User-space Probes (UProbes) for powerpc + * + * 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. + * + * Copyright IBM Corporation, 2007-2012 + * + * Adapted from the x86 port by Ananth N Mavinakayanahalli <ananth@in.ibm.com> + */ + +#include <linux/notifier.h> +#include <asm/probes.h> + +typedef ppc_opcode_t uprobe_opcode_t; + +#define MAX_UINSN_BYTES 4 +#define UPROBE_XOL_SLOT_BYTES (MAX_UINSN_BYTES) + +/* The following alias is needed for reference from arch-agnostic code */ +#define UPROBE_SWBP_INSN BREAKPOINT_INSTRUCTION +#define UPROBE_SWBP_INSN_SIZE 4 /* swbp insn size in bytes */ + +struct arch_uprobe { + union { + u8 insn[MAX_UINSN_BYTES]; + u32 ainsn; + }; +}; + +struct arch_uprobe_task { + unsigned long saved_trap_nr; +}; + +extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); +extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); +extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); +extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); +extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); +extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); +#endif /* _ASM_UPROBES_H */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index bb282dd81612..cde12f8a4ebc 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_UPROBES) += uprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index e8995727b1c1..7523539cfe9f 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -206,6 +206,7 @@ int main(void) DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); DEFINE(PACA_NAPSTATELOST, offsetof(struct paca_struct, nap_state_lost)); + DEFINE(PACA_SPRG3, offsetof(struct paca_struct, sprg3)); #endif /* CONFIG_PPC64 */ /* RTAS */ @@ -534,7 +535,6 @@ int main(void) HSTATE_FIELD(HSTATE_VMHANDLER, vmhandler); HSTATE_FIELD(HSTATE_SCRATCH0, scratch0); HSTATE_FIELD(HSTATE_SCRATCH1, scratch1); - HSTATE_FIELD(HSTATE_SPRG3, sprg3); HSTATE_FIELD(HSTATE_IN_GUEST, in_guest); HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5); HSTATE_FIELD(HSTATE_NAPPING, napping); diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S index 69fdd2322a66..dcd881937f7a 100644 --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S @@ -16,6 +16,8 @@ #include <asm/processor.h> #include <asm/cputable.h> #include <asm/ppc_asm.h> +#include <asm/mmu-book3e.h> +#include <asm/asm-offsets.h> _GLOBAL(__e500_icache_setup) mfspr r0, SPRN_L1CSR1 @@ -73,27 +75,81 @@ _GLOBAL(__setup_cpu_e500v2) mtlr r4 blr _GLOBAL(__setup_cpu_e500mc) - mr r5, r4 - mflr r4 +_GLOBAL(__setup_cpu_e5500) + mflr r5 bl __e500_icache_setup bl __e500_dcache_setup bl __setup_e500mc_ivors - mtlr r4 + /* + * We only want to touch IVOR38-41 if we're running on hardware + * that supports category E.HV. The architectural way to determine + * this is MMUCFG[LPIDSIZE]. + */ + mfspr r3, SPRN_MMUCFG + rlwinm. r3, r3, 0, MMUCFG_LPIDSIZE + beq 1f + bl __setup_ehv_ivors + b 2f +1: + lwz r3, CPU_SPEC_FEATURES(r4) + /* We need this check as cpu_setup is also called for + * the secondary cores. So, if we have already cleared + * the feature on the primary core, avoid doing it on the + * secondary core. + */ + andis. r6, r3, CPU_FTR_EMB_HV@h + beq 2f + rlwinm r3, r3, 0, ~CPU_FTR_EMB_HV + stw r3, CPU_SPEC_FEATURES(r4) +2: + mtlr r5 blr #endif -/* Right now, restore and setup are the same thing */ + +#ifdef CONFIG_PPC_BOOK3E_64 _GLOBAL(__restore_cpu_e5500) -_GLOBAL(__setup_cpu_e5500) mflr r4 bl __e500_icache_setup bl __e500_dcache_setup -#ifdef CONFIG_PPC_BOOK3E_64 bl .__setup_base_ivors bl .setup_perfmon_ivor bl .setup_doorbell_ivors + /* + * We only want to touch IVOR38-41 if we're running on hardware + * that supports category E.HV. The architectural way to determine + * this is MMUCFG[LPIDSIZE]. + */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beq 1f bl .setup_ehv_ivors -#else - bl __setup_e500mc_ivors -#endif +1: mtlr r4 blr + +_GLOBAL(__setup_cpu_e5500) + mflr r5 + bl __e500_icache_setup + bl __e500_dcache_setup + bl .__setup_base_ivors + bl .setup_perfmon_ivor + bl .setup_doorbell_ivors + /* + * We only want to touch IVOR38-41 if we're running on hardware + * that supports category E.HV. The architectural way to determine + * this is MMUCFG[LPIDSIZE]. + */ + mfspr r10,SPRN_MMUCFG + rlwinm. r10,r10,0,MMUCFG_LPIDSIZE + beq 1f + bl .setup_ehv_ivors + b 2f +1: + ld r10,CPU_SPEC_FEATURES(r4) + LOAD_REG_IMMEDIATE(r9,CPU_FTR_EMB_HV) + andc r10,r10,r9 + std r10,CPU_SPEC_FEATURES(r4) +2: + mtlr r5 + blr +#endif diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 455faa389876..0514c21f138b 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -2016,7 +2016,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc/e500mc", .oprofile_type = PPC_OPROFILE_FSL_EMB, .cpu_setup = __setup_cpu_e5500, +#ifndef CONFIG_PPC32 .cpu_restore = __restore_cpu_e5500, +#endif .machine_check = machine_check_e500mc, .platform = "ppce5500", }, @@ -2034,7 +2036,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .oprofile_cpu_type = "ppc/e6500", .oprofile_type = PPC_OPROFILE_FSL_EMB, .cpu_setup = __setup_cpu_e5500, +#ifndef CONFIG_PPC32 .cpu_restore = __restore_cpu_e5500, +#endif .machine_check = machine_check_e500mc, .platform = "ppce6500", }, diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index 46943651da23..bd1a2aba599f 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -12,6 +12,7 @@ */ #include <linux/dma-mapping.h> +#include <linux/memblock.h> #include <linux/pfn.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -20,7 +21,6 @@ #include <asm/machdep.h> #include <asm/swiotlb.h> #include <asm/dma.h> -#include <asm/abs_addr.h> unsigned int ppc_swiotlb_enable; @@ -105,3 +105,23 @@ int __init swiotlb_setup_bus_notifier(void) &ppc_swiotlb_plat_bus_notifier); return 0; } + +void swiotlb_detect_4g(void) +{ + if ((memblock_end_of_DRAM() - 1) > 0xffffffff) + ppc_swiotlb_enable = 1; +} + +static int __init swiotlb_late_init(void) +{ + if (ppc_swiotlb_enable) { + swiotlb_print_info(); + set_pci_dma_ops(&swiotlb_dma_ops); + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + } else { + swiotlb_free(); + } + + return 0; +} +subsys_initcall(swiotlb_late_init); diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 355b9d84b0f8..8032b97ccdcb 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -14,7 +14,6 @@ #include <linux/pci.h> #include <asm/vio.h> #include <asm/bug.h> -#include <asm/abs_addr.h> #include <asm/machdep.h> /* @@ -50,7 +49,7 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size, return NULL; ret = page_address(page); memset(ret, 0, size); - *dma_handle = virt_to_abs(ret) + get_dma_offset(dev); + *dma_handle = __pa(ret) + get_dma_offset(dev); return ret; #endif diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index ead5016b02d0..af37528da49f 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -831,19 +831,56 @@ restore_user: bnel- load_dbcr0 #endif -#ifdef CONFIG_PREEMPT b restore /* N.B. the only way to get here is from the beq following ret_from_except. */ resume_kernel: - /* check current_thread_info->preempt_count */ + /* check current_thread_info, _TIF_EMULATE_STACK_STORE */ CURRENT_THREAD_INFO(r9, r1) + lwz r8,TI_FLAGS(r9) + andis. r8,r8,_TIF_EMULATE_STACK_STORE@h + beq+ 1f + + addi r8,r1,INT_FRAME_SIZE /* Get the kprobed function entry */ + + lwz r3,GPR1(r1) + subi r3,r3,INT_FRAME_SIZE /* dst: Allocate a trampoline exception frame */ + mr r4,r1 /* src: current exception frame */ + mr r1,r3 /* Reroute the trampoline frame to r1 */ + + /* Copy from the original to the trampoline. */ + li r5,INT_FRAME_SIZE/4 /* size: INT_FRAME_SIZE */ + li r6,0 /* start offset: 0 */ + mtctr r5 +2: lwzx r0,r6,r4 + stwx r0,r6,r3 + addi r6,r6,4 + bdnz 2b + + /* Do real store operation to complete stwu */ + lwz r5,GPR1(r1) + stw r8,0(r5) + + /* Clear _TIF_EMULATE_STACK_STORE flag */ + lis r11,_TIF_EMULATE_STACK_STORE@h + addi r5,r9,TI_FLAGS +0: lwarx r8,0,r5 + andc r8,r8,r11 +#ifdef CONFIG_IBM405_ERR77 + dcbt 0,r5 +#endif + stwcx. r8,0,r5 + bne- 0b +1: + +#ifdef CONFIG_PREEMPT + /* check current_thread_info->preempt_count */ lwz r0,TI_PREEMPT(r9) cmpwi 0,r0,0 /* if non-zero, just restore regs and return */ bne restore - lwz r0,TI_FLAGS(r9) - andi. r0,r0,_TIF_NEED_RESCHED + andi. r8,r8,_TIF_NEED_RESCHED beq+ restore + lwz r3,_MSR(r1) andi. r0,r3,MSR_EE /* interrupts off? */ beq restore /* don't schedule if so */ #ifdef CONFIG_TRACE_IRQFLAGS @@ -864,8 +901,6 @@ resume_kernel: */ bl trace_hardirqs_on #endif -#else -resume_kernel: #endif /* CONFIG_PREEMPT */ /* interrupts are hard-disabled at this point */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index b40e0b4815b3..0e931aaffca2 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -593,6 +593,41 @@ _GLOBAL(ret_from_except_lite) b .ret_from_except resume_kernel: + /* check current_thread_info, _TIF_EMULATE_STACK_STORE */ + CURRENT_THREAD_INFO(r9, r1) + ld r8,TI_FLAGS(r9) + andis. r8,r8,_TIF_EMULATE_STACK_STORE@h + beq+ 1f + + addi r8,r1,INT_FRAME_SIZE /* Get the kprobed function entry */ + + lwz r3,GPR1(r1) + subi r3,r3,INT_FRAME_SIZE /* dst: Allocate a trampoline exception frame */ + mr r4,r1 /* src: current exception frame */ + mr r1,r3 /* Reroute the trampoline frame to r1 */ + + /* Copy from the original to the trampoline. */ + li r5,INT_FRAME_SIZE/8 /* size: INT_FRAME_SIZE */ + li r6,0 /* start offset: 0 */ + mtctr r5 +2: ldx r0,r6,r4 + stdx r0,r6,r3 + addi r6,r6,8 + bdnz 2b + + /* Do real store operation to complete stwu */ + lwz r5,GPR1(r1) + std r8,0(r5) + + /* Clear _TIF_EMULATE_STACK_STORE flag */ + lis r11,_TIF_EMULATE_STACK_STORE@h + addi r5,r9,TI_FLAGS + ldarx r4,0,r5 + andc r4,r4,r11 + stdcx. r4,0,r5 + bne- 0b +1: + #ifdef CONFIG_PREEMPT /* Check if we need to preempt */ andi. r0,r4,_TIF_NEED_RESCHED diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 98be7f0cd227..4684e33a26c3 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -25,6 +25,8 @@ #include <asm/ppc-opcode.h> #include <asm/mmu.h> #include <asm/hw_irq.h> +#include <asm/kvm_asm.h> +#include <asm/kvm_booke_hv_asm.h> /* XXX This will ultimately add space for a special exception save * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... @@ -35,16 +37,18 @@ #define SPECIAL_EXC_FRAME_SIZE INT_FRAME_SIZE /* Exception prolog code for all exceptions */ -#define EXCEPTION_PROLOG(n, type, addition) \ +#define EXCEPTION_PROLOG(n, intnum, type, addition) \ mtspr SPRN_SPRG_##type##_SCRATCH,r13; /* get spare registers */ \ mfspr r13,SPRN_SPRG_PACA; /* get PACA */ \ std r10,PACA_EX##type+EX_R10(r13); \ std r11,PACA_EX##type+EX_R11(r13); \ + PROLOG_STORE_RESTORE_SCRATCH_##type; \ mfcr r10; /* save CR */ \ + mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \ + DO_KVM intnum,SPRN_##type##_SRR1; /* KVM hook */ \ + stw r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \ addition; /* additional code for that exc. */ \ std r1,PACA_EX##type+EX_R1(r13); /* save old r1 in the PACA */ \ - stw r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \ - mfspr r11,SPRN_##type##_SRR1;/* what are we coming from */ \ type##_SET_KSTACK; /* get special stack if necessary */\ andi. r10,r11,MSR_PR; /* save stack pointer */ \ beq 1f; /* branch around if supervisor */ \ @@ -59,6 +63,10 @@ #define SPRN_GEN_SRR0 SPRN_SRR0 #define SPRN_GEN_SRR1 SPRN_SRR1 +#define GDBELL_SET_KSTACK GEN_SET_KSTACK +#define SPRN_GDBELL_SRR0 SPRN_GSRR0 +#define SPRN_GDBELL_SRR1 SPRN_GSRR1 + #define CRIT_SET_KSTACK \ ld r1,PACA_CRIT_STACK(r13); \ subi r1,r1,SPECIAL_EXC_FRAME_SIZE; @@ -77,29 +85,46 @@ #define SPRN_MC_SRR0 SPRN_MCSRR0 #define SPRN_MC_SRR1 SPRN_MCSRR1 -#define NORMAL_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, GEN, addition##_GEN(n)) +#define NORMAL_EXCEPTION_PROLOG(n, intnum, addition) \ + EXCEPTION_PROLOG(n, intnum, GEN, addition##_GEN(n)) + +#define CRIT_EXCEPTION_PROLOG(n, intnum, addition) \ + EXCEPTION_PROLOG(n, intnum, CRIT, addition##_CRIT(n)) -#define CRIT_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n)) +#define DBG_EXCEPTION_PROLOG(n, intnum, addition) \ + EXCEPTION_PROLOG(n, intnum, DBG, addition##_DBG(n)) -#define DBG_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, DBG, addition##_DBG(n)) +#define MC_EXCEPTION_PROLOG(n, intnum, addition) \ + EXCEPTION_PROLOG(n, intnum, MC, addition##_MC(n)) -#define MC_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, MC, addition##_MC(n)) +#define GDBELL_EXCEPTION_PROLOG(n, intnum, addition) \ + EXCEPTION_PROLOG(n, intnum, GDBELL, addition##_GDBELL(n)) +/* + * Store user-visible scratch in PACA exception slots and restore proper value + */ +#define PROLOG_STORE_RESTORE_SCRATCH_GEN +#define PROLOG_STORE_RESTORE_SCRATCH_GDBELL +#define PROLOG_STORE_RESTORE_SCRATCH_DBG +#define PROLOG_STORE_RESTORE_SCRATCH_MC + +#define PROLOG_STORE_RESTORE_SCRATCH_CRIT \ + mfspr r10,SPRN_SPRG_CRIT_SCRATCH; /* get r13 */ \ + std r10,PACA_EXCRIT+EX_R13(r13); \ + ld r11,PACA_SPRG3(r13); \ + mtspr SPRN_SPRG_CRIT_SCRATCH,r11; /* Variants of the "addition" argument for the prolog */ #define PROLOG_ADDITION_NONE_GEN(n) +#define PROLOG_ADDITION_NONE_GDBELL(n) #define PROLOG_ADDITION_NONE_CRIT(n) #define PROLOG_ADDITION_NONE_DBG(n) #define PROLOG_ADDITION_NONE_MC(n) #define PROLOG_ADDITION_MASKABLE_GEN(n) \ - lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ - cmpwi cr0,r11,0; /* yes -> go out of line */ \ + lbz r10,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ + cmpwi cr0,r10,0; /* yes -> go out of line */ \ beq masked_interrupt_book3e_##n #define PROLOG_ADDITION_2REGS_GEN(n) \ @@ -233,9 +258,9 @@ exc_##n##_bad_stack: \ 1: -#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ +#define MASKABLE_EXCEPTION(trapnum, intnum, label, hdlr, ack) \ START_EXCEPTION(label); \ - NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ + NORMAL_EXCEPTION_PROLOG(trapnum, intnum, PROLOG_ADDITION_MASKABLE)\ EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \ ack(r8); \ CHECK_NAPPING(); \ @@ -286,7 +311,8 @@ interrupt_end_book3e: /* Critical Input Interrupt */ START_EXCEPTION(critical_input); - CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) + CRIT_EXCEPTION_PROLOG(0x100, BOOKE_INTERRUPT_CRITICAL, + PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); @@ -297,7 +323,8 @@ interrupt_end_book3e: /* Machine Check Interrupt */ START_EXCEPTION(machine_check); - CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE) + MC_EXCEPTION_PROLOG(0x200, BOOKE_INTERRUPT_MACHINE_CHECK, + PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE) // bl special_reg_save_mc // addi r3,r1,STACK_FRAME_OVERHEAD @@ -308,7 +335,8 @@ interrupt_end_book3e: /* Data Storage Interrupt */ START_EXCEPTION(data_storage) - NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS) + NORMAL_EXCEPTION_PROLOG(0x300, BOOKE_INTERRUPT_DATA_STORAGE, + PROLOG_ADDITION_2REGS) mfspr r14,SPRN_DEAR mfspr r15,SPRN_ESR EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE) @@ -316,18 +344,21 @@ interrupt_end_book3e: /* Instruction Storage Interrupt */ START_EXCEPTION(instruction_storage); - NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS) + NORMAL_EXCEPTION_PROLOG(0x400, BOOKE_INTERRUPT_INST_STORAGE, + PROLOG_ADDITION_2REGS) li r15,0 mr r14,r10 EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE) b storage_fault_common /* External Input Interrupt */ - MASKABLE_EXCEPTION(0x500, external_input, .do_IRQ, ACK_NONE) + MASKABLE_EXCEPTION(0x500, BOOKE_INTERRUPT_EXTERNAL, + external_input, .do_IRQ, ACK_NONE) /* Alignment */ START_EXCEPTION(alignment); - NORMAL_EXCEPTION_PROLOG(0x600, PROLOG_ADDITION_2REGS) + NORMAL_EXCEPTION_PROLOG(0x600, BOOKE_INTERRUPT_ALIGNMENT, + PROLOG_ADDITION_2REGS) mfspr r14,SPRN_DEAR mfspr r15,SPRN_ESR EXCEPTION_COMMON(0x600, PACA_EXGEN, INTS_KEEP) @@ -335,7 +366,8 @@ interrupt_end_book3e: /* Program Interrupt */ START_EXCEPTION(program); - NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG) + NORMAL_EXCEPTION_PROLOG(0x700, BOOKE_INTERRUPT_PROGRAM, + PROLOG_ADDITION_1REG) mfspr r14,SPRN_ESR EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE) std r14,_DSISR(r1) @@ -347,7 +379,8 @@ interrupt_end_book3e: /* Floating Point Unavailable Interrupt */ START_EXCEPTION(fp_unavailable); - NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE) + NORMAL_EXCEPTION_PROLOG(0x800, BOOKE_INTERRUPT_FP_UNAVAIL, + PROLOG_ADDITION_NONE) /* we can probably do a shorter exception entry for that one... */ EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP) ld r12,_MSR(r1) @@ -362,14 +395,17 @@ interrupt_end_book3e: b .ret_from_except /* Decrementer Interrupt */ - MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC) + MASKABLE_EXCEPTION(0x900, BOOKE_INTERRUPT_DECREMENTER, + decrementer, .timer_interrupt, ACK_DEC) /* Fixed Interval Timer Interrupt */ - MASKABLE_EXCEPTION(0x980, fixed_interval, .unknown_exception, ACK_FIT) + MASKABLE_EXCEPTION(0x980, BOOKE_INTERRUPT_FIT, + fixed_interval, .unknown_exception, ACK_FIT) /* Watchdog Timer Interrupt */ START_EXCEPTION(watchdog); - CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) + CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG, + PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); @@ -388,7 +424,8 @@ interrupt_end_book3e: /* Auxiliary Processor Unavailable Interrupt */ START_EXCEPTION(ap_unavailable); - NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) + NORMAL_EXCEPTION_PROLOG(0xf20, BOOKE_INTERRUPT_AP_UNAVAIL, + PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE) bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD @@ -397,7 +434,8 @@ interrupt_end_book3e: /* Debug exception as a critical interrupt*/ START_EXCEPTION(debug_crit); - CRIT_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) + CRIT_EXCEPTION_PROLOG(0xd00, BOOKE_INTERRUPT_DEBUG, + PROLOG_ADDITION_2REGS) /* * If there is a single step or branch-taken exception in an @@ -431,7 +469,7 @@ interrupt_end_book3e: mtcr r10 ld r10,PACA_EXCRIT+EX_R10(r13) /* restore registers */ ld r11,PACA_EXCRIT+EX_R11(r13) - mfspr r13,SPRN_SPRG_CRIT_SCRATCH + ld r13,PACA_EXCRIT+EX_R13(r13) rfci /* Normal debug exception */ @@ -444,7 +482,7 @@ interrupt_end_book3e: /* Now we mash up things to make it look like we are coming on a * normal exception */ - mfspr r15,SPRN_SPRG_CRIT_SCRATCH + ld r15,PACA_EXCRIT+EX_R13(r13) mtspr SPRN_SPRG_GEN_SCRATCH,r15 mfspr r14,SPRN_DBSR EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE) @@ -462,7 +500,8 @@ kernel_dbg_exc: /* Debug exception as a debug interrupt*/ START_EXCEPTION(debug_debug); - DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS) + DBG_EXCEPTION_PROLOG(0xd00, BOOKE_INTERRUPT_DEBUG, + PROLOG_ADDITION_2REGS) /* * If there is a single step or branch-taken exception in an @@ -523,18 +562,21 @@ kernel_dbg_exc: b .ret_from_except START_EXCEPTION(perfmon); - NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE) + NORMAL_EXCEPTION_PROLOG(0x260, BOOKE_INTERRUPT_PERFORMANCE_MONITOR, + PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE) addi r3,r1,STACK_FRAME_OVERHEAD bl .performance_monitor_exception b .ret_from_except_lite /* Doorbell interrupt */ - MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x280, BOOKE_INTERRUPT_DOORBELL, + doorbell, .doorbell_exception, ACK_NONE) /* Doorbell critical Interrupt */ START_EXCEPTION(doorbell_crit); - CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE) + CRIT_EXCEPTION_PROLOG(0x2a0, BOOKE_INTERRUPT_DOORBELL_CRITICAL, + PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); @@ -543,12 +585,24 @@ kernel_dbg_exc: // b ret_from_crit_except b . -/* Guest Doorbell */ - MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) +/* + * Guest doorbell interrupt + * This general exception use GSRRx save/restore registers + */ + START_EXCEPTION(guest_doorbell); + GDBELL_EXCEPTION_PROLOG(0x2c0, BOOKE_INTERRUPT_GUEST_DBELL, + PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x2c0, PACA_EXGEN, INTS_KEEP) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .save_nvgprs + INTS_RESTORE_HARD + bl .unknown_exception + b .ret_from_except /* Guest Doorbell critical Interrupt */ START_EXCEPTION(guest_doorbell_crit); - CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE) + CRIT_EXCEPTION_PROLOG(0x2e0, BOOKE_INTERRUPT_GUEST_DBELL_CRIT, + PROLOG_ADDITION_NONE) // EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); @@ -559,7 +613,8 @@ kernel_dbg_exc: /* Hypervisor call */ START_EXCEPTION(hypercall); - NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE) + NORMAL_EXCEPTION_PROLOG(0x310, BOOKE_INTERRUPT_HV_SYSCALL, + PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP) addi r3,r1,STACK_FRAME_OVERHEAD bl .save_nvgprs @@ -569,7 +624,8 @@ kernel_dbg_exc: /* Embedded Hypervisor priviledged */ START_EXCEPTION(ehpriv); - NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE) + NORMAL_EXCEPTION_PROLOG(0x320, BOOKE_INTERRUPT_HV_PRIV, + PROLOG_ADDITION_NONE) EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP) addi r3,r1,STACK_FRAME_OVERHEAD bl .save_nvgprs @@ -582,44 +638,42 @@ kernel_dbg_exc: * accordingly and if the interrupt is level sensitive, we hard disable */ +.macro masked_interrupt_book3e paca_irq full_mask + lbz r10,PACAIRQHAPPENED(r13) + ori r10,r10,\paca_irq + stb r10,PACAIRQHAPPENED(r13) + + .if \full_mask == 1 + rldicl r10,r11,48,1 /* clear MSR_EE */ + rotldi r11,r10,16 + mtspr SPRN_SRR1,r11 + .endif + + lwz r11,PACA_EXGEN+EX_CR(r13) + mtcr r11 + ld r10,PACA_EXGEN+EX_R10(r13) + ld r11,PACA_EXGEN+EX_R11(r13) + mfspr r13,SPRN_SPRG_GEN_SCRATCH + rfi + b . +.endm + masked_interrupt_book3e_0x500: - /* XXX When adding support for EPR, use PACA_IRQ_EE_EDGE */ - li r11,PACA_IRQ_EE - b masked_interrupt_book3e_full_mask + // XXX When adding support for EPR, use PACA_IRQ_EE_EDGE + masked_interrupt_book3e PACA_IRQ_EE 1 masked_interrupt_book3e_0x900: - ACK_DEC(r11); - li r11,PACA_IRQ_DEC - b masked_interrupt_book3e_no_mask + ACK_DEC(r10); + masked_interrupt_book3e PACA_IRQ_DEC 0 + masked_interrupt_book3e_0x980: - ACK_FIT(r11); - li r11,PACA_IRQ_DEC - b masked_interrupt_book3e_no_mask + ACK_FIT(r10); + masked_interrupt_book3e PACA_IRQ_DEC 0 + masked_interrupt_book3e_0x280: masked_interrupt_book3e_0x2c0: - li r11,PACA_IRQ_DBELL - b masked_interrupt_book3e_no_mask + masked_interrupt_book3e PACA_IRQ_DBELL 0 -masked_interrupt_book3e_no_mask: - mtcr r10 - lbz r10,PACAIRQHAPPENED(r13) - or r10,r10,r11 - stb r10,PACAIRQHAPPENED(r13) - b 1f -masked_interrupt_book3e_full_mask: - mtcr r10 - lbz r10,PACAIRQHAPPENED(r13) - or r10,r10,r11 - stb r10,PACAIRQHAPPENED(r13) - mfspr r10,SPRN_SRR1 - rldicl r11,r10,48,1 /* clear MSR_EE */ - rotldi r10,r11,16 - mtspr SPRN_SRR1,r10 -1: ld r10,PACA_EXGEN+EX_R10(r13); - ld r11,PACA_EXGEN+EX_R11(r13); - mfspr r13,SPRN_SPRG_GEN_SCRATCH; - rfi - b . /* * Called from arch_local_irq_enable when an interrupt needs * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280 @@ -1302,25 +1356,11 @@ _GLOBAL(setup_perfmon_ivor) _GLOBAL(setup_doorbell_ivors) SET_IVOR(36, 0x280) /* Processor Doorbell */ SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */ - - /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */ - mfspr r10,SPRN_MMUCFG - rlwinm. r10,r10,0,MMUCFG_LPIDSIZE - beqlr - - SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ - SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ blr _GLOBAL(setup_ehv_ivors) - /* - * We may be running as a guest and lack E.HV even on a chip - * that normally has it. - */ - mfspr r10,SPRN_MMUCFG - rlwinm. r10,r10,0,MMUCFG_LPIDSIZE - beqlr - SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */ SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */ + SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ + SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ blr diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 39aa97d3ff88..10b658ad65e1 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -275,6 +275,31 @@ vsx_unavailable_pSeries_1: STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint) KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300) + . = 0x1500 + .global denorm_Hypervisor +denorm_exception_hv: + HMT_MEDIUM + mtspr SPRN_SPRG_HSCRATCH0,r13 + mfspr r13,SPRN_SPRG_HPACA + std r9,PACA_EXGEN+EX_R9(r13) + std r10,PACA_EXGEN+EX_R10(r13) + std r11,PACA_EXGEN+EX_R11(r13) + std r12,PACA_EXGEN+EX_R12(r13) + mfspr r9,SPRN_SPRG_HSCRATCH0 + std r9,PACA_EXGEN+EX_R13(r13) + mfcr r9 + +#ifdef CONFIG_PPC_DENORMALISATION + mfspr r10,SPRN_HSRR1 + mfspr r11,SPRN_HSRR0 /* save HSRR0 */ + andis. r10,r10,(HSRR1_DENORM)@h /* denorm? */ + addi r11,r11,-4 /* HSRR0 is next instruction */ + bne+ denorm_assist +#endif + + EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV) + KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1500) + #ifdef CONFIG_CBE_RAS STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602) @@ -336,6 +361,103 @@ do_stab_bolted_pSeries: KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900) KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982) +#ifdef CONFIG_PPC_DENORMALISATION +denorm_assist: +BEGIN_FTR_SECTION +/* + * To denormalise we need to move a copy of the register to itself. + * For POWER6 do that here for all FP regs. + */ + mfmsr r10 + ori r10,r10,(MSR_FP|MSR_FE0|MSR_FE1) + xori r10,r10,(MSR_FE0|MSR_FE1) + mtmsrd r10 + sync + fmr 0,0 + fmr 1,1 + fmr 2,2 + fmr 3,3 + fmr 4,4 + fmr 5,5 + fmr 6,6 + fmr 7,7 + fmr 8,8 + fmr 9,9 + fmr 10,10 + fmr 11,11 + fmr 12,12 + fmr 13,13 + fmr 14,14 + fmr 15,15 + fmr 16,16 + fmr 17,17 + fmr 18,18 + fmr 19,19 + fmr 20,20 + fmr 21,21 + fmr 22,22 + fmr 23,23 + fmr 24,24 + fmr 25,25 + fmr 26,26 + fmr 27,27 + fmr 28,28 + fmr 29,29 + fmr 30,30 + fmr 31,31 +FTR_SECTION_ELSE +/* + * To denormalise we need to move a copy of the register to itself. + * For POWER7 do that here for the first 32 VSX registers only. + */ + mfmsr r10 + oris r10,r10,MSR_VSX@h + mtmsrd r10 + sync + XVCPSGNDP(0,0,0) + XVCPSGNDP(1,1,1) + XVCPSGNDP(2,2,2) + XVCPSGNDP(3,3,3) + XVCPSGNDP(4,4,4) + XVCPSGNDP(5,5,5) + XVCPSGNDP(6,6,6) + XVCPSGNDP(7,7,7) + XVCPSGNDP(8,8,8) + XVCPSGNDP(9,9,9) + XVCPSGNDP(10,10,10) + XVCPSGNDP(11,11,11) + XVCPSGNDP(12,12,12) + XVCPSGNDP(13,13,13) + XVCPSGNDP(14,14,14) + XVCPSGNDP(15,15,15) + XVCPSGNDP(16,16,16) + XVCPSGNDP(17,17,17) + XVCPSGNDP(18,18,18) + XVCPSGNDP(19,19,19) + XVCPSGNDP(20,20,20) + XVCPSGNDP(21,21,21) + XVCPSGNDP(22,22,22) + XVCPSGNDP(23,23,23) + XVCPSGNDP(24,24,24) + XVCPSGNDP(25,25,25) + XVCPSGNDP(26,26,26) + XVCPSGNDP(27,27,27) + XVCPSGNDP(28,28,28) + XVCPSGNDP(29,29,29) + XVCPSGNDP(30,30,30) + XVCPSGNDP(31,31,31) +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206) + mtspr SPRN_HSRR0,r11 + mtcrf 0x80,r9 + ld r9,PACA_EXGEN+EX_R9(r13) + ld r10,PACA_EXGEN+EX_R10(r13) + ld r11,PACA_EXGEN+EX_R11(r13) + ld r12,PACA_EXGEN+EX_R12(r13) + ld r13,PACA_EXGEN+EX_R13(r13) + HRFID + b . +#endif + .align 7 /* moved from 0xe00 */ STD_EXCEPTION_HV(., 0xe02, h_data_storage) @@ -495,6 +617,7 @@ machine_check_common: STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) + STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception) #ifdef CONFIG_ALTIVEC STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) #else @@ -960,7 +1083,9 @@ _GLOBAL(do_stab_bolted) rldimi r10,r11,7,52 /* r10 = first ste of the group */ /* Calculate VSID */ - /* This is a kernel address, so protovsid = ESID */ + /* This is a kernel address, so protovsid = ESID | 1 << 37 */ + li r9,0x1 + rldimi r11,r9,(CONTEXT_BITS + USER_ESID_BITS),0 ASM_VSID_SCRAMBLE(r11, r9, 256M) rldic r9,r11,12,16 /* r9 = vsid << 12 */ diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 18bdf74fa164..06c8202a69cf 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -289,8 +289,7 @@ int __init fadump_reserve_mem(void) else memory_limit = memblock_end_of_DRAM(); printk(KERN_INFO "Adjusted memory_limit for firmware-assisted" - " dump, now %#016llx\n", - (unsigned long long)memory_limit); + " dump, now %#016llx\n", memory_limit); } if (memory_limit) memory_boundary = memory_limit; diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 0f59863c3ade..6f62a737f607 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -895,15 +895,11 @@ _GLOBAL(__setup_e500mc_ivors) mtspr SPRN_IVOR36,r3 li r3,CriticalDoorbell@l mtspr SPRN_IVOR37,r3 + sync + blr - /* - * We only want to touch IVOR38-41 if we're running on hardware - * that supports category E.HV. The architectural way to determine - * this is MMUCFG[LPIDSIZE]. - */ - mfspr r3, SPRN_MMUCFG - andis. r3, r3, MMUCFG_LPIDSIZE@h - beq no_hv +/* setup ehv ivors for */ +_GLOBAL(__setup_ehv_ivors) li r3,GuestDoorbell@l mtspr SPRN_IVOR38,r3 li r3,CriticalGuestDoorbell@l @@ -912,14 +908,8 @@ _GLOBAL(__setup_e500mc_ivors) mtspr SPRN_IVOR40,r3 li r3,Ehvpriv@l mtspr SPRN_IVOR41,r3 -skip_hv_ivors: sync blr -no_hv: - lwz r3, CPU_SPEC_FEATURES(r5) - rlwinm r3, r3, 0, ~CPU_FTR_EMB_HV - stw r3, CPU_SPEC_FEATURES(r5) - b skip_hv_ivors #ifdef CONFIG_SPE /* @@ -1043,6 +1033,34 @@ _GLOBAL(flush_dcache_L1) blr +/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */ +_GLOBAL(__flush_disable_L1) + mflr r10 + bl flush_dcache_L1 /* Flush L1 d-cache */ + mtlr r10 + + mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */ + li r5, 2 + rlwimi r4, r5, 0, 3 + + msync + isync + mtspr SPRN_L1CSR0, r4 + isync + +1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */ + andi. r4, r4, 2 + bne 1b + + mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */ + li r5, 2 + rlwimi r4, r5, 0, 3 + + mtspr SPRN_L1CSR1, r4 + isync + + blr + #ifdef CONFIG_SMP /* When we get here, r24 needs to hold the CPU # */ .globl __secondary_start diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 956a4c496de9..a89cae481b04 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) * If so, DABR will be populated in single_step_dabr_instruction(). */ if (current->thread.last_hit_ubp != bp) - set_dabr(info->address | info->type | DABR_TRANSLATION); + set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); return 0; } @@ -97,7 +97,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) } *slot = NULL; - set_dabr(0); + set_dabr(0, 0); } /* @@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) info->address = bp->attr.bp_addr; info->len = bp->attr.bp_len; + info->dabrx = DABRX_ALL; + if (bp->attr.exclude_user) + info->dabrx &= ~DABRX_USER; + if (bp->attr.exclude_kernel) + info->dabrx &= ~DABRX_KERNEL; + if (bp->attr.exclude_hv) + info->dabrx &= ~DABRX_HYP; /* * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8) @@ -197,7 +204,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs) info = counter_arch_bp(tsk->thread.last_hit_ubp); regs->msr &= ~MSR_SE; - set_dabr(info->address | info->type | DABR_TRANSLATION); + set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); tsk->thread.last_hit_ubp = NULL; } @@ -215,7 +222,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) unsigned long dar = regs->dar; /* Disable breakpoints during exception handling */ - set_dabr(0); + set_dabr(0, 0); /* * The counter may be concurrently released but that can only @@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) if (!info->extraneous_interrupt) perf_bp_event(bp, regs); - set_dabr(info->address | info->type | DABR_TRANSLATION); + set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); out: rcu_read_unlock(); return rc; @@ -294,7 +301,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) { struct pt_regs *regs = args->regs; struct perf_event *bp = NULL; - struct arch_hw_breakpoint *bp_info; + struct arch_hw_breakpoint *info; bp = current->thread.last_hit_ubp; /* @@ -304,16 +311,16 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) if (!bp) return NOTIFY_DONE; - bp_info = counter_arch_bp(bp); + info = counter_arch_bp(bp); /* * We shall invoke the user-defined callback function in the single * stepping handler to confirm to 'trigger-after-execute' semantics */ - if (!bp_info->extraneous_interrupt) + if (!info->extraneous_interrupt) perf_bp_event(bp, regs); - set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION); + set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); current->thread.last_hit_ubp = NULL; /* diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index b01d14eeca8d..8220baa46faf 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -47,7 +47,6 @@ #include <linux/stat.h> #include <linux/of_platform.h> #include <asm/ibmebus.h> -#include <asm/abs_addr.h> static struct device ibmebus_bus_device = { /* fake "parent" device */ .init_name = "ibmebus", diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index ff5a6ce027b8..8226c6cb348a 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -215,7 +215,8 @@ static unsigned long iommu_range_alloc(struct device *dev, spin_lock_irqsave(&(pool->lock), flags); again: - if ((pass == 0) && handle && *handle) + if ((pass == 0) && handle && *handle && + (*handle >= pool->start) && (*handle < pool->end)) start = *handle; else start = pool->hint; @@ -236,7 +237,9 @@ again: * but on second pass, start at 0 in pool 0. */ if ((start & mask) >= limit || pass > 0) { + spin_unlock(&(pool->lock)); pool = &(tbl->pools[0]); + spin_lock(&(pool->lock)); start = pool->start; } else { start &= mask; diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 1f017bb7a7ce..71413f41278f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -489,10 +489,10 @@ void do_IRQ(struct pt_regs *regs) struct pt_regs *old_regs = set_irq_regs(regs); unsigned int irq; - trace_irq_entry(regs); - irq_enter(); + trace_irq_entry(regs); + check_stack_overflow(); /* @@ -511,10 +511,10 @@ void do_IRQ(struct pt_regs *regs) else __get_cpu_var(irq_stat).spurious_irqs++; + trace_irq_exit(regs); + irq_exit(); set_irq_regs(old_regs); - - trace_irq_exit(regs); } void __init init_IRQ(void) diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 5df777794403..fa9f6c72f557 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -165,7 +165,7 @@ void __init reserve_crashkernel(void) if (memory_limit && memory_limit <= crashk_res.end) { memory_limit = crashk_res.end + 1; printk("Adjusted memory limit for crashkernel, now 0x%llx\n", - (unsigned long long)memory_limit); + memory_limit); } printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " @@ -204,6 +204,12 @@ static struct property crashk_size_prop = { .value = &crashk_size, }; +static struct property memory_limit_prop = { + .name = "linux,memory-limit", + .length = sizeof(unsigned long long), + .value = &memory_limit, +}; + static void __init export_crashk_values(struct device_node *node) { struct property *prop; @@ -223,6 +229,12 @@ static void __init export_crashk_values(struct device_node *node) crashk_size = resource_size(&crashk_res); prom_add_property(node, &crashk_size_prop); } + + /* + * memory_limit is required by the kexec-tools to limit the + * crash regions to the actual memory used. + */ + prom_update_property(node, &memory_limit_prop); } static int __init kexec_setup(void) diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index fbe1a12dc7f1..cd6da855090c 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -142,6 +142,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu) new_paca->hw_cpu_id = 0xffff; new_paca->kexec_state = KEXEC_STATE_NONE; new_paca->__current = &init_task; + new_paca->data_offset = 0xfeeeeeeeeeeeeeeeULL; #ifdef CONFIG_PPC_STD_MMU_64 new_paca->slb_shadow_ptr = &slb_shadow[cpu]; #endif /* CONFIG_PPC_STD_MMU_64 */ diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 43fea543d686..7f94f760dd0c 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -980,13 +980,14 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus) if (i >= 3 && bus->self->transparent) continue; - /* If we are going to re-assign everything, mark the resource - * as unset and move it down to 0 + /* If we're going to reassign everything, we can + * shrink the P2P resource to have size as being + * of 0 in order to save space. */ if (pci_has_flag(PCI_REASSIGN_ALL_RSRC)) { res->flags |= IORESOURCE_UNSET; - res->end -= res->start; res->start = 0; + res->end = -1; continue; } @@ -1248,7 +1249,14 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) pr_warning("PCI: Cannot allocate resource region " "%d of PCI bridge %d, will remap\n", i, bus->number); clear_resource: - res->start = res->end = 0; + /* The resource might be figured out when doing + * reassignment based on the resources required + * by the downstream PCI devices. Here we set + * the size of the resource to be 0 in order to + * save more space. + */ + res->start = 0; + res->end = -1; res->flags = 0; } diff --git a/arch/powerpc/kernel/ppc32.h b/arch/powerpc/kernel/ppc32.h index dc16aefe1dd0..02fb0ee26093 100644 --- a/arch/powerpc/kernel/ppc32.h +++ b/arch/powerpc/kernel/ppc32.h @@ -16,57 +16,6 @@ /* These are here to support 32-bit syscalls on a 64-bit kernel. */ -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[SI_PAD_SIZE32]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - compat_uid_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - compat_uid_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - compat_uid_t _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - #define __old_sigaction32 old_sigaction32 struct __old_sigaction32 { diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index e9cb51f5f801..d5ad666efd8b 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -258,6 +258,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address, { siginfo_t info; + current->thread.trap_nr = signal_code; if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, 11, SIGSEGV) == NOTIFY_STOP) return; @@ -275,6 +276,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, { siginfo_t info; + current->thread.trap_nr = TRAP_HWBKPT; if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, 11, SIGSEGV) == NOTIFY_STOP) return; @@ -283,7 +285,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, return; /* Clear the DABR */ - set_dabr(0); + set_dabr(0, 0); /* Deliver the signal to userspace */ info.si_signo = SIGTRAP; @@ -364,18 +366,19 @@ static void set_debug_reg_defaults(struct thread_struct *thread) { if (thread->dabr) { thread->dabr = 0; - set_dabr(0); + thread->dabrx = 0; + set_dabr(0, 0); } } #endif /* !CONFIG_HAVE_HW_BREAKPOINT */ #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ -int set_dabr(unsigned long dabr) +int set_dabr(unsigned long dabr, unsigned long dabrx) { __get_cpu_var(current_dabr) = dabr; if (ppc_md.set_dabr) - return ppc_md.set_dabr(dabr); + return ppc_md.set_dabr(dabr, dabrx); /* XXX should we have a CPU_FTR_HAS_DABR ? */ #ifdef CONFIG_PPC_ADV_DEBUG_REGS @@ -385,9 +388,8 @@ int set_dabr(unsigned long dabr) #endif #elif defined(CONFIG_PPC_BOOK3S) mtspr(SPRN_DABR, dabr); + mtspr(SPRN_DABRX, dabrx); #endif - - return 0; } @@ -480,7 +482,7 @@ struct task_struct *__switch_to(struct task_struct *prev, */ #ifndef CONFIG_HAVE_HW_BREAKPOINT if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) - set_dabr(new->thread.dabr); + set_dabr(new->thread.dabr, new->thread.dabrx); #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f191bf02943a..37725e86651e 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -78,7 +78,7 @@ static int __init early_parse_mem(char *p) return 1; memory_limit = PAGE_ALIGN(memparse(p, &p)); - DBG("memory limit = 0x%llx\n", (unsigned long long)memory_limit); + DBG("memory limit = 0x%llx\n", memory_limit); return 0; } @@ -661,7 +661,7 @@ void __init early_init_devtree(void *params) /* make sure we've parsed cmdline for mem= before this */ if (memory_limit) - first_memblock_size = min(first_memblock_size, memory_limit); + first_memblock_size = min_t(u64, first_memblock_size, memory_limit); setup_initial_memory_limit(memstart_addr, first_memblock_size); /* Reserve MEMBLOCK regions used by kernel, initrd, dt, etc... */ memblock_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index e144498bcddd..cb6c123722a2 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -705,6 +705,7 @@ static void __init early_cmdline_parse(void) #endif #define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */ #define OV5_PFO_HW_RNG 0x80 /* PFO Random Number Generator */ +#define OV5_PFO_HW_842 0x40 /* PFO Compression Accelerator */ #define OV5_PFO_HW_ENCR 0x20 /* PFO Encryption Accelerator */ /* Option Vector 6: IBM PAPR hints */ @@ -774,8 +775,7 @@ static unsigned char ibm_architecture_vec[] = { 0, 0, 0, - OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR, - + OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842, /* option vector 6: IBM PAPR hints */ 4 - 2, /* length */ 0, @@ -1748,7 +1748,7 @@ static void __init prom_initialize_tce_table(void) * else will impact performance, so we always allocate 8MB. * Anton */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) + if (pvr_version_is(PVR_POWER4) || pvr_version_is(PVR_POWER4p)) minsize = 8UL << 20; else minsize = 4UL << 20; diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index c10fc28b9092..79d8e56470df 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -960,6 +960,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, thread->ptrace_bps[0] = bp; ptrace_put_breakpoints(task); thread->dabr = data; + thread->dabrx = DABRX_ALL; return 0; } @@ -983,6 +984,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, /* Move contents to the DABR register */ task->thread.dabr = data; + task->thread.dabrx = DABRX_ALL; #else /* CONFIG_PPC_ADV_DEBUG_REGS */ /* As described above, it was assumed 3 bits were passed with the data * address, but we will assume only the mode bits will be passed @@ -1397,6 +1399,7 @@ static long ppc_set_hwdebug(struct task_struct *child, dabr |= DABR_DATA_WRITE; child->thread.dabr = dabr; + child->thread.dabrx = DABRX_ALL; return 1; #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */ diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 2c0ee6405633..20b0120db0c3 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -21,7 +21,6 @@ #include <asm/delay.h> #include <asm/uaccess.h> #include <asm/rtas.h> -#include <asm/abs_addr.h> #define MODULE_VERS "1.0" #define MODULE_NAME "rtas_flash" @@ -582,7 +581,7 @@ static void rtas_flash_firmware(int reboot_type) flist = (struct flash_block_list *)&rtas_data_buf[0]; flist->num_blocks = 0; flist->next = rtas_firmware_flash_list; - rtas_block_list = virt_to_abs(flist); + rtas_block_list = __pa(flist); if (rtas_block_list >= 4UL*1024*1024*1024) { printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); spin_unlock(&rtas_data_buf_lock); @@ -596,13 +595,13 @@ static void rtas_flash_firmware(int reboot_type) for (f = flist; f; f = next) { /* Translate data addrs to absolute */ for (i = 0; i < f->num_blocks; i++) { - f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); + f->blocks[i].data = (char *)__pa(f->blocks[i].data); image_size += f->blocks[i].length; } next = f->next; /* Don't translate NULL pointer for last entry */ if (f->next) - f->next = (struct flash_block_list *)virt_to_abs(f->next); + f->next = (struct flash_block_list *)__pa(f->next); else f->next = NULL; /* make num_blocks into the version/length field */ diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 179af906dcda..6de63e3250bb 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -81,7 +81,7 @@ int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) return PCIBIOS_DEVICE_NOT_FOUND; if (returnval == EEH_IO_ERROR_VALUE(size) && - eeh_dn_check_failure (pdn->node, NULL)) + eeh_dev_check_failure(of_node_to_eeh_dev(pdn->node))) return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; @@ -275,9 +275,6 @@ void __init find_and_init_phbs(void) of_node_put(root); pci_devs_phb_init(); - /* Create EEH devices for all PHBs */ - eeh_dev_phb_init(); - /* * PCI_PROBE_ONLY and PCI_REASSIGN_ALL_BUS can be set via properties * in chosen. diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 389bd4f0cdb1..efb6a41b3131 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -208,6 +208,8 @@ void __init early_setup(unsigned long dt_ptr) /* Fix up paca fields required for the boot cpu */ get_paca()->cpu_start = 1; + /* Allow percpu accesses to "work" until we setup percpu data */ + get_paca()->data_offset = 0; /* Probe the machine type */ probe_machine(); diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 5c023c9cf16e..a2dc75793bd5 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -11,6 +11,7 @@ #include <linux/tracehook.h> #include <linux/signal.h> +#include <linux/uprobes.h> #include <linux/key.h> #include <asm/hw_breakpoint.h> #include <asm/uaccess.h> @@ -130,7 +131,7 @@ static int do_signal(struct pt_regs *regs) * triggered inside the kernel. */ if (current->thread.dabr) - set_dabr(current->thread.dabr); + set_dabr(current->thread.dabr, current->thread.dabrx); #endif /* Re-enable the breakpoints for the signal stack */ thread_change_pc(current, regs); @@ -157,6 +158,11 @@ static int do_signal(struct pt_regs *regs) void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) { + if (thread_info_flags & _TIF_UPROBE) { + clear_thread_flag(TIF_UPROBE); + uprobe_notify_resume(regs); + } + if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 8d4214afc21d..2b952b5386fd 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -102,7 +102,7 @@ int __devinit smp_generic_kick_cpu(int nr) * Ok it's not there, so it might be soft-unplugged, let's * try to bring it back */ - per_cpu(cpu_state, nr) = CPU_UP_PREPARE; + generic_set_cpu_up(nr); smp_wmb(); smp_send_reschedule(nr); #endif /* CONFIG_HOTPLUG_CPU */ @@ -171,7 +171,7 @@ int smp_request_message_ipi(int virq, int msg) } #endif err = request_irq(virq, smp_ipi_action[msg], - IRQF_PERCPU | IRQF_NO_THREAD, + IRQF_PERCPU | IRQF_NO_THREAD | IRQF_NO_SUSPEND, smp_ipi_name[msg], 0); WARN(err < 0, "unable to request_irq %d for %s (rc %d)\n", virq, smp_ipi_name[msg], err); @@ -413,6 +413,16 @@ void generic_set_cpu_dead(unsigned int cpu) per_cpu(cpu_state, cpu) = CPU_DEAD; } +/* + * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise + * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(), + * which makes the delay in generic_cpu_die() not happen. + */ +void generic_set_cpu_up(unsigned int cpu) +{ + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; +} + int generic_check_cpu_restart(unsigned int cpu) { return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE; diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index eaa9d0e6abca..c9986fd400d8 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -508,8 +508,6 @@ void timer_interrupt(struct pt_regs * regs) */ may_hard_irq_enable(); - trace_timer_interrupt_entry(regs); - __get_cpu_var(irq_stat).timer_irqs++; #if defined(CONFIG_PPC32) && defined(CONFIG_PMAC) @@ -520,6 +518,8 @@ void timer_interrupt(struct pt_regs * regs) old_regs = set_irq_regs(regs); irq_enter(); + trace_timer_interrupt_entry(regs); + if (test_irq_work_pending()) { clear_irq_work_pending(); irq_work_run(); @@ -544,10 +544,10 @@ void timer_interrupt(struct pt_regs * regs) } #endif + trace_timer_interrupt_exit(regs); + irq_exit(); set_irq_regs(old_regs); - - trace_timer_interrupt_exit(regs); } /* diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index ae0843fa7a61..32518401af68 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -251,6 +251,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) if (arch_irqs_disabled() && !arch_irq_disabled_regs(regs)) local_irq_enable(); + current->thread.trap_nr = code; memset(&info, 0, sizeof(info)); info.si_signo = signr; info.si_code = code; diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c new file mode 100644 index 000000000000..d2d46d1014f8 --- /dev/null +++ b/arch/powerpc/kernel/uprobes.c @@ -0,0 +1,184 @@ +/* + * User-space Probes (UProbes) for powerpc + * + * 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. + * + * Copyright IBM Corporation, 2007-2012 + * + * Adapted from the x86 port by Ananth N Mavinakayanahalli <ananth@in.ibm.com> + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/uprobes.h> +#include <linux/uaccess.h> +#include <linux/kdebug.h> + +#include <asm/sstep.h> + +#define UPROBE_TRAP_NR UINT_MAX + +/** + * arch_uprobe_analyze_insn + * @mm: the probed address space. + * @arch_uprobe: the probepoint information. + * @addr: vaddr to probe. + * Return 0 on success or a -ve number on error. + */ +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, + struct mm_struct *mm, unsigned long addr) +{ + if (addr & 0x03) + return -EINVAL; + + /* + * We currently don't support a uprobe on an already + * existing breakpoint instruction underneath + */ + if (is_trap(auprobe->ainsn)) + return -ENOTSUPP; + return 0; +} + +/* + * arch_uprobe_pre_xol - prepare to execute out of line. + * @auprobe: the probepoint information. + * @regs: reflects the saved user state of current task. + */ +int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct arch_uprobe_task *autask = ¤t->utask->autask; + + autask->saved_trap_nr = current->thread.trap_nr; + current->thread.trap_nr = UPROBE_TRAP_NR; + regs->nip = current->utask->xol_vaddr; + return 0; +} + +/** + * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs + * @regs: Reflects the saved state of the task after it has hit a breakpoint + * instruction. + * Return the address of the breakpoint instruction. + */ +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +/* + * If xol insn itself traps and generates a signal (SIGILL/SIGSEGV/etc), + * then detect the case where a singlestepped instruction jumps back to its + * own address. It is assumed that anything like do_page_fault/do_trap/etc + * sets thread.trap_nr != UINT_MAX. + * + * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, + * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to + * UPROBE_TRAP_NR == UINT_MAX set by arch_uprobe_pre_xol(). + */ +bool arch_uprobe_xol_was_trapped(struct task_struct *t) +{ + if (t->thread.trap_nr != UPROBE_TRAP_NR) + return true; + + return false; +} + +/* + * Called after single-stepping. To avoid the SMP problems that can + * occur when we temporarily put back the original opcode to + * single-step, we single-stepped a copy of the instruction. + * + * This function prepares to resume execution after the single-step. + */ +int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); + + current->thread.trap_nr = utask->autask.saved_trap_nr; + + /* + * On powerpc, except for loads and stores, most instructions + * including ones that alter code flow (branches, calls, returns) + * are emulated in the kernel. We get here only if the emulation + * support doesn't exist and have to fix-up the next instruction + * to be executed. + */ + regs->nip = utask->vaddr + MAX_UINSN_BYTES; + return 0; +} + +/* callback routine for handling exceptions. */ +int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct die_args *args = data; + struct pt_regs *regs = args->regs; + + /* regs == NULL is a kernel bug */ + if (WARN_ON(!regs)) + return NOTIFY_DONE; + + /* We are only interested in userspace traps */ + if (!user_mode(regs)) + return NOTIFY_DONE; + + switch (val) { + case DIE_BPT: + if (uprobe_pre_sstep_notifier(regs)) + return NOTIFY_STOP; + break; + case DIE_SSTEP: + if (uprobe_post_sstep_notifier(regs)) + return NOTIFY_STOP; + default: + break; + } + return NOTIFY_DONE; +} + +/* + * This function gets called when XOL instruction either gets trapped or + * the thread has a fatal signal, so reset the instruction pointer to its + * probed address. + */ +void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + current->thread.trap_nr = utask->autask.saved_trap_nr; + instruction_pointer_set(regs, utask->vaddr); +} + +/* + * See if the instruction can be emulated. + * Returns true if instruction was emulated, false otherwise. + */ +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + int ret; + + /* + * emulate_step() returns 1 if the insn was successfully emulated. + * For all other cases, we need to single-step in hardware. + */ + ret = emulate_step(regs, auprobe->ainsn); + if (ret > 0) + return true; + + return false; +} diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index b67db22e102d..1b2076f049ce 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -723,9 +723,7 @@ int __cpuinit vdso_getcpu_init(void) val = (cpu & 0xfff) | ((node & 0xffff) << 16); mtspr(SPRN_SPRG3, val); -#ifdef CONFIG_KVM_BOOK3S_HANDLER - get_paca()->kvm_hstate.sprg3 = val; -#endif + get_paca()->sprg3 = val; put_cpu(); diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 02b32216bbc3..201ba59738be 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -33,7 +33,6 @@ #include <asm/prom.h> #include <asm/firmware.h> #include <asm/tce.h> -#include <asm/abs_addr.h> #include <asm/page.h> #include <asm/hvcall.h> diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 33aa715dab28..5dd3ab469976 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c @@ -319,7 +319,6 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, if (is_error_page(new_page)) { printk(KERN_ERR "Couldn't get guest page for gfn %llx!\n", (unsigned long long)gfn); - kvm_release_page_clean(new_page); return; } hpaddr = page_to_phys(new_page); diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c index 837f13e7b6bf..00aa61268e0d 100644 --- a/arch/powerpc/kvm/book3s_32_mmu_host.c +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c @@ -141,7 +141,7 @@ extern char etext[]; int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) { pfn_t hpaddr; - u64 va; + u64 vpn; u64 vsid; struct kvmppc_sid_map *map; volatile u32 *pteg; @@ -173,7 +173,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) BUG_ON(!map); vsid = map->host_vsid; - va = (vsid << SID_SHIFT) | (eaddr & ~ESID_MASK); + vpn = (vsid << (SID_SHIFT - VPN_SHIFT)) | ((eaddr & ~ESID_MASK) >> VPN_SHIFT) next_pteg: if (rr == 16) { @@ -244,11 +244,11 @@ next_pteg: dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n", orig_pte->may_write ? 'w' : '-', orig_pte->may_execute ? 'x' : '-', - orig_pte->eaddr, (ulong)pteg, va, + orig_pte->eaddr, (ulong)pteg, vpn, orig_pte->vpage, hpaddr); pte->slot = (ulong)&pteg[rr]; - pte->host_va = va; + pte->host_vpn = vpn; pte->pte = *orig_pte; pte->pfn = hpaddr >> PAGE_SHIFT; diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index 0688b6b39585..4d72f9ebc554 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -33,7 +33,7 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { - ppc_md.hpte_invalidate(pte->slot, pte->host_va, + ppc_md.hpte_invalidate(pte->slot, pte->host_vpn, MMU_PAGE_4K, MMU_SEGSIZE_256M, false); } @@ -80,8 +80,9 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) { + unsigned long vpn; pfn_t hpaddr; - ulong hash, hpteg, va; + ulong hash, hpteg; u64 vsid; int ret; int rflags = 0x192; @@ -117,7 +118,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) } vsid = map->host_vsid; - va = hpt_va(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M); + vpn = hpt_vpn(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M); if (!orig_pte->may_write) rflags |= HPTE_R_PP; @@ -129,7 +130,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) else kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT); - hash = hpt_hash(va, PTE_SIZE, MMU_SEGSIZE_256M); + hash = hpt_hash(vpn, PTE_SIZE, MMU_SEGSIZE_256M); map_again: hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); @@ -141,7 +142,8 @@ map_again: goto out; } - ret = ppc_md.hpte_insert(hpteg, va, hpaddr, rflags, vflags, MMU_PAGE_4K, MMU_SEGSIZE_256M); + ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags, + MMU_PAGE_4K, MMU_SEGSIZE_256M); if (ret < 0) { /* If we couldn't map a primary PTE, try a secondary */ @@ -152,7 +154,8 @@ map_again: } else { struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu); - trace_kvm_book3s_64_mmu_map(rflags, hpteg, va, hpaddr, orig_pte); + trace_kvm_book3s_64_mmu_map(rflags, hpteg, + vpn, hpaddr, orig_pte); /* The ppc_md code may give us a secondary entry even though we asked for a primary. Fix up. */ @@ -162,7 +165,7 @@ map_again: } pte->slot = hpteg + (ret & 7); - pte->host_va = va; + pte->host_vpn = vpn; pte->pte = *orig_pte; pte->pfn = hpaddr >> PAGE_SHIFT; diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index d03eb6f7b058..d95d11322a15 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -705,7 +705,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, goto out_unlock; hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID; - rmap = &memslot->rmap[gfn - memslot->base_gfn]; + rmap = &memslot->arch.rmap[gfn - memslot->base_gfn]; lock_rmap(rmap); /* Check if we might have been invalidated; let the guest retry if so */ @@ -756,9 +756,12 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu, goto out_put; } -static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, - int (*handler)(struct kvm *kvm, unsigned long *rmapp, - unsigned long gfn)) +static int kvm_handle_hva_range(struct kvm *kvm, + unsigned long start, + unsigned long end, + int (*handler)(struct kvm *kvm, + unsigned long *rmapp, + unsigned long gfn)) { int ret; int retval = 0; @@ -767,15 +770,25 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, slots = kvm_memslots(kvm); kvm_for_each_memslot(memslot, slots) { - unsigned long start = memslot->userspace_addr; - unsigned long end; + unsigned long hva_start, hva_end; + gfn_t gfn, gfn_end; - end = start + (memslot->npages << PAGE_SHIFT); - if (hva >= start && hva < end) { - gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; + hva_start = max(start, memslot->userspace_addr); + hva_end = min(end, memslot->userspace_addr + + (memslot->npages << PAGE_SHIFT)); + if (hva_start >= hva_end) + continue; + /* + * {gfn(page) | page intersects with [hva_start, hva_end)} = + * {gfn, gfn+1, ..., gfn_end-1}. + */ + gfn = hva_to_gfn_memslot(hva_start, memslot); + gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); + + for (; gfn < gfn_end; ++gfn) { + gfn_t gfn_offset = gfn - memslot->base_gfn; - ret = handler(kvm, &memslot->rmap[gfn_offset], - memslot->base_gfn + gfn_offset); + ret = handler(kvm, &memslot->arch.rmap[gfn_offset], gfn); retval |= ret; } } @@ -783,6 +796,13 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, return retval; } +static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, + int (*handler)(struct kvm *kvm, unsigned long *rmapp, + unsigned long gfn)) +{ + return kvm_handle_hva_range(kvm, hva, hva + 1, handler); +} + static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, unsigned long gfn) { @@ -850,6 +870,13 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) return 0; } +int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) +{ + if (kvm->arch.using_mmu_notifiers) + kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp); + return 0; +} + static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, unsigned long gfn) { @@ -1009,7 +1036,7 @@ long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot) unsigned long *rmapp, *map; preempt_disable(); - rmapp = memslot->rmap; + rmapp = memslot->arch.rmap; map = memslot->dirty_bitmap; for (i = 0; i < memslot->npages; ++i) { if (kvm_test_clear_dirty(kvm, rmapp)) diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 5c70d19494f9..fb0e821622d4 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -84,7 +84,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index, if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) return; - rmap = real_vmalloc_addr(&memslot->rmap[gfn - memslot->base_gfn]); + rmap = real_vmalloc_addr(&memslot->arch.rmap[gfn - memslot->base_gfn]); lock_rmap(rmap); head = *rmap & KVMPPC_RMAP_INDEX; @@ -180,7 +180,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, if (!slot_is_aligned(memslot, psize)) return H_PARAMETER; slot_fn = gfn - memslot->base_gfn; - rmap = &memslot->rmap[slot_fn]; + rmap = &memslot->arch.rmap[slot_fn]; if (!kvm->arch.using_mmu_notifiers) { physp = kvm->arch.slot_phys[memslot->id]; @@ -197,7 +197,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, pa &= PAGE_MASK; } else { /* Translate to host virtual address */ - hva = gfn_to_hva_memslot(memslot, gfn); + hva = __gfn_to_hva_memslot(memslot, gfn); /* Look up the Linux PTE for the backing page */ pte_size = psize; diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 44b72feaff7d..74a24bbb9637 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1065,7 +1065,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) mtspr SPRN_DABRX,r6 /* Restore SPRG3 */ - ld r3,HSTATE_SPRG3(r13) + ld r3,PACA_SPRG3(r13) mtspr SPRN_SPRG3,r3 /* diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index a1baec340f7e..05c28f59f77f 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -242,10 +242,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) int i; hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); - if (is_error_page(hpage)) { - kvm_release_page_clean(hpage); + if (is_error_page(hpage)) return; - } hpage_offset = pte->raddr & ~PAGE_MASK; hpage_offset &= ~0xFFFULL; diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index a2b66717813d..ff38b664195d 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c @@ -520,11 +520,10 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, if (likely(!pfnmap)) { unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT); - pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn); + pfn = gfn_to_pfn_memslot(slot, gfn); if (is_error_pfn(pfn)) { printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", (long)gfn); - kvm_release_pfn_clean(pfn); return; } diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 87f4dc886076..4d213b8b0fb5 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -302,10 +302,18 @@ long kvm_arch_dev_ioctl(struct file *filp, void kvm_arch_free_memslot(struct kvm_memory_slot *free, struct kvm_memory_slot *dont) { + if (!dont || free->arch.rmap != dont->arch.rmap) { + vfree(free->arch.rmap); + free->arch.rmap = NULL; + } } int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) { + slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap)); + if (!slot->arch.rmap) + return -ENOMEM; + return 0; } @@ -326,8 +334,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, kvmppc_core_commit_memory_region(kvm, mem); } +void kvm_arch_flush_shadow_all(struct kvm *kvm) +{ +} -void kvm_arch_flush_shadow(struct kvm *kvm) +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot) { } diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h index 877186b7b1c3..ddb6a2149d44 100644 --- a/arch/powerpc/kvm/trace.h +++ b/arch/powerpc/kvm/trace.h @@ -189,7 +189,7 @@ TRACE_EVENT(kvm_book3s_mmu_map, TP_ARGS(pte), TP_STRUCT__entry( - __field( u64, host_va ) + __field( u64, host_vpn ) __field( u64, pfn ) __field( ulong, eaddr ) __field( u64, vpage ) @@ -198,7 +198,7 @@ TRACE_EVENT(kvm_book3s_mmu_map, ), TP_fast_assign( - __entry->host_va = pte->host_va; + __entry->host_vpn = pte->host_vpn; __entry->pfn = pte->pfn; __entry->eaddr = pte->pte.eaddr; __entry->vpage = pte->pte.vpage; @@ -208,8 +208,8 @@ TRACE_EVENT(kvm_book3s_mmu_map, (pte->pte.may_execute ? 0x1 : 0); ), - TP_printk("Map: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]", - __entry->host_va, __entry->pfn, __entry->eaddr, + TP_printk("Map: hvpn=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]", + __entry->host_vpn, __entry->pfn, __entry->eaddr, __entry->vpage, __entry->raddr, __entry->flags) ); @@ -218,7 +218,7 @@ TRACE_EVENT(kvm_book3s_mmu_invalidate, TP_ARGS(pte), TP_STRUCT__entry( - __field( u64, host_va ) + __field( u64, host_vpn ) __field( u64, pfn ) __field( ulong, eaddr ) __field( u64, vpage ) @@ -227,7 +227,7 @@ TRACE_EVENT(kvm_book3s_mmu_invalidate, ), TP_fast_assign( - __entry->host_va = pte->host_va; + __entry->host_vpn = pte->host_vpn; __entry->pfn = pte->pfn; __entry->eaddr = pte->pte.eaddr; __entry->vpage = pte->pte.vpage; @@ -238,7 +238,7 @@ TRACE_EVENT(kvm_book3s_mmu_invalidate, ), TP_printk("Flush: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]", - __entry->host_va, __entry->pfn, __entry->eaddr, + __entry->host_vpn, __entry->pfn, __entry->eaddr, __entry->vpage, __entry->raddr, __entry->flags) ); diff --git a/arch/powerpc/lib/memcpy_power7.S b/arch/powerpc/lib/memcpy_power7.S index 7ba6c96de778..0663630baf3b 100644 --- a/arch/powerpc/lib/memcpy_power7.S +++ b/arch/powerpc/lib/memcpy_power7.S @@ -239,8 +239,8 @@ _GLOBAL(memcpy_power7) ori r9,r9,1 /* stream=1 */ srdi r7,r5,7 /* length in cachelines, capped at 0x3FF */ - cmpldi cr1,r7,0x3FF - ble cr1,1f + cmpldi r7,0x3FF + ble 1f li r7,0x3FF 1: lis r0,0x0E00 /* depth=7 */ sldi r7,r7,7 diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 9a52349874ee..e15c521846ca 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -566,7 +566,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) unsigned long int ea; unsigned int cr, mb, me, sh; int err; - unsigned long old_ra; + unsigned long old_ra, val3; long ival; opcode = instr >> 26; @@ -1486,11 +1486,43 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr) goto ldst_done; case 36: /* stw */ - case 37: /* stwu */ val = regs->gpr[rd]; err = write_mem(val, dform_ea(instr, regs), 4, regs); goto ldst_done; + case 37: /* stwu */ + val = regs->gpr[rd]; + val3 = dform_ea(instr, regs); + /* + * For PPC32 we always use stwu to change stack point with r1. So + * this emulated store may corrupt the exception frame, now we + * have to provide the exception frame trampoline, which is pushed + * below the kprobed function stack. So we only update gpr[1] but + * don't emulate the real store operation. We will do real store + * operation safely in exception return code by checking this flag. + */ + if ((ra == 1) && !(regs->msr & MSR_PR) \ + && (val3 >= (regs->gpr[1] - STACK_INT_FRAME_SIZE))) { + /* + * Check if we will touch kernel sack overflow + */ + if (val3 - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) { + printk(KERN_CRIT "Can't kprobe this since Kernel stack overflow.\n"); + err = -EINVAL; + break; + } + + /* + * Check if we already set since that means we'll + * lose the previous value. + */ + WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE)); + set_thread_flag(TIF_EMULATE_STACK_STORE); + err = 0; + } else + err = write_mem(val, val3, 4, regs); + goto ldst_done; + case 38: /* stb */ case 39: /* stbu */ val = regs->gpr[rd]; diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index e5f028b5794e..5495ebe983a2 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -133,6 +133,7 @@ static int do_sigbus(struct pt_regs *regs, unsigned long address) up_read(¤t->mm->mmap_sem); if (user_mode(regs)) { + current->thread.trap_nr = BUS_ADRERR; info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 602aeb06d298..56585086413a 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -63,7 +63,7 @@ _GLOBAL(__hash_page_4K) /* Save non-volatile registers. * r31 will hold "old PTE" * r30 is "new PTE" - * r29 is "va" + * r29 is vpn * r28 is a hash value * r27 is hashtab mask (maybe dynamic patched instead ?) */ @@ -111,10 +111,10 @@ BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) - /* Calc va and put it in r29 */ - rldicr r29,r5,28,63-28 - rldicl r3,r3,0,36 - or r29,r3,r29 + /* Calc vpn and put it in r29 */ + sldi r29,r5,SID_SHIFT - VPN_SHIFT + rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT) + or r29,r28,r29 /* Calculate hash value for primary slot and store it in r28 */ rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ @@ -122,14 +122,19 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) xor r28,r5,r0 b 4f -3: /* Calc VA and hash in r29 and r28 for 1T segment */ - sldi r29,r5,40 /* vsid << 40 */ - clrldi r3,r3,24 /* ea & 0xffffffffff */ +3: /* Calc vpn and put it in r29 */ + sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT + rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT) + or r29,r28,r29 + + /* + * calculate hash value for primary slot and + * store it in r28 for 1T segment + */ rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ clrldi r5,r5,40 /* vsid & 0xffffff */ rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */ xor r28,r28,r5 - or r29,r3,r29 /* VA */ xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ @@ -185,7 +190,7 @@ htab_insert_pte: /* Call ppc_md.hpte_insert */ ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */ - mr r4,r29 /* Retrieve va */ + mr r4,r29 /* Retrieve vpn */ li r7,0 /* !bolted, !secondary */ li r8,MMU_PAGE_4K /* page size */ ld r9,STK_PARAM(R9)(r1) /* segment size */ @@ -208,7 +213,7 @@ _GLOBAL(htab_call_hpte_insert1) /* Call ppc_md.hpte_insert */ ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */ - mr r4,r29 /* Retrieve va */ + mr r4,r29 /* Retrieve vpn */ li r7,HPTE_V_SECONDARY /* !bolted, secondary */ li r8,MMU_PAGE_4K /* page size */ ld r9,STK_PARAM(R9)(r1) /* segment size */ @@ -278,7 +283,7 @@ htab_modify_pte: add r3,r0,r3 /* add slot idx */ /* Call ppc_md.hpte_updatepp */ - mr r5,r29 /* va */ + mr r5,r29 /* vpn */ li r6,MMU_PAGE_4K /* page size */ ld r7,STK_PARAM(R9)(r1) /* segment size */ ld r8,STK_PARAM(R8)(r1) /* get "local" param */ @@ -339,7 +344,7 @@ _GLOBAL(__hash_page_4K) /* Save non-volatile registers. * r31 will hold "old PTE" * r30 is "new PTE" - * r29 is "va" + * r29 is vpn * r28 is a hash value * r27 is hashtab mask (maybe dynamic patched instead ?) * r26 is the hidx mask @@ -394,10 +399,14 @@ BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) - /* Calc va and put it in r29 */ - rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */ - rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */ - or r29,r3,r29 /* r29 = va */ + /* Calc vpn and put it in r29 */ + sldi r29,r5,SID_SHIFT - VPN_SHIFT + /* + * clrldi r3,r3,64 - SID_SHIFT --> ea & 0xfffffff + * srdi r28,r3,VPN_SHIFT + */ + rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT) + or r29,r28,r29 /* Calculate hash value for primary slot and store it in r28 */ rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ @@ -405,14 +414,23 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) xor r28,r5,r0 b 4f -3: /* Calc VA and hash in r29 and r28 for 1T segment */ - sldi r29,r5,40 /* vsid << 40 */ - clrldi r3,r3,24 /* ea & 0xffffffffff */ +3: /* Calc vpn and put it in r29 */ + sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT + /* + * clrldi r3,r3,64 - SID_SHIFT_1T --> ea & 0xffffffffff + * srdi r28,r3,VPN_SHIFT + */ + rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT) + or r29,r28,r29 + + /* + * Calculate hash value for primary slot and + * store it in r28 for 1T segment + */ rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ clrldi r5,r5,40 /* vsid & 0xffffff */ rldicl r0,r3,64-12,36 /* (ea >> 12) & 0xfffffff */ xor r28,r28,r5 - or r29,r3,r29 /* VA */ xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ @@ -488,7 +506,7 @@ htab_special_pfn: /* Call ppc_md.hpte_insert */ ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */ - mr r4,r29 /* Retrieve va */ + mr r4,r29 /* Retrieve vpn */ li r7,0 /* !bolted, !secondary */ li r8,MMU_PAGE_4K /* page size */ ld r9,STK_PARAM(R9)(r1) /* segment size */ @@ -515,7 +533,7 @@ _GLOBAL(htab_call_hpte_insert1) /* Call ppc_md.hpte_insert */ ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */ - mr r4,r29 /* Retrieve va */ + mr r4,r29 /* Retrieve vpn */ li r7,HPTE_V_SECONDARY /* !bolted, secondary */ li r8,MMU_PAGE_4K /* page size */ ld r9,STK_PARAM(R9)(r1) /* segment size */ @@ -547,7 +565,7 @@ _GLOBAL(htab_call_hpte_remove) * useless now that the segment has been switched to 4k pages. */ htab_inval_old_hpte: - mr r3,r29 /* virtual addr */ + mr r3,r29 /* vpn */ mr r4,r31 /* PTE.pte */ li r5,0 /* PTE.hidx */ li r6,MMU_PAGE_64K /* psize */ @@ -620,7 +638,7 @@ htab_modify_pte: add r3,r0,r3 /* add slot idx */ /* Call ppc_md.hpte_updatepp */ - mr r5,r29 /* va */ + mr r5,r29 /* vpn */ li r6,MMU_PAGE_4K /* page size */ ld r7,STK_PARAM(R9)(r1) /* segment size */ ld r8,STK_PARAM(R8)(r1) /* get "local" param */ @@ -676,7 +694,7 @@ _GLOBAL(__hash_page_64K) /* Save non-volatile registers. * r31 will hold "old PTE" * r30 is "new PTE" - * r29 is "va" + * r29 is vpn * r28 is a hash value * r27 is hashtab mask (maybe dynamic patched instead ?) */ @@ -729,10 +747,10 @@ BEGIN_FTR_SECTION cmpdi r9,0 /* check segment size */ bne 3f END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) - /* Calc va and put it in r29 */ - rldicr r29,r5,28,63-28 - rldicl r3,r3,0,36 - or r29,r3,r29 + /* Calc vpn and put it in r29 */ + sldi r29,r5,SID_SHIFT - VPN_SHIFT + rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT) + or r29,r28,r29 /* Calculate hash value for primary slot and store it in r28 */ rldicl r5,r5,0,25 /* vsid & 0x0000007fffffffff */ @@ -740,14 +758,19 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) xor r28,r5,r0 b 4f -3: /* Calc VA and hash in r29 and r28 for 1T segment */ - sldi r29,r5,40 /* vsid << 40 */ - clrldi r3,r3,24 /* ea & 0xffffffffff */ +3: /* Calc vpn and put it in r29 */ + sldi r29,r5,SID_SHIFT_1T - VPN_SHIFT + rldicl r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT) + or r29,r28,r29 + + /* + * calculate hash value for primary slot and + * store it in r28 for 1T segment + */ rldic r28,r5,25,25 /* (vsid << 25) & 0x7fffffffff */ clrldi r5,r5,40 /* vsid & 0xffffff */ rldicl r0,r3,64-16,40 /* (ea >> 16) & 0xffffff */ xor r28,r28,r5 - or r29,r3,r29 /* VA */ xor r28,r28,r0 /* hash */ /* Convert linux PTE bits into HW equivalents */ @@ -806,7 +829,7 @@ ht64_insert_pte: /* Call ppc_md.hpte_insert */ ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */ - mr r4,r29 /* Retrieve va */ + mr r4,r29 /* Retrieve vpn */ li r7,0 /* !bolted, !secondary */ li r8,MMU_PAGE_64K ld r9,STK_PARAM(R9)(r1) /* segment size */ @@ -829,7 +852,7 @@ _GLOBAL(ht64_call_hpte_insert1) /* Call ppc_md.hpte_insert */ ld r6,STK_PARAM(R4)(r1) /* Retrieve new pp bits */ - mr r4,r29 /* Retrieve va */ + mr r4,r29 /* Retrieve vpn */ li r7,HPTE_V_SECONDARY /* !bolted, secondary */ li r8,MMU_PAGE_64K ld r9,STK_PARAM(R9)(r1) /* segment size */ @@ -899,7 +922,7 @@ ht64_modify_pte: add r3,r0,r3 /* add slot idx */ /* Call ppc_md.hpte_updatepp */ - mr r5,r29 /* va */ + mr r5,r29 /* vpn */ li r6,MMU_PAGE_64K ld r7,STK_PARAM(R9)(r1) /* segment size */ ld r8,STK_PARAM(R8)(r1) /* get "local" param */ diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index 90039bc64119..ffc1e00f7a22 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c @@ -14,10 +14,10 @@ #include <linux/spinlock.h> #include <linux/bitops.h> +#include <linux/of.h> #include <linux/threads.h> #include <linux/smp.h> -#include <asm/abs_addr.h> #include <asm/machdep.h> #include <asm/mmu.h> #include <asm/mmu_context.h> @@ -39,22 +39,35 @@ DEFINE_RAW_SPINLOCK(native_tlbie_lock); -static inline void __tlbie(unsigned long va, int psize, int ssize) +static inline void __tlbie(unsigned long vpn, int psize, int ssize) { + unsigned long va; unsigned int penc; - /* clear top 16 bits, non SLS segment */ + /* + * We need 14 to 65 bits of va for a tlibe of 4K page + * With vpn we ignore the lower VPN_SHIFT bits already. + * And top two bits are already ignored because we can + * only accomadate 76 bits in a 64 bit vpn with a VPN_SHIFT + * of 12. + */ + va = vpn << VPN_SHIFT; + /* + * clear top 16 bits of 64bit va, non SLS segment + * Older versions of the architecture (2.02 and earler) require the + * masking of the top 16 bits. + */ va &= ~(0xffffULL << 48); switch (psize) { case MMU_PAGE_4K: - va &= ~0xffful; va |= ssize << 8; asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2) : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206) : "memory"); break; default: + /* We need 14 to 14 + i bits of va */ penc = mmu_psize_defs[psize].penc; va &= ~((1ul << mmu_psize_defs[psize].shift) - 1); va |= penc << 12; @@ -67,21 +80,28 @@ static inline void __tlbie(unsigned long va, int psize, int ssize) } } -static inline void __tlbiel(unsigned long va, int psize, int ssize) +static inline void __tlbiel(unsigned long vpn, int psize, int ssize) { + unsigned long va; unsigned int penc; - /* clear top 16 bits, non SLS segment */ + /* VPN_SHIFT can be atmost 12 */ + va = vpn << VPN_SHIFT; + /* + * clear top 16 bits of 64 bit va, non SLS segment + * Older versions of the architecture (2.02 and earler) require the + * masking of the top 16 bits. + */ va &= ~(0xffffULL << 48); switch (psize) { case MMU_PAGE_4K: - va &= ~0xffful; va |= ssize << 8; asm volatile(".long 0x7c000224 | (%0 << 11) | (0 << 21)" : : "r"(va) : "memory"); break; default: + /* We need 14 to 14 + i bits of va */ penc = mmu_psize_defs[psize].penc; va &= ~((1ul << mmu_psize_defs[psize].shift) - 1); va |= penc << 12; @@ -94,7 +114,7 @@ static inline void __tlbiel(unsigned long va, int psize, int ssize) } -static inline void tlbie(unsigned long va, int psize, int ssize, int local) +static inline void tlbie(unsigned long vpn, int psize, int ssize, int local) { unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); @@ -105,10 +125,10 @@ static inline void tlbie(unsigned long va, int psize, int ssize, int local) raw_spin_lock(&native_tlbie_lock); asm volatile("ptesync": : :"memory"); if (use_local) { - __tlbiel(va, psize, ssize); + __tlbiel(vpn, psize, ssize); asm volatile("ptesync": : :"memory"); } else { - __tlbie(va, psize, ssize); + __tlbie(vpn, psize, ssize); asm volatile("eieio; tlbsync; ptesync": : :"memory"); } if (lock_tlbie && !use_local) @@ -134,7 +154,7 @@ static inline void native_unlock_hpte(struct hash_pte *hptep) clear_bit_unlock(HPTE_LOCK_BIT, word); } -static long native_hpte_insert(unsigned long hpte_group, unsigned long va, +static long native_hpte_insert(unsigned long hpte_group, unsigned long vpn, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize, int ssize) { @@ -143,9 +163,9 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va, int i; if (!(vflags & HPTE_V_BOLTED)) { - DBG_LOW(" insert(group=%lx, va=%016lx, pa=%016lx," + DBG_LOW(" insert(group=%lx, vpn=%016lx, pa=%016lx," " rflags=%lx, vflags=%lx, psize=%d)\n", - hpte_group, va, pa, rflags, vflags, psize); + hpte_group, vpn, pa, rflags, vflags, psize); } for (i = 0; i < HPTES_PER_GROUP; i++) { @@ -163,7 +183,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va, if (i == HPTES_PER_GROUP) return -1; - hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) { @@ -225,17 +245,17 @@ static long native_hpte_remove(unsigned long hpte_group) } static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int ssize, + unsigned long vpn, int psize, int ssize, int local) { struct hash_pte *hptep = htab_address + slot; unsigned long hpte_v, want_v; int ret = 0; - want_v = hpte_encode_v(va, psize, ssize); + want_v = hpte_encode_v(vpn, psize, ssize); - DBG_LOW(" update(va=%016lx, avpnv=%016lx, hash=%016lx, newpp=%x)", - va, want_v & HPTE_V_AVPN, slot, newpp); + DBG_LOW(" update(vpn=%016lx, avpnv=%016lx, group=%lx, newpp=%lx)", + vpn, want_v & HPTE_V_AVPN, slot, newpp); native_lock_hpte(hptep); @@ -254,12 +274,12 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp, native_unlock_hpte(hptep); /* Ensure it is out of the tlb too. */ - tlbie(va, psize, ssize, local); + tlbie(vpn, psize, ssize, local); return ret; } -static long native_hpte_find(unsigned long va, int psize, int ssize) +static long native_hpte_find(unsigned long vpn, int psize, int ssize) { struct hash_pte *hptep; unsigned long hash; @@ -267,8 +287,8 @@ static long native_hpte_find(unsigned long va, int psize, int ssize) long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize); - want_v = hpte_encode_v(va, psize, ssize); + hash = hpt_hash(vpn, mmu_psize_defs[psize].shift, ssize); + want_v = hpte_encode_v(vpn, psize, ssize); /* Bolted mappings are only ever in the primary group */ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; @@ -295,14 +315,15 @@ static long native_hpte_find(unsigned long va, int psize, int ssize) static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, int psize, int ssize) { - unsigned long vsid, va; + unsigned long vpn; + unsigned long vsid; long slot; struct hash_pte *hptep; vsid = get_kernel_vsid(ea, ssize); - va = hpt_va(ea, vsid, ssize); + vpn = hpt_vpn(ea, vsid, ssize); - slot = native_hpte_find(va, psize, ssize); + slot = native_hpte_find(vpn, psize, ssize); if (slot == -1) panic("could not find page to bolt\n"); hptep = htab_address + slot; @@ -312,10 +333,10 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, (newpp & (HPTE_R_PP | HPTE_R_N)); /* Ensure it is out of the tlb too. */ - tlbie(va, psize, ssize, 0); + tlbie(vpn, psize, ssize, 0); } -static void native_hpte_invalidate(unsigned long slot, unsigned long va, +static void native_hpte_invalidate(unsigned long slot, unsigned long vpn, int psize, int ssize, int local) { struct hash_pte *hptep = htab_address + slot; @@ -325,9 +346,9 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, local_irq_save(flags); - DBG_LOW(" invalidate(va=%016lx, hash: %x)\n", va, slot); + DBG_LOW(" invalidate(vpn=%016lx, hash: %lx)\n", vpn, slot); - want_v = hpte_encode_v(va, psize, ssize); + want_v = hpte_encode_v(vpn, psize, ssize); native_lock_hpte(hptep); hpte_v = hptep->v; @@ -339,7 +360,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, hptep->v = 0; /* Invalidate the TLB */ - tlbie(va, psize, ssize, local); + tlbie(vpn, psize, ssize, local); local_irq_restore(flags); } @@ -349,11 +370,12 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va, #define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT) static void hpte_decode(struct hash_pte *hpte, unsigned long slot, - int *psize, int *ssize, unsigned long *va) + int *psize, int *ssize, unsigned long *vpn) { + unsigned long avpn, pteg, vpi; unsigned long hpte_r = hpte->r; unsigned long hpte_v = hpte->v; - unsigned long avpn; + unsigned long vsid, seg_off; int i, size, shift, penc; if (!(hpte_v & HPTE_V_LARGE)) @@ -380,32 +402,38 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, } /* This works for all page sizes, and for 256M and 1T segments */ + *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT; shift = mmu_psize_defs[size].shift; - avpn = (HPTE_V_AVPN_VAL(hpte_v) & ~mmu_psize_defs[size].avpnm) << 23; - - if (shift < 23) { - unsigned long vpi, vsid, pteg; - pteg = slot / HPTES_PER_GROUP; - if (hpte_v & HPTE_V_SECONDARY) - pteg = ~pteg; - switch (hpte_v >> HPTE_V_SSIZE_SHIFT) { - case MMU_SEGSIZE_256M: - vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask; - break; - case MMU_SEGSIZE_1T: - vsid = avpn >> 40; + avpn = (HPTE_V_AVPN_VAL(hpte_v) & ~mmu_psize_defs[size].avpnm); + pteg = slot / HPTES_PER_GROUP; + if (hpte_v & HPTE_V_SECONDARY) + pteg = ~pteg; + + switch (*ssize) { + case MMU_SEGSIZE_256M: + /* We only have 28 - 23 bits of seg_off in avpn */ + seg_off = (avpn & 0x1f) << 23; + vsid = avpn >> 5; + /* We can find more bits from the pteg value */ + if (shift < 23) { + vpi = (vsid ^ pteg) & htab_hash_mask; + seg_off |= vpi << shift; + } + *vpn = vsid << (SID_SHIFT - VPN_SHIFT) | seg_off >> VPN_SHIFT; + case MMU_SEGSIZE_1T: + /* We only have 40 - 23 bits of seg_off in avpn */ + seg_off = (avpn & 0x1ffff) << 23; + vsid = avpn >> 17; + if (shift < 23) { vpi = (vsid ^ (vsid << 25) ^ pteg) & htab_hash_mask; - break; - default: - avpn = vpi = size = 0; + seg_off |= vpi << shift; } - avpn |= (vpi << mmu_psize_defs[size].shift); + *vpn = vsid << (SID_SHIFT_1T - VPN_SHIFT) | seg_off >> VPN_SHIFT; + default: + *vpn = size = 0; } - - *va = avpn; *psize = size; - *ssize = hpte_v >> HPTE_V_SSIZE_SHIFT; } /* @@ -418,9 +446,10 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, */ static void native_hpte_clear(void) { + unsigned long vpn = 0; unsigned long slot, slots, flags; struct hash_pte *hptep = htab_address; - unsigned long hpte_v, va; + unsigned long hpte_v; unsigned long pteg_count; int psize, ssize; @@ -448,9 +477,9 @@ static void native_hpte_clear(void) * already hold the native_tlbie_lock. */ if (hpte_v & HPTE_V_VALID) { - hpte_decode(hptep, slot, &psize, &ssize, &va); + hpte_decode(hptep, slot, &psize, &ssize, &vpn); hptep->v = 0; - __tlbie(va, psize, ssize); + __tlbie(vpn, psize, ssize); } } @@ -465,7 +494,8 @@ static void native_hpte_clear(void) */ static void native_flush_hash_range(unsigned long number, int local) { - unsigned long va, hash, index, hidx, shift, slot; + unsigned long vpn; + unsigned long hash, index, hidx, shift, slot; struct hash_pte *hptep; unsigned long hpte_v; unsigned long want_v; @@ -479,18 +509,18 @@ static void native_flush_hash_range(unsigned long number, int local) local_irq_save(flags); for (i = 0; i < number; i++) { - va = batch->vaddr[i]; + vpn = batch->vpn[i]; pte = batch->pte[i]; - pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift, ssize); + pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { + hash = hpt_hash(vpn, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; hptep = htab_address + slot; - want_v = hpte_encode_v(va, psize, ssize); + want_v = hpte_encode_v(vpn, psize, ssize); native_lock_hpte(hptep); hpte_v = hptep->v; if (!HPTE_V_COMPARE(hpte_v, want_v) || @@ -505,12 +535,12 @@ static void native_flush_hash_range(unsigned long number, int local) mmu_psize_defs[psize].tlbiel && local) { asm volatile("ptesync":::"memory"); for (i = 0; i < number; i++) { - va = batch->vaddr[i]; + vpn = batch->vpn[i]; pte = batch->pte[i]; - pte_iterate_hashed_subpages(pte, psize, va, index, - shift) { - __tlbiel(va, psize, ssize); + pte_iterate_hashed_subpages(pte, psize, + vpn, index, shift) { + __tlbiel(vpn, psize, ssize); } pte_iterate_hashed_end(); } asm volatile("ptesync":::"memory"); @@ -522,12 +552,12 @@ static void native_flush_hash_range(unsigned long number, int local) asm volatile("ptesync":::"memory"); for (i = 0; i < number; i++) { - va = batch->vaddr[i]; + vpn = batch->vpn[i]; pte = batch->pte[i]; - pte_iterate_hashed_subpages(pte, psize, va, index, - shift) { - __tlbie(va, psize, ssize); + pte_iterate_hashed_subpages(pte, psize, + vpn, index, shift) { + __tlbie(vpn, psize, ssize); } pte_iterate_hashed_end(); } asm volatile("eieio; tlbsync; ptesync":::"memory"); @@ -539,29 +569,6 @@ static void native_flush_hash_range(unsigned long number, int local) local_irq_restore(flags); } -#ifdef CONFIG_PPC_PSERIES -/* Disable TLB batching on nighthawk */ -static inline int tlb_batching_enabled(void) -{ - struct device_node *root = of_find_node_by_path("/"); - int enabled = 1; - - if (root) { - const char *model = of_get_property(root, "model", NULL); - if (model && !strcmp(model, "IBM,9076-N81")) - enabled = 0; - of_node_put(root); - } - - return enabled; -} -#else -static inline int tlb_batching_enabled(void) -{ - return 1; -} -#endif - void __init hpte_init_native(void) { ppc_md.hpte_invalidate = native_hpte_invalidate; @@ -570,6 +577,5 @@ void __init hpte_init_native(void) ppc_md.hpte_insert = native_hpte_insert; ppc_md.hpte_remove = native_hpte_remove; ppc_md.hpte_clear_all = native_hpte_clear; - if (tlb_batching_enabled()) - ppc_md.flush_hash_range = native_flush_hash_range; + ppc_md.flush_hash_range = native_flush_hash_range; } diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 377e5cbedbbb..3a292be2e079 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -43,7 +43,6 @@ #include <asm/uaccess.h> #include <asm/machdep.h> #include <asm/prom.h> -#include <asm/abs_addr.h> #include <asm/tlbflush.h> #include <asm/io.h> #include <asm/eeh.h> @@ -192,18 +191,18 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, vaddr += step, paddr += step) { unsigned long hash, hpteg; unsigned long vsid = get_kernel_vsid(vaddr, ssize); - unsigned long va = hpt_va(vaddr, vsid, ssize); + unsigned long vpn = hpt_vpn(vaddr, vsid, ssize); unsigned long tprot = prot; /* Make kernel text executable */ if (overlaps_kernel_text(vaddr, vaddr + step)) tprot &= ~HPTE_R_N; - hash = hpt_hash(va, shift, ssize); + hash = hpt_hash(vpn, shift, ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); BUG_ON(!ppc_md.hpte_insert); - ret = ppc_md.hpte_insert(hpteg, va, paddr, tprot, + ret = ppc_md.hpte_insert(hpteg, vpn, paddr, tprot, HPTE_V_BOLTED, psize, ssize); if (ret < 0) @@ -651,7 +650,7 @@ static void __init htab_initialize(void) DBG("Hash table allocated at %lx, size: %lx\n", table, htab_size_bytes); - htab_address = abs_to_virt(table); + htab_address = __va(table); /* htab absolute addr + encoded htabsize */ _SDR1 = table + __ilog2(pteg_count) - 11; @@ -804,16 +803,19 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) #ifdef CONFIG_PPC_MM_SLICES unsigned int get_paca_psize(unsigned long addr) { - unsigned long index, slices; + u64 lpsizes; + unsigned char *hpsizes; + unsigned long index, mask_index; if (addr < SLICE_LOW_TOP) { - slices = get_paca()->context.low_slices_psize; + lpsizes = get_paca()->context.low_slices_psize; index = GET_LOW_SLICE_INDEX(addr); - } else { - slices = get_paca()->context.high_slices_psize; - index = GET_HIGH_SLICE_INDEX(addr); + return (lpsizes >> (index * 4)) & 0xF; } - return (slices >> (index * 4)) & 0xF; + hpsizes = get_paca()->context.high_slices_psize; + index = GET_HIGH_SLICE_INDEX(addr); + mask_index = index & 0x1; + return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xF; } #else @@ -1153,21 +1155,21 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, /* WARNING: This is called from hash_low_64.S, if you change this prototype, * do not forget to update the assembly call site ! */ -void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int ssize, +void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize, int local) { unsigned long hash, index, shift, hidx, slot; - DBG_LOW("flush_hash_page(va=%016lx)\n", va); - pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift, ssize); + DBG_LOW("flush_hash_page(vpn=%016lx)\n", vpn); + pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { + hash = hpt_hash(vpn, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx); - ppc_md.hpte_invalidate(slot, va, psize, ssize, local); + ppc_md.hpte_invalidate(slot, vpn, psize, ssize, local); } pte_iterate_hashed_end(); } @@ -1181,7 +1183,7 @@ void flush_hash_range(unsigned long number, int local) &__get_cpu_var(ppc64_tlb_batch); for (i = 0; i < number; i++) - flush_hash_page(batch->vaddr[i], batch->pte[i], + flush_hash_page(batch->vpn[i], batch->pte[i], batch->psize, batch->ssize, local); } } @@ -1208,14 +1210,14 @@ static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) { unsigned long hash, hpteg; unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); - unsigned long va = hpt_va(vaddr, vsid, mmu_kernel_ssize); + unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); unsigned long mode = htab_convert_pte_flags(PAGE_KERNEL); int ret; - hash = hpt_hash(va, PAGE_SHIFT, mmu_kernel_ssize); + hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); - ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr), + ret = ppc_md.hpte_insert(hpteg, vpn, __pa(vaddr), mode, HPTE_V_BOLTED, mmu_linear_psize, mmu_kernel_ssize); BUG_ON (ret < 0); @@ -1229,9 +1231,9 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) { unsigned long hash, hidx, slot; unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); - unsigned long va = hpt_va(vaddr, vsid, mmu_kernel_ssize); + unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); - hash = hpt_hash(va, PAGE_SHIFT, mmu_kernel_ssize); + hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); spin_lock(&linear_map_hash_lock); BUG_ON(!(linear_map_hash_slots[lmi] & 0x80)); hidx = linear_map_hash_slots[lmi] & 0x7f; @@ -1241,7 +1243,7 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; - ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, mmu_kernel_ssize, 0); + ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_kernel_ssize, 0); } void kernel_map_pages(struct page *page, int numpages, int enable) diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c index cc5c273086cf..cecad348f604 100644 --- a/arch/powerpc/mm/hugetlbpage-hash64.c +++ b/arch/powerpc/mm/hugetlbpage-hash64.c @@ -18,14 +18,15 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, pte_t *ptep, unsigned long trap, int local, int ssize, unsigned int shift, unsigned int mmu_psize) { + unsigned long vpn; unsigned long old_pte, new_pte; - unsigned long va, rflags, pa, sz; + unsigned long rflags, pa, sz; long slot; BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); /* Search the Linux page table for a match with va */ - va = hpt_va(ea, vsid, ssize); + vpn = hpt_vpn(ea, vsid, ssize); /* At this point, we have a pte (old_pte) which can be used to build * or update an HPTE. There are 2 cases: @@ -69,19 +70,19 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, /* There MIGHT be an HPTE for this pte */ unsigned long hash, slot; - hash = hpt_hash(va, shift, ssize); + hash = hpt_hash(vpn, shift, ssize); if (old_pte & _PAGE_F_SECOND) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += (old_pte & _PAGE_F_GIX) >> 12; - if (ppc_md.hpte_updatepp(slot, rflags, va, mmu_psize, + if (ppc_md.hpte_updatepp(slot, rflags, vpn, mmu_psize, ssize, local) == -1) old_pte &= ~_PAGE_HPTEFLAGS; } if (likely(!(old_pte & _PAGE_HASHPTE))) { - unsigned long hash = hpt_hash(va, shift, ssize); + unsigned long hash = hpt_hash(vpn, shift, ssize); unsigned long hpte_group; pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT; @@ -101,14 +102,14 @@ repeat: _PAGE_COHERENT | _PAGE_GUARDED)); /* Insert into the hash table, primary slot */ - slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, 0, + slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0, mmu_psize, ssize); /* Primary is full, try the secondary */ if (unlikely(slot == -1)) { hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; - slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, + slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, HPTE_V_SECONDARY, mmu_psize, ssize); if (slot == -1) { diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 620b7acd2fdf..95a45293e5ac 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -62,7 +62,6 @@ #include <asm/cputable.h> #include <asm/sections.h> #include <asm/iommu.h> -#include <asm/abs_addr.h> #include <asm/vdso.h> #include "mmu_decl.h" diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index fbdad0e3929a..0dba5066c22a 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -62,7 +62,7 @@ int init_bootmem_done; int mem_init_done; -phys_addr_t memory_limit; +unsigned long long memory_limit; #ifdef CONFIG_HIGHMEM pte_t *kmap_pte; @@ -300,8 +300,7 @@ void __init mem_init(void) unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize; #ifdef CONFIG_SWIOTLB - if (ppc_swiotlb_enable) - swiotlb_init(1); + swiotlb_init(0); #endif num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT; diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index 40677aa0190e..40bc5b0ace54 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -30,11 +30,13 @@ static DEFINE_SPINLOCK(mmu_context_lock); static DEFINE_IDA(mmu_context_ida); /* - * The proto-VSID space has 2^35 - 1 segments available for user mappings. - * Each segment contains 2^28 bytes. Each context maps 2^44 bytes, - * so we can support 2^19-1 contexts (19 == 35 + 28 - 44). + * 256MB segment + * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments + * available for user mappings. Each segment contains 2^28 bytes. Each + * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts + * (19 == 37 + 28 - 46). */ -#define MAX_CONTEXT ((1UL << 19) - 1) +#define MAX_CONTEXT ((1UL << CONTEXT_BITS) - 1) int __init_new_context(void) { diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 249a0631c4db..e212a271c7a4 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -51,13 +51,22 @@ #include <asm/processor.h> #include <asm/cputable.h> #include <asm/sections.h> -#include <asm/abs_addr.h> #include <asm/firmware.h> #include "mmu_decl.h" -unsigned long ioremap_bot = IOREMAP_BASE; +/* Some sanity checking */ +#if TASK_SIZE_USER64 > PGTABLE_RANGE +#error TASK_SIZE_USER64 exceeds pagetable range +#endif + +#ifdef CONFIG_PPC_STD_MMU_64 +#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT)) +#error TASK_SIZE_USER64 exceeds user VSID range +#endif +#endif +unsigned long ioremap_bot = IOREMAP_BASE; #ifdef CONFIG_PPC_MMU_NOHASH static void *early_alloc_pgtable(unsigned long size) diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index b9ee79ce2200..1a16ca227757 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -56,6 +56,12 @@ _GLOBAL(slb_allocate_realmode) */ _GLOBAL(slb_miss_kernel_load_linear) li r11,0 + li r9,0x1 + /* + * for 1T we shift 12 bits more. slb_finish_load_1T will do + * the necessary adjustment + */ + rldimi r10,r9,(CONTEXT_BITS + USER_ESID_BITS),0 BEGIN_FTR_SECTION b slb_finish_load END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) @@ -85,6 +91,12 @@ _GLOBAL(slb_miss_kernel_load_vmemmap) _GLOBAL(slb_miss_kernel_load_io) li r11,0 6: + li r9,0x1 + /* + * for 1T we shift 12 bits more. slb_finish_load_1T will do + * the necessary adjustment + */ + rldimi r10,r9,(CONTEXT_BITS + USER_ESID_BITS),0 BEGIN_FTR_SECTION b slb_finish_load END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) @@ -108,17 +120,31 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT) * between 4k and 64k standard page size */ #ifdef CONFIG_PPC_MM_SLICES + /* r10 have esid */ cmpldi r10,16 - - /* Get the slice index * 4 in r11 and matching slice size mask in r9 */ - ld r9,PACALOWSLICESPSIZE(r13) - sldi r11,r10,2 + /* below SLICE_LOW_TOP */ blt 5f - ld r9,PACAHIGHSLICEPSIZE(r13) - srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2) - andi. r11,r11,0x3c + /* + * Handle hpsizes, + * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index + */ + srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */ + addi r9,r11,PACAHIGHSLICEPSIZE + lbzx r9,r13,r9 /* r9 is hpsizes[r11] */ + /* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */ + rldicl r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63 + b 6f -5: /* Extract the psize and multiply to get an array offset */ +5: + /* + * Handle lpsizes + * r9 is get_paca()->context.low_slices_psize, r11 is index + */ + ld r9,PACALOWSLICESPSIZE(r13) + mr r11,r10 +6: + sldi r11,r11,2 /* index * 4 */ + /* Extract the psize and multiply to get an array offset */ srd r9,r9,r11 andi. r9,r9,0xf mulli r9,r9,MMUPSIZEDEFSIZE @@ -209,7 +235,11 @@ _GLOBAL(slb_allocate_user) */ slb_finish_load: ASM_VSID_SCRAMBLE(r10,r9,256M) - rldimi r11,r10,SLB_VSID_SHIFT,16 /* combine VSID and flags */ + /* + * bits above VSID_BITS_256M need to be ignored from r10 + * also combine VSID and flags + */ + rldimi r11,r10,SLB_VSID_SHIFT,(64 - (SLB_VSID_SHIFT + VSID_BITS_256M)) /* r3 = EA, r11 = VSID data */ /* @@ -252,10 +282,10 @@ _GLOBAL(slb_compare_rr_to_size) bge 1f /* still room in the slb cache */ - sldi r11,r3,1 /* r11 = offset * sizeof(u16) */ - rldicl r10,r10,36,28 /* get low 16 bits of the ESID */ - add r11,r11,r13 /* r11 = (u16 *)paca + offset */ - sth r10,PACASLBCACHE(r11) /* paca->slb_cache[offset] = esid */ + sldi r11,r3,2 /* r11 = offset * sizeof(u32) */ + srdi r10,r10,28 /* get the 36 bits of the ESID */ + add r11,r11,r13 /* r11 = (u32 *)paca + offset */ + stw r10,PACASLBCACHE(r11) /* paca->slb_cache[offset] = esid */ addi r3,r3,1 /* offset++ */ b 2f 1: /* offset >= SLB_CACHE_ENTRIES */ @@ -273,7 +303,11 @@ _GLOBAL(slb_compare_rr_to_size) slb_finish_load_1T: srdi r10,r10,40-28 /* get 1T ESID */ ASM_VSID_SCRAMBLE(r10,r9,1T) - rldimi r11,r10,SLB_VSID_SHIFT_1T,16 /* combine VSID and flags */ + /* + * bits above VSID_BITS_1T need to be ignored from r10 + * also combine VSID and flags + */ + rldimi r11,r10,SLB_VSID_SHIFT_1T,(64 - (SLB_VSID_SHIFT_1T + VSID_BITS_1T)) li r10,MMU_SEGSIZE_1T rldimi r11,r10,SLB_VSID_SSIZE_SHIFT,0 /* insert segment size */ diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 73709f7ce92c..5829d2a950d4 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -34,6 +34,11 @@ #include <asm/mmu.h> #include <asm/spu.h> +/* some sanity checks */ +#if (PGTABLE_RANGE >> 43) > SLICE_MASK_SIZE +#error PGTABLE_RANGE exceeds slice_mask high_slices size +#endif + static DEFINE_SPINLOCK(slice_convert_lock); @@ -42,7 +47,7 @@ int _slice_debug = 1; static void slice_print_mask(const char *label, struct slice_mask mask) { - char *p, buf[16 + 3 + 16 + 1]; + char *p, buf[16 + 3 + 64 + 1]; int i; if (!_slice_debug) @@ -54,7 +59,7 @@ static void slice_print_mask(const char *label, struct slice_mask mask) *(p++) = '-'; *(p++) = ' '; for (i = 0; i < SLICE_NUM_HIGH; i++) - *(p++) = (mask.high_slices & (1 << i)) ? '1' : '0'; + *(p++) = (mask.high_slices & (1ul << i)) ? '1' : '0'; *(p++) = 0; printk(KERN_DEBUG "%s:%s\n", label, buf); @@ -84,8 +89,8 @@ static struct slice_mask slice_range_to_mask(unsigned long start, } if ((start + len) > SLICE_LOW_TOP) - ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1)) - - (1u << GET_HIGH_SLICE_INDEX(start)); + ret.high_slices = (1ul << (GET_HIGH_SLICE_INDEX(end) + 1)) + - (1ul << GET_HIGH_SLICE_INDEX(start)); return ret; } @@ -135,26 +140,31 @@ static struct slice_mask slice_mask_for_free(struct mm_struct *mm) for (i = 0; i < SLICE_NUM_HIGH; i++) if (!slice_high_has_vma(mm, i)) - ret.high_slices |= 1u << i; + ret.high_slices |= 1ul << i; return ret; } static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize) { + unsigned char *hpsizes; + int index, mask_index; struct slice_mask ret = { 0, 0 }; unsigned long i; - u64 psizes; + u64 lpsizes; - psizes = mm->context.low_slices_psize; + lpsizes = mm->context.low_slices_psize; for (i = 0; i < SLICE_NUM_LOW; i++) - if (((psizes >> (i * 4)) & 0xf) == psize) + if (((lpsizes >> (i * 4)) & 0xf) == psize) ret.low_slices |= 1u << i; - psizes = mm->context.high_slices_psize; - for (i = 0; i < SLICE_NUM_HIGH; i++) - if (((psizes >> (i * 4)) & 0xf) == psize) - ret.high_slices |= 1u << i; + hpsizes = mm->context.high_slices_psize; + for (i = 0; i < SLICE_NUM_HIGH; i++) { + mask_index = i & 0x1; + index = i >> 1; + if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == psize) + ret.high_slices |= 1ul << i; + } return ret; } @@ -183,8 +193,10 @@ static void slice_flush_segments(void *parm) static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize) { + int index, mask_index; /* Write the new slice psize bits */ - u64 lpsizes, hpsizes; + unsigned char *hpsizes; + u64 lpsizes; unsigned long i, flags; slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize); @@ -201,14 +213,18 @@ static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psiz lpsizes = (lpsizes & ~(0xful << (i * 4))) | (((unsigned long)psize) << (i * 4)); - hpsizes = mm->context.high_slices_psize; - for (i = 0; i < SLICE_NUM_HIGH; i++) - if (mask.high_slices & (1u << i)) - hpsizes = (hpsizes & ~(0xful << (i * 4))) | - (((unsigned long)psize) << (i * 4)); - + /* Assign the value back */ mm->context.low_slices_psize = lpsizes; - mm->context.high_slices_psize = hpsizes; + + hpsizes = mm->context.high_slices_psize; + for (i = 0; i < SLICE_NUM_HIGH; i++) { + mask_index = i & 0x1; + index = i >> 1; + if (mask.high_slices & (1ul << i)) + hpsizes[index] = (hpsizes[index] & + ~(0xf << (mask_index * 4))) | + (((unsigned long)psize) << (mask_index * 4)); + } slice_dbg(" lsps=%lx, hsps=%lx\n", mm->context.low_slices_psize, @@ -587,18 +603,19 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr) { - u64 psizes; - int index; + unsigned char *hpsizes; + int index, mask_index; if (addr < SLICE_LOW_TOP) { - psizes = mm->context.low_slices_psize; + u64 lpsizes; + lpsizes = mm->context.low_slices_psize; index = GET_LOW_SLICE_INDEX(addr); - } else { - psizes = mm->context.high_slices_psize; - index = GET_HIGH_SLICE_INDEX(addr); + return (lpsizes >> (index * 4)) & 0xf; } - - return (psizes >> (index * 4)) & 0xf; + hpsizes = mm->context.high_slices_psize; + index = GET_HIGH_SLICE_INDEX(addr); + mask_index = index & 0x1; + return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xf; } EXPORT_SYMBOL_GPL(get_slice_psize); @@ -618,7 +635,9 @@ EXPORT_SYMBOL_GPL(get_slice_psize); */ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) { - unsigned long flags, lpsizes, hpsizes; + int index, mask_index; + unsigned char *hpsizes; + unsigned long flags, lpsizes; unsigned int old_psize; int i; @@ -639,15 +658,21 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) if (((lpsizes >> (i * 4)) & 0xf) == old_psize) lpsizes = (lpsizes & ~(0xful << (i * 4))) | (((unsigned long)psize) << (i * 4)); + /* Assign the value back */ + mm->context.low_slices_psize = lpsizes; hpsizes = mm->context.high_slices_psize; - for (i = 0; i < SLICE_NUM_HIGH; i++) - if (((hpsizes >> (i * 4)) & 0xf) == old_psize) - hpsizes = (hpsizes & ~(0xful << (i * 4))) | - (((unsigned long)psize) << (i * 4)); + for (i = 0; i < SLICE_NUM_HIGH; i++) { + mask_index = i & 0x1; + index = i >> 1; + if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == old_psize) + hpsizes[index] = (hpsizes[index] & + ~(0xf << (mask_index * 4))) | + (((unsigned long)psize) << (mask_index * 4)); + } + + - mm->context.low_slices_psize = lpsizes; - mm->context.high_slices_psize = hpsizes; slice_dbg(" lsps=%lx, hsps=%lx\n", mm->context.low_slices_psize, @@ -660,18 +685,27 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned int psize) void slice_set_psize(struct mm_struct *mm, unsigned long address, unsigned int psize) { + unsigned char *hpsizes; unsigned long i, flags; - u64 *p; + u64 *lpsizes; spin_lock_irqsave(&slice_convert_lock, flags); if (address < SLICE_LOW_TOP) { i = GET_LOW_SLICE_INDEX(address); - p = &mm->context.low_slices_psize; + lpsizes = &mm->context.low_slices_psize; + *lpsizes = (*lpsizes & ~(0xful << (i * 4))) | + ((unsigned long) psize << (i * 4)); } else { + int index, mask_index; i = GET_HIGH_SLICE_INDEX(address); - p = &mm->context.high_slices_psize; + hpsizes = mm->context.high_slices_psize; + mask_index = i & 0x1; + index = i >> 1; + hpsizes[index] = (hpsizes[index] & + ~(0xf << (mask_index * 4))) | + (((unsigned long)psize) << (mask_index * 4)); } - *p = (*p & ~(0xful << (i * 4))) | ((unsigned long) psize << (i * 4)); + spin_unlock_irqrestore(&slice_convert_lock, flags); #ifdef CONFIG_SPU_BASE diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 9106ebb118f5..3f8efa6f2997 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -20,7 +20,6 @@ #include <asm/paca.h> #include <asm/cputable.h> #include <asm/prom.h> -#include <asm/abs_addr.h> struct stab_entry { unsigned long esid_data; @@ -257,7 +256,7 @@ void __init stabs_alloc(void) memset((void *)newstab, 0, HW_PAGE_SIZE); paca[cpu].stab_addr = newstab; - paca[cpu].stab_real = virt_to_abs(newstab); + paca[cpu].stab_real = __pa(newstab); printk(KERN_INFO "Segment table for CPU %d at 0x%llx " "virtual, 0x%llx absolute\n", cpu, paca[cpu].stab_addr, paca[cpu].stab_real); diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c index e4f8f1fc81a5..7c415ddde948 100644 --- a/arch/powerpc/mm/subpage-prot.c +++ b/arch/powerpc/mm/subpage-prot.c @@ -95,7 +95,8 @@ static void subpage_prot_clear(unsigned long addr, unsigned long len) struct mm_struct *mm = current->mm; struct subpage_prot_table *spt = &mm->context.spt; u32 **spm, *spp; - int i, nw; + unsigned long i; + size_t nw; unsigned long next, limit; down_write(&mm->mmap_sem); @@ -144,7 +145,8 @@ long sys_subpage_prot(unsigned long addr, unsigned long len, u32 __user *map) struct mm_struct *mm = current->mm; struct subpage_prot_table *spt = &mm->context.spt; u32 **spm, *spp; - int i, nw; + unsigned long i; + size_t nw; unsigned long next, limit; int err; diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c index 31f18207970b..ae758b3ff72c 100644 --- a/arch/powerpc/mm/tlb_hash64.c +++ b/arch/powerpc/mm/tlb_hash64.c @@ -42,8 +42,9 @@ DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch); void hpte_need_flush(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned long pte, int huge) { + unsigned long vpn; struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch); - unsigned long vsid, vaddr; + unsigned long vsid; unsigned int psize; int ssize; real_pte_t rpte; @@ -86,7 +87,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, vsid = get_kernel_vsid(addr, mmu_kernel_ssize); ssize = mmu_kernel_ssize; } - vaddr = hpt_va(addr, vsid, ssize); + vpn = hpt_vpn(addr, vsid, ssize); rpte = __real_pte(__pte(pte), ptep); /* @@ -96,7 +97,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, * and decide to use local invalidates instead... */ if (!batch->active) { - flush_hash_page(vaddr, rpte, psize, ssize, 0); + flush_hash_page(vpn, rpte, psize, ssize, 0); put_cpu_var(ppc64_tlb_batch); return; } @@ -122,7 +123,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, batch->ssize = ssize; } batch->pte[i] = rpte; - batch->vaddr[i] = vaddr; + batch->vpn[i] = vpn; batch->index = ++i; if (i >= PPC64_TLB_BATCH_NR) __flush_tlb_pending(batch); @@ -146,7 +147,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch) if (cpumask_equal(mm_cpumask(batch->mm), tmp)) local = 1; if (i == 1) - flush_hash_page(batch->vaddr[0], batch->pte[0], + flush_hash_page(batch->vpn[0], batch->pte[0], batch->psize, batch->ssize, local); else flush_hash_range(i, local); diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S index f09d48e3268d..b4113bf86353 100644 --- a/arch/powerpc/mm/tlb_low_64e.S +++ b/arch/powerpc/mm/tlb_low_64e.S @@ -20,6 +20,8 @@ #include <asm/pgtable.h> #include <asm/exception-64e.h> #include <asm/ppc-opcode.h> +#include <asm/kvm_asm.h> +#include <asm/kvm_booke_hv_asm.h> #ifdef CONFIG_PPC_64K_PAGES #define VPTE_PMD_SHIFT (PTE_INDEX_SIZE+1) @@ -37,12 +39,18 @@ * * **********************************************************************/ -.macro tlb_prolog_bolted addr - mtspr SPRN_SPRG_TLB_SCRATCH,r13 +.macro tlb_prolog_bolted intnum addr + mtspr SPRN_SPRG_GEN_SCRATCH,r13 mfspr r13,SPRN_SPRG_PACA std r10,PACA_EXTLB+EX_TLB_R10(r13) mfcr r10 std r11,PACA_EXTLB+EX_TLB_R11(r13) +#ifdef CONFIG_KVM_BOOKE_HV +BEGIN_FTR_SECTION + mfspr r11, SPRN_SRR1 +END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) +#endif + DO_KVM \intnum, SPRN_SRR1 std r16,PACA_EXTLB+EX_TLB_R16(r13) mfspr r16,\addr /* get faulting address */ std r14,PACA_EXTLB+EX_TLB_R14(r13) @@ -61,12 +69,12 @@ ld r15,PACA_EXTLB+EX_TLB_R15(r13) TLB_MISS_RESTORE_STATS_BOLTED ld r16,PACA_EXTLB+EX_TLB_R16(r13) - mfspr r13,SPRN_SPRG_TLB_SCRATCH + mfspr r13,SPRN_SPRG_GEN_SCRATCH .endm /* Data TLB miss */ START_EXCEPTION(data_tlb_miss_bolted) - tlb_prolog_bolted SPRN_DEAR + tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR /* We need _PAGE_PRESENT and _PAGE_ACCESSED set */ @@ -214,7 +222,7 @@ itlb_miss_fault_bolted: /* Instruction TLB miss */ START_EXCEPTION(instruction_tlb_miss_bolted) - tlb_prolog_bolted SPRN_SRR0 + tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0 rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4 srdi r15,r16,60 /* get region */ diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index 95ae77dec3f6..315f9495e9b2 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -21,6 +21,13 @@ #include <asm/reg.h> #define dbg(args...) +#define OPROFILE_PM_PMCSEL_MSK 0xffULL +#define OPROFILE_PM_UNIT_SHIFT 60 +#define OPROFILE_PM_UNIT_MSK 0xfULL +#define OPROFILE_MAX_PMC_NUM 3 +#define OPROFILE_PMSEL_FIELD_WIDTH 8 +#define OPROFILE_UNIT_FIELD_WIDTH 4 +#define MMCRA_SIAR_VALID_MASK 0x10000000ULL static unsigned long reset_value[OP_MAX_COUNTER]; @@ -31,6 +38,61 @@ static int use_slot_nums; static u32 mmcr0_val; static u64 mmcr1_val; static u64 mmcra_val; +static u32 cntr_marked_events; + +static int power7_marked_instr_event(u64 mmcr1) +{ + u64 psel, unit; + int pmc, cntr_marked_events = 0; + + /* Given the MMCR1 value, look at the field for each counter to + * determine if it is a marked event. Code based on the function + * power7_marked_instr_event() in file arch/powerpc/perf/power7-pmu.c. + */ + for (pmc = 0; pmc < 4; pmc++) { + psel = mmcr1 & (OPROFILE_PM_PMCSEL_MSK + << (OPROFILE_MAX_PMC_NUM - pmc) + * OPROFILE_MAX_PMC_NUM); + psel = (psel >> ((OPROFILE_MAX_PMC_NUM - pmc) + * OPROFILE_PMSEL_FIELD_WIDTH)) & ~1ULL; + unit = mmcr1 & (OPROFILE_PM_UNIT_MSK + << (OPROFILE_PM_UNIT_SHIFT + - (pmc * OPROFILE_PMSEL_FIELD_WIDTH ))); + unit = unit >> (OPROFILE_PM_UNIT_SHIFT + - (pmc * OPROFILE_PMSEL_FIELD_WIDTH)); + + switch (psel >> 4) { + case 2: + cntr_marked_events |= (pmc == 1 || pmc == 3) << pmc; + break; + case 3: + if (psel == 0x3c) { + cntr_marked_events |= (pmc == 0) << pmc; + break; + } + + if (psel == 0x3e) { + cntr_marked_events |= (pmc != 1) << pmc; + break; + } + + cntr_marked_events |= 1 << pmc; + break; + case 4: + case 5: + cntr_marked_events |= (unit == 0xd) << pmc; + break; + case 6: + if (psel == 0x64) + cntr_marked_events |= (pmc >= 2) << pmc; + break; + case 8: + cntr_marked_events |= (unit == 0xd) << pmc; + break; + } + } + return cntr_marked_events; +} static int power4_reg_setup(struct op_counter_config *ctr, struct op_system_config *sys, @@ -47,6 +109,23 @@ static int power4_reg_setup(struct op_counter_config *ctr, mmcr1_val = sys->mmcr1; mmcra_val = sys->mmcra; + /* Power 7+ and newer architectures: + * Determine which counter events in the group (the group of events is + * specified by the bit settings in the MMCR1 register) are marked + * events for use in the interrupt handler. Do the calculation once + * before OProfile starts. Information is used in the interrupt + * handler. Starting with Power 7+ we only record the sample for + * marked events if the SIAR valid bit is set. For non marked events + * the sample is always recorded. + */ + if (pvr_version_is(PVR_POWER7p)) + cntr_marked_events = power7_marked_instr_event(mmcr1_val); + else + cntr_marked_events = 0; /* For older processors, set the bit map + * to zero so the sample will always be + * be recorded. + */ + for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) reset_value[i] = 0x80000000UL - ctr[i].count; @@ -61,10 +140,10 @@ static int power4_reg_setup(struct op_counter_config *ctr, else mmcr0_val |= MMCR0_PROBLEM_DISABLE; - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) || - __is_processor(PV_970) || __is_processor(PV_970FX) || - __is_processor(PV_970MP) || __is_processor(PV_970GX) || - __is_processor(PV_POWER5) || __is_processor(PV_POWER5p)) + if (pvr_version_is(PVR_POWER4) || pvr_version_is(PVR_POWER4p) || + pvr_version_is(PVR_970) || pvr_version_is(PVR_970FX) || + pvr_version_is(PVR_970MP) || pvr_version_is(PVR_970GX) || + pvr_version_is(PVR_POWER5) || pvr_version_is(PVR_POWER5p)) use_slot_nums = 1; return 0; @@ -84,9 +163,9 @@ extern void ppc_enable_pmcs(void); */ static inline int mmcra_must_set_sample(void) { - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) || - __is_processor(PV_970) || __is_processor(PV_970FX) || - __is_processor(PV_970MP) || __is_processor(PV_970GX)) + if (pvr_version_is(PVR_POWER4) || pvr_version_is(PVR_POWER4p) || + pvr_version_is(PVR_970) || pvr_version_is(PVR_970FX) || + pvr_version_is(PVR_970MP) || pvr_version_is(PVR_970GX)) return 1; return 0; @@ -276,7 +355,7 @@ static bool pmc_overflow(unsigned long val) * PMCs because a user might set a period of less than 256 and we * don't want to mistakenly reset them. */ - if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256)) + if (pvr_version_is(PVR_POWER7) && ((0x80000000 - val) <= 256)) return true; return false; @@ -291,6 +370,7 @@ static void power4_handle_interrupt(struct pt_regs *regs, int i; unsigned int mmcr0; unsigned long mmcra; + bool siar_valid = false; mmcra = mfspr(SPRN_MMCRA); @@ -300,11 +380,29 @@ static void power4_handle_interrupt(struct pt_regs *regs, /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); + /* Check that the SIAR valid bit in MMCRA is set to 1. */ + if ((mmcra & MMCRA_SIAR_VALID_MASK) == MMCRA_SIAR_VALID_MASK) + siar_valid = true; + for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) { val = classic_ctr_read(i); if (pmc_overflow(val)) { if (oprofile_running && ctr[i].enabled) { - oprofile_add_ext_sample(pc, regs, i, is_kernel); + /* Power 7+ and newer architectures: + * If the event is a marked event, then only + * save the sample if the SIAR valid bit is + * set. If the event is not marked, then + * always save the sample. + * Note, the Sample enable bit in the MMCRA + * register must be set to 1 if the group + * contains a marked event. + */ + if ((siar_valid && + (cntr_marked_events & (1 << i))) + || !(cntr_marked_events & (1 << i))) + oprofile_add_ext_sample(pc, regs, i, + is_kernel); + classic_ctr_write(i, reset_value[i]); } else { classic_ctr_write(i, 0); diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 7cd2dbd6e4c4..0db88f501f91 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -82,6 +82,11 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs) return 0; } +static inline int siar_valid(struct pt_regs *regs) +{ + return 1; +} + #endif /* CONFIG_PPC32 */ /* @@ -106,14 +111,20 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) * If we're not doing instruction sampling, give them the SDAR * (sampled data address). If we are doing instruction sampling, then * only give them the SDAR if it corresponds to the instruction - * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC - * bit in MMCRA. + * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC or + * the [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA. */ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { unsigned long mmcra = regs->dsisr; - unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ? - POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC; + unsigned long sdsync; + + if (ppmu->flags & PPMU_SIAR_VALID) + sdsync = POWER7P_MMCRA_SDAR_VALID; + else if (ppmu->flags & PPMU_ALT_SIPR) + sdsync = POWER6_MMCRA_SDSYNC; + else + sdsync = MMCRA_SDSYNC; if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync)) *addrp = mfspr(SPRN_SDAR); @@ -230,6 +241,24 @@ static inline int perf_intr_is_nmi(struct pt_regs *regs) return !regs->softe; } +/* + * On processors like P7+ that have the SIAR-Valid bit, marked instructions + * must be sampled only if the SIAR-valid bit is set. + * + * For unmarked instructions and for processors that don't have the SIAR-Valid + * bit, assume that SIAR is valid. + */ +static inline int siar_valid(struct pt_regs *regs) +{ + unsigned long mmcra = regs->dsisr; + int marked = mmcra & MMCRA_SAMPLE_ENABLE; + + if ((ppmu->flags & PPMU_SIAR_VALID) && marked) + return mmcra & POWER7P_MMCRA_SIAR_VALID; + + return 1; +} + #endif /* CONFIG_PPC64 */ static void perf_event_interrupt(struct pt_regs *regs); @@ -1291,6 +1320,7 @@ struct pmu power_pmu = { .event_idx = power_pmu_event_idx, }; + /* * A counter has overflowed; update its count and record * things if requested. Note that interrupts are hard-disabled @@ -1324,7 +1354,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, left += period; if (left <= 0) left = period; - record = 1; + record = siar_valid(regs); event->hw.last_period = event->hw.sample_period; } if (left < 0x80000000LL) @@ -1374,8 +1404,10 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) { unsigned long use_siar = regs->result; - if (use_siar) + if (use_siar && siar_valid(regs)) return mfspr(SPRN_SIAR) + perf_ip_adjust(regs); + else if (use_siar) + return 0; // no valid instruction pointer else return regs->nip; } @@ -1396,7 +1428,7 @@ static bool pmc_overflow(unsigned long val) * PMCs because a user might set a period of less than 256 and we * don't want to mistakenly reset them. */ - if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256)) + if (pvr_version_is(PVR_POWER7) && ((0x80000000 - val) <= 256)) return true; return false; diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 1251e4d7e262..441af08edf43 100644 --- a/arch/powerpc/perf/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c @@ -373,6 +373,9 @@ static int __init init_power7_pmu(void) strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7")) return -ENODEV; + if (pvr_version_is(PVR_POWER7p)) + power7_pmu.flags |= PPMU_SIAR_VALID; + return register_power_pmu(&power7_pmu); } diff --git a/arch/powerpc/platforms/40x/ppc40x_simple.c b/arch/powerpc/platforms/40x/ppc40x_simple.c index 97612068fae3..969dddcf3320 100644 --- a/arch/powerpc/platforms/40x/ppc40x_simple.c +++ b/arch/powerpc/platforms/40x/ppc40x_simple.c @@ -50,7 +50,7 @@ machine_device_initcall(ppc40x_simple, ppc40x_device_probe); * Again, if your board needs to do things differently then create a * board.c file for it rather than adding it to this list. */ -static const char *board[] __initdata = { +static const char * const board[] __initconst = { "amcc,acadia", "amcc,haleakala", "amcc,kilauea", diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c index 9f6c33d63a42..6bd89a0e0dea 100644 --- a/arch/powerpc/platforms/44x/currituck.c +++ b/arch/powerpc/platforms/44x/currituck.c @@ -21,7 +21,6 @@ */ #include <linux/init.h> -#include <linux/memblock.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/rtc.h> @@ -159,13 +158,8 @@ static void __init ppc47x_setup_arch(void) /* No need to check the DMA config as we /know/ our windows are all of * RAM. Lets hope that doesn't change */ -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > 0xffffffff) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + swiotlb_detect_4g(); + ppc47x_smp_init(); } diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index c16999802ecf..b62508b113db 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -2,6 +2,7 @@ config PPC_MPC512x bool "512x-based boards" depends on 6xx select FSL_SOC + select FB_FSL_DIU select IPIC select PPC_CLOCK select PPC_PCI_CHOICE diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c index 1d8700ff60b0..9f771e05457c 100644 --- a/arch/powerpc/platforms/512x/clock.c +++ b/arch/powerpc/platforms/512x/clock.c @@ -54,14 +54,16 @@ static DEFINE_MUTEX(clocks_mutex); static struct clk *mpc5121_clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); - int dev_match = 0; - int id_match = 0; + int dev_match; + int id_match; if (dev == NULL || id == NULL) return clk; mutex_lock(&clocks_mutex); list_for_each_entry(p, &clocks, node) { + dev_match = id_match = 0; + if (dev == p->dev) dev_match++; if (strcmp(id, p->name) == 0) diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c index 926731f1ff01..ca1ca6669990 100644 --- a/arch/powerpc/platforms/512x/mpc5121_generic.c +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c @@ -26,7 +26,7 @@ /* * list of supported boards */ -static const char *board[] __initdata = { +static const char * const board[] __initconst = { "prt,prtlvt", NULL }; diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index cfe958e94e1e..1650e090ef3a 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -191,8 +191,6 @@ mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port) static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; -#if defined(CONFIG_FB_FSL_DIU) || \ - defined(CONFIG_FB_FSL_DIU_MODULE) static inline void mpc512x_free_bootmem(struct page *page) { __ClearPageReserved(page); @@ -220,7 +218,6 @@ void mpc512x_release_bootmem(void) } diu_ops.release_bootmem = NULL; } -#endif /* * Check if DIU was pre-initialized. If so, perform steps @@ -323,15 +320,12 @@ void __init mpc512x_setup_diu(void) } } -#if defined(CONFIG_FB_FSL_DIU) || \ - defined(CONFIG_FB_FSL_DIU_MODULE) diu_ops.get_pixel_format = mpc512x_get_pixel_format; diu_ops.set_gamma_table = mpc512x_set_gamma_table; diu_ops.set_monitor_port = mpc512x_set_monitor_port; diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; diu_ops.valid_monitor_port = mpc512x_valid_monitor_port; diu_ops.release_bootmem = mpc512x_release_bootmem; -#endif } void __init mpc512x_init_IRQ(void) diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 01ffa64d2aa7..448d862bcf3d 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -172,7 +172,7 @@ static void __init lite5200_setup_arch(void) mpc52xx_setup_pci(); } -static const char *board[] __initdata = { +static const char * const board[] __initconst = { "fsl,lite5200", "fsl,lite5200b", NULL, diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 17d91b7da315..070d315dd6cd 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c @@ -232,7 +232,7 @@ static void __init media5200_setup_arch(void) } /* list of the supported boards */ -static const char *board[] __initdata = { +static const char * const board[] __initconst = { "fsl,media5200", NULL }; diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index c0aa04068d69..9cf36020cf0d 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -52,6 +52,7 @@ static void __init mpc5200_simple_setup_arch(void) static const char *board[] __initdata = { "anonymous,a4m072", "anon,charon", + "ifm,o2d", "intercontrol,digsy-mtc", "manroland,mucmc52", "manroland,uc101", diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c index d61fb1c0c1a0..2351f9e0fb6f 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c @@ -170,7 +170,8 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bit_fields); /* Kick it off */ - out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); + if (!lpbfifo.req->defer_xfer_start) + out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); if (dma) bcom_enable(lpbfifo.bcom_cur_task); } @@ -421,6 +422,38 @@ int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req) } EXPORT_SYMBOL(mpc52xx_lpbfifo_submit); +int mpc52xx_lpbfifo_start_xfer(struct mpc52xx_lpbfifo_request *req) +{ + unsigned long flags; + + if (!lpbfifo.regs) + return -ENODEV; + + spin_lock_irqsave(&lpbfifo.lock, flags); + + /* + * If the req pointer is already set and a transfer was + * started on submit, then this transfer is in progress + */ + if (lpbfifo.req && !lpbfifo.req->defer_xfer_start) { + spin_unlock_irqrestore(&lpbfifo.lock, flags); + return -EBUSY; + } + + /* + * If the req was previously submitted but not + * started, start it now + */ + if (lpbfifo.req && lpbfifo.req == req && + lpbfifo.req->defer_xfer_start) { + out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); + } + + spin_unlock_irqrestore(&lpbfifo.lock, flags); + return 0; +} +EXPORT_SYMBOL(mpc52xx_lpbfifo_start_xfer); + void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req) { unsigned long flags; diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c index 16c9c9cbbb7f..eca1f0960fff 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c @@ -60,7 +60,7 @@ static void __init mpc837x_rdb_setup_arch(void) machine_device_initcall(mpc837x_rdb, mpc83xx_declare_of_platform_devices); -static const char *board[] __initdata = { +static const char * const board[] __initconst = { "fsl,mpc8377rdb", "fsl,mpc8378rdb", "fsl,mpc8379rdb", diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 159c01e91463..02d02a09942d 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -104,6 +104,13 @@ config P1022_DS help This option enables support for the Freescale P1022DS reference board. +config P1022_RDK + bool "Freescale / iVeia P1022 RDK" + select DEFAULT_UIMAGE + help + This option enables support for the Freescale / iVeia P1022RDK + reference board. + config P1023_RDS bool "Freescale P1023 RDS" select DEFAULT_UIMAGE @@ -254,6 +261,20 @@ config P5020_DS help This option enables support for the P5020 DS board +config P5040_DS + bool "Freescale P5040 DS" + select DEFAULT_UIMAGE + select E500 + select PPC_E500MC + select PHYS_64BIT + select SWIOTLB + select ARCH_REQUIRE_GPIOLIB + select GPIO_MPC8XXX + select HAS_RAPIDIO + select PPC_EPAPR_HV_PIC + help + This option enables support for the P5040 DS board + config PPC_QEMU_E500 bool "QEMU generic e500 platform" depends on EXPERIMENTAL diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 3dfe81175036..76f679cb04a0 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -15,11 +15,13 @@ obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o obj-$(CONFIG_P1010_RDB) += p1010rdb.o obj-$(CONFIG_P1022_DS) += p1022_ds.o +obj-$(CONFIG_P1022_RDK) += p1022_rdk.o obj-$(CONFIG_P1023_RDS) += p1023_rds.o obj-$(CONFIG_P2041_RDB) += p2041_rdb.o corenet_ds.o obj-$(CONFIG_P3041_DS) += p3041_ds.o corenet_ds.o obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o obj-$(CONFIG_P5020_DS) += p5020_ds.o corenet_ds.o +obj-$(CONFIG_P5040_DS) += p5040_ds.o corenet_ds.o obj-$(CONFIG_STX_GP3) += stx_gp3.o obj-$(CONFIG_TQM85xx) += tqm85xx.o obj-$(CONFIG_SBC8548) += sbc8548.o diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c index 67dac22b4363..d0861a0d8360 100644 --- a/arch/powerpc/platforms/85xx/common.c +++ b/arch/powerpc/platforms/85xx/common.c @@ -27,6 +27,16 @@ static struct of_device_id __initdata mpc85xx_common_ids[] = { { .compatible = "fsl,mpc8548-guts", }, /* Probably unnecessary? */ { .compatible = "gpio-leds", }, + /* For all PCI controllers */ + { .compatible = "fsl,mpc8540-pci", }, + { .compatible = "fsl,mpc8548-pcie", }, + { .compatible = "fsl,p1022-pcie", }, + { .compatible = "fsl,p1010-pcie", }, + { .compatible = "fsl,p1023-pcie", }, + { .compatible = "fsl,p4080-pcie", }, + { .compatible = "fsl,qoriq-pcie-v2.4", }, + { .compatible = "fsl,qoriq-pcie-v2.3", }, + { .compatible = "fsl,qoriq-pcie-v2.2", }, {}, }; diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index 925b02874233..ed69c9250717 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/arch/powerpc/platforms/85xx/corenet_ds.c @@ -16,7 +16,6 @@ #include <linux/kdev_t.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/memblock.h> #include <asm/time.h> #include <asm/machdep.h> @@ -52,37 +51,16 @@ void __init corenet_ds_pic_init(void) */ void __init corenet_ds_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; - struct pci_controller *hose; -#endif - dma_addr_t max = 0xffffffff; - mpc85xx_smp_init(); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,p4080-pcie") || - of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2")) { - fsl_add_bridge(np, 0); - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } - } - -#ifdef CONFIG_PPC64 +#if defined(CONFIG_PCI) && defined(CONFIG_PPC64) pci_devs_phb_init(); #endif -#endif -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + fsl_pci_assign_primary(); + + swiotlb_detect_4g(); + pr_info("%s board from Freescale Semiconductor\n", ppc_md.name); } @@ -99,6 +77,12 @@ static const struct of_device_id of_device_ids[] __devinitconst = { { .compatible = "fsl,qoriq-pcie-v2.2", }, + { + .compatible = "fsl,qoriq-pcie-v2.3", + }, + { + .compatible = "fsl,qoriq-pcie-v2.4", + }, /* The following two are for the Freescale hypervisor */ { .name = "hypervisor", diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c index b6a728b0a8ca..e6285ae6f423 100644 --- a/arch/powerpc/platforms/85xx/ge_imp3a.c +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -22,7 +22,6 @@ #include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/of_platform.h> -#include <linux/memblock.h> #include <asm/time.h> #include <asm/machdep.h> @@ -84,53 +83,39 @@ void __init ge_imp3a_pic_init(void) of_node_put(cascade_node); } -#ifdef CONFIG_PCI -static int primary_phb_addr; -#endif /* CONFIG_PCI */ - -/* - * Setup the architecture - */ -static void __init ge_imp3a_setup_arch(void) +static void ge_imp3a_pci_assign_primary(void) { - struct device_node *regs; #ifdef CONFIG_PCI struct device_node *np; - struct pci_controller *hose; -#endif - dma_addr_t max = 0xffffffff; + struct resource rsrc; - if (ppc_md.progress) - ppc_md.progress("ge_imp3a_setup_arch()", 0); - -#ifdef CONFIG_PCI for_each_node_by_type(np, "pci") { if (of_device_is_compatible(np, "fsl,mpc8540-pci") || of_device_is_compatible(np, "fsl,mpc8548-pcie") || of_device_is_compatible(np, "fsl,p2020-pcie")) { - struct resource rsrc; of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == primary_phb_addr) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); + if ((rsrc.start & 0xfffff) == 0x9000) + fsl_pci_primary = np; } } #endif +} + +/* + * Setup the architecture + */ +static void __init ge_imp3a_setup_arch(void) +{ + struct device_node *regs; + + if (ppc_md.progress) + ppc_md.progress("ge_imp3a_setup_arch()", 0); mpc85xx_smp_init(); -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + ge_imp3a_pci_assign_primary(); + + swiotlb_detect_4g(); /* Remap basic board registers */ regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs"); @@ -215,17 +200,10 @@ static int __init ge_imp3a_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (of_flat_dt_is_compatible(root, "ge,IMP3A")) { -#ifdef CONFIG_PCI - primary_phb_addr = 0x9000; -#endif - return 1; - } - - return 0; + return of_flat_dt_is_compatible(root, "ge,IMP3A"); } -machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices); +machine_arch_initcall(ge_imp3a, mpc85xx_common_publish_devices); machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index 767c7cf18a9c..15ce4b55f117 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -17,7 +17,6 @@ #include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/of_platform.h> -#include <linux/memblock.h> #include <asm/time.h> #include <asm/machdep.h> @@ -46,46 +45,17 @@ void __init mpc8536_ds_pic_init(void) */ static void __init mpc8536_ds_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; - struct pci_controller *hose; -#endif - dma_addr_t max = 0xffffffff; - if (ppc_md.progress) ppc_md.progress("mpc8536_ds_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } - } - -#endif + fsl_pci_assign_primary(); -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + swiotlb_detect_4g(); printk("MPC8536 DS board from Freescale Semiconductor\n"); } -machine_device_initcall(mpc8536_ds, mpc85xx_common_publish_devices); +machine_arch_initcall(mpc8536_ds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8536_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 29ee8fcd75a2..7d12a19aa7ee 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -137,10 +137,6 @@ static void __init init_ioports(void) static void __init mpc85xx_ads_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("mpc85xx_ads_setup_arch()", 0); @@ -150,11 +146,10 @@ static void __init mpc85xx_ads_setup_arch(void) #endif #ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") - fsl_add_bridge(np, 1); - ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif + + fsl_pci_assign_primary(); } static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) @@ -173,7 +168,7 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -machine_device_initcall(mpc85xx_ads, mpc85xx_common_publish_devices); +machine_arch_initcall(mpc85xx_ads, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 11156fb53d83..c474505ad0d0 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -276,6 +276,33 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); #endif /* CONFIG_PPC_I8259 */ +static void mpc85xx_cds_pci_assign_primary(void) +{ +#ifdef CONFIG_PCI + struct device_node *np; + + if (fsl_pci_primary) + return; + + /* + * MPC85xx_CDS has ISA bridge but unfortunately there is no + * isa node in device tree. We now looking for i8259 node as + * a workaround for such a broken device tree. This routine + * is for complying to all device trees. + */ + np = of_find_node_by_name(NULL, "i8259"); + while ((fsl_pci_primary = of_get_parent(np))) { + of_node_put(np); + np = fsl_pci_primary; + + if ((of_device_is_compatible(np, "fsl,mpc8540-pci") || + of_device_is_compatible(np, "fsl,mpc8548-pcie")) && + of_device_is_available(np)) + return; + } +#endif +} + /* * Setup the architecture */ @@ -309,21 +336,12 @@ static void __init mpc85xx_cds_setup_arch(void) } #ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - } - } - ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif + + mpc85xx_cds_pci_assign_primary(); + fsl_pci_assign_primary(); } static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) @@ -355,7 +373,7 @@ static int __init mpc85xx_cds_probe(void) return of_flat_dt_is_compatible(root, "MPC85xxCDS"); } -machine_device_initcall(mpc85xx_cds, mpc85xx_common_publish_devices); +machine_arch_initcall(mpc85xx_cds, mpc85xx_common_publish_devices); define_machine(mpc85xx_cds) { .name = "MPC85xx CDS", diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 6d3265fe7718..9ebb91ed96a3 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -20,7 +20,6 @@ #include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/of_platform.h> -#include <linux/memblock.h> #include <asm/time.h> #include <asm/machdep.h> @@ -129,13 +128,11 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, } #endif /* CONFIG_PCI */ -static void __init mpc85xx_ds_pci_init(void) +static void __init mpc85xx_ds_uli_init(void) { #ifdef CONFIG_PCI struct device_node *node; - fsl_pci_init(); - /* See if we have a ULI under the primary */ node = of_find_node_by_name(NULL, "uli1575"); @@ -159,7 +156,9 @@ static void __init mpc85xx_ds_setup_arch(void) if (ppc_md.progress) ppc_md.progress("mpc85xx_ds_setup_arch()", 0); - mpc85xx_ds_pci_init(); + swiotlb_detect_4g(); + fsl_pci_assign_primary(); + mpc85xx_ds_uli_init(); mpc85xx_smp_init(); printk("MPC85xx DS board from Freescale Semiconductor\n"); @@ -175,9 +174,9 @@ static int __init mpc8544_ds_probe(void) return !!of_flat_dt_is_compatible(root, "MPC8544DS"); } -machine_device_initcall(mpc8544_ds, mpc85xx_common_publish_devices); -machine_device_initcall(mpc8572_ds, mpc85xx_common_publish_devices); -machine_device_initcall(p2020_ds, mpc85xx_common_publish_devices); +machine_arch_initcall(mpc8544_ds, mpc85xx_common_publish_devices); +machine_arch_initcall(mpc8572_ds, mpc85xx_common_publish_devices); +machine_arch_initcall(p2020_ds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8544_ds, swiotlb_setup_bus_notifier); machine_arch_initcall(mpc8572_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 8e4b094c553b..8498f7323470 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -327,44 +327,16 @@ static void __init mpc85xx_mds_qeic_init(void) { } static void __init mpc85xx_mds_setup_arch(void) { -#ifdef CONFIG_PCI - struct pci_controller *hose; - struct device_node *np; -#endif - dma_addr_t max = 0xffffffff; - if (ppc_md.progress) ppc_md.progress("mpc85xx_mds_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } - } -#endif - mpc85xx_smp_init(); mpc85xx_mds_qe_init(); -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + fsl_pci_assign_primary(); + + swiotlb_detect_4g(); } @@ -409,9 +381,9 @@ static int __init mpc85xx_publish_devices(void) return mpc85xx_common_publish_devices(); } -machine_device_initcall(mpc8568_mds, mpc85xx_publish_devices); -machine_device_initcall(mpc8569_mds, mpc85xx_publish_devices); -machine_device_initcall(p1021_mds, mpc85xx_common_publish_devices); +machine_arch_initcall(mpc8568_mds, mpc85xx_publish_devices); +machine_arch_initcall(mpc8569_mds, mpc85xx_publish_devices); +machine_arch_initcall(p1021_mds, mpc85xx_common_publish_devices); machine_arch_initcall(mpc8568_mds, swiotlb_setup_bus_notifier); machine_arch_initcall(mpc8569_mds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index 1910fdcb75b2..ede8771d6f02 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -86,23 +86,17 @@ void __init mpc85xx_rdb_pic_init(void) */ static void __init mpc85xx_rdb_setup_arch(void) { -#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE) +#ifdef CONFIG_QUICC_ENGINE struct device_node *np; #endif if (ppc_md.progress) ppc_md.progress("mpc85xx_rdb_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8548-pcie")) - fsl_add_bridge(np, 0); - } - -#endif - mpc85xx_smp_init(); + fsl_pci_assign_primary(); + #ifdef CONFIG_QUICC_ENGINE np = of_find_compatible_node(NULL, NULL, "fsl,qe"); if (!np) { @@ -161,15 +155,15 @@ qe_fail: printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); } -machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); -machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices); -machine_device_initcall(p1024_rdb, mpc85xx_common_publish_devices); +machine_arch_initcall(p2020_rdb, mpc85xx_common_publish_devices); +machine_arch_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); +machine_arch_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices); +machine_arch_initcall(p1020_rdb, mpc85xx_common_publish_devices); +machine_arch_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); +machine_arch_initcall(p1020_utm_pc, mpc85xx_common_publish_devices); +machine_arch_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); +machine_arch_initcall(p1025_rdb, mpc85xx_common_publish_devices); +machine_arch_initcall(p1024_rdb, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index dbaf44354f0d..0252961392d5 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -46,25 +46,15 @@ void __init p1010_rdb_pic_init(void) */ static void __init p1010_rdb_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("p1010_rdb_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,p1010-pcie")) - fsl_add_bridge(np, 0); - } - -#endif + fsl_pci_assign_primary(); printk(KERN_INFO "P1010 RDB board from Freescale Semiconductor\n"); } -machine_device_initcall(p1010_rdb, mpc85xx_common_publish_devices); +machine_arch_initcall(p1010_rdb, mpc85xx_common_publish_devices); machine_arch_initcall(p1010_rdb, swiotlb_setup_bus_notifier); /* diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 3c732acf331d..848a3e98e1c1 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -18,7 +18,6 @@ #include <linux/pci.h> #include <linux/of_platform.h> -#include <linux/memblock.h> #include <asm/div64.h> #include <asm/mpic.h> #include <asm/swiotlb.h> @@ -507,32 +506,9 @@ early_param("video", early_video_setup); */ static void __init p1022_ds_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - dma_addr_t max = 0xffffffff; - if (ppc_md.progress) ppc_md.progress("p1022_ds_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,p1022-pcie") { - struct resource rsrc; - struct pci_controller *hose; - - of_address_to_resource(np, 0, &rsrc); - - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } -#endif - #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) diu_ops.get_pixel_format = p1022ds_get_pixel_format; diu_ops.set_gamma_table = p1022ds_set_gamma_table; @@ -601,18 +577,14 @@ static void __init p1022_ds_setup_arch(void) mpc85xx_smp_init(); -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + fsl_pci_assign_primary(); + + swiotlb_detect_4g(); pr_info("Freescale P1022 DS reference board\n"); } -machine_device_initcall(p1022_ds, mpc85xx_common_publish_devices); +machine_arch_initcall(p1022_ds, mpc85xx_common_publish_devices); machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c new file mode 100644 index 000000000000..55ffa1cc380c --- /dev/null +++ b/arch/powerpc/platforms/85xx/p1022_rdk.c @@ -0,0 +1,167 @@ +/* + * P1022 RDK board specific routines + * + * Copyright 2012 Freescale Semiconductor, Inc. + * + * Author: Timur Tabi <timur@freescale.com> + * + * Based on p1022_ds.c + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/pci.h> +#include <linux/of_platform.h> +#include <asm/div64.h> +#include <asm/mpic.h> +#include <asm/swiotlb.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> +#include <asm/udbg.h> +#include <asm/fsl_guts.h> +#include "smp.h" + +#include "mpc85xx.h" + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + +/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ +#define CLKDVDR_PXCKEN 0x80000000 +#define CLKDVDR_PXCKINV 0x10000000 +#define CLKDVDR_PXCKDLY 0x06000000 +#define CLKDVDR_PXCLK_MASK 0x00FF0000 + +/** + * p1022rdk_set_monitor_port: switch the output to a different monitor port + */ +static void p1022rdk_set_monitor_port(enum fsl_diu_monitor_port port) +{ + if (port != FSL_DIU_PORT_DVI) { + pr_err("p1022rdk: unsupported monitor port %i\n", port); + return; + } +} + +/** + * p1022rdk_set_pixel_clock: program the DIU's clock + * + * @pixclock: the wavelength, in picoseconds, of the clock + */ +void p1022rdk_set_pixel_clock(unsigned int pixclock) +{ + struct device_node *guts_np = NULL; + struct ccsr_guts __iomem *guts; + unsigned long freq; + u64 temp; + u32 pxclk; + + /* Map the global utilities registers. */ + guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); + if (!guts_np) { + pr_err("p1022rdk: missing global utilties device node\n"); + return; + } + + guts = of_iomap(guts_np, 0); + of_node_put(guts_np); + if (!guts) { + pr_err("p1022rdk: could not map global utilties device\n"); + return; + } + + /* Convert pixclock from a wavelength to a frequency */ + temp = 1000000000000ULL; + do_div(temp, pixclock); + freq = temp; + + /* + * 'pxclk' is the ratio of the platform clock to the pixel clock. + * This number is programmed into the CLKDVDR register, and the valid + * range of values is 2-255. + */ + pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); + pxclk = clamp_t(u32, pxclk, 2, 255); + + /* Disable the pixel clock, and set it to non-inverted and no delay */ + clrbits32(&guts->clkdvdr, + CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); + + /* Enable the clock and set the pxclk */ + setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); + + iounmap(guts); +} + +/** + * p1022rdk_valid_monitor_port: set the monitor port for sysfs + */ +enum fsl_diu_monitor_port +p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port) +{ + return FSL_DIU_PORT_DVI; +} + +#endif + +void __init p1022_rdk_pic_init(void) +{ + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, + 0, 256, " OpenPIC "); + BUG_ON(mpic == NULL); + mpic_init(mpic); +} + +/* + * Setup the architecture + */ +static void __init p1022_rdk_setup_arch(void) +{ + if (ppc_md.progress) + ppc_md.progress("p1022_rdk_setup_arch()", 0); + +#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + diu_ops.set_monitor_port = p1022rdk_set_monitor_port; + diu_ops.set_pixel_clock = p1022rdk_set_pixel_clock; + diu_ops.valid_monitor_port = p1022rdk_valid_monitor_port; +#endif + + mpc85xx_smp_init(); + + fsl_pci_assign_primary(); + + swiotlb_detect_4g(); + + pr_info("Freescale / iVeia P1022 RDK reference board\n"); +} + +machine_arch_initcall(p1022_rdk, mpc85xx_common_publish_devices); + +machine_arch_initcall(p1022_rdk, swiotlb_setup_bus_notifier); + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init p1022_rdk_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,p1022rdk"); +} + +define_machine(p1022_rdk) { + .name = "P1022 RDK", + .probe = p1022_rdk_probe, + .setup_arch = p1022_rdk_setup_arch, + .init_IRQ = p1022_rdk_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif + .get_irq = mpic_get_irq, + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index 2990e8b13dc9..9cc60a738834 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c @@ -80,15 +80,12 @@ static void __init mpc85xx_rds_setup_arch(void) } } -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,p1023-pcie") - fsl_add_bridge(np, 0); -#endif - mpc85xx_smp_init(); + + fsl_pci_assign_primary(); } -machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices); +machine_arch_initcall(p1023_rds, mpc85xx_common_publish_devices); static void __init mpc85xx_rds_pic_init(void) { diff --git a/arch/powerpc/platforms/85xx/p2041_rdb.c b/arch/powerpc/platforms/85xx/p2041_rdb.c index 6541fa2630c0..000c0892fc40 100644 --- a/arch/powerpc/platforms/85xx/p2041_rdb.c +++ b/arch/powerpc/platforms/85xx/p2041_rdb.c @@ -80,7 +80,7 @@ define_machine(p2041_rdb) { .power_save = e500_idle, }; -machine_device_initcall(p2041_rdb, corenet_ds_publish_devices); +machine_arch_initcall(p2041_rdb, corenet_ds_publish_devices); #ifdef CONFIG_SWIOTLB machine_arch_initcall(p2041_rdb, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/p3041_ds.c b/arch/powerpc/platforms/85xx/p3041_ds.c index f238efa75891..b3edc205daa9 100644 --- a/arch/powerpc/platforms/85xx/p3041_ds.c +++ b/arch/powerpc/platforms/85xx/p3041_ds.c @@ -82,7 +82,7 @@ define_machine(p3041_ds) { .power_save = e500_idle, }; -machine_device_initcall(p3041_ds, corenet_ds_publish_devices); +machine_arch_initcall(p3041_ds, corenet_ds_publish_devices); #ifdef CONFIG_SWIOTLB machine_arch_initcall(p3041_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/p4080_ds.c b/arch/powerpc/platforms/85xx/p4080_ds.c index c92417dc6574..54df10632aea 100644 --- a/arch/powerpc/platforms/85xx/p4080_ds.c +++ b/arch/powerpc/platforms/85xx/p4080_ds.c @@ -81,7 +81,7 @@ define_machine(p4080_ds) { .power_save = e500_idle, }; -machine_device_initcall(p4080_ds, corenet_ds_publish_devices); +machine_arch_initcall(p4080_ds, corenet_ds_publish_devices); #ifdef CONFIG_SWIOTLB machine_arch_initcall(p4080_ds, swiotlb_setup_bus_notifier); #endif diff --git a/arch/powerpc/platforms/85xx/p5020_ds.c b/arch/powerpc/platforms/85xx/p5020_ds.c index 17bef15a85ed..753a42c29d4d 100644 --- a/arch/powerpc/platforms/85xx/p5020_ds.c +++ b/arch/powerpc/platforms/85xx/p5020_ds.c @@ -91,7 +91,7 @@ define_machine(p5020_ds) { #endif }; -machine_device_initcall(p5020_ds, corenet_ds_publish_devices); +machine_arch_initcall(p5020_ds, corenet_ds_publish_devices); #ifdef CONFIG_SWIOTLB machine_arch_initcall(p5020_ds, swiotlb_setup_bus_notifier); diff --git a/arch/powerpc/platforms/85xx/p5040_ds.c b/arch/powerpc/platforms/85xx/p5040_ds.c new file mode 100644 index 000000000000..11381851828e --- /dev/null +++ b/arch/powerpc/platforms/85xx/p5040_ds.c @@ -0,0 +1,89 @@ +/* + * P5040 DS Setup + * + * Copyright 2009-2010 Freescale Semiconductor Inc. + * + * 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/kernel.h> +#include <linux/pci.h> + +#include <asm/machdep.h> +#include <asm/udbg.h> +#include <asm/mpic.h> + +#include <linux/of_fdt.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> +#include <asm/ehv_pic.h> + +#include "corenet_ds.h" + +/* + * Called very early, device-tree isn't unflattened + */ +static int __init p5040_ds_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); +#ifdef CONFIG_SMP + extern struct smp_ops_t smp_85xx_ops; +#endif + + if (of_flat_dt_is_compatible(root, "fsl,P5040DS")) + return 1; + + /* Check if we're running under the Freescale hypervisor */ + if (of_flat_dt_is_compatible(root, "fsl,P5040DS-hv")) { + ppc_md.init_IRQ = ehv_pic_init; + ppc_md.get_irq = ehv_pic_get_irq; + ppc_md.restart = fsl_hv_restart; + ppc_md.power_off = fsl_hv_halt; + ppc_md.halt = fsl_hv_halt; +#ifdef CONFIG_SMP + /* + * Disable the timebase sync operations because we can't write + * to the timebase registers under the hypervisor. + */ + smp_85xx_ops.give_timebase = NULL; + smp_85xx_ops.take_timebase = NULL; +#endif + return 1; + } + + return 0; +} + +define_machine(p5040_ds) { + .name = "P5040 DS", + .probe = p5040_ds_probe, + .setup_arch = corenet_ds_setup_arch, + .init_IRQ = corenet_ds_pic_init, +#ifdef CONFIG_PCI + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, +#endif +/* coreint doesn't play nice with lazy EE, use legacy mpic for now */ +#ifdef CONFIG_PPC64 + .get_irq = mpic_get_irq, +#else + .get_irq = mpic_get_coreint_irq, +#endif + .restart = fsl_rstcr_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +#ifdef CONFIG_PPC64 + .power_save = book3e_idle, +#else + .power_save = e500_idle, +#endif +}; + +machine_arch_initcall(p5040_ds, corenet_ds_publish_devices); + +#ifdef CONFIG_SWIOTLB +machine_arch_initcall(p5040_ds, swiotlb_setup_bus_notifier); +#endif diff --git a/arch/powerpc/platforms/85xx/qemu_e500.c b/arch/powerpc/platforms/85xx/qemu_e500.c index 95a2e53af71b..f6ea5618c733 100644 --- a/arch/powerpc/platforms/85xx/qemu_e500.c +++ b/arch/powerpc/platforms/85xx/qemu_e500.c @@ -41,7 +41,8 @@ static void __init qemu_e500_setup_arch(void) { ppc_md.progress("qemu_e500_setup_arch()", 0); - fsl_pci_init(); + fsl_pci_assign_primary(); + swiotlb_detect_4g(); mpc85xx_smp_init(); } @@ -55,7 +56,7 @@ static int __init qemu_e500_probe(void) return !!of_flat_dt_is_compatible(root, "fsl,qemu-e500"); } -machine_device_initcall(qemu_e500, mpc85xx_common_publish_devices); +machine_arch_initcall(qemu_e500, mpc85xx_common_publish_devices); define_machine(qemu_e500) { .name = "QEMU e500", diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index cd3a66bdb54b..f62121825914 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -88,26 +88,11 @@ static int __init sbc8548_hw_rev(void) */ static void __init sbc8548_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("sbc8548_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - } - } -#endif + fsl_pci_assign_primary(); + sbc_rev = sbc8548_hw_rev(); } @@ -128,7 +113,7 @@ static void sbc8548_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -machine_device_initcall(sbc8548, mpc85xx_common_publish_devices); +machine_arch_initcall(sbc8548, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index ff4249044a3c..6fcfa12e5c56 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -2,7 +2,7 @@ * Author: Andy Fleming <afleming@freescale.com> * Kumar Gala <galak@kernel.crashing.org> * - * Copyright 2006-2008, 2011 Freescale Semiconductor Inc. + * Copyright 2006-2008, 2011-2012 Freescale Semiconductor Inc. * * 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 @@ -17,6 +17,7 @@ #include <linux/of.h> #include <linux/kexec.h> #include <linux/highmem.h> +#include <linux/cpu.h> #include <asm/machdep.h> #include <asm/pgtable.h> @@ -24,33 +25,118 @@ #include <asm/mpic.h> #include <asm/cacheflush.h> #include <asm/dbell.h> +#include <asm/fsl_guts.h> #include <sysdev/fsl_soc.h> #include <sysdev/mpic.h> #include "smp.h" -extern void __early_start(void); - -#define BOOT_ENTRY_ADDR_UPPER 0 -#define BOOT_ENTRY_ADDR_LOWER 1 -#define BOOT_ENTRY_R3_UPPER 2 -#define BOOT_ENTRY_R3_LOWER 3 -#define BOOT_ENTRY_RESV 4 -#define BOOT_ENTRY_PIR 5 -#define BOOT_ENTRY_R6_UPPER 6 -#define BOOT_ENTRY_R6_LOWER 7 -#define NUM_BOOT_ENTRY 8 -#define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32)) - -static int __init -smp_85xx_kick_cpu(int nr) +struct epapr_spin_table { + u32 addr_h; + u32 addr_l; + u32 r3_h; + u32 r3_l; + u32 reserved; + u32 pir; +}; + +static struct ccsr_guts __iomem *guts; +static u64 timebase; +static int tb_req; +static int tb_valid; + +static void mpc85xx_timebase_freeze(int freeze) +{ + uint32_t mask; + + mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1; + if (freeze) + setbits32(&guts->devdisr, mask); + else + clrbits32(&guts->devdisr, mask); + + in_be32(&guts->devdisr); +} + +static void mpc85xx_give_timebase(void) +{ + unsigned long flags; + + local_irq_save(flags); + + while (!tb_req) + barrier(); + tb_req = 0; + + mpc85xx_timebase_freeze(1); + timebase = get_tb(); + mb(); + tb_valid = 1; + + while (tb_valid) + barrier(); + + mpc85xx_timebase_freeze(0); + + local_irq_restore(flags); +} + +static void mpc85xx_take_timebase(void) +{ + unsigned long flags; + + local_irq_save(flags); + + tb_req = 1; + while (!tb_valid) + barrier(); + + set_tb(timebase >> 32, timebase & 0xffffffff); + isync(); + tb_valid = 0; + + local_irq_restore(flags); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void __cpuinit smp_85xx_mach_cpu_die(void) +{ + unsigned int cpu = smp_processor_id(); + u32 tmp; + + local_irq_disable(); + idle_task_exit(); + generic_set_cpu_dead(cpu); + mb(); + + mtspr(SPRN_TCR, 0); + + __flush_disable_L1(); + tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP; + mtspr(SPRN_HID0, tmp); + isync(); + + /* Enter NAP mode. */ + tmp = mfmsr(); + tmp |= MSR_WE; + mb(); + mtmsr(tmp); + isync(); + + while (1) + ; +} +#endif + +static int __cpuinit smp_85xx_kick_cpu(int nr) { unsigned long flags; const u64 *cpu_rel_addr; - __iomem u32 *bptr_vaddr; + __iomem struct epapr_spin_table *spin_table; struct device_node *np; - int n = 0, hw_cpu = get_hard_smp_processor_id(nr); + int hw_cpu = get_hard_smp_processor_id(nr); int ioremappable; + int ret = 0; WARN_ON(nr < 0 || nr >= NR_CPUS); WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS); @@ -75,46 +161,81 @@ smp_85xx_kick_cpu(int nr) /* Map the spin table */ if (ioremappable) - bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); + spin_table = ioremap(*cpu_rel_addr, + sizeof(struct epapr_spin_table)); else - bptr_vaddr = phys_to_virt(*cpu_rel_addr); + spin_table = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); - - out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu); #ifdef CONFIG_PPC32 - out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); +#ifdef CONFIG_HOTPLUG_CPU + /* Corresponding to generic_set_cpu_dead() */ + generic_set_cpu_up(nr); + + if (system_state == SYSTEM_RUNNING) { + out_be32(&spin_table->addr_l, 0); + + /* + * We don't set the BPTR register here since it already points + * to the boot page properly. + */ + mpic_reset_core(hw_cpu); + + /* wait until core is ready... */ + if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1, + 10000, 100)) { + pr_err("%s: timeout waiting for core %d to reset\n", + __func__, hw_cpu); + ret = -ENOENT; + goto out; + } + + /* clear the acknowledge status */ + __secondary_hold_acknowledge = -1; + } +#endif + out_be32(&spin_table->pir, hw_cpu); + out_be32(&spin_table->addr_l, __pa(__early_start)); if (!ioremappable) - flush_dcache_range((ulong)bptr_vaddr, - (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY)); + flush_dcache_range((ulong)spin_table, + (ulong)spin_table + sizeof(struct epapr_spin_table)); /* Wait a bit for the CPU to ack. */ - while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000)) - mdelay(1); + if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu, + 10000, 100)) { + pr_err("%s: timeout waiting for core %d to ack\n", + __func__, hw_cpu); + ret = -ENOENT; + goto out; + } +out: #else smp_generic_kick_cpu(nr); - out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER), - __pa((u64)*((unsigned long long *) generic_secondary_smp_init))); + out_be32(&spin_table->pir, hw_cpu); + out_be64((u64 *)(&spin_table->addr_h), + __pa((u64)*((unsigned long long *)generic_secondary_smp_init))); if (!ioremappable) - flush_dcache_range((ulong)bptr_vaddr, - (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY)); + flush_dcache_range((ulong)spin_table, + (ulong)spin_table + sizeof(struct epapr_spin_table)); #endif local_irq_restore(flags); if (ioremappable) - iounmap(bptr_vaddr); - - pr_debug("waited %d msecs for CPU #%d.\n", n, nr); + iounmap(spin_table); - return 0; + return ret; } struct smp_ops_t smp_85xx_ops = { .kick_cpu = smp_85xx_kick_cpu, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = generic_cpu_disable, + .cpu_die = generic_cpu_die, +#endif #ifdef CONFIG_KEXEC .give_timebase = smp_generic_give_timebase, .take_timebase = smp_generic_take_timebase, @@ -218,8 +339,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image) } #endif /* CONFIG_KEXEC */ -static void __init -smp_85xx_setup_cpu(int cpu_nr) +static void __cpuinit smp_85xx_setup_cpu(int cpu_nr) { if (smp_85xx_ops.probe == smp_mpic_probe) mpic_setup_this_cpu(); @@ -228,6 +348,16 @@ smp_85xx_setup_cpu(int cpu_nr) doorbell_setup_this_cpu(); } +static const struct of_device_id mpc85xx_smp_guts_ids[] = { + { .compatible = "fsl,mpc8572-guts", }, + { .compatible = "fsl,p1020-guts", }, + { .compatible = "fsl,p1021-guts", }, + { .compatible = "fsl,p1022-guts", }, + { .compatible = "fsl,p1023-guts", }, + { .compatible = "fsl,p2020-guts", }, + {}, +}; + void __init mpc85xx_smp_init(void) { struct device_node *np; @@ -249,6 +379,22 @@ void __init mpc85xx_smp_init(void) smp_85xx_ops.cause_ipi = doorbell_cause_ipi; } + np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); + if (np) { + guts = of_iomap(np, 0); + of_node_put(np); + if (!guts) { + pr_err("%s: Could not map guts node address\n", + __func__); + return; + } + smp_85xx_ops.give_timebase = mpc85xx_give_timebase; + smp_85xx_ops.take_timebase = mpc85xx_take_timebase; +#ifdef CONFIG_HOTPLUG_CPU + ppc_md.cpu_die = smp_85xx_mach_cpu_die; +#endif + } + smp_ops = &smp_85xx_ops; #ifdef CONFIG_KEXEC diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index b9c6daa07b66..ae368e0e1076 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -66,20 +66,13 @@ static void __init socrates_pic_init(void) */ static void __init socrates_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("socrates_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") - fsl_add_bridge(np, 1); -#endif + fsl_pci_assign_primary(); } -machine_device_initcall(socrates, mpc85xx_common_publish_devices); +machine_arch_initcall(socrates, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index e0508002b086..6f4939b6309e 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -60,21 +60,14 @@ static void __init stx_gp3_pic_init(void) */ static void __init stx_gp3_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("stx_gp3_setup_arch()", 0); + fsl_pci_assign_primary(); + #ifdef CONFIG_CPM2 cpm2_reset(); #endif - -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") - fsl_add_bridge(np, 1); -#endif } static void stx_gp3_show_cpuinfo(struct seq_file *m) @@ -93,7 +86,7 @@ static void stx_gp3_show_cpuinfo(struct seq_file *m) seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); } -machine_device_initcall(stx_gp3, mpc85xx_common_publish_devices); +machine_arch_initcall(stx_gp3, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index 3e70a2035e53..b4e58cdc09a5 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c @@ -59,10 +59,6 @@ static void __init tqm85xx_pic_init(void) */ static void __init tqm85xx_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("tqm85xx_setup_arch()", 0); @@ -70,20 +66,7 @@ static void __init tqm85xx_setup_arch(void) cpm2_reset(); #endif -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - if (!of_address_to_resource(np, 0, &rsrc)) { - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - } - } - } -#endif + fsl_pci_assign_primary(); } static void tqm85xx_show_cpuinfo(struct seq_file *m) @@ -123,9 +106,9 @@ static void __devinit tqm85xx_ti1520_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1520, tqm85xx_ti1520_fixup); -machine_device_initcall(tqm85xx, mpc85xx_common_publish_devices); +machine_arch_initcall(tqm85xx, mpc85xx_common_publish_devices); -static const char *board[] __initdata = { +static const char * const board[] __initconst = { "tqc,tqm8540", "tqc,tqm8541", "tqc,tqm8548", diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 41c687550ea7..dcbf7e42dce7 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -111,18 +111,11 @@ static void xes_mpc85xx_fixups(void) } } -#ifdef CONFIG_PCI -static int primary_phb_addr; -#endif - /* * Setup the architecture */ static void __init xes_mpc85xx_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif struct device_node *root; const char *model = "Unknown"; @@ -137,26 +130,14 @@ static void __init xes_mpc85xx_setup_arch(void) xes_mpc85xx_fixups(); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == primary_phb_addr) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - } - } -#endif - mpc85xx_smp_init(); + + fsl_pci_assign_primary(); } -machine_device_initcall(xes_mpc8572, mpc85xx_common_publish_devices); -machine_device_initcall(xes_mpc8548, mpc85xx_common_publish_devices); -machine_device_initcall(xes_mpc8540, mpc85xx_common_publish_devices); +machine_arch_initcall(xes_mpc8572, mpc85xx_common_publish_devices); +machine_arch_initcall(xes_mpc8548, mpc85xx_common_publish_devices); +machine_arch_initcall(xes_mpc8540, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened @@ -165,42 +146,21 @@ static int __init xes_mpc8572_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (of_flat_dt_is_compatible(root, "xes,MPC8572")) { -#ifdef CONFIG_PCI - primary_phb_addr = 0x8000; -#endif - return 1; - } else { - return 0; - } + return of_flat_dt_is_compatible(root, "xes,MPC8572"); } static int __init xes_mpc8548_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (of_flat_dt_is_compatible(root, "xes,MPC8548")) { -#ifdef CONFIG_PCI - primary_phb_addr = 0xb000; -#endif - return 1; - } else { - return 0; - } + return of_flat_dt_is_compatible(root, "xes,MPC8548"); } static int __init xes_mpc8540_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (of_flat_dt_is_compatible(root, "xes,MPC8540")) { -#ifdef CONFIG_PCI - primary_phb_addr = 0xb000; -#endif - return 1; - } else { - return 0; - } + return of_flat_dt_is_compatible(root, "xes,MPC8540"); } define_machine(xes_mpc8572) { diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 563aafa8629c..bf5338754c5a 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -73,13 +73,6 @@ static void __init gef_ppc9a_init_irq(void) static void __init gef_ppc9a_setup_arch(void) { struct device_node *regs; -#ifdef CONFIG_PCI - struct device_node *np; - - for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") { - fsl_add_bridge(np, 1); - } -#endif printk(KERN_INFO "GE Intelligent Platforms PPC9A 6U VME SBC\n"); @@ -87,6 +80,8 @@ static void __init gef_ppc9a_setup_arch(void) mpc86xx_smp_init(); #endif + fsl_pci_assign_primary(); + /* Remap basic board registers */ regs = of_find_compatible_node(NULL, NULL, "gef,ppc9a-fpga-regs"); if (regs) { @@ -221,6 +216,7 @@ static long __init mpc86xx_time_init(void) static __initdata struct of_device_id of_bus_ids[] = { { .compatible = "simple-bus", }, { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, {}, }; @@ -231,7 +227,7 @@ static int __init declare_of_platform_devices(void) return 0; } -machine_device_initcall(gef_ppc9a, declare_of_platform_devices); +machine_arch_initcall(gef_ppc9a, declare_of_platform_devices); define_machine(gef_ppc9a) { .name = "GE PPC9A", diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index cc6a91ae0889..0b7851330a07 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -73,20 +73,14 @@ static void __init gef_sbc310_init_irq(void) static void __init gef_sbc310_setup_arch(void) { struct device_node *regs; -#ifdef CONFIG_PCI - struct device_node *np; - - for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") { - fsl_add_bridge(np, 1); - } -#endif - printk(KERN_INFO "GE Intelligent Platforms SBC310 6U VPX SBC\n"); #ifdef CONFIG_SMP mpc86xx_smp_init(); #endif + fsl_pci_assign_primary(); + /* Remap basic board registers */ regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs"); if (regs) { @@ -209,6 +203,7 @@ static long __init mpc86xx_time_init(void) static __initdata struct of_device_id of_bus_ids[] = { { .compatible = "simple-bus", }, { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, {}, }; @@ -219,7 +214,7 @@ static int __init declare_of_platform_devices(void) return 0; } -machine_device_initcall(gef_sbc310, declare_of_platform_devices); +machine_arch_initcall(gef_sbc310, declare_of_platform_devices); define_machine(gef_sbc310) { .name = "GE SBC310", diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index aead6b337f4a..b9eb174897b1 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -73,13 +73,6 @@ static void __init gef_sbc610_init_irq(void) static void __init gef_sbc610_setup_arch(void) { struct device_node *regs; -#ifdef CONFIG_PCI - struct device_node *np; - - for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") { - fsl_add_bridge(np, 1); - } -#endif printk(KERN_INFO "GE Intelligent Platforms SBC610 6U VPX SBC\n"); @@ -87,6 +80,8 @@ static void __init gef_sbc610_setup_arch(void) mpc86xx_smp_init(); #endif + fsl_pci_assign_primary(); + /* Remap basic board registers */ regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs"); if (regs) { @@ -198,6 +193,7 @@ static long __init mpc86xx_time_init(void) static __initdata struct of_device_id of_bus_ids[] = { { .compatible = "simple-bus", }, { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, {}, }; @@ -208,7 +204,7 @@ static int __init declare_of_platform_devices(void) return 0; } -machine_device_initcall(gef_sbc610, declare_of_platform_devices); +machine_arch_initcall(gef_sbc610, declare_of_platform_devices); define_machine(gef_sbc610) { .name = "GE SBC610", diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 62cd3c555bfb..a817398a56da 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -91,6 +91,9 @@ static struct of_device_id __initdata mpc8610_ids[] = { { .compatible = "simple-bus", }, /* So that the DMA channel nodes can be probed individually: */ { .compatible = "fsl,eloplus-dma", }, + /* PCI controllers */ + { .compatible = "fsl,mpc8610-pci", }, + { .compatible = "fsl,mpc8641-pcie", }, {} }; @@ -107,7 +110,7 @@ static int __init mpc8610_declare_of_platform_devices(void) return 0; } -machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); +machine_arch_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) @@ -278,25 +281,13 @@ mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port) static void __init mpc86xx_hpcd_setup_arch(void) { struct resource r; - struct device_node *np; unsigned char *pixis; if (ppc_md.progress) ppc_md.progress("mpc86xx_hpcd_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8610-pci") - || of_device_is_compatible(np, "fsl,mpc8641-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0xa000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - } - } -#endif + fsl_pci_assign_primary(); + #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format; diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 817245bc0219..e8bf3fae5606 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -19,7 +19,6 @@ #include <linux/delay.h> #include <linux/seq_file.h> #include <linux/of_platform.h> -#include <linux/memblock.h> #include <asm/time.h> #include <asm/machdep.h> @@ -51,15 +50,8 @@ extern int uli_exclude_device(struct pci_controller *hose, static int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { - struct device_node* node; - struct resource rsrc; - - node = hose->dn; - of_address_to_resource(node, 0, &rsrc); - - if ((rsrc.start & 0xfffff) == 0x8000) { + if (hose->dn == fsl_pci_primary) return uli_exclude_device(hose, bus, devfn); - } return PCIBIOS_SUCCESSFUL; } @@ -69,30 +61,11 @@ static int mpc86xx_exclude_device(struct pci_controller *hose, static void __init mpc86xx_hpcn_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; - struct pci_controller *hose; -#endif - dma_addr_t max = 0xffffffff; - if (ppc_md.progress) ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); #ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == 0x8000) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } - ppc_md.pci_exclude_device = mpc86xx_exclude_device; - #endif printk("MPC86xx HPCN board from Freescale Semiconductor\n"); @@ -101,13 +74,9 @@ mpc86xx_hpcn_setup_arch(void) mpc86xx_smp_init(); #endif -#ifdef CONFIG_SWIOTLB - if ((memblock_end_of_DRAM() - 1) > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif + fsl_pci_assign_primary(); + + swiotlb_detect_4g(); } @@ -162,6 +131,7 @@ static __initdata struct of_device_id of_bus_ids[] = { { .compatible = "simple-bus", }, { .compatible = "fsl,srio", }, { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, {}, }; @@ -171,7 +141,7 @@ static int __init declare_of_platform_devices(void) return 0; } -machine_device_initcall(mpc86xx_hpcn, declare_of_platform_devices); +machine_arch_initcall(mpc86xx_hpcn, declare_of_platform_devices); machine_arch_initcall(mpc86xx_hpcn, swiotlb_setup_bus_notifier); define_machine(mpc86xx_hpcn) { diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c index e7007d0d949e..b47a8fd0f3d3 100644 --- a/arch/powerpc/platforms/86xx/sbc8641d.c +++ b/arch/powerpc/platforms/86xx/sbc8641d.c @@ -38,23 +38,16 @@ static void __init sbc8641_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - if (ppc_md.progress) ppc_md.progress("sbc8641_setup_arch()", 0); -#ifdef CONFIG_PCI - for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") - fsl_add_bridge(np, 0); -#endif - printk("SBC8641 board from Wind River\n"); #ifdef CONFIG_SMP mpc86xx_smp_init(); #endif + + fsl_pci_assign_primary(); } @@ -102,6 +95,7 @@ mpc86xx_time_init(void) static __initdata struct of_device_id of_bus_ids[] = { { .compatible = "simple-bus", }, { .compatible = "gianfar", }, + { .compatible = "fsl,mpc8641-pcie", }, {}, }; @@ -111,7 +105,7 @@ static int __init declare_of_platform_devices(void) return 0; } -machine_device_initcall(sbc8641, declare_of_platform_devices); +machine_arch_initcall(sbc8641, declare_of_platform_devices); define_machine(sbc8641) { .name = "SBC8641D", diff --git a/arch/powerpc/platforms/cell/beat.c b/arch/powerpc/platforms/cell/beat.c index 852592b2b712..affcf566d460 100644 --- a/arch/powerpc/platforms/cell/beat.c +++ b/arch/powerpc/platforms/cell/beat.c @@ -136,9 +136,9 @@ ssize_t beat_nvram_get_size(void) return BEAT_NVRAM_SIZE; } -int beat_set_xdabr(unsigned long dabr) +int beat_set_xdabr(unsigned long dabr, unsigned long dabrx) { - if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER)) + if (beat_set_dabr(dabr, dabrx)) return -1; return 0; } diff --git a/arch/powerpc/platforms/cell/beat.h b/arch/powerpc/platforms/cell/beat.h index 32c8efcedc80..bfcb8e351ae5 100644 --- a/arch/powerpc/platforms/cell/beat.h +++ b/arch/powerpc/platforms/cell/beat.h @@ -32,7 +32,7 @@ void beat_get_rtc_time(struct rtc_time *); ssize_t beat_nvram_get_size(void); ssize_t beat_nvram_read(char *, size_t, loff_t *); ssize_t beat_nvram_write(char *, size_t, loff_t *); -int beat_set_xdabr(unsigned long); +int beat_set_xdabr(unsigned long, unsigned long); void beat_power_save(void); void beat_kexec_cpu_down(int, int); diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c index 943c9d39aa16..0f6f83988b3d 100644 --- a/arch/powerpc/platforms/cell/beat_htab.c +++ b/arch/powerpc/platforms/cell/beat_htab.c @@ -88,7 +88,7 @@ static inline unsigned int beat_read_mask(unsigned hpte_group) } static long beat_lpar_hpte_insert(unsigned long hpte_group, - unsigned long va, unsigned long pa, + unsigned long vpn, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize, int ssize) { @@ -103,7 +103,7 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group, "rflags=%lx, vflags=%lx, psize=%d)\n", hpte_group, va, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + hpte_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; @@ -184,14 +184,14 @@ static void beat_lpar_hptab_clear(void) */ static long beat_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, + unsigned long vpn, int psize, int ssize, int local) { unsigned long lpar_rc; u64 dummy0, dummy1; unsigned long want_v; - want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + want_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M); DBG_LOW(" update: " "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", @@ -220,15 +220,15 @@ static long beat_lpar_hpte_updatepp(unsigned long slot, return 0; } -static long beat_lpar_hpte_find(unsigned long va, int psize) +static long beat_lpar_hpte_find(unsigned long vpn, int psize) { unsigned long hash; unsigned long i, j; long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift, MMU_SEGSIZE_256M); - want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + hash = hpt_hash(vpn, mmu_psize_defs[psize].shift, MMU_SEGSIZE_256M); + want_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M); for (j = 0; j < 2; j++) { slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; @@ -255,14 +255,15 @@ static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, int psize, int ssize) { - unsigned long lpar_rc, slot, vsid, va; + unsigned long vpn; + unsigned long lpar_rc, slot, vsid; u64 dummy0, dummy1; vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); - va = (vsid << 28) | (ea & 0x0fffffff); + vpn = hpt_vpn(ea, vsid, MMU_SEGSIZE_256M); raw_spin_lock(&beat_htab_lock); - slot = beat_lpar_hpte_find(va, psize); + slot = beat_lpar_hpte_find(vpn, psize); BUG_ON(slot == -1); lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, @@ -272,7 +273,7 @@ static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, BUG_ON(lpar_rc != 0); } -static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, +static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn, int psize, int ssize, int local) { unsigned long want_v; @@ -282,7 +283,7 @@ static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", slot, va, psize, local); - want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + want_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M); raw_spin_lock_irqsave(&beat_htab_lock, flags); dummy1 = beat_lpar_hpte_getword0(slot); @@ -311,7 +312,7 @@ void __init hpte_init_beat(void) } static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, - unsigned long va, unsigned long pa, + unsigned long vpn, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize, int ssize) { @@ -322,11 +323,11 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, return -1; if (!(vflags & HPTE_V_BOLTED)) - DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " + DBG_LOW("hpte_insert(group=%lx, vpn=%016lx, pa=%016lx, " "rflags=%lx, vflags=%lx, psize=%d)\n", - hpte_group, va, pa, rflags, vflags, psize); + hpte_group, vpn, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M) | + hpte_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; @@ -364,14 +365,14 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group, */ static long beat_lpar_hpte_updatepp_v3(unsigned long slot, unsigned long newpp, - unsigned long va, + unsigned long vpn, int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long want_v; unsigned long pss; - want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + want_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M); pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; DBG_LOW(" update: " @@ -392,16 +393,16 @@ static long beat_lpar_hpte_updatepp_v3(unsigned long slot, return 0; } -static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long va, +static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long vpn, int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; unsigned long pss; - DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", - slot, va, psize, local); - want_v = hpte_encode_v(va, psize, MMU_SEGSIZE_256M); + DBG_LOW(" inval : slot=%lx, vpn=%016lx, psize: %d, local: %d\n", + slot, vpn, psize, local); + want_v = hpte_encode_v(vpn, psize, MMU_SEGSIZE_256M); pss = (psize == MMU_PAGE_4K) ? -1UL : mmu_psize_defs[psize].penc; lpar_rc = beat_invalidate_htab_entry3(0, slot, want_v, pss); diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 14943ef01918..7d2d036754b5 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -19,12 +19,12 @@ #undef DEBUG +#include <linux/memblock.h> #include <linux/types.h> #include <linux/spinlock.h> #include <linux/pci.h> #include <asm/iommu.h> #include <asm/machdep.h> -#include <asm/abs_addr.h> #include <asm/firmware.h> #define IOBMAP_PAGE_SHIFT 12 @@ -99,7 +99,7 @@ static int iobmap_build(struct iommu_table *tbl, long index, ip = ((u32 *)tbl->it_base) + index; while (npages--) { - rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT; + rpn = __pa(uaddr) >> IOBMAP_PAGE_SHIFT; *(ip++) = IOBMAP_L2E_V | rpn; /* invalidate tlb, can be optimized more */ @@ -258,7 +258,7 @@ void __init alloc_iobmap_l2(void) return; #endif /* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */ - iob_l2_base = (u32 *)abs_to_virt(memblock_alloc_base(1UL<<21, 1UL<<21, 0x80000000)); + iob_l2_base = (u32 *)__va(memblock_alloc_base(1UL<<21, 1UL<<21, 0x80000000)); printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base); } diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 0e7eccc0f88d..471aa3ccd9fd 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -30,19 +30,10 @@ #include <asm/opal.h> #include <asm/iommu.h> #include <asm/tce.h> -#include <asm/abs_addr.h> #include "powernv.h" #include "pci.h" -struct resource_wrap { - struct list_head link; - resource_size_t size; - resource_size_t align; - struct pci_dev *dev; /* Set if it's a device */ - struct pci_bus *bus; /* Set if it's a bridge */ -}; - static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe, struct va_format *vaf) { @@ -78,273 +69,6 @@ define_pe_printk_level(pe_err, KERN_ERR); define_pe_printk_level(pe_warn, KERN_WARNING); define_pe_printk_level(pe_info, KERN_INFO); - -/* Calculate resource usage & alignment requirement of a single - * device. This will also assign all resources within the device - * for a given type starting at 0 for the biggest one and then - * assigning in decreasing order of size. - */ -static void __devinit pnv_ioda_calc_dev(struct pci_dev *dev, unsigned int flags, - resource_size_t *size, - resource_size_t *align) -{ - resource_size_t start; - struct resource *r; - int i; - - pr_devel(" -> CDR %s\n", pci_name(dev)); - - *size = *align = 0; - - /* Clear the resources out and mark them all unset */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - r = &dev->resource[i]; - if (!(r->flags & flags)) - continue; - if (r->start) { - r->end -= r->start; - r->start = 0; - } - r->flags |= IORESOURCE_UNSET; - } - - /* We currently keep all memory resources together, we - * will handle prefetch & 64-bit separately in the future - * but for now we stick everybody in M32 - */ - start = 0; - for (;;) { - resource_size_t max_size = 0; - int max_no = -1; - - /* Find next biggest resource */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - r = &dev->resource[i]; - if (!(r->flags & IORESOURCE_UNSET) || - !(r->flags & flags)) - continue; - if (resource_size(r) > max_size) { - max_size = resource_size(r); - max_no = i; - } - } - if (max_no < 0) - break; - r = &dev->resource[max_no]; - if (max_size > *align) - *align = max_size; - *size += max_size; - r->start = start; - start += max_size; - r->end = r->start + max_size - 1; - r->flags &= ~IORESOURCE_UNSET; - pr_devel(" -> R%d %016llx..%016llx\n", - max_no, r->start, r->end); - } - pr_devel(" <- CDR %s size=%llx align=%llx\n", - pci_name(dev), *size, *align); -} - -/* Allocate a resource "wrap" for a given device or bridge and - * insert it at the right position in the sorted list - */ -static void __devinit pnv_ioda_add_wrap(struct list_head *list, - struct pci_bus *bus, - struct pci_dev *dev, - resource_size_t size, - resource_size_t align) -{ - struct resource_wrap *w1, *w = kzalloc(sizeof(*w), GFP_KERNEL); - - w->size = size; - w->align = align; - w->dev = dev; - w->bus = bus; - - list_for_each_entry(w1, list, link) { - if (w1->align < align) { - list_add_tail(&w->link, &w1->link); - return; - } - } - list_add_tail(&w->link, list); -} - -/* Offset device resources of a given type */ -static void __devinit pnv_ioda_offset_dev(struct pci_dev *dev, - unsigned int flags, - resource_size_t offset) -{ - struct resource *r; - int i; - - pr_devel(" -> ODR %s [%x] +%016llx\n", pci_name(dev), flags, offset); - - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - r = &dev->resource[i]; - if (r->flags & flags) { - dev->resource[i].start += offset; - dev->resource[i].end += offset; - } - } - - pr_devel(" <- ODR %s [%x] +%016llx\n", pci_name(dev), flags, offset); -} - -/* Offset bus resources (& all children) of a given type */ -static void __devinit pnv_ioda_offset_bus(struct pci_bus *bus, - unsigned int flags, - resource_size_t offset) -{ - struct resource *r; - struct pci_dev *dev; - struct pci_bus *cbus; - int i; - - pr_devel(" -> OBR %s [%x] +%016llx\n", - bus->self ? pci_name(bus->self) : "root", flags, offset); - - pci_bus_for_each_resource(bus, r, i) { - if (r && (r->flags & flags)) { - r->start += offset; - r->end += offset; - } - } - list_for_each_entry(dev, &bus->devices, bus_list) - pnv_ioda_offset_dev(dev, flags, offset); - list_for_each_entry(cbus, &bus->children, node) - pnv_ioda_offset_bus(cbus, flags, offset); - - pr_devel(" <- OBR %s [%x]\n", - bus->self ? pci_name(bus->self) : "root", flags); -} - -/* This is the guts of our IODA resource allocation. This is called - * recursively for each bus in the system. It calculates all the - * necessary size and requirements for children and assign them - * resources such that: - * - * - Each function fits in it's own contiguous set of IO/M32 - * segment - * - * - All segments behind a P2P bridge are contiguous and obey - * alignment constraints of those bridges - */ -static void __devinit pnv_ioda_calc_bus(struct pci_bus *bus, unsigned int flags, - resource_size_t *size, - resource_size_t *align) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - struct pnv_phb *phb = hose->private_data; - resource_size_t dev_size, dev_align, start; - resource_size_t min_align, min_balign; - struct pci_dev *cdev; - struct pci_bus *cbus; - struct list_head head; - struct resource_wrap *w; - unsigned int bres; - - *size = *align = 0; - - pr_devel("-> CBR %s [%x]\n", - bus->self ? pci_name(bus->self) : "root", flags); - - /* Calculate alignment requirements based on the type - * of resource we are working on - */ - if (flags & IORESOURCE_IO) { - bres = 0; - min_align = phb->ioda.io_segsize; - min_balign = 0x1000; - } else { - bres = 1; - min_align = phb->ioda.m32_segsize; - min_balign = 0x100000; - } - - /* Gather all our children resources ordered by alignment */ - INIT_LIST_HEAD(&head); - - /* - Busses */ - list_for_each_entry(cbus, &bus->children, node) { - pnv_ioda_calc_bus(cbus, flags, &dev_size, &dev_align); - pnv_ioda_add_wrap(&head, cbus, NULL, dev_size, dev_align); - } - - /* - Devices */ - list_for_each_entry(cdev, &bus->devices, bus_list) { - pnv_ioda_calc_dev(cdev, flags, &dev_size, &dev_align); - /* Align them to segment size */ - if (dev_align < min_align) - dev_align = min_align; - pnv_ioda_add_wrap(&head, NULL, cdev, dev_size, dev_align); - } - if (list_empty(&head)) - goto empty; - - /* Now we can do two things: assign offsets to them within that - * level and get our total alignment & size requirements. The - * assignment algorithm is going to be uber-trivial for now, we - * can try to be smarter later at filling out holes. - */ - if (bus->self) { - /* No offset for downstream bridges */ - start = 0; - } else { - /* Offset from the root */ - if (flags & IORESOURCE_IO) - /* Don't hand out IO 0 */ - start = hose->io_resource.start + 0x1000; - else - start = hose->mem_resources[0].start; - } - while(!list_empty(&head)) { - w = list_first_entry(&head, struct resource_wrap, link); - list_del(&w->link); - if (w->size) { - if (start) { - start = ALIGN(start, w->align); - if (w->dev) - pnv_ioda_offset_dev(w->dev,flags,start); - else if (w->bus) - pnv_ioda_offset_bus(w->bus,flags,start); - } - if (w->align > *align) - *align = w->align; - } - start += w->size; - kfree(w); - } - *size = start; - - /* Align and setup bridge resources */ - *align = max_t(resource_size_t, *align, - max_t(resource_size_t, min_align, min_balign)); - *size = ALIGN(*size, - max_t(resource_size_t, min_align, min_balign)); - empty: - /* Only setup P2P's, not the PHB itself */ - if (bus->self) { - struct resource *res = bus->resource[bres]; - - if (WARN_ON(res == NULL)) - return; - - /* - * FIXME: We should probably export and call - * pci_bridge_check_ranges() to properly re-initialize - * the PCI portion of the flags here, and to detect - * what the bridge actually supports. - */ - res->start = 0; - res->flags = (*size) ? flags : 0; - res->end = (*size) ? (*size - 1) : 0; - } - - pr_devel("<- CBR %s [%x] *size=%016llx *align=%016llx\n", - bus->self ? pci_name(bus->self) : "root", flags,*size,*align); -} - static struct pci_dn *pnv_ioda_get_pdn(struct pci_dev *dev) { struct device_node *np; @@ -355,172 +79,6 @@ static struct pci_dn *pnv_ioda_get_pdn(struct pci_dev *dev) return PCI_DN(np); } -static void __devinit pnv_ioda_setup_pe_segments(struct pci_dev *dev) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pnv_ioda_get_pdn(dev); - unsigned int pe, i; - resource_size_t pos; - struct resource io_res; - struct resource m32_res; - struct pci_bus_region region; - int rc; - - /* Anything not referenced in the device-tree gets PE#0 */ - pe = pdn ? pdn->pe_number : 0; - - /* Calculate the device min/max */ - io_res.start = m32_res.start = (resource_size_t)-1; - io_res.end = m32_res.end = 0; - io_res.flags = IORESOURCE_IO; - m32_res.flags = IORESOURCE_MEM; - - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *r = NULL; - if (dev->resource[i].flags & IORESOURCE_IO) - r = &io_res; - if (dev->resource[i].flags & IORESOURCE_MEM) - r = &m32_res; - if (!r) - continue; - if (dev->resource[i].start < r->start) - r->start = dev->resource[i].start; - if (dev->resource[i].end > r->end) - r->end = dev->resource[i].end; - } - - /* Setup IO segments */ - if (io_res.start < io_res.end) { - pcibios_resource_to_bus(dev, ®ion, &io_res); - pos = region.start; - i = pos / phb->ioda.io_segsize; - while(i < phb->ioda.total_pe && pos <= region.end) { - if (phb->ioda.io_segmap[i]) { - pr_err("%s: Trying to use IO seg #%d which is" - " already used by PE# %d\n", - pci_name(dev), i, - phb->ioda.io_segmap[i]); - /* XXX DO SOMETHING TO DISABLE DEVICE ? */ - break; - } - phb->ioda.io_segmap[i] = pe; - rc = opal_pci_map_pe_mmio_window(phb->opal_id, pe, - OPAL_IO_WINDOW_TYPE, - 0, i); - if (rc != OPAL_SUCCESS) { - pr_err("%s: OPAL error %d setting up mapping" - " for IO seg# %d\n", - pci_name(dev), rc, i); - /* XXX DO SOMETHING TO DISABLE DEVICE ? */ - break; - } - pos += phb->ioda.io_segsize; - i++; - }; - } - - /* Setup M32 segments */ - if (m32_res.start < m32_res.end) { - pcibios_resource_to_bus(dev, ®ion, &m32_res); - pos = region.start; - i = pos / phb->ioda.m32_segsize; - while(i < phb->ioda.total_pe && pos <= region.end) { - if (phb->ioda.m32_segmap[i]) { - pr_err("%s: Trying to use M32 seg #%d which is" - " already used by PE# %d\n", - pci_name(dev), i, - phb->ioda.m32_segmap[i]); - /* XXX DO SOMETHING TO DISABLE DEVICE ? */ - break; - } - phb->ioda.m32_segmap[i] = pe; - rc = opal_pci_map_pe_mmio_window(phb->opal_id, pe, - OPAL_M32_WINDOW_TYPE, - 0, i); - if (rc != OPAL_SUCCESS) { - pr_err("%s: OPAL error %d setting up mapping" - " for M32 seg# %d\n", - pci_name(dev), rc, i); - /* XXX DO SOMETHING TO DISABLE DEVICE ? */ - break; - } - pos += phb->ioda.m32_segsize; - i++; - } - } -} - -/* Check if a resource still fits in the total IO or M32 range - * for a given PHB - */ -static int __devinit pnv_ioda_resource_fit(struct pci_controller *hose, - struct resource *r) -{ - struct resource *bounds; - - if (r->flags & IORESOURCE_IO) - bounds = &hose->io_resource; - else if (r->flags & IORESOURCE_MEM) - bounds = &hose->mem_resources[0]; - else - return 1; - - if (r->start >= bounds->start && r->end <= bounds->end) - return 1; - r->flags = 0; - return 0; -} - -static void __devinit pnv_ioda_update_resources(struct pci_bus *bus) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_bus *cbus; - struct pci_dev *cdev; - unsigned int i; - - /* We used to clear all device enables here. However it looks like - * clearing MEM enable causes Obsidian (IPR SCS) to go bonkers, - * and shoot fatal errors to the PHB which in turns fences itself - * and we can't recover from that ... yet. So for now, let's leave - * the enables as-is and hope for the best. - */ - - /* Check if bus resources fit in our IO or M32 range */ - for (i = 0; bus->self && (i < 2); i++) { - struct resource *r = bus->resource[i]; - if (r && !pnv_ioda_resource_fit(hose, r)) - pr_err("%s: Bus %d resource %d disabled, no room\n", - pci_name(bus->self), bus->number, i); - } - - /* Update self if it's not a PHB */ - if (bus->self) - pci_setup_bridge(bus); - - /* Update child devices */ - list_for_each_entry(cdev, &bus->devices, bus_list) { - /* Check if resource fits, if not, disabled it */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *r = &cdev->resource[i]; - if (!pnv_ioda_resource_fit(hose, r)) - pr_err("%s: Resource %d disabled, no room\n", - pci_name(cdev), i); - } - - /* Assign segments */ - pnv_ioda_setup_pe_segments(cdev); - - /* Update HW BARs */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) - pci_update_resource(cdev, i); - } - - /* Update child busses */ - list_for_each_entry(cbus, &bus->children, node) - pnv_ioda_update_resources(cbus); -} - static int __devinit pnv_ioda_alloc_pe(struct pnv_phb *phb) { unsigned long pe; @@ -548,7 +106,7 @@ static void __devinit pnv_ioda_free_pe(struct pnv_phb *phb, int pe) * but in the meantime, we need to protect them to avoid warnings */ #ifdef CONFIG_PCI_MSI -static struct pnv_ioda_pe * __devinit __pnv_ioda_get_one_pe(struct pci_dev *dev) +static struct pnv_ioda_pe * __devinit pnv_ioda_get_pe(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; @@ -560,19 +118,6 @@ static struct pnv_ioda_pe * __devinit __pnv_ioda_get_one_pe(struct pci_dev *dev) return NULL; return &phb->ioda.pe_array[pdn->pe_number]; } - -static struct pnv_ioda_pe * __devinit pnv_ioda_get_pe(struct pci_dev *dev) -{ - struct pnv_ioda_pe *pe = __pnv_ioda_get_one_pe(dev); - - while (!pe && dev->bus->self) { - dev = dev->bus->self; - pe = __pnv_ioda_get_one_pe(dev); - if (pe) - pe = pe->bus_pe; - } - return pe; -} #endif /* CONFIG_PCI_MSI */ static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb, @@ -589,7 +134,11 @@ static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb, dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER; fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER; parent = pe->pbus->self; - count = pe->pbus->busn_res.end - pe->pbus->busn_res.start + 1; + if (pe->flags & PNV_IODA_PE_BUS_ALL) + count = pe->pbus->busn_res.end - pe->pbus->busn_res.start + 1; + else + count = 1; + switch(count) { case 1: bcomp = OpalPciBusAll; break; case 2: bcomp = OpalPciBus7Bits; break; @@ -666,13 +215,13 @@ static void __devinit pnv_ioda_link_pe_by_weight(struct pnv_phb *phb, { struct pnv_ioda_pe *lpe; - list_for_each_entry(lpe, &phb->ioda.pe_list, link) { + list_for_each_entry(lpe, &phb->ioda.pe_dma_list, dma_link) { if (lpe->dma_weight < pe->dma_weight) { - list_add_tail(&pe->link, &lpe->link); + list_add_tail(&pe->dma_link, &lpe->dma_link); return; } } - list_add_tail(&pe->link, &phb->ioda.pe_list); + list_add_tail(&pe->dma_link, &phb->ioda.pe_dma_list); } static unsigned int pnv_ioda_dma_weight(struct pci_dev *dev) @@ -699,6 +248,7 @@ static unsigned int pnv_ioda_dma_weight(struct pci_dev *dev) return 10; } +#if 0 static struct pnv_ioda_pe * __devinit pnv_ioda_setup_dev_PE(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); @@ -767,6 +317,7 @@ static struct pnv_ioda_pe * __devinit pnv_ioda_setup_dev_PE(struct pci_dev *dev) return pe; } +#endif /* Useful for SRIOV case */ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe) { @@ -784,34 +335,33 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe) pdn->pcidev = dev; pdn->pe_number = pe->pe_number; pe->dma_weight += pnv_ioda_dma_weight(dev); - if (dev->subordinate) + if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate) pnv_ioda_setup_same_PE(dev->subordinate, pe); } } -static void __devinit pnv_ioda_setup_bus_PE(struct pci_dev *dev, - struct pnv_ioda_pe *ppe) +/* + * There're 2 types of PCI bus sensitive PEs: One that is compromised of + * single PCI bus. Another one that contains the primary PCI bus and its + * subordinate PCI devices and buses. The second type of PE is normally + * orgiriated by PCIe-to-PCI bridge or PLX switch downstream ports. + */ +static void __devinit pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all) { - struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pci_controller *hose = pci_bus_to_host(bus); struct pnv_phb *phb = hose->private_data; - struct pci_bus *bus = dev->subordinate; struct pnv_ioda_pe *pe; int pe_num; - if (!bus) { - pr_warning("%s: Bridge without a subordinate bus !\n", - pci_name(dev)); - return; - } pe_num = pnv_ioda_alloc_pe(phb); if (pe_num == IODA_INVALID_PE) { - pr_warning("%s: Not enough PE# available, disabling bus\n", - pci_name(dev)); + pr_warning("%s: Not enough PE# available for PCI bus %04x:%02x\n", + __func__, pci_domain_nr(bus), bus->number); return; } pe = &phb->ioda.pe_array[pe_num]; - ppe->bus_pe = pe; + pe->flags = (all ? PNV_IODA_PE_BUS_ALL : PNV_IODA_PE_BUS); pe->pbus = bus; pe->pdev = NULL; pe->tce32_seg = -1; @@ -819,8 +369,12 @@ static void __devinit pnv_ioda_setup_bus_PE(struct pci_dev *dev, pe->rid = bus->busn_res.start << 8; pe->dma_weight = 0; - pe_info(pe, "Secondary busses %pR associated with PE\n", - &bus->busn_res); + if (all) + pe_info(pe, "Secondary bus %d..%d associated with PE#%d\n", + bus->busn_res.start, bus->busn_res.end, pe_num); + else + pe_info(pe, "Secondary bus %d associated with PE#%d\n", + bus->busn_res.start, pe_num); if (pnv_ioda_configure_pe(phb, pe)) { /* XXX What do we do here ? */ @@ -833,6 +387,9 @@ static void __devinit pnv_ioda_setup_bus_PE(struct pci_dev *dev, /* Associate it with all child devices */ pnv_ioda_setup_same_PE(bus, pe); + /* Put PE to the list */ + list_add_tail(&pe->list, &phb->ioda.pe_list); + /* Account for one DMA PE if at least one DMA capable device exist * below the bridge */ @@ -848,17 +405,33 @@ static void __devinit pnv_ioda_setup_bus_PE(struct pci_dev *dev, static void __devinit pnv_ioda_setup_PEs(struct pci_bus *bus) { struct pci_dev *dev; - struct pnv_ioda_pe *pe; + + pnv_ioda_setup_bus_PE(bus, 0); list_for_each_entry(dev, &bus->devices, bus_list) { - pe = pnv_ioda_setup_dev_PE(dev); - if (pe == NULL) - continue; - /* Leaving the PCIe domain ... single PE# */ - if (pci_pcie_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) - pnv_ioda_setup_bus_PE(dev, pe); - else if (dev->subordinate) - pnv_ioda_setup_PEs(dev->subordinate); + if (dev->subordinate) { + if (pci_pcie_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) + pnv_ioda_setup_bus_PE(dev->subordinate, 1); + else + pnv_ioda_setup_PEs(dev->subordinate); + } + } +} + +/* + * Configure PEs so that the downstream PCI buses and devices + * could have their associated PE#. Unfortunately, we didn't + * figure out the way to identify the PLX bridge yet. So we + * simply put the PCI bus and the subordinate behind the root + * port to PE# here. The game rule here is expected to be changed + * as soon as we can detected PLX bridge correctly. + */ +static void __devinit pnv_pci_ioda_setup_PEs(void) +{ + struct pci_controller *hose, *tmp; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + pnv_ioda_setup_PEs(hose->bus); } } @@ -1000,7 +573,7 @@ static void __devinit pnv_ioda_setup_dma(struct pnv_phb *phb) remaining = phb->ioda.tce32_count; tw = phb->ioda.dma_weight; base = 0; - list_for_each_entry(pe, &phb->ioda.pe_list, link) { + list_for_each_entry(pe, &phb->ioda.pe_dma_list, dma_link) { if (!pe->dma_weight) continue; if (!remaining) { @@ -1109,36 +682,115 @@ static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { } #endif /* CONFIG_PCI_MSI */ -/* This is the starting point of our IODA specific resource - * allocation process +/* + * This function is supposed to be called on basis of PE from top + * to bottom style. So the the I/O or MMIO segment assigned to + * parent PE could be overrided by its child PEs if necessary. */ -static void __devinit pnv_pci_ioda_fixup_phb(struct pci_controller *hose) +static void __devinit pnv_ioda_setup_pe_seg(struct pci_controller *hose, + struct pnv_ioda_pe *pe) { - resource_size_t size, align; - struct pci_bus *child; + struct pnv_phb *phb = hose->private_data; + struct pci_bus_region region; + struct resource *res; + int i, index; + int rc; - /* Associate PEs per functions */ - pnv_ioda_setup_PEs(hose->bus); + /* + * NOTE: We only care PCI bus based PE for now. For PCI + * device based PE, for example SRIOV sensitive VF should + * be figured out later. + */ + BUG_ON(!(pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))); - /* Calculate all resources */ - pnv_ioda_calc_bus(hose->bus, IORESOURCE_IO, &size, &align); - pnv_ioda_calc_bus(hose->bus, IORESOURCE_MEM, &size, &align); + pci_bus_for_each_resource(pe->pbus, res, i) { + if (!res || !res->flags || + res->start > res->end) + continue; - /* Apply then to HW */ - pnv_ioda_update_resources(hose->bus); + if (res->flags & IORESOURCE_IO) { + region.start = res->start - phb->ioda.io_pci_base; + region.end = res->end - phb->ioda.io_pci_base; + index = region.start / phb->ioda.io_segsize; + + while (index < phb->ioda.total_pe && + region.start <= region.end) { + phb->ioda.io_segmap[index] = pe->pe_number; + rc = opal_pci_map_pe_mmio_window(phb->opal_id, + pe->pe_number, OPAL_IO_WINDOW_TYPE, 0, index); + if (rc != OPAL_SUCCESS) { + pr_err("%s: OPAL error %d when mapping IO " + "segment #%d to PE#%d\n", + __func__, rc, index, pe->pe_number); + break; + } + + region.start += phb->ioda.io_segsize; + index++; + } + } else if (res->flags & IORESOURCE_MEM) { + region.start = res->start - + hose->pci_mem_offset - + phb->ioda.m32_pci_base; + region.end = res->end - + hose->pci_mem_offset - + phb->ioda.m32_pci_base; + index = region.start / phb->ioda.m32_segsize; + + while (index < phb->ioda.total_pe && + region.start <= region.end) { + phb->ioda.m32_segmap[index] = pe->pe_number; + rc = opal_pci_map_pe_mmio_window(phb->opal_id, + pe->pe_number, OPAL_M32_WINDOW_TYPE, 0, index); + if (rc != OPAL_SUCCESS) { + pr_err("%s: OPAL error %d when mapping M32 " + "segment#%d to PE#%d", + __func__, rc, index, pe->pe_number); + break; + } + + region.start += phb->ioda.m32_segsize; + index++; + } + } + } +} - /* Setup DMA */ - pnv_ioda_setup_dma(hose->private_data); +static void __devinit pnv_pci_ioda_setup_seg(void) +{ + struct pci_controller *tmp, *hose; + struct pnv_phb *phb; + struct pnv_ioda_pe *pe; - /* Configure PCI Express settings */ - list_for_each_entry(child, &hose->bus->children, node) { - struct pci_dev *self = child->self; - if (!self) - continue; - pcie_bus_configure_settings(child, self->pcie_mpss); + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + phb = hose->private_data; + list_for_each_entry(pe, &phb->ioda.pe_list, list) { + pnv_ioda_setup_pe_seg(hose, pe); + } + } +} + +static void __devinit pnv_pci_ioda_setup_DMA(void) +{ + struct pci_controller *hose, *tmp; + struct pnv_phb *phb; + + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { + pnv_ioda_setup_dma(hose->private_data); + + /* Mark the PHB initialization done */ + phb = hose->private_data; + phb->initialized = 1; } } +static void __devinit pnv_pci_ioda_fixup(void) +{ + pnv_pci_ioda_setup_PEs(); + pnv_pci_ioda_setup_seg(); + pnv_pci_ioda_setup_DMA(); +} + /* * Returns the alignment for I/O or memory windows for P2P * bridges. That actually depends on how PEs are segmented. @@ -1182,10 +834,22 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus, */ static int __devinit pnv_pci_enable_device_hook(struct pci_dev *dev) { - struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + struct pci_controller *hose = pci_bus_to_host(dev->bus); + struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn; + /* The function is probably called while the PEs have + * not be created yet. For example, resource reassignment + * during PCI probe period. We just skip the check if + * PEs isn't ready. + */ + if (!phb->initialized) + return 0; + + pdn = pnv_ioda_get_pdn(dev); if (!pdn || pdn->pe_number == IODA_INVALID_PE) return -EINVAL; + return 0; } @@ -1276,9 +940,9 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) /* Allocate aux data & arrays */ size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); m32map_off = size; - size += phb->ioda.total_pe; + size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]); iomap_off = size; - size += phb->ioda.total_pe; + size += phb->ioda.total_pe * sizeof(phb->ioda.io_segmap[0]); pemap_off = size; size += phb->ioda.total_pe * sizeof(struct pnv_ioda_pe); aux = alloc_bootmem(size); @@ -1289,6 +953,7 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) phb->ioda.pe_array = aux + pemap_off; set_bit(0, phb->ioda.pe_alloc); + INIT_LIST_HEAD(&phb->ioda.pe_dma_list); INIT_LIST_HEAD(&phb->ioda.pe_list); /* Calculate how many 32-bit TCE segments we have */ @@ -1337,15 +1002,17 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) /* Setup MSI support */ pnv_pci_init_ioda_msis(phb); - /* We set both PCI_PROBE_ONLY and PCI_REASSIGN_ALL_RSRC. This is an - * odd combination which essentially means that we skip all resource - * fixups and assignments in the generic code, and do it all - * ourselves here + /* + * We pass the PCI probe flag PCI_REASSIGN_ALL_RSRC here + * to let the PCI core do resource assignment. It's supposed + * that the PCI core will do correct I/O and MMIO alignment + * for the P2P bridge bars so that each PCI bus (excluding + * the child P2P bridges) can form individual PE. */ - ppc_md.pcibios_fixup_phb = pnv_pci_ioda_fixup_phb; + ppc_md.pcibios_fixup = pnv_pci_ioda_fixup; ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook; ppc_md.pcibios_window_alignment = pnv_pci_window_alignment; - pci_add_flags(PCI_PROBE_ONLY | PCI_REASSIGN_ALL_RSRC); + pci_add_flags(PCI_REASSIGN_ALL_RSRC); /* Reset IODA tables to a clean state */ rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET); diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c index 264967770c3a..6b4bef4e9d82 100644 --- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c +++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c @@ -30,7 +30,6 @@ #include <asm/opal.h> #include <asm/iommu.h> #include <asm/tce.h> -#include <asm/abs_addr.h> #include "powernv.h" #include "pci.h" diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index be3cfc5ceabb..c01688a1a741 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -30,7 +30,6 @@ #include <asm/opal.h> #include <asm/iommu.h> #include <asm/tce.h> -#include <asm/abs_addr.h> #include <asm/firmware.h> #include "powernv.h" @@ -447,6 +446,11 @@ static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) pnv_tce_invalidate(tbl, tces, tcep - 1); } +static unsigned long pnv_tce_get(struct iommu_table *tbl, long index) +{ + return ((u64 *)tbl->it_base)[index - tbl->it_offset]; +} + void pnv_pci_setup_iommu_table(struct iommu_table *tbl, void *tce_mem, u64 tce_size, u64 dma_offset) @@ -597,6 +601,7 @@ void __init pnv_pci_init(void) ppc_md.pci_dma_dev_setup = pnv_pci_dma_dev_setup; ppc_md.tce_build = pnv_tce_build; ppc_md.tce_free = pnv_tce_free; + ppc_md.tce_get = pnv_tce_get; ppc_md.pci_probe_mode = pnv_pci_probe_mode; set_pci_dma_ops(&dma_iommu_ops); diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 8bc479634643..7cfb7c883deb 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -17,9 +17,14 @@ enum pnv_phb_model { }; #define PNV_PCI_DIAG_BUF_SIZE 4096 +#define PNV_IODA_PE_DEV (1 << 0) /* PE has single PCI device */ +#define PNV_IODA_PE_BUS (1 << 1) /* PE has primary PCI bus */ +#define PNV_IODA_PE_BUS_ALL (1 << 2) /* PE has subordinate buses */ /* Data associated with a PE, including IOMMU tracking etc.. */ struct pnv_ioda_pe { + unsigned long flags; + /* A PE can be associated with a single device or an * entire bus (& children). In the former case, pdev * is populated, in the later case, pbus is. @@ -40,11 +45,6 @@ struct pnv_ioda_pe { */ unsigned int dma_weight; - /* This is a PCI-E -> PCI-X bridge, this points to the - * corresponding bus PE - */ - struct pnv_ioda_pe *bus_pe; - /* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */ int tce32_seg; int tce32_segcount; @@ -59,7 +59,8 @@ struct pnv_ioda_pe { int mve_number; /* Link in list of PE#s */ - struct list_head link; + struct list_head dma_link; + struct list_head list; }; struct pnv_phb { @@ -68,6 +69,7 @@ struct pnv_phb { enum pnv_phb_model model; u64 opal_id; void __iomem *regs; + int initialized; spinlock_t lock; #ifdef CONFIG_PCI_MSI @@ -107,6 +109,11 @@ struct pnv_phb { unsigned int *io_segmap; struct pnv_ioda_pe *pe_array; + /* Sorted list of used PE's based + * on the sequence of creation + */ + struct list_head pe_list; + /* Reverse map of PEs, will have to extend if * we are to support more than 256 PEs, indexed * bus { bus, devfn } @@ -125,7 +132,7 @@ struct pnv_phb { /* Sorted list of used PE's, sorted at * boot for resource allocation purposes */ - struct list_head pe_list; + struct list_head pe_dma_list; } ioda; }; diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 3124cf791ebb..d00d7b0a3bda 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -43,7 +43,7 @@ enum ps3_lpar_vas_id { static DEFINE_SPINLOCK(ps3_htab_lock); -static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, +static long ps3_hpte_insert(unsigned long hpte_group, unsigned long vpn, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize, int ssize) { @@ -61,7 +61,7 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, */ vflags &= ~HPTE_V_SECONDARY; - hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(ps3_mm_phys_to_lpar(pa), psize) | rflags; spin_lock_irqsave(&ps3_htab_lock, flags); @@ -75,8 +75,8 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, if (result) { /* all entries bolted !*/ - pr_info("%s:result=%d va=%lx pa=%lx ix=%lx v=%llx r=%llx\n", - __func__, result, va, pa, hpte_group, hpte_v, hpte_r); + pr_info("%s:result=%d vpn=%lx pa=%lx ix=%lx v=%llx r=%llx\n", + __func__, result, vpn, pa, hpte_group, hpte_v, hpte_r); BUG(); } @@ -107,7 +107,7 @@ static long ps3_hpte_remove(unsigned long hpte_group) } static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int psize, int ssize, int local) + unsigned long vpn, int psize, int ssize, int local) { int result; u64 hpte_v, want_v, hpte_rs; @@ -115,7 +115,7 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long flags; long ret; - want_v = hpte_encode_v(va, psize, ssize); + want_v = hpte_encode_v(vpn, psize, ssize); spin_lock_irqsave(&ps3_htab_lock, flags); @@ -125,8 +125,8 @@ static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp, &hpte_rs); if (result) { - pr_info("%s: res=%d read va=%lx slot=%lx psize=%d\n", - __func__, result, va, slot, psize); + pr_info("%s: res=%d read vpn=%lx slot=%lx psize=%d\n", + __func__, result, vpn, slot, psize); BUG(); } @@ -159,7 +159,7 @@ static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, panic("ps3_hpte_updateboltedpp() not implemented"); } -static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, +static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn, int psize, int ssize, int local) { unsigned long flags; @@ -170,8 +170,8 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, result = lv1_write_htab_entry(PS3_LPAR_VAS_ID_CURRENT, slot, 0, 0); if (result) { - pr_info("%s: res=%d va=%lx slot=%lx psize=%d\n", - __func__, result, va, slot, psize); + pr_info("%s: res=%d vpn=%lx slot=%lx psize=%d\n", + __func__, result, vpn, slot, psize); BUG(); } diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 2d664c5a83b0..3f509f86432c 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -184,11 +184,15 @@ early_param("ps3flash", early_parse_ps3flash); #define prealloc_ps3flash_bounce_buffer() do { } while (0) #endif -static int ps3_set_dabr(unsigned long dabr) +static int ps3_set_dabr(unsigned long dabr, unsigned long dabrx) { - enum {DABR_USER = 1, DABR_KERNEL = 2,}; + /* Have to set at least one bit in the DABRX */ + if (dabrx == 0 && dabr == 0) + dabrx = DABRX_USER; + /* hypervisor only allows us to set BTI, Kernel and user */ + dabrx &= DABRX_BTI | DABRX_KERNEL | DABRX_USER; - return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0; + return lv1_set_dabr(dabr, dabrx) ? -1 : 0; } static void __init ps3_setup_arch(void) diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index c222189f5bb2..890622b87c8f 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -6,8 +6,9 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ firmware.o power.o dlpar.o mobility.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \ - eeh_event.o eeh_sysfs.o eeh_pseries.o +obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \ + eeh_driver.o eeh_event.o eeh_sysfs.o \ + eeh_pseries.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_PSERIES_MSI) += msi.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index ecd394cf34e6..9a04322b1736 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -92,6 +92,20 @@ struct eeh_ops *eeh_ops = NULL; int eeh_subsystem_enabled; EXPORT_SYMBOL(eeh_subsystem_enabled); +/* + * EEH probe mode support. The intention is to support multiple + * platforms for EEH. Some platforms like pSeries do PCI emunation + * based on device tree. However, other platforms like powernv probe + * PCI devices from hardware. The flag is used to distinguish that. + * In addition, struct eeh_ops::probe would be invoked for particular + * OF node or PCI device so that the corresponding PE would be created + * there. + */ +int eeh_probe_mode; + +/* Global EEH mutex */ +DEFINE_MUTEX(eeh_mutex); + /* Lock to avoid races due to multiple reports of an error */ static DEFINE_RAW_SPINLOCK(confirm_error_lock); @@ -204,22 +218,12 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) } } - /* Gather status on devices under the bridge */ - if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - struct device_node *child; - - for_each_child_of_node(dn, child) { - if (of_node_to_eeh_dev(child)) - n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n); - } - } - return n; } /** * eeh_slot_error_detail - Generate combined log including driver log and error log - * @edev: device to report error log for + * @pe: EEH PE * @severity: temporary or permanent error log * * This routine should be called to generate the combined log, which @@ -227,17 +231,22 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) * out from the config space of the corresponding PCI device, while * the error log is fetched through platform dependent function call. */ -void eeh_slot_error_detail(struct eeh_dev *edev, int severity) +void eeh_slot_error_detail(struct eeh_pe *pe, int severity) { size_t loglen = 0; - pci_regs_buf[0] = 0; + struct eeh_dev *edev; - eeh_pci_enable(edev, EEH_OPT_THAW_MMIO); - eeh_ops->configure_bridge(eeh_dev_to_of_node(edev)); - eeh_restore_bars(edev); - loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); + eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); + eeh_ops->configure_bridge(pe); + eeh_pe_restore_bars(pe); - eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen); + pci_regs_buf[0] = 0; + eeh_pe_for_each_dev(pe, edev) { + loglen += eeh_gather_pci_data(edev, pci_regs_buf, + EEH_PCI_REGS_LOG_LEN); + } + + eeh_ops->get_log(pe, severity, pci_regs_buf, loglen); } /** @@ -261,126 +270,8 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) } /** - * eeh_find_device_pe - Retrieve the PE for the given device - * @dn: device node - * - * Return the PE under which this device lies - */ -struct device_node *eeh_find_device_pe(struct device_node *dn) -{ - while (dn->parent && of_node_to_eeh_dev(dn->parent) && - (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { - dn = dn->parent; - } - return dn; -} - -/** - * __eeh_mark_slot - Mark all child devices as failed - * @parent: parent device - * @mode_flag: failure flag - * - * Mark all devices that are children of this device as failed. - * Mark the device driver too, so that it can see the failure - * immediately; this is critical, since some drivers poll - * status registers in interrupts ... If a driver is polling, - * and the slot is frozen, then the driver can deadlock in - * an interrupt context, which is bad. - */ -static void __eeh_mark_slot(struct device_node *parent, int mode_flag) -{ - struct device_node *dn; - - for_each_child_of_node(parent, dn) { - if (of_node_to_eeh_dev(dn)) { - /* Mark the pci device driver too */ - struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; - - of_node_to_eeh_dev(dn)->mode |= mode_flag; - - if (dev && dev->driver) - dev->error_state = pci_channel_io_frozen; - - __eeh_mark_slot(dn, mode_flag); - } - } -} - -/** - * eeh_mark_slot - Mark the indicated device and its children as failed - * @dn: parent device - * @mode_flag: failure flag - * - * Mark the indicated device and its child devices as failed. - * The device drivers are marked as failed as well. - */ -void eeh_mark_slot(struct device_node *dn, int mode_flag) -{ - struct pci_dev *dev; - dn = eeh_find_device_pe(dn); - - /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) - dn = dn->parent; - - of_node_to_eeh_dev(dn)->mode |= mode_flag; - - /* Mark the pci device too */ - dev = of_node_to_eeh_dev(dn)->pdev; - if (dev) - dev->error_state = pci_channel_io_frozen; - - __eeh_mark_slot(dn, mode_flag); -} - -/** - * __eeh_clear_slot - Clear failure flag for the child devices - * @parent: parent device - * @mode_flag: flag to be cleared - * - * Clear failure flag for the child devices. - */ -static void __eeh_clear_slot(struct device_node *parent, int mode_flag) -{ - struct device_node *dn; - - for_each_child_of_node(parent, dn) { - if (of_node_to_eeh_dev(dn)) { - of_node_to_eeh_dev(dn)->mode &= ~mode_flag; - of_node_to_eeh_dev(dn)->check_count = 0; - __eeh_clear_slot(dn, mode_flag); - } - } -} - -/** - * eeh_clear_slot - Clear failure flag for the indicated device and its children - * @dn: parent device - * @mode_flag: flag to be cleared - * - * Clear failure flag for the indicated device and its children. - */ -void eeh_clear_slot(struct device_node *dn, int mode_flag) -{ - unsigned long flags; - raw_spin_lock_irqsave(&confirm_error_lock, flags); - - dn = eeh_find_device_pe(dn); - - /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) - dn = dn->parent; - - of_node_to_eeh_dev(dn)->mode &= ~mode_flag; - of_node_to_eeh_dev(dn)->check_count = 0; - __eeh_clear_slot(dn, mode_flag); - raw_spin_unlock_irqrestore(&confirm_error_lock, flags); -} - -/** - * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze - * @dn: device node - * @dev: pci device, if known + * eeh_dev_check_failure - Check if all 1's data is due to EEH slot freeze + * @edev: eeh device * * Check for an EEH failure for the given device node. Call this * routine if the result of a read was all 0xff's and you want to @@ -392,11 +283,13 @@ void eeh_clear_slot(struct device_node *dn, int mode_flag) * * It is safe to call this routine in an interrupt context. */ -int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) +int eeh_dev_check_failure(struct eeh_dev *edev) { int ret; unsigned long flags; - struct eeh_dev *edev; + struct device_node *dn; + struct pci_dev *dev; + struct eeh_pe *pe; int rc = 0; const char *location; @@ -405,23 +298,23 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) if (!eeh_subsystem_enabled) return 0; - if (!dn) { + if (!edev) { eeh_stats.no_dn++; return 0; } - dn = eeh_find_device_pe(dn); - edev = of_node_to_eeh_dev(dn); + dn = eeh_dev_to_of_node(edev); + dev = eeh_dev_to_pci_dev(edev); + pe = edev->pe; /* Access to IO BARs might get this far and still not want checking. */ - if (!(edev->mode & EEH_MODE_SUPPORTED) || - edev->mode & EEH_MODE_NOCHECK) { + if (!pe) { eeh_stats.ignored_check++; - pr_debug("EEH: Ignored check (%x) for %s %s\n", - edev->mode, eeh_pci_name(dev), dn->full_name); + pr_debug("EEH: Ignored check for %s %s\n", + eeh_pci_name(dev), dn->full_name); return 0; } - if (!edev->config_addr && !edev->pe_config_addr) { + if (!pe->addr && !pe->config_addr) { eeh_stats.no_cfg_addr++; return 0; } @@ -434,13 +327,13 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) */ raw_spin_lock_irqsave(&confirm_error_lock, flags); rc = 1; - if (edev->mode & EEH_MODE_ISOLATED) { - edev->check_count++; - if (edev->check_count % EEH_MAX_FAILS == 0) { + if (pe->state & EEH_PE_ISOLATED) { + pe->check_count++; + if (pe->check_count % EEH_MAX_FAILS == 0) { location = of_get_property(dn, "ibm,loc-code", NULL); printk(KERN_ERR "EEH: %d reads ignored for recovering device at " "location=%s driver=%s pci addr=%s\n", - edev->check_count, location, + pe->check_count, location, eeh_driver_name(dev), eeh_pci_name(dev)); printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", eeh_driver_name(dev)); @@ -456,7 +349,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) * function zero of a multi-function device. * In any case they must share a common PHB. */ - ret = eeh_ops->get_state(dn, NULL); + ret = eeh_ops->get_state(pe, NULL); /* Note that config-io to empty slots may fail; * they are empty when they don't have children. @@ -469,7 +362,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { eeh_stats.false_positives++; - edev->false_positives ++; + pe->false_positives++; rc = 0; goto dn_unlock; } @@ -480,10 +373,10 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) * with other functions on this device, and functions under * bridges. */ - eeh_mark_slot(dn, EEH_MODE_ISOLATED); + eeh_pe_state_mark(pe, EEH_PE_ISOLATED); raw_spin_unlock_irqrestore(&confirm_error_lock, flags); - eeh_send_failure_event(edev); + eeh_send_failure_event(pe); /* Most EEH events are due to device driver bugs. Having * a stack trace will help the device-driver authors figure @@ -497,7 +390,7 @@ dn_unlock: return rc; } -EXPORT_SYMBOL_GPL(eeh_dn_check_failure); +EXPORT_SYMBOL_GPL(eeh_dev_check_failure); /** * eeh_check_failure - Check if all 1's data is due to EEH slot freeze @@ -514,21 +407,19 @@ EXPORT_SYMBOL_GPL(eeh_dn_check_failure); unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) { unsigned long addr; - struct pci_dev *dev; - struct device_node *dn; + struct eeh_dev *edev; /* Finding the phys addr + pci device; this is pretty quick. */ addr = eeh_token_to_phys((unsigned long __force) token); - dev = pci_addr_cache_get_device(addr); - if (!dev) { + edev = eeh_addr_cache_get_dev(addr); + if (!edev) { eeh_stats.no_device++; return val; } - dn = pci_device_to_OF_node(dev); - eeh_dn_check_failure(dn, dev); + eeh_dev_check_failure(edev); - pci_dev_put(dev); + pci_dev_put(eeh_dev_to_pci_dev(edev)); return val; } @@ -537,23 +428,22 @@ EXPORT_SYMBOL(eeh_check_failure); /** * eeh_pci_enable - Enable MMIO or DMA transfers for this slot - * @edev: pci device node + * @pe: EEH PE * * This routine should be called to reenable frozen MMIO or DMA * so that it would work correctly again. It's useful while doing * recovery or log collection on the indicated device. */ -int eeh_pci_enable(struct eeh_dev *edev, int function) +int eeh_pci_enable(struct eeh_pe *pe, int function) { int rc; - struct device_node *dn = eeh_dev_to_of_node(edev); - rc = eeh_ops->set_option(dn, function); + rc = eeh_ops->set_option(pe, function); if (rc) - printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", - function, rc, dn->full_name); + pr_warning("%s: Unexpected state change %d on PHB#%d-PE#%x, err=%d\n", + __func__, function, pe->phb->global_number, pe->addr, rc); - rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); + rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && (function == EEH_OPT_THAW_MMIO)) return 0; @@ -571,17 +461,24 @@ int eeh_pci_enable(struct eeh_dev *edev, int function) */ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) { - struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); + struct eeh_pe *pe = edev->pe; + + if (!pe) { + pr_err("%s: No PE found on PCI device %s\n", + __func__, pci_name(dev)); + return -EINVAL; + } switch (state) { case pcie_deassert_reset: - eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); + eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); break; case pcie_hot_reset: - eeh_ops->reset(dn, EEH_RESET_HOT); + eeh_ops->reset(pe, EEH_RESET_HOT); break; case pcie_warm_reset: - eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); + eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); break; default: return -EINVAL; @@ -591,66 +488,37 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat } /** - * __eeh_set_pe_freset - Check the required reset for child devices - * @parent: parent device - * @freset: return value - * - * Each device might have its preferred reset type: fundamental or - * hot reset. The routine is used to collect the information from - * the child devices so that they could be reset accordingly. - */ -void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) -{ - struct device_node *dn; - - for_each_child_of_node(parent, dn) { - if (of_node_to_eeh_dev(dn)) { - struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; - - if (dev && dev->driver) - *freset |= dev->needs_freset; - - __eeh_set_pe_freset(dn, freset); - } - } -} - -/** - * eeh_set_pe_freset - Check the required reset for the indicated device and its children - * @dn: parent device - * @freset: return value + * eeh_set_pe_freset - Check the required reset for the indicated device + * @data: EEH device + * @flag: return value * * Each device might have its preferred reset type: fundamental or * hot reset. The routine is used to collected the information for * the indicated device and its children so that the bunch of the * devices could be reset properly. */ -void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) +static void *eeh_set_dev_freset(void *data, void *flag) { struct pci_dev *dev; - dn = eeh_find_device_pe(dn); - - /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) - dn = dn->parent; + unsigned int *freset = (unsigned int *)flag; + struct eeh_dev *edev = (struct eeh_dev *)data; - dev = of_node_to_eeh_dev(dn)->pdev; + dev = eeh_dev_to_pci_dev(edev); if (dev) *freset |= dev->needs_freset; - __eeh_set_pe_freset(dn, freset); + return NULL; } /** * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second - * @edev: pci device node to be reset. + * @pe: EEH PE * * Assert the PCI #RST line for 1/4 second. */ -static void eeh_reset_pe_once(struct eeh_dev *edev) +static void eeh_reset_pe_once(struct eeh_pe *pe) { unsigned int freset = 0; - struct device_node *dn = eeh_dev_to_of_node(edev); /* Determine type of EEH reset required for * Partitionable Endpoint, a hot-reset (1) @@ -658,12 +526,12 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) * A fundamental reset required by any device under * Partitionable Endpoint trumps hot-reset. */ - eeh_set_pe_freset(dn, &freset); + eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset); if (freset) - eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); + eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); else - eeh_ops->reset(dn, EEH_RESET_HOT); + eeh_ops->reset(pe, EEH_RESET_HOT); /* The PCI bus requires that the reset be held high for at least * a 100 milliseconds. We wait a bit longer 'just in case'. @@ -675,9 +543,9 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) * pci slot reset line is dropped. Make sure we don't miss * these, and clear the flag now. */ - eeh_clear_slot(dn, EEH_MODE_ISOLATED); + eeh_pe_state_clear(pe, EEH_PE_ISOLATED); - eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); + eeh_ops->reset(pe, EEH_RESET_DEACTIVATE); /* After a PCI slot has been reset, the PCI Express spec requires * a 1.5 second idle time for the bus to stabilize, before starting @@ -689,116 +557,36 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) /** * eeh_reset_pe - Reset the indicated PE - * @edev: PCI device associated EEH device + * @pe: EEH PE * * This routine should be called to reset indicated device, including * PE. A PE might include multiple PCI devices and sometimes PCI bridges * might be involved as well. */ -int eeh_reset_pe(struct eeh_dev *edev) +int eeh_reset_pe(struct eeh_pe *pe) { int i, rc; - struct device_node *dn = eeh_dev_to_of_node(edev); /* Take three shots at resetting the bus */ for (i=0; i<3; i++) { - eeh_reset_pe_once(edev); + eeh_reset_pe_once(pe); - rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); + rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC); if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) return 0; if (rc < 0) { - printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", - dn->full_name); + pr_err("%s: Unrecoverable slot failure on PHB#%d-PE#%x", + __func__, pe->phb->global_number, pe->addr); return -1; } - printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", - i+1, dn->full_name, rc); + pr_err("EEH: bus reset %d failed on PHB#%d-PE#%x, rc=%d\n", + i+1, pe->phb->global_number, pe->addr, rc); } return -1; } -/** Save and restore of PCI BARs - * - * Although firmware will set up BARs during boot, it doesn't - * set up device BAR's after a device reset, although it will, - * if requested, set up bridge configuration. Thus, we need to - * configure the PCI devices ourselves. - */ - -/** - * eeh_restore_one_device_bars - Restore the Base Address Registers for one device - * @edev: PCI device associated EEH device - * - * Loads the PCI configuration space base address registers, - * the expansion ROM base address, the latency timer, and etc. - * from the saved values in the device node. - */ -static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) -{ - int i; - u32 cmd; - struct device_node *dn = eeh_dev_to_of_node(edev); - - if (!edev->phb) - return; - - for (i=4; i<10; i++) { - eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); - } - - /* 12 == Expansion ROM Address */ - eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); - -#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) -#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) - - eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, - SAVED_BYTE(PCI_CACHE_LINE_SIZE)); - - eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, - SAVED_BYTE(PCI_LATENCY_TIMER)); - - /* max latency, min grant, interrupt pin and line */ - eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); - - /* Restore PERR & SERR bits, some devices require it, - * don't touch the other command bits - */ - eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); - if (edev->config_space[1] & PCI_COMMAND_PARITY) - cmd |= PCI_COMMAND_PARITY; - else - cmd &= ~PCI_COMMAND_PARITY; - if (edev->config_space[1] & PCI_COMMAND_SERR) - cmd |= PCI_COMMAND_SERR; - else - cmd &= ~PCI_COMMAND_SERR; - eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); -} - -/** - * eeh_restore_bars - Restore the PCI config space info - * @edev: EEH device - * - * This routine performs a recursive walk to the children - * of this device as well. - */ -void eeh_restore_bars(struct eeh_dev *edev) -{ - struct device_node *dn; - if (!edev) - return; - - if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) - eeh_restore_one_device_bars(edev); - - for_each_child_of_node(eeh_dev_to_of_node(edev), dn) - eeh_restore_bars(of_node_to_eeh_dev(dn)); -} - /** * eeh_save_bars - Save device bars * @edev: PCI device associated EEH device @@ -808,7 +596,7 @@ void eeh_restore_bars(struct eeh_dev *edev) * PCI devices are added individually; but, for the restore, * an entire slot is reset at a time. */ -static void eeh_save_bars(struct eeh_dev *edev) +void eeh_save_bars(struct eeh_dev *edev) { int i; struct device_node *dn; @@ -822,102 +610,6 @@ static void eeh_save_bars(struct eeh_dev *edev) } /** - * eeh_early_enable - Early enable EEH on the indicated device - * @dn: device node - * @data: BUID - * - * Enable EEH functionality on the specified PCI device. The function - * is expected to be called before real PCI probing is done. However, - * the PHBs have been initialized at this point. - */ -static void *eeh_early_enable(struct device_node *dn, void *data) -{ - int ret; - const u32 *class_code = of_get_property(dn, "class-code", NULL); - const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); - const u32 *device_id = of_get_property(dn, "device-id", NULL); - const u32 *regs; - int enable; - struct eeh_dev *edev = of_node_to_eeh_dev(dn); - - edev->class_code = 0; - edev->mode = 0; - edev->check_count = 0; - edev->freeze_count = 0; - edev->false_positives = 0; - - if (!of_device_is_available(dn)) - return NULL; - - /* Ignore bad nodes. */ - if (!class_code || !vendor_id || !device_id) - return NULL; - - /* There is nothing to check on PCI to ISA bridges */ - if (dn->type && !strcmp(dn->type, "isa")) { - edev->mode |= EEH_MODE_NOCHECK; - return NULL; - } - edev->class_code = *class_code; - - /* Ok... see if this device supports EEH. Some do, some don't, - * and the only way to find out is to check each and every one. - */ - regs = of_get_property(dn, "reg", NULL); - if (regs) { - /* First register entry is addr (00BBSS00) */ - /* Try to enable eeh */ - ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE); - - enable = 0; - if (ret == 0) { - edev->config_addr = regs[0]; - - /* If the newer, better, ibm,get-config-addr-info is supported, - * then use that instead. - */ - edev->pe_config_addr = eeh_ops->get_pe_addr(dn); - - /* Some older systems (Power4) allow the - * ibm,set-eeh-option call to succeed even on nodes - * where EEH is not supported. Verify support - * explicitly. - */ - ret = eeh_ops->get_state(dn, NULL); - if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) - enable = 1; - } - - if (enable) { - eeh_subsystem_enabled = 1; - edev->mode |= EEH_MODE_SUPPORTED; - - pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", - dn->full_name, edev->config_addr, - edev->pe_config_addr); - } else { - - /* This device doesn't support EEH, but it may have an - * EEH parent, in which case we mark it as supported. - */ - if (dn->parent && of_node_to_eeh_dev(dn->parent) && - (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { - /* Parent supports EEH. */ - edev->mode |= EEH_MODE_SUPPORTED; - edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; - return NULL; - } - } - } else { - printk(KERN_WARNING "EEH: %s: unable to get reg property.\n", - dn->full_name); - } - - eeh_save_bars(edev); - return NULL; -} - -/** * eeh_ops_register - Register platform dependent EEH operations * @ops: platform dependent EEH operations * @@ -982,7 +674,7 @@ int __exit eeh_ops_unregister(const char *name) * Even if force-off is set, the EEH hardware is still enabled, so that * newer systems can boot. */ -void __init eeh_init(void) +static int __init eeh_init(void) { struct pci_controller *hose, *tmp; struct device_node *phb; @@ -992,27 +684,34 @@ void __init eeh_init(void) if (!eeh_ops) { pr_warning("%s: Platform EEH operation not found\n", __func__); - return; + return -EEXIST; } else if ((ret = eeh_ops->init())) { pr_warning("%s: Failed to call platform init function (%d)\n", __func__, ret); - return; + return ret; } raw_spin_lock_init(&confirm_error_lock); /* Enable EEH for all adapters */ - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - phb = hose->dn; - traverse_pci_devices(phb, eeh_early_enable, NULL); + if (eeh_probe_mode_devtree()) { + list_for_each_entry_safe(hose, tmp, + &hose_list, list_node) { + phb = hose->dn; + traverse_pci_devices(phb, eeh_ops->of_probe, NULL); + } } if (eeh_subsystem_enabled) - printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n"); + pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); else - printk(KERN_WARNING "EEH: No capable adapters found\n"); + pr_warning("EEH: No capable adapters found\n"); + + return ret; } +core_initcall_sync(eeh_init); + /** * eeh_add_device_early - Enable EEH for the indicated device_node * @dn: device node for which to set up EEH @@ -1029,7 +728,7 @@ static void eeh_add_device_early(struct device_node *dn) { struct pci_controller *phb; - if (!dn || !of_node_to_eeh_dev(dn)) + if (!of_node_to_eeh_dev(dn)) return; phb = of_node_to_eeh_dev(dn)->phb; @@ -1037,7 +736,8 @@ static void eeh_add_device_early(struct device_node *dn) if (NULL == phb || 0 == phb->buid) return; - eeh_early_enable(dn, NULL); + /* FIXME: hotplug support on POWERNV */ + eeh_ops->of_probe(dn, NULL); } /** @@ -1087,7 +787,7 @@ static void eeh_add_device_late(struct pci_dev *dev) edev->pdev = dev; dev->dev.archdata.edev = edev; - pci_addr_cache_insert_device(dev); + eeh_addr_cache_insert_dev(dev); eeh_sysfs_add_device(dev); } @@ -1117,6 +817,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); /** * eeh_remove_device - Undo EEH setup for the indicated pci device * @dev: pci device to be removed + * @purge_pe: remove the PE or not * * This routine should be called when a device is removed from * a running system (e.g. by hotplug or dlpar). It unregisters @@ -1124,7 +825,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); * this device will no longer be detected after this call; thus, * i/o errors affecting this slot may leave this device unusable. */ -static void eeh_remove_device(struct pci_dev *dev) +static void eeh_remove_device(struct pci_dev *dev, int purge_pe) { struct eeh_dev *edev; @@ -1143,28 +844,30 @@ static void eeh_remove_device(struct pci_dev *dev) dev->dev.archdata.edev = NULL; pci_dev_put(dev); - pci_addr_cache_remove_device(dev); + eeh_rmv_from_parent_pe(edev, purge_pe); + eeh_addr_cache_rmv_dev(dev); eeh_sysfs_remove_device(dev); } /** * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device * @dev: PCI device + * @purge_pe: remove the corresponding PE or not * * This routine must be called when a device is removed from the * running system through hotplug or dlpar. The corresponding * PCI address cache will be removed. */ -void eeh_remove_bus_device(struct pci_dev *dev) +void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { struct pci_bus *bus = dev->subordinate; struct pci_dev *child, *tmp; - eeh_remove_device(dev); + eeh_remove_device(dev, purge_pe); if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) - eeh_remove_bus_device(child); + eeh_remove_bus_device(child, purge_pe); } } EXPORT_SYMBOL_GPL(eeh_remove_bus_device); diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index e5ae1c687c66..5a4c87903057 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -50,6 +50,7 @@ struct pci_io_addr_range { struct rb_node rb_node; unsigned long addr_lo; unsigned long addr_hi; + struct eeh_dev *edev; struct pci_dev *pcidev; unsigned int flags; }; @@ -59,7 +60,7 @@ static struct pci_io_addr_cache { spinlock_t piar_lock; } pci_io_addr_cache_root; -static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) +static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr) { struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; @@ -74,7 +75,7 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) n = n->rb_right; } else { pci_dev_get(piar->pcidev); - return piar->pcidev; + return piar->edev; } } } @@ -83,7 +84,7 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) } /** - * pci_addr_cache_get_device - Get device, given only address + * eeh_addr_cache_get_dev - Get device, given only address * @addr: mmio (PIO) phys address or i/o port number * * Given an mmio phys address, or a port number, find a pci device @@ -92,15 +93,15 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) * from zero (that is, they do *not* have pci_io_addr added in). * It is safe to call this function within an interrupt. */ -struct pci_dev *pci_addr_cache_get_device(unsigned long addr) +struct eeh_dev *eeh_addr_cache_get_dev(unsigned long addr) { - struct pci_dev *dev; + struct eeh_dev *edev; unsigned long flags; spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - dev = __pci_addr_cache_get_device(addr); + edev = __eeh_addr_cache_get_device(addr); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); - return dev; + return edev; } #ifdef DEBUG @@ -108,7 +109,7 @@ struct pci_dev *pci_addr_cache_get_device(unsigned long addr) * Handy-dandy debug print routine, does nothing more * than print out the contents of our addr cache. */ -static void pci_addr_cache_print(struct pci_io_addr_cache *cache) +static void eeh_addr_cache_print(struct pci_io_addr_cache *cache) { struct rb_node *n; int cnt = 0; @@ -117,7 +118,7 @@ static void pci_addr_cache_print(struct pci_io_addr_cache *cache) while (n) { struct pci_io_addr_range *piar; piar = rb_entry(n, struct pci_io_addr_range, rb_node); - printk(KERN_DEBUG "PCI: %s addr range %d [%lx-%lx]: %s\n", + pr_debug("PCI: %s addr range %d [%lx-%lx]: %s\n", (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt, piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev)); cnt++; @@ -128,7 +129,7 @@ static void pci_addr_cache_print(struct pci_io_addr_cache *cache) /* Insert address range into the rb tree. */ static struct pci_io_addr_range * -pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, +eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo, unsigned long ahi, unsigned int flags) { struct rb_node **p = &pci_io_addr_cache_root.rb_root.rb_node; @@ -146,23 +147,24 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, } else { if (dev != piar->pcidev || alo != piar->addr_lo || ahi != piar->addr_hi) { - printk(KERN_WARNING "PIAR: overlapping address range\n"); + pr_warning("PIAR: overlapping address range\n"); } return piar; } } - piar = kmalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC); + piar = kzalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC); if (!piar) return NULL; pci_dev_get(dev); piar->addr_lo = alo; piar->addr_hi = ahi; + piar->edev = pci_dev_to_eeh_dev(dev); piar->pcidev = dev; piar->flags = flags; #ifdef DEBUG - printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", + pr_debug("PIAR: insert range=[%lx:%lx] dev=%s\n", alo, ahi, pci_name(dev)); #endif @@ -172,7 +174,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, return piar; } -static void __pci_addr_cache_insert_device(struct pci_dev *dev) +static void __eeh_addr_cache_insert_dev(struct pci_dev *dev) { struct device_node *dn; struct eeh_dev *edev; @@ -180,7 +182,7 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) dn = pci_device_to_OF_node(dev); if (!dn) { - printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", pci_name(dev)); + pr_warning("PCI: no pci dn found for dev=%s\n", pci_name(dev)); return; } @@ -192,8 +194,7 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) } /* Skip any devices for which EEH is not enabled. */ - if (!(edev->mode & EEH_MODE_SUPPORTED) || - edev->mode & EEH_MODE_NOCHECK) { + if (!edev->pe) { #ifdef DEBUG pr_info("PCI: skip building address cache for=%s - %s\n", pci_name(dev), dn->full_name); @@ -212,19 +213,19 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) continue; if (start == 0 || ~start == 0 || end == 0 || ~end == 0) continue; - pci_addr_cache_insert(dev, start, end, flags); + eeh_addr_cache_insert(dev, start, end, flags); } } /** - * pci_addr_cache_insert_device - Add a device to the address cache + * eeh_addr_cache_insert_dev - Add a device to the address cache * @dev: PCI device whose I/O addresses we are interested in. * * In order to support the fast lookup of devices based on addresses, * we maintain a cache of devices that can be quickly searched. * This routine adds a device to that cache. */ -void pci_addr_cache_insert_device(struct pci_dev *dev) +void eeh_addr_cache_insert_dev(struct pci_dev *dev) { unsigned long flags; @@ -233,11 +234,11 @@ void pci_addr_cache_insert_device(struct pci_dev *dev) return; spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - __pci_addr_cache_insert_device(dev); + __eeh_addr_cache_insert_dev(dev); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); } -static inline void __pci_addr_cache_remove_device(struct pci_dev *dev) +static inline void __eeh_addr_cache_rmv_dev(struct pci_dev *dev) { struct rb_node *n; @@ -258,7 +259,7 @@ restart: } /** - * pci_addr_cache_remove_device - remove pci device from addr cache + * eeh_addr_cache_rmv_dev - remove pci device from addr cache * @dev: device to remove * * Remove a device from the addr-cache tree. @@ -266,17 +267,17 @@ restart: * the tree multiple times (once per resource). * But so what; device removal doesn't need to be that fast. */ -void pci_addr_cache_remove_device(struct pci_dev *dev) +void eeh_addr_cache_rmv_dev(struct pci_dev *dev) { unsigned long flags; spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - __pci_addr_cache_remove_device(dev); + __eeh_addr_cache_rmv_dev(dev); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); } /** - * pci_addr_cache_build - Build a cache of I/O addresses + * eeh_addr_cache_build - Build a cache of I/O addresses * * Build a cache of pci i/o addresses. This cache will be used to * find the pci device that corresponds to a given address. @@ -284,7 +285,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) * Must be run late in boot process, after the pci controllers * have been scanned for devices (after all device resources are known). */ -void __init pci_addr_cache_build(void) +void __init eeh_addr_cache_build(void) { struct device_node *dn; struct eeh_dev *edev; @@ -293,7 +294,7 @@ void __init pci_addr_cache_build(void) spin_lock_init(&pci_io_addr_cache_root.piar_lock); for_each_pci_dev(dev) { - pci_addr_cache_insert_device(dev); + eeh_addr_cache_insert_dev(dev); dn = pci_device_to_OF_node(dev); if (!dn) @@ -312,7 +313,7 @@ void __init pci_addr_cache_build(void) #ifdef DEBUG /* Verify tree built up above, echo back the list of addrs. */ - pci_addr_cache_print(&pci_io_addr_cache_root); + eeh_addr_cache_print(&pci_io_addr_cache_root); #endif } diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c index c4507d095900..66442341d3a6 100644 --- a/arch/powerpc/platforms/pseries/eeh_dev.c +++ b/arch/powerpc/platforms/pseries/eeh_dev.c @@ -55,7 +55,7 @@ void * __devinit eeh_dev_init(struct device_node *dn, void *data) struct eeh_dev *edev; /* Allocate EEH device */ - edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL); + edev = kzalloc(sizeof(*edev), GFP_KERNEL); if (!edev) { pr_warning("%s: out of memory\n", __func__); return NULL; @@ -65,6 +65,7 @@ void * __devinit eeh_dev_init(struct device_node *dn, void *data) PCI_DN(dn)->edev = edev; edev->dn = dn; edev->phb = phb; + INIT_LIST_HEAD(&edev->list); return NULL; } @@ -80,6 +81,9 @@ void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) { struct device_node *dn = phb->dn; + /* EEH PE for PHB */ + eeh_phb_pe_create(phb); + /* EEH device for PHB */ eeh_dev_init(dn, phb); @@ -93,10 +97,16 @@ void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) * Scan all the existing PHBs and create EEH devices for their OF * nodes and their children OF nodes */ -void __init eeh_dev_phb_init(void) +static int __init eeh_dev_phb_init(void) { struct pci_controller *phb, *tmp; list_for_each_entry_safe(phb, tmp, &hose_list, list_node) eeh_dev_phb_init_dynamic(phb); + + pr_info("EEH: devices created\n"); + + return 0; } + +core_initcall(eeh_dev_phb_init); diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index baf92cd9dfab..a3fefb61097c 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -25,6 +25,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/module.h> #include <linux/pci.h> #include <asm/eeh.h> #include <asm/eeh_event.h> @@ -47,6 +48,41 @@ static inline const char *eeh_pcid_name(struct pci_dev *pdev) return ""; } +/** + * eeh_pcid_get - Get the PCI device driver + * @pdev: PCI device + * + * The function is used to retrieve the PCI device driver for + * the indicated PCI device. Besides, we will increase the reference + * of the PCI device driver to prevent that being unloaded on + * the fly. Otherwise, kernel crash would be seen. + */ +static inline struct pci_driver *eeh_pcid_get(struct pci_dev *pdev) +{ + if (!pdev || !pdev->driver) + return NULL; + + if (!try_module_get(pdev->driver->driver.owner)) + return NULL; + + return pdev->driver; +} + +/** + * eeh_pcid_put - Dereference on the PCI device driver + * @pdev: PCI device + * + * The function is called to do dereference on the PCI device + * driver of the indicated PCI device. + */ +static inline void eeh_pcid_put(struct pci_dev *pdev) +{ + if (!pdev || !pdev->driver) + return; + + module_put(pdev->driver->driver.owner); +} + #if 0 static void print_device_node_tree(struct pci_dn *pdn, int dent) { @@ -93,7 +129,7 @@ static void eeh_disable_irq(struct pci_dev *dev) if (!irq_has_action(dev->irq)) return; - edev->mode |= EEH_MODE_IRQ_DISABLED; + edev->mode |= EEH_DEV_IRQ_DISABLED; disable_irq_nosync(dev->irq); } @@ -108,36 +144,44 @@ static void eeh_enable_irq(struct pci_dev *dev) { struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); - if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { - edev->mode &= ~EEH_MODE_IRQ_DISABLED; + if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { + edev->mode &= ~EEH_DEV_IRQ_DISABLED; enable_irq(dev->irq); } } /** * eeh_report_error - Report pci error to each device driver - * @dev: PCI device + * @data: eeh device * @userdata: return value * * Report an EEH error to each device driver, collect up and * merge the device driver responses. Cumulative response * passed back in "userdata". */ -static int eeh_report_error(struct pci_dev *dev, void *userdata) +static void *eeh_report_error(void *data, void *userdata) { + struct eeh_dev *edev = (struct eeh_dev *)data; + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); enum pci_ers_result rc, *res = userdata; - struct pci_driver *driver = dev->driver; + struct pci_driver *driver; + /* We might not have the associated PCI device, + * then we should continue for next one. + */ + if (!dev) return NULL; dev->error_state = pci_channel_io_frozen; - if (!driver) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return NULL; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) - return 0; + !driver->err_handler->error_detected) { + eeh_pcid_put(dev); + return NULL; + } rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); @@ -145,27 +189,34 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; - return 0; + eeh_pcid_put(dev); + return NULL; } /** * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled - * @dev: PCI device + * @data: eeh device * @userdata: return value * * Tells each device driver that IO ports, MMIO and config space I/O * are now enabled. Collects up and merges the device driver responses. * Cumulative response passed back in "userdata". */ -static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) +static void *eeh_report_mmio_enabled(void *data, void *userdata) { + struct eeh_dev *edev = (struct eeh_dev *)data; + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); enum pci_ers_result rc, *res = userdata; - struct pci_driver *driver = dev->driver; + struct pci_driver *driver; - if (!driver || - !driver->err_handler || - !driver->err_handler->mmio_enabled) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return NULL; + + if (!driver->err_handler || + !driver->err_handler->mmio_enabled) { + eeh_pcid_put(dev); + return NULL; + } rc = driver->err_handler->mmio_enabled(dev); @@ -173,12 +224,13 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; - return 0; + eeh_pcid_put(dev); + return NULL; } /** * eeh_report_reset - Tell device that slot has been reset - * @dev: PCI device + * @data: eeh device * @userdata: return value * * This routine must be called while EEH tries to reset particular @@ -186,21 +238,26 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) * some actions, usually to save data the driver needs so that the * driver can work again while the device is recovered. */ -static int eeh_report_reset(struct pci_dev *dev, void *userdata) +static void *eeh_report_reset(void *data, void *userdata) { + struct eeh_dev *edev = (struct eeh_dev *)data; + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); enum pci_ers_result rc, *res = userdata; - struct pci_driver *driver = dev->driver; - - if (!driver) - return 0; + struct pci_driver *driver; + if (!dev) return NULL; dev->error_state = pci_channel_io_normal; + driver = eeh_pcid_get(dev); + if (!driver) return NULL; + eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->slot_reset) - return 0; + !driver->err_handler->slot_reset) { + eeh_pcid_put(dev); + return NULL; + } rc = driver->err_handler->slot_reset(dev); if ((*res == PCI_ERS_RESULT_NONE) || @@ -208,109 +265,115 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) if (*res == PCI_ERS_RESULT_DISCONNECT && rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; - return 0; + eeh_pcid_put(dev); + return NULL; } /** * eeh_report_resume - Tell device to resume normal operations - * @dev: PCI device + * @data: eeh device * @userdata: return value * * This routine must be called to notify the device driver that it * could resume so that the device driver can do some initialization * to make the recovered device work again. */ -static int eeh_report_resume(struct pci_dev *dev, void *userdata) +static void *eeh_report_resume(void *data, void *userdata) { - struct pci_driver *driver = dev->driver; + struct eeh_dev *edev = (struct eeh_dev *)data; + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); + struct pci_driver *driver; + if (!dev) return NULL; dev->error_state = pci_channel_io_normal; - if (!driver) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return NULL; eeh_enable_irq(dev); if (!driver->err_handler || - !driver->err_handler->resume) - return 0; + !driver->err_handler->resume) { + eeh_pcid_put(dev); + return NULL; + } driver->err_handler->resume(dev); - return 0; + eeh_pcid_put(dev); + return NULL; } /** * eeh_report_failure - Tell device driver that device is dead. - * @dev: PCI device + * @data: eeh device * @userdata: return value * * This informs the device driver that the device is permanently * dead, and that no further recovery attempts will be made on it. */ -static int eeh_report_failure(struct pci_dev *dev, void *userdata) +static void *eeh_report_failure(void *data, void *userdata) { - struct pci_driver *driver = dev->driver; + struct eeh_dev *edev = (struct eeh_dev *)data; + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); + struct pci_driver *driver; + if (!dev) return NULL; dev->error_state = pci_channel_io_perm_failure; - if (!driver) - return 0; + driver = eeh_pcid_get(dev); + if (!driver) return NULL; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) - return 0; + !driver->err_handler->error_detected) { + eeh_pcid_put(dev); + return NULL; + } driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); - return 0; + eeh_pcid_put(dev); + return NULL; } /** * eeh_reset_device - Perform actual reset of a pci slot - * @edev: PE associated EEH device + * @pe: EEH PE * @bus: PCI bus corresponding to the isolcated slot * * This routine must be called to do reset on the indicated PE. * During the reset, udev might be invoked because those affected * PCI devices will be removed and then added. */ -static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) +static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) { - struct device_node *dn; int cnt, rc; /* pcibios will clear the counter; save the value */ - cnt = edev->freeze_count; + cnt = pe->freeze_count; + /* + * We don't remove the corresponding PE instances because + * we need the information afterwords. The attached EEH + * devices are expected to be attached soon when calling + * into pcibios_add_pci_devices(). + */ if (bus) - pcibios_remove_pci_devices(bus); + __pcibios_remove_pci_devices(bus, 0); /* Reset the pci controller. (Asserts RST#; resets config space). * Reconfigure bridges and devices. Don't try to bring the system * up if the reset failed for some reason. */ - rc = eeh_reset_pe(edev); + rc = eeh_reset_pe(pe); if (rc) return rc; - /* Walk over all functions on this device. */ - dn = eeh_dev_to_of_node(edev); - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) - dn = dn->parent->child; - - while (dn) { - struct eeh_dev *pedev = of_node_to_eeh_dev(dn); - - /* On Power4, always true because eeh_pe_config_addr=0 */ - if (edev->pe_config_addr == pedev->pe_config_addr) { - eeh_ops->configure_bridge(dn); - eeh_restore_bars(pedev); - } - dn = dn->sibling; - } + /* Restore PE */ + eeh_ops->configure_bridge(pe); + eeh_pe_restore_bars(pe); /* Give the system 5 seconds to finish running the user-space * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, @@ -322,7 +385,7 @@ static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) ssleep(5); pcibios_add_pci_devices(bus); } - edev->freeze_count = cnt; + pe->freeze_count = cnt; return 0; } @@ -334,7 +397,7 @@ static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) /** * eeh_handle_event - Reset a PCI device after hard lockup. - * @event: EEH event + * @pe: EEH PE * * While PHB detects address or data parity errors on particular PCI * slot, the associated PE will be frozen. Besides, DMA's occurring @@ -349,69 +412,24 @@ static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) * drivers (which cause a second set of hotplug events to go out to * userspace). */ -struct eeh_dev *handle_eeh_events(struct eeh_event *event) +void eeh_handle_event(struct eeh_pe *pe) { - struct device_node *frozen_dn; - struct eeh_dev *frozen_edev; struct pci_bus *frozen_bus; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; - const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; - - frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev)); - if (!frozen_dn) { - location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL); - location = location ? location : "unknown"; - printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " - "for location=%s pci addr=%s\n", - location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev))); - return NULL; - } - - frozen_bus = pcibios_find_pci_bus(frozen_dn); - location = of_get_property(frozen_dn, "ibm,loc-code", NULL); - location = location ? location : "unknown"; - - /* There are two different styles for coming up with the PE. - * In the old style, it was the highest EEH-capable device - * which was always an EADS pci bridge. In the new style, - * there might not be any EADS bridges, and even when there are, - * the firmware marks them as "EEH incapable". So another - * two-step is needed to find the pci bus.. - */ - if (!frozen_bus) - frozen_bus = pcibios_find_pci_bus(frozen_dn->parent); + frozen_bus = eeh_pe_bus_get(pe); if (!frozen_bus) { - printk(KERN_ERR "EEH: Cannot find PCI bus " - "for location=%s dn=%s\n", - location, frozen_dn->full_name); - return NULL; + pr_err("%s: Cannot find PCI bus for PHB#%d-PE#%x\n", + __func__, pe->phb->global_number, pe->addr); + return; } - frozen_edev = of_node_to_eeh_dev(frozen_dn); - frozen_edev->freeze_count++; - pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev)); - drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev)); - - if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES) + pe->freeze_count++; + if (pe->freeze_count > EEH_MAX_ALLOWED_FREEZES) goto excess_failures; - - printk(KERN_WARNING - "EEH: This PCI device has failed %d times in the last hour:\n", - frozen_edev->freeze_count); - - if (frozen_edev->pdev) { - bus_pci_str = pci_name(frozen_edev->pdev); - bus_drv_str = eeh_pcid_name(frozen_edev->pdev); - printk(KERN_WARNING - "EEH: Bus location=%s driver=%s pci addr=%s\n", - location, bus_drv_str, bus_pci_str); - } - - printk(KERN_WARNING - "EEH: Device location=%s driver=%s pci addr=%s\n", - location, drv_str, pci_str); + pr_warning("EEH: This PCI device has failed %d times in the last hour\n", + pe->freeze_count); /* Walk the various device drivers attached to this slot through * a reset sequence, giving each an opportunity to do what it needs @@ -419,12 +437,12 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) * status ... if any child can't handle the reset, then the entire * slot is dlpar removed and added. */ - pci_walk_bus(frozen_bus, eeh_report_error, &result); + eeh_pe_dev_traverse(pe, eeh_report_error, &result); /* Get the current PCI slot state. This can take a long time, * sometimes over 3 seconds for certain systems. */ - rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000); + rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { printk(KERN_WARNING "EEH: Permanent failure\n"); goto hard_fail; @@ -434,14 +452,14 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) * don't post the error log until after all dev drivers * have been informed. */ - eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP); + eeh_slot_error_detail(pe, EEH_LOG_TEMP); /* If all device drivers were EEH-unaware, then shut * down all of the device drivers, and hope they * go down willingly, without panicing the system. */ if (result == PCI_ERS_RESULT_NONE) { - rc = eeh_reset_device(frozen_edev, frozen_bus); + rc = eeh_reset_device(pe, frozen_bus); if (rc) { printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); goto hard_fail; @@ -450,7 +468,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) /* If all devices reported they can proceed, then re-enable MMIO */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { - rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO); + rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); if (rc < 0) goto hard_fail; @@ -458,13 +476,13 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) result = PCI_ERS_RESULT_NEED_RESET; } else { result = PCI_ERS_RESULT_NONE; - pci_walk_bus(frozen_bus, eeh_report_mmio_enabled, &result); + eeh_pe_dev_traverse(pe, eeh_report_mmio_enabled, &result); } } /* If all devices reported they can proceed, then re-enable DMA */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { - rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA); + rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA); if (rc < 0) goto hard_fail; @@ -482,13 +500,13 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) /* If any device called out for a reset, then reset the slot */ if (result == PCI_ERS_RESULT_NEED_RESET) { - rc = eeh_reset_device(frozen_edev, NULL); + rc = eeh_reset_device(pe, NULL); if (rc) { printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); goto hard_fail; } result = PCI_ERS_RESULT_NONE; - pci_walk_bus(frozen_bus, eeh_report_reset, &result); + eeh_pe_dev_traverse(pe, eeh_report_reset, &result); } /* All devices should claim they have recovered by now. */ @@ -499,9 +517,9 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) } /* Tell all device drivers that they can resume operations */ - pci_walk_bus(frozen_bus, eeh_report_resume, NULL); + eeh_pe_dev_traverse(pe, eeh_report_resume, NULL); - return frozen_edev; + return; excess_failures: /* @@ -509,30 +527,26 @@ excess_failures: * are due to poorly seated PCI cards. Only 10% or so are * due to actual, failed cards. */ - printk(KERN_ERR - "EEH: PCI device at location=%s driver=%s pci addr=%s\n" - "has failed %d times in the last hour " - "and has been permanently disabled.\n" - "Please try reseating this device or replacing it.\n", - location, drv_str, pci_str, frozen_edev->freeze_count); + pr_err("EEH: PHB#%d-PE#%x has failed %d times in the\n" + "last hour and has been permanently disabled.\n" + "Please try reseating or replacing it.\n", + pe->phb->global_number, pe->addr, + pe->freeze_count); goto perm_error; hard_fail: - printk(KERN_ERR - "EEH: Unable to recover from failure of PCI device " - "at location=%s driver=%s pci addr=%s\n" - "Please try reseating this device or replacing it.\n", - location, drv_str, pci_str); + pr_err("EEH: Unable to recover from failure from PHB#%d-PE#%x.\n" + "Please try reseating or replacing it\n", + pe->phb->global_number, pe->addr); perm_error: - eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM); + eeh_slot_error_detail(pe, EEH_LOG_PERM); /* Notify all devices that they're about to go down. */ - pci_walk_bus(frozen_bus, eeh_report_failure, NULL); + eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); /* Shut down the device drivers for good. */ - pcibios_remove_pci_devices(frozen_bus); - - return NULL; + if (frozen_bus) + pcibios_remove_pci_devices(frozen_bus); } diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index fb506317ebb0..51faaac8abe6 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -57,7 +57,7 @@ static int eeh_event_handler(void * dummy) { unsigned long flags; struct eeh_event *event; - struct eeh_dev *edev; + struct eeh_pe *pe; set_task_comm(current, "eehd"); @@ -76,28 +76,23 @@ static int eeh_event_handler(void * dummy) /* Serialize processing of EEH events */ mutex_lock(&eeh_event_mutex); - edev = event->edev; - eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); - - printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", - eeh_pci_name(edev->pdev)); + pe = event->pe; + eeh_pe_state_mark(pe, EEH_PE_RECOVERING); + pr_info("EEH: Detected PCI bus error on PHB#%d-PE#%x\n", + pe->phb->global_number, pe->addr); set_current_state(TASK_INTERRUPTIBLE); /* Don't add to load average */ - edev = handle_eeh_events(event); - - if (edev) { - eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); - pci_dev_put(edev->pdev); - } + eeh_handle_event(pe); + eeh_pe_state_clear(pe, EEH_PE_RECOVERING); kfree(event); mutex_unlock(&eeh_event_mutex); /* If there are no new errors after an hour, clear the counter. */ - if (edev && edev->freeze_count>0) { + if (pe && pe->freeze_count > 0) { msleep_interruptible(3600*1000); - if (edev->freeze_count>0) - edev->freeze_count--; + if (pe->freeze_count > 0) + pe->freeze_count--; } @@ -119,36 +114,23 @@ static void eeh_thread_launcher(struct work_struct *dummy) /** * eeh_send_failure_event - Generate a PCI error event - * @edev: EEH device + * @pe: EEH PE * * This routine can be called within an interrupt context; * the actual event will be delivered in a normal context * (from a workqueue). */ -int eeh_send_failure_event(struct eeh_dev *edev) +int eeh_send_failure_event(struct eeh_pe *pe) { unsigned long flags; struct eeh_event *event; - struct device_node *dn = eeh_dev_to_of_node(edev); - const char *location; - - if (!mem_init_done) { - printk(KERN_ERR "EEH: event during early boot not handled\n"); - location = of_get_property(dn, "ibm,loc-code", NULL); - printk(KERN_ERR "EEH: device node = %s\n", dn->full_name); - printk(KERN_ERR "EEH: PCI location = %s\n", location); - return 1; - } - event = kmalloc(sizeof(*event), GFP_ATOMIC); - if (event == NULL) { - printk(KERN_ERR "EEH: out of memory, event not handled\n"); - return 1; - } - - if (edev->pdev) - pci_dev_get(edev->pdev); - event->edev = edev; + event = kzalloc(sizeof(*event), GFP_ATOMIC); + if (!event) { + pr_err("EEH: out of memory, event not handled\n"); + return -ENOMEM; + } + event->pe = pe; /* We may or may not be called in an interrupt context */ spin_lock_irqsave(&eeh_eventlist_lock, flags); diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c new file mode 100644 index 000000000000..797cd181dc3f --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_pe.c @@ -0,0 +1,652 @@ +/* + * The file intends to implement PE based on the information from + * platforms. Basically, there have 3 types of PEs: PHB/Bus/Device. + * All the PEs should be organized as hierarchy tree. The first level + * of the tree will be associated to existing PHBs since the particular + * PE is only meaningful in one PHB domain. + * + * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. + * + * 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 <linux/export.h> +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> + +#include <asm/pci-bridge.h> +#include <asm/ppc-pci.h> + +static LIST_HEAD(eeh_phb_pe); + +/** + * eeh_pe_alloc - Allocate PE + * @phb: PCI controller + * @type: PE type + * + * Allocate PE instance dynamically. + */ +static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type) +{ + struct eeh_pe *pe; + + /* Allocate PHB PE */ + pe = kzalloc(sizeof(struct eeh_pe), GFP_KERNEL); + if (!pe) return NULL; + + /* Initialize PHB PE */ + pe->type = type; + pe->phb = phb; + INIT_LIST_HEAD(&pe->child_list); + INIT_LIST_HEAD(&pe->child); + INIT_LIST_HEAD(&pe->edevs); + + return pe; +} + +/** + * eeh_phb_pe_create - Create PHB PE + * @phb: PCI controller + * + * The function should be called while the PHB is detected during + * system boot or PCI hotplug in order to create PHB PE. + */ +int __devinit eeh_phb_pe_create(struct pci_controller *phb) +{ + struct eeh_pe *pe; + + /* Allocate PHB PE */ + pe = eeh_pe_alloc(phb, EEH_PE_PHB); + if (!pe) { + pr_err("%s: out of memory!\n", __func__); + return -ENOMEM; + } + + /* Put it into the list */ + eeh_lock(); + list_add_tail(&pe->child, &eeh_phb_pe); + eeh_unlock(); + + pr_debug("EEH: Add PE for PHB#%d\n", phb->global_number); + + return 0; +} + +/** + * eeh_phb_pe_get - Retrieve PHB PE based on the given PHB + * @phb: PCI controller + * + * The overall PEs form hierarchy tree. The first layer of the + * hierarchy tree is composed of PHB PEs. The function is used + * to retrieve the corresponding PHB PE according to the given PHB. + */ +static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb) +{ + struct eeh_pe *pe; + + list_for_each_entry(pe, &eeh_phb_pe, child) { + /* + * Actually, we needn't check the type since + * the PE for PHB has been determined when that + * was created. + */ + if ((pe->type & EEH_PE_PHB) && pe->phb == phb) + return pe; + } + + return NULL; +} + +/** + * eeh_pe_next - Retrieve the next PE in the tree + * @pe: current PE + * @root: root PE + * + * The function is used to retrieve the next PE in the + * hierarchy PE tree. + */ +static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, + struct eeh_pe *root) +{ + struct list_head *next = pe->child_list.next; + + if (next == &pe->child_list) { + while (1) { + if (pe == root) + return NULL; + next = pe->child.next; + if (next != &pe->parent->child_list) + break; + pe = pe->parent; + } + } + + return list_entry(next, struct eeh_pe, child); +} + +/** + * eeh_pe_traverse - Traverse PEs in the specified PHB + * @root: root PE + * @fn: callback + * @flag: extra parameter to callback + * + * The function is used to traverse the specified PE and its + * child PEs. The traversing is to be terminated once the + * callback returns something other than NULL, or no more PEs + * to be traversed. + */ +static void *eeh_pe_traverse(struct eeh_pe *root, + eeh_traverse_func fn, void *flag) +{ + struct eeh_pe *pe; + void *ret; + + for (pe = root; pe; pe = eeh_pe_next(pe, root)) { + ret = fn(pe, flag); + if (ret) return ret; + } + + return NULL; +} + +/** + * eeh_pe_dev_traverse - Traverse the devices from the PE + * @root: EEH PE + * @fn: function callback + * @flag: extra parameter to callback + * + * The function is used to traverse the devices of the specified + * PE and its child PEs. + */ +void *eeh_pe_dev_traverse(struct eeh_pe *root, + eeh_traverse_func fn, void *flag) +{ + struct eeh_pe *pe; + struct eeh_dev *edev; + void *ret; + + if (!root) { + pr_warning("%s: Invalid PE %p\n", __func__, root); + return NULL; + } + + eeh_lock(); + + /* Traverse root PE */ + for (pe = root; pe; pe = eeh_pe_next(pe, root)) { + eeh_pe_for_each_dev(pe, edev) { + ret = fn(edev, flag); + if (ret) { + eeh_unlock(); + return ret; + } + } + } + + eeh_unlock(); + + return NULL; +} + +/** + * __eeh_pe_get - Check the PE address + * @data: EEH PE + * @flag: EEH device + * + * For one particular PE, it can be identified by PE address + * or tranditional BDF address. BDF address is composed of + * Bus/Device/Function number. The extra data referred by flag + * indicates which type of address should be used. + */ +static void *__eeh_pe_get(void *data, void *flag) +{ + struct eeh_pe *pe = (struct eeh_pe *)data; + struct eeh_dev *edev = (struct eeh_dev *)flag; + + /* Unexpected PHB PE */ + if (pe->type & EEH_PE_PHB) + return NULL; + + /* We prefer PE address */ + if (edev->pe_config_addr && + (edev->pe_config_addr == pe->addr)) + return pe; + + /* Try BDF address */ + if (edev->pe_config_addr && + (edev->config_addr == pe->config_addr)) + return pe; + + return NULL; +} + +/** + * eeh_pe_get - Search PE based on the given address + * @edev: EEH device + * + * Search the corresponding PE based on the specified address which + * is included in the eeh device. The function is used to check if + * the associated PE has been created against the PE address. It's + * notable that the PE address has 2 format: traditional PE address + * which is composed of PCI bus/device/function number, or unified + * PE address. + */ +static struct eeh_pe *eeh_pe_get(struct eeh_dev *edev) +{ + struct eeh_pe *root = eeh_phb_pe_get(edev->phb); + struct eeh_pe *pe; + + pe = eeh_pe_traverse(root, __eeh_pe_get, edev); + + return pe; +} + +/** + * eeh_pe_get_parent - Retrieve the parent PE + * @edev: EEH device + * + * The whole PEs existing in the system are organized as hierarchy + * tree. The function is used to retrieve the parent PE according + * to the parent EEH device. + */ +static struct eeh_pe *eeh_pe_get_parent(struct eeh_dev *edev) +{ + struct device_node *dn; + struct eeh_dev *parent; + + /* + * It might have the case for the indirect parent + * EEH device already having associated PE, but + * the direct parent EEH device doesn't have yet. + */ + dn = edev->dn->parent; + while (dn) { + /* We're poking out of PCI territory */ + if (!PCI_DN(dn)) return NULL; + + parent = of_node_to_eeh_dev(dn); + /* We're poking out of PCI territory */ + if (!parent) return NULL; + + if (parent->pe) + return parent->pe; + + dn = dn->parent; + } + + return NULL; +} + +/** + * eeh_add_to_parent_pe - Add EEH device to parent PE + * @edev: EEH device + * + * Add EEH device to the parent PE. If the parent PE already + * exists, the PE type will be changed to EEH_PE_BUS. Otherwise, + * we have to create new PE to hold the EEH device and the new + * PE will be linked to its parent PE as well. + */ +int eeh_add_to_parent_pe(struct eeh_dev *edev) +{ + struct eeh_pe *pe, *parent; + + eeh_lock(); + + /* + * Search the PE has been existing or not according + * to the PE address. If that has been existing, the + * PE should be composed of PCI bus and its subordinate + * components. + */ + pe = eeh_pe_get(edev); + if (pe && !(pe->type & EEH_PE_INVALID)) { + if (!edev->pe_config_addr) { + eeh_unlock(); + pr_err("%s: PE with addr 0x%x already exists\n", + __func__, edev->config_addr); + return -EEXIST; + } + + /* Mark the PE as type of PCI bus */ + pe->type = EEH_PE_BUS; + edev->pe = pe; + + /* Put the edev to PE */ + list_add_tail(&edev->list, &pe->edevs); + eeh_unlock(); + pr_debug("EEH: Add %s to Bus PE#%x\n", + edev->dn->full_name, pe->addr); + + return 0; + } else if (pe && (pe->type & EEH_PE_INVALID)) { + list_add_tail(&edev->list, &pe->edevs); + edev->pe = pe; + /* + * We're running to here because of PCI hotplug caused by + * EEH recovery. We need clear EEH_PE_INVALID until the top. + */ + parent = pe; + while (parent) { + if (!(parent->type & EEH_PE_INVALID)) + break; + parent->type &= ~EEH_PE_INVALID; + parent = parent->parent; + } + eeh_unlock(); + pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", + edev->dn->full_name, pe->addr, pe->parent->addr); + + return 0; + } + + /* Create a new EEH PE */ + pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE); + if (!pe) { + eeh_unlock(); + pr_err("%s: out of memory!\n", __func__); + return -ENOMEM; + } + pe->addr = edev->pe_config_addr; + pe->config_addr = edev->config_addr; + + /* + * Put the new EEH PE into hierarchy tree. If the parent + * can't be found, the newly created PE will be attached + * to PHB directly. Otherwise, we have to associate the + * PE with its parent. + */ + parent = eeh_pe_get_parent(edev); + if (!parent) { + parent = eeh_phb_pe_get(edev->phb); + if (!parent) { + eeh_unlock(); + pr_err("%s: No PHB PE is found (PHB Domain=%d)\n", + __func__, edev->phb->global_number); + edev->pe = NULL; + kfree(pe); + return -EEXIST; + } + } + pe->parent = parent; + + /* + * Put the newly created PE into the child list and + * link the EEH device accordingly. + */ + list_add_tail(&pe->child, &parent->child_list); + list_add_tail(&edev->list, &pe->edevs); + edev->pe = pe; + eeh_unlock(); + pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", + edev->dn->full_name, pe->addr, pe->parent->addr); + + return 0; +} + +/** + * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE + * @edev: EEH device + * @purge_pe: remove PE or not + * + * The PE hierarchy tree might be changed when doing PCI hotplug. + * Also, the PCI devices or buses could be removed from the system + * during EEH recovery. So we have to call the function remove the + * corresponding PE accordingly if necessary. + */ +int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) +{ + struct eeh_pe *pe, *parent, *child; + int cnt; + + if (!edev->pe) { + pr_warning("%s: No PE found for EEH device %s\n", + __func__, edev->dn->full_name); + return -EEXIST; + } + + eeh_lock(); + + /* Remove the EEH device */ + pe = edev->pe; + edev->pe = NULL; + list_del(&edev->list); + + /* + * Check if the parent PE includes any EEH devices. + * If not, we should delete that. Also, we should + * delete the parent PE if it doesn't have associated + * child PEs and EEH devices. + */ + while (1) { + parent = pe->parent; + if (pe->type & EEH_PE_PHB) + break; + + if (purge_pe) { + if (list_empty(&pe->edevs) && + list_empty(&pe->child_list)) { + list_del(&pe->child); + kfree(pe); + } else { + break; + } + } else { + if (list_empty(&pe->edevs)) { + cnt = 0; + list_for_each_entry(child, &pe->child_list, child) { + if (!(pe->type & EEH_PE_INVALID)) { + cnt++; + break; + } + } + + if (!cnt) + pe->type |= EEH_PE_INVALID; + else + break; + } + } + + pe = parent; + } + + eeh_unlock(); + + return 0; +} + +/** + * __eeh_pe_state_mark - Mark the state for the PE + * @data: EEH PE + * @flag: state + * + * The function is used to mark the indicated state for the given + * PE. Also, the associated PCI devices will be put into IO frozen + * state as well. + */ +static void *__eeh_pe_state_mark(void *data, void *flag) +{ + struct eeh_pe *pe = (struct eeh_pe *)data; + int state = *((int *)flag); + struct eeh_dev *tmp; + struct pci_dev *pdev; + + /* + * Mark the PE with the indicated state. Also, + * the associated PCI device will be put into + * I/O frozen state to avoid I/O accesses from + * the PCI device driver. + */ + pe->state |= state; + eeh_pe_for_each_dev(pe, tmp) { + pdev = eeh_dev_to_pci_dev(tmp); + if (pdev) + pdev->error_state = pci_channel_io_frozen; + } + + return NULL; +} + +/** + * eeh_pe_state_mark - Mark specified state for PE and its associated device + * @pe: EEH PE + * + * EEH error affects the current PE and its child PEs. The function + * is used to mark appropriate state for the affected PEs and the + * associated devices. + */ +void eeh_pe_state_mark(struct eeh_pe *pe, int state) +{ + eeh_lock(); + eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); + eeh_unlock(); +} + +/** + * __eeh_pe_state_clear - Clear state for the PE + * @data: EEH PE + * @flag: state + * + * The function is used to clear the indicated state from the + * given PE. Besides, we also clear the check count of the PE + * as well. + */ +static void *__eeh_pe_state_clear(void *data, void *flag) +{ + struct eeh_pe *pe = (struct eeh_pe *)data; + int state = *((int *)flag); + + pe->state &= ~state; + pe->check_count = 0; + + return NULL; +} + +/** + * eeh_pe_state_clear - Clear state for the PE and its children + * @pe: PE + * @state: state to be cleared + * + * When the PE and its children has been recovered from error, + * we need clear the error state for that. The function is used + * for the purpose. + */ +void eeh_pe_state_clear(struct eeh_pe *pe, int state) +{ + eeh_lock(); + eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); + eeh_unlock(); +} + +/** + * eeh_restore_one_device_bars - Restore the Base Address Registers for one device + * @data: EEH device + * @flag: Unused + * + * Loads the PCI configuration space base address registers, + * the expansion ROM base address, the latency timer, and etc. + * from the saved values in the device node. + */ +static void *eeh_restore_one_device_bars(void *data, void *flag) +{ + int i; + u32 cmd; + struct eeh_dev *edev = (struct eeh_dev *)data; + struct device_node *dn = eeh_dev_to_of_node(edev); + + for (i = 4; i < 10; i++) + eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); + /* 12 == Expansion ROM Address */ + eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); + +#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) +#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) + + eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, + SAVED_BYTE(PCI_CACHE_LINE_SIZE)); + eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, + SAVED_BYTE(PCI_LATENCY_TIMER)); + + /* max latency, min grant, interrupt pin and line */ + eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); + + /* + * Restore PERR & SERR bits, some devices require it, + * don't touch the other command bits + */ + eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); + if (edev->config_space[1] & PCI_COMMAND_PARITY) + cmd |= PCI_COMMAND_PARITY; + else + cmd &= ~PCI_COMMAND_PARITY; + if (edev->config_space[1] & PCI_COMMAND_SERR) + cmd |= PCI_COMMAND_SERR; + else + cmd &= ~PCI_COMMAND_SERR; + eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); + + return NULL; +} + +/** + * eeh_pe_restore_bars - Restore the PCI config space info + * @pe: EEH PE + * + * This routine performs a recursive walk to the children + * of this device as well. + */ +void eeh_pe_restore_bars(struct eeh_pe *pe) +{ + /* + * We needn't take the EEH lock since eeh_pe_dev_traverse() + * will take that. + */ + eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL); +} + +/** + * eeh_pe_bus_get - Retrieve PCI bus according to the given PE + * @pe: EEH PE + * + * Retrieve the PCI bus according to the given PE. Basically, + * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the + * primary PCI bus will be retrieved. The parent bus will be + * returned for BUS PE. However, we don't have associated PCI + * bus for DEVICE PE. + */ +struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) +{ + struct pci_bus *bus = NULL; + struct eeh_dev *edev; + struct pci_dev *pdev; + + eeh_lock(); + + if (pe->type & EEH_PE_PHB) { + bus = pe->phb->bus; + } else if (pe->type & EEH_PE_BUS) { + edev = list_first_entry(&pe->edevs, struct eeh_dev, list); + pdev = eeh_dev_to_pci_dev(edev); + if (pdev) + bus = pdev->bus; + } + + eeh_unlock(); + + return bus; +} diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index c33360ec4f4f..19506f935737 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -129,27 +129,117 @@ static int pseries_eeh_init(void) eeh_error_buf_size = RTAS_ERROR_LOG_MAX; } + /* Set EEH probe mode */ + eeh_probe_mode_set(EEH_PROBE_MODE_DEVTREE); + return 0; } /** + * pseries_eeh_of_probe - EEH probe on the given device + * @dn: OF node + * @flag: Unused + * + * When EEH module is installed during system boot, all PCI devices + * are checked one by one to see if it supports EEH. The function + * is introduced for the purpose. + */ +static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) +{ + struct eeh_dev *edev; + struct eeh_pe pe; + const u32 *class_code, *vendor_id, *device_id; + const u32 *regs; + int enable = 0; + int ret; + + /* Retrieve OF node and eeh device */ + edev = of_node_to_eeh_dev(dn); + if (!of_device_is_available(dn)) + return NULL; + + /* Retrieve class/vendor/device IDs */ + class_code = of_get_property(dn, "class-code", NULL); + vendor_id = of_get_property(dn, "vendor-id", NULL); + device_id = of_get_property(dn, "device-id", NULL); + + /* Skip for bad OF node or PCI-ISA bridge */ + if (!class_code || !vendor_id || !device_id) + return NULL; + if (dn->type && !strcmp(dn->type, "isa")) + return NULL; + + /* Update class code and mode of eeh device */ + edev->class_code = *class_code; + edev->mode = 0; + + /* Retrieve the device address */ + regs = of_get_property(dn, "reg", NULL); + if (!regs) { + pr_warning("%s: OF node property %s::reg not found\n", + __func__, dn->full_name); + return NULL; + } + + /* Initialize the fake PE */ + memset(&pe, 0, sizeof(struct eeh_pe)); + pe.phb = edev->phb; + pe.config_addr = regs[0]; + + /* Enable EEH on the device */ + ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE); + if (!ret) { + edev->config_addr = regs[0]; + /* Retrieve PE address */ + edev->pe_config_addr = eeh_ops->get_pe_addr(&pe); + pe.addr = edev->pe_config_addr; + + /* Some older systems (Power4) allow the ibm,set-eeh-option + * call to succeed even on nodes where EEH is not supported. + * Verify support explicitly. + */ + ret = eeh_ops->get_state(&pe, NULL); + if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) + enable = 1; + + if (enable) { + eeh_subsystem_enabled = 1; + eeh_add_to_parent_pe(edev); + + pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n", + __func__, dn->full_name, pe.phb->global_number, + pe.addr, pe.config_addr); + } else if (dn->parent && of_node_to_eeh_dev(dn->parent) && + (of_node_to_eeh_dev(dn->parent))->pe) { + /* This device doesn't support EEH, but it may have an + * EEH parent, in which case we mark it as supported. + */ + edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; + edev->pe_config_addr = of_node_to_eeh_dev(dn->parent)->pe_config_addr; + eeh_add_to_parent_pe(edev); + } + } + + /* Save memory bars */ + eeh_save_bars(edev); + + return NULL; +} + +/** * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable - * @dn: device node + * @pe: EEH PE * @option: operation to be issued * * The function is used to control the EEH functionality globally. * Currently, following options are support according to PAPR: * Enable EEH, Disable EEH, Enable MMIO and Enable DMA */ -static int pseries_eeh_set_option(struct device_node *dn, int option) +static int pseries_eeh_set_option(struct eeh_pe *pe, int option) { int ret = 0; - struct eeh_dev *edev; - const u32 *reg; int config_addr; - edev = of_node_to_eeh_dev(dn); - /* * When we're enabling or disabling EEH functioality on * the particular PE, the PE config address is possibly @@ -159,15 +249,11 @@ static int pseries_eeh_set_option(struct device_node *dn, int option) switch (option) { case EEH_OPT_DISABLE: case EEH_OPT_ENABLE: - reg = of_get_property(dn, "reg", NULL); - config_addr = reg[0]; - break; - case EEH_OPT_THAW_MMIO: case EEH_OPT_THAW_DMA: - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; + config_addr = pe->config_addr; + if (pe->addr) + config_addr = pe->addr; break; default: @@ -177,15 +263,15 @@ static int pseries_eeh_set_option(struct device_node *dn, int option) } ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), option); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid), option); return ret; } /** * pseries_eeh_get_pe_addr - Retrieve PE address - * @dn: device node + * @pe: EEH PE * * Retrieve the assocated PE address. Actually, there're 2 RTAS * function calls dedicated for the purpose. We need implement @@ -196,14 +282,11 @@ static int pseries_eeh_set_option(struct device_node *dn, int option) * It's notable that zero'ed return value means invalid PE config * address. */ -static int pseries_eeh_get_pe_addr(struct device_node *dn) +static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) { - struct eeh_dev *edev; int ret = 0; int rets[3]; - edev = of_node_to_eeh_dev(dn); - if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { /* * First of all, we need to make sure there has one PE @@ -211,18 +294,18 @@ static int pseries_eeh_get_pe_addr(struct device_node *dn) * meaningless. */ ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, - edev->config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), 1); + pe->config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid), 1); if (ret || (rets[0] == 0)) return 0; /* Retrieve the associated PE config address */ ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, - edev->config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), 0); + pe->config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid), 0); if (ret) { - pr_warning("%s: Failed to get PE address for %s\n", - __func__, dn->full_name); + pr_warning("%s: Failed to get address for PHB#%d-PE#%x\n", + __func__, pe->phb->global_number, pe->config_addr); return 0; } @@ -231,11 +314,11 @@ static int pseries_eeh_get_pe_addr(struct device_node *dn) if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, - edev->config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), 0); + pe->config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid), 0); if (ret) { - pr_warning("%s: Failed to get PE address for %s\n", - __func__, dn->full_name); + pr_warning("%s: Failed to get address for PHB#%d-PE#%x\n", + __func__, pe->phb->global_number, pe->config_addr); return 0; } @@ -247,7 +330,7 @@ static int pseries_eeh_get_pe_addr(struct device_node *dn) /** * pseries_eeh_get_state - Retrieve PE state - * @dn: PE associated device node + * @pe: EEH PE * @state: return value * * Retrieve the state of the specified PE. On RTAS compliant @@ -258,30 +341,28 @@ static int pseries_eeh_get_pe_addr(struct device_node *dn) * RTAS calls for the purpose, we need to try the new one and back * to the old one if the new one couldn't work properly. */ -static int pseries_eeh_get_state(struct device_node *dn, int *state) +static int pseries_eeh_get_state(struct eeh_pe *pe, int *state) { - struct eeh_dev *edev; int config_addr; int ret; int rets[4]; int result; /* Figure out PE config address if possible */ - edev = of_node_to_eeh_dev(dn); - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; + config_addr = pe->config_addr; + if (pe->addr) + config_addr = pe->addr; if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { /* Fake PE unavailable info */ rets[2] = 0; ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); } else { return EEH_STATE_NOT_SUPPORT; } @@ -333,34 +414,32 @@ static int pseries_eeh_get_state(struct device_node *dn, int *state) /** * pseries_eeh_reset - Reset the specified PE - * @dn: PE associated device node + * @pe: EEH PE * @option: reset option * * Reset the specified PE */ -static int pseries_eeh_reset(struct device_node *dn, int option) +static int pseries_eeh_reset(struct eeh_pe *pe, int option) { - struct eeh_dev *edev; int config_addr; int ret; /* Figure out PE address */ - edev = of_node_to_eeh_dev(dn); - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; + config_addr = pe->config_addr; + if (pe->addr) + config_addr = pe->addr; /* Reset PE through RTAS call */ ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), option); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid), option); /* If fundamental-reset not supported, try hot-reset */ if (option == EEH_RESET_FUNDAMENTAL && ret == -8) { ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), EEH_RESET_HOT); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid), EEH_RESET_HOT); } return ret; @@ -368,13 +447,13 @@ static int pseries_eeh_reset(struct device_node *dn, int option) /** * pseries_eeh_wait_state - Wait for PE state - * @dn: PE associated device node + * @pe: EEH PE * @max_wait: maximal period in microsecond * * Wait for the state of associated PE. It might take some time * to retrieve the PE's state. */ -static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) +static int pseries_eeh_wait_state(struct eeh_pe *pe, int max_wait) { int ret; int mwait; @@ -391,7 +470,7 @@ static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) #define EEH_STATE_MAX_WAIT_TIME (300 * 1000) while (1) { - ret = pseries_eeh_get_state(dn, &mwait); + ret = pseries_eeh_get_state(pe, &mwait); /* * If the PE's state is temporarily unavailable, @@ -426,7 +505,7 @@ static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) /** * pseries_eeh_get_log - Retrieve error log - * @dn: device node + * @pe: EEH PE * @severity: temporary or permanent error log * @drv_log: driver log to be combined with retrieved error log * @len: length of driver log @@ -435,24 +514,22 @@ static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) * Actually, the error will be retrieved through the dedicated * RTAS call. */ -static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) +static int pseries_eeh_get_log(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len) { - struct eeh_dev *edev; int config_addr; unsigned long flags; int ret; - edev = of_node_to_eeh_dev(dn); spin_lock_irqsave(&slot_errbuf_lock, flags); memset(slot_errbuf, 0, eeh_error_buf_size); /* Figure out the PE address */ - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; + config_addr = pe->config_addr; + if (pe->addr) + config_addr = pe->addr; ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, - BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), + BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), virt_to_phys(drv_log), len, virt_to_phys(slot_errbuf), eeh_error_buf_size, severity); @@ -465,40 +542,38 @@ static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_l /** * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE - * @dn: PE associated device node + * @pe: EEH PE * * The function will be called to reconfigure the bridges included * in the specified PE so that the mulfunctional PE would be recovered * again. */ -static int pseries_eeh_configure_bridge(struct device_node *dn) +static int pseries_eeh_configure_bridge(struct eeh_pe *pe) { - struct eeh_dev *edev; int config_addr; int ret; /* Figure out the PE address */ - edev = of_node_to_eeh_dev(dn); - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; + config_addr = pe->config_addr; + if (pe->addr) + config_addr = pe->addr; /* Use new configure-pe function, if supported */ if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_configure_pe, 3, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); + config_addr, BUID_HI(pe->phb->buid), + BUID_LO(pe->phb->buid)); } else { return -EFAULT; } if (ret) - pr_warning("%s: Unable to configure bridge %d for %s\n", - __func__, ret, dn->full_name); + pr_warning("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", + __func__, pe->phb->global_number, pe->addr, ret); return ret; } @@ -542,6 +617,8 @@ static int pseries_eeh_write_config(struct device_node *dn, int where, int size, static struct eeh_ops pseries_eeh_ops = { .name = "pseries", .init = pseries_eeh_init, + .of_probe = pseries_eeh_of_probe, + .dev_probe = NULL, .set_option = pseries_eeh_set_option, .get_pe_addr = pseries_eeh_get_pe_addr, .get_state = pseries_eeh_get_state, @@ -559,7 +636,21 @@ static struct eeh_ops pseries_eeh_ops = { * EEH initialization on pseries platform. This function should be * called before any EEH related functions. */ -int __init eeh_pseries_init(void) +static int __init eeh_pseries_init(void) { - return eeh_ops_register(&pseries_eeh_ops); + int ret = -EINVAL; + + if (!machine_is(pseries)) + return ret; + + ret = eeh_ops_register(&pseries_eeh_ops); + if (!ret) + pr_info("EEH: pSeries platform initialized\n"); + else + pr_info("EEH: pSeries platform initialization failure (%d)\n", + ret); + + return ret; } + +early_initcall(eeh_pseries_init); diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index 243b3510d70f..d37708360f2e 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -53,9 +53,6 @@ static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); EEH_SHOW_ATTR(eeh_mode, mode, "0x%x"); EEH_SHOW_ATTR(eeh_config_addr, config_addr, "0x%x"); EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_check_count, check_count, "%d" ); -EEH_SHOW_ATTR(eeh_freeze_count, freeze_count, "%d" ); -EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d" ); void eeh_sysfs_add_device(struct pci_dev *pdev) { @@ -64,9 +61,6 @@ void eeh_sysfs_add_device(struct pci_dev *pdev) rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); - rc += device_create_file(&pdev->dev, &dev_attr_eeh_check_count); - rc += device_create_file(&pdev->dev, &dev_attr_eeh_false_positives); - rc += device_create_file(&pdev->dev, &dev_attr_eeh_freeze_count); if (rc) printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); @@ -77,8 +71,5 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev) device_remove_file(&pdev->dev, &dev_attr_eeh_mode); device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); - device_remove_file(&pdev->dev, &dev_attr_eeh_check_count); - device_remove_file(&pdev->dev, &dev_attr_eeh_false_positives); - device_remove_file(&pdev->dev, &dev_attr_eeh_freeze_count); } diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index bca220f2873c..6153eea27ce7 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/memblock.h> #include <linux/spinlock.h> #include <linux/sched.h> /* for show_stack */ #include <linux/string.h> @@ -41,7 +42,6 @@ #include <asm/iommu.h> #include <asm/pci-bridge.h> #include <asm/machdep.h> -#include <asm/abs_addr.h> #include <asm/pSeries_reconfig.h> #include <asm/firmware.h> #include <asm/tce.h> @@ -99,7 +99,7 @@ static int tce_build_pSeries(struct iommu_table *tbl, long index, while (npages--) { /* can't move this out since we might cross MEMBLOCK boundary */ - rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + rpn = __pa(uaddr) >> TCE_SHIFT; *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; uaddr += TCE_PAGE_SIZE; @@ -148,7 +148,7 @@ static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, int ret = 0; long tcenum_start = tcenum, npages_start = npages; - rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + rpn = __pa(uaddr) >> TCE_SHIFT; proto_tce = TCE_PCI_READ; if (direction != DMA_TO_DEVICE) proto_tce |= TCE_PCI_WRITE; @@ -217,7 +217,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, __get_cpu_var(tce_page) = tcep; } - rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT; + rpn = __pa(uaddr) >> TCE_SHIFT; proto_tce = TCE_PCI_READ; if (direction != DMA_TO_DEVICE) proto_tce |= TCE_PCI_WRITE; @@ -237,7 +237,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, rc = plpar_tce_put_indirect((u64)tbl->it_index, (u64)tcenum << 12, - (u64)virt_to_abs(tcep), + (u64)__pa(tcep), limit); npages -= limit; @@ -441,7 +441,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn, rc = plpar_tce_put_indirect(liobn, dma_offset, - (u64)virt_to_abs(tcep), + (u64)__pa(tcep), limit); num_tce -= limit; diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 5f3ef876ded2..0da39fed355a 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -31,7 +31,6 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <asm/machdep.h> -#include <asm/abs_addr.h> #include <asm/mmu_context.h> #include <asm/iommu.h> #include <asm/tlbflush.h> @@ -108,9 +107,9 @@ void vpa_init(int cpu) } static long pSeries_lpar_hpte_insert(unsigned long hpte_group, - unsigned long va, unsigned long pa, - unsigned long rflags, unsigned long vflags, - int psize, int ssize) + unsigned long vpn, unsigned long pa, + unsigned long rflags, unsigned long vflags, + int psize, int ssize) { unsigned long lpar_rc; unsigned long flags; @@ -118,11 +117,11 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long hpte_v, hpte_r; if (!(vflags & HPTE_V_BOLTED)) - pr_devel("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " - "rflags=%lx, vflags=%lx, psize=%d)\n", - hpte_group, va, pa, rflags, vflags, psize); + pr_devel("hpte_insert(group=%lx, vpn=%016lx, " + "pa=%016lx, rflags=%lx, vflags=%lx, psize=%d)\n", + hpte_group, vpn, pa, rflags, vflags, psize); - hpte_v = hpte_encode_v(va, psize, ssize) | vflags | HPTE_V_VALID; + hpte_v = hpte_encode_v(vpn, psize, ssize) | vflags | HPTE_V_VALID; hpte_r = hpte_encode_r(pa, psize) | rflags; if (!(vflags & HPTE_V_BOLTED)) @@ -227,22 +226,6 @@ static void pSeries_lpar_hptab_clear(void) } /* - * This computes the AVPN and B fields of the first dword of a HPTE, - * for use when we want to match an existing PTE. The bottom 7 bits - * of the returned value are zero. - */ -static inline unsigned long hpte_encode_avpn(unsigned long va, int psize, - int ssize) -{ - unsigned long v; - - v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm); - v <<= HPTE_V_AVPN_SHIFT; - v |= ((unsigned long) ssize) << HPTE_V_SSIZE_SHIFT; - return v; -} - -/* * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up. So no transform is needed. * We can probably optimize here and assume the high bits of newpp are @@ -250,14 +233,14 @@ static inline unsigned long hpte_encode_avpn(unsigned long va, int psize, */ static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, + unsigned long vpn, int psize, int ssize, int local) { unsigned long lpar_rc; unsigned long flags = (newpp & 7) | H_AVPN; unsigned long want_v; - want_v = hpte_encode_avpn(va, psize, ssize); + want_v = hpte_encode_avpn(vpn, psize, ssize); pr_devel(" update: avpnv=%016lx, hash=%016lx, f=%lx, psize: %d ...", want_v, slot, flags, psize); @@ -295,15 +278,15 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) return dword0; } -static long pSeries_lpar_hpte_find(unsigned long va, int psize, int ssize) +static long pSeries_lpar_hpte_find(unsigned long vpn, int psize, int ssize) { unsigned long hash; unsigned long i; long slot; unsigned long want_v, hpte_v; - hash = hpt_hash(va, mmu_psize_defs[psize].shift, ssize); - want_v = hpte_encode_avpn(va, psize, ssize); + hash = hpt_hash(vpn, mmu_psize_defs[psize].shift, ssize); + want_v = hpte_encode_avpn(vpn, psize, ssize); /* Bolted entries are always in the primary group */ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; @@ -323,12 +306,13 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, int psize, int ssize) { - unsigned long lpar_rc, slot, vsid, va, flags; + unsigned long vpn; + unsigned long lpar_rc, slot, vsid, flags; vsid = get_kernel_vsid(ea, ssize); - va = hpt_va(ea, vsid, ssize); + vpn = hpt_vpn(ea, vsid, ssize); - slot = pSeries_lpar_hpte_find(va, psize, ssize); + slot = pSeries_lpar_hpte_find(vpn, psize, ssize); BUG_ON(slot == -1); flags = newpp & 7; @@ -337,17 +321,17 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, BUG_ON(lpar_rc != H_SUCCESS); } -static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, +static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn, int psize, int ssize, int local) { unsigned long want_v; unsigned long lpar_rc; unsigned long dummy1, dummy2; - pr_devel(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", - slot, va, psize, local); + pr_devel(" inval : slot=%lx, vpn=%016lx, psize: %d, local: %d\n", + slot, vpn, psize, local); - want_v = hpte_encode_avpn(va, psize, ssize); + want_v = hpte_encode_avpn(vpn, psize, ssize); lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v, &dummy1, &dummy2); if (lpar_rc == H_NOT_FOUND) return; @@ -358,15 +342,16 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, static void pSeries_lpar_hpte_removebolted(unsigned long ea, int psize, int ssize) { - unsigned long slot, vsid, va; + unsigned long vpn; + unsigned long slot, vsid; vsid = get_kernel_vsid(ea, ssize); - va = hpt_va(ea, vsid, ssize); + vpn = hpt_vpn(ea, vsid, ssize); - slot = pSeries_lpar_hpte_find(va, psize, ssize); + slot = pSeries_lpar_hpte_find(vpn, psize, ssize); BUG_ON(slot == -1); - pSeries_lpar_hpte_invalidate(slot, va, psize, ssize, 0); + pSeries_lpar_hpte_invalidate(slot, vpn, psize, ssize, 0); } /* Flag bits for H_BULK_REMOVE */ @@ -382,12 +367,12 @@ static void pSeries_lpar_hpte_removebolted(unsigned long ea, */ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) { + unsigned long vpn; unsigned long i, pix, rc; unsigned long flags = 0; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE); unsigned long param[9]; - unsigned long va; unsigned long hash, index, shift, hidx, slot; real_pte_t pte; int psize, ssize; @@ -399,21 +384,21 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local) ssize = batch->ssize; pix = 0; for (i = 0; i < number; i++) { - va = batch->vaddr[i]; + vpn = batch->vpn[i]; pte = batch->pte[i]; - pte_iterate_hashed_subpages(pte, psize, va, index, shift) { - hash = hpt_hash(va, shift, ssize); + pte_iterate_hashed_subpages(pte, psize, vpn, index, shift) { + hash = hpt_hash(vpn, shift, ssize); hidx = __rpte_to_hidx(pte, index); if (hidx & _PTEIDX_SECONDARY) hash = ~hash; slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; slot += hidx & _PTEIDX_GROUP_IX; if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { - pSeries_lpar_hpte_invalidate(slot, va, psize, + pSeries_lpar_hpte_invalidate(slot, vpn, psize, ssize, local); } else { param[pix] = HBR_REQUEST | HBR_AVPN | slot; - param[pix+1] = hpte_encode_avpn(va, psize, + param[pix+1] = hpte_encode_avpn(vpn, psize, ssize); pix += 2; if (pix == 8) { diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 109fdb75578d..d19f4977c834 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -210,6 +210,7 @@ static struct device_node *find_pe_total_msi(struct pci_dev *dev, int *total) static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) { struct device_node *dn; + struct eeh_dev *edev; /* Found our PE and assume 8 at that point. */ @@ -217,7 +218,10 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) if (!dn) return NULL; - dn = eeh_find_device_pe(dn); + /* Get the top level device in the PE */ + edev = of_node_to_eeh_dev(dn); + edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); + dn = eeh_dev_to_of_node(edev); if (!dn) return NULL; @@ -387,12 +391,13 @@ static int check_msix_entries(struct pci_dev *pdev) return 0; } -static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) +static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) { struct pci_dn *pdn; int hwirq, virq, i, rc; struct msi_desc *entry; struct msi_msg msg; + int nvec = nvec_in; pdn = get_pdn(pdev); if (!pdn) @@ -402,10 +407,23 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return -EINVAL; /* + * Firmware currently refuse any non power of two allocation + * so we round up if the quota will allow it. + */ + if (type == PCI_CAP_ID_MSIX) { + int m = roundup_pow_of_two(nvec); + int quota = msi_quota_for_device(pdev, m); + + if (quota >= m) + nvec = m; + } + + /* * Try the new more explicit firmware interface, if that fails fall * back to the old interface. The old interface is known to never * return MSI-Xs. */ +again: if (type == PCI_CAP_ID_MSI) { rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); @@ -417,6 +435,10 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); if (rc != nvec) { + if (nvec != nvec_in) { + nvec = nvec_in; + goto again; + } pr_debug("rtas_msi: rtas_change_msi() failed\n"); return rc; } diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 2c6ded29f73d..56b864d777ee 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -73,7 +73,7 @@ void __init pSeries_final_fixup(void) { pSeries_request_regions(); - pci_addr_cache_build(); + eeh_addr_cache_build(); } /* diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 3ccebc83dc02..261a577a3dd2 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -65,27 +65,43 @@ pcibios_find_pci_bus(struct device_node *dn) EXPORT_SYMBOL_GPL(pcibios_find_pci_bus); /** - * pcibios_remove_pci_devices - remove all devices under this bus + * __pcibios_remove_pci_devices - remove all devices under this bus + * @bus: the indicated PCI bus + * @purge_pe: destroy the PE on removal of PCI devices * * Remove all of the PCI devices under this bus both from the * linux pci device tree, and from the powerpc EEH address cache. + * By default, the corresponding PE will be destroied during the + * normal PCI hotplug path. For PCI hotplug during EEH recovery, + * the corresponding PE won't be destroied and deallocated. */ -void pcibios_remove_pci_devices(struct pci_bus *bus) +void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe) { - struct pci_dev *dev, *tmp; + struct pci_dev *dev, *tmp; struct pci_bus *child_bus; /* First go down child busses */ list_for_each_entry(child_bus, &bus->children, node) - pcibios_remove_pci_devices(child_bus); + __pcibios_remove_pci_devices(child_bus, purge_pe); pr_debug("PCI: Removing devices on bus %04x:%02x\n", - pci_domain_nr(bus), bus->number); + pci_domain_nr(bus), bus->number); list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { pr_debug(" * Removing %s...\n", pci_name(dev)); - eeh_remove_bus_device(dev); - pci_stop_and_remove_bus_device(dev); - } + eeh_remove_bus_device(dev, purge_pe); + pci_stop_and_remove_bus_device(dev); + } +} + +/** + * pcibios_remove_pci_devices - remove all devices under this bus + * + * Remove all of the PCI devices under this bus both from the + * linux pci device tree, and from the powerpc EEH address cache. + */ +void pcibios_remove_pci_devices(struct pci_bus *bus) +{ + __pcibios_remove_pci_devices(bus, 1); } EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 51ecac920dd8..e3cb7ae61658 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -388,10 +388,8 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); - eeh_pseries_init(); find_and_init_phbs(); pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); - eeh_init(); pSeries_nvram_init(); @@ -416,16 +414,20 @@ static int __init pSeries_init_panel(void) } machine_arch_initcall(pseries, pSeries_init_panel); -static int pseries_set_dabr(unsigned long dabr) +static int pseries_set_dabr(unsigned long dabr, unsigned long dabrx) { return plpar_hcall_norets(H_SET_DABR, dabr); } -static int pseries_set_xdabr(unsigned long dabr) +static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx) { - /* We want to catch accesses from kernel and userspace */ - return plpar_hcall_norets(H_SET_XDABR, dabr, - H_DABRX_KERNEL | H_DABRX_USER); + /* Have to set at least one bit in the DABRX according to PAPR */ + if (dabrx == 0 && dabr == 0) + dabrx = DABRX_USER; + /* PAPR says we can only set kernel and user bits */ + dabrx &= DABRX_KERNEL | DABRX_USER; + + return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx); } #define CMO_CHARACTERISTICS_TOKEN 44 @@ -529,10 +531,10 @@ static void __init pSeries_init_early(void) if (firmware_has_feature(FW_FEATURE_LPAR)) hvc_vio_init_early(); #endif - if (firmware_has_feature(FW_FEATURE_DABR)) - ppc_md.set_dabr = pseries_set_dabr; - else if (firmware_has_feature(FW_FEATURE_XDABR)) + if (firmware_has_feature(FW_FEATURE_XDABR)) ppc_md.set_dabr = pseries_set_xdabr; + else if (firmware_has_feature(FW_FEATURE_DABR)) + ppc_md.set_dabr = pseries_set_dabr; pSeries_cmo_feature_init(); iommu_init_early_pSeries(); diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 1bd7ecb24620..a57600b3a4e3 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o obj-$(CONFIG_PPC_PMI) += pmi.o obj-$(CONFIG_U3_DART) += dart_iommu.o obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o -obj-$(CONFIG_FSL_SOC) += fsl_soc.o +obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) obj-$(CONFIG_FSL_PMC) += fsl_pmc.o obj-$(CONFIG_FSL_LBC) += fsl_lbc.o diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 4f2680f431b5..bd968a43a48b 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -43,7 +43,6 @@ #include <asm/iommu.h> #include <asm/pci-bridge.h> #include <asm/machdep.h> -#include <asm/abs_addr.h> #include <asm/cacheflush.h> #include <asm/ppc-pci.h> @@ -74,11 +73,16 @@ static int dart_is_u4; #define DBG(...) +static DEFINE_SPINLOCK(invalidate_lock); + static inline void dart_tlb_invalidate_all(void) { unsigned long l = 0; unsigned int reg, inv_bit; unsigned long limit; + unsigned long flags; + + spin_lock_irqsave(&invalidate_lock, flags); DBG("dart: flush\n"); @@ -111,12 +115,17 @@ retry: panic("DART: TLB did not flush after waiting a long " "time. Buggy U3 ?"); } + + spin_unlock_irqrestore(&invalidate_lock, flags); } static inline void dart_tlb_invalidate_one(unsigned long bus_rpn) { unsigned int reg; unsigned int l, limit; + unsigned long flags; + + spin_lock_irqsave(&invalidate_lock, flags); reg = DART_CNTL_U4_ENABLE | DART_CNTL_U4_IONE | (bus_rpn & DART_CNTL_U4_IONE_MASK); @@ -138,6 +147,8 @@ wait_more: panic("DART: TLB did not flush after waiting a long " "time. Buggy U4 ?"); } + + spin_unlock_irqrestore(&invalidate_lock, flags); } static void dart_flush(struct iommu_table *tbl) @@ -167,7 +178,7 @@ static int dart_build(struct iommu_table *tbl, long index, */ l = npages; while (l--) { - rpn = virt_to_abs(uaddr) >> DART_PAGE_SHIFT; + rpn = __pa(uaddr) >> DART_PAGE_SHIFT; *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); @@ -244,7 +255,7 @@ static int __init dart_init(struct device_node *dart_node) panic("DART: Cannot map registers!"); /* Map in DART table */ - dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); + dart_vbase = ioremap(__pa(dart_tablebase), dart_tablesize); /* Fill initial table */ for (i = 0; i < dart_tablesize/4; i++) @@ -463,7 +474,7 @@ void __init alloc_dart_table(void) * will blow up an entire large page anyway in the kernel mapping */ dart_tablebase = (unsigned long) - abs_to_virt(memblock_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); + __va(memblock_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase); } diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index 68ac3aacb191..d131c8a1cb15 100644 --- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c @@ -193,6 +193,16 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = { { .compatible = "fsl,mpc8548-l2-cache-controller", }, + { .compatible = "fsl,mpc8544-l2-cache-controller",}, + { .compatible = "fsl,mpc8572-l2-cache-controller",}, + { .compatible = "fsl,mpc8536-l2-cache-controller",}, + { .compatible = "fsl,p1021-l2-cache-controller",}, + { .compatible = "fsl,p1012-l2-cache-controller",}, + { .compatible = "fsl,p1025-l2-cache-controller",}, + { .compatible = "fsl,p1016-l2-cache-controller",}, + { .compatible = "fsl,p1024-l2-cache-controller",}, + { .compatible = "fsl,p1015-l2-cache-controller",}, + { .compatible = "fsl,p1010-l2-cache-controller",}, {}, }; diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c index b31f19f61031..097cc9d2585b 100644 --- a/arch/powerpc/sysdev/fsl_ifc.c +++ b/arch/powerpc/sysdev/fsl_ifc.c @@ -244,12 +244,6 @@ static int __devinit fsl_ifc_ctrl_probe(struct platform_device *dev) /* get the nand machine irq */ fsl_ifc_ctrl_dev->nand_irq = irq_of_parse_and_map(dev->dev.of_node, 1); - if (fsl_ifc_ctrl_dev->nand_irq == NO_IRQ) { - dev_err(&dev->dev, "failed to get irq resource " - "for NAND Machine\n"); - ret = -ENODEV; - goto err; - } fsl_ifc_ctrl_dev->dev = &dev->dev; @@ -267,12 +261,14 @@ static int __devinit fsl_ifc_ctrl_probe(struct platform_device *dev) goto err_irq; } - ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq, 0, - "fsl-ifc-nand", fsl_ifc_ctrl_dev); - if (ret != 0) { - dev_err(&dev->dev, "failed to install irq (%d)\n", - fsl_ifc_ctrl_dev->nand_irq); - goto err_nandirq; + if (fsl_ifc_ctrl_dev->nand_irq) { + ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq, + 0, "fsl-ifc-nand", fsl_ifc_ctrl_dev); + if (ret != 0) { + dev_err(&dev->dev, "failed to install irq (%d)\n", + fsl_ifc_ctrl_dev->nand_irq); + goto err_nandirq; + } } return 0; diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c new file mode 100644 index 000000000000..b83f32562a37 --- /dev/null +++ b/arch/powerpc/sysdev/fsl_mpic_err.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * Author: Varun Sethi <varun.sethi@freescale.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. + * + */ + +#include <linux/irq.h> +#include <linux/smp.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mpic.h> + +#include "mpic.h" + +#define MPIC_ERR_INT_BASE 0x3900 +#define MPIC_ERR_INT_EISR 0x0000 +#define MPIC_ERR_INT_EIMR 0x0010 + +static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg) +{ + return in_be32(base + (err_reg >> 2)); +} + +static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value) +{ + out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value); +} + +static void fsl_mpic_mask_err(struct irq_data *d) +{ + u32 eimr; + struct mpic *mpic = irq_data_get_irq_chip_data(d); + unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0]; + + eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR); + eimr |= (1 << (31 - src)); + mpic_fsl_err_write(mpic->err_regs, eimr); +} + +static void fsl_mpic_unmask_err(struct irq_data *d) +{ + u32 eimr; + struct mpic *mpic = irq_data_get_irq_chip_data(d); + unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0]; + + eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR); + eimr &= ~(1 << (31 - src)); + mpic_fsl_err_write(mpic->err_regs, eimr); +} + +static struct irq_chip fsl_mpic_err_chip = { + .irq_disable = fsl_mpic_mask_err, + .irq_mask = fsl_mpic_mask_err, + .irq_unmask = fsl_mpic_unmask_err, +}; + +int mpic_setup_error_int(struct mpic *mpic, int intvec) +{ + int i; + + mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000); + if (!mpic->err_regs) { + pr_err("could not map mpic error registers\n"); + return -ENOMEM; + } + mpic->hc_err = fsl_mpic_err_chip; + mpic->hc_err.name = mpic->name; + mpic->flags |= MPIC_FSL_HAS_EIMR; + /* allocate interrupt vectors for error interrupts */ + for (i = MPIC_MAX_ERR - 1; i >= 0; i--) + mpic->err_int_vecs[i] = --intvec; + + return 0; +} + +int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw) +{ + if ((mpic->flags & MPIC_FSL_HAS_EIMR) && + (hw >= mpic->err_int_vecs[0] && + hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) { + WARN_ON(mpic->flags & MPIC_SECONDARY); + + pr_debug("mpic: mapping as Error Interrupt\n"); + irq_set_chip_data(virq, mpic); + irq_set_chip_and_handler(virq, &mpic->hc_err, + handle_level_irq); + return 1; + } + + return 0; +} + +static irqreturn_t fsl_error_int_handler(int irq, void *data) +{ + struct mpic *mpic = (struct mpic *) data; + u32 eisr, eimr; + int errint; + unsigned int cascade_irq; + + eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR); + eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR); + + if (!(eisr & ~eimr)) + return IRQ_NONE; + + while (eisr) { + errint = __builtin_clz(eisr); + cascade_irq = irq_linear_revmap(mpic->irqhost, + mpic->err_int_vecs[errint]); + WARN_ON(cascade_irq == NO_IRQ); + if (cascade_irq != NO_IRQ) { + generic_handle_irq(cascade_irq); + } else { + eimr |= 1 << (31 - errint); + mpic_fsl_err_write(mpic->err_regs, eimr); + } + eisr &= ~(1 << (31 - errint)); + } + + return IRQ_HANDLED; +} + +void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum) +{ + unsigned int virq; + int ret; + + virq = irq_create_mapping(mpic->irqhost, irqnum); + if (virq == NO_IRQ) { + pr_err("Error interrupt setup failed\n"); + return; + } + + /* Mask all error interrupts */ + mpic_fsl_err_write(mpic->err_regs, ~0); + + ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD, + "mpic-error-int", mpic); + if (ret) + pr_err("Failed to register error interrupt handler\n"); +} diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index c37f46136321..ffb93ae9379b 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -38,15 +38,15 @@ static int fsl_pcie_bus_fixup, is_mpc83xx_pci; static void __devinit quirk_fsl_pcie_header(struct pci_dev *dev) { - u8 progif; + u8 hdr_type; /* if we aren't a PCIe don't bother */ if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) return; /* if we aren't in host mode don't bother */ - pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); - if (progif & 0x1) + pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type); + if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) return; dev->class = PCI_CLASS_BRIDGE_PCI << 8; @@ -143,18 +143,20 @@ static void __init setup_pci_atmu(struct pci_controller *hose, pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", (u64)rsrc->start, (u64)resource_size(rsrc)); - if (of_device_is_compatible(hose->dn, "fsl,qoriq-pcie-v2.2")) { - win_idx = 2; - start_idx = 0; - end_idx = 3; - } - pci = ioremap(rsrc->start, resource_size(rsrc)); if (!pci) { dev_err(hose->parent, "Unable to map ATMU registers\n"); return; } + if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { + if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) { + win_idx = 2; + start_idx = 0; + end_idx = 3; + } + } + /* Disable all windows (except powar0 since it's ignored) */ for(i = 1; i < 5; i++) out_be32(&pci->pow[i].powar, 0); @@ -425,7 +427,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) struct pci_controller *hose; struct resource rsrc; const int *bus_range; - u8 progif; + u8 hdr_type, progif; if (!of_device_is_available(dev)) { pr_warning("%s: disabled\n", dev->full_name); @@ -457,15 +459,17 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4, PPC_INDIRECT_TYPE_BIG_ENDIAN); - early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif); - if ((progif & 1) == 1) { - /* unmap cfg_data & cfg_addr separately if not on same page */ - if (((unsigned long)hose->cfg_data & PAGE_MASK) != - ((unsigned long)hose->cfg_addr & PAGE_MASK)) - iounmap(hose->cfg_data); - iounmap(hose->cfg_addr); - pcibios_free_controller(hose); - return -ENODEV; + if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { + /* For PCIE read HEADER_TYPE to identify controler mode */ + early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type); + if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) + goto no_bridge; + + } else { + /* For PCI read PROG to identify controller mode */ + early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif); + if ((progif & 1) == 1) + goto no_bridge; } setup_pci_cmd(hose); @@ -494,6 +498,15 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) setup_pci_atmu(hose, &rsrc); return 0; + +no_bridge: + /* unmap cfg_data & cfg_addr separately if not on same page */ + if (((unsigned long)hose->cfg_data & PAGE_MASK) != + ((unsigned long)hose->cfg_addr & PAGE_MASK)) + iounmap(hose->cfg_data); + iounmap(hose->cfg_addr); + pcibios_free_controller(hose); + return -ENODEV; } #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ @@ -818,6 +831,7 @@ static const struct of_device_id pci_ids[] = { { .compatible = "fsl,p1010-pcie", }, { .compatible = "fsl,p1023-pcie", }, { .compatible = "fsl,p4080-pcie", }, + { .compatible = "fsl,qoriq-pcie-v2.4", }, { .compatible = "fsl,qoriq-pcie-v2.3", }, { .compatible = "fsl,qoriq-pcie-v2.2", }, {}, @@ -825,57 +839,80 @@ static const struct of_device_id pci_ids[] = { struct device_node *fsl_pci_primary; -void __devinit fsl_pci_init(void) +void fsl_pci_assign_primary(void) { - int ret; - struct device_node *node; - struct pci_controller *hose; - dma_addr_t max = 0xffffffff; + struct device_node *np; /* Callers can specify the primary bus using other means. */ - if (!fsl_pci_primary) { - /* If a PCI host bridge contains an ISA node, it's primary. */ - node = of_find_node_by_type(NULL, "isa"); - while ((fsl_pci_primary = of_get_parent(node))) { - of_node_put(node); - node = fsl_pci_primary; - - if (of_match_node(pci_ids, node)) - break; - } + if (fsl_pci_primary) + return; + + /* If a PCI host bridge contains an ISA node, it's primary. */ + np = of_find_node_by_type(NULL, "isa"); + while ((fsl_pci_primary = of_get_parent(np))) { + of_node_put(np); + np = fsl_pci_primary; + + if (of_match_node(pci_ids, np) && of_device_is_available(np)) + return; } - node = NULL; - for_each_node_by_type(node, "pci") { - if (of_match_node(pci_ids, node)) { - /* - * If there's no PCI host bridge with ISA, arbitrarily - * designate one as primary. This can go away once - * various bugs with primary-less systems are fixed. - */ - if (!fsl_pci_primary) - fsl_pci_primary = node; - - ret = fsl_add_bridge(node, fsl_pci_primary == node); - if (ret == 0) { - hose = pci_find_hose_for_OF_device(node); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } + /* + * If there's no PCI host bridge with ISA, arbitrarily + * designate one as primary. This can go away once + * various bugs with primary-less systems are fixed. + */ + for_each_matching_node(np, pci_ids) { + if (of_device_is_available(np)) { + fsl_pci_primary = np; + of_node_put(np); + return; } } +} +static int __devinit fsl_pci_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *node; #ifdef CONFIG_SWIOTLB - /* - * if we couldn't map all of DRAM via the dma windows - * we need SWIOTLB to handle buffers located outside of - * dma capable memory region - */ - if (memblock_end_of_DRAM() - 1 > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; + struct pci_controller *hose; +#endif + + node = pdev->dev.of_node; + ret = fsl_add_bridge(node, fsl_pci_primary == node); + +#ifdef CONFIG_SWIOTLB + if (ret == 0) { + hose = pci_find_hose_for_OF_device(pdev->dev.of_node); + + /* + * if we couldn't map all of DRAM via the dma windows + * we need SWIOTLB to handle buffers located outside of + * dma capable memory region + */ + if (memblock_end_of_DRAM() - 1 > hose->dma_window_base_cur + + hose->dma_window_size) + ppc_swiotlb_enable = 1; } #endif + + mpc85xx_pci_err_probe(pdev); + + return 0; +} + +static struct platform_driver fsl_pci_driver = { + .driver = { + .name = "fsl-pci", + .of_match_table = pci_ids, + }, + .probe = fsl_pci_probe, +}; + +static int __init fsl_pci_init(void) +{ + return platform_driver_register(&fsl_pci_driver); } +arch_initcall(fsl_pci_init); #endif diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index baa0fd18289f..d078537adece 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h @@ -16,6 +16,7 @@ #define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */ #define PCIE_LTSSM_L0 0x16 /* L0 state */ +#define PCIE_IP_REV_2_2 0x02080202 /* PCIE IP block version Rev2.2 */ #define PIWAR_EN 0x80000000 /* Enable */ #define PIWAR_PF 0x20000000 /* prefetch */ #define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */ @@ -57,7 +58,9 @@ struct ccsr_pci { __be32 pex_pme_mes_disr; /* 0x.024 - PCIE PME and message disable register */ __be32 pex_pme_mes_ier; /* 0x.028 - PCIE PME and message interrupt enable register */ __be32 pex_pmcr; /* 0x.02c - PCIE power management command register */ - u8 res3[3024]; + u8 res3[3016]; + __be32 block_rev1; /* 0x.bf8 - PCIE Block Revision register 1 */ + __be32 block_rev2; /* 0x.bfc - PCIE Block Revision register 2 */ /* PCI/PCI Express outbound window 0-4 * Window 0 is the default window and is the only window enabled upon reset. @@ -95,10 +98,19 @@ u64 fsl_pci_immrbar_base(struct pci_controller *hose); extern struct device_node *fsl_pci_primary; -#ifdef CONFIG_FSL_PCI -void fsl_pci_init(void); +#ifdef CONFIG_PCI +void fsl_pci_assign_primary(void); #else -static inline void fsl_pci_init(void) {} +static inline void fsl_pci_assign_primary(void) {} +#endif + +#ifdef CONFIG_EDAC_MPC85XX +int mpc85xx_pci_err_probe(struct platform_device *op); +#else +static inline int mpc85xx_pci_err_probe(struct platform_device *op) +{ + return -ENOTSUPP; +} #endif #endif /* __POWERPC_FSL_PCI_H */ diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index bfc6211e5422..9c6e535daad2 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -6,7 +6,7 @@ * with various broken implementations of this HW. * * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. - * Copyright 2010-2011 Freescale Semiconductor, Inc. + * Copyright 2010-2012 Freescale Semiconductor, 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 @@ -221,24 +221,24 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu _mpic_write(mpic->reg_type, &mpic->gregs, offset, value); } -static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) +static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm) { - unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + - ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); + return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE + + (tm & 3) * MPIC_INFO(TIMER_STRIDE); +} - if (tm >= 4) - offset += 0x1000 / 4; +static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm) +{ + unsigned int offset = mpic_tm_offset(mpic, tm) + + MPIC_INFO(TIMER_VECTOR_PRI); return _mpic_read(mpic->reg_type, &mpic->tmregs, offset); } static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value) { - unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) + - ((tm & 3) * MPIC_INFO(TIMER_STRIDE)); - - if (tm >= 4) - offset += 0x1000 / 4; + unsigned int offset = mpic_tm_offset(mpic, tm) + + MPIC_INFO(TIMER_VECTOR_PRI); _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value); } @@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq, return 0; } + if (mpic_map_error_int(mpic, virq, hw)) + return 0; + if (hw >= mpic->num_sources) return -EINVAL; @@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct, */ switch (intspec[2]) { case 0: - case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ + break; + case 1: + if (!(mpic->flags & MPIC_FSL_HAS_EIMR)) + break; + + if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs)) + return -EINVAL; + + *out_hwirq = mpic->err_int_vecs[intspec[3]]; + break; case 2: if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) @@ -1301,6 +1313,42 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); + if (mpic->flags & MPIC_FSL) { + u32 brr1, version; + int ret; + + /* + * Yes, Freescale really did put global registers in the + * magic per-cpu area -- and they don't even show up in the + * non-magic per-cpu copies that this driver normally uses. + */ + mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs, + MPIC_CPU_THISBASE, 0x1000); + + brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs, + MPIC_FSL_BRR1); + version = brr1 & MPIC_FSL_BRR1_VER; + + /* Error interrupt mask register (EIMR) is required for + * handling individual device error interrupts. EIMR + * was added in MPIC version 4.1. + * + * Over here we reserve vector number space for error + * interrupt vectors. This space is stolen from the + * global vector number space, as in case of ipis + * and timer interrupts. + * + * Available vector space = intvec_top - 12, where 12 + * is the number of vectors which have been consumed by + * ipis and timer interrupts. + */ + if (version >= 0x401) { + ret = mpic_setup_error_int(mpic, intvec_top - 12); + if (ret) + return NULL; + } + } + /* Reset */ /* When using a device-node, reset requests are only honored if the MPIC @@ -1440,6 +1488,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, void __init mpic_init(struct mpic *mpic) { int i, cpu; + int num_timers = 4; BUG_ON(mpic->num_sources == 0); @@ -1448,15 +1497,34 @@ void __init mpic_init(struct mpic *mpic) /* Set current processor priority to max */ mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf); + if (mpic->flags & MPIC_FSL) { + u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs, + MPIC_FSL_BRR1); + u32 version = brr1 & MPIC_FSL_BRR1_VER; + + /* + * Timer group B is present at the latest in MPIC 3.1 (e.g. + * mpc8536). It is not present in MPIC 2.0 (e.g. mpc8544). + * I don't know about the status of intermediate versions (or + * whether they even exist). + */ + if (version >= 0x0301) + num_timers = 8; + } + + /* FSL mpic error interrupt intialization */ + if (mpic->flags & MPIC_FSL_HAS_EIMR) + mpic_err_int_init(mpic, MPIC_FSL_ERR_INT); + /* Initialize timers to our reserved vectors and mask them for now */ - for (i = 0; i < 4; i++) { + for (i = 0; i < num_timers; i++) { + unsigned int offset = mpic_tm_offset(mpic, i); + mpic_write(mpic->tmregs, - i * MPIC_INFO(TIMER_STRIDE) + - MPIC_INFO(TIMER_DESTINATION), + offset + MPIC_INFO(TIMER_DESTINATION), 1 << hard_smp_processor_id()); mpic_write(mpic->tmregs, - i * MPIC_INFO(TIMER_STRIDE) + - MPIC_INFO(TIMER_VECTOR_PRI), + offset + MPIC_INFO(TIMER_VECTOR_PRI), MPIC_VECPRI_MASK | (9 << MPIC_VECPRI_PRIORITY_SHIFT) | (mpic->timer_vecs[0] + i)); diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index 13f3e8913a93..24bf07a63924 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h @@ -40,4 +40,26 @@ extern int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force); extern void mpic_reset_core(int cpu); +#ifdef CONFIG_FSL_SOC +extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw); +extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum); +extern int mpic_setup_error_int(struct mpic *mpic, int intvec); +#else +static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw) +{ + return 0; +} + + +static inline void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum) +{ + return; +} + +static inline int mpic_setup_error_int(struct mpic *mpic, int intvec) +{ + return -1; +} +#endif + #endif /* _POWERPC_SYSDEV_MPIC_H */ diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 9b49c65ee7a4..3a56a639a92e 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -60,6 +60,8 @@ static cpumask_t cpus_in_xmon = CPU_MASK_NONE; static unsigned long xmon_taken = 1; static int xmon_owner; static int xmon_gate; +#else +#define xmon_owner 0 #endif /* CONFIG_SMP */ static unsigned long in_xmon __read_mostly = 0; @@ -202,7 +204,13 @@ Commands:\n\ di dump instructions\n\ df dump float values\n\ dd dump double values\n\ - dl dump the kernel log buffer\n\ + dl dump the kernel log buffer\n" +#ifdef CONFIG_PPC64 + "\ + dp[#] dump paca for current cpu, or cpu #\n\ + dpa dump paca for all possible cpus\n" +#endif + "\ dr dump stream of raw bytes\n\ e print exception information\n\ f flush cache\n\ @@ -740,7 +748,7 @@ static void insert_bpts(void) static void insert_cpu_bpts(void) { if (dabr.enabled) - set_dabr(dabr.address | (dabr.enabled & 7)); + set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL); if (iabr && cpu_has_feature(CPU_FTR_IABR)) mtspr(SPRN_IABR, iabr->address | (iabr->enabled & (BP_IABR|BP_IABR_TE))); @@ -768,7 +776,7 @@ static void remove_bpts(void) static void remove_cpu_bpts(void) { - set_dabr(0); + set_dabr(0, 0); if (cpu_has_feature(CPU_FTR_IABR)) mtspr(SPRN_IABR, 0); } @@ -2009,6 +2017,95 @@ static void xmon_rawdump (unsigned long adrs, long ndump) printf("\n"); } +#ifdef CONFIG_PPC64 +static void dump_one_paca(int cpu) +{ + struct paca_struct *p; + + if (setjmp(bus_error_jmp) != 0) { + printf("*** Error dumping paca for cpu 0x%x!\n", cpu); + return; + } + + catch_memory_errors = 1; + sync(); + + p = &paca[cpu]; + + printf("paca for cpu 0x%x @ %p:\n", cpu, p); + + printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no"); + printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no"); + printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no"); + +#define DUMP(paca, name, format) \ + printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \ + offsetof(struct paca_struct, name)); + + DUMP(p, lock_token, "x"); + DUMP(p, paca_index, "x"); + DUMP(p, kernel_toc, "lx"); + DUMP(p, kernelbase, "lx"); + DUMP(p, kernel_msr, "lx"); +#ifdef CONFIG_PPC_STD_MMU_64 + DUMP(p, stab_real, "lx"); + DUMP(p, stab_addr, "lx"); +#endif + DUMP(p, emergency_sp, "p"); + DUMP(p, data_offset, "lx"); + DUMP(p, hw_cpu_id, "x"); + DUMP(p, cpu_start, "x"); + DUMP(p, kexec_state, "x"); + DUMP(p, __current, "p"); + DUMP(p, kstack, "lx"); + DUMP(p, stab_rr, "lx"); + DUMP(p, saved_r1, "lx"); + DUMP(p, trap_save, "x"); + DUMP(p, soft_enabled, "x"); + DUMP(p, irq_happened, "x"); + DUMP(p, io_sync, "x"); + DUMP(p, irq_work_pending, "x"); + DUMP(p, nap_state_lost, "x"); + +#undef DUMP + + catch_memory_errors = 0; + sync(); +} + +static void dump_all_pacas(void) +{ + int cpu; + + if (num_possible_cpus() == 0) { + printf("No possible cpus, use 'dp #' to dump individual cpus\n"); + return; + } + + for_each_possible_cpu(cpu) + dump_one_paca(cpu); +} + +static void dump_pacas(void) +{ + unsigned long num; + int c; + + c = inchar(); + if (c == 'a') { + dump_all_pacas(); + return; + } + + termch = c; /* Put c back, it wasn't 'a' */ + + if (scanhex(&num)) + dump_one_paca(num); + else + dump_one_paca(xmon_owner); +} +#endif + #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ || ('a' <= (c) && (c) <= 'f') \ || ('A' <= (c) && (c) <= 'F')) @@ -2018,6 +2115,14 @@ dump(void) int c; c = inchar(); + +#ifdef CONFIG_PPC64 + if (c == 'p') { + dump_pacas(); + return; + } +#endif + if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') termch = c; scanhex((void *)&adrs); diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index e402a9dd4eda..da3c1a7dcd8e 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -216,7 +216,6 @@ static struct crypto_alg aes_alg = { .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_init = fallback_init_cip, .cra_exit = fallback_exit_cip, .cra_u = { @@ -398,7 +397,6 @@ static struct crypto_alg ecb_aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_u = { @@ -508,7 +506,6 @@ static struct crypto_alg cbc_aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_u = { @@ -710,7 +707,6 @@ static struct crypto_alg xts_aes_alg = { .cra_ctxsize = sizeof(struct s390_xts_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(xts_aes_alg.cra_list), .cra_init = xts_fallback_init, .cra_exit = xts_fallback_exit, .cra_u = { @@ -832,7 +828,6 @@ static struct crypto_alg ctr_aes_alg = { .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ctr_aes_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 1eaa371ca3ee..b49fb96f4207 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -70,7 +70,6 @@ static struct crypto_alg des_alg = { .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES_KEY_SIZE, @@ -163,7 +162,6 @@ static struct crypto_alg ecb_des_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES_KEY_SIZE, @@ -206,7 +204,6 @@ static struct crypto_alg cbc_des_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES_KEY_SIZE, @@ -271,7 +268,6 @@ static struct crypto_alg des3_alg = { .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des3_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES3_KEY_SIZE, @@ -314,8 +310,6 @@ static struct crypto_alg ecb_des3_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT( - ecb_des3_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES3_KEY_SIZE, @@ -358,8 +352,6 @@ static struct crypto_alg cbc_des3_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT( - cbc_des3_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES3_KEY_SIZE, @@ -452,7 +444,6 @@ static struct crypto_alg ctr_des_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ctr_des_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES_KEY_SIZE, @@ -496,7 +487,6 @@ static struct crypto_alg ctr_des3_alg = { .cra_ctxsize = sizeof(struct s390_des_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ctr_des3_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = DES3_KEY_SIZE, diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c index b1bd170f24b1..1ebd3a15cca4 100644 --- a/arch/s390/crypto/ghash_s390.c +++ b/arch/s390/crypto/ghash_s390.c @@ -135,7 +135,6 @@ static struct shash_alg ghash_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_ctxsize = sizeof(struct ghash_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), }, }; diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 234f1d859cea..a34a9d612fc0 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -65,6 +65,7 @@ typedef s64 compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -144,6 +145,79 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[128/sizeof(int) - 3]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + int _status;/* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + __u32 _addr; /* faulting insn/memory ref. - pointer */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + +/* + * How these fields are to be accessed. + */ +#define si_pid _sifields._kill._pid +#define si_uid _sifields._kill._uid +#define si_status _sifields._sigchld._status +#define si_utime _sifields._sigchld._utime +#define si_stime _sifields._sigchld._stime +#define si_value _sifields._rt._sigval +#define si_int _sifields._rt._sigval.sival_int +#define si_ptr _sifields._rt._sigval.sival_ptr +#define si_addr _sifields._sigfault._addr +#define si_band _sifields._sigpoll._band +#define si_fd _sifields._sigpoll._fd +#define si_tid _sifields._timer._tid +#define si_overrun _sifields._timer._overrun + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -153,7 +227,6 @@ typedef u32 compat_sigset_word; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index f3e0aabfc6bc..56831dfa9198 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -159,6 +159,7 @@ extern unsigned long thread_saved_pc(struct task_struct *t); extern void show_code(struct pt_regs *regs); extern void print_fn_code(unsigned char *code, unsigned long len); +extern int insn_to_mnemonic(unsigned char *instruction, char buf[8]); unsigned long get_wchan(struct task_struct *p); #define task_pt_regs(tsk) ((struct pt_regs *) \ diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 9635d759c2b9..90887bd98cf0 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -23,74 +23,6 @@ struct old_sigaction32 { __u32 sa_flags; __u32 sa_restorer; /* Another 32 bit pointer */ }; - -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[((128/sizeof(int)) - 3)]; - - /* kill() */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - pid_t _pid; /* sender's pid */ - uid_t _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - pid_t _pid; /* which child */ - uid_t _uid; /* sender's uid */ - int _status;/* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - __u32 _addr; /* faulting insn/memory ref. - pointer */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} compat_siginfo_t; - -/* - * How these fields are to be accessed. - */ -#define si_pid _sifields._kill._pid -#define si_uid _sifields._kill._uid -#define si_status _sifields._sigchld._status -#define si_utime _sifields._sigchld._utime -#define si_stime _sifields._sigchld._stime -#define si_value _sifields._rt._sigval -#define si_int _sifields._rt._sigval.sival_int -#define si_ptr _sifields._rt._sigval.sival_ptr -#define si_addr _sifields._sigfault._addr -#define si_band _sifields._sigpoll._band -#define si_fd _sifields._sigpoll._fd -#define si_tid _sifields._timer._tid -#define si_overrun _sifields._timer._overrun /* asm/sigcontext.h */ typedef union diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index cc84a24c023f..f00286bd2ef9 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -1501,6 +1501,33 @@ static struct insn *find_insn(unsigned char *code) return NULL; } +/** + * insn_to_mnemonic - decode an s390 instruction + * @instruction: instruction to decode + * @buf: buffer to fill with mnemonic + * + * Decode the instruction at @instruction and store the corresponding + * mnemonic into @buf. + * @buf is left unchanged if the instruction could not be decoded. + * Returns: + * %0 on success, %-ENOENT if the instruction was not found. + */ +int insn_to_mnemonic(unsigned char *instruction, char buf[8]) +{ + struct insn *insn; + + insn = find_insn(instruction); + if (!insn) + return -ENOENT; + if (insn->name[0] == '\0') + snprintf(buf, sizeof(buf), "%s", + long_insn_name[(int) insn->name[1]]); + else + snprintf(buf, sizeof(buf), "%.5s", insn->name); + return 0; +} +EXPORT_SYMBOL_GPL(insn_to_mnemonic); + static int print_insn(char *buffer, unsigned char *code, unsigned long addr) { struct insn *insn; diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 9b04a32e5695..b58dd869cb32 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -21,6 +21,7 @@ config KVM depends on HAVE_KVM && EXPERIMENTAL select PREEMPT_NOTIFIERS select ANON_INODES + select HAVE_KVM_CPU_RELAX_INTERCEPT ---help--- Support hosting paravirtualized guest machines using the SIE virtualization capability on the mainframe. This should work diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index c88bb7793390..a390687feb13 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -14,6 +14,8 @@ #include <linux/kvm.h> #include <linux/kvm_host.h> #include "kvm-s390.h" +#include "trace.h" +#include "trace-s390.h" static int diag_release_pages(struct kvm_vcpu *vcpu) { @@ -98,6 +100,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) vcpu->run->exit_reason = KVM_EXIT_S390_RESET; VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx", vcpu->run->s390_reset_flags); + trace_kvm_s390_request_resets(vcpu->run->s390_reset_flags); return -EREMOTE; } @@ -105,6 +108,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) { int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; + trace_kvm_s390_handle_diag(vcpu, code); switch (code) { case 0x10: return diag_release_pages(vcpu); diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index adae539f12e2..22798ec33fd1 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -19,6 +19,8 @@ #include "kvm-s390.h" #include "gaccess.h" +#include "trace.h" +#include "trace-s390.h" static int handle_lctlg(struct kvm_vcpu *vcpu) { @@ -45,6 +47,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, disp2); + trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); do { rc = get_guest_u64(vcpu, useraddr, @@ -82,6 +85,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, disp2); + trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); reg = reg1; do { @@ -135,6 +139,8 @@ static int handle_stop(struct kvm_vcpu *vcpu) vcpu->stat.exit_stop_request++; spin_lock_bh(&vcpu->arch.local_int.lock); + trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits); + if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) { vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP; rc = SIE_INTERCEPT_RERUNVCPU; @@ -171,6 +177,7 @@ static int handle_validity(struct kvm_vcpu *vcpu) int rc; vcpu->stat.exit_validity++; + trace_kvm_s390_intercept_validity(vcpu, viwhy); if (viwhy == 0x37) { vmaddr = gmap_fault(vcpu->arch.sie_block->prefix, vcpu->arch.gmap); @@ -213,6 +220,9 @@ static int handle_instruction(struct kvm_vcpu *vcpu) intercept_handler_t handler; vcpu->stat.exit_instruction++; + trace_kvm_s390_intercept_instruction(vcpu, + vcpu->arch.sie_block->ipa, + vcpu->arch.sie_block->ipb); handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; if (handler) return handler(vcpu); @@ -222,6 +232,7 @@ static int handle_instruction(struct kvm_vcpu *vcpu) static int handle_prog(struct kvm_vcpu *vcpu) { vcpu->stat.exit_program_interruption++; + trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc); return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); } diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index b7bc1aac8ed2..ff1e2f8ef94a 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -19,6 +19,7 @@ #include <asm/uaccess.h> #include "kvm-s390.h" #include "gaccess.h" +#include "trace-s390.h" static int psw_extint_disabled(struct kvm_vcpu *vcpu) { @@ -130,6 +131,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, case KVM_S390_INT_EMERGENCY: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg"); vcpu->stat.deliver_emergency_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->emerg.code, 0); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201); if (rc == -EFAULT) exception = 1; @@ -152,6 +155,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, case KVM_S390_INT_EXTERNAL_CALL: VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); vcpu->stat.deliver_external_call++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->extcall.code, 0); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); if (rc == -EFAULT) exception = 1; @@ -175,6 +180,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", inti->ext.ext_params); vcpu->stat.deliver_service_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->ext.ext_params, 0); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401); if (rc == -EFAULT) exception = 1; @@ -198,6 +205,9 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx", inti->ext.ext_params, inti->ext.ext_params2); vcpu->stat.deliver_virtio_interrupt++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->ext.ext_params, + inti->ext.ext_params2); rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603); if (rc == -EFAULT) exception = 1; @@ -229,6 +239,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, case KVM_S390_SIGP_STOP: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop"); vcpu->stat.deliver_stop_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + 0, 0); __set_intercept_indicator(vcpu, inti); break; @@ -236,12 +248,16 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x", inti->prefix.address); vcpu->stat.deliver_prefix_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->prefix.address, 0); kvm_s390_set_prefix(vcpu, inti->prefix.address); break; case KVM_S390_RESTART: VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart"); vcpu->stat.deliver_restart_signal++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + 0, 0); rc = copy_to_guest(vcpu, offsetof(struct _lowcore, restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); if (rc == -EFAULT) @@ -259,6 +275,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, inti->pgm.code, table[vcpu->arch.sie_block->ipa >> 14]); vcpu->stat.deliver_program_int++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + inti->pgm.code, 0); rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code); if (rc == -EFAULT) exception = 1; @@ -405,9 +423,7 @@ no_timer: set_current_state(TASK_INTERRUPTIBLE); spin_unlock_bh(&vcpu->arch.local_int.lock); spin_unlock(&vcpu->arch.local_int.float_int->lock); - vcpu_put(vcpu); schedule(); - vcpu_load(vcpu); spin_lock(&vcpu->arch.local_int.float_int->lock); spin_lock_bh(&vcpu->arch.local_int.lock); } @@ -515,6 +531,7 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code) inti->pgm.code = code; VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code); + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1); spin_lock_bh(&li->lock); list_add(&inti->list, &li->list); atomic_set(&li->active, 1); @@ -556,6 +573,8 @@ int kvm_s390_inject_vm(struct kvm *kvm, kfree(inti); return -EINVAL; } + trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, + 2); mutex_lock(&kvm->lock); fi = &kvm->arch.float_int; @@ -621,6 +640,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, kfree(inti); return -EINVAL; } + trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm, + s390int->parm64, 2); mutex_lock(&vcpu->kvm->lock); li = &vcpu->arch.local_int; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index d470ccbfabae..ecced9d18986 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -32,6 +32,10 @@ #include "kvm-s390.h" #include "gaccess.h" +#define CREATE_TRACE_POINTS +#include "trace.h" +#include "trace-s390.h" + #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU struct kvm_stats_debugfs_item debugfs_entries[] = { @@ -242,6 +246,7 @@ out_err: void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { VCPU_EVENT(vcpu, 3, "%s", "free cpu"); + trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id); if (!kvm_is_ucontrol(vcpu->kvm)) { clear_bit(63 - vcpu->vcpu_id, (unsigned long *) &vcpu->kvm->arch.sca->mcn); @@ -417,6 +422,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, goto out_free_sie_block; VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu, vcpu->arch.sie_block); + trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block); return vcpu; out_free_sie_block: @@ -607,18 +613,22 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) local_irq_enable(); VCPU_EVENT(vcpu, 6, "entering sie flags %x", atomic_read(&vcpu->arch.sie_block->cpuflags)); + trace_kvm_s390_sie_enter(vcpu, + atomic_read(&vcpu->arch.sie_block->cpuflags)); rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); if (rc) { if (kvm_is_ucontrol(vcpu->kvm)) { rc = SIE_INTERCEPT_UCONTROL; } else { VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); + trace_kvm_s390_sie_fault(vcpu); kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); rc = 0; } } VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", vcpu->arch.sie_block->icptcode); + trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); local_irq_disable(); kvm_guest_exit(); local_irq_enable(); @@ -959,7 +969,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, return; } -void kvm_arch_flush_shadow(struct kvm *kvm) +void kvm_arch_flush_shadow_all(struct kvm *kvm) +{ +} + +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot) { } diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 310be61bead7..d768906f15c8 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -20,6 +20,7 @@ #include <asm/sysinfo.h> #include "gaccess.h" #include "kvm-s390.h" +#include "trace.h" static int handle_set_prefix(struct kvm_vcpu *vcpu) { @@ -59,6 +60,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu) kvm_s390_set_prefix(vcpu, address); VCPU_EVENT(vcpu, 5, "setting prefix to %x", address); + trace_kvm_s390_handle_prefix(vcpu, 1, address); out: return 0; } @@ -91,6 +93,7 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu) } VCPU_EVENT(vcpu, 5, "storing prefix to %x", address); + trace_kvm_s390_handle_prefix(vcpu, 0, address); out: return 0; } @@ -119,6 +122,7 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu) } VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr); + trace_kvm_s390_handle_stap(vcpu, useraddr); out: return 0; } @@ -164,9 +168,11 @@ static int handle_stfl(struct kvm_vcpu *vcpu) &facility_list, sizeof(facility_list)); if (rc == -EFAULT) kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); - else + else { VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list); + trace_kvm_s390_handle_stfl(vcpu, facility_list); + } return 0; } @@ -278,6 +284,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu) kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); goto out_mem; } + trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); free_page(mem); vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); vcpu->run->s.regs.gprs[0] = 0; diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 56f80e1f98f7..566ddf6e8dfb 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -18,6 +18,7 @@ #include <asm/sigp.h> #include "gaccess.h" #include "kvm-s390.h" +#include "trace.h" static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg) @@ -344,6 +345,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) else parameter = vcpu->run->s.regs.gprs[r1 + 1]; + trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter); switch (order_code) { case SIGP_SENSE: vcpu->stat.instruction_sigp_sense++; diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h new file mode 100644 index 000000000000..90fdf85b5ff7 --- /dev/null +++ b/arch/s390/kvm/trace-s390.h @@ -0,0 +1,210 @@ +#if !defined(_TRACE_KVMS390_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_KVMS390_H + +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM kvm-s390 +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace-s390 + +/* + * Trace point for the creation of the kvm instance. + */ +TRACE_EVENT(kvm_s390_create_vm, + TP_PROTO(unsigned long type), + TP_ARGS(type), + + TP_STRUCT__entry( + __field(unsigned long, type) + ), + + TP_fast_assign( + __entry->type = type; + ), + + TP_printk("create vm%s", + __entry->type & KVM_VM_S390_UCONTROL ? " (UCONTROL)" : "") + ); + +/* + * Trace points for creation and destruction of vpcus. + */ +TRACE_EVENT(kvm_s390_create_vcpu, + TP_PROTO(unsigned int id, struct kvm_vcpu *vcpu, + struct kvm_s390_sie_block *sie_block), + TP_ARGS(id, vcpu, sie_block), + + TP_STRUCT__entry( + __field(unsigned int, id) + __field(struct kvm_vcpu *, vcpu) + __field(struct kvm_s390_sie_block *, sie_block) + ), + + TP_fast_assign( + __entry->id = id; + __entry->vcpu = vcpu; + __entry->sie_block = sie_block; + ), + + TP_printk("create cpu %d at %p, sie block at %p", __entry->id, + __entry->vcpu, __entry->sie_block) + ); + +TRACE_EVENT(kvm_s390_destroy_vcpu, + TP_PROTO(unsigned int id), + TP_ARGS(id), + + TP_STRUCT__entry( + __field(unsigned int, id) + ), + + TP_fast_assign( + __entry->id = id; + ), + + TP_printk("destroy cpu %d", __entry->id) + ); + +/* + * Trace points for injection of interrupts, either per machine or + * per vcpu. + */ + +#define kvm_s390_int_type \ + {KVM_S390_SIGP_STOP, "sigp stop"}, \ + {KVM_S390_PROGRAM_INT, "program interrupt"}, \ + {KVM_S390_SIGP_SET_PREFIX, "sigp set prefix"}, \ + {KVM_S390_RESTART, "sigp restart"}, \ + {KVM_S390_INT_VIRTIO, "virtio interrupt"}, \ + {KVM_S390_INT_SERVICE, "sclp interrupt"}, \ + {KVM_S390_INT_EMERGENCY, "sigp emergency"}, \ + {KVM_S390_INT_EXTERNAL_CALL, "sigp ext call"} + +TRACE_EVENT(kvm_s390_inject_vm, + TP_PROTO(__u64 type, __u32 parm, __u64 parm64, int who), + TP_ARGS(type, parm, parm64, who), + + TP_STRUCT__entry( + __field(__u32, inttype) + __field(__u32, parm) + __field(__u64, parm64) + __field(int, who) + ), + + TP_fast_assign( + __entry->inttype = type & 0x00000000ffffffff; + __entry->parm = parm; + __entry->parm64 = parm64; + __entry->who = who; + ), + + TP_printk("inject%s: type:%x (%s) parm:%x parm64:%llx", + (__entry->who == 1) ? " (from kernel)" : + (__entry->who == 2) ? " (from user)" : "", + __entry->inttype, + __print_symbolic(__entry->inttype, kvm_s390_int_type), + __entry->parm, __entry->parm64) + ); + +TRACE_EVENT(kvm_s390_inject_vcpu, + TP_PROTO(unsigned int id, __u64 type, __u32 parm, __u64 parm64, \ + int who), + TP_ARGS(id, type, parm, parm64, who), + + TP_STRUCT__entry( + __field(int, id) + __field(__u32, inttype) + __field(__u32, parm) + __field(__u64, parm64) + __field(int, who) + ), + + TP_fast_assign( + __entry->id = id; + __entry->inttype = type & 0x00000000ffffffff; + __entry->parm = parm; + __entry->parm64 = parm64; + __entry->who = who; + ), + + TP_printk("inject%s (vcpu %d): type:%x (%s) parm:%x parm64:%llx", + (__entry->who == 1) ? " (from kernel)" : + (__entry->who == 2) ? " (from user)" : "", + __entry->id, __entry->inttype, + __print_symbolic(__entry->inttype, kvm_s390_int_type), + __entry->parm, __entry->parm64) + ); + +/* + * Trace point for the actual delivery of interrupts. + */ +TRACE_EVENT(kvm_s390_deliver_interrupt, + TP_PROTO(unsigned int id, __u64 type, __u32 data0, __u64 data1), + TP_ARGS(id, type, data0, data1), + + TP_STRUCT__entry( + __field(int, id) + __field(__u32, inttype) + __field(__u32, data0) + __field(__u64, data1) + ), + + TP_fast_assign( + __entry->id = id; + __entry->inttype = type & 0x00000000ffffffff; + __entry->data0 = data0; + __entry->data1 = data1; + ), + + TP_printk("deliver interrupt (vcpu %d): type:%x (%s) " \ + "data:%08x %016llx", + __entry->id, __entry->inttype, + __print_symbolic(__entry->inttype, kvm_s390_int_type), + __entry->data0, __entry->data1) + ); + +/* + * Trace point for resets that may be requested from userspace. + */ +TRACE_EVENT(kvm_s390_request_resets, + TP_PROTO(__u64 resets), + TP_ARGS(resets), + + TP_STRUCT__entry( + __field(__u64, resets) + ), + + TP_fast_assign( + __entry->resets = resets; + ), + + TP_printk("requesting userspace resets %llx", + __entry->resets) + ); + +/* + * Trace point for a vcpu's stop requests. + */ +TRACE_EVENT(kvm_s390_stop_request, + TP_PROTO(unsigned int action_bits), + TP_ARGS(action_bits), + + TP_STRUCT__entry( + __field(unsigned int, action_bits) + ), + + TP_fast_assign( + __entry->action_bits = action_bits; + ), + + TP_printk("stop request, action_bits = %08x", + __entry->action_bits) + ); + + +#endif /* _TRACE_KVMS390_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h new file mode 100644 index 000000000000..2b29e62351d3 --- /dev/null +++ b/arch/s390/kvm/trace.h @@ -0,0 +1,341 @@ +#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_KVM_H + +#include <linux/tracepoint.h> +#include <asm/sigp.h> +#include <asm/debug.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM kvm +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* + * Helpers for vcpu-specific tracepoints containing the same information + * as s390dbf VCPU_EVENTs. + */ +#define VCPU_PROTO_COMMON struct kvm_vcpu *vcpu +#define VCPU_ARGS_COMMON vcpu +#define VCPU_FIELD_COMMON __field(int, id) \ + __field(unsigned long, pswmask) \ + __field(unsigned long, pswaddr) +#define VCPU_ASSIGN_COMMON do { \ + __entry->id = vcpu->vcpu_id; \ + __entry->pswmask = vcpu->arch.sie_block->gpsw.mask; \ + __entry->pswaddr = vcpu->arch.sie_block->gpsw.addr; \ + } while (0); +#define VCPU_TP_PRINTK(p_str, p_args...) \ + TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id, \ + __entry->pswmask, __entry->pswaddr, p_args) + +/* + * Tracepoints for SIE entry and exit. + */ +TRACE_EVENT(kvm_s390_sie_enter, + TP_PROTO(VCPU_PROTO_COMMON, int cpuflags), + TP_ARGS(VCPU_ARGS_COMMON, cpuflags), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, cpuflags) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->cpuflags = cpuflags; + ), + + VCPU_TP_PRINTK("entering sie flags %x", __entry->cpuflags) + ); + +TRACE_EVENT(kvm_s390_sie_fault, + TP_PROTO(VCPU_PROTO_COMMON), + TP_ARGS(VCPU_ARGS_COMMON), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + ), + + VCPU_TP_PRINTK("%s", "fault in sie instruction") + ); + +#define sie_intercept_code \ + {0x04, "Instruction"}, \ + {0x08, "Program interruption"}, \ + {0x0C, "Instruction and program interuption"}, \ + {0x10, "External request"}, \ + {0x14, "External interruption"}, \ + {0x18, "I/O request"}, \ + {0x1C, "Wait state"}, \ + {0x20, "Validity"}, \ + {0x28, "Stop request"} + +TRACE_EVENT(kvm_s390_sie_exit, + TP_PROTO(VCPU_PROTO_COMMON, u8 icptcode), + TP_ARGS(VCPU_ARGS_COMMON, icptcode), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(u8, icptcode) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->icptcode = icptcode; + ), + + VCPU_TP_PRINTK("exit sie icptcode %d (%s)", __entry->icptcode, + __print_symbolic(__entry->icptcode, + sie_intercept_code)) + ); + +/* + * Trace point for intercepted instructions. + */ +TRACE_EVENT(kvm_s390_intercept_instruction, + TP_PROTO(VCPU_PROTO_COMMON, __u16 ipa, __u32 ipb), + TP_ARGS(VCPU_ARGS_COMMON, ipa, ipb), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u64, instruction) + __field(char, insn[8]) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->instruction = ((__u64)ipa << 48) | + ((__u64)ipb << 16); + ), + + VCPU_TP_PRINTK("intercepted instruction %016llx (%s)", + __entry->instruction, + insn_to_mnemonic((unsigned char *) + &__entry->instruction, + __entry->insn) ? + "unknown" : __entry->insn) + ); + +/* + * Trace point for intercepted program interruptions. + */ +TRACE_EVENT(kvm_s390_intercept_prog, + TP_PROTO(VCPU_PROTO_COMMON, __u16 code), + TP_ARGS(VCPU_ARGS_COMMON, code), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u16, code) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->code = code; + ), + + VCPU_TP_PRINTK("intercepted program interruption %04x", + __entry->code) + ); + +/* + * Trace point for validity intercepts. + */ +TRACE_EVENT(kvm_s390_intercept_validity, + TP_PROTO(VCPU_PROTO_COMMON, __u16 viwhy), + TP_ARGS(VCPU_ARGS_COMMON, viwhy), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u16, viwhy) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->viwhy = viwhy; + ), + + VCPU_TP_PRINTK("got validity intercept %04x", __entry->viwhy) + ); + +/* + * Trace points for instructions that are of special interest. + */ + +#define sigp_order_codes \ + {SIGP_SENSE, "sense"}, \ + {SIGP_EXTERNAL_CALL, "external call"}, \ + {SIGP_EMERGENCY_SIGNAL, "emergency signal"}, \ + {SIGP_STOP, "stop"}, \ + {SIGP_STOP_AND_STORE_STATUS, "stop and store status"}, \ + {SIGP_SET_ARCHITECTURE, "set architecture"}, \ + {SIGP_SET_PREFIX, "set prefix"}, \ + {SIGP_SENSE_RUNNING, "sense running"}, \ + {SIGP_RESTART, "restart"} + +TRACE_EVENT(kvm_s390_handle_sigp, + TP_PROTO(VCPU_PROTO_COMMON, __u8 order_code, __u16 cpu_addr, \ + __u32 parameter), + TP_ARGS(VCPU_ARGS_COMMON, order_code, cpu_addr, parameter), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u8, order_code) + __field(__u16, cpu_addr) + __field(__u32, parameter) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->order_code = order_code; + __entry->cpu_addr = cpu_addr; + __entry->parameter = parameter; + ), + + VCPU_TP_PRINTK("handle sigp order %02x (%s), cpu address %04x, " \ + "parameter %08x", __entry->order_code, + __print_symbolic(__entry->order_code, + sigp_order_codes), + __entry->cpu_addr, __entry->parameter) + ); + +#define diagnose_codes \ + {0x10, "release pages"}, \ + {0x44, "time slice end"}, \ + {0x308, "ipl functions"}, \ + {0x500, "kvm hypercall"}, \ + {0x501, "kvm breakpoint"} + +TRACE_EVENT(kvm_s390_handle_diag, + TP_PROTO(VCPU_PROTO_COMMON, __u16 code), + TP_ARGS(VCPU_ARGS_COMMON, code), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(__u16, code) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->code = code; + ), + + VCPU_TP_PRINTK("handle diagnose call %04x (%s)", __entry->code, + __print_symbolic(__entry->code, diagnose_codes)) + ); + +TRACE_EVENT(kvm_s390_handle_lctl, + TP_PROTO(VCPU_PROTO_COMMON, int g, int reg1, int reg3, u64 addr), + TP_ARGS(VCPU_ARGS_COMMON, g, reg1, reg3, addr), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, g) + __field(int, reg1) + __field(int, reg3) + __field(u64, addr) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->g = g; + __entry->reg1 = reg1; + __entry->reg3 = reg3; + __entry->addr = addr; + ), + + VCPU_TP_PRINTK("%s: loading cr %x-%x from %016llx", + __entry->g ? "lctlg" : "lctl", + __entry->reg1, __entry->reg3, __entry->addr) + ); + +TRACE_EVENT(kvm_s390_handle_prefix, + TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address), + TP_ARGS(VCPU_ARGS_COMMON, set, address), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, set) + __field(u32, address) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->set = set; + __entry->address = address; + ), + + VCPU_TP_PRINTK("%s prefix to %08x", + __entry->set ? "setting" : "storing", + __entry->address) + ); + +TRACE_EVENT(kvm_s390_handle_stap, + TP_PROTO(VCPU_PROTO_COMMON, u64 address), + TP_ARGS(VCPU_ARGS_COMMON, address), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(u64, address) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->address = address; + ), + + VCPU_TP_PRINTK("storing cpu address to %016llx", + __entry->address) + ); + +TRACE_EVENT(kvm_s390_handle_stfl, + TP_PROTO(VCPU_PROTO_COMMON, unsigned int facility_list), + TP_ARGS(VCPU_ARGS_COMMON, facility_list), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(unsigned int, facility_list) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->facility_list = facility_list; + ), + + VCPU_TP_PRINTK("store facility list value %08x", + __entry->facility_list) + ); + +TRACE_EVENT(kvm_s390_handle_stsi, + TP_PROTO(VCPU_PROTO_COMMON, int fc, int sel1, int sel2, u64 addr), + TP_ARGS(VCPU_ARGS_COMMON, fc, sel1, sel2, addr), + + TP_STRUCT__entry( + VCPU_FIELD_COMMON + __field(int, fc) + __field(int, sel1) + __field(int, sel2) + __field(u64, addr) + ), + + TP_fast_assign( + VCPU_ASSIGN_COMMON + __entry->fc = fc; + __entry->sel1 = sel1; + __entry->sel2 = sel2; + __entry->addr = addr; + ), + + VCPU_TP_PRINTK("STSI %d.%d.%d information stored to %016llx", + __entry->fc, __entry->sel1, __entry->sel2, + __entry->addr) + ); + +#endif /* _TRACE_KVM_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/arch/score/Kconfig b/arch/score/Kconfig index ba0f412920be..461c23747491 100644 --- a/arch/score/Kconfig +++ b/arch/score/Kconfig @@ -5,6 +5,7 @@ config SCORE select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_SHOW select GENERIC_IOMAP + select GENERIC_ATOMIC64 select HAVE_MEMBLOCK select HAVE_MEMBLOCK_NODE_MAP select ARCH_DISCARD_MEMBLOCK diff --git a/arch/score/include/asm/elf.h b/arch/score/include/asm/elf.h index f478ce94181f..5d566c7a0af2 100644 --- a/arch/score/include/asm/elf.h +++ b/arch/score/include/asm/elf.h @@ -54,7 +54,7 @@ typedef elf_fpreg_t elf_fpregset_t; #define SET_PERSONALITY(ex) \ do { \ - set_personality(PER_LINUX); \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))); \ } while (0) struct task_struct; diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index e478bf9a7e91..21e867974066 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c @@ -112,6 +112,7 @@ score_execve(struct pt_regs *regs) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ +asmlinkage int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]) diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h index f38112be67d2..37924afa8d8a 100644 --- a/arch/sh/include/asm/elf.h +++ b/arch/sh/include/asm/elf.h @@ -183,7 +183,8 @@ do { \ } while (0) #endif -#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX_32BIT | (current->personality & (~PER_MASK))) #ifdef CONFIG_VSYSCALL /* vDSO has arch_setup_additional_pages */ diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 0cf60a628814..73a23f4617a3 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -134,7 +134,7 @@ __BUILD_MEMORY_STRING(__raw_, q, u64) * load/store instructions. sh_io_port_base is the virtual address to * which all ports are being mapped. */ -extern const unsigned long sh_io_port_base; +extern unsigned long sh_io_port_base; static inline void __set_io_port_base(unsigned long pbase) { diff --git a/arch/sh/kernel/ioport.c b/arch/sh/kernel/ioport.c index e3ad6103e7c1..cca14ba84a37 100644 --- a/arch/sh/kernel/ioport.c +++ b/arch/sh/kernel/ioport.c @@ -11,7 +11,7 @@ #include <linux/module.h> #include <linux/io.h> -const unsigned long sh_io_port_base __read_mostly = -1; +unsigned long sh_io_port_base __read_mostly = -1; EXPORT_SYMBOL(sh_io_port_base); void __iomem *__ioport_map(unsigned long addr, unsigned int size) diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index b8be20d42a0a..cef99fbc0a21 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -36,6 +36,7 @@ typedef s64 compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -147,6 +148,65 @@ typedef u32 compat_old_sigset_t; typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +#define SI_PAD_SIZE32 (128/sizeof(int) - 3) + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[SI_PAD_SIZE32]; + + /* kill() */ + struct { + compat_pid_t _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + compat_pid_t _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + compat_pid_t _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ + struct { + u32 _addr; /* faulting insn/memory ref. */ + int _trapno; + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -156,7 +216,6 @@ typedef u32 compat_sigset_word; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h index 2d4d755cba9e..ac74a2c98e6d 100644 --- a/arch/sparc/include/asm/elf_32.h +++ b/arch/sparc/include/asm/elf_32.h @@ -128,6 +128,7 @@ typedef struct { #define ELF_PLATFORM (NULL) -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #endif /* !(__ASMSPARC_ELF_H) */ diff --git a/arch/sparc/include/asm/siginfo.h b/arch/sparc/include/asm/siginfo.h index 215900fce21b..dbc182c438b4 100644 --- a/arch/sparc/include/asm/siginfo.h +++ b/arch/sparc/include/asm/siginfo.h @@ -3,7 +3,6 @@ #if defined(__sparc__) && defined(__arch64__) -#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) #define __ARCH_SI_BAND_T int diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index a53e0a5fd3a3..53e48f721ce3 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -54,58 +54,6 @@ struct signal_frame32 { /* __siginfo_rwin_t * */u32 rwin_save; } __attribute__((aligned(8))); -typedef struct compat_siginfo{ - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[SI_PAD_SIZE32]; - - /* kill() */ - struct { - compat_pid_t _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - compat_pid_t _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - compat_pid_t _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */ - struct { - u32 _addr; /* faulting insn/memory ref. */ - int _trapno; - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -}compat_siginfo_t; - struct rt_signal_frame32 { struct sparc_stackf32 ss; compat_siginfo_t info; diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 6e74450ff0a1..3063e6fc8daa 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -110,6 +110,68 @@ struct compat_flock64 { typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +#define COMPAT_SI_PAD_SIZE (128/sizeof(int) - 3) + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[COMPAT_SI_PAD_SIZE]; + + /* kill() */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + int _overrun_incr; /* amount to add to overrun */ + } _timer; + + /* POSIX.1b signals */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + unsigned int _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + unsigned int _addr; /* faulting insn/memory ref. */ +#ifdef __ARCH_SI_TRAPNO + int _trapno; /* TRAP # which caused the signal */ +#endif + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h index d16d006d660e..f8ccf08f6934 100644 --- a/arch/tile/include/asm/elf.h +++ b/arch/tile/include/asm/elf.h @@ -156,12 +156,12 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, #undef SET_PERSONALITY #define SET_PERSONALITY(ex) \ do { \ - current->personality = PER_LINUX; \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))); \ current_thread_info()->status &= ~TS_COMPAT; \ } while (0) #define COMPAT_SET_PERSONALITY(ex) \ do { \ - current->personality = PER_LINUX_32BIT; \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))); \ current_thread_info()->status |= TS_COMPAT; \ } while (0) diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 474571b84085..7bc0859a9f5e 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -55,63 +55,6 @@ struct compat_ucontext { sigset_t uc_sigmask; /* mask last for extensibility */ }; -#define COMPAT_SI_PAD_SIZE ((SI_MAX_SIZE - 3 * sizeof(int)) / sizeof(int)) - -struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[COMPAT_SI_PAD_SIZE]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - int _overrun_incr; /* amount to add to overrun */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO - int _trapno; /* TRAP # which caused the signal */ -#endif - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -}; - struct compat_rt_sigframe { unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */ struct compat_siginfo info; diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig index b0a47433341e..1e638e75a6b7 100644 --- a/arch/unicore32/Kconfig +++ b/arch/unicore32/Kconfig @@ -6,6 +6,7 @@ config UNICORE32 select HAVE_DMA_ATTRS select HAVE_KERNEL_GZIP select HAVE_KERNEL_BZIP2 + select GENERIC_ATOMIC64 select HAVE_KERNEL_LZO select HAVE_KERNEL_LZMA select ARCH_HAVE_CUSTOM_GPIO_H diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7f9a395c5254..b72777ff32a9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -586,23 +586,18 @@ config PARAVIRT_TIME_ACCOUNTING source "arch/x86/xen/Kconfig" -config KVM_CLOCK - bool "KVM paravirtualized clock" - select PARAVIRT - select PARAVIRT_CLOCK - ---help--- - Turning on this option will allow you to run a paravirtualized clock - when running over the KVM hypervisor. Instead of relying on a PIT - (or probably other) emulation by the underlying device model, the host - provides the guest with timing infrastructure such as time of day, and - system time - config KVM_GUEST - bool "KVM Guest support" + bool "KVM Guest support (including kvmclock)" + select PARAVIRT select PARAVIRT + select PARAVIRT_CLOCK + default y if PARAVIRT_GUEST ---help--- This option enables various optimizations for running under the KVM - hypervisor. + hypervisor. It includes a paravirtualized clock, so that instead + of relying on a PIT (or probably other) emulation by the + underlying device model, the host provides the guest with + timing infrastructure such as time of day, and system time source "arch/x86/lguest/Kconfig" diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index e908e5de82d3..5bacb4a226ac 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -12,6 +12,8 @@ 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_CAST5_AVX_X86_64) += cast5-avx-x86_64.o +obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-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 @@ -32,6 +34,8 @@ 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 +cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o +cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_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/aes_glue.c b/arch/x86/crypto/aes_glue.c index 59b37deb8c8d..aafe8ce0d65d 100644 --- a/arch/x86/crypto/aes_glue.c +++ b/arch/x86/crypto/aes_glue.c @@ -40,7 +40,6 @@ static struct crypto_alg aes_alg = { .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index 34fdcff4d2c8..7c04d0da709b 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -28,6 +28,9 @@ #include <crypto/aes.h> #include <crypto/cryptd.h> #include <crypto/ctr.h> +#include <crypto/b128ops.h> +#include <crypto/lrw.h> +#include <crypto/xts.h> #include <asm/cpu_device_id.h> #include <asm/i387.h> #include <asm/crypto/aes.h> @@ -41,18 +44,10 @@ #define HAS_CTR #endif -#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE) -#define HAS_LRW -#endif - #if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE) #define HAS_PCBC #endif -#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE) -#define HAS_XTS -#endif - /* This data is stored at the end of the crypto_tfm struct. * It's a type of per "session" data storage location. * This needs to be 16 byte aligned. @@ -79,6 +74,16 @@ struct aesni_hash_subkey_req_data { #define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1)) #define RFC4106_HASH_SUBKEY_SIZE 16 +struct aesni_lrw_ctx { + struct lrw_table_ctx lrw_table; + u8 raw_aes_ctx[sizeof(struct crypto_aes_ctx) + AESNI_ALIGN - 1]; +}; + +struct aesni_xts_ctx { + u8 raw_tweak_ctx[sizeof(struct crypto_aes_ctx) + AESNI_ALIGN - 1]; + u8 raw_crypt_ctx[sizeof(struct crypto_aes_ctx) + AESNI_ALIGN - 1]; +}; + asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key, unsigned int key_len); asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out, @@ -398,13 +403,6 @@ static int ablk_rfc3686_ctr_init(struct crypto_tfm *tfm) #endif #endif -#ifdef HAS_LRW -static int ablk_lrw_init(struct crypto_tfm *tfm) -{ - return ablk_init_common(tfm, "fpu(lrw(__driver-aes-aesni))"); -} -#endif - #ifdef HAS_PCBC static int ablk_pcbc_init(struct crypto_tfm *tfm) { @@ -412,12 +410,160 @@ static int ablk_pcbc_init(struct crypto_tfm *tfm) } #endif -#ifdef HAS_XTS -static int ablk_xts_init(struct crypto_tfm *tfm) +static void lrw_xts_encrypt_callback(void *ctx, u8 *blks, unsigned int nbytes) { - return ablk_init_common(tfm, "fpu(xts(__driver-aes-aesni))"); + aesni_ecb_enc(ctx, blks, blks, nbytes); +} + +static void lrw_xts_decrypt_callback(void *ctx, u8 *blks, unsigned int nbytes) +{ + aesni_ecb_dec(ctx, blks, blks, nbytes); +} + +static int lrw_aesni_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct aesni_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + err = aes_set_key_common(tfm, ctx->raw_aes_ctx, key, + keylen - AES_BLOCK_SIZE); + if (err) + return err; + + return lrw_init_table(&ctx->lrw_table, key + keylen - AES_BLOCK_SIZE); +} + +static void lrw_aesni_exit_tfm(struct crypto_tfm *tfm) +{ + struct aesni_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + + lrw_free_table(&ctx->lrw_table); +} + +static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct aesni_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[8]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = aes_ctx(ctx->raw_aes_ctx), + .crypt_fn = lrw_xts_encrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + kernel_fpu_begin(); + ret = lrw_crypt(desc, dst, src, nbytes, &req); + kernel_fpu_end(); + + return ret; +} + +static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct aesni_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[8]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = aes_ctx(ctx->raw_aes_ctx), + .crypt_fn = lrw_xts_decrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + kernel_fpu_begin(); + ret = lrw_crypt(desc, dst, src, nbytes, &req); + kernel_fpu_end(); + + return ret; +} + +static int xts_aesni_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct aesni_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 = aes_set_key_common(tfm, ctx->raw_crypt_ctx, key, keylen / 2); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return aes_set_key_common(tfm, ctx->raw_tweak_ctx, key + keylen / 2, + keylen / 2); +} + + +static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct aesni_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[8]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = aes_ctx(ctx->raw_tweak_ctx), + .tweak_fn = XTS_TWEAK_CAST(aesni_enc), + .crypt_ctx = aes_ctx(ctx->raw_crypt_ctx), + .crypt_fn = lrw_xts_encrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + kernel_fpu_begin(); + ret = xts_crypt(desc, dst, src, nbytes, &req); + kernel_fpu_end(); + + return ret; +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct aesni_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[8]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = aes_ctx(ctx->raw_tweak_ctx), + .tweak_fn = XTS_TWEAK_CAST(aesni_enc), + .crypt_ctx = aes_ctx(ctx->raw_crypt_ctx), + .crypt_fn = lrw_xts_decrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + kernel_fpu_begin(); + ret = xts_crypt(desc, dst, src, nbytes, &req); + kernel_fpu_end(); + + return ret; } -#endif #ifdef CONFIG_X86_64 static int rfc4106_init(struct crypto_tfm *tfm) @@ -1035,10 +1181,10 @@ static struct crypto_alg aesni_algs[] = { { }, #endif #endif -#ifdef HAS_LRW +#ifdef HAS_PCBC }, { - .cra_name = "lrw(aes)", - .cra_driver_name = "lrw-aes-aesni", + .cra_name = "pcbc(aes)", + .cra_driver_name = "pcbc-aes-aesni", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, @@ -1046,12 +1192,12 @@ static struct crypto_alg aesni_algs[] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_init = ablk_lrw_init, + .cra_init = ablk_pcbc_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE, - .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, .setkey = ablk_set_key, .encrypt = ablk_encrypt, @@ -1059,10 +1205,50 @@ static struct crypto_alg aesni_algs[] = { { }, }, #endif -#ifdef HAS_PCBC }, { - .cra_name = "pcbc(aes)", - .cra_driver_name = "pcbc-aes-aesni", + .cra_name = "__lrw-aes-aesni", + .cra_driver_name = "__driver-lrw-aes-aesni", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aesni_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_exit = lrw_aesni_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = lrw_aesni_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "__xts-aes-aesni", + .cra_driver_name = "__driver-xts-aes-aesni", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aesni_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = xts_aesni_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}, { + .cra_name = "lrw(aes)", + .cra_driver_name = "lrw-aes-aesni", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, @@ -1070,20 +1256,18 @@ static struct crypto_alg aesni_algs[] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_init = ablk_pcbc_init, + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, + .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE, .ivsize = AES_BLOCK_SIZE, .setkey = ablk_set_key, .encrypt = ablk_encrypt, .decrypt = ablk_decrypt, }, }, -#endif -#ifdef HAS_XTS }, { .cra_name = "xts(aes)", .cra_driver_name = "xts-aes-aesni", @@ -1094,7 +1278,7 @@ static struct crypto_alg aesni_algs[] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_init = ablk_xts_init, + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -1106,7 +1290,6 @@ static struct crypto_alg aesni_algs[] = { { .decrypt = ablk_decrypt, }, }, -#endif } }; @@ -1118,7 +1301,7 @@ MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id); static int __init aesni_init(void) { - int err, i; + int err; if (!x86_match_cpu(aesni_cpu_id)) return -ENODEV; @@ -1127,9 +1310,6 @@ static int __init aesni_init(void) if (err) return err; - for (i = 0; i < ARRAY_SIZE(aesni_algs); i++) - INIT_LIST_HEAD(&aesni_algs[i].cra_list); - return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs)); } diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c index 7967474de8f7..50ec333b70e6 100644 --- a/arch/x86/crypto/blowfish_glue.c +++ b/arch/x86/crypto/blowfish_glue.c @@ -367,7 +367,6 @@ static struct crypto_alg bf_algs[4] = { { .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, @@ -387,7 +386,6 @@ static struct crypto_alg bf_algs[4] = { { .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, @@ -407,7 +405,6 @@ static struct crypto_alg bf_algs[4] = { { .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, @@ -428,7 +425,6 @@ static struct crypto_alg bf_algs[4] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, diff --git a/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c index eeb2b3b743e9..42ffd2bbab5b 100644 --- a/arch/x86/crypto/camellia_glue.c +++ b/arch/x86/crypto/camellia_glue.c @@ -92,715 +92,715 @@ static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *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, + 0x7000007070707000ULL, 0x8200008282828200ULL, 0x2c00002c2c2c2c00ULL, + 0xec0000ecececec00ULL, 0xb30000b3b3b3b300ULL, 0x2700002727272700ULL, + 0xc00000c0c0c0c000ULL, 0xe50000e5e5e5e500ULL, 0xe40000e4e4e4e400ULL, + 0x8500008585858500ULL, 0x5700005757575700ULL, 0x3500003535353500ULL, + 0xea0000eaeaeaea00ULL, 0x0c00000c0c0c0c00ULL, 0xae0000aeaeaeae00ULL, + 0x4100004141414100ULL, 0x2300002323232300ULL, 0xef0000efefefef00ULL, + 0x6b00006b6b6b6b00ULL, 0x9300009393939300ULL, 0x4500004545454500ULL, + 0x1900001919191900ULL, 0xa50000a5a5a5a500ULL, 0x2100002121212100ULL, + 0xed0000edededed00ULL, 0x0e00000e0e0e0e00ULL, 0x4f00004f4f4f4f00ULL, + 0x4e00004e4e4e4e00ULL, 0x1d00001d1d1d1d00ULL, 0x6500006565656500ULL, + 0x9200009292929200ULL, 0xbd0000bdbdbdbd00ULL, 0x8600008686868600ULL, + 0xb80000b8b8b8b800ULL, 0xaf0000afafafaf00ULL, 0x8f00008f8f8f8f00ULL, + 0x7c00007c7c7c7c00ULL, 0xeb0000ebebebeb00ULL, 0x1f00001f1f1f1f00ULL, + 0xce0000cececece00ULL, 0x3e00003e3e3e3e00ULL, 0x3000003030303000ULL, + 0xdc0000dcdcdcdc00ULL, 0x5f00005f5f5f5f00ULL, 0x5e00005e5e5e5e00ULL, + 0xc50000c5c5c5c500ULL, 0x0b00000b0b0b0b00ULL, 0x1a00001a1a1a1a00ULL, + 0xa60000a6a6a6a600ULL, 0xe10000e1e1e1e100ULL, 0x3900003939393900ULL, + 0xca0000cacacaca00ULL, 0xd50000d5d5d5d500ULL, 0x4700004747474700ULL, + 0x5d00005d5d5d5d00ULL, 0x3d00003d3d3d3d00ULL, 0xd90000d9d9d9d900ULL, + 0x0100000101010100ULL, 0x5a00005a5a5a5a00ULL, 0xd60000d6d6d6d600ULL, + 0x5100005151515100ULL, 0x5600005656565600ULL, 0x6c00006c6c6c6c00ULL, + 0x4d00004d4d4d4d00ULL, 0x8b00008b8b8b8b00ULL, 0x0d00000d0d0d0d00ULL, + 0x9a00009a9a9a9a00ULL, 0x6600006666666600ULL, 0xfb0000fbfbfbfb00ULL, + 0xcc0000cccccccc00ULL, 0xb00000b0b0b0b000ULL, 0x2d00002d2d2d2d00ULL, + 0x7400007474747400ULL, 0x1200001212121200ULL, 0x2b00002b2b2b2b00ULL, + 0x2000002020202000ULL, 0xf00000f0f0f0f000ULL, 0xb10000b1b1b1b100ULL, + 0x8400008484848400ULL, 0x9900009999999900ULL, 0xdf0000dfdfdfdf00ULL, + 0x4c00004c4c4c4c00ULL, 0xcb0000cbcbcbcb00ULL, 0xc20000c2c2c2c200ULL, + 0x3400003434343400ULL, 0x7e00007e7e7e7e00ULL, 0x7600007676767600ULL, + 0x0500000505050500ULL, 0x6d00006d6d6d6d00ULL, 0xb70000b7b7b7b700ULL, + 0xa90000a9a9a9a900ULL, 0x3100003131313100ULL, 0xd10000d1d1d1d100ULL, + 0x1700001717171700ULL, 0x0400000404040400ULL, 0xd70000d7d7d7d700ULL, + 0x1400001414141400ULL, 0x5800005858585800ULL, 0x3a00003a3a3a3a00ULL, + 0x6100006161616100ULL, 0xde0000dededede00ULL, 0x1b00001b1b1b1b00ULL, + 0x1100001111111100ULL, 0x1c00001c1c1c1c00ULL, 0x3200003232323200ULL, + 0x0f00000f0f0f0f00ULL, 0x9c00009c9c9c9c00ULL, 0x1600001616161600ULL, + 0x5300005353535300ULL, 0x1800001818181800ULL, 0xf20000f2f2f2f200ULL, + 0x2200002222222200ULL, 0xfe0000fefefefe00ULL, 0x4400004444444400ULL, + 0xcf0000cfcfcfcf00ULL, 0xb20000b2b2b2b200ULL, 0xc30000c3c3c3c300ULL, + 0xb50000b5b5b5b500ULL, 0x7a00007a7a7a7a00ULL, 0x9100009191919100ULL, + 0x2400002424242400ULL, 0x0800000808080800ULL, 0xe80000e8e8e8e800ULL, + 0xa80000a8a8a8a800ULL, 0x6000006060606000ULL, 0xfc0000fcfcfcfc00ULL, + 0x6900006969696900ULL, 0x5000005050505000ULL, 0xaa0000aaaaaaaa00ULL, + 0xd00000d0d0d0d000ULL, 0xa00000a0a0a0a000ULL, 0x7d00007d7d7d7d00ULL, + 0xa10000a1a1a1a100ULL, 0x8900008989898900ULL, 0x6200006262626200ULL, + 0x9700009797979700ULL, 0x5400005454545400ULL, 0x5b00005b5b5b5b00ULL, + 0x1e00001e1e1e1e00ULL, 0x9500009595959500ULL, 0xe00000e0e0e0e000ULL, + 0xff0000ffffffff00ULL, 0x6400006464646400ULL, 0xd20000d2d2d2d200ULL, + 0x1000001010101000ULL, 0xc40000c4c4c4c400ULL, 0x0000000000000000ULL, + 0x4800004848484800ULL, 0xa30000a3a3a3a300ULL, 0xf70000f7f7f7f700ULL, + 0x7500007575757500ULL, 0xdb0000dbdbdbdb00ULL, 0x8a00008a8a8a8a00ULL, + 0x0300000303030300ULL, 0xe60000e6e6e6e600ULL, 0xda0000dadadada00ULL, + 0x0900000909090900ULL, 0x3f00003f3f3f3f00ULL, 0xdd0000dddddddd00ULL, + 0x9400009494949400ULL, 0x8700008787878700ULL, 0x5c00005c5c5c5c00ULL, + 0x8300008383838300ULL, 0x0200000202020200ULL, 0xcd0000cdcdcdcd00ULL, + 0x4a00004a4a4a4a00ULL, 0x9000009090909000ULL, 0x3300003333333300ULL, + 0x7300007373737300ULL, 0x6700006767676700ULL, 0xf60000f6f6f6f600ULL, + 0xf30000f3f3f3f300ULL, 0x9d00009d9d9d9d00ULL, 0x7f00007f7f7f7f00ULL, + 0xbf0000bfbfbfbf00ULL, 0xe20000e2e2e2e200ULL, 0x5200005252525200ULL, + 0x9b00009b9b9b9b00ULL, 0xd80000d8d8d8d800ULL, 0x2600002626262600ULL, + 0xc80000c8c8c8c800ULL, 0x3700003737373700ULL, 0xc60000c6c6c6c600ULL, + 0x3b00003b3b3b3b00ULL, 0x8100008181818100ULL, 0x9600009696969600ULL, + 0x6f00006f6f6f6f00ULL, 0x4b00004b4b4b4b00ULL, 0x1300001313131300ULL, + 0xbe0000bebebebe00ULL, 0x6300006363636300ULL, 0x2e00002e2e2e2e00ULL, + 0xe90000e9e9e9e900ULL, 0x7900007979797900ULL, 0xa70000a7a7a7a700ULL, + 0x8c00008c8c8c8c00ULL, 0x9f00009f9f9f9f00ULL, 0x6e00006e6e6e6e00ULL, + 0xbc0000bcbcbcbc00ULL, 0x8e00008e8e8e8e00ULL, 0x2900002929292900ULL, + 0xf50000f5f5f5f500ULL, 0xf90000f9f9f9f900ULL, 0xb60000b6b6b6b600ULL, + 0x2f00002f2f2f2f00ULL, 0xfd0000fdfdfdfd00ULL, 0xb40000b4b4b4b400ULL, + 0x5900005959595900ULL, 0x7800007878787800ULL, 0x9800009898989800ULL, + 0x0600000606060600ULL, 0x6a00006a6a6a6a00ULL, 0xe70000e7e7e7e700ULL, + 0x4600004646464600ULL, 0x7100007171717100ULL, 0xba0000babababa00ULL, + 0xd40000d4d4d4d400ULL, 0x2500002525252500ULL, 0xab0000abababab00ULL, + 0x4200004242424200ULL, 0x8800008888888800ULL, 0xa20000a2a2a2a200ULL, + 0x8d00008d8d8d8d00ULL, 0xfa0000fafafafa00ULL, 0x7200007272727200ULL, + 0x0700000707070700ULL, 0xb90000b9b9b9b900ULL, 0x5500005555555500ULL, + 0xf80000f8f8f8f800ULL, 0xee0000eeeeeeee00ULL, 0xac0000acacacac00ULL, + 0x0a00000a0a0a0a00ULL, 0x3600003636363600ULL, 0x4900004949494900ULL, + 0x2a00002a2a2a2a00ULL, 0x6800006868686800ULL, 0x3c00003c3c3c3c00ULL, + 0x3800003838383800ULL, 0xf10000f1f1f1f100ULL, 0xa40000a4a4a4a400ULL, + 0x4000004040404000ULL, 0x2800002828282800ULL, 0xd30000d3d3d3d300ULL, + 0x7b00007b7b7b7b00ULL, 0xbb0000bbbbbbbb00ULL, 0xc90000c9c9c9c900ULL, + 0x4300004343434300ULL, 0xc10000c1c1c1c100ULL, 0x1500001515151500ULL, + 0xe30000e3e3e3e300ULL, 0xad0000adadadad00ULL, 0xf40000f4f4f4f400ULL, + 0x7700007777777700ULL, 0xc70000c7c7c7c700ULL, 0x8000008080808000ULL, + 0x9e00009e9e9e9e00ULL, }; 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, + 0xe0e0000000e0e0e0ULL, 0x0505000000050505ULL, 0x5858000000585858ULL, + 0xd9d9000000d9d9d9ULL, 0x6767000000676767ULL, 0x4e4e0000004e4e4eULL, + 0x8181000000818181ULL, 0xcbcb000000cbcbcbULL, 0xc9c9000000c9c9c9ULL, + 0x0b0b0000000b0b0bULL, 0xaeae000000aeaeaeULL, 0x6a6a0000006a6a6aULL, + 0xd5d5000000d5d5d5ULL, 0x1818000000181818ULL, 0x5d5d0000005d5d5dULL, + 0x8282000000828282ULL, 0x4646000000464646ULL, 0xdfdf000000dfdfdfULL, + 0xd6d6000000d6d6d6ULL, 0x2727000000272727ULL, 0x8a8a0000008a8a8aULL, + 0x3232000000323232ULL, 0x4b4b0000004b4b4bULL, 0x4242000000424242ULL, + 0xdbdb000000dbdbdbULL, 0x1c1c0000001c1c1cULL, 0x9e9e0000009e9e9eULL, + 0x9c9c0000009c9c9cULL, 0x3a3a0000003a3a3aULL, 0xcaca000000cacacaULL, + 0x2525000000252525ULL, 0x7b7b0000007b7b7bULL, 0x0d0d0000000d0d0dULL, + 0x7171000000717171ULL, 0x5f5f0000005f5f5fULL, 0x1f1f0000001f1f1fULL, + 0xf8f8000000f8f8f8ULL, 0xd7d7000000d7d7d7ULL, 0x3e3e0000003e3e3eULL, + 0x9d9d0000009d9d9dULL, 0x7c7c0000007c7c7cULL, 0x6060000000606060ULL, + 0xb9b9000000b9b9b9ULL, 0xbebe000000bebebeULL, 0xbcbc000000bcbcbcULL, + 0x8b8b0000008b8b8bULL, 0x1616000000161616ULL, 0x3434000000343434ULL, + 0x4d4d0000004d4d4dULL, 0xc3c3000000c3c3c3ULL, 0x7272000000727272ULL, + 0x9595000000959595ULL, 0xabab000000abababULL, 0x8e8e0000008e8e8eULL, + 0xbaba000000bababaULL, 0x7a7a0000007a7a7aULL, 0xb3b3000000b3b3b3ULL, + 0x0202000000020202ULL, 0xb4b4000000b4b4b4ULL, 0xadad000000adadadULL, + 0xa2a2000000a2a2a2ULL, 0xacac000000acacacULL, 0xd8d8000000d8d8d8ULL, + 0x9a9a0000009a9a9aULL, 0x1717000000171717ULL, 0x1a1a0000001a1a1aULL, + 0x3535000000353535ULL, 0xcccc000000ccccccULL, 0xf7f7000000f7f7f7ULL, + 0x9999000000999999ULL, 0x6161000000616161ULL, 0x5a5a0000005a5a5aULL, + 0xe8e8000000e8e8e8ULL, 0x2424000000242424ULL, 0x5656000000565656ULL, + 0x4040000000404040ULL, 0xe1e1000000e1e1e1ULL, 0x6363000000636363ULL, + 0x0909000000090909ULL, 0x3333000000333333ULL, 0xbfbf000000bfbfbfULL, + 0x9898000000989898ULL, 0x9797000000979797ULL, 0x8585000000858585ULL, + 0x6868000000686868ULL, 0xfcfc000000fcfcfcULL, 0xecec000000ecececULL, + 0x0a0a0000000a0a0aULL, 0xdada000000dadadaULL, 0x6f6f0000006f6f6fULL, + 0x5353000000535353ULL, 0x6262000000626262ULL, 0xa3a3000000a3a3a3ULL, + 0x2e2e0000002e2e2eULL, 0x0808000000080808ULL, 0xafaf000000afafafULL, + 0x2828000000282828ULL, 0xb0b0000000b0b0b0ULL, 0x7474000000747474ULL, + 0xc2c2000000c2c2c2ULL, 0xbdbd000000bdbdbdULL, 0x3636000000363636ULL, + 0x2222000000222222ULL, 0x3838000000383838ULL, 0x6464000000646464ULL, + 0x1e1e0000001e1e1eULL, 0x3939000000393939ULL, 0x2c2c0000002c2c2cULL, + 0xa6a6000000a6a6a6ULL, 0x3030000000303030ULL, 0xe5e5000000e5e5e5ULL, + 0x4444000000444444ULL, 0xfdfd000000fdfdfdULL, 0x8888000000888888ULL, + 0x9f9f0000009f9f9fULL, 0x6565000000656565ULL, 0x8787000000878787ULL, + 0x6b6b0000006b6b6bULL, 0xf4f4000000f4f4f4ULL, 0x2323000000232323ULL, + 0x4848000000484848ULL, 0x1010000000101010ULL, 0xd1d1000000d1d1d1ULL, + 0x5151000000515151ULL, 0xc0c0000000c0c0c0ULL, 0xf9f9000000f9f9f9ULL, + 0xd2d2000000d2d2d2ULL, 0xa0a0000000a0a0a0ULL, 0x5555000000555555ULL, + 0xa1a1000000a1a1a1ULL, 0x4141000000414141ULL, 0xfafa000000fafafaULL, + 0x4343000000434343ULL, 0x1313000000131313ULL, 0xc4c4000000c4c4c4ULL, + 0x2f2f0000002f2f2fULL, 0xa8a8000000a8a8a8ULL, 0xb6b6000000b6b6b6ULL, + 0x3c3c0000003c3c3cULL, 0x2b2b0000002b2b2bULL, 0xc1c1000000c1c1c1ULL, + 0xffff000000ffffffULL, 0xc8c8000000c8c8c8ULL, 0xa5a5000000a5a5a5ULL, + 0x2020000000202020ULL, 0x8989000000898989ULL, 0x0000000000000000ULL, + 0x9090000000909090ULL, 0x4747000000474747ULL, 0xefef000000efefefULL, + 0xeaea000000eaeaeaULL, 0xb7b7000000b7b7b7ULL, 0x1515000000151515ULL, + 0x0606000000060606ULL, 0xcdcd000000cdcdcdULL, 0xb5b5000000b5b5b5ULL, + 0x1212000000121212ULL, 0x7e7e0000007e7e7eULL, 0xbbbb000000bbbbbbULL, + 0x2929000000292929ULL, 0x0f0f0000000f0f0fULL, 0xb8b8000000b8b8b8ULL, + 0x0707000000070707ULL, 0x0404000000040404ULL, 0x9b9b0000009b9b9bULL, + 0x9494000000949494ULL, 0x2121000000212121ULL, 0x6666000000666666ULL, + 0xe6e6000000e6e6e6ULL, 0xcece000000cececeULL, 0xeded000000edededULL, + 0xe7e7000000e7e7e7ULL, 0x3b3b0000003b3b3bULL, 0xfefe000000fefefeULL, + 0x7f7f0000007f7f7fULL, 0xc5c5000000c5c5c5ULL, 0xa4a4000000a4a4a4ULL, + 0x3737000000373737ULL, 0xb1b1000000b1b1b1ULL, 0x4c4c0000004c4c4cULL, + 0x9191000000919191ULL, 0x6e6e0000006e6e6eULL, 0x8d8d0000008d8d8dULL, + 0x7676000000767676ULL, 0x0303000000030303ULL, 0x2d2d0000002d2d2dULL, + 0xdede000000dededeULL, 0x9696000000969696ULL, 0x2626000000262626ULL, + 0x7d7d0000007d7d7dULL, 0xc6c6000000c6c6c6ULL, 0x5c5c0000005c5c5cULL, + 0xd3d3000000d3d3d3ULL, 0xf2f2000000f2f2f2ULL, 0x4f4f0000004f4f4fULL, + 0x1919000000191919ULL, 0x3f3f0000003f3f3fULL, 0xdcdc000000dcdcdcULL, + 0x7979000000797979ULL, 0x1d1d0000001d1d1dULL, 0x5252000000525252ULL, + 0xebeb000000ebebebULL, 0xf3f3000000f3f3f3ULL, 0x6d6d0000006d6d6dULL, + 0x5e5e0000005e5e5eULL, 0xfbfb000000fbfbfbULL, 0x6969000000696969ULL, + 0xb2b2000000b2b2b2ULL, 0xf0f0000000f0f0f0ULL, 0x3131000000313131ULL, + 0x0c0c0000000c0c0cULL, 0xd4d4000000d4d4d4ULL, 0xcfcf000000cfcfcfULL, + 0x8c8c0000008c8c8cULL, 0xe2e2000000e2e2e2ULL, 0x7575000000757575ULL, + 0xa9a9000000a9a9a9ULL, 0x4a4a0000004a4a4aULL, 0x5757000000575757ULL, + 0x8484000000848484ULL, 0x1111000000111111ULL, 0x4545000000454545ULL, + 0x1b1b0000001b1b1bULL, 0xf5f5000000f5f5f5ULL, 0xe4e4000000e4e4e4ULL, + 0x0e0e0000000e0e0eULL, 0x7373000000737373ULL, 0xaaaa000000aaaaaaULL, + 0xf1f1000000f1f1f1ULL, 0xdddd000000ddddddULL, 0x5959000000595959ULL, + 0x1414000000141414ULL, 0x6c6c0000006c6c6cULL, 0x9292000000929292ULL, + 0x5454000000545454ULL, 0xd0d0000000d0d0d0ULL, 0x7878000000787878ULL, + 0x7070000000707070ULL, 0xe3e3000000e3e3e3ULL, 0x4949000000494949ULL, + 0x8080000000808080ULL, 0x5050000000505050ULL, 0xa7a7000000a7a7a7ULL, + 0xf6f6000000f6f6f6ULL, 0x7777000000777777ULL, 0x9393000000939393ULL, + 0x8686000000868686ULL, 0x8383000000838383ULL, 0x2a2a0000002a2a2aULL, + 0xc7c7000000c7c7c7ULL, 0x5b5b0000005b5b5bULL, 0xe9e9000000e9e9e9ULL, + 0xeeee000000eeeeeeULL, 0x8f8f0000008f8f8fULL, 0x0101000000010101ULL, + 0x3d3d0000003d3d3dULL, }; 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, + 0x0038380038003838ULL, 0x0041410041004141ULL, 0x0016160016001616ULL, + 0x0076760076007676ULL, 0x00d9d900d900d9d9ULL, 0x0093930093009393ULL, + 0x0060600060006060ULL, 0x00f2f200f200f2f2ULL, 0x0072720072007272ULL, + 0x00c2c200c200c2c2ULL, 0x00abab00ab00ababULL, 0x009a9a009a009a9aULL, + 0x0075750075007575ULL, 0x0006060006000606ULL, 0x0057570057005757ULL, + 0x00a0a000a000a0a0ULL, 0x0091910091009191ULL, 0x00f7f700f700f7f7ULL, + 0x00b5b500b500b5b5ULL, 0x00c9c900c900c9c9ULL, 0x00a2a200a200a2a2ULL, + 0x008c8c008c008c8cULL, 0x00d2d200d200d2d2ULL, 0x0090900090009090ULL, + 0x00f6f600f600f6f6ULL, 0x0007070007000707ULL, 0x00a7a700a700a7a7ULL, + 0x0027270027002727ULL, 0x008e8e008e008e8eULL, 0x00b2b200b200b2b2ULL, + 0x0049490049004949ULL, 0x00dede00de00dedeULL, 0x0043430043004343ULL, + 0x005c5c005c005c5cULL, 0x00d7d700d700d7d7ULL, 0x00c7c700c700c7c7ULL, + 0x003e3e003e003e3eULL, 0x00f5f500f500f5f5ULL, 0x008f8f008f008f8fULL, + 0x0067670067006767ULL, 0x001f1f001f001f1fULL, 0x0018180018001818ULL, + 0x006e6e006e006e6eULL, 0x00afaf00af00afafULL, 0x002f2f002f002f2fULL, + 0x00e2e200e200e2e2ULL, 0x0085850085008585ULL, 0x000d0d000d000d0dULL, + 0x0053530053005353ULL, 0x00f0f000f000f0f0ULL, 0x009c9c009c009c9cULL, + 0x0065650065006565ULL, 0x00eaea00ea00eaeaULL, 0x00a3a300a300a3a3ULL, + 0x00aeae00ae00aeaeULL, 0x009e9e009e009e9eULL, 0x00ecec00ec00ececULL, + 0x0080800080008080ULL, 0x002d2d002d002d2dULL, 0x006b6b006b006b6bULL, + 0x00a8a800a800a8a8ULL, 0x002b2b002b002b2bULL, 0x0036360036003636ULL, + 0x00a6a600a600a6a6ULL, 0x00c5c500c500c5c5ULL, 0x0086860086008686ULL, + 0x004d4d004d004d4dULL, 0x0033330033003333ULL, 0x00fdfd00fd00fdfdULL, + 0x0066660066006666ULL, 0x0058580058005858ULL, 0x0096960096009696ULL, + 0x003a3a003a003a3aULL, 0x0009090009000909ULL, 0x0095950095009595ULL, + 0x0010100010001010ULL, 0x0078780078007878ULL, 0x00d8d800d800d8d8ULL, + 0x0042420042004242ULL, 0x00cccc00cc00ccccULL, 0x00efef00ef00efefULL, + 0x0026260026002626ULL, 0x00e5e500e500e5e5ULL, 0x0061610061006161ULL, + 0x001a1a001a001a1aULL, 0x003f3f003f003f3fULL, 0x003b3b003b003b3bULL, + 0x0082820082008282ULL, 0x00b6b600b600b6b6ULL, 0x00dbdb00db00dbdbULL, + 0x00d4d400d400d4d4ULL, 0x0098980098009898ULL, 0x00e8e800e800e8e8ULL, + 0x008b8b008b008b8bULL, 0x0002020002000202ULL, 0x00ebeb00eb00ebebULL, + 0x000a0a000a000a0aULL, 0x002c2c002c002c2cULL, 0x001d1d001d001d1dULL, + 0x00b0b000b000b0b0ULL, 0x006f6f006f006f6fULL, 0x008d8d008d008d8dULL, + 0x0088880088008888ULL, 0x000e0e000e000e0eULL, 0x0019190019001919ULL, + 0x0087870087008787ULL, 0x004e4e004e004e4eULL, 0x000b0b000b000b0bULL, + 0x00a9a900a900a9a9ULL, 0x000c0c000c000c0cULL, 0x0079790079007979ULL, + 0x0011110011001111ULL, 0x007f7f007f007f7fULL, 0x0022220022002222ULL, + 0x00e7e700e700e7e7ULL, 0x0059590059005959ULL, 0x00e1e100e100e1e1ULL, + 0x00dada00da00dadaULL, 0x003d3d003d003d3dULL, 0x00c8c800c800c8c8ULL, + 0x0012120012001212ULL, 0x0004040004000404ULL, 0x0074740074007474ULL, + 0x0054540054005454ULL, 0x0030300030003030ULL, 0x007e7e007e007e7eULL, + 0x00b4b400b400b4b4ULL, 0x0028280028002828ULL, 0x0055550055005555ULL, + 0x0068680068006868ULL, 0x0050500050005050ULL, 0x00bebe00be00bebeULL, + 0x00d0d000d000d0d0ULL, 0x00c4c400c400c4c4ULL, 0x0031310031003131ULL, + 0x00cbcb00cb00cbcbULL, 0x002a2a002a002a2aULL, 0x00adad00ad00adadULL, + 0x000f0f000f000f0fULL, 0x00caca00ca00cacaULL, 0x0070700070007070ULL, + 0x00ffff00ff00ffffULL, 0x0032320032003232ULL, 0x0069690069006969ULL, + 0x0008080008000808ULL, 0x0062620062006262ULL, 0x0000000000000000ULL, + 0x0024240024002424ULL, 0x00d1d100d100d1d1ULL, 0x00fbfb00fb00fbfbULL, + 0x00baba00ba00babaULL, 0x00eded00ed00ededULL, 0x0045450045004545ULL, + 0x0081810081008181ULL, 0x0073730073007373ULL, 0x006d6d006d006d6dULL, + 0x0084840084008484ULL, 0x009f9f009f009f9fULL, 0x00eeee00ee00eeeeULL, + 0x004a4a004a004a4aULL, 0x00c3c300c300c3c3ULL, 0x002e2e002e002e2eULL, + 0x00c1c100c100c1c1ULL, 0x0001010001000101ULL, 0x00e6e600e600e6e6ULL, + 0x0025250025002525ULL, 0x0048480048004848ULL, 0x0099990099009999ULL, + 0x00b9b900b900b9b9ULL, 0x00b3b300b300b3b3ULL, 0x007b7b007b007b7bULL, + 0x00f9f900f900f9f9ULL, 0x00cece00ce00ceceULL, 0x00bfbf00bf00bfbfULL, + 0x00dfdf00df00dfdfULL, 0x0071710071007171ULL, 0x0029290029002929ULL, + 0x00cdcd00cd00cdcdULL, 0x006c6c006c006c6cULL, 0x0013130013001313ULL, + 0x0064640064006464ULL, 0x009b9b009b009b9bULL, 0x0063630063006363ULL, + 0x009d9d009d009d9dULL, 0x00c0c000c000c0c0ULL, 0x004b4b004b004b4bULL, + 0x00b7b700b700b7b7ULL, 0x00a5a500a500a5a5ULL, 0x0089890089008989ULL, + 0x005f5f005f005f5fULL, 0x00b1b100b100b1b1ULL, 0x0017170017001717ULL, + 0x00f4f400f400f4f4ULL, 0x00bcbc00bc00bcbcULL, 0x00d3d300d300d3d3ULL, + 0x0046460046004646ULL, 0x00cfcf00cf00cfcfULL, 0x0037370037003737ULL, + 0x005e5e005e005e5eULL, 0x0047470047004747ULL, 0x0094940094009494ULL, + 0x00fafa00fa00fafaULL, 0x00fcfc00fc00fcfcULL, 0x005b5b005b005b5bULL, + 0x0097970097009797ULL, 0x00fefe00fe00fefeULL, 0x005a5a005a005a5aULL, + 0x00acac00ac00acacULL, 0x003c3c003c003c3cULL, 0x004c4c004c004c4cULL, + 0x0003030003000303ULL, 0x0035350035003535ULL, 0x00f3f300f300f3f3ULL, + 0x0023230023002323ULL, 0x00b8b800b800b8b8ULL, 0x005d5d005d005d5dULL, + 0x006a6a006a006a6aULL, 0x0092920092009292ULL, 0x00d5d500d500d5d5ULL, + 0x0021210021002121ULL, 0x0044440044004444ULL, 0x0051510051005151ULL, + 0x00c6c600c600c6c6ULL, 0x007d7d007d007d7dULL, 0x0039390039003939ULL, + 0x0083830083008383ULL, 0x00dcdc00dc00dcdcULL, 0x00aaaa00aa00aaaaULL, + 0x007c7c007c007c7cULL, 0x0077770077007777ULL, 0x0056560056005656ULL, + 0x0005050005000505ULL, 0x001b1b001b001b1bULL, 0x00a4a400a400a4a4ULL, + 0x0015150015001515ULL, 0x0034340034003434ULL, 0x001e1e001e001e1eULL, + 0x001c1c001c001c1cULL, 0x00f8f800f800f8f8ULL, 0x0052520052005252ULL, + 0x0020200020002020ULL, 0x0014140014001414ULL, 0x00e9e900e900e9e9ULL, + 0x00bdbd00bd00bdbdULL, 0x00dddd00dd00ddddULL, 0x00e4e400e400e4e4ULL, + 0x00a1a100a100a1a1ULL, 0x00e0e000e000e0e0ULL, 0x008a8a008a008a8aULL, + 0x00f1f100f100f1f1ULL, 0x00d6d600d600d6d6ULL, 0x007a7a007a007a7aULL, + 0x00bbbb00bb00bbbbULL, 0x00e3e300e300e3e3ULL, 0x0040400040004040ULL, + 0x004f4f004f004f4fULL, }; 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, + 0x0000707070700070ULL, 0x00002c2c2c2c002cULL, 0x0000b3b3b3b300b3ULL, + 0x0000c0c0c0c000c0ULL, 0x0000e4e4e4e400e4ULL, 0x0000575757570057ULL, + 0x0000eaeaeaea00eaULL, 0x0000aeaeaeae00aeULL, 0x0000232323230023ULL, + 0x00006b6b6b6b006bULL, 0x0000454545450045ULL, 0x0000a5a5a5a500a5ULL, + 0x0000edededed00edULL, 0x00004f4f4f4f004fULL, 0x00001d1d1d1d001dULL, + 0x0000929292920092ULL, 0x0000868686860086ULL, 0x0000afafafaf00afULL, + 0x00007c7c7c7c007cULL, 0x00001f1f1f1f001fULL, 0x00003e3e3e3e003eULL, + 0x0000dcdcdcdc00dcULL, 0x00005e5e5e5e005eULL, 0x00000b0b0b0b000bULL, + 0x0000a6a6a6a600a6ULL, 0x0000393939390039ULL, 0x0000d5d5d5d500d5ULL, + 0x00005d5d5d5d005dULL, 0x0000d9d9d9d900d9ULL, 0x00005a5a5a5a005aULL, + 0x0000515151510051ULL, 0x00006c6c6c6c006cULL, 0x00008b8b8b8b008bULL, + 0x00009a9a9a9a009aULL, 0x0000fbfbfbfb00fbULL, 0x0000b0b0b0b000b0ULL, + 0x0000747474740074ULL, 0x00002b2b2b2b002bULL, 0x0000f0f0f0f000f0ULL, + 0x0000848484840084ULL, 0x0000dfdfdfdf00dfULL, 0x0000cbcbcbcb00cbULL, + 0x0000343434340034ULL, 0x0000767676760076ULL, 0x00006d6d6d6d006dULL, + 0x0000a9a9a9a900a9ULL, 0x0000d1d1d1d100d1ULL, 0x0000040404040004ULL, + 0x0000141414140014ULL, 0x00003a3a3a3a003aULL, 0x0000dededede00deULL, + 0x0000111111110011ULL, 0x0000323232320032ULL, 0x00009c9c9c9c009cULL, + 0x0000535353530053ULL, 0x0000f2f2f2f200f2ULL, 0x0000fefefefe00feULL, + 0x0000cfcfcfcf00cfULL, 0x0000c3c3c3c300c3ULL, 0x00007a7a7a7a007aULL, + 0x0000242424240024ULL, 0x0000e8e8e8e800e8ULL, 0x0000606060600060ULL, + 0x0000696969690069ULL, 0x0000aaaaaaaa00aaULL, 0x0000a0a0a0a000a0ULL, + 0x0000a1a1a1a100a1ULL, 0x0000626262620062ULL, 0x0000545454540054ULL, + 0x00001e1e1e1e001eULL, 0x0000e0e0e0e000e0ULL, 0x0000646464640064ULL, + 0x0000101010100010ULL, 0x0000000000000000ULL, 0x0000a3a3a3a300a3ULL, + 0x0000757575750075ULL, 0x00008a8a8a8a008aULL, 0x0000e6e6e6e600e6ULL, + 0x0000090909090009ULL, 0x0000dddddddd00ddULL, 0x0000878787870087ULL, + 0x0000838383830083ULL, 0x0000cdcdcdcd00cdULL, 0x0000909090900090ULL, + 0x0000737373730073ULL, 0x0000f6f6f6f600f6ULL, 0x00009d9d9d9d009dULL, + 0x0000bfbfbfbf00bfULL, 0x0000525252520052ULL, 0x0000d8d8d8d800d8ULL, + 0x0000c8c8c8c800c8ULL, 0x0000c6c6c6c600c6ULL, 0x0000818181810081ULL, + 0x00006f6f6f6f006fULL, 0x0000131313130013ULL, 0x0000636363630063ULL, + 0x0000e9e9e9e900e9ULL, 0x0000a7a7a7a700a7ULL, 0x00009f9f9f9f009fULL, + 0x0000bcbcbcbc00bcULL, 0x0000292929290029ULL, 0x0000f9f9f9f900f9ULL, + 0x00002f2f2f2f002fULL, 0x0000b4b4b4b400b4ULL, 0x0000787878780078ULL, + 0x0000060606060006ULL, 0x0000e7e7e7e700e7ULL, 0x0000717171710071ULL, + 0x0000d4d4d4d400d4ULL, 0x0000abababab00abULL, 0x0000888888880088ULL, + 0x00008d8d8d8d008dULL, 0x0000727272720072ULL, 0x0000b9b9b9b900b9ULL, + 0x0000f8f8f8f800f8ULL, 0x0000acacacac00acULL, 0x0000363636360036ULL, + 0x00002a2a2a2a002aULL, 0x00003c3c3c3c003cULL, 0x0000f1f1f1f100f1ULL, + 0x0000404040400040ULL, 0x0000d3d3d3d300d3ULL, 0x0000bbbbbbbb00bbULL, + 0x0000434343430043ULL, 0x0000151515150015ULL, 0x0000adadadad00adULL, + 0x0000777777770077ULL, 0x0000808080800080ULL, 0x0000828282820082ULL, + 0x0000ecececec00ecULL, 0x0000272727270027ULL, 0x0000e5e5e5e500e5ULL, + 0x0000858585850085ULL, 0x0000353535350035ULL, 0x00000c0c0c0c000cULL, + 0x0000414141410041ULL, 0x0000efefefef00efULL, 0x0000939393930093ULL, + 0x0000191919190019ULL, 0x0000212121210021ULL, 0x00000e0e0e0e000eULL, + 0x00004e4e4e4e004eULL, 0x0000656565650065ULL, 0x0000bdbdbdbd00bdULL, + 0x0000b8b8b8b800b8ULL, 0x00008f8f8f8f008fULL, 0x0000ebebebeb00ebULL, + 0x0000cececece00ceULL, 0x0000303030300030ULL, 0x00005f5f5f5f005fULL, + 0x0000c5c5c5c500c5ULL, 0x00001a1a1a1a001aULL, 0x0000e1e1e1e100e1ULL, + 0x0000cacacaca00caULL, 0x0000474747470047ULL, 0x00003d3d3d3d003dULL, + 0x0000010101010001ULL, 0x0000d6d6d6d600d6ULL, 0x0000565656560056ULL, + 0x00004d4d4d4d004dULL, 0x00000d0d0d0d000dULL, 0x0000666666660066ULL, + 0x0000cccccccc00ccULL, 0x00002d2d2d2d002dULL, 0x0000121212120012ULL, + 0x0000202020200020ULL, 0x0000b1b1b1b100b1ULL, 0x0000999999990099ULL, + 0x00004c4c4c4c004cULL, 0x0000c2c2c2c200c2ULL, 0x00007e7e7e7e007eULL, + 0x0000050505050005ULL, 0x0000b7b7b7b700b7ULL, 0x0000313131310031ULL, + 0x0000171717170017ULL, 0x0000d7d7d7d700d7ULL, 0x0000585858580058ULL, + 0x0000616161610061ULL, 0x00001b1b1b1b001bULL, 0x00001c1c1c1c001cULL, + 0x00000f0f0f0f000fULL, 0x0000161616160016ULL, 0x0000181818180018ULL, + 0x0000222222220022ULL, 0x0000444444440044ULL, 0x0000b2b2b2b200b2ULL, + 0x0000b5b5b5b500b5ULL, 0x0000919191910091ULL, 0x0000080808080008ULL, + 0x0000a8a8a8a800a8ULL, 0x0000fcfcfcfc00fcULL, 0x0000505050500050ULL, + 0x0000d0d0d0d000d0ULL, 0x00007d7d7d7d007dULL, 0x0000898989890089ULL, + 0x0000979797970097ULL, 0x00005b5b5b5b005bULL, 0x0000959595950095ULL, + 0x0000ffffffff00ffULL, 0x0000d2d2d2d200d2ULL, 0x0000c4c4c4c400c4ULL, + 0x0000484848480048ULL, 0x0000f7f7f7f700f7ULL, 0x0000dbdbdbdb00dbULL, + 0x0000030303030003ULL, 0x0000dadadada00daULL, 0x00003f3f3f3f003fULL, + 0x0000949494940094ULL, 0x00005c5c5c5c005cULL, 0x0000020202020002ULL, + 0x00004a4a4a4a004aULL, 0x0000333333330033ULL, 0x0000676767670067ULL, + 0x0000f3f3f3f300f3ULL, 0x00007f7f7f7f007fULL, 0x0000e2e2e2e200e2ULL, + 0x00009b9b9b9b009bULL, 0x0000262626260026ULL, 0x0000373737370037ULL, + 0x00003b3b3b3b003bULL, 0x0000969696960096ULL, 0x00004b4b4b4b004bULL, + 0x0000bebebebe00beULL, 0x00002e2e2e2e002eULL, 0x0000797979790079ULL, + 0x00008c8c8c8c008cULL, 0x00006e6e6e6e006eULL, 0x00008e8e8e8e008eULL, + 0x0000f5f5f5f500f5ULL, 0x0000b6b6b6b600b6ULL, 0x0000fdfdfdfd00fdULL, + 0x0000595959590059ULL, 0x0000989898980098ULL, 0x00006a6a6a6a006aULL, + 0x0000464646460046ULL, 0x0000babababa00baULL, 0x0000252525250025ULL, + 0x0000424242420042ULL, 0x0000a2a2a2a200a2ULL, 0x0000fafafafa00faULL, + 0x0000070707070007ULL, 0x0000555555550055ULL, 0x0000eeeeeeee00eeULL, + 0x00000a0a0a0a000aULL, 0x0000494949490049ULL, 0x0000686868680068ULL, + 0x0000383838380038ULL, 0x0000a4a4a4a400a4ULL, 0x0000282828280028ULL, + 0x00007b7b7b7b007bULL, 0x0000c9c9c9c900c9ULL, 0x0000c1c1c1c100c1ULL, + 0x0000e3e3e3e300e3ULL, 0x0000f4f4f4f400f4ULL, 0x0000c7c7c7c700c7ULL, + 0x00009e9e9e9e009eULL, }; 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, + 0x00e0e0e000e0e0e0ULL, 0x0005050500050505ULL, 0x0058585800585858ULL, + 0x00d9d9d900d9d9d9ULL, 0x0067676700676767ULL, 0x004e4e4e004e4e4eULL, + 0x0081818100818181ULL, 0x00cbcbcb00cbcbcbULL, 0x00c9c9c900c9c9c9ULL, + 0x000b0b0b000b0b0bULL, 0x00aeaeae00aeaeaeULL, 0x006a6a6a006a6a6aULL, + 0x00d5d5d500d5d5d5ULL, 0x0018181800181818ULL, 0x005d5d5d005d5d5dULL, + 0x0082828200828282ULL, 0x0046464600464646ULL, 0x00dfdfdf00dfdfdfULL, + 0x00d6d6d600d6d6d6ULL, 0x0027272700272727ULL, 0x008a8a8a008a8a8aULL, + 0x0032323200323232ULL, 0x004b4b4b004b4b4bULL, 0x0042424200424242ULL, + 0x00dbdbdb00dbdbdbULL, 0x001c1c1c001c1c1cULL, 0x009e9e9e009e9e9eULL, + 0x009c9c9c009c9c9cULL, 0x003a3a3a003a3a3aULL, 0x00cacaca00cacacaULL, + 0x0025252500252525ULL, 0x007b7b7b007b7b7bULL, 0x000d0d0d000d0d0dULL, + 0x0071717100717171ULL, 0x005f5f5f005f5f5fULL, 0x001f1f1f001f1f1fULL, + 0x00f8f8f800f8f8f8ULL, 0x00d7d7d700d7d7d7ULL, 0x003e3e3e003e3e3eULL, + 0x009d9d9d009d9d9dULL, 0x007c7c7c007c7c7cULL, 0x0060606000606060ULL, + 0x00b9b9b900b9b9b9ULL, 0x00bebebe00bebebeULL, 0x00bcbcbc00bcbcbcULL, + 0x008b8b8b008b8b8bULL, 0x0016161600161616ULL, 0x0034343400343434ULL, + 0x004d4d4d004d4d4dULL, 0x00c3c3c300c3c3c3ULL, 0x0072727200727272ULL, + 0x0095959500959595ULL, 0x00ababab00abababULL, 0x008e8e8e008e8e8eULL, + 0x00bababa00bababaULL, 0x007a7a7a007a7a7aULL, 0x00b3b3b300b3b3b3ULL, + 0x0002020200020202ULL, 0x00b4b4b400b4b4b4ULL, 0x00adadad00adadadULL, + 0x00a2a2a200a2a2a2ULL, 0x00acacac00acacacULL, 0x00d8d8d800d8d8d8ULL, + 0x009a9a9a009a9a9aULL, 0x0017171700171717ULL, 0x001a1a1a001a1a1aULL, + 0x0035353500353535ULL, 0x00cccccc00ccccccULL, 0x00f7f7f700f7f7f7ULL, + 0x0099999900999999ULL, 0x0061616100616161ULL, 0x005a5a5a005a5a5aULL, + 0x00e8e8e800e8e8e8ULL, 0x0024242400242424ULL, 0x0056565600565656ULL, + 0x0040404000404040ULL, 0x00e1e1e100e1e1e1ULL, 0x0063636300636363ULL, + 0x0009090900090909ULL, 0x0033333300333333ULL, 0x00bfbfbf00bfbfbfULL, + 0x0098989800989898ULL, 0x0097979700979797ULL, 0x0085858500858585ULL, + 0x0068686800686868ULL, 0x00fcfcfc00fcfcfcULL, 0x00ececec00ecececULL, + 0x000a0a0a000a0a0aULL, 0x00dadada00dadadaULL, 0x006f6f6f006f6f6fULL, + 0x0053535300535353ULL, 0x0062626200626262ULL, 0x00a3a3a300a3a3a3ULL, + 0x002e2e2e002e2e2eULL, 0x0008080800080808ULL, 0x00afafaf00afafafULL, + 0x0028282800282828ULL, 0x00b0b0b000b0b0b0ULL, 0x0074747400747474ULL, + 0x00c2c2c200c2c2c2ULL, 0x00bdbdbd00bdbdbdULL, 0x0036363600363636ULL, + 0x0022222200222222ULL, 0x0038383800383838ULL, 0x0064646400646464ULL, + 0x001e1e1e001e1e1eULL, 0x0039393900393939ULL, 0x002c2c2c002c2c2cULL, + 0x00a6a6a600a6a6a6ULL, 0x0030303000303030ULL, 0x00e5e5e500e5e5e5ULL, + 0x0044444400444444ULL, 0x00fdfdfd00fdfdfdULL, 0x0088888800888888ULL, + 0x009f9f9f009f9f9fULL, 0x0065656500656565ULL, 0x0087878700878787ULL, + 0x006b6b6b006b6b6bULL, 0x00f4f4f400f4f4f4ULL, 0x0023232300232323ULL, + 0x0048484800484848ULL, 0x0010101000101010ULL, 0x00d1d1d100d1d1d1ULL, + 0x0051515100515151ULL, 0x00c0c0c000c0c0c0ULL, 0x00f9f9f900f9f9f9ULL, + 0x00d2d2d200d2d2d2ULL, 0x00a0a0a000a0a0a0ULL, 0x0055555500555555ULL, + 0x00a1a1a100a1a1a1ULL, 0x0041414100414141ULL, 0x00fafafa00fafafaULL, + 0x0043434300434343ULL, 0x0013131300131313ULL, 0x00c4c4c400c4c4c4ULL, + 0x002f2f2f002f2f2fULL, 0x00a8a8a800a8a8a8ULL, 0x00b6b6b600b6b6b6ULL, + 0x003c3c3c003c3c3cULL, 0x002b2b2b002b2b2bULL, 0x00c1c1c100c1c1c1ULL, + 0x00ffffff00ffffffULL, 0x00c8c8c800c8c8c8ULL, 0x00a5a5a500a5a5a5ULL, + 0x0020202000202020ULL, 0x0089898900898989ULL, 0x0000000000000000ULL, + 0x0090909000909090ULL, 0x0047474700474747ULL, 0x00efefef00efefefULL, + 0x00eaeaea00eaeaeaULL, 0x00b7b7b700b7b7b7ULL, 0x0015151500151515ULL, + 0x0006060600060606ULL, 0x00cdcdcd00cdcdcdULL, 0x00b5b5b500b5b5b5ULL, + 0x0012121200121212ULL, 0x007e7e7e007e7e7eULL, 0x00bbbbbb00bbbbbbULL, + 0x0029292900292929ULL, 0x000f0f0f000f0f0fULL, 0x00b8b8b800b8b8b8ULL, + 0x0007070700070707ULL, 0x0004040400040404ULL, 0x009b9b9b009b9b9bULL, + 0x0094949400949494ULL, 0x0021212100212121ULL, 0x0066666600666666ULL, + 0x00e6e6e600e6e6e6ULL, 0x00cecece00cececeULL, 0x00ededed00edededULL, + 0x00e7e7e700e7e7e7ULL, 0x003b3b3b003b3b3bULL, 0x00fefefe00fefefeULL, + 0x007f7f7f007f7f7fULL, 0x00c5c5c500c5c5c5ULL, 0x00a4a4a400a4a4a4ULL, + 0x0037373700373737ULL, 0x00b1b1b100b1b1b1ULL, 0x004c4c4c004c4c4cULL, + 0x0091919100919191ULL, 0x006e6e6e006e6e6eULL, 0x008d8d8d008d8d8dULL, + 0x0076767600767676ULL, 0x0003030300030303ULL, 0x002d2d2d002d2d2dULL, + 0x00dedede00dededeULL, 0x0096969600969696ULL, 0x0026262600262626ULL, + 0x007d7d7d007d7d7dULL, 0x00c6c6c600c6c6c6ULL, 0x005c5c5c005c5c5cULL, + 0x00d3d3d300d3d3d3ULL, 0x00f2f2f200f2f2f2ULL, 0x004f4f4f004f4f4fULL, + 0x0019191900191919ULL, 0x003f3f3f003f3f3fULL, 0x00dcdcdc00dcdcdcULL, + 0x0079797900797979ULL, 0x001d1d1d001d1d1dULL, 0x0052525200525252ULL, + 0x00ebebeb00ebebebULL, 0x00f3f3f300f3f3f3ULL, 0x006d6d6d006d6d6dULL, + 0x005e5e5e005e5e5eULL, 0x00fbfbfb00fbfbfbULL, 0x0069696900696969ULL, + 0x00b2b2b200b2b2b2ULL, 0x00f0f0f000f0f0f0ULL, 0x0031313100313131ULL, + 0x000c0c0c000c0c0cULL, 0x00d4d4d400d4d4d4ULL, 0x00cfcfcf00cfcfcfULL, + 0x008c8c8c008c8c8cULL, 0x00e2e2e200e2e2e2ULL, 0x0075757500757575ULL, + 0x00a9a9a900a9a9a9ULL, 0x004a4a4a004a4a4aULL, 0x0057575700575757ULL, + 0x0084848400848484ULL, 0x0011111100111111ULL, 0x0045454500454545ULL, + 0x001b1b1b001b1b1bULL, 0x00f5f5f500f5f5f5ULL, 0x00e4e4e400e4e4e4ULL, + 0x000e0e0e000e0e0eULL, 0x0073737300737373ULL, 0x00aaaaaa00aaaaaaULL, + 0x00f1f1f100f1f1f1ULL, 0x00dddddd00ddddddULL, 0x0059595900595959ULL, + 0x0014141400141414ULL, 0x006c6c6c006c6c6cULL, 0x0092929200929292ULL, + 0x0054545400545454ULL, 0x00d0d0d000d0d0d0ULL, 0x0078787800787878ULL, + 0x0070707000707070ULL, 0x00e3e3e300e3e3e3ULL, 0x0049494900494949ULL, + 0x0080808000808080ULL, 0x0050505000505050ULL, 0x00a7a7a700a7a7a7ULL, + 0x00f6f6f600f6f6f6ULL, 0x0077777700777777ULL, 0x0093939300939393ULL, + 0x0086868600868686ULL, 0x0083838300838383ULL, 0x002a2a2a002a2a2aULL, + 0x00c7c7c700c7c7c7ULL, 0x005b5b5b005b5b5bULL, 0x00e9e9e900e9e9e9ULL, + 0x00eeeeee00eeeeeeULL, 0x008f8f8f008f8f8fULL, 0x0001010100010101ULL, + 0x003d3d3d003d3d3dULL, }; 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, + 0x3800383838003838ULL, 0x4100414141004141ULL, 0x1600161616001616ULL, + 0x7600767676007676ULL, 0xd900d9d9d900d9d9ULL, 0x9300939393009393ULL, + 0x6000606060006060ULL, 0xf200f2f2f200f2f2ULL, 0x7200727272007272ULL, + 0xc200c2c2c200c2c2ULL, 0xab00ababab00ababULL, 0x9a009a9a9a009a9aULL, + 0x7500757575007575ULL, 0x0600060606000606ULL, 0x5700575757005757ULL, + 0xa000a0a0a000a0a0ULL, 0x9100919191009191ULL, 0xf700f7f7f700f7f7ULL, + 0xb500b5b5b500b5b5ULL, 0xc900c9c9c900c9c9ULL, 0xa200a2a2a200a2a2ULL, + 0x8c008c8c8c008c8cULL, 0xd200d2d2d200d2d2ULL, 0x9000909090009090ULL, + 0xf600f6f6f600f6f6ULL, 0x0700070707000707ULL, 0xa700a7a7a700a7a7ULL, + 0x2700272727002727ULL, 0x8e008e8e8e008e8eULL, 0xb200b2b2b200b2b2ULL, + 0x4900494949004949ULL, 0xde00dedede00dedeULL, 0x4300434343004343ULL, + 0x5c005c5c5c005c5cULL, 0xd700d7d7d700d7d7ULL, 0xc700c7c7c700c7c7ULL, + 0x3e003e3e3e003e3eULL, 0xf500f5f5f500f5f5ULL, 0x8f008f8f8f008f8fULL, + 0x6700676767006767ULL, 0x1f001f1f1f001f1fULL, 0x1800181818001818ULL, + 0x6e006e6e6e006e6eULL, 0xaf00afafaf00afafULL, 0x2f002f2f2f002f2fULL, + 0xe200e2e2e200e2e2ULL, 0x8500858585008585ULL, 0x0d000d0d0d000d0dULL, + 0x5300535353005353ULL, 0xf000f0f0f000f0f0ULL, 0x9c009c9c9c009c9cULL, + 0x6500656565006565ULL, 0xea00eaeaea00eaeaULL, 0xa300a3a3a300a3a3ULL, + 0xae00aeaeae00aeaeULL, 0x9e009e9e9e009e9eULL, 0xec00ececec00ececULL, + 0x8000808080008080ULL, 0x2d002d2d2d002d2dULL, 0x6b006b6b6b006b6bULL, + 0xa800a8a8a800a8a8ULL, 0x2b002b2b2b002b2bULL, 0x3600363636003636ULL, + 0xa600a6a6a600a6a6ULL, 0xc500c5c5c500c5c5ULL, 0x8600868686008686ULL, + 0x4d004d4d4d004d4dULL, 0x3300333333003333ULL, 0xfd00fdfdfd00fdfdULL, + 0x6600666666006666ULL, 0x5800585858005858ULL, 0x9600969696009696ULL, + 0x3a003a3a3a003a3aULL, 0x0900090909000909ULL, 0x9500959595009595ULL, + 0x1000101010001010ULL, 0x7800787878007878ULL, 0xd800d8d8d800d8d8ULL, + 0x4200424242004242ULL, 0xcc00cccccc00ccccULL, 0xef00efefef00efefULL, + 0x2600262626002626ULL, 0xe500e5e5e500e5e5ULL, 0x6100616161006161ULL, + 0x1a001a1a1a001a1aULL, 0x3f003f3f3f003f3fULL, 0x3b003b3b3b003b3bULL, + 0x8200828282008282ULL, 0xb600b6b6b600b6b6ULL, 0xdb00dbdbdb00dbdbULL, + 0xd400d4d4d400d4d4ULL, 0x9800989898009898ULL, 0xe800e8e8e800e8e8ULL, + 0x8b008b8b8b008b8bULL, 0x0200020202000202ULL, 0xeb00ebebeb00ebebULL, + 0x0a000a0a0a000a0aULL, 0x2c002c2c2c002c2cULL, 0x1d001d1d1d001d1dULL, + 0xb000b0b0b000b0b0ULL, 0x6f006f6f6f006f6fULL, 0x8d008d8d8d008d8dULL, + 0x8800888888008888ULL, 0x0e000e0e0e000e0eULL, 0x1900191919001919ULL, + 0x8700878787008787ULL, 0x4e004e4e4e004e4eULL, 0x0b000b0b0b000b0bULL, + 0xa900a9a9a900a9a9ULL, 0x0c000c0c0c000c0cULL, 0x7900797979007979ULL, + 0x1100111111001111ULL, 0x7f007f7f7f007f7fULL, 0x2200222222002222ULL, + 0xe700e7e7e700e7e7ULL, 0x5900595959005959ULL, 0xe100e1e1e100e1e1ULL, + 0xda00dadada00dadaULL, 0x3d003d3d3d003d3dULL, 0xc800c8c8c800c8c8ULL, + 0x1200121212001212ULL, 0x0400040404000404ULL, 0x7400747474007474ULL, + 0x5400545454005454ULL, 0x3000303030003030ULL, 0x7e007e7e7e007e7eULL, + 0xb400b4b4b400b4b4ULL, 0x2800282828002828ULL, 0x5500555555005555ULL, + 0x6800686868006868ULL, 0x5000505050005050ULL, 0xbe00bebebe00bebeULL, + 0xd000d0d0d000d0d0ULL, 0xc400c4c4c400c4c4ULL, 0x3100313131003131ULL, + 0xcb00cbcbcb00cbcbULL, 0x2a002a2a2a002a2aULL, 0xad00adadad00adadULL, + 0x0f000f0f0f000f0fULL, 0xca00cacaca00cacaULL, 0x7000707070007070ULL, + 0xff00ffffff00ffffULL, 0x3200323232003232ULL, 0x6900696969006969ULL, + 0x0800080808000808ULL, 0x6200626262006262ULL, 0x0000000000000000ULL, + 0x2400242424002424ULL, 0xd100d1d1d100d1d1ULL, 0xfb00fbfbfb00fbfbULL, + 0xba00bababa00babaULL, 0xed00ededed00ededULL, 0x4500454545004545ULL, + 0x8100818181008181ULL, 0x7300737373007373ULL, 0x6d006d6d6d006d6dULL, + 0x8400848484008484ULL, 0x9f009f9f9f009f9fULL, 0xee00eeeeee00eeeeULL, + 0x4a004a4a4a004a4aULL, 0xc300c3c3c300c3c3ULL, 0x2e002e2e2e002e2eULL, + 0xc100c1c1c100c1c1ULL, 0x0100010101000101ULL, 0xe600e6e6e600e6e6ULL, + 0x2500252525002525ULL, 0x4800484848004848ULL, 0x9900999999009999ULL, + 0xb900b9b9b900b9b9ULL, 0xb300b3b3b300b3b3ULL, 0x7b007b7b7b007b7bULL, + 0xf900f9f9f900f9f9ULL, 0xce00cecece00ceceULL, 0xbf00bfbfbf00bfbfULL, + 0xdf00dfdfdf00dfdfULL, 0x7100717171007171ULL, 0x2900292929002929ULL, + 0xcd00cdcdcd00cdcdULL, 0x6c006c6c6c006c6cULL, 0x1300131313001313ULL, + 0x6400646464006464ULL, 0x9b009b9b9b009b9bULL, 0x6300636363006363ULL, + 0x9d009d9d9d009d9dULL, 0xc000c0c0c000c0c0ULL, 0x4b004b4b4b004b4bULL, + 0xb700b7b7b700b7b7ULL, 0xa500a5a5a500a5a5ULL, 0x8900898989008989ULL, + 0x5f005f5f5f005f5fULL, 0xb100b1b1b100b1b1ULL, 0x1700171717001717ULL, + 0xf400f4f4f400f4f4ULL, 0xbc00bcbcbc00bcbcULL, 0xd300d3d3d300d3d3ULL, + 0x4600464646004646ULL, 0xcf00cfcfcf00cfcfULL, 0x3700373737003737ULL, + 0x5e005e5e5e005e5eULL, 0x4700474747004747ULL, 0x9400949494009494ULL, + 0xfa00fafafa00fafaULL, 0xfc00fcfcfc00fcfcULL, 0x5b005b5b5b005b5bULL, + 0x9700979797009797ULL, 0xfe00fefefe00fefeULL, 0x5a005a5a5a005a5aULL, + 0xac00acacac00acacULL, 0x3c003c3c3c003c3cULL, 0x4c004c4c4c004c4cULL, + 0x0300030303000303ULL, 0x3500353535003535ULL, 0xf300f3f3f300f3f3ULL, + 0x2300232323002323ULL, 0xb800b8b8b800b8b8ULL, 0x5d005d5d5d005d5dULL, + 0x6a006a6a6a006a6aULL, 0x9200929292009292ULL, 0xd500d5d5d500d5d5ULL, + 0x2100212121002121ULL, 0x4400444444004444ULL, 0x5100515151005151ULL, + 0xc600c6c6c600c6c6ULL, 0x7d007d7d7d007d7dULL, 0x3900393939003939ULL, + 0x8300838383008383ULL, 0xdc00dcdcdc00dcdcULL, 0xaa00aaaaaa00aaaaULL, + 0x7c007c7c7c007c7cULL, 0x7700777777007777ULL, 0x5600565656005656ULL, + 0x0500050505000505ULL, 0x1b001b1b1b001b1bULL, 0xa400a4a4a400a4a4ULL, + 0x1500151515001515ULL, 0x3400343434003434ULL, 0x1e001e1e1e001e1eULL, + 0x1c001c1c1c001c1cULL, 0xf800f8f8f800f8f8ULL, 0x5200525252005252ULL, + 0x2000202020002020ULL, 0x1400141414001414ULL, 0xe900e9e9e900e9e9ULL, + 0xbd00bdbdbd00bdbdULL, 0xdd00dddddd00ddddULL, 0xe400e4e4e400e4e4ULL, + 0xa100a1a1a100a1a1ULL, 0xe000e0e0e000e0e0ULL, 0x8a008a8a8a008a8aULL, + 0xf100f1f1f100f1f1ULL, 0xd600d6d6d600d6d6ULL, 0x7a007a7a7a007a7aULL, + 0xbb00bbbbbb00bbbbULL, 0xe300e3e3e300e3e3ULL, 0x4000404040004040ULL, + 0x4f004f4f4f004f4fULL, }; 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, + 0x7070007070700070ULL, 0x2c2c002c2c2c002cULL, 0xb3b300b3b3b300b3ULL, + 0xc0c000c0c0c000c0ULL, 0xe4e400e4e4e400e4ULL, 0x5757005757570057ULL, + 0xeaea00eaeaea00eaULL, 0xaeae00aeaeae00aeULL, 0x2323002323230023ULL, + 0x6b6b006b6b6b006bULL, 0x4545004545450045ULL, 0xa5a500a5a5a500a5ULL, + 0xeded00ededed00edULL, 0x4f4f004f4f4f004fULL, 0x1d1d001d1d1d001dULL, + 0x9292009292920092ULL, 0x8686008686860086ULL, 0xafaf00afafaf00afULL, + 0x7c7c007c7c7c007cULL, 0x1f1f001f1f1f001fULL, 0x3e3e003e3e3e003eULL, + 0xdcdc00dcdcdc00dcULL, 0x5e5e005e5e5e005eULL, 0x0b0b000b0b0b000bULL, + 0xa6a600a6a6a600a6ULL, 0x3939003939390039ULL, 0xd5d500d5d5d500d5ULL, + 0x5d5d005d5d5d005dULL, 0xd9d900d9d9d900d9ULL, 0x5a5a005a5a5a005aULL, + 0x5151005151510051ULL, 0x6c6c006c6c6c006cULL, 0x8b8b008b8b8b008bULL, + 0x9a9a009a9a9a009aULL, 0xfbfb00fbfbfb00fbULL, 0xb0b000b0b0b000b0ULL, + 0x7474007474740074ULL, 0x2b2b002b2b2b002bULL, 0xf0f000f0f0f000f0ULL, + 0x8484008484840084ULL, 0xdfdf00dfdfdf00dfULL, 0xcbcb00cbcbcb00cbULL, + 0x3434003434340034ULL, 0x7676007676760076ULL, 0x6d6d006d6d6d006dULL, + 0xa9a900a9a9a900a9ULL, 0xd1d100d1d1d100d1ULL, 0x0404000404040004ULL, + 0x1414001414140014ULL, 0x3a3a003a3a3a003aULL, 0xdede00dedede00deULL, + 0x1111001111110011ULL, 0x3232003232320032ULL, 0x9c9c009c9c9c009cULL, + 0x5353005353530053ULL, 0xf2f200f2f2f200f2ULL, 0xfefe00fefefe00feULL, + 0xcfcf00cfcfcf00cfULL, 0xc3c300c3c3c300c3ULL, 0x7a7a007a7a7a007aULL, + 0x2424002424240024ULL, 0xe8e800e8e8e800e8ULL, 0x6060006060600060ULL, + 0x6969006969690069ULL, 0xaaaa00aaaaaa00aaULL, 0xa0a000a0a0a000a0ULL, + 0xa1a100a1a1a100a1ULL, 0x6262006262620062ULL, 0x5454005454540054ULL, + 0x1e1e001e1e1e001eULL, 0xe0e000e0e0e000e0ULL, 0x6464006464640064ULL, + 0x1010001010100010ULL, 0x0000000000000000ULL, 0xa3a300a3a3a300a3ULL, + 0x7575007575750075ULL, 0x8a8a008a8a8a008aULL, 0xe6e600e6e6e600e6ULL, + 0x0909000909090009ULL, 0xdddd00dddddd00ddULL, 0x8787008787870087ULL, + 0x8383008383830083ULL, 0xcdcd00cdcdcd00cdULL, 0x9090009090900090ULL, + 0x7373007373730073ULL, 0xf6f600f6f6f600f6ULL, 0x9d9d009d9d9d009dULL, + 0xbfbf00bfbfbf00bfULL, 0x5252005252520052ULL, 0xd8d800d8d8d800d8ULL, + 0xc8c800c8c8c800c8ULL, 0xc6c600c6c6c600c6ULL, 0x8181008181810081ULL, + 0x6f6f006f6f6f006fULL, 0x1313001313130013ULL, 0x6363006363630063ULL, + 0xe9e900e9e9e900e9ULL, 0xa7a700a7a7a700a7ULL, 0x9f9f009f9f9f009fULL, + 0xbcbc00bcbcbc00bcULL, 0x2929002929290029ULL, 0xf9f900f9f9f900f9ULL, + 0x2f2f002f2f2f002fULL, 0xb4b400b4b4b400b4ULL, 0x7878007878780078ULL, + 0x0606000606060006ULL, 0xe7e700e7e7e700e7ULL, 0x7171007171710071ULL, + 0xd4d400d4d4d400d4ULL, 0xabab00ababab00abULL, 0x8888008888880088ULL, + 0x8d8d008d8d8d008dULL, 0x7272007272720072ULL, 0xb9b900b9b9b900b9ULL, + 0xf8f800f8f8f800f8ULL, 0xacac00acacac00acULL, 0x3636003636360036ULL, + 0x2a2a002a2a2a002aULL, 0x3c3c003c3c3c003cULL, 0xf1f100f1f1f100f1ULL, + 0x4040004040400040ULL, 0xd3d300d3d3d300d3ULL, 0xbbbb00bbbbbb00bbULL, + 0x4343004343430043ULL, 0x1515001515150015ULL, 0xadad00adadad00adULL, + 0x7777007777770077ULL, 0x8080008080800080ULL, 0x8282008282820082ULL, + 0xecec00ececec00ecULL, 0x2727002727270027ULL, 0xe5e500e5e5e500e5ULL, + 0x8585008585850085ULL, 0x3535003535350035ULL, 0x0c0c000c0c0c000cULL, + 0x4141004141410041ULL, 0xefef00efefef00efULL, 0x9393009393930093ULL, + 0x1919001919190019ULL, 0x2121002121210021ULL, 0x0e0e000e0e0e000eULL, + 0x4e4e004e4e4e004eULL, 0x6565006565650065ULL, 0xbdbd00bdbdbd00bdULL, + 0xb8b800b8b8b800b8ULL, 0x8f8f008f8f8f008fULL, 0xebeb00ebebeb00ebULL, + 0xcece00cecece00ceULL, 0x3030003030300030ULL, 0x5f5f005f5f5f005fULL, + 0xc5c500c5c5c500c5ULL, 0x1a1a001a1a1a001aULL, 0xe1e100e1e1e100e1ULL, + 0xcaca00cacaca00caULL, 0x4747004747470047ULL, 0x3d3d003d3d3d003dULL, + 0x0101000101010001ULL, 0xd6d600d6d6d600d6ULL, 0x5656005656560056ULL, + 0x4d4d004d4d4d004dULL, 0x0d0d000d0d0d000dULL, 0x6666006666660066ULL, + 0xcccc00cccccc00ccULL, 0x2d2d002d2d2d002dULL, 0x1212001212120012ULL, + 0x2020002020200020ULL, 0xb1b100b1b1b100b1ULL, 0x9999009999990099ULL, + 0x4c4c004c4c4c004cULL, 0xc2c200c2c2c200c2ULL, 0x7e7e007e7e7e007eULL, + 0x0505000505050005ULL, 0xb7b700b7b7b700b7ULL, 0x3131003131310031ULL, + 0x1717001717170017ULL, 0xd7d700d7d7d700d7ULL, 0x5858005858580058ULL, + 0x6161006161610061ULL, 0x1b1b001b1b1b001bULL, 0x1c1c001c1c1c001cULL, + 0x0f0f000f0f0f000fULL, 0x1616001616160016ULL, 0x1818001818180018ULL, + 0x2222002222220022ULL, 0x4444004444440044ULL, 0xb2b200b2b2b200b2ULL, + 0xb5b500b5b5b500b5ULL, 0x9191009191910091ULL, 0x0808000808080008ULL, + 0xa8a800a8a8a800a8ULL, 0xfcfc00fcfcfc00fcULL, 0x5050005050500050ULL, + 0xd0d000d0d0d000d0ULL, 0x7d7d007d7d7d007dULL, 0x8989008989890089ULL, + 0x9797009797970097ULL, 0x5b5b005b5b5b005bULL, 0x9595009595950095ULL, + 0xffff00ffffff00ffULL, 0xd2d200d2d2d200d2ULL, 0xc4c400c4c4c400c4ULL, + 0x4848004848480048ULL, 0xf7f700f7f7f700f7ULL, 0xdbdb00dbdbdb00dbULL, + 0x0303000303030003ULL, 0xdada00dadada00daULL, 0x3f3f003f3f3f003fULL, + 0x9494009494940094ULL, 0x5c5c005c5c5c005cULL, 0x0202000202020002ULL, + 0x4a4a004a4a4a004aULL, 0x3333003333330033ULL, 0x6767006767670067ULL, + 0xf3f300f3f3f300f3ULL, 0x7f7f007f7f7f007fULL, 0xe2e200e2e2e200e2ULL, + 0x9b9b009b9b9b009bULL, 0x2626002626260026ULL, 0x3737003737370037ULL, + 0x3b3b003b3b3b003bULL, 0x9696009696960096ULL, 0x4b4b004b4b4b004bULL, + 0xbebe00bebebe00beULL, 0x2e2e002e2e2e002eULL, 0x7979007979790079ULL, + 0x8c8c008c8c8c008cULL, 0x6e6e006e6e6e006eULL, 0x8e8e008e8e8e008eULL, + 0xf5f500f5f5f500f5ULL, 0xb6b600b6b6b600b6ULL, 0xfdfd00fdfdfd00fdULL, + 0x5959005959590059ULL, 0x9898009898980098ULL, 0x6a6a006a6a6a006aULL, + 0x4646004646460046ULL, 0xbaba00bababa00baULL, 0x2525002525250025ULL, + 0x4242004242420042ULL, 0xa2a200a2a2a200a2ULL, 0xfafa00fafafa00faULL, + 0x0707000707070007ULL, 0x5555005555550055ULL, 0xeeee00eeeeee00eeULL, + 0x0a0a000a0a0a000aULL, 0x4949004949490049ULL, 0x6868006868680068ULL, + 0x3838003838380038ULL, 0xa4a400a4a4a400a4ULL, 0x2828002828280028ULL, + 0x7b7b007b7b7b007bULL, 0xc9c900c9c9c900c9ULL, 0xc1c100c1c1c100c1ULL, + 0xe3e300e3e3e300e3ULL, 0xf4f400f4f4f400f4ULL, 0xc7c700c7c7c700c7ULL, + 0x9e9e009e9e9e009eULL, }; 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, + 0x7070700070707000ULL, 0x8282820082828200ULL, 0x2c2c2c002c2c2c00ULL, + 0xececec00ececec00ULL, 0xb3b3b300b3b3b300ULL, 0x2727270027272700ULL, + 0xc0c0c000c0c0c000ULL, 0xe5e5e500e5e5e500ULL, 0xe4e4e400e4e4e400ULL, + 0x8585850085858500ULL, 0x5757570057575700ULL, 0x3535350035353500ULL, + 0xeaeaea00eaeaea00ULL, 0x0c0c0c000c0c0c00ULL, 0xaeaeae00aeaeae00ULL, + 0x4141410041414100ULL, 0x2323230023232300ULL, 0xefefef00efefef00ULL, + 0x6b6b6b006b6b6b00ULL, 0x9393930093939300ULL, 0x4545450045454500ULL, + 0x1919190019191900ULL, 0xa5a5a500a5a5a500ULL, 0x2121210021212100ULL, + 0xededed00ededed00ULL, 0x0e0e0e000e0e0e00ULL, 0x4f4f4f004f4f4f00ULL, + 0x4e4e4e004e4e4e00ULL, 0x1d1d1d001d1d1d00ULL, 0x6565650065656500ULL, + 0x9292920092929200ULL, 0xbdbdbd00bdbdbd00ULL, 0x8686860086868600ULL, + 0xb8b8b800b8b8b800ULL, 0xafafaf00afafaf00ULL, 0x8f8f8f008f8f8f00ULL, + 0x7c7c7c007c7c7c00ULL, 0xebebeb00ebebeb00ULL, 0x1f1f1f001f1f1f00ULL, + 0xcecece00cecece00ULL, 0x3e3e3e003e3e3e00ULL, 0x3030300030303000ULL, + 0xdcdcdc00dcdcdc00ULL, 0x5f5f5f005f5f5f00ULL, 0x5e5e5e005e5e5e00ULL, + 0xc5c5c500c5c5c500ULL, 0x0b0b0b000b0b0b00ULL, 0x1a1a1a001a1a1a00ULL, + 0xa6a6a600a6a6a600ULL, 0xe1e1e100e1e1e100ULL, 0x3939390039393900ULL, + 0xcacaca00cacaca00ULL, 0xd5d5d500d5d5d500ULL, 0x4747470047474700ULL, + 0x5d5d5d005d5d5d00ULL, 0x3d3d3d003d3d3d00ULL, 0xd9d9d900d9d9d900ULL, + 0x0101010001010100ULL, 0x5a5a5a005a5a5a00ULL, 0xd6d6d600d6d6d600ULL, + 0x5151510051515100ULL, 0x5656560056565600ULL, 0x6c6c6c006c6c6c00ULL, + 0x4d4d4d004d4d4d00ULL, 0x8b8b8b008b8b8b00ULL, 0x0d0d0d000d0d0d00ULL, + 0x9a9a9a009a9a9a00ULL, 0x6666660066666600ULL, 0xfbfbfb00fbfbfb00ULL, + 0xcccccc00cccccc00ULL, 0xb0b0b000b0b0b000ULL, 0x2d2d2d002d2d2d00ULL, + 0x7474740074747400ULL, 0x1212120012121200ULL, 0x2b2b2b002b2b2b00ULL, + 0x2020200020202000ULL, 0xf0f0f000f0f0f000ULL, 0xb1b1b100b1b1b100ULL, + 0x8484840084848400ULL, 0x9999990099999900ULL, 0xdfdfdf00dfdfdf00ULL, + 0x4c4c4c004c4c4c00ULL, 0xcbcbcb00cbcbcb00ULL, 0xc2c2c200c2c2c200ULL, + 0x3434340034343400ULL, 0x7e7e7e007e7e7e00ULL, 0x7676760076767600ULL, + 0x0505050005050500ULL, 0x6d6d6d006d6d6d00ULL, 0xb7b7b700b7b7b700ULL, + 0xa9a9a900a9a9a900ULL, 0x3131310031313100ULL, 0xd1d1d100d1d1d100ULL, + 0x1717170017171700ULL, 0x0404040004040400ULL, 0xd7d7d700d7d7d700ULL, + 0x1414140014141400ULL, 0x5858580058585800ULL, 0x3a3a3a003a3a3a00ULL, + 0x6161610061616100ULL, 0xdedede00dedede00ULL, 0x1b1b1b001b1b1b00ULL, + 0x1111110011111100ULL, 0x1c1c1c001c1c1c00ULL, 0x3232320032323200ULL, + 0x0f0f0f000f0f0f00ULL, 0x9c9c9c009c9c9c00ULL, 0x1616160016161600ULL, + 0x5353530053535300ULL, 0x1818180018181800ULL, 0xf2f2f200f2f2f200ULL, + 0x2222220022222200ULL, 0xfefefe00fefefe00ULL, 0x4444440044444400ULL, + 0xcfcfcf00cfcfcf00ULL, 0xb2b2b200b2b2b200ULL, 0xc3c3c300c3c3c300ULL, + 0xb5b5b500b5b5b500ULL, 0x7a7a7a007a7a7a00ULL, 0x9191910091919100ULL, + 0x2424240024242400ULL, 0x0808080008080800ULL, 0xe8e8e800e8e8e800ULL, + 0xa8a8a800a8a8a800ULL, 0x6060600060606000ULL, 0xfcfcfc00fcfcfc00ULL, + 0x6969690069696900ULL, 0x5050500050505000ULL, 0xaaaaaa00aaaaaa00ULL, + 0xd0d0d000d0d0d000ULL, 0xa0a0a000a0a0a000ULL, 0x7d7d7d007d7d7d00ULL, + 0xa1a1a100a1a1a100ULL, 0x8989890089898900ULL, 0x6262620062626200ULL, + 0x9797970097979700ULL, 0x5454540054545400ULL, 0x5b5b5b005b5b5b00ULL, + 0x1e1e1e001e1e1e00ULL, 0x9595950095959500ULL, 0xe0e0e000e0e0e000ULL, + 0xffffff00ffffff00ULL, 0x6464640064646400ULL, 0xd2d2d200d2d2d200ULL, + 0x1010100010101000ULL, 0xc4c4c400c4c4c400ULL, 0x0000000000000000ULL, + 0x4848480048484800ULL, 0xa3a3a300a3a3a300ULL, 0xf7f7f700f7f7f700ULL, + 0x7575750075757500ULL, 0xdbdbdb00dbdbdb00ULL, 0x8a8a8a008a8a8a00ULL, + 0x0303030003030300ULL, 0xe6e6e600e6e6e600ULL, 0xdadada00dadada00ULL, + 0x0909090009090900ULL, 0x3f3f3f003f3f3f00ULL, 0xdddddd00dddddd00ULL, + 0x9494940094949400ULL, 0x8787870087878700ULL, 0x5c5c5c005c5c5c00ULL, + 0x8383830083838300ULL, 0x0202020002020200ULL, 0xcdcdcd00cdcdcd00ULL, + 0x4a4a4a004a4a4a00ULL, 0x9090900090909000ULL, 0x3333330033333300ULL, + 0x7373730073737300ULL, 0x6767670067676700ULL, 0xf6f6f600f6f6f600ULL, + 0xf3f3f300f3f3f300ULL, 0x9d9d9d009d9d9d00ULL, 0x7f7f7f007f7f7f00ULL, + 0xbfbfbf00bfbfbf00ULL, 0xe2e2e200e2e2e200ULL, 0x5252520052525200ULL, + 0x9b9b9b009b9b9b00ULL, 0xd8d8d800d8d8d800ULL, 0x2626260026262600ULL, + 0xc8c8c800c8c8c800ULL, 0x3737370037373700ULL, 0xc6c6c600c6c6c600ULL, + 0x3b3b3b003b3b3b00ULL, 0x8181810081818100ULL, 0x9696960096969600ULL, + 0x6f6f6f006f6f6f00ULL, 0x4b4b4b004b4b4b00ULL, 0x1313130013131300ULL, + 0xbebebe00bebebe00ULL, 0x6363630063636300ULL, 0x2e2e2e002e2e2e00ULL, + 0xe9e9e900e9e9e900ULL, 0x7979790079797900ULL, 0xa7a7a700a7a7a700ULL, + 0x8c8c8c008c8c8c00ULL, 0x9f9f9f009f9f9f00ULL, 0x6e6e6e006e6e6e00ULL, + 0xbcbcbc00bcbcbc00ULL, 0x8e8e8e008e8e8e00ULL, 0x2929290029292900ULL, + 0xf5f5f500f5f5f500ULL, 0xf9f9f900f9f9f900ULL, 0xb6b6b600b6b6b600ULL, + 0x2f2f2f002f2f2f00ULL, 0xfdfdfd00fdfdfd00ULL, 0xb4b4b400b4b4b400ULL, + 0x5959590059595900ULL, 0x7878780078787800ULL, 0x9898980098989800ULL, + 0x0606060006060600ULL, 0x6a6a6a006a6a6a00ULL, 0xe7e7e700e7e7e700ULL, + 0x4646460046464600ULL, 0x7171710071717100ULL, 0xbababa00bababa00ULL, + 0xd4d4d400d4d4d400ULL, 0x2525250025252500ULL, 0xababab00ababab00ULL, + 0x4242420042424200ULL, 0x8888880088888800ULL, 0xa2a2a200a2a2a200ULL, + 0x8d8d8d008d8d8d00ULL, 0xfafafa00fafafa00ULL, 0x7272720072727200ULL, + 0x0707070007070700ULL, 0xb9b9b900b9b9b900ULL, 0x5555550055555500ULL, + 0xf8f8f800f8f8f800ULL, 0xeeeeee00eeeeee00ULL, 0xacacac00acacac00ULL, + 0x0a0a0a000a0a0a00ULL, 0x3636360036363600ULL, 0x4949490049494900ULL, + 0x2a2a2a002a2a2a00ULL, 0x6868680068686800ULL, 0x3c3c3c003c3c3c00ULL, + 0x3838380038383800ULL, 0xf1f1f100f1f1f100ULL, 0xa4a4a400a4a4a400ULL, + 0x4040400040404000ULL, 0x2828280028282800ULL, 0xd3d3d300d3d3d300ULL, + 0x7b7b7b007b7b7b00ULL, 0xbbbbbb00bbbbbb00ULL, 0xc9c9c900c9c9c900ULL, + 0x4343430043434300ULL, 0xc1c1c100c1c1c100ULL, 0x1515150015151500ULL, + 0xe3e3e300e3e3e300ULL, 0xadadad00adadad00ULL, 0xf4f4f400f4f4f400ULL, + 0x7777770077777700ULL, 0xc7c7c700c7c7c700ULL, 0x8080800080808000ULL, + 0x9e9e9e009e9e9e00ULL, }; /* key constants */ @@ -1601,7 +1601,6 @@ static struct crypto_alg camellia_algs[6] = { { .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, @@ -1621,7 +1620,6 @@ static struct crypto_alg camellia_algs[6] = { { .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, @@ -1641,7 +1639,6 @@ static struct crypto_alg camellia_algs[6] = { { .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, @@ -1662,7 +1659,6 @@ static struct crypto_alg camellia_algs[6] = { { .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, @@ -1683,7 +1679,6 @@ static struct crypto_alg camellia_algs[6] = { { .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 = { @@ -1707,7 +1702,6 @@ static struct crypto_alg camellia_algs[6] = { { .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, diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S new file mode 100644 index 000000000000..a41a3aaba220 --- /dev/null +++ b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S @@ -0,0 +1,376 @@ +/* + * Cast5 Cipher 16-way parallel algorithm (AVX/x86_64) + * + * Copyright (C) 2012 Johannes Goetzfried + * <Johannes.Goetzfried@informatik.stud.uni-erlangen.de> + * + * Copyright © 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 "cast5-avx-x86_64-asm_64.S" + +.extern cast5_s1 +.extern cast5_s2 +.extern cast5_s3 +.extern cast5_s4 + +/* structure of crypto context */ +#define km 0 +#define kr (16*4) +#define rr ((16*4)+16) + +/* s-boxes */ +#define s1 cast5_s1 +#define s2 cast5_s2 +#define s3 cast5_s3 +#define s4 cast5_s4 + +/********************************************************************** + 16-way AVX cast5 + **********************************************************************/ +#define CTX %rdi + +#define RL1 %xmm0 +#define RR1 %xmm1 +#define RL2 %xmm2 +#define RR2 %xmm3 +#define RL3 %xmm4 +#define RR3 %xmm5 +#define RL4 %xmm6 +#define RR4 %xmm7 + +#define RX %xmm8 + +#define RKM %xmm9 +#define RKR %xmm10 +#define RKRF %xmm11 +#define RKRR %xmm12 + +#define R32 %xmm13 +#define R1ST %xmm14 + +#define RTMP %xmm15 + +#define RID1 %rbp +#define RID1d %ebp +#define RID2 %rsi +#define RID2d %esi + +#define RGI1 %rdx +#define RGI1bl %dl +#define RGI1bh %dh +#define RGI2 %rcx +#define RGI2bl %cl +#define RGI2bh %ch + +#define RGI3 %rax +#define RGI3bl %al +#define RGI3bh %ah +#define RGI4 %rbx +#define RGI4bl %bl +#define RGI4bh %bh + +#define RFS1 %r8 +#define RFS1d %r8d +#define RFS2 %r9 +#define RFS2d %r9d +#define RFS3 %r10 +#define RFS3d %r10d + + +#define lookup_32bit(src, dst, op1, op2, op3, interleave_op, il_reg) \ + movzbl src ## bh, RID1d; \ + movzbl src ## bl, RID2d; \ + shrq $16, src; \ + movl s1(, RID1, 4), dst ## d; \ + op1 s2(, RID2, 4), dst ## d; \ + movzbl src ## bh, RID1d; \ + movzbl src ## bl, RID2d; \ + interleave_op(il_reg); \ + op2 s3(, RID1, 4), dst ## d; \ + op3 s4(, RID2, 4), dst ## d; + +#define dummy(d) /* do nothing */ + +#define shr_next(reg) \ + shrq $16, reg; + +#define F_head(a, x, gi1, gi2, op0) \ + op0 a, RKM, x; \ + vpslld RKRF, x, RTMP; \ + vpsrld RKRR, x, x; \ + vpor RTMP, x, x; \ + \ + vmovq x, gi1; \ + vpextrq $1, x, gi2; + +#define F_tail(a, x, gi1, gi2, op1, op2, op3) \ + lookup_32bit(##gi1, RFS1, op1, op2, op3, shr_next, ##gi1); \ + lookup_32bit(##gi2, RFS3, op1, op2, op3, shr_next, ##gi2); \ + \ + lookup_32bit(##gi1, RFS2, op1, op2, op3, dummy, none); \ + shlq $32, RFS2; \ + orq RFS1, RFS2; \ + lookup_32bit(##gi2, RFS1, op1, op2, op3, dummy, none); \ + shlq $32, RFS1; \ + orq RFS1, RFS3; \ + \ + vmovq RFS2, x; \ + vpinsrq $1, RFS3, x, x; + +#define F_2(a1, b1, a2, b2, op0, op1, op2, op3) \ + F_head(b1, RX, RGI1, RGI2, op0); \ + F_head(b2, RX, RGI3, RGI4, op0); \ + \ + F_tail(b1, RX, RGI1, RGI2, op1, op2, op3); \ + F_tail(b2, RTMP, RGI3, RGI4, op1, op2, op3); \ + \ + vpxor a1, RX, a1; \ + vpxor a2, RTMP, a2; + +#define F1_2(a1, b1, a2, b2) \ + F_2(a1, b1, a2, b2, vpaddd, xorl, subl, addl) +#define F2_2(a1, b1, a2, b2) \ + F_2(a1, b1, a2, b2, vpxor, subl, addl, xorl) +#define F3_2(a1, b1, a2, b2) \ + F_2(a1, b1, a2, b2, vpsubd, addl, xorl, subl) + +#define subround(a1, b1, a2, b2, f) \ + F ## f ## _2(a1, b1, a2, b2); + +#define round(l, r, n, f) \ + vbroadcastss (km+(4*n))(CTX), RKM; \ + vpand R1ST, RKR, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + vpsrldq $1, RKR, RKR; \ + subround(l ## 1, r ## 1, l ## 2, r ## 2, f); \ + subround(l ## 3, r ## 3, l ## 4, r ## 4, f); + +#define enc_preload_rkr() \ + vbroadcastss .L16_mask, RKR; \ + /* add 16-bit rotation to key rotations (mod 32) */ \ + vpxor kr(CTX), RKR, RKR; + +#define dec_preload_rkr() \ + vbroadcastss .L16_mask, RKR; \ + /* add 16-bit rotation to key rotations (mod 32) */ \ + vpxor kr(CTX), RKR, RKR; \ + vpshufb .Lbswap128_mask, RKR, RKR; + +#define transpose_2x4(x0, x1, t0, t1) \ + vpunpckldq x1, x0, t0; \ + vpunpckhdq x1, x0, t1; \ + \ + vpunpcklqdq t1, t0, x0; \ + vpunpckhqdq t1, t0, x1; + +#define inpack_blocks(in, x0, x1, t0, t1, rmask) \ + vmovdqu (0*4*4)(in), x0; \ + vmovdqu (1*4*4)(in), x1; \ + vpshufb rmask, x0, x0; \ + vpshufb rmask, x1, x1; \ + \ + transpose_2x4(x0, x1, t0, t1) + +#define outunpack_blocks(out, x0, x1, t0, t1, rmask) \ + transpose_2x4(x0, x1, t0, t1) \ + \ + vpshufb rmask, x0, x0; \ + vpshufb rmask, x1, x1; \ + vmovdqu x0, (0*4*4)(out); \ + vmovdqu x1, (1*4*4)(out); + +#define outunpack_xor_blocks(out, x0, x1, t0, t1, rmask) \ + transpose_2x4(x0, x1, t0, t1) \ + \ + vpshufb rmask, x0, x0; \ + vpshufb rmask, x1, x1; \ + vpxor (0*4*4)(out), x0, x0; \ + vmovdqu x0, (0*4*4)(out); \ + vpxor (1*4*4)(out), x1, x1; \ + vmovdqu x1, (1*4*4)(out); + +.data + +.align 16 +.Lbswap_mask: + .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 +.Lbswap128_mask: + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +.L16_mask: + .byte 16, 16, 16, 16 +.L32_mask: + .byte 32, 0, 0, 0 +.Lfirst_mask: + .byte 0x1f, 0, 0, 0 + +.text + +.align 16 +.global __cast5_enc_blk_16way +.type __cast5_enc_blk_16way,@function; + +__cast5_enc_blk_16way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool, if true: xor output + */ + + pushq %rbp; + pushq %rbx; + pushq %rcx; + + vmovdqa .Lbswap_mask, RKM; + vmovd .Lfirst_mask, R1ST; + vmovd .L32_mask, R32; + enc_preload_rkr(); + + leaq 1*(2*4*4)(%rdx), %rax; + inpack_blocks(%rdx, RL1, RR1, RTMP, RX, RKM); + inpack_blocks(%rax, RL2, RR2, RTMP, RX, RKM); + leaq 2*(2*4*4)(%rdx), %rax; + inpack_blocks(%rax, RL3, RR3, RTMP, RX, RKM); + leaq 3*(2*4*4)(%rdx), %rax; + inpack_blocks(%rax, RL4, RR4, RTMP, RX, RKM); + + movq %rsi, %r11; + + round(RL, RR, 0, 1); + round(RR, RL, 1, 2); + round(RL, RR, 2, 3); + round(RR, RL, 3, 1); + round(RL, RR, 4, 2); + round(RR, RL, 5, 3); + round(RL, RR, 6, 1); + round(RR, RL, 7, 2); + round(RL, RR, 8, 3); + round(RR, RL, 9, 1); + round(RL, RR, 10, 2); + round(RR, RL, 11, 3); + + movzbl rr(CTX), %eax; + testl %eax, %eax; + jnz __skip_enc; + + round(RL, RR, 12, 1); + round(RR, RL, 13, 2); + round(RL, RR, 14, 3); + round(RR, RL, 15, 1); + +__skip_enc: + popq %rcx; + popq %rbx; + popq %rbp; + + vmovdqa .Lbswap_mask, RKM; + leaq 1*(2*4*4)(%r11), %rax; + + testb %cl, %cl; + jnz __enc_xor16; + + outunpack_blocks(%r11, RR1, RL1, RTMP, RX, RKM); + outunpack_blocks(%rax, RR2, RL2, RTMP, RX, RKM); + leaq 2*(2*4*4)(%r11), %rax; + outunpack_blocks(%rax, RR3, RL3, RTMP, RX, RKM); + leaq 3*(2*4*4)(%r11), %rax; + outunpack_blocks(%rax, RR4, RL4, RTMP, RX, RKM); + + ret; + +__enc_xor16: + outunpack_xor_blocks(%r11, RR1, RL1, RTMP, RX, RKM); + outunpack_xor_blocks(%rax, RR2, RL2, RTMP, RX, RKM); + leaq 2*(2*4*4)(%r11), %rax; + outunpack_xor_blocks(%rax, RR3, RL3, RTMP, RX, RKM); + leaq 3*(2*4*4)(%r11), %rax; + outunpack_xor_blocks(%rax, RR4, RL4, RTMP, RX, RKM); + + ret; + +.align 16 +.global cast5_dec_blk_16way +.type cast5_dec_blk_16way,@function; + +cast5_dec_blk_16way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + + pushq %rbp; + pushq %rbx; + + vmovdqa .Lbswap_mask, RKM; + vmovd .Lfirst_mask, R1ST; + vmovd .L32_mask, R32; + dec_preload_rkr(); + + leaq 1*(2*4*4)(%rdx), %rax; + inpack_blocks(%rdx, RL1, RR1, RTMP, RX, RKM); + inpack_blocks(%rax, RL2, RR2, RTMP, RX, RKM); + leaq 2*(2*4*4)(%rdx), %rax; + inpack_blocks(%rax, RL3, RR3, RTMP, RX, RKM); + leaq 3*(2*4*4)(%rdx), %rax; + inpack_blocks(%rax, RL4, RR4, RTMP, RX, RKM); + + movq %rsi, %r11; + + movzbl rr(CTX), %eax; + testl %eax, %eax; + jnz __skip_dec; + + round(RL, RR, 15, 1); + round(RR, RL, 14, 3); + round(RL, RR, 13, 2); + round(RR, RL, 12, 1); + +__dec_tail: + round(RL, RR, 11, 3); + round(RR, RL, 10, 2); + round(RL, RR, 9, 1); + round(RR, RL, 8, 3); + round(RL, RR, 7, 2); + round(RR, RL, 6, 1); + round(RL, RR, 5, 3); + round(RR, RL, 4, 2); + round(RL, RR, 3, 1); + round(RR, RL, 2, 3); + round(RL, RR, 1, 2); + round(RR, RL, 0, 1); + + vmovdqa .Lbswap_mask, RKM; + popq %rbx; + popq %rbp; + + leaq 1*(2*4*4)(%r11), %rax; + outunpack_blocks(%r11, RR1, RL1, RTMP, RX, RKM); + outunpack_blocks(%rax, RR2, RL2, RTMP, RX, RKM); + leaq 2*(2*4*4)(%r11), %rax; + outunpack_blocks(%rax, RR3, RL3, RTMP, RX, RKM); + leaq 3*(2*4*4)(%r11), %rax; + outunpack_blocks(%rax, RR4, RL4, RTMP, RX, RKM); + + ret; + +__skip_dec: + vpsrldq $4, RKR, RKR; + jmp __dec_tail; diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c new file mode 100644 index 000000000000..e0ea14f9547f --- /dev/null +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -0,0 +1,530 @@ +/* + * Glue Code for the AVX assembler implemention of the Cast5 Cipher + * + * Copyright (C) 2012 Johannes Goetzfried + * <Johannes.Goetzfried@informatik.stud.uni-erlangen.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +#include <linux/module.h> +#include <linux/hardirq.h> +#include <linux/types.h> +#include <linux/crypto.h> +#include <linux/err.h> +#include <crypto/algapi.h> +#include <crypto/cast5.h> +#include <crypto/cryptd.h> +#include <crypto/ctr.h> +#include <asm/xcr.h> +#include <asm/xsave.h> +#include <asm/crypto/ablk_helper.h> +#include <asm/crypto/glue_helper.h> + +#define CAST5_PARALLEL_BLOCKS 16 + +asmlinkage void __cast5_enc_blk_16way(struct cast5_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void cast5_dec_blk_16way(struct cast5_ctx *ctx, u8 *dst, + const u8 *src); + +static inline void cast5_enc_blk_xway(struct cast5_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast5_enc_blk_16way(ctx, dst, src, false); +} + +static inline void cast5_enc_blk_xway_xor(struct cast5_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast5_enc_blk_16way(ctx, dst, src, true); +} + +static inline void cast5_dec_blk_xway(struct cast5_ctx *ctx, u8 *dst, + const u8 *src) +{ + cast5_dec_blk_16way(ctx, dst, src); +} + + +static inline bool cast5_fpu_begin(bool fpu_enabled, unsigned int nbytes) +{ + return glue_fpu_begin(CAST5_BLOCK_SIZE, CAST5_PARALLEL_BLOCKS, + NULL, fpu_enabled, nbytes); +} + +static inline void cast5_fpu_end(bool fpu_enabled) +{ + return glue_fpu_end(fpu_enabled); +} + +static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, + bool enc) +{ + bool fpu_enabled = false; + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes; + int err; + + err = blkcipher_walk_virt(desc, walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + while ((nbytes = walk->nbytes)) { + u8 *wsrc = walk->src.virt.addr; + u8 *wdst = walk->dst.virt.addr; + + fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes); + + /* Process multi-block batch */ + if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + do { + if (enc) + cast5_enc_blk_xway(ctx, wdst, wsrc); + else + cast5_dec_blk_xway(ctx, wdst, wsrc); + + wsrc += bsize * CAST5_PARALLEL_BLOCKS; + wdst += bsize * CAST5_PARALLEL_BLOCKS; + nbytes -= bsize * CAST5_PARALLEL_BLOCKS; + } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + if (enc) + __cast5_encrypt(ctx, wdst, wsrc); + else + __cast5_decrypt(ctx, wdst, wsrc); + + wsrc += bsize; + wdst += bsize; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + err = blkcipher_walk_done(desc, walk, nbytes); + } + + cast5_fpu_end(fpu_enabled); + 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, true); +} + +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, false); +} + +static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u64 *src = (u64 *)walk->src.virt.addr; + u64 *dst = (u64 *)walk->dst.virt.addr; + u64 *iv = (u64 *)walk->iv; + + do { + *dst = *src ^ *iv; + __cast5_encrypt(ctx, (u8 *)dst, (u8 *)dst); + iv = dst; + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + + *(u64 *)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 cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u64 *src = (u64 *)walk->src.virt.addr; + u64 *dst = (u64 *)walk->dst.virt.addr; + u64 ivs[CAST5_PARALLEL_BLOCKS - 1]; + u64 last_iv; + int i; + + /* Start of the last block. */ + src += nbytes / bsize - 1; + dst += nbytes / bsize - 1; + + last_iv = *src; + + /* Process multi-block batch */ + if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + do { + nbytes -= bsize * (CAST5_PARALLEL_BLOCKS - 1); + src -= CAST5_PARALLEL_BLOCKS - 1; + dst -= CAST5_PARALLEL_BLOCKS - 1; + + for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++) + ivs[i] = src[i]; + + cast5_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); + + for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++) + *(dst + (i + 1)) ^= *(ivs + i); + + nbytes -= bsize; + if (nbytes < bsize) + goto done; + + *dst ^= *(src - 1); + src -= 1; + dst -= 1; + } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + for (;;) { + __cast5_decrypt(ctx, (u8 *)dst, (u8 *)src); + + nbytes -= bsize; + if (nbytes < bsize) + break; + + *dst ^= *(src - 1); + src -= 1; + dst -= 1; + } + +done: + *dst ^= *(u64 *)walk->iv; + *(u64 *)walk->iv = last_iv; + + return nbytes; +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + bool fpu_enabled = false; + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt(desc, &walk); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + while ((nbytes = walk.nbytes)) { + fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes); + nbytes = __cbc_decrypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + cast5_fpu_end(fpu_enabled); + return err; +} + +static void ctr_crypt_final(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + u8 *ctrblk = walk->iv; + u8 keystream[CAST5_BLOCK_SIZE]; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + unsigned int nbytes = walk->nbytes; + + __cast5_encrypt(ctx, keystream, ctrblk); + crypto_xor(keystream, src, nbytes); + memcpy(dst, keystream, nbytes); + + crypto_inc(ctrblk, CAST5_BLOCK_SIZE); +} + +static unsigned int __ctr_crypt(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) +{ + struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + const unsigned int bsize = CAST5_BLOCK_SIZE; + unsigned int nbytes = walk->nbytes; + u64 *src = (u64 *)walk->src.virt.addr; + u64 *dst = (u64 *)walk->dst.virt.addr; + u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); + __be64 ctrblocks[CAST5_PARALLEL_BLOCKS]; + int i; + + /* Process multi-block batch */ + if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + do { + /* create ctrblks for parallel encrypt */ + for (i = 0; i < CAST5_PARALLEL_BLOCKS; i++) { + if (dst != src) + dst[i] = src[i]; + + ctrblocks[i] = cpu_to_be64(ctrblk++); + } + + cast5_enc_blk_xway_xor(ctx, (u8 *)dst, + (u8 *)ctrblocks); + + src += CAST5_PARALLEL_BLOCKS; + dst += CAST5_PARALLEL_BLOCKS; + nbytes -= bsize * CAST5_PARALLEL_BLOCKS; + } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS); + + if (nbytes < bsize) + goto done; + } + + /* Handle leftovers */ + do { + if (dst != src) + *dst = *src; + + ctrblocks[0] = cpu_to_be64(ctrblk++); + + __cast5_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); + *dst ^= ctrblocks[0]; + + src += 1; + dst += 1; + nbytes -= bsize; + } while (nbytes >= bsize); + +done: + *(__be64 *)walk->iv = cpu_to_be64(ctrblk); + return nbytes; +} + +static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + bool fpu_enabled = false; + struct blkcipher_walk walk; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, CAST5_BLOCK_SIZE); + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + + while ((nbytes = walk.nbytes) >= CAST5_BLOCK_SIZE) { + fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes); + nbytes = __ctr_crypt(desc, &walk); + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + cast5_fpu_end(fpu_enabled); + + if (walk.nbytes) { + ctr_crypt_final(desc, &walk); + err = blkcipher_walk_done(desc, &walk, 0); + } + + return err; +} + + +static struct crypto_alg cast5_algs[6] = { { + .cra_name = "__ecb-cast5-avx", + .cra_driver_name = "__driver-ecb-cast5-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .setkey = cast5_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "__cbc-cast5-avx", + .cra_driver_name = "__driver-cbc-cast5-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .setkey = cast5_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "__ctr-cast5-avx", + .cra_driver_name = "__driver-ctr-cast5-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .ivsize = CAST5_BLOCK_SIZE, + .setkey = cast5_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "ecb(cast5)", + .cra_driver_name = "ecb-cast5-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "cbc(cast5)", + .cra_driver_name = "cbc-cast5-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .ivsize = CAST5_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = __ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "ctr(cast5)", + .cra_driver_name = "ctr-cast5-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST5_MIN_KEY_SIZE, + .max_keysize = CAST5_MAX_KEY_SIZE, + .ivsize = CAST5_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_encrypt, + .geniv = "chainiv", + }, + }, +} }; + +static int __init cast5_init(void) +{ + u64 xcr0; + + if (!cpu_has_avx || !cpu_has_osxsave) { + pr_info("AVX instructions are not detected.\n"); + return -ENODEV; + } + + xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) { + pr_info("AVX detected but unusable.\n"); + return -ENODEV; + } + + return crypto_register_algs(cast5_algs, ARRAY_SIZE(cast5_algs)); +} + +static void __exit cast5_exit(void) +{ + crypto_unregister_algs(cast5_algs, ARRAY_SIZE(cast5_algs)); +} + +module_init(cast5_init); +module_exit(cast5_exit); + +MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("cast5"); diff --git a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S new file mode 100644 index 000000000000..218d283772f4 --- /dev/null +++ b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S @@ -0,0 +1,383 @@ +/* + * Cast6 Cipher 8-way parallel algorithm (AVX/x86_64) + * + * Copyright (C) 2012 Johannes Goetzfried + * <Johannes.Goetzfried@informatik.stud.uni-erlangen.de> + * + * Copyright © 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 "cast6-avx-x86_64-asm_64.S" + +.extern cast6_s1 +.extern cast6_s2 +.extern cast6_s3 +.extern cast6_s4 + +/* structure of crypto context */ +#define km 0 +#define kr (12*4*4) + +/* s-boxes */ +#define s1 cast6_s1 +#define s2 cast6_s2 +#define s3 cast6_s3 +#define s4 cast6_s4 + +/********************************************************************** + 8-way AVX cast6 + **********************************************************************/ +#define CTX %rdi + +#define RA1 %xmm0 +#define RB1 %xmm1 +#define RC1 %xmm2 +#define RD1 %xmm3 + +#define RA2 %xmm4 +#define RB2 %xmm5 +#define RC2 %xmm6 +#define RD2 %xmm7 + +#define RX %xmm8 + +#define RKM %xmm9 +#define RKR %xmm10 +#define RKRF %xmm11 +#define RKRR %xmm12 +#define R32 %xmm13 +#define R1ST %xmm14 + +#define RTMP %xmm15 + +#define RID1 %rbp +#define RID1d %ebp +#define RID2 %rsi +#define RID2d %esi + +#define RGI1 %rdx +#define RGI1bl %dl +#define RGI1bh %dh +#define RGI2 %rcx +#define RGI2bl %cl +#define RGI2bh %ch + +#define RGI3 %rax +#define RGI3bl %al +#define RGI3bh %ah +#define RGI4 %rbx +#define RGI4bl %bl +#define RGI4bh %bh + +#define RFS1 %r8 +#define RFS1d %r8d +#define RFS2 %r9 +#define RFS2d %r9d +#define RFS3 %r10 +#define RFS3d %r10d + + +#define lookup_32bit(src, dst, op1, op2, op3, interleave_op, il_reg) \ + movzbl src ## bh, RID1d; \ + movzbl src ## bl, RID2d; \ + shrq $16, src; \ + movl s1(, RID1, 4), dst ## d; \ + op1 s2(, RID2, 4), dst ## d; \ + movzbl src ## bh, RID1d; \ + movzbl src ## bl, RID2d; \ + interleave_op(il_reg); \ + op2 s3(, RID1, 4), dst ## d; \ + op3 s4(, RID2, 4), dst ## d; + +#define dummy(d) /* do nothing */ + +#define shr_next(reg) \ + shrq $16, reg; + +#define F_head(a, x, gi1, gi2, op0) \ + op0 a, RKM, x; \ + vpslld RKRF, x, RTMP; \ + vpsrld RKRR, x, x; \ + vpor RTMP, x, x; \ + \ + vmovq x, gi1; \ + vpextrq $1, x, gi2; + +#define F_tail(a, x, gi1, gi2, op1, op2, op3) \ + lookup_32bit(##gi1, RFS1, op1, op2, op3, shr_next, ##gi1); \ + lookup_32bit(##gi2, RFS3, op1, op2, op3, shr_next, ##gi2); \ + \ + lookup_32bit(##gi1, RFS2, op1, op2, op3, dummy, none); \ + shlq $32, RFS2; \ + orq RFS1, RFS2; \ + lookup_32bit(##gi2, RFS1, op1, op2, op3, dummy, none); \ + shlq $32, RFS1; \ + orq RFS1, RFS3; \ + \ + vmovq RFS2, x; \ + vpinsrq $1, RFS3, x, x; + +#define F_2(a1, b1, a2, b2, op0, op1, op2, op3) \ + F_head(b1, RX, RGI1, RGI2, op0); \ + F_head(b2, RX, RGI3, RGI4, op0); \ + \ + F_tail(b1, RX, RGI1, RGI2, op1, op2, op3); \ + F_tail(b2, RTMP, RGI3, RGI4, op1, op2, op3); \ + \ + vpxor a1, RX, a1; \ + vpxor a2, RTMP, a2; + +#define F1_2(a1, b1, a2, b2) \ + F_2(a1, b1, a2, b2, vpaddd, xorl, subl, addl) +#define F2_2(a1, b1, a2, b2) \ + F_2(a1, b1, a2, b2, vpxor, subl, addl, xorl) +#define F3_2(a1, b1, a2, b2) \ + F_2(a1, b1, a2, b2, vpsubd, addl, xorl, subl) + +#define qop(in, out, f) \ + F ## f ## _2(out ## 1, in ## 1, out ## 2, in ## 2); + +#define get_round_keys(nn) \ + vbroadcastss (km+(4*(nn)))(CTX), RKM; \ + vpand R1ST, RKR, RKRF; \ + vpsubq RKRF, R32, RKRR; \ + vpsrldq $1, RKR, RKR; + +#define Q(n) \ + get_round_keys(4*n+0); \ + qop(RD, RC, 1); \ + \ + get_round_keys(4*n+1); \ + qop(RC, RB, 2); \ + \ + get_round_keys(4*n+2); \ + qop(RB, RA, 3); \ + \ + get_round_keys(4*n+3); \ + qop(RA, RD, 1); + +#define QBAR(n) \ + get_round_keys(4*n+3); \ + qop(RA, RD, 1); \ + \ + get_round_keys(4*n+2); \ + qop(RB, RA, 3); \ + \ + get_round_keys(4*n+1); \ + qop(RC, RB, 2); \ + \ + get_round_keys(4*n+0); \ + qop(RD, RC, 1); + +#define shuffle(mask) \ + vpshufb mask, RKR, RKR; + +#define preload_rkr(n, do_mask, mask) \ + vbroadcastss .L16_mask, RKR; \ + /* add 16-bit rotation to key rotations (mod 32) */ \ + vpxor (kr+n*16)(CTX), RKR, RKR; \ + do_mask(mask); + +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ + vpunpckldq x1, x0, t0; \ + vpunpckhdq x1, x0, t2; \ + vpunpckldq x3, x2, t1; \ + vpunpckhdq x3, x2, x3; \ + \ + vpunpcklqdq t1, t0, x0; \ + vpunpckhqdq t1, t0, x1; \ + vpunpcklqdq x3, t2, x2; \ + vpunpckhqdq x3, t2, x3; + +#define inpack_blocks(in, x0, x1, x2, x3, t0, t1, t2, rmask) \ + vmovdqu (0*4*4)(in), x0; \ + vmovdqu (1*4*4)(in), x1; \ + vmovdqu (2*4*4)(in), x2; \ + vmovdqu (3*4*4)(in), x3; \ + vpshufb rmask, x0, x0; \ + vpshufb rmask, x1, x1; \ + vpshufb rmask, x2, x2; \ + vpshufb rmask, x3, x3; \ + \ + transpose_4x4(x0, x1, x2, x3, t0, t1, t2) + +#define outunpack_blocks(out, x0, x1, x2, x3, t0, t1, t2, rmask) \ + transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ + \ + vpshufb rmask, x0, x0; \ + vpshufb rmask, x1, x1; \ + vpshufb rmask, x2, x2; \ + vpshufb rmask, x3, x3; \ + vmovdqu x0, (0*4*4)(out); \ + vmovdqu x1, (1*4*4)(out); \ + vmovdqu x2, (2*4*4)(out); \ + vmovdqu x3, (3*4*4)(out); + +#define outunpack_xor_blocks(out, x0, x1, x2, x3, t0, t1, t2, rmask) \ + transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ + \ + vpshufb rmask, x0, x0; \ + vpshufb rmask, x1, x1; \ + vpshufb rmask, x2, x2; \ + vpshufb rmask, x3, x3; \ + vpxor (0*4*4)(out), x0, x0; \ + vmovdqu x0, (0*4*4)(out); \ + vpxor (1*4*4)(out), x1, x1; \ + vmovdqu x1, (1*4*4)(out); \ + vpxor (2*4*4)(out), x2, x2; \ + vmovdqu x2, (2*4*4)(out); \ + vpxor (3*4*4)(out), x3, x3; \ + vmovdqu x3, (3*4*4)(out); + +.data + +.align 16 +.Lbswap_mask: + .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 +.Lrkr_enc_Q_Q_QBAR_QBAR: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 11, 10, 9, 8, 15, 14, 13, 12 +.Lrkr_enc_QBAR_QBAR_QBAR_QBAR: + .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 +.Lrkr_dec_Q_Q_Q_Q: + .byte 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3 +.Lrkr_dec_Q_Q_QBAR_QBAR: + .byte 12, 13, 14, 15, 8, 9, 10, 11, 7, 6, 5, 4, 3, 2, 1, 0 +.Lrkr_dec_QBAR_QBAR_QBAR_QBAR: + .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +.L16_mask: + .byte 16, 16, 16, 16 +.L32_mask: + .byte 32, 0, 0, 0 +.Lfirst_mask: + .byte 0x1f, 0, 0, 0 + +.text + +.align 16 +.global __cast6_enc_blk_8way +.type __cast6_enc_blk_8way,@function; + +__cast6_enc_blk_8way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + * %rcx: bool, if true: xor output + */ + + pushq %rbp; + pushq %rbx; + pushq %rcx; + + vmovdqa .Lbswap_mask, RKM; + vmovd .Lfirst_mask, R1ST; + vmovd .L32_mask, R32; + + leaq (4*4*4)(%rdx), %rax; + inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); + inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + + movq %rsi, %r11; + + preload_rkr(0, dummy, none); + Q(0); + Q(1); + Q(2); + Q(3); + preload_rkr(1, shuffle, .Lrkr_enc_Q_Q_QBAR_QBAR); + Q(4); + Q(5); + QBAR(6); + QBAR(7); + preload_rkr(2, shuffle, .Lrkr_enc_QBAR_QBAR_QBAR_QBAR); + QBAR(8); + QBAR(9); + QBAR(10); + QBAR(11); + + popq %rcx; + popq %rbx; + popq %rbp; + + vmovdqa .Lbswap_mask, RKM; + leaq (4*4*4)(%r11), %rax; + + testb %cl, %cl; + jnz __enc_xor8; + + outunpack_blocks(%r11, RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); + outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + + ret; + +__enc_xor8: + outunpack_xor_blocks(%r11, RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); + outunpack_xor_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + + ret; + +.align 16 +.global cast6_dec_blk_8way +.type cast6_dec_blk_8way,@function; + +cast6_dec_blk_8way: + /* input: + * %rdi: ctx, CTX + * %rsi: dst + * %rdx: src + */ + + pushq %rbp; + pushq %rbx; + + vmovdqa .Lbswap_mask, RKM; + vmovd .Lfirst_mask, R1ST; + vmovd .L32_mask, R32; + + leaq (4*4*4)(%rdx), %rax; + inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); + inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + + movq %rsi, %r11; + + preload_rkr(2, shuffle, .Lrkr_dec_Q_Q_Q_Q); + Q(11); + Q(10); + Q(9); + Q(8); + preload_rkr(1, shuffle, .Lrkr_dec_Q_Q_QBAR_QBAR); + Q(7); + Q(6); + QBAR(5); + QBAR(4); + preload_rkr(0, shuffle, .Lrkr_dec_QBAR_QBAR_QBAR_QBAR); + QBAR(3); + QBAR(2); + QBAR(1); + QBAR(0); + + popq %rbx; + popq %rbp; + + vmovdqa .Lbswap_mask, RKM; + leaq (4*4*4)(%r11), %rax; + outunpack_blocks(%r11, RA1, RB1, RC1, RD1, RTMP, RX, RKRF, RKM); + outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKRF, RKM); + + ret; diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c new file mode 100644 index 000000000000..15e5f85a5011 --- /dev/null +++ b/arch/x86/crypto/cast6_avx_glue.c @@ -0,0 +1,648 @@ +/* + * Glue Code for the AVX assembler implemention of the Cast6 Cipher + * + * Copyright (C) 2012 Johannes Goetzfried + * <Johannes.Goetzfried@informatik.stud.uni-erlangen.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +#include <linux/module.h> +#include <linux/hardirq.h> +#include <linux/types.h> +#include <linux/crypto.h> +#include <linux/err.h> +#include <crypto/algapi.h> +#include <crypto/cast6.h> +#include <crypto/cryptd.h> +#include <crypto/b128ops.h> +#include <crypto/ctr.h> +#include <crypto/lrw.h> +#include <crypto/xts.h> +#include <asm/xcr.h> +#include <asm/xsave.h> +#include <asm/crypto/ablk_helper.h> +#include <asm/crypto/glue_helper.h> + +#define CAST6_PARALLEL_BLOCKS 8 + +asmlinkage void __cast6_enc_blk_8way(struct cast6_ctx *ctx, u8 *dst, + const u8 *src, bool xor); +asmlinkage void cast6_dec_blk_8way(struct cast6_ctx *ctx, u8 *dst, + const u8 *src); + +static inline void cast6_enc_blk_xway(struct cast6_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast6_enc_blk_8way(ctx, dst, src, false); +} + +static inline void cast6_enc_blk_xway_xor(struct cast6_ctx *ctx, u8 *dst, + const u8 *src) +{ + __cast6_enc_blk_8way(ctx, dst, src, true); +} + +static inline void cast6_dec_blk_xway(struct cast6_ctx *ctx, u8 *dst, + const u8 *src) +{ + cast6_dec_blk_8way(ctx, dst, src); +} + + +static void cast6_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src) +{ + u128 ivs[CAST6_PARALLEL_BLOCKS - 1]; + unsigned int j; + + for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++) + ivs[j] = src[j]; + + cast6_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); + + for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++) + u128_xor(dst + (j + 1), dst + (j + 1), ivs + j); +} + +static void cast6_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv) +{ + be128 ctrblk; + + u128_to_be128(&ctrblk, iv); + u128_inc(iv); + + __cast6_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk); + u128_xor(dst, src, (u128 *)&ctrblk); +} + +static void cast6_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src, + u128 *iv) +{ + be128 ctrblks[CAST6_PARALLEL_BLOCKS]; + unsigned int i; + + for (i = 0; i < CAST6_PARALLEL_BLOCKS; i++) { + if (dst != src) + dst[i] = src[i]; + + u128_to_be128(&ctrblks[i], iv); + u128_inc(iv); + } + + cast6_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks); +} + +static const struct common_glue_ctx cast6_enc = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .ecb = GLUE_FUNC_CAST(cast6_enc_blk_xway) } + }, { + .num_blocks = 1, + .fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_encrypt) } + } } +}; + +static const struct common_glue_ctx cast6_ctr = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr_xway) } + }, { + .num_blocks = 1, + .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr) } + } } +}; + +static const struct common_glue_ctx cast6_dec = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .ecb = GLUE_FUNC_CAST(cast6_dec_blk_xway) } + }, { + .num_blocks = 1, + .fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_decrypt) } + } } +}; + +static const struct common_glue_ctx cast6_dec_cbc = { + .num_funcs = 2, + .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS, + + .funcs = { { + .num_blocks = CAST6_PARALLEL_BLOCKS, + .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(cast6_decrypt_cbc_xway) } + }, { + .num_blocks = 1, + .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__cast6_decrypt) } + } } +}; + +static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_ecb_crypt_128bit(&cast6_enc, desc, dst, src, nbytes); +} + +static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_ecb_crypt_128bit(&cast6_dec, desc, dst, src, nbytes); +} + +static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__cast6_encrypt), desc, + dst, src, nbytes); +} + +static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_cbc_decrypt_128bit(&cast6_dec_cbc, desc, dst, src, + nbytes); +} + +static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + return glue_ctr_crypt_128bit(&cast6_ctr, desc, dst, src, nbytes); +} + +static inline bool cast6_fpu_begin(bool fpu_enabled, unsigned int nbytes) +{ + return glue_fpu_begin(CAST6_BLOCK_SIZE, CAST6_PARALLEL_BLOCKS, + NULL, fpu_enabled, nbytes); +} + +static inline void cast6_fpu_end(bool fpu_enabled) +{ + glue_fpu_end(fpu_enabled); +} + +struct crypt_priv { + struct cast6_ctx *ctx; + bool fpu_enabled; +}; + +static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAST6_BLOCK_SIZE; + struct crypt_priv *ctx = priv; + int i; + + ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes); + + if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) { + cast6_enc_blk_xway(ctx->ctx, srcdst, srcdst); + return; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + __cast6_encrypt(ctx->ctx, srcdst, srcdst); +} + +static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = CAST6_BLOCK_SIZE; + struct crypt_priv *ctx = priv; + int i; + + ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes); + + if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) { + cast6_dec_blk_xway(ctx->ctx, srcdst, srcdst); + return; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + __cast6_decrypt(ctx->ctx, srcdst, srcdst); +} + +struct cast6_lrw_ctx { + struct lrw_table_ctx lrw_table; + struct cast6_ctx cast6_ctx; +}; + +static int lrw_cast6_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + err = __cast6_setkey(&ctx->cast6_ctx, key, keylen - CAST6_BLOCK_SIZE, + &tfm->crt_flags); + if (err) + return err; + + return lrw_init_table(&ctx->lrw_table, key + keylen - CAST6_BLOCK_SIZE); +} + +static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->cast6_ctx, + .fpu_enabled = false, + }; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &crypt_ctx, + .crypt_fn = encrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = lrw_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->cast6_ctx, + .fpu_enabled = false, + }; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &crypt_ctx, + .crypt_fn = decrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = lrw_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static void lrw_exit_tfm(struct crypto_tfm *tfm) +{ + struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + + lrw_free_table(&ctx->lrw_table); +} + +struct cast6_xts_ctx { + struct cast6_ctx tweak_ctx; + struct cast6_ctx crypt_ctx; +}; + +static int xts_cast6_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct cast6_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 = __cast6_setkey(&ctx->crypt_ctx, key, keylen / 2, flags); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return __cast6_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 cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->crypt_ctx, + .fpu_enabled = false, + }; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt), + .crypt_ctx = &crypt_ctx, + .crypt_fn = encrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = xts_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[CAST6_PARALLEL_BLOCKS]; + struct crypt_priv crypt_ctx = { + .ctx = &ctx->crypt_ctx, + .fpu_enabled = false, + }; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt), + .crypt_ctx = &crypt_ctx, + .crypt_fn = decrypt_callback, + }; + int ret; + + desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; + ret = xts_crypt(desc, dst, src, nbytes, &req); + cast6_fpu_end(crypt_ctx.fpu_enabled); + + return ret; +} + +static struct crypto_alg cast6_algs[10] = { { + .cra_name = "__ecb-cast6-avx", + .cra_driver_name = "__driver-ecb-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .setkey = cast6_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}, { + .cra_name = "__cbc-cast6-avx", + .cra_driver_name = "__driver-cbc-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .setkey = cast6_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}, { + .cra_name = "__ctr-cast6-avx", + .cra_driver_name = "__driver-ctr-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct cast6_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = cast6_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}, { + .cra_name = "__lrw-cast6-avx", + .cra_driver_name = "__driver-lrw-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE + + CAST6_BLOCK_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE + + CAST6_BLOCK_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = lrw_cast6_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}, { + .cra_name = "__xts-cast6-avx", + .cra_driver_name = "__driver-xts-cast6-avx", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast6_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE * 2, + .max_keysize = CAST6_MAX_KEY_SIZE * 2, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = xts_cast6_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}, { + .cra_name = "ecb(cast6)", + .cra_driver_name = "ecb-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "cbc(cast6)", + .cra_driver_name = "cbc-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = __ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "ctr(cast6)", + .cra_driver_name = "ctr-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_encrypt, + .geniv = "chainiv", + }, + }, +}, { + .cra_name = "lrw(cast6)", + .cra_driver_name = "lrw-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE + + CAST6_BLOCK_SIZE, + .max_keysize = CAST6_MAX_KEY_SIZE + + CAST6_BLOCK_SIZE, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +}, { + .cra_name = "xts(cast6)", + .cra_driver_name = "xts-cast6-avx", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = CAST6_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct async_helper_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = ablk_init, + .cra_exit = ablk_exit, + .cra_u = { + .ablkcipher = { + .min_keysize = CAST6_MIN_KEY_SIZE * 2, + .max_keysize = CAST6_MAX_KEY_SIZE * 2, + .ivsize = CAST6_BLOCK_SIZE, + .setkey = ablk_set_key, + .encrypt = ablk_encrypt, + .decrypt = ablk_decrypt, + }, + }, +} }; + +static int __init cast6_init(void) +{ + u64 xcr0; + + if (!cpu_has_avx || !cpu_has_osxsave) { + pr_info("AVX instructions are not detected.\n"); + return -ENODEV; + } + + xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) { + pr_info("AVX detected but unusable.\n"); + return -ENODEV; + } + + return crypto_register_algs(cast6_algs, ARRAY_SIZE(cast6_algs)); +} + +static void __exit cast6_exit(void) +{ + crypto_unregister_algs(cast6_algs, ARRAY_SIZE(cast6_algs)); +} + +module_init(cast6_init); +module_exit(cast6_exit); + +MODULE_DESCRIPTION("Cast6 Cipher Algorithm, AVX optimized"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("cast6"); diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index b4bf0a63b520..6759dd1135be 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -150,7 +150,6 @@ static struct shash_alg ghash_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_ctxsize = sizeof(struct ghash_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), }, }; @@ -288,7 +287,6 @@ static struct ahash_alg ghash_async_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_type = &crypto_ahash_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list), .cra_init = ghash_async_init_tfm, .cra_exit = ghash_async_exit_tfm, }, diff --git a/arch/x86/crypto/glue_helper.c b/arch/x86/crypto/glue_helper.c index 4854f0f31e4f..30b3927bd733 100644 --- a/arch/x86/crypto/glue_helper.c +++ b/arch/x86/crypto/glue_helper.c @@ -110,7 +110,7 @@ static unsigned int __glue_cbc_encrypt_128bit(const common_glue_func_t fn, nbytes -= bsize; } while (nbytes >= bsize); - u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); + *(u128 *)walk->iv = *iv; return nbytes; } diff --git a/arch/x86/crypto/salsa20_glue.c b/arch/x86/crypto/salsa20_glue.c index bccb76d80987..a3a3c0205c16 100644 --- a/arch/x86/crypto/salsa20_glue.c +++ b/arch/x86/crypto/salsa20_glue.c @@ -97,7 +97,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct salsa20_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .blkcipher = { .setkey = setkey, diff --git a/arch/x86/crypto/serpent_avx_glue.c b/arch/x86/crypto/serpent_avx_glue.c index b36bdac237eb..3f543a04cf1e 100644 --- a/arch/x86/crypto/serpent_avx_glue.c +++ b/arch/x86/crypto/serpent_avx_glue.c @@ -390,7 +390,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -410,7 +409,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -430,7 +428,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -451,7 +448,6 @@ static struct crypto_alg serpent_algs[10] = { { .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 = { @@ -475,7 +471,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -496,7 +491,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -518,7 +512,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -541,7 +534,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -565,7 +557,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -590,7 +581,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index d679c8675f4a..9107a9908c41 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -393,7 +393,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -413,7 +412,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -433,7 +431,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -454,7 +451,6 @@ static struct crypto_alg serpent_algs[10] = { { .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 = { @@ -478,7 +474,6 @@ static struct crypto_alg serpent_algs[10] = { { .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, @@ -499,7 +494,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -521,7 +515,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -544,7 +537,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -568,7 +560,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -593,7 +584,6 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { diff --git a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S index 35f45574390d..1585abb13dde 100644 --- a/arch/x86/crypto/twofish-avx-x86_64-asm_64.S +++ b/arch/x86/crypto/twofish-avx-x86_64-asm_64.S @@ -4,6 +4,8 @@ * Copyright (C) 2012 Johannes Goetzfried * <Johannes.Goetzfried@informatik.stud.uni-erlangen.de> * + * Copyright © 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 @@ -47,16 +49,22 @@ #define RC2 %xmm6 #define RD2 %xmm7 -#define RX %xmm8 -#define RY %xmm9 +#define RX0 %xmm8 +#define RY0 %xmm9 + +#define RX1 %xmm10 +#define RY1 %xmm11 -#define RK1 %xmm10 -#define RK2 %xmm11 +#define RK1 %xmm12 +#define RK2 %xmm13 -#define RID1 %rax -#define RID1b %al -#define RID2 %rbx -#define RID2b %bl +#define RT %xmm14 +#define RR %xmm15 + +#define RID1 %rbp +#define RID1d %ebp +#define RID2 %rsi +#define RID2d %esi #define RGI1 %rdx #define RGI1bl %dl @@ -65,6 +73,13 @@ #define RGI2bl %cl #define RGI2bh %ch +#define RGI3 %rax +#define RGI3bl %al +#define RGI3bh %ah +#define RGI4 %rbx +#define RGI4bl %bl +#define RGI4bh %bh + #define RGS1 %r8 #define RGS1d %r8d #define RGS2 %r9 @@ -73,89 +88,123 @@ #define RGS3d %r10d -#define lookup_32bit(t0, t1, t2, t3, src, dst) \ - movb src ## bl, RID1b; \ - movb src ## bh, RID2b; \ - movl t0(CTX, RID1, 4), dst ## d; \ - xorl t1(CTX, RID2, 4), dst ## d; \ +#define lookup_32bit(t0, t1, t2, t3, src, dst, interleave_op, il_reg) \ + movzbl src ## bl, RID1d; \ + movzbl src ## bh, RID2d; \ shrq $16, src; \ - movb src ## bl, RID1b; \ - movb src ## bh, RID2b; \ + movl t0(CTX, RID1, 4), dst ## d; \ + movl t1(CTX, RID2, 4), RID2d; \ + movzbl src ## bl, RID1d; \ + xorl RID2d, dst ## d; \ + movzbl src ## bh, RID2d; \ + interleave_op(il_reg); \ xorl t2(CTX, RID1, 4), dst ## d; \ xorl t3(CTX, RID2, 4), dst ## d; -#define G(a, x, t0, t1, t2, t3) \ - vmovq a, RGI1; \ - vpsrldq $8, a, x; \ - vmovq x, RGI2; \ +#define dummy(d) /* do nothing */ + +#define shr_next(reg) \ + shrq $16, reg; + +#define G(gi1, gi2, x, t0, t1, t2, t3) \ + lookup_32bit(t0, t1, t2, t3, ##gi1, RGS1, shr_next, ##gi1); \ + lookup_32bit(t0, t1, t2, t3, ##gi2, RGS3, shr_next, ##gi2); \ + \ + lookup_32bit(t0, t1, t2, t3, ##gi1, RGS2, dummy, none); \ + shlq $32, RGS2; \ + orq RGS1, RGS2; \ + lookup_32bit(t0, t1, t2, t3, ##gi2, RGS1, dummy, none); \ + shlq $32, RGS1; \ + orq RGS1, RGS3; + +#define round_head_2(a, b, x1, y1, x2, y2) \ + vmovq b ## 1, RGI3; \ + vpextrq $1, b ## 1, RGI4; \ \ - lookup_32bit(t0, t1, t2, t3, RGI1, RGS1); \ - shrq $16, RGI1; \ - lookup_32bit(t0, t1, t2, t3, RGI1, RGS2); \ - shlq $32, RGS2; \ - orq RGS1, RGS2; \ + G(RGI1, RGI2, x1, s0, s1, s2, s3); \ + vmovq a ## 2, RGI1; \ + vpextrq $1, a ## 2, RGI2; \ + vmovq RGS2, x1; \ + vpinsrq $1, RGS3, x1, x1; \ \ - lookup_32bit(t0, t1, t2, t3, RGI2, RGS1); \ - shrq $16, RGI2; \ - lookup_32bit(t0, t1, t2, t3, RGI2, RGS3); \ - shlq $32, RGS3; \ - orq RGS1, RGS3; \ + G(RGI3, RGI4, y1, s1, s2, s3, s0); \ + vmovq b ## 2, RGI3; \ + vpextrq $1, b ## 2, RGI4; \ + vmovq RGS2, y1; \ + vpinsrq $1, RGS3, y1, y1; \ \ - vmovq RGS2, x; \ - vpinsrq $1, RGS3, x, x; + G(RGI1, RGI2, x2, s0, s1, s2, s3); \ + vmovq RGS2, x2; \ + vpinsrq $1, RGS3, x2, x2; \ + \ + G(RGI3, RGI4, y2, s1, s2, s3, s0); \ + vmovq RGS2, y2; \ + vpinsrq $1, RGS3, y2, y2; -#define encround(a, b, c, d, x, y) \ - G(a, x, s0, s1, s2, s3); \ - G(b, y, s1, s2, s3, s0); \ +#define encround_tail(a, b, c, d, x, y, prerotate) \ vpaddd x, y, x; \ + vpaddd x, RK1, RT;\ + prerotate(b); \ + vpxor RT, c, c; \ vpaddd y, x, y; \ - vpaddd x, RK1, x; \ vpaddd y, RK2, y; \ - vpxor x, c, c; \ - vpsrld $1, c, x; \ + vpsrld $1, c, RT; \ vpslld $(32 - 1), c, c; \ - vpor c, x, c; \ - vpslld $1, d, x; \ - vpsrld $(32 - 1), d, d; \ - vpor d, x, d; \ - vpxor d, y, d; - -#define decround(a, b, c, d, x, y) \ - G(a, x, s0, s1, s2, s3); \ - G(b, y, s1, s2, s3, s0); \ + vpor c, RT, c; \ + vpxor d, y, d; \ + +#define decround_tail(a, b, c, d, x, y, prerotate) \ vpaddd x, y, x; \ + vpaddd x, RK1, RT;\ + prerotate(a); \ + vpxor RT, c, c; \ vpaddd y, x, y; \ vpaddd y, RK2, y; \ vpxor d, y, d; \ vpsrld $1, d, y; \ vpslld $(32 - 1), d, d; \ vpor d, y, d; \ - vpslld $1, c, y; \ - vpsrld $(32 - 1), c, c; \ - vpor c, y, c; \ - vpaddd x, RK1, x; \ - vpxor x, c, c; - -#define encrypt_round(n, a, b, c, d) \ - vbroadcastss (k+4*(2*(n)))(CTX), RK1; \ - vbroadcastss (k+4*(2*(n)+1))(CTX), RK2; \ - encround(a ## 1, b ## 1, c ## 1, d ## 1, RX, RY); \ - encround(a ## 2, b ## 2, c ## 2, d ## 2, RX, RY); - -#define decrypt_round(n, a, b, c, d) \ - vbroadcastss (k+4*(2*(n)))(CTX), RK1; \ - vbroadcastss (k+4*(2*(n)+1))(CTX), RK2; \ - decround(a ## 1, b ## 1, c ## 1, d ## 1, RX, RY); \ - decround(a ## 2, b ## 2, c ## 2, d ## 2, RX, RY); + +#define rotate_1l(x) \ + vpslld $1, x, RR; \ + vpsrld $(32 - 1), x, x; \ + vpor x, RR, x; + +#define preload_rgi(c) \ + vmovq c, RGI1; \ + vpextrq $1, c, RGI2; + +#define encrypt_round(n, a, b, c, d, preload, prerotate) \ + vbroadcastss (k+4*(2*(n)))(CTX), RK1; \ + vbroadcastss (k+4*(2*(n)+1))(CTX), RK2; \ + round_head_2(a, b, RX0, RY0, RX1, RY1); \ + encround_tail(a ## 1, b ## 1, c ## 1, d ## 1, RX0, RY0, prerotate); \ + preload(c ## 1); \ + encround_tail(a ## 2, b ## 2, c ## 2, d ## 2, RX1, RY1, prerotate); + +#define decrypt_round(n, a, b, c, d, preload, prerotate) \ + vbroadcastss (k+4*(2*(n)))(CTX), RK1; \ + vbroadcastss (k+4*(2*(n)+1))(CTX), RK2; \ + round_head_2(a, b, RX0, RY0, RX1, RY1); \ + decround_tail(a ## 1, b ## 1, c ## 1, d ## 1, RX0, RY0, prerotate); \ + preload(c ## 1); \ + decround_tail(a ## 2, b ## 2, c ## 2, d ## 2, RX1, RY1, prerotate); #define encrypt_cycle(n) \ - encrypt_round((2*n), RA, RB, RC, RD); \ - encrypt_round(((2*n) + 1), RC, RD, RA, RB); + encrypt_round((2*n), RA, RB, RC, RD, preload_rgi, rotate_1l); \ + encrypt_round(((2*n) + 1), RC, RD, RA, RB, preload_rgi, rotate_1l); + +#define encrypt_cycle_last(n) \ + encrypt_round((2*n), RA, RB, RC, RD, preload_rgi, rotate_1l); \ + encrypt_round(((2*n) + 1), RC, RD, RA, RB, dummy, dummy); #define decrypt_cycle(n) \ - decrypt_round(((2*n) + 1), RC, RD, RA, RB); \ - decrypt_round((2*n), RA, RB, RC, RD); + decrypt_round(((2*n) + 1), RC, RD, RA, RB, preload_rgi, rotate_1l); \ + decrypt_round((2*n), RA, RB, RC, RD, preload_rgi, rotate_1l); +#define decrypt_cycle_last(n) \ + decrypt_round(((2*n) + 1), RC, RD, RA, RB, preload_rgi, rotate_1l); \ + decrypt_round((2*n), RA, RB, RC, RD, dummy, dummy); #define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ vpunpckldq x1, x0, t0; \ @@ -216,17 +265,20 @@ __twofish_enc_blk_8way: * %rcx: bool, if true: xor output */ + pushq %rbp; pushq %rbx; pushq %rcx; vmovdqu w(CTX), RK1; leaq (4*4*4)(%rdx), %rax; - inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RK1, RX, RY, RK2); - inpack_blocks(%rax, RA2, RB2, RC2, RD2, RK1, RX, RY, RK2); + inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RK1, RX0, RY0, RK2); + preload_rgi(RA1); + rotate_1l(RD1); + inpack_blocks(%rax, RA2, RB2, RC2, RD2, RK1, RX0, RY0, RK2); + rotate_1l(RD2); - xorq RID1, RID1; - xorq RID2, RID2; + movq %rsi, %r11; encrypt_cycle(0); encrypt_cycle(1); @@ -235,26 +287,27 @@ __twofish_enc_blk_8way: encrypt_cycle(4); encrypt_cycle(5); encrypt_cycle(6); - encrypt_cycle(7); + encrypt_cycle_last(7); vmovdqu (w+4*4)(CTX), RK1; popq %rcx; popq %rbx; + popq %rbp; - leaq (4*4*4)(%rsi), %rax; + leaq (4*4*4)(%r11), %rax; testb %cl, %cl; jnz __enc_xor8; - outunpack_blocks(%rsi, RC1, RD1, RA1, RB1, RK1, RX, RY, RK2); - outunpack_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX, RY, RK2); + outunpack_blocks(%r11, RC1, RD1, RA1, RB1, RK1, RX0, RY0, RK2); + outunpack_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX0, RY0, RK2); ret; __enc_xor8: - outunpack_xor_blocks(%rsi, RC1, RD1, RA1, RB1, RK1, RX, RY, RK2); - outunpack_xor_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX, RY, RK2); + outunpack_xor_blocks(%r11, RC1, RD1, RA1, RB1, RK1, RX0, RY0, RK2); + outunpack_xor_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX0, RY0, RK2); ret; @@ -269,16 +322,19 @@ twofish_dec_blk_8way: * %rdx: src */ + pushq %rbp; pushq %rbx; vmovdqu (w+4*4)(CTX), RK1; leaq (4*4*4)(%rdx), %rax; - inpack_blocks(%rdx, RC1, RD1, RA1, RB1, RK1, RX, RY, RK2); - inpack_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX, RY, RK2); + inpack_blocks(%rdx, RC1, RD1, RA1, RB1, RK1, RX0, RY0, RK2); + preload_rgi(RC1); + rotate_1l(RA1); + inpack_blocks(%rax, RC2, RD2, RA2, RB2, RK1, RX0, RY0, RK2); + rotate_1l(RA2); - xorq RID1, RID1; - xorq RID2, RID2; + movq %rsi, %r11; decrypt_cycle(7); decrypt_cycle(6); @@ -287,14 +343,15 @@ twofish_dec_blk_8way: decrypt_cycle(3); decrypt_cycle(2); decrypt_cycle(1); - decrypt_cycle(0); + decrypt_cycle_last(0); vmovdqu (w)(CTX), RK1; popq %rbx; + popq %rbp; - leaq (4*4*4)(%rsi), %rax; - outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RK1, RX, RY, RK2); - outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RK1, RX, RY, RK2); + leaq (4*4*4)(%r11), %rax; + outunpack_blocks(%r11, RA1, RB1, RC1, RD1, RK1, RX0, RY0, RK2); + outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RK1, RX0, RY0, RK2); ret; diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c index 782b67ddaf6a..e7708b5442e0 100644 --- a/arch/x86/crypto/twofish_avx_glue.c +++ b/arch/x86/crypto/twofish_avx_glue.c @@ -378,7 +378,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[0].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -398,7 +397,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[1].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -418,7 +416,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[2].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE, @@ -439,7 +436,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[3].cra_list), .cra_exit = lrw_twofish_exit_tfm, .cra_u = { .blkcipher = { @@ -463,7 +459,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, @@ -484,7 +479,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[5].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -506,7 +500,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[6].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -529,7 +522,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[7].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -553,7 +545,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[8].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { @@ -578,7 +569,6 @@ static struct crypto_alg twofish_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(twofish_algs[9].cra_list), .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c index 359ae084275c..0a5202303501 100644 --- a/arch/x86/crypto/twofish_glue.c +++ b/arch/x86/crypto/twofish_glue.c @@ -70,7 +70,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct twofish_ctx), .cra_alignmask = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = TF_MIN_KEY_SIZE, diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 15f9347316c8..aa3eb358b7e8 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -342,7 +342,6 @@ static struct crypto_alg tf_algs[5] = { { .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, @@ -362,7 +361,6 @@ static struct crypto_alg tf_algs[5] = { { .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, @@ -383,7 +381,6 @@ static struct crypto_alg tf_algs[5] = { { .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, @@ -404,7 +401,6 @@ static struct crypto_alg tf_algs[5] = { { .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_twofish_exit_tfm, .cra_u = { .blkcipher = { @@ -426,7 +422,6 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index f34261296ffb..338803422239 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -409,7 +409,7 @@ extern struct apic *apic; * to enforce the order with in them. */ #define apic_driver(sym) \ - static struct apic *__apicdrivers_##sym __used \ + static const struct apic *__apicdrivers_##sym __used \ __aligned(sizeof(struct apic *)) \ __section(.apicdrivers) = { &sym } diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index fedf32b73e65..59c6c401f79f 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -41,6 +41,7 @@ typedef s64 __attribute__((aligned(4))) compat_s64; typedef u32 compat_uint_t; typedef u32 compat_ulong_t; typedef u64 __attribute__((aligned(4))) compat_u64; +typedef u32 compat_uptr_t; struct compat_timespec { compat_time_t tv_sec; @@ -124,6 +125,78 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ typedef u32 compat_sigset_word; +typedef union compat_sigval { + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[128/sizeof(int) - 3]; + + /* kill() */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + compat_timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + compat_sigval_t _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + int _overrun_incr; /* amount to add to overrun */ + } _timer; + + /* POSIX.1b signals */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + unsigned int _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGCHLD (x32 version) */ + struct { + unsigned int _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_s64 _utime; + compat_s64 _stime; + } _sigchld_x32; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + unsigned int _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + + struct { + unsigned int _call_addr; /* calling insn */ + int _syscall; /* triggering system call number */ + unsigned int _arch; /* AUDIT_ARCH_* of syscall */ + } _sigsys; + } _sifields; +} compat_siginfo_t; + #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL @@ -209,7 +282,6 @@ typedef struct user_regs_struct32 compat_elf_gregset_t; * as pointers because the syscall entry code will have * appropriately converted them already. */ -typedef u32 compat_uptr_t; static inline void __user *compat_ptr(compat_uptr_t uptr) { diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h index b04cbdb138cd..e6232773ce49 100644 --- a/arch/x86/include/asm/ia32.h +++ b/arch/x86/include/asm/ia32.h @@ -86,73 +86,6 @@ struct stat64 { unsigned long long st_ino; } __attribute__((packed)); -typedef struct compat_siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[((128 / sizeof(int)) - 3)]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - compat_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - compat_sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - int _overrun_incr; /* amount to add to overrun */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - compat_sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGCHLD (x32 version) */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_s64 _utime; - compat_s64 _stime; - } _sigchld_x32; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - struct { - unsigned int _call_addr; /* calling insn */ - int _syscall; /* triggering system call number */ - unsigned int _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} compat_siginfo_t; - #define IA32_STACK_TOP IA32_PAGE_OFFSET #ifdef __KERNEL__ diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index 41e08cb6a092..a65ec29e6ffb 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -41,6 +41,7 @@ #define __KVM_HAVE_DEBUGREGS #define __KVM_HAVE_XSAVE #define __KVM_HAVE_XCRS +#define __KVM_HAVE_READONLY_MEM /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index c764f43b71c5..15f960c06ff7 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -86,6 +86,19 @@ struct x86_instruction_info { struct x86_emulate_ops { /* + * read_gpr: read a general purpose register (rax - r15) + * + * @reg: gpr number. + */ + ulong (*read_gpr)(struct x86_emulate_ctxt *ctxt, unsigned reg); + /* + * write_gpr: write a general purpose register (rax - r15) + * + * @reg: gpr number. + * @val: value to write. + */ + void (*write_gpr)(struct x86_emulate_ctxt *ctxt, unsigned reg, ulong val); + /* * read_std: Read bytes of standard (non-emulated/special) memory. * Used for descriptor reading. * @addr: [IN ] Linear address from which to read. @@ -200,8 +213,9 @@ typedef u32 __attribute__((vector_size(16))) sse128_t; /* Type, address-of, and value of an instruction's operand. */ struct operand { - enum { OP_REG, OP_MEM, OP_IMM, OP_XMM, OP_MM, OP_NONE } type; + enum { OP_REG, OP_MEM, OP_MEM_STR, OP_IMM, OP_XMM, OP_MM, OP_NONE } type; unsigned int bytes; + unsigned int count; union { unsigned long orig_val; u64 orig_val64; @@ -221,6 +235,7 @@ struct operand { char valptr[sizeof(unsigned long) + 2]; sse128_t vec_val; u64 mm_val; + void *data; }; }; @@ -236,14 +251,23 @@ struct read_cache { unsigned long end; }; +/* Execution mode, passed to the emulator. */ +enum x86emul_mode { + X86EMUL_MODE_REAL, /* Real mode. */ + X86EMUL_MODE_VM86, /* Virtual 8086 mode. */ + X86EMUL_MODE_PROT16, /* 16-bit protected mode. */ + X86EMUL_MODE_PROT32, /* 32-bit protected mode. */ + X86EMUL_MODE_PROT64, /* 64-bit (long) mode. */ +}; + struct x86_emulate_ctxt { - struct x86_emulate_ops *ops; + const struct x86_emulate_ops *ops; /* Register state before/after emulation. */ unsigned long eflags; unsigned long eip; /* eip before instruction emulation */ /* Emulated execution mode, represented by an X86EMUL_MODE value. */ - int mode; + enum x86emul_mode mode; /* interruptibility state, as a result of execution of STI or MOV SS */ int interruptibility; @@ -281,8 +305,10 @@ struct x86_emulate_ctxt { bool rip_relative; unsigned long _eip; struct operand memop; + u32 regs_valid; /* bitmaps of registers in _regs[] that can be read */ + u32 regs_dirty; /* bitmaps of registers in _regs[] that have been written */ /* Fields above regs are cleared together. */ - unsigned long regs[NR_VCPU_REGS]; + unsigned long _regs[NR_VCPU_REGS]; struct operand *memopp; struct fetch_cache fetch; struct read_cache io_read; @@ -293,17 +319,6 @@ struct x86_emulate_ctxt { #define REPE_PREFIX 0xf3 #define REPNE_PREFIX 0xf2 -/* Execution mode, passed to the emulator. */ -#define X86EMUL_MODE_REAL 0 /* Real mode. */ -#define X86EMUL_MODE_VM86 1 /* Virtual 8086 mode. */ -#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */ -#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */ -#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */ - -/* any protected mode */ -#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \ - X86EMUL_MODE_PROT64) - /* CPUID vendors */ #define X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx 0x68747541 #define X86EMUL_CPUID_VENDOR_AuthenticAMD_ecx 0x444d4163 @@ -394,4 +409,7 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, u16 tss_selector, int idt_index, int reason, bool has_error_code, u32 error_code); int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq); +void emulator_invalidate_register_cache(struct x86_emulate_ctxt *ctxt); +void emulator_writeback_register_cache(struct x86_emulate_ctxt *ctxt); + #endif /* _ASM_X86_KVM_X86_EMULATE_H */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1eaa6b056670..b2e11f452435 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -271,10 +271,24 @@ struct kvm_mmu { union kvm_mmu_page_role base_role; bool direct_map; + /* + * Bitmap; bit set = permission fault + * Byte index: page fault error code [4:1] + * Bit index: pte permissions in ACC_* format + */ + u8 permissions[16]; + u64 *pae_root; u64 *lm_root; u64 rsvd_bits_mask[2][4]; + /* + * Bitmap: bit set = last pte in walk + * index[0:1]: level (zero-based) + * index[2]: pte.ps + */ + u8 last_pte_bitmap; + bool nx; u64 pdptrs[4]; /* pae */ @@ -398,12 +412,15 @@ struct kvm_vcpu_arch { struct x86_emulate_ctxt emulate_ctxt; bool emulate_regs_need_sync_to_vcpu; bool emulate_regs_need_sync_from_vcpu; + int (*complete_userspace_io)(struct kvm_vcpu *vcpu); gpa_t time; struct pvclock_vcpu_time_info hv_clock; unsigned int hw_tsc_khz; unsigned int time_offset; struct page *time_page; + /* set guest stopped flag in pvclock flags field */ + bool pvclock_set_guest_stopped_request; struct { u64 msr_val; @@ -438,6 +455,7 @@ struct kvm_vcpu_arch { unsigned long dr6; unsigned long dr7; unsigned long eff_db[KVM_NR_DB_REGS]; + unsigned long guest_debug_dr7; u64 mcg_cap; u64 mcg_status; @@ -484,14 +502,24 @@ struct kvm_vcpu_arch { }; struct kvm_lpage_info { - unsigned long rmap_pde; int write_count; }; struct kvm_arch_memory_slot { + unsigned long *rmap[KVM_NR_PAGE_SIZES]; struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1]; }; +struct kvm_apic_map { + struct rcu_head rcu; + u8 ldr_bits; + /* fields bellow are used to decode ldr values in different modes */ + u32 cid_shift, cid_mask, lid_mask; + struct kvm_lapic *phys_map[256]; + /* first index is cluster id second is cpu id in a cluster */ + struct kvm_lapic *logical_map[16][16]; +}; + struct kvm_arch { unsigned int n_used_mmu_pages; unsigned int n_requested_mmu_pages; @@ -509,6 +537,8 @@ struct kvm_arch { struct kvm_ioapic *vioapic; struct kvm_pit *vpit; int vapics_in_nmi_mode; + struct mutex apic_map_lock; + struct kvm_apic_map *apic_map; unsigned int tss_addr; struct page *apic_access_page; @@ -602,8 +632,7 @@ struct kvm_x86_ops { void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); void (*vcpu_put)(struct kvm_vcpu *vcpu); - void (*set_guest_debug)(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg); + void (*update_db_bp_intercept)(struct kvm_vcpu *vcpu); int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); @@ -941,6 +970,7 @@ extern bool kvm_rebooting; #define KVM_ARCH_WANT_MMU_NOTIFIER int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); +int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end); int kvm_age_hva(struct kvm *kvm, unsigned long hva); int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index 2f7712e08b1e..eb3e9d85e1f1 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h @@ -102,21 +102,21 @@ struct kvm_vcpu_pv_apf_data { extern void kvmclock_init(void); extern int kvm_register_clock(char *txt); -#ifdef CONFIG_KVM_CLOCK +#ifdef CONFIG_KVM_GUEST bool kvm_check_and_clear_guest_paused(void); #else static inline bool kvm_check_and_clear_guest_paused(void) { return false; } -#endif /* CONFIG_KVMCLOCK */ +#endif /* CONFIG_KVM_GUEST */ /* This instruction is vmcall. On non-VT architectures, it will generate a * trap that we will then rewrite to the appropriate instruction. */ #define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1" -/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun +/* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall * instruction. The hypervisor may replace it with something else but only the * instructions are guaranteed to be supported. * diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h index 1707cfa928fb..6d2f75a82a14 100644 --- a/arch/x86/include/asm/xen/interface.h +++ b/arch/x86/include/asm/xen/interface.h @@ -51,6 +51,7 @@ * with Xen so that on ARM we can have one ABI that works for 32 and 64 * bit guests. */ typedef unsigned long xen_pfn_t; +typedef unsigned long xen_ulong_t; /* Guest handles for primitive C types. */ __DEFINE_GUEST_HANDLE(uchar, unsigned char); __DEFINE_GUEST_HANDLE(uint, unsigned int); diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 8d7a619718b5..a48ea05157d3 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -81,8 +81,7 @@ obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o -obj-$(CONFIG_KVM_GUEST) += kvm.o -obj-$(CONFIG_KVM_CLOCK) += kvmclock.o +obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt_patch_$(BITS).o obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= paravirt-spinlocks.o obj-$(CONFIG_PARAVIRT_CLOCK) += pvclock.o diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index bc552cff2578..a65829ac2b9a 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -30,7 +30,7 @@ static int numachip_system __read_mostly; -static struct apic apic_numachip __read_mostly; +static const struct apic apic_numachip __read_mostly; static unsigned int get_apic_id(unsigned long x) { @@ -199,7 +199,7 @@ static int numachip_acpi_madt_oem_check(char *oem_id, char *oem_table_id) return 0; } -static struct apic apic_numachip __refconst = { +static const struct apic apic_numachip __refconst = { .name = "NumaConnect system", .probe = numachip_probe, diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index c1d61ee4b4f1..b3e5e51bc907 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -354,6 +354,7 @@ static void kvm_pv_guest_cpu_reboot(void *unused) if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) wrmsrl(MSR_KVM_PV_EOI_EN, 0); kvm_pv_disable_apf(); + kvm_disable_steal_time(); } static int kvm_pv_reboot_notify(struct notifier_block *nb, @@ -396,9 +397,7 @@ void kvm_disable_steal_time(void) #ifdef CONFIG_SMP static void __init kvm_smp_prepare_boot_cpu(void) { -#ifdef CONFIG_KVM_CLOCK WARN_ON(kvm_register_clock("primary cpu clock")); -#endif kvm_guest_cpu_init(); native_smp_prepare_boot_cpu(); } diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index af6db6ec5b2a..4929c1be0ac0 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -225,7 +225,7 @@ static struct platform_device rtc_device = { static __init int add_rtc_cmos(void) { #ifdef CONFIG_PNP - static const char *ids[] __initconst = + static const char * const const ids[] __initconst = { "PNP0b00", "PNP0b01", "PNP0b02", }; struct pnp_dev *dev; struct pnp_id *id; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 4f165479c453..d609be046b57 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -957,7 +957,7 @@ void __init setup_arch(char **cmdline_p) initmem_init(); memblock_find_dma_reserve(); -#ifdef CONFIG_KVM_CLOCK +#ifdef CONFIG_KVM_GUEST kvmclock_init(); #endif diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index a28f338843ea..586f00059805 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -20,6 +20,7 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on HAVE_KVM + depends on HIGH_RES_TIMERS # for device assignment: depends on PCI # for TASKSTATS/TASK_DELAY_ACCT: @@ -37,6 +38,7 @@ config KVM select TASK_DELAY_ACCT select PERF_EVENTS select HAVE_KVM_MSI + select HAVE_KVM_CPU_RELAX_INTERCEPT ---help--- Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 4f579e8dcacf..04d30401c5cb 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -12,7 +12,7 @@ kvm-$(CONFIG_IOMMU_API) += $(addprefix ../../../virt/kvm/, iommu.o) kvm-$(CONFIG_KVM_ASYNC_PF) += $(addprefix ../../../virt/kvm/, async_pf.o) kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \ - i8254.o timer.o cpuid.o pmu.o + i8254.o cpuid.o pmu.o kvm-intel-y += vmx.o kvm-amd-y += svm.o diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 0595f1397b7c..ec79e773342e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -316,7 +316,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, } case 7: { entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; - /* Mask ebx against host capbability word 9 */ + /* Mask ebx against host capability word 9 */ if (index == 0) { entry->ebx &= kvm_supported_word9_x86_features; cpuid_mask(&entry->ebx, 9); @@ -397,8 +397,8 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, break; } case KVM_CPUID_SIGNATURE: { - char signature[12] = "KVMKVMKVM\0\0"; - u32 *sigptr = (u32 *)signature; + static const char signature[12] = "KVMKVMKVM\0\0"; + const u32 *sigptr = (const u32 *)signature; entry->eax = KVM_CPUID_FEATURES; entry->ebx = sigptr[0]; entry->ecx = sigptr[1]; @@ -484,10 +484,10 @@ struct kvm_cpuid_param { u32 func; u32 idx; bool has_leaf_count; - bool (*qualifier)(struct kvm_cpuid_param *param); + bool (*qualifier)(const struct kvm_cpuid_param *param); }; -static bool is_centaur_cpu(struct kvm_cpuid_param *param) +static bool is_centaur_cpu(const struct kvm_cpuid_param *param) { return boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR; } @@ -498,7 +498,7 @@ int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *cpuid_entries; int limit, nent = 0, r = -E2BIG, i; u32 func; - static struct kvm_cpuid_param param[] = { + static const struct kvm_cpuid_param param[] = { { .func = 0, .has_leaf_count = true }, { .func = 0x80000000, .has_leaf_count = true }, { .func = 0xC0000000, .qualifier = is_centaur_cpu, .has_leaf_count = true }, @@ -517,7 +517,7 @@ int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, r = 0; for (i = 0; i < ARRAY_SIZE(param); i++) { - struct kvm_cpuid_param *ent = ¶m[i]; + const struct kvm_cpuid_param *ent = ¶m[i]; if (ent->qualifier && !ent->qualifier(ent)) continue; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index a3b57a27be88..39171cb307ea 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -161,9 +161,9 @@ struct opcode { u64 intercept : 8; union { int (*execute)(struct x86_emulate_ctxt *ctxt); - struct opcode *group; - struct group_dual *gdual; - struct gprefix *gprefix; + const struct opcode *group; + const struct group_dual *gdual; + const struct gprefix *gprefix; } u; int (*check_perm)(struct x86_emulate_ctxt *ctxt); }; @@ -202,6 +202,42 @@ struct gprefix { #define EFLG_RESERVED_ZEROS_MASK 0xffc0802a #define EFLG_RESERVED_ONE_MASK 2 +static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) +{ + if (!(ctxt->regs_valid & (1 << nr))) { + ctxt->regs_valid |= 1 << nr; + ctxt->_regs[nr] = ctxt->ops->read_gpr(ctxt, nr); + } + return ctxt->_regs[nr]; +} + +static ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr) +{ + ctxt->regs_valid |= 1 << nr; + ctxt->regs_dirty |= 1 << nr; + return &ctxt->_regs[nr]; +} + +static ulong *reg_rmw(struct x86_emulate_ctxt *ctxt, unsigned nr) +{ + reg_read(ctxt, nr); + return reg_write(ctxt, nr); +} + +static void writeback_registers(struct x86_emulate_ctxt *ctxt) +{ + unsigned reg; + + for_each_set_bit(reg, (ulong *)&ctxt->regs_dirty, 16) + ctxt->ops->write_gpr(ctxt, reg, ctxt->_regs[reg]); +} + +static void invalidate_registers(struct x86_emulate_ctxt *ctxt) +{ + ctxt->regs_dirty = 0; + ctxt->regs_valid = 0; +} + /* * Instruction emulation: * Most instructions are emulated directly via a fragment of inline assembly @@ -374,8 +410,8 @@ struct gprefix { #define __emulate_1op_rax_rdx(ctxt, _op, _suffix, _ex) \ do { \ unsigned long _tmp; \ - ulong *rax = &(ctxt)->regs[VCPU_REGS_RAX]; \ - ulong *rdx = &(ctxt)->regs[VCPU_REGS_RDX]; \ + ulong *rax = reg_rmw((ctxt), VCPU_REGS_RAX); \ + ulong *rdx = reg_rmw((ctxt), VCPU_REGS_RDX); \ \ __asm__ __volatile__ ( \ _PRE_EFLAGS("0", "5", "1") \ @@ -494,7 +530,7 @@ register_address_increment(struct x86_emulate_ctxt *ctxt, unsigned long *reg, in static void rsp_increment(struct x86_emulate_ctxt *ctxt, int inc) { - masked_increment(&ctxt->regs[VCPU_REGS_RSP], stack_mask(ctxt), inc); + masked_increment(reg_rmw(ctxt, VCPU_REGS_RSP), stack_mask(ctxt), inc); } static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) @@ -632,8 +668,6 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, la = seg_base(ctxt, addr.seg) + addr.ea; switch (ctxt->mode) { - case X86EMUL_MODE_REAL: - break; case X86EMUL_MODE_PROT64: if (((signed long)la << 16) >> 16 != la) return emulate_gp(ctxt, 0); @@ -655,7 +689,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim) goto bad; } else { - /* exapand-down segment */ + /* expand-down segment */ if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim) goto bad; lim = desc.d ? 0xffffffff : 0xffff; @@ -663,7 +697,10 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, goto bad; } cpl = ctxt->ops->cpl(ctxt); - rpl = sel & 3; + if (ctxt->mode == X86EMUL_MODE_REAL) + rpl = 0; + else + rpl = sel & 3; cpl = max(cpl, rpl); if (!(desc.type & 8)) { /* data segment */ @@ -688,9 +725,9 @@ static int __linearize(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; bad: if (addr.seg == VCPU_SREG_SS) - return emulate_ss(ctxt, addr.seg); + return emulate_ss(ctxt, sel); else - return emulate_gp(ctxt, addr.seg); + return emulate_gp(ctxt, sel); } static int linearize(struct x86_emulate_ctxt *ctxt, @@ -786,14 +823,15 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt, * pointer into the block that addresses the relevant register. * @highbyte_regs specifies whether to decode AH,CH,DH,BH. */ -static void *decode_register(u8 modrm_reg, unsigned long *regs, +static void *decode_register(struct x86_emulate_ctxt *ctxt, u8 modrm_reg, int highbyte_regs) { void *p; - p = ®s[modrm_reg]; if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8) - p = (unsigned char *)®s[modrm_reg & 3] + 1; + p = (unsigned char *)reg_rmw(ctxt, modrm_reg & 3) + 1; + else + p = reg_rmw(ctxt, modrm_reg); return p; } @@ -871,23 +909,23 @@ static void read_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, int reg) { ctxt->ops->get_fpu(ctxt); switch (reg) { - case 0: asm("movdqu %%xmm0, %0" : "=m"(*data)); break; - case 1: asm("movdqu %%xmm1, %0" : "=m"(*data)); break; - case 2: asm("movdqu %%xmm2, %0" : "=m"(*data)); break; - case 3: asm("movdqu %%xmm3, %0" : "=m"(*data)); break; - case 4: asm("movdqu %%xmm4, %0" : "=m"(*data)); break; - case 5: asm("movdqu %%xmm5, %0" : "=m"(*data)); break; - case 6: asm("movdqu %%xmm6, %0" : "=m"(*data)); break; - case 7: asm("movdqu %%xmm7, %0" : "=m"(*data)); break; + case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break; + case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break; + case 2: asm("movdqa %%xmm2, %0" : "=m"(*data)); break; + case 3: asm("movdqa %%xmm3, %0" : "=m"(*data)); break; + case 4: asm("movdqa %%xmm4, %0" : "=m"(*data)); break; + case 5: asm("movdqa %%xmm5, %0" : "=m"(*data)); break; + case 6: asm("movdqa %%xmm6, %0" : "=m"(*data)); break; + case 7: asm("movdqa %%xmm7, %0" : "=m"(*data)); break; #ifdef CONFIG_X86_64 - case 8: asm("movdqu %%xmm8, %0" : "=m"(*data)); break; - case 9: asm("movdqu %%xmm9, %0" : "=m"(*data)); break; - case 10: asm("movdqu %%xmm10, %0" : "=m"(*data)); break; - case 11: asm("movdqu %%xmm11, %0" : "=m"(*data)); break; - case 12: asm("movdqu %%xmm12, %0" : "=m"(*data)); break; - case 13: asm("movdqu %%xmm13, %0" : "=m"(*data)); break; - case 14: asm("movdqu %%xmm14, %0" : "=m"(*data)); break; - case 15: asm("movdqu %%xmm15, %0" : "=m"(*data)); break; + case 8: asm("movdqa %%xmm8, %0" : "=m"(*data)); break; + case 9: asm("movdqa %%xmm9, %0" : "=m"(*data)); break; + case 10: asm("movdqa %%xmm10, %0" : "=m"(*data)); break; + case 11: asm("movdqa %%xmm11, %0" : "=m"(*data)); break; + case 12: asm("movdqa %%xmm12, %0" : "=m"(*data)); break; + case 13: asm("movdqa %%xmm13, %0" : "=m"(*data)); break; + case 14: asm("movdqa %%xmm14, %0" : "=m"(*data)); break; + case 15: asm("movdqa %%xmm15, %0" : "=m"(*data)); break; #endif default: BUG(); } @@ -899,23 +937,23 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, { ctxt->ops->get_fpu(ctxt); switch (reg) { - case 0: asm("movdqu %0, %%xmm0" : : "m"(*data)); break; - case 1: asm("movdqu %0, %%xmm1" : : "m"(*data)); break; - case 2: asm("movdqu %0, %%xmm2" : : "m"(*data)); break; - case 3: asm("movdqu %0, %%xmm3" : : "m"(*data)); break; - case 4: asm("movdqu %0, %%xmm4" : : "m"(*data)); break; - case 5: asm("movdqu %0, %%xmm5" : : "m"(*data)); break; - case 6: asm("movdqu %0, %%xmm6" : : "m"(*data)); break; - case 7: asm("movdqu %0, %%xmm7" : : "m"(*data)); break; + case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break; + case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break; + case 2: asm("movdqa %0, %%xmm2" : : "m"(*data)); break; + case 3: asm("movdqa %0, %%xmm3" : : "m"(*data)); break; + case 4: asm("movdqa %0, %%xmm4" : : "m"(*data)); break; + case 5: asm("movdqa %0, %%xmm5" : : "m"(*data)); break; + case 6: asm("movdqa %0, %%xmm6" : : "m"(*data)); break; + case 7: asm("movdqa %0, %%xmm7" : : "m"(*data)); break; #ifdef CONFIG_X86_64 - case 8: asm("movdqu %0, %%xmm8" : : "m"(*data)); break; - case 9: asm("movdqu %0, %%xmm9" : : "m"(*data)); break; - case 10: asm("movdqu %0, %%xmm10" : : "m"(*data)); break; - case 11: asm("movdqu %0, %%xmm11" : : "m"(*data)); break; - case 12: asm("movdqu %0, %%xmm12" : : "m"(*data)); break; - case 13: asm("movdqu %0, %%xmm13" : : "m"(*data)); break; - case 14: asm("movdqu %0, %%xmm14" : : "m"(*data)); break; - case 15: asm("movdqu %0, %%xmm15" : : "m"(*data)); break; + case 8: asm("movdqa %0, %%xmm8" : : "m"(*data)); break; + case 9: asm("movdqa %0, %%xmm9" : : "m"(*data)); break; + case 10: asm("movdqa %0, %%xmm10" : : "m"(*data)); break; + case 11: asm("movdqa %0, %%xmm11" : : "m"(*data)); break; + case 12: asm("movdqa %0, %%xmm12" : : "m"(*data)); break; + case 13: asm("movdqa %0, %%xmm13" : : "m"(*data)); break; + case 14: asm("movdqa %0, %%xmm14" : : "m"(*data)); break; + case 15: asm("movdqa %0, %%xmm15" : : "m"(*data)); break; #endif default: BUG(); } @@ -982,10 +1020,10 @@ static void decode_register_operand(struct x86_emulate_ctxt *ctxt, op->type = OP_REG; if (ctxt->d & ByteOp) { - op->addr.reg = decode_register(reg, ctxt->regs, highbyte_regs); + op->addr.reg = decode_register(ctxt, reg, highbyte_regs); op->bytes = 1; } else { - op->addr.reg = decode_register(reg, ctxt->regs, 0); + op->addr.reg = decode_register(ctxt, reg, 0); op->bytes = ctxt->op_bytes; } fetch_register_operand(op); @@ -1020,8 +1058,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, if (ctxt->modrm_mod == 3) { op->type = OP_REG; op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - op->addr.reg = decode_register(ctxt->modrm_rm, - ctxt->regs, ctxt->d & ByteOp); + op->addr.reg = decode_register(ctxt, ctxt->modrm_rm, ctxt->d & ByteOp); if (ctxt->d & Sse) { op->type = OP_XMM; op->bytes = 16; @@ -1042,10 +1079,10 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, op->type = OP_MEM; if (ctxt->ad_bytes == 2) { - unsigned bx = ctxt->regs[VCPU_REGS_RBX]; - unsigned bp = ctxt->regs[VCPU_REGS_RBP]; - unsigned si = ctxt->regs[VCPU_REGS_RSI]; - unsigned di = ctxt->regs[VCPU_REGS_RDI]; + unsigned bx = reg_read(ctxt, VCPU_REGS_RBX); + unsigned bp = reg_read(ctxt, VCPU_REGS_RBP); + unsigned si = reg_read(ctxt, VCPU_REGS_RSI); + unsigned di = reg_read(ctxt, VCPU_REGS_RDI); /* 16-bit ModR/M decode. */ switch (ctxt->modrm_mod) { @@ -1102,17 +1139,17 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt, if ((base_reg & 7) == 5 && ctxt->modrm_mod == 0) modrm_ea += insn_fetch(s32, ctxt); else { - modrm_ea += ctxt->regs[base_reg]; + modrm_ea += reg_read(ctxt, base_reg); adjust_modrm_seg(ctxt, base_reg); } if (index_reg != 4) - modrm_ea += ctxt->regs[index_reg] << scale; + modrm_ea += reg_read(ctxt, index_reg) << scale; } else if ((ctxt->modrm_rm & 7) == 5 && ctxt->modrm_mod == 0) { if (ctxt->mode == X86EMUL_MODE_PROT64) ctxt->rip_relative = 1; } else { base_reg = ctxt->modrm_rm; - modrm_ea += ctxt->regs[base_reg]; + modrm_ea += reg_read(ctxt, base_reg); adjust_modrm_seg(ctxt, base_reg); } switch (ctxt->modrm_mod) { @@ -1179,24 +1216,21 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt, int rc; struct read_cache *mc = &ctxt->mem_read; - while (size) { - int n = min(size, 8u); - size -= n; - if (mc->pos < mc->end) - goto read_cached; + if (mc->pos < mc->end) + goto read_cached; - rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, n, - &ctxt->exception); - if (rc != X86EMUL_CONTINUE) - return rc; - mc->end += n; + WARN_ON((mc->end + size) >= sizeof(mc->data)); - read_cached: - memcpy(dest, mc->data + mc->pos, n); - mc->pos += n; - dest += n; - addr += n; - } + rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size, + &ctxt->exception); + if (rc != X86EMUL_CONTINUE) + return rc; + + mc->end += size; + +read_cached: + memcpy(dest, mc->data + mc->pos, size); + mc->pos += size; return X86EMUL_CONTINUE; } @@ -1253,10 +1287,10 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, if (rc->pos == rc->end) { /* refill pio read ahead */ unsigned int in_page, n; unsigned int count = ctxt->rep_prefix ? - address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) : 1; + address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) : 1; in_page = (ctxt->eflags & EFLG_DF) ? - offset_in_page(ctxt->regs[VCPU_REGS_RDI]) : - PAGE_SIZE - offset_in_page(ctxt->regs[VCPU_REGS_RDI]); + offset_in_page(reg_read(ctxt, VCPU_REGS_RDI)) : + PAGE_SIZE - offset_in_page(reg_read(ctxt, VCPU_REGS_RDI)); n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size, count); if (n == 0) @@ -1267,8 +1301,15 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, rc->end = n * size; } - memcpy(dest, rc->data + rc->pos, size); - rc->pos += size; + if (ctxt->rep_prefix && !(ctxt->eflags & EFLG_DF)) { + ctxt->dst.data = rc->data + rc->pos; + ctxt->dst.type = OP_MEM_STR; + ctxt->dst.count = (rc->end - rc->pos) / size; + rc->pos = rc->end; + } else { + memcpy(dest, rc->data + rc->pos, size); + rc->pos += size; + } return 1; } @@ -1291,7 +1332,7 @@ static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt, static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, u16 selector, struct desc_ptr *dt) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; if (selector & 1 << 2) { struct desc_struct desc; @@ -1355,19 +1396,15 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */ ulong desc_addr; int ret; + u16 dummy; memset(&seg_desc, 0, sizeof seg_desc); if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86) || ctxt->mode == X86EMUL_MODE_REAL) { /* set real mode segment descriptor */ + ctxt->ops->get_segment(ctxt, &dummy, &seg_desc, NULL, seg); set_desc_base(&seg_desc, selector << 4); - set_desc_limit(&seg_desc, 0xffff); - seg_desc.type = 3; - seg_desc.p = 1; - seg_desc.s = 1; - if (ctxt->mode == X86EMUL_MODE_VM86) - seg_desc.dpl = 3; goto load; } @@ -1396,7 +1433,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, err_code = selector & 0xfffc; err_vec = GP_VECTOR; - /* can't load system descriptor into segment selecor */ + /* can't load system descriptor into segment selector */ if (seg <= VCPU_SREG_GS && !seg_desc.s) goto exception; @@ -1516,6 +1553,14 @@ static int writeback(struct x86_emulate_ctxt *ctxt) if (rc != X86EMUL_CONTINUE) return rc; break; + case OP_MEM_STR: + rc = segmented_write(ctxt, + ctxt->dst.addr.mem, + ctxt->dst.data, + ctxt->dst.bytes * ctxt->dst.count); + if (rc != X86EMUL_CONTINUE) + return rc; + break; case OP_XMM: write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm); break; @@ -1536,7 +1581,7 @@ static int push(struct x86_emulate_ctxt *ctxt, void *data, int bytes) struct segmented_address addr; rsp_increment(ctxt, -bytes); - addr.ea = ctxt->regs[VCPU_REGS_RSP] & stack_mask(ctxt); + addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt); addr.seg = VCPU_SREG_SS; return segmented_write(ctxt, addr, data, bytes); @@ -1555,7 +1600,7 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt, int rc; struct segmented_address addr; - addr.ea = ctxt->regs[VCPU_REGS_RSP] & stack_mask(ctxt); + addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt); addr.seg = VCPU_SREG_SS; rc = segmented_read(ctxt, addr, dest, len); if (rc != X86EMUL_CONTINUE) @@ -1623,26 +1668,28 @@ static int em_enter(struct x86_emulate_ctxt *ctxt) int rc; unsigned frame_size = ctxt->src.val; unsigned nesting_level = ctxt->src2.val & 31; + ulong rbp; if (nesting_level) return X86EMUL_UNHANDLEABLE; - rc = push(ctxt, &ctxt->regs[VCPU_REGS_RBP], stack_size(ctxt)); + rbp = reg_read(ctxt, VCPU_REGS_RBP); + rc = push(ctxt, &rbp, stack_size(ctxt)); if (rc != X86EMUL_CONTINUE) return rc; - assign_masked(&ctxt->regs[VCPU_REGS_RBP], ctxt->regs[VCPU_REGS_RSP], + assign_masked(reg_rmw(ctxt, VCPU_REGS_RBP), reg_read(ctxt, VCPU_REGS_RSP), stack_mask(ctxt)); - assign_masked(&ctxt->regs[VCPU_REGS_RSP], - ctxt->regs[VCPU_REGS_RSP] - frame_size, + assign_masked(reg_rmw(ctxt, VCPU_REGS_RSP), + reg_read(ctxt, VCPU_REGS_RSP) - frame_size, stack_mask(ctxt)); return X86EMUL_CONTINUE; } static int em_leave(struct x86_emulate_ctxt *ctxt) { - assign_masked(&ctxt->regs[VCPU_REGS_RSP], ctxt->regs[VCPU_REGS_RBP], + assign_masked(reg_rmw(ctxt, VCPU_REGS_RSP), reg_read(ctxt, VCPU_REGS_RBP), stack_mask(ctxt)); - return emulate_pop(ctxt, &ctxt->regs[VCPU_REGS_RBP], ctxt->op_bytes); + return emulate_pop(ctxt, reg_rmw(ctxt, VCPU_REGS_RBP), ctxt->op_bytes); } static int em_push_sreg(struct x86_emulate_ctxt *ctxt) @@ -1670,13 +1717,13 @@ static int em_pop_sreg(struct x86_emulate_ctxt *ctxt) static int em_pusha(struct x86_emulate_ctxt *ctxt) { - unsigned long old_esp = ctxt->regs[VCPU_REGS_RSP]; + unsigned long old_esp = reg_read(ctxt, VCPU_REGS_RSP); int rc = X86EMUL_CONTINUE; int reg = VCPU_REGS_RAX; while (reg <= VCPU_REGS_RDI) { (reg == VCPU_REGS_RSP) ? - (ctxt->src.val = old_esp) : (ctxt->src.val = ctxt->regs[reg]); + (ctxt->src.val = old_esp) : (ctxt->src.val = reg_read(ctxt, reg)); rc = em_push(ctxt); if (rc != X86EMUL_CONTINUE) @@ -1705,7 +1752,7 @@ static int em_popa(struct x86_emulate_ctxt *ctxt) --reg; } - rc = emulate_pop(ctxt, &ctxt->regs[reg], ctxt->op_bytes); + rc = emulate_pop(ctxt, reg_rmw(ctxt, reg), ctxt->op_bytes); if (rc != X86EMUL_CONTINUE) break; --reg; @@ -1713,9 +1760,9 @@ static int em_popa(struct x86_emulate_ctxt *ctxt) return rc; } -int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) +static int __emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; int rc; struct desc_ptr dt; gva_t cs_addr; @@ -1762,11 +1809,22 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) return rc; } +int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) +{ + int rc; + + invalidate_registers(ctxt); + rc = __emulate_int_real(ctxt, irq); + if (rc == X86EMUL_CONTINUE) + writeback_registers(ctxt); + return rc; +} + static int emulate_int(struct x86_emulate_ctxt *ctxt, int irq) { switch(ctxt->mode) { case X86EMUL_MODE_REAL: - return emulate_int_real(ctxt, irq); + return __emulate_int_real(ctxt, irq); case X86EMUL_MODE_VM86: case X86EMUL_MODE_PROT16: case X86EMUL_MODE_PROT32: @@ -1973,14 +2031,14 @@ static int em_cmpxchg8b(struct x86_emulate_ctxt *ctxt) { u64 old = ctxt->dst.orig_val64; - if (((u32) (old >> 0) != (u32) ctxt->regs[VCPU_REGS_RAX]) || - ((u32) (old >> 32) != (u32) ctxt->regs[VCPU_REGS_RDX])) { - ctxt->regs[VCPU_REGS_RAX] = (u32) (old >> 0); - ctxt->regs[VCPU_REGS_RDX] = (u32) (old >> 32); + if (((u32) (old >> 0) != (u32) reg_read(ctxt, VCPU_REGS_RAX)) || + ((u32) (old >> 32) != (u32) reg_read(ctxt, VCPU_REGS_RDX))) { + *reg_write(ctxt, VCPU_REGS_RAX) = (u32) (old >> 0); + *reg_write(ctxt, VCPU_REGS_RDX) = (u32) (old >> 32); ctxt->eflags &= ~EFLG_ZF; } else { - ctxt->dst.val64 = ((u64)ctxt->regs[VCPU_REGS_RCX] << 32) | - (u32) ctxt->regs[VCPU_REGS_RBX]; + ctxt->dst.val64 = ((u64)reg_read(ctxt, VCPU_REGS_RCX) << 32) | + (u32) reg_read(ctxt, VCPU_REGS_RBX); ctxt->eflags |= EFLG_ZF; } @@ -2016,7 +2074,7 @@ static int em_cmpxchg(struct x86_emulate_ctxt *ctxt) { /* Save real source value, then compare EAX against destination. */ ctxt->src.orig_val = ctxt->src.val; - ctxt->src.val = ctxt->regs[VCPU_REGS_RAX]; + ctxt->src.val = reg_read(ctxt, VCPU_REGS_RAX); emulate_2op_SrcV(ctxt, "cmp"); if (ctxt->eflags & EFLG_ZF) { @@ -2025,7 +2083,7 @@ static int em_cmpxchg(struct x86_emulate_ctxt *ctxt) } else { /* Failure: write the value we saw to EAX. */ ctxt->dst.type = OP_REG; - ctxt->dst.addr.reg = (unsigned long *)&ctxt->regs[VCPU_REGS_RAX]; + ctxt->dst.addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX); } return X86EMUL_CONTINUE; } @@ -2050,12 +2108,6 @@ static void setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, struct desc_struct *cs, struct desc_struct *ss) { - u16 selector; - - memset(cs, 0, sizeof(struct desc_struct)); - ctxt->ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS); - memset(ss, 0, sizeof(struct desc_struct)); - cs->l = 0; /* will be adjusted later */ set_desc_base(cs, 0); /* flat segment */ cs->g = 1; /* 4kb granularity */ @@ -2065,6 +2117,7 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, cs->dpl = 0; /* will be adjusted later */ cs->p = 1; cs->d = 1; + cs->avl = 0; set_desc_base(ss, 0); /* flat segment */ set_desc_limit(ss, 0xfffff); /* 4GB limit */ @@ -2074,6 +2127,8 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt, ss->d = 1; /* 32bit stack segment */ ss->dpl = 0; ss->p = 1; + ss->l = 0; + ss->avl = 0; } static bool vendor_intel(struct x86_emulate_ctxt *ctxt) @@ -2089,7 +2144,7 @@ static bool vendor_intel(struct x86_emulate_ctxt *ctxt) static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; u32 eax, ebx, ecx, edx; /* @@ -2133,7 +2188,7 @@ static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) static int em_syscall(struct x86_emulate_ctxt *ctxt) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct cs, ss; u64 msr_data; u16 cs_sel, ss_sel; @@ -2165,10 +2220,10 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); - ctxt->regs[VCPU_REGS_RCX] = ctxt->_eip; + *reg_write(ctxt, VCPU_REGS_RCX) = ctxt->_eip; if (efer & EFER_LMA) { #ifdef CONFIG_X86_64 - ctxt->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF; + *reg_write(ctxt, VCPU_REGS_R11) = ctxt->eflags & ~EFLG_RF; ops->get_msr(ctxt, ctxt->mode == X86EMUL_MODE_PROT64 ? @@ -2191,7 +2246,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt) static int em_sysenter(struct x86_emulate_ctxt *ctxt) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct cs, ss; u64 msr_data; u16 cs_sel, ss_sel; @@ -2228,6 +2283,8 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) if (msr_data == 0x0) return emulate_gp(ctxt, 0); break; + default: + break; } ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF); @@ -2247,14 +2304,14 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt) ctxt->_eip = msr_data; ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); - ctxt->regs[VCPU_REGS_RSP] = msr_data; + *reg_write(ctxt, VCPU_REGS_RSP) = msr_data; return X86EMUL_CONTINUE; } static int em_sysexit(struct x86_emulate_ctxt *ctxt) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct cs, ss; u64 msr_data; int usermode; @@ -2297,8 +2354,8 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); - ctxt->_eip = ctxt->regs[VCPU_REGS_RDX]; - ctxt->regs[VCPU_REGS_RSP] = ctxt->regs[VCPU_REGS_RCX]; + ctxt->_eip = reg_read(ctxt, VCPU_REGS_RDX); + *reg_write(ctxt, VCPU_REGS_RSP) = reg_read(ctxt, VCPU_REGS_RCX); return X86EMUL_CONTINUE; } @@ -2317,7 +2374,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, u16 port, u16 len) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct tr_seg; u32 base3; int r; @@ -2367,14 +2424,14 @@ static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt, { tss->ip = ctxt->_eip; tss->flag = ctxt->eflags; - tss->ax = ctxt->regs[VCPU_REGS_RAX]; - tss->cx = ctxt->regs[VCPU_REGS_RCX]; - tss->dx = ctxt->regs[VCPU_REGS_RDX]; - tss->bx = ctxt->regs[VCPU_REGS_RBX]; - tss->sp = ctxt->regs[VCPU_REGS_RSP]; - tss->bp = ctxt->regs[VCPU_REGS_RBP]; - tss->si = ctxt->regs[VCPU_REGS_RSI]; - tss->di = ctxt->regs[VCPU_REGS_RDI]; + tss->ax = reg_read(ctxt, VCPU_REGS_RAX); + tss->cx = reg_read(ctxt, VCPU_REGS_RCX); + tss->dx = reg_read(ctxt, VCPU_REGS_RDX); + tss->bx = reg_read(ctxt, VCPU_REGS_RBX); + tss->sp = reg_read(ctxt, VCPU_REGS_RSP); + tss->bp = reg_read(ctxt, VCPU_REGS_RBP); + tss->si = reg_read(ctxt, VCPU_REGS_RSI); + tss->di = reg_read(ctxt, VCPU_REGS_RDI); tss->es = get_segment_selector(ctxt, VCPU_SREG_ES); tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS); @@ -2390,14 +2447,14 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, ctxt->_eip = tss->ip; ctxt->eflags = tss->flag | 2; - ctxt->regs[VCPU_REGS_RAX] = tss->ax; - ctxt->regs[VCPU_REGS_RCX] = tss->cx; - ctxt->regs[VCPU_REGS_RDX] = tss->dx; - ctxt->regs[VCPU_REGS_RBX] = tss->bx; - ctxt->regs[VCPU_REGS_RSP] = tss->sp; - ctxt->regs[VCPU_REGS_RBP] = tss->bp; - ctxt->regs[VCPU_REGS_RSI] = tss->si; - ctxt->regs[VCPU_REGS_RDI] = tss->di; + *reg_write(ctxt, VCPU_REGS_RAX) = tss->ax; + *reg_write(ctxt, VCPU_REGS_RCX) = tss->cx; + *reg_write(ctxt, VCPU_REGS_RDX) = tss->dx; + *reg_write(ctxt, VCPU_REGS_RBX) = tss->bx; + *reg_write(ctxt, VCPU_REGS_RSP) = tss->sp; + *reg_write(ctxt, VCPU_REGS_RBP) = tss->bp; + *reg_write(ctxt, VCPU_REGS_RSI) = tss->si; + *reg_write(ctxt, VCPU_REGS_RDI) = tss->di; /* * SDM says that segment selectors are loaded before segment @@ -2410,7 +2467,7 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS); /* - * Now load segment descriptors. If fault happenes at this stage + * Now load segment descriptors. If fault happens at this stage * it is handled in a context of new task */ ret = load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR); @@ -2436,7 +2493,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_16 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); @@ -2482,14 +2539,14 @@ static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, tss->cr3 = ctxt->ops->get_cr(ctxt, 3); tss->eip = ctxt->_eip; tss->eflags = ctxt->eflags; - tss->eax = ctxt->regs[VCPU_REGS_RAX]; - tss->ecx = ctxt->regs[VCPU_REGS_RCX]; - tss->edx = ctxt->regs[VCPU_REGS_RDX]; - tss->ebx = ctxt->regs[VCPU_REGS_RBX]; - tss->esp = ctxt->regs[VCPU_REGS_RSP]; - tss->ebp = ctxt->regs[VCPU_REGS_RBP]; - tss->esi = ctxt->regs[VCPU_REGS_RSI]; - tss->edi = ctxt->regs[VCPU_REGS_RDI]; + tss->eax = reg_read(ctxt, VCPU_REGS_RAX); + tss->ecx = reg_read(ctxt, VCPU_REGS_RCX); + tss->edx = reg_read(ctxt, VCPU_REGS_RDX); + tss->ebx = reg_read(ctxt, VCPU_REGS_RBX); + tss->esp = reg_read(ctxt, VCPU_REGS_RSP); + tss->ebp = reg_read(ctxt, VCPU_REGS_RBP); + tss->esi = reg_read(ctxt, VCPU_REGS_RSI); + tss->edi = reg_read(ctxt, VCPU_REGS_RDI); tss->es = get_segment_selector(ctxt, VCPU_SREG_ES); tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS); @@ -2511,14 +2568,14 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, ctxt->eflags = tss->eflags | 2; /* General purpose registers */ - ctxt->regs[VCPU_REGS_RAX] = tss->eax; - ctxt->regs[VCPU_REGS_RCX] = tss->ecx; - ctxt->regs[VCPU_REGS_RDX] = tss->edx; - ctxt->regs[VCPU_REGS_RBX] = tss->ebx; - ctxt->regs[VCPU_REGS_RSP] = tss->esp; - ctxt->regs[VCPU_REGS_RBP] = tss->ebp; - ctxt->regs[VCPU_REGS_RSI] = tss->esi; - ctxt->regs[VCPU_REGS_RDI] = tss->edi; + *reg_write(ctxt, VCPU_REGS_RAX) = tss->eax; + *reg_write(ctxt, VCPU_REGS_RCX) = tss->ecx; + *reg_write(ctxt, VCPU_REGS_RDX) = tss->edx; + *reg_write(ctxt, VCPU_REGS_RBX) = tss->ebx; + *reg_write(ctxt, VCPU_REGS_RSP) = tss->esp; + *reg_write(ctxt, VCPU_REGS_RBP) = tss->ebp; + *reg_write(ctxt, VCPU_REGS_RSI) = tss->esi; + *reg_write(ctxt, VCPU_REGS_RDI) = tss->edi; /* * SDM says that segment selectors are loaded before segment @@ -2583,7 +2640,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_32 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); @@ -2627,7 +2684,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, u16 tss_selector, int idt_index, int reason, bool has_error_code, u32 error_code) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; struct desc_struct curr_tss_desc, next_tss_desc; int ret; u16 old_tss_sel = get_segment_selector(ctxt, VCPU_SREG_TR); @@ -2652,7 +2709,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, * * 1. jmp/call/int to task gate: Check against DPL of the task gate * 2. Exception/IRQ/iret: No check is performed - * 3. jmp/call to TSS: Check agains DPL of the TSS + * 3. jmp/call to TSS: Check against DPL of the TSS */ if (reason == TASK_SWITCH_GATE) { if (idt_index != -1) { @@ -2693,7 +2750,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT; /* set back link to prev task only if NT bit is set in eflags - note that old_tss_sel is not used afetr this point */ + note that old_tss_sel is not used after this point */ if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE) old_tss_sel = 0xffff; @@ -2733,26 +2790,28 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, { int rc; + invalidate_registers(ctxt); ctxt->_eip = ctxt->eip; ctxt->dst.type = OP_NONE; rc = emulator_do_task_switch(ctxt, tss_selector, idt_index, reason, has_error_code, error_code); - if (rc == X86EMUL_CONTINUE) + if (rc == X86EMUL_CONTINUE) { ctxt->eip = ctxt->_eip; + writeback_registers(ctxt); + } return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; } -static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned seg, - int reg, struct operand *op) +static void string_addr_inc(struct x86_emulate_ctxt *ctxt, int reg, + struct operand *op) { - int df = (ctxt->eflags & EFLG_DF) ? -1 : 1; + int df = (ctxt->eflags & EFLG_DF) ? -op->count : op->count; - register_address_increment(ctxt, &ctxt->regs[reg], df * op->bytes); - op->addr.mem.ea = register_address(ctxt, ctxt->regs[reg]); - op->addr.mem.seg = seg; + register_address_increment(ctxt, reg_rmw(ctxt, reg), df * op->bytes); + op->addr.mem.ea = register_address(ctxt, reg_read(ctxt, reg)); } static int em_das(struct x86_emulate_ctxt *ctxt) @@ -2927,7 +2986,7 @@ static int em_cwd(struct x86_emulate_ctxt *ctxt) { ctxt->dst.type = OP_REG; ctxt->dst.bytes = ctxt->src.bytes; - ctxt->dst.addr.reg = &ctxt->regs[VCPU_REGS_RDX]; + ctxt->dst.addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX); ctxt->dst.val = ~((ctxt->src.val >> (ctxt->src.bytes * 8 - 1)) - 1); return X86EMUL_CONTINUE; @@ -2938,8 +2997,8 @@ static int em_rdtsc(struct x86_emulate_ctxt *ctxt) u64 tsc = 0; ctxt->ops->get_msr(ctxt, MSR_IA32_TSC, &tsc); - ctxt->regs[VCPU_REGS_RAX] = (u32)tsc; - ctxt->regs[VCPU_REGS_RDX] = tsc >> 32; + *reg_write(ctxt, VCPU_REGS_RAX) = (u32)tsc; + *reg_write(ctxt, VCPU_REGS_RDX) = tsc >> 32; return X86EMUL_CONTINUE; } @@ -2947,10 +3006,10 @@ static int em_rdpmc(struct x86_emulate_ctxt *ctxt) { u64 pmc; - if (ctxt->ops->read_pmc(ctxt, ctxt->regs[VCPU_REGS_RCX], &pmc)) + if (ctxt->ops->read_pmc(ctxt, reg_read(ctxt, VCPU_REGS_RCX), &pmc)) return emulate_gp(ctxt, 0); - ctxt->regs[VCPU_REGS_RAX] = (u32)pmc; - ctxt->regs[VCPU_REGS_RDX] = pmc >> 32; + *reg_write(ctxt, VCPU_REGS_RAX) = (u32)pmc; + *reg_write(ctxt, VCPU_REGS_RDX) = pmc >> 32; return X86EMUL_CONTINUE; } @@ -2992,9 +3051,9 @@ static int em_wrmsr(struct x86_emulate_ctxt *ctxt) { u64 msr_data; - msr_data = (u32)ctxt->regs[VCPU_REGS_RAX] - | ((u64)ctxt->regs[VCPU_REGS_RDX] << 32); - if (ctxt->ops->set_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], msr_data)) + msr_data = (u32)reg_read(ctxt, VCPU_REGS_RAX) + | ((u64)reg_read(ctxt, VCPU_REGS_RDX) << 32); + if (ctxt->ops->set_msr(ctxt, reg_read(ctxt, VCPU_REGS_RCX), msr_data)) return emulate_gp(ctxt, 0); return X86EMUL_CONTINUE; @@ -3004,11 +3063,11 @@ static int em_rdmsr(struct x86_emulate_ctxt *ctxt) { u64 msr_data; - if (ctxt->ops->get_msr(ctxt, ctxt->regs[VCPU_REGS_RCX], &msr_data)) + if (ctxt->ops->get_msr(ctxt, reg_read(ctxt, VCPU_REGS_RCX), &msr_data)) return emulate_gp(ctxt, 0); - ctxt->regs[VCPU_REGS_RAX] = (u32)msr_data; - ctxt->regs[VCPU_REGS_RDX] = msr_data >> 32; + *reg_write(ctxt, VCPU_REGS_RAX) = (u32)msr_data; + *reg_write(ctxt, VCPU_REGS_RDX) = msr_data >> 32; return X86EMUL_CONTINUE; } @@ -3188,8 +3247,8 @@ static int em_lmsw(struct x86_emulate_ctxt *ctxt) static int em_loop(struct x86_emulate_ctxt *ctxt) { - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RCX], -1); - if ((address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) != 0) && + register_address_increment(ctxt, reg_rmw(ctxt, VCPU_REGS_RCX), -1); + if ((address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) != 0) && (ctxt->b == 0xe2 || test_cc(ctxt->b ^ 0x5, ctxt->eflags))) jmp_rel(ctxt, ctxt->src.val); @@ -3198,7 +3257,7 @@ static int em_loop(struct x86_emulate_ctxt *ctxt) static int em_jcxz(struct x86_emulate_ctxt *ctxt) { - if (address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) == 0) + if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) jmp_rel(ctxt, ctxt->src.val); return X86EMUL_CONTINUE; @@ -3286,20 +3345,20 @@ static int em_cpuid(struct x86_emulate_ctxt *ctxt) { u32 eax, ebx, ecx, edx; - eax = ctxt->regs[VCPU_REGS_RAX]; - ecx = ctxt->regs[VCPU_REGS_RCX]; + eax = reg_read(ctxt, VCPU_REGS_RAX); + ecx = reg_read(ctxt, VCPU_REGS_RCX); ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx); - ctxt->regs[VCPU_REGS_RAX] = eax; - ctxt->regs[VCPU_REGS_RBX] = ebx; - ctxt->regs[VCPU_REGS_RCX] = ecx; - ctxt->regs[VCPU_REGS_RDX] = edx; + *reg_write(ctxt, VCPU_REGS_RAX) = eax; + *reg_write(ctxt, VCPU_REGS_RBX) = ebx; + *reg_write(ctxt, VCPU_REGS_RCX) = ecx; + *reg_write(ctxt, VCPU_REGS_RDX) = edx; return X86EMUL_CONTINUE; } static int em_lahf(struct x86_emulate_ctxt *ctxt) { - ctxt->regs[VCPU_REGS_RAX] &= ~0xff00UL; - ctxt->regs[VCPU_REGS_RAX] |= (ctxt->eflags & 0xff) << 8; + *reg_rmw(ctxt, VCPU_REGS_RAX) &= ~0xff00UL; + *reg_rmw(ctxt, VCPU_REGS_RAX) |= (ctxt->eflags & 0xff) << 8; return X86EMUL_CONTINUE; } @@ -3456,7 +3515,7 @@ static int check_svme(struct x86_emulate_ctxt *ctxt) static int check_svme_pa(struct x86_emulate_ctxt *ctxt) { - u64 rax = ctxt->regs[VCPU_REGS_RAX]; + u64 rax = reg_read(ctxt, VCPU_REGS_RAX); /* Valid physical address? */ if (rax & 0xffff000000000000ULL) @@ -3478,7 +3537,7 @@ static int check_rdtsc(struct x86_emulate_ctxt *ctxt) static int check_rdpmc(struct x86_emulate_ctxt *ctxt) { u64 cr4 = ctxt->ops->get_cr(ctxt, 4); - u64 rcx = ctxt->regs[VCPU_REGS_RCX]; + u64 rcx = reg_read(ctxt, VCPU_REGS_RCX); if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || (rcx > 3)) @@ -3531,13 +3590,13 @@ static int check_perm_out(struct x86_emulate_ctxt *ctxt) I2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \ I2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e) -static struct opcode group7_rm1[] = { +static const struct opcode group7_rm1[] = { DI(SrcNone | Priv, monitor), DI(SrcNone | Priv, mwait), N, N, N, N, N, N, }; -static struct opcode group7_rm3[] = { +static const struct opcode group7_rm3[] = { DIP(SrcNone | Prot | Priv, vmrun, check_svme_pa), II(SrcNone | Prot | VendorSpecific, em_vmmcall, vmmcall), DIP(SrcNone | Prot | Priv, vmload, check_svme_pa), @@ -3548,13 +3607,13 @@ static struct opcode group7_rm3[] = { DIP(SrcNone | Prot | Priv, invlpga, check_svme), }; -static struct opcode group7_rm7[] = { +static const struct opcode group7_rm7[] = { N, DIP(SrcNone, rdtscp, check_rdtsc), N, N, N, N, N, N, }; -static struct opcode group1[] = { +static const struct opcode group1[] = { I(Lock, em_add), I(Lock | PageTable, em_or), I(Lock, em_adc), @@ -3565,11 +3624,11 @@ static struct opcode group1[] = { I(0, em_cmp), }; -static struct opcode group1A[] = { +static const struct opcode group1A[] = { I(DstMem | SrcNone | Mov | Stack, em_pop), N, N, N, N, N, N, N, }; -static struct opcode group3[] = { +static const struct opcode group3[] = { I(DstMem | SrcImm, em_test), I(DstMem | SrcImm, em_test), I(DstMem | SrcNone | Lock, em_not), @@ -3580,13 +3639,13 @@ static struct opcode group3[] = { I(SrcMem, em_idiv_ex), }; -static struct opcode group4[] = { +static const struct opcode group4[] = { I(ByteOp | DstMem | SrcNone | Lock, em_grp45), I(ByteOp | DstMem | SrcNone | Lock, em_grp45), N, N, N, N, N, N, }; -static struct opcode group5[] = { +static const struct opcode group5[] = { I(DstMem | SrcNone | Lock, em_grp45), I(DstMem | SrcNone | Lock, em_grp45), I(SrcMem | Stack, em_grp45), @@ -3596,7 +3655,7 @@ static struct opcode group5[] = { I(SrcMem | Stack, em_grp45), N, }; -static struct opcode group6[] = { +static const struct opcode group6[] = { DI(Prot, sldt), DI(Prot, str), II(Prot | Priv | SrcMem16, em_lldt, lldt), @@ -3604,7 +3663,7 @@ static struct opcode group6[] = { N, N, N, N, }; -static struct group_dual group7 = { { +static const struct group_dual group7 = { { II(Mov | DstMem | Priv, em_sgdt, sgdt), II(Mov | DstMem | Priv, em_sidt, sidt), II(SrcMem | Priv, em_lgdt, lgdt), @@ -3621,7 +3680,7 @@ static struct group_dual group7 = { { EXT(0, group7_rm7), } }; -static struct opcode group8[] = { +static const struct opcode group8[] = { N, N, N, N, I(DstMem | SrcImmByte, em_bt), I(DstMem | SrcImmByte | Lock | PageTable, em_bts), @@ -3629,26 +3688,26 @@ static struct opcode group8[] = { I(DstMem | SrcImmByte | Lock | PageTable, em_btc), }; -static struct group_dual group9 = { { +static const struct group_dual group9 = { { N, I(DstMem64 | Lock | PageTable, em_cmpxchg8b), N, N, N, N, N, N, }, { N, N, N, N, N, N, N, N, } }; -static struct opcode group11[] = { +static const struct opcode group11[] = { I(DstMem | SrcImm | Mov | PageTable, em_mov), X7(D(Undefined)), }; -static struct gprefix pfx_0f_6f_0f_7f = { +static const struct gprefix pfx_0f_6f_0f_7f = { I(Mmx, em_mov), I(Sse | Aligned, em_mov), N, I(Sse | Unaligned, em_mov), }; -static struct gprefix pfx_vmovntpx = { +static const struct gprefix pfx_vmovntpx = { I(0, em_mov), N, N, N, }; -static struct opcode opcode_table[256] = { +static const struct opcode opcode_table[256] = { /* 0x00 - 0x07 */ I6ALU(Lock, em_add), I(ImplicitOps | Stack | No64 | Src2ES, em_push_sreg), @@ -3689,7 +3748,7 @@ static struct opcode opcode_table[256] = { I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), I(SrcImmByte | Mov | Stack, em_push), I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), - I2bvIP(DstDI | SrcDX | Mov | String, em_in, ins, check_perm_in), /* insb, insw/insd */ + I2bvIP(DstDI | SrcDX | Mov | String | Unaligned, em_in, ins, check_perm_in), /* insb, insw/insd */ I2bvIP(SrcSI | DstDX | String, em_out, outs, check_perm_out), /* outsb, outsw/outsd */ /* 0x70 - 0x7F */ X16(D(SrcImmByte)), @@ -3765,7 +3824,7 @@ static struct opcode opcode_table[256] = { D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5), }; -static struct opcode twobyte_table[256] = { +static const struct opcode twobyte_table[256] = { /* 0x00 - 0x0F */ G(0, group6), GD(0, &group7), N, N, N, I(ImplicitOps | VendorSpecific, em_syscall), @@ -3936,7 +3995,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, case OpAcc: op->type = OP_REG; op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; - op->addr.reg = &ctxt->regs[VCPU_REGS_RAX]; + op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX); fetch_register_operand(op); op->orig_val = op->val; break; @@ -3944,19 +4003,20 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, op->type = OP_MEM; op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; op->addr.mem.ea = - register_address(ctxt, ctxt->regs[VCPU_REGS_RDI]); + register_address(ctxt, reg_read(ctxt, VCPU_REGS_RDI)); op->addr.mem.seg = VCPU_SREG_ES; op->val = 0; + op->count = 1; break; case OpDX: op->type = OP_REG; op->bytes = 2; - op->addr.reg = &ctxt->regs[VCPU_REGS_RDX]; + op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX); fetch_register_operand(op); break; case OpCL: op->bytes = 1; - op->val = ctxt->regs[VCPU_REGS_RCX] & 0xff; + op->val = reg_read(ctxt, VCPU_REGS_RCX) & 0xff; break; case OpImmByte: rc = decode_imm(ctxt, op, 1, true); @@ -3987,9 +4047,10 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, op->type = OP_MEM; op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; op->addr.mem.ea = - register_address(ctxt, ctxt->regs[VCPU_REGS_RSI]); + register_address(ctxt, reg_read(ctxt, VCPU_REGS_RSI)); op->addr.mem.seg = seg_override(ctxt); op->val = 0; + op->count = 1; break; case OpImmFAddr: op->type = OP_IMM; @@ -4293,9 +4354,10 @@ static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt, read_mmx_reg(ctxt, &op->mm_val, op->addr.mm); } + int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) { - struct x86_emulate_ops *ops = ctxt->ops; + const struct x86_emulate_ops *ops = ctxt->ops; int rc = X86EMUL_CONTINUE; int saved_dst_type = ctxt->dst.type; @@ -4356,7 +4418,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) } /* Instruction can only be executed in protected mode */ - if ((ctxt->d & Prot) && !(ctxt->mode & X86EMUL_MODE_PROT)) { + if ((ctxt->d & Prot) && ctxt->mode < X86EMUL_MODE_PROT16) { rc = emulate_ud(ctxt); goto done; } @@ -4377,7 +4439,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt) if (ctxt->rep_prefix && (ctxt->d & String)) { /* All REP prefixes have the same first termination condition */ - if (address_mask(ctxt, ctxt->regs[VCPU_REGS_RCX]) == 0) { + if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) { ctxt->eip = ctxt->_eip; goto done; } @@ -4450,7 +4512,7 @@ special_insn: ctxt->dst.val = ctxt->src.addr.mem.ea; break; case 0x90 ... 0x97: /* nop / xchg reg, rax */ - if (ctxt->dst.addr.reg == &ctxt->regs[VCPU_REGS_RAX]) + if (ctxt->dst.addr.reg == reg_rmw(ctxt, VCPU_REGS_RAX)) break; rc = em_xchg(ctxt); break; @@ -4478,7 +4540,7 @@ special_insn: rc = em_grp2(ctxt); break; case 0xd2 ... 0xd3: /* Grp2 */ - ctxt->src.val = ctxt->regs[VCPU_REGS_RCX]; + ctxt->src.val = reg_read(ctxt, VCPU_REGS_RCX); rc = em_grp2(ctxt); break; case 0xe9: /* jmp rel */ @@ -4524,23 +4586,27 @@ writeback: ctxt->dst.type = saved_dst_type; if ((ctxt->d & SrcMask) == SrcSI) - string_addr_inc(ctxt, seg_override(ctxt), - VCPU_REGS_RSI, &ctxt->src); + string_addr_inc(ctxt, VCPU_REGS_RSI, &ctxt->src); if ((ctxt->d & DstMask) == DstDI) - string_addr_inc(ctxt, VCPU_SREG_ES, VCPU_REGS_RDI, - &ctxt->dst); + string_addr_inc(ctxt, VCPU_REGS_RDI, &ctxt->dst); if (ctxt->rep_prefix && (ctxt->d & String)) { + unsigned int count; struct read_cache *r = &ctxt->io_read; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RCX], -1); + if ((ctxt->d & SrcMask) == SrcSI) + count = ctxt->src.count; + else + count = ctxt->dst.count; + register_address_increment(ctxt, reg_rmw(ctxt, VCPU_REGS_RCX), + -count); if (!string_insn_completed(ctxt)) { /* * Re-enter guest when pio read ahead buffer is empty * or, if it is not used, after each 1024 iteration. */ - if ((r->end != 0 || ctxt->regs[VCPU_REGS_RCX] & 0x3ff) && + if ((r->end != 0 || reg_read(ctxt, VCPU_REGS_RCX) & 0x3ff) && (r->end == 0 || r->end != r->pos)) { /* * Reset read cache. Usually happens before @@ -4548,6 +4614,7 @@ writeback: * we have to do it here. */ ctxt->mem_read.end = 0; + writeback_registers(ctxt); return EMULATION_RESTART; } goto done; /* skip rip writeback */ @@ -4562,6 +4629,9 @@ done: if (rc == X86EMUL_INTERCEPTED) return EMULATION_INTERCEPTED; + if (rc == X86EMUL_CONTINUE) + writeback_registers(ctxt); + return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; twobyte_insn: @@ -4634,3 +4704,13 @@ twobyte_insn: cannot_emulate: return EMULATION_FAILED; } + +void emulator_invalidate_register_cache(struct x86_emulate_ctxt *ctxt) +{ + invalidate_registers(ctxt); +} + +void emulator_writeback_register_cache(struct x86_emulate_ctxt *ctxt) +{ + writeback_registers(ctxt); +} diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index adba28f88d1a..11300d2fa714 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -108,7 +108,7 @@ static s64 __kpit_elapsed(struct kvm *kvm) ktime_t remaining; struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; - if (!ps->pit_timer.period) + if (!ps->period) return 0; /* @@ -120,9 +120,9 @@ static s64 __kpit_elapsed(struct kvm *kvm) * itself with the initial count and continues counting * from there. */ - remaining = hrtimer_get_remaining(&ps->pit_timer.timer); - elapsed = ps->pit_timer.period - ktime_to_ns(remaining); - elapsed = mod_64(elapsed, ps->pit_timer.period); + remaining = hrtimer_get_remaining(&ps->timer); + elapsed = ps->period - ktime_to_ns(remaining); + elapsed = mod_64(elapsed, ps->period); return elapsed; } @@ -238,12 +238,12 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian) int value; spin_lock(&ps->inject_lock); - value = atomic_dec_return(&ps->pit_timer.pending); + value = atomic_dec_return(&ps->pending); if (value < 0) /* spurious acks can be generated if, for example, the * PIC is being reset. Handle it gracefully here */ - atomic_inc(&ps->pit_timer.pending); + atomic_inc(&ps->pending); else if (value > 0) /* in this case, we had multiple outstanding pit interrupts * that we needed to inject. Reinject @@ -261,28 +261,17 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) if (!kvm_vcpu_is_bsp(vcpu) || !pit) return; - timer = &pit->pit_state.pit_timer.timer; + timer = &pit->pit_state.timer; if (hrtimer_cancel(timer)) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); } static void destroy_pit_timer(struct kvm_pit *pit) { - hrtimer_cancel(&pit->pit_state.pit_timer.timer); + hrtimer_cancel(&pit->pit_state.timer); flush_kthread_work(&pit->expired); } -static bool kpit_is_periodic(struct kvm_timer *ktimer) -{ - struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state, - pit_timer); - return ps->is_periodic; -} - -static struct kvm_timer_ops kpit_ops = { - .is_periodic = kpit_is_periodic, -}; - static void pit_do_work(struct kthread_work *work) { struct kvm_pit *pit = container_of(work, struct kvm_pit, expired); @@ -322,16 +311,16 @@ static void pit_do_work(struct kthread_work *work) static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) { - struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); - struct kvm_pit *pt = ktimer->kvm->arch.vpit; + struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer); + struct kvm_pit *pt = ps->kvm->arch.vpit; - if (ktimer->reinject || !atomic_read(&ktimer->pending)) { - atomic_inc(&ktimer->pending); + if (ps->reinject || !atomic_read(&ps->pending)) { + atomic_inc(&ps->pending); queue_kthread_work(&pt->worker, &pt->expired); } - if (ktimer->t_ops->is_periodic(ktimer)) { - hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); + if (ps->is_periodic) { + hrtimer_add_expires_ns(&ps->timer, ps->period); return HRTIMER_RESTART; } else return HRTIMER_NORESTART; @@ -340,7 +329,6 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) { struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; - struct kvm_timer *pt = &ps->pit_timer; s64 interval; if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY) @@ -351,19 +339,18 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) pr_debug("create pit timer, interval is %llu nsec\n", interval); /* TODO The new value only affected after the retriggered */ - hrtimer_cancel(&pt->timer); + hrtimer_cancel(&ps->timer); flush_kthread_work(&ps->pit->expired); - pt->period = interval; + ps->period = interval; ps->is_periodic = is_period; - pt->timer.function = pit_timer_fn; - pt->t_ops = &kpit_ops; - pt->kvm = ps->pit->kvm; + ps->timer.function = pit_timer_fn; + ps->kvm = ps->pit->kvm; - atomic_set(&pt->pending, 0); + atomic_set(&ps->pending, 0); ps->irq_ack = 1; - hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval), + hrtimer_start(&ps->timer, ktime_add_ns(ktime_get(), interval), HRTIMER_MODE_ABS); } @@ -639,7 +626,7 @@ void kvm_pit_reset(struct kvm_pit *pit) } mutex_unlock(&pit->pit_state.lock); - atomic_set(&pit->pit_state.pit_timer.pending, 0); + atomic_set(&pit->pit_state.pending, 0); pit->pit_state.irq_ack = 1; } @@ -648,7 +635,7 @@ static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask) struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier); if (!mask) { - atomic_set(&pit->pit_state.pit_timer.pending, 0); + atomic_set(&pit->pit_state.pending, 0); pit->pit_state.irq_ack = 1; } } @@ -706,12 +693,11 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) pit_state = &pit->pit_state; pit_state->pit = pit; - hrtimer_init(&pit_state->pit_timer.timer, - CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + hrtimer_init(&pit_state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); pit_state->irq_ack_notifier.gsi = 0; pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); - pit_state->pit_timer.reinject = true; + pit_state->reinject = true; mutex_unlock(&pit->pit_state.lock); kvm_pit_reset(pit); @@ -761,7 +747,7 @@ void kvm_free_pit(struct kvm *kvm) kvm_unregister_irq_ack_notifier(kvm, &kvm->arch.vpit->pit_state.irq_ack_notifier); mutex_lock(&kvm->arch.vpit->pit_state.lock); - timer = &kvm->arch.vpit->pit_state.pit_timer.timer; + timer = &kvm->arch.vpit->pit_state.timer; hrtimer_cancel(timer); flush_kthread_work(&kvm->arch.vpit->expired); kthread_stop(kvm->arch.vpit->worker_task); diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index fdf40425ea1d..dd1b16b611b0 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h @@ -24,8 +24,12 @@ struct kvm_kpit_channel_state { struct kvm_kpit_state { struct kvm_kpit_channel_state channels[3]; u32 flags; - struct kvm_timer pit_timer; bool is_periodic; + s64 period; /* unit: ns */ + struct hrtimer timer; + atomic_t pending; /* accumulated triggered timers */ + bool reinject; + struct kvm *kvm; u32 speaker_data_on; struct mutex lock; struct kvm_pit *pit; diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 9fc9aa7ac703..848206df0967 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -190,17 +190,17 @@ void kvm_pic_update_irq(struct kvm_pic *s) int kvm_pic_set_irq(struct kvm_pic *s, int irq, int irq_source_id, int level) { - int ret = -1; + int ret, irq_level; + + BUG_ON(irq < 0 || irq >= PIC_NUM_PINS); pic_lock(s); - if (irq >= 0 && irq < PIC_NUM_PINS) { - int irq_level = __kvm_irq_line_state(&s->irq_states[irq], - irq_source_id, level); - ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, irq_level); - pic_update_irq(s); - trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, - s->pics[irq >> 3].imr, ret == 0); - } + irq_level = __kvm_irq_line_state(&s->irq_states[irq], + irq_source_id, level); + ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, irq_level); + pic_update_irq(s); + trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, + s->pics[irq >> 3].imr, ret == 0); pic_unlock(s); return ret; @@ -275,23 +275,20 @@ void kvm_pic_reset(struct kvm_kpic_state *s) { int irq, i; struct kvm_vcpu *vcpu; - u8 irr = s->irr, isr = s->imr; + u8 edge_irr = s->irr & ~s->elcr; bool found = false; s->last_irr = 0; - s->irr = 0; + s->irr &= s->elcr; s->imr = 0; - s->isr = 0; s->priority_add = 0; - s->irq_base = 0; - s->read_reg_select = 0; - s->poll = 0; s->special_mask = 0; - s->init_state = 0; - s->auto_eoi = 0; - s->rotate_on_auto_eoi = 0; - s->special_fully_nested_mode = 0; - s->init4 = 0; + s->read_reg_select = 0; + if (!s->init4) { + s->special_fully_nested_mode = 0; + s->auto_eoi = 0; + } + s->init_state = 1; kvm_for_each_vcpu(i, vcpu, s->pics_state->kvm) if (kvm_apic_accept_pic_intr(vcpu)) { @@ -304,7 +301,7 @@ void kvm_pic_reset(struct kvm_kpic_state *s) return; for (irq = 0; irq < PIC_NUM_PINS/2; irq++) - if (irr & (1 << irq) || isr & (1 << irq)) + if (edge_irr & (1 << irq)) pic_clear_isr(s, irq); } @@ -316,40 +313,13 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) addr &= 1; if (addr == 0) { if (val & 0x10) { - u8 edge_irr = s->irr & ~s->elcr; - int i; - bool found = false; - struct kvm_vcpu *vcpu; - s->init4 = val & 1; - s->last_irr = 0; - s->irr &= s->elcr; - s->imr = 0; - s->priority_add = 0; - s->special_mask = 0; - s->read_reg_select = 0; - if (!s->init4) { - s->special_fully_nested_mode = 0; - s->auto_eoi = 0; - } - s->init_state = 1; if (val & 0x02) pr_pic_unimpl("single mode not supported"); if (val & 0x08) pr_pic_unimpl( - "level sensitive irq not supported"); - - kvm_for_each_vcpu(i, vcpu, s->pics_state->kvm) - if (kvm_apic_accept_pic_intr(vcpu)) { - found = true; - break; - } - - - if (found) - for (irq = 0; irq < PIC_NUM_PINS/2; irq++) - if (edge_irr & (1 << irq)) - pic_clear_isr(s, irq); + "level sensitive irq not supported"); + kvm_pic_reset(s); } else if (val & 0x08) { if (val & 0x04) s->poll = 1; diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 2086f2bfba33..2d03568e9498 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -70,7 +70,7 @@ struct kvm_pic { struct kvm_io_device dev_slave; struct kvm_io_device dev_eclr; void (*ack_notifier)(void *opaque, int irq); - unsigned long irq_states[16]; + unsigned long irq_states[PIC_NUM_PINS]; }; struct kvm_pic *kvm_create_pic(struct kvm *kvm); diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h deleted file mode 100644 index 497dbaa366d4..000000000000 --- a/arch/x86/kvm/kvm_timer.h +++ /dev/null @@ -1,18 +0,0 @@ - -struct kvm_timer { - struct hrtimer timer; - s64 period; /* unit: ns */ - u32 timer_mode_mask; - u64 tscdeadline; - atomic_t pending; /* accumulated triggered timers */ - bool reinject; - struct kvm_timer_ops *t_ops; - struct kvm *kvm; - struct kvm_vcpu *vcpu; -}; - -struct kvm_timer_ops { - bool (*is_periodic)(struct kvm_timer *); -}; - -enum hrtimer_restart kvm_timer_fn(struct hrtimer *data); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ce878788a39f..c6e6b721b6ee 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -34,6 +34,7 @@ #include <asm/current.h> #include <asm/apicdef.h> #include <linux/atomic.h> +#include <linux/jump_label.h> #include "kvm_cache_regs.h" #include "irq.h" #include "trace.h" @@ -65,6 +66,7 @@ #define APIC_DEST_NOSHORT 0x0 #define APIC_DEST_MASK 0x800 #define MAX_APIC_VECTOR 256 +#define APIC_VECTORS_PER_REG 32 #define VEC_POS(v) ((v) & (32 - 1)) #define REG_POS(v) (((v) >> 5) << 4) @@ -72,11 +74,6 @@ static unsigned int min_timer_period_us = 500; module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR); -static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) -{ - return *((u32 *) (apic->regs + reg_off)); -} - static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) { *((u32 *) (apic->regs + reg_off)) = val; @@ -117,19 +114,23 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap) return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); } -static inline int apic_hw_enabled(struct kvm_lapic *apic) -{ - return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; -} +struct static_key_deferred apic_hw_disabled __read_mostly; +struct static_key_deferred apic_sw_disabled __read_mostly; -static inline int apic_sw_enabled(struct kvm_lapic *apic) +static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) { - return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; + if ((kvm_apic_get_reg(apic, APIC_SPIV) ^ val) & APIC_SPIV_APIC_ENABLED) { + if (val & APIC_SPIV_APIC_ENABLED) + static_key_slow_dec_deferred(&apic_sw_disabled); + else + static_key_slow_inc(&apic_sw_disabled.key); + } + apic_set_reg(apic, APIC_SPIV, val); } static inline int apic_enabled(struct kvm_lapic *apic) { - return apic_sw_enabled(apic) && apic_hw_enabled(apic); + return kvm_apic_sw_enabled(apic) && kvm_apic_hw_enabled(apic); } #define LVT_MASK \ @@ -139,36 +140,135 @@ static inline int apic_enabled(struct kvm_lapic *apic) (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) +static inline int apic_x2apic_mode(struct kvm_lapic *apic) +{ + return apic->vcpu->arch.apic_base & X2APIC_ENABLE; +} + static inline int kvm_apic_id(struct kvm_lapic *apic) { - return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; + return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; +} + +static inline u16 apic_cluster_id(struct kvm_apic_map *map, u32 ldr) +{ + u16 cid; + ldr >>= 32 - map->ldr_bits; + cid = (ldr >> map->cid_shift) & map->cid_mask; + + BUG_ON(cid >= ARRAY_SIZE(map->logical_map)); + + return cid; +} + +static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr) +{ + ldr >>= (32 - map->ldr_bits); + return ldr & map->lid_mask; +} + +static void recalculate_apic_map(struct kvm *kvm) +{ + struct kvm_apic_map *new, *old = NULL; + struct kvm_vcpu *vcpu; + int i; + + new = kzalloc(sizeof(struct kvm_apic_map), GFP_KERNEL); + + mutex_lock(&kvm->arch.apic_map_lock); + + if (!new) + goto out; + + new->ldr_bits = 8; + /* flat mode is default */ + new->cid_shift = 8; + new->cid_mask = 0; + new->lid_mask = 0xff; + + kvm_for_each_vcpu(i, vcpu, kvm) { + struct kvm_lapic *apic = vcpu->arch.apic; + u16 cid, lid; + u32 ldr; + + if (!kvm_apic_present(vcpu)) + continue; + + /* + * All APICs have to be configured in the same mode by an OS. + * We take advatage of this while building logical id loockup + * table. After reset APICs are in xapic/flat mode, so if we + * find apic with different setting we assume this is the mode + * OS wants all apics to be in; build lookup table accordingly. + */ + if (apic_x2apic_mode(apic)) { + new->ldr_bits = 32; + new->cid_shift = 16; + new->cid_mask = new->lid_mask = 0xffff; + } else if (kvm_apic_sw_enabled(apic) && + !new->cid_mask /* flat mode */ && + kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) { + new->cid_shift = 4; + new->cid_mask = 0xf; + new->lid_mask = 0xf; + } + + new->phys_map[kvm_apic_id(apic)] = apic; + + ldr = kvm_apic_get_reg(apic, APIC_LDR); + cid = apic_cluster_id(new, ldr); + lid = apic_logical_id(new, ldr); + + if (lid) + new->logical_map[cid][ffs(lid) - 1] = apic; + } +out: + old = rcu_dereference_protected(kvm->arch.apic_map, + lockdep_is_held(&kvm->arch.apic_map_lock)); + rcu_assign_pointer(kvm->arch.apic_map, new); + mutex_unlock(&kvm->arch.apic_map_lock); + + if (old) + kfree_rcu(old, rcu); +} + +static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id) +{ + apic_set_reg(apic, APIC_ID, id << 24); + recalculate_apic_map(apic->vcpu->kvm); +} + +static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id) +{ + apic_set_reg(apic, APIC_LDR, id); + recalculate_apic_map(apic->vcpu->kvm); } static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) { - return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); + return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); } static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) { - return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; + return kvm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; } static inline int apic_lvtt_oneshot(struct kvm_lapic *apic) { - return ((apic_get_reg(apic, APIC_LVTT) & + return ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT); } static inline int apic_lvtt_period(struct kvm_lapic *apic) { - return ((apic_get_reg(apic, APIC_LVTT) & + return ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC); } static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic) { - return ((apic_get_reg(apic, APIC_LVTT) & + return ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_TSCDEADLINE); } @@ -184,7 +284,7 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *feat; u32 v = APIC_VERSION; - if (!irqchip_in_kernel(vcpu->kvm)) + if (!kvm_vcpu_has_lapic(vcpu)) return; feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0); @@ -193,12 +293,7 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) apic_set_reg(apic, APIC_LVR, v); } -static inline int apic_x2apic_mode(struct kvm_lapic *apic) -{ - return apic->vcpu->arch.apic_base & X2APIC_ENABLE; -} - -static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { +static const unsigned int apic_lvt_mask[APIC_LVT_NUM] = { LVT_MASK , /* part LVTT mask, timer mode mask added at runtime */ LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ LVT_MASK | APIC_MODE_MASK, /* LVTPC */ @@ -208,25 +303,30 @@ static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { static int find_highest_vector(void *bitmap) { - u32 *word = bitmap; - int word_offset = MAX_APIC_VECTOR >> 5; + int vec; + u32 *reg; - while ((word_offset != 0) && (word[(--word_offset) << 2] == 0)) - continue; + for (vec = MAX_APIC_VECTOR - APIC_VECTORS_PER_REG; + vec >= 0; vec -= APIC_VECTORS_PER_REG) { + reg = bitmap + REG_POS(vec); + if (*reg) + return fls(*reg) - 1 + vec; + } - if (likely(!word_offset && !word[0])) - return -1; - else - return fls(word[word_offset << 2]) - 1 + (word_offset << 5); + return -1; } static u8 count_vectors(void *bitmap) { - u32 *word = bitmap; - int word_offset; + int vec; + u32 *reg; u8 count = 0; - for (word_offset = 0; word_offset < MAX_APIC_VECTOR >> 5; ++word_offset) - count += hweight32(word[word_offset << 2]); + + for (vec = 0; vec < MAX_APIC_VECTOR; vec += APIC_VECTORS_PER_REG) { + reg = bitmap + REG_POS(vec); + count += hweight32(*reg); + } + return count; } @@ -285,7 +385,6 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; int highest_irr; /* This may race with setting of irr in __apic_accept_irq() and @@ -293,9 +392,9 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) * will cause vmexit immediately and the value will be recalculated * on the next vmentry. */ - if (!apic) + if (!kvm_vcpu_has_lapic(vcpu)) return 0; - highest_irr = apic_find_highest_irr(apic); + highest_irr = apic_find_highest_irr(vcpu->arch.apic); return highest_irr; } @@ -378,8 +477,8 @@ static void apic_update_ppr(struct kvm_lapic *apic) u32 tpr, isrv, ppr, old_ppr; int isr; - old_ppr = apic_get_reg(apic, APIC_PROCPRI); - tpr = apic_get_reg(apic, APIC_TASKPRI); + old_ppr = kvm_apic_get_reg(apic, APIC_PROCPRI); + tpr = kvm_apic_get_reg(apic, APIC_TASKPRI); isr = apic_find_highest_isr(apic); isrv = (isr != -1) ? isr : 0; @@ -415,13 +514,13 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) u32 logical_id; if (apic_x2apic_mode(apic)) { - logical_id = apic_get_reg(apic, APIC_LDR); + logical_id = kvm_apic_get_reg(apic, APIC_LDR); return logical_id & mda; } - logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); + logical_id = GET_APIC_LOGICAL_ID(kvm_apic_get_reg(apic, APIC_LDR)); - switch (apic_get_reg(apic, APIC_DFR)) { + switch (kvm_apic_get_reg(apic, APIC_DFR)) { case APIC_DFR_FLAT: if (logical_id & mda) result = 1; @@ -433,7 +532,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) break; default: apic_debug("Bad DFR vcpu %d: %08x\n", - apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); + apic->vcpu->vcpu_id, kvm_apic_get_reg(apic, APIC_DFR)); break; } @@ -478,6 +577,72 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, return result; } +bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, + struct kvm_lapic_irq *irq, int *r) +{ + struct kvm_apic_map *map; + unsigned long bitmap = 1; + struct kvm_lapic **dst; + int i; + bool ret = false; + + *r = -1; + + if (irq->shorthand == APIC_DEST_SELF) { + *r = kvm_apic_set_irq(src->vcpu, irq); + return true; + } + + if (irq->shorthand) + return false; + + rcu_read_lock(); + map = rcu_dereference(kvm->arch.apic_map); + + if (!map) + goto out; + + if (irq->dest_mode == 0) { /* physical mode */ + if (irq->delivery_mode == APIC_DM_LOWEST || + irq->dest_id == 0xff) + goto out; + dst = &map->phys_map[irq->dest_id & 0xff]; + } else { + u32 mda = irq->dest_id << (32 - map->ldr_bits); + + dst = map->logical_map[apic_cluster_id(map, mda)]; + + bitmap = apic_logical_id(map, mda); + + if (irq->delivery_mode == APIC_DM_LOWEST) { + int l = -1; + for_each_set_bit(i, &bitmap, 16) { + if (!dst[i]) + continue; + if (l < 0) + l = i; + else if (kvm_apic_compare_prio(dst[i]->vcpu, dst[l]->vcpu) < 0) + l = i; + } + + bitmap = (l >= 0) ? 1 << l : 0; + } + } + + for_each_set_bit(i, &bitmap, 16) { + if (!dst[i]) + continue; + if (*r < 0) + *r = 0; + *r += kvm_apic_set_irq(dst[i]->vcpu, irq); + } + + ret = true; +out: + rcu_read_unlock(); + return ret; +} + /* * Add a pending IRQ into lapic. * Return 1 if successfully added and 0 if discarded. @@ -591,7 +756,7 @@ static int apic_set_eoi(struct kvm_lapic *apic) apic_clear_isr(vector, apic); apic_update_ppr(apic); - if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && + if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) { int trigger_mode; if (apic_test_vector(vector, apic->regs + APIC_TMR)) @@ -606,8 +771,8 @@ static int apic_set_eoi(struct kvm_lapic *apic) static void apic_send_ipi(struct kvm_lapic *apic) { - u32 icr_low = apic_get_reg(apic, APIC_ICR); - u32 icr_high = apic_get_reg(apic, APIC_ICR2); + u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR); + u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2); struct kvm_lapic_irq irq; irq.vector = icr_low & APIC_VECTOR_MASK; @@ -642,7 +807,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) ASSERT(apic != NULL); /* if initial count is 0, current count should also be 0 */ - if (apic_get_reg(apic, APIC_TMICT) == 0) + if (kvm_apic_get_reg(apic, APIC_TMICT) == 0) return 0; remaining = hrtimer_get_remaining(&apic->lapic_timer.timer); @@ -696,13 +861,15 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) val = apic_get_tmcct(apic); break; - + case APIC_PROCPRI: + apic_update_ppr(apic); + val = kvm_apic_get_reg(apic, offset); + break; case APIC_TASKPRI: report_tpr_access(apic, false); /* fall thru */ default: - apic_update_ppr(apic); - val = apic_get_reg(apic, offset); + val = kvm_apic_get_reg(apic, offset); break; } @@ -719,7 +886,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len, { unsigned char alignment = offset & 0xf; u32 result; - /* this bitmask has a bit cleared for each reserver register */ + /* this bitmask has a bit cleared for each reserved register */ static const u64 rmask = 0x43ff01ffffffe70cULL; if ((alignment + len) > 4) { @@ -754,7 +921,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len, static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr) { - return apic_hw_enabled(apic) && + return kvm_apic_hw_enabled(apic) && addr >= apic->base_address && addr < apic->base_address + LAPIC_MMIO_LENGTH; } @@ -777,7 +944,7 @@ static void update_divide_count(struct kvm_lapic *apic) { u32 tmp1, tmp2, tdcr; - tdcr = apic_get_reg(apic, APIC_TDCR); + tdcr = kvm_apic_get_reg(apic, APIC_TDCR); tmp1 = tdcr & 0xf; tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; apic->divide_count = 0x1 << (tmp2 & 0x7); @@ -792,9 +959,9 @@ static void start_apic_timer(struct kvm_lapic *apic) atomic_set(&apic->lapic_timer.pending, 0); if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) { - /* lapic timer in oneshot or peroidic mode */ + /* lapic timer in oneshot or periodic mode */ now = apic->lapic_timer.timer.base->get_time(); - apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) + apic->lapic_timer.period = (u64)kvm_apic_get_reg(apic, APIC_TMICT) * APIC_BUS_CYCLE_NS * apic->divide_count; if (!apic->lapic_timer.period) @@ -826,7 +993,7 @@ static void start_apic_timer(struct kvm_lapic *apic) "timer initial count 0x%x, period %lldns, " "expire @ 0x%016" PRIx64 ".\n", __func__, APIC_BUS_CYCLE_NS, ktime_to_ns(now), - apic_get_reg(apic, APIC_TMICT), + kvm_apic_get_reg(apic, APIC_TMICT), apic->lapic_timer.period, ktime_to_ns(ktime_add_ns(now, apic->lapic_timer.period))); @@ -858,7 +1025,7 @@ static void start_apic_timer(struct kvm_lapic *apic) static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) { - int nmi_wd_enabled = apic_lvt_nmi_mode(apic_get_reg(apic, APIC_LVT0)); + int nmi_wd_enabled = apic_lvt_nmi_mode(kvm_apic_get_reg(apic, APIC_LVT0)); if (apic_lvt_nmi_mode(lvt0_val)) { if (!nmi_wd_enabled) { @@ -879,7 +1046,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) switch (reg) { case APIC_ID: /* Local APIC ID */ if (!apic_x2apic_mode(apic)) - apic_set_reg(apic, APIC_ID, val); + kvm_apic_set_id(apic, val >> 24); else ret = 1; break; @@ -895,29 +1062,30 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_LDR: if (!apic_x2apic_mode(apic)) - apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); + kvm_apic_set_ldr(apic, val & APIC_LDR_MASK); else ret = 1; break; case APIC_DFR: - if (!apic_x2apic_mode(apic)) + if (!apic_x2apic_mode(apic)) { apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); - else + recalculate_apic_map(apic->vcpu->kvm); + } else ret = 1; break; case APIC_SPIV: { u32 mask = 0x3ff; - if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) + if (kvm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) mask |= APIC_SPIV_DIRECTED_EOI; - apic_set_reg(apic, APIC_SPIV, val & mask); + apic_set_spiv(apic, val & mask); if (!(val & APIC_SPIV_APIC_ENABLED)) { int i; u32 lvt_val; for (i = 0; i < APIC_LVT_NUM; i++) { - lvt_val = apic_get_reg(apic, + lvt_val = kvm_apic_get_reg(apic, APIC_LVTT + 0x10 * i); apic_set_reg(apic, APIC_LVTT + 0x10 * i, lvt_val | APIC_LVT_MASKED); @@ -946,7 +1114,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_LVT1: case APIC_LVTERR: /* TODO: Check vector */ - if (!apic_sw_enabled(apic)) + if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4]; @@ -955,12 +1123,12 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) break; case APIC_LVTT: - if ((apic_get_reg(apic, APIC_LVTT) & + if ((kvm_apic_get_reg(apic, APIC_LVTT) & apic->lapic_timer.timer_mode_mask) != (val & apic->lapic_timer.timer_mode_mask)) hrtimer_cancel(&apic->lapic_timer.timer); - if (!apic_sw_enabled(apic)) + if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); apic_set_reg(apic, APIC_LVTT, val); @@ -1039,24 +1207,30 @@ static int apic_mmio_write(struct kvm_io_device *this, void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; - - if (apic) + if (kvm_vcpu_has_lapic(vcpu)) apic_reg_write(vcpu->arch.apic, APIC_EOI, 0); } EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); void kvm_free_lapic(struct kvm_vcpu *vcpu) { + struct kvm_lapic *apic = vcpu->arch.apic; + if (!vcpu->arch.apic) return; - hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); + hrtimer_cancel(&apic->lapic_timer.timer); + + if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE)) + static_key_slow_dec_deferred(&apic_hw_disabled); + + if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED)) + static_key_slow_dec_deferred(&apic_sw_disabled); - if (vcpu->arch.apic->regs) - free_page((unsigned long)vcpu->arch.apic->regs); + if (apic->regs) + free_page((unsigned long)apic->regs); - kfree(vcpu->arch.apic); + kfree(apic); } /* @@ -1068,10 +1242,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic) - return 0; - if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic)) + if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || + apic_lvtt_period(apic)) return 0; return apic->lapic_timer.tscdeadline; @@ -1080,10 +1253,9 @@ u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu) void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic) - return; - if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic)) + if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) || + apic_lvtt_period(apic)) return; hrtimer_cancel(&apic->lapic_timer.timer); @@ -1095,20 +1267,21 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!apic) + if (!kvm_vcpu_has_lapic(vcpu)) return; + apic_set_tpr(apic, ((cr8 & 0x0f) << 4) - | (apic_get_reg(apic, APIC_TASKPRI) & 4)); + | (kvm_apic_get_reg(apic, APIC_TASKPRI) & 4)); } u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; u64 tpr; - if (!apic) + if (!kvm_vcpu_has_lapic(vcpu)) return 0; - tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); + + tpr = (u64) kvm_apic_get_reg(vcpu->arch.apic, APIC_TASKPRI); return (tpr & 0xf0) >> 4; } @@ -1123,6 +1296,15 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) return; } + /* update jump label if enable bit changes */ + if ((vcpu->arch.apic_base ^ value) & MSR_IA32_APICBASE_ENABLE) { + if (value & MSR_IA32_APICBASE_ENABLE) + static_key_slow_dec_deferred(&apic_hw_disabled); + else + static_key_slow_inc(&apic_hw_disabled.key); + recalculate_apic_map(vcpu->kvm); + } + if (!kvm_vcpu_is_bsp(apic->vcpu)) value &= ~MSR_IA32_APICBASE_BSP; @@ -1130,7 +1312,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) if (apic_x2apic_mode(apic)) { u32 id = kvm_apic_id(apic); u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf)); - apic_set_reg(apic, APIC_LDR, ldr); + kvm_apic_set_ldr(apic, ldr); } apic->base_address = apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_BASE; @@ -1155,7 +1337,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) /* Stop the timer in case it's a reset to an active apic */ hrtimer_cancel(&apic->lapic_timer.timer); - apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); + kvm_apic_set_id(apic, vcpu->vcpu_id); kvm_apic_set_version(apic->vcpu); for (i = 0; i < APIC_LVT_NUM; i++) @@ -1164,9 +1346,9 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); apic_set_reg(apic, APIC_DFR, 0xffffffffU); - apic_set_reg(apic, APIC_SPIV, 0xff); + apic_set_spiv(apic, 0xff); apic_set_reg(apic, APIC_TASKPRI, 0); - apic_set_reg(apic, APIC_LDR, 0); + kvm_apic_set_ldr(apic, 0); apic_set_reg(apic, APIC_ESR, 0); apic_set_reg(apic, APIC_ICR, 0); apic_set_reg(apic, APIC_ICR2, 0); @@ -1183,7 +1365,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) update_divide_count(apic); atomic_set(&apic->lapic_timer.pending, 0); if (kvm_vcpu_is_bsp(vcpu)) - vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; + kvm_lapic_set_base(vcpu, + vcpu->arch.apic_base | MSR_IA32_APICBASE_BSP); vcpu->arch.pv_eoi.msr_val = 0; apic_update_ppr(apic); @@ -1196,45 +1379,34 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) vcpu->arch.apic_base, apic->base_address); } -bool kvm_apic_present(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic); -} - -int kvm_lapic_enabled(struct kvm_vcpu *vcpu) -{ - return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic); -} - /* *---------------------------------------------------------------------- * timer interface *---------------------------------------------------------------------- */ -static bool lapic_is_periodic(struct kvm_timer *ktimer) +static bool lapic_is_periodic(struct kvm_lapic *apic) { - struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, - lapic_timer); return apic_lvtt_period(apic); } int apic_has_pending_timer(struct kvm_vcpu *vcpu) { - struct kvm_lapic *lapic = vcpu->arch.apic; + struct kvm_lapic *apic = vcpu->arch.apic; - if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT)) - return atomic_read(&lapic->lapic_timer.pending); + if (kvm_vcpu_has_lapic(vcpu) && apic_enabled(apic) && + apic_lvt_enabled(apic, APIC_LVTT)) + return atomic_read(&apic->lapic_timer.pending); return 0; } int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) { - u32 reg = apic_get_reg(apic, lvt_type); + u32 reg = kvm_apic_get_reg(apic, lvt_type); int vector, mode, trig_mode; - if (apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) { + if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) { vector = reg & APIC_VECTOR_MASK; mode = reg & APIC_MODE_MASK; trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; @@ -1251,15 +1423,40 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu) kvm_apic_local_deliver(apic, APIC_LVT0); } -static struct kvm_timer_ops lapic_timer_ops = { - .is_periodic = lapic_is_periodic, -}; - static const struct kvm_io_device_ops apic_mmio_ops = { .read = apic_mmio_read, .write = apic_mmio_write, }; +static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) +{ + struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); + struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, lapic_timer); + struct kvm_vcpu *vcpu = apic->vcpu; + wait_queue_head_t *q = &vcpu->wq; + + /* + * There is a race window between reading and incrementing, but we do + * not care about potentially losing timer events in the !reinject + * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked + * in vcpu_enter_guest. + */ + if (!atomic_read(&ktimer->pending)) { + atomic_inc(&ktimer->pending); + /* FIXME: this code should not know anything about vcpus */ + kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); + } + + if (waitqueue_active(q)) + wake_up_interruptible(q); + + if (lapic_is_periodic(apic)) { + hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); + return HRTIMER_RESTART; + } else + return HRTIMER_NORESTART; +} + int kvm_create_lapic(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic; @@ -1283,14 +1480,17 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - apic->lapic_timer.timer.function = kvm_timer_fn; - apic->lapic_timer.t_ops = &lapic_timer_ops; - apic->lapic_timer.kvm = vcpu->kvm; - apic->lapic_timer.vcpu = vcpu; + apic->lapic_timer.timer.function = apic_timer_fn; - apic->base_address = APIC_DEFAULT_PHYS_BASE; - vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; + /* + * APIC is created enabled. This will prevent kvm_lapic_set_base from + * thinking that APIC satet has changed. + */ + vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE; + kvm_lapic_set_base(vcpu, + APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); + static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */ kvm_lapic_reset(vcpu); kvm_iodevice_init(&apic->dev, &apic_mmio_ops); @@ -1306,23 +1506,23 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) struct kvm_lapic *apic = vcpu->arch.apic; int highest_irr; - if (!apic || !apic_enabled(apic)) + if (!kvm_vcpu_has_lapic(vcpu) || !apic_enabled(apic)) return -1; apic_update_ppr(apic); highest_irr = apic_find_highest_irr(apic); if ((highest_irr == -1) || - ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) + ((highest_irr & 0xF0) <= kvm_apic_get_reg(apic, APIC_PROCPRI))) return -1; return highest_irr; } int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) { - u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0); + u32 lvt0 = kvm_apic_get_reg(vcpu->arch.apic, APIC_LVT0); int r = 0; - if (!apic_hw_enabled(vcpu->arch.apic)) + if (!kvm_apic_hw_enabled(vcpu->arch.apic)) r = 1; if ((lvt0 & APIC_LVT_MASKED) == 0 && GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT) @@ -1334,7 +1534,10 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (apic && atomic_read(&apic->lapic_timer.pending) > 0) { + if (!kvm_vcpu_has_lapic(vcpu)) + return; + + if (atomic_read(&apic->lapic_timer.pending) > 0) { if (kvm_apic_local_deliver(apic, APIC_LVTT)) atomic_dec(&apic->lapic_timer.pending); } @@ -1354,12 +1557,17 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) return vector; } -void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s) { struct kvm_lapic *apic = vcpu->arch.apic; - apic->base_address = vcpu->arch.apic_base & - MSR_IA32_APICBASE_BASE; + kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); + /* set SPIV separately to get count of SW disabled APICs right */ + apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV))); + memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s); + /* call kvm_apic_set_id() to put apic into apic_map */ + kvm_apic_set_id(apic, kvm_apic_id(apic)); kvm_apic_set_version(vcpu); apic_update_ppr(apic); @@ -1374,13 +1582,12 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) { - struct kvm_lapic *apic = vcpu->arch.apic; struct hrtimer *timer; - if (!apic) + if (!kvm_vcpu_has_lapic(vcpu)) return; - timer = &apic->lapic_timer.timer; + timer = &vcpu->arch.apic->lapic_timer.timer; if (hrtimer_cancel(timer)) hrtimer_start_expires(timer, HRTIMER_MODE_ABS); } @@ -1478,7 +1685,7 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention)) return; - tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff; + tpr = kvm_apic_get_reg(apic, APIC_TASKPRI) & 0xff; max_irr = apic_find_highest_irr(apic); if (max_irr < 0) max_irr = 0; @@ -1537,7 +1744,7 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data) { struct kvm_lapic *apic = vcpu->arch.apic; - if (!irqchip_in_kernel(vcpu->kvm)) + if (!kvm_vcpu_has_lapic(vcpu)) return 1; /* if this is ICR write vector before command */ @@ -1551,7 +1758,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data) struct kvm_lapic *apic = vcpu->arch.apic; u32 low, high = 0; - if (!irqchip_in_kernel(vcpu->kvm)) + if (!kvm_vcpu_has_lapic(vcpu)) return 1; if (apic_reg_read(apic, reg, 4, &low)) @@ -1576,3 +1783,10 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data) return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data, addr); } + +void kvm_lapic_init(void) +{ + /* do not patch jump label more than once per second */ + jump_label_rate_limit(&apic_hw_disabled, HZ); + jump_label_rate_limit(&apic_sw_disabled, HZ); +} diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 4af5405ae1e2..e5ebf9f3571f 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -2,10 +2,17 @@ #define __KVM_X86_LAPIC_H #include "iodev.h" -#include "kvm_timer.h" #include <linux/kvm_host.h> +struct kvm_timer { + struct hrtimer timer; + s64 period; /* unit: ns */ + u32 timer_mode_mask; + u64 tscdeadline; + atomic_t pending; /* accumulated triggered timers */ +}; + struct kvm_lapic { unsigned long base_address; struct kvm_io_device dev; @@ -45,11 +52,13 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type); +bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, + struct kvm_lapic_irq *irq, int *r); + u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); -void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); -int kvm_lapic_enabled(struct kvm_vcpu *vcpu); -bool kvm_apic_present(struct kvm_vcpu *vcpu); +void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, + struct kvm_lapic_state *s); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu); @@ -71,4 +80,48 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) } int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); +void kvm_lapic_init(void); + +static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off) +{ + return *((u32 *) (apic->regs + reg_off)); +} + +extern struct static_key kvm_no_apic_vcpu; + +static inline bool kvm_vcpu_has_lapic(struct kvm_vcpu *vcpu) +{ + if (static_key_false(&kvm_no_apic_vcpu)) + return vcpu->arch.apic; + return true; +} + +extern struct static_key_deferred apic_hw_disabled; + +static inline int kvm_apic_hw_enabled(struct kvm_lapic *apic) +{ + if (static_key_false(&apic_hw_disabled.key)) + return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; + return MSR_IA32_APICBASE_ENABLE; +} + +extern struct static_key_deferred apic_sw_disabled; + +static inline int kvm_apic_sw_enabled(struct kvm_lapic *apic) +{ + if (static_key_false(&apic_sw_disabled.key)) + return kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; + return APIC_SPIV_APIC_ENABLED; +} + +static inline bool kvm_apic_present(struct kvm_vcpu *vcpu) +{ + return kvm_vcpu_has_lapic(vcpu) && kvm_apic_hw_enabled(vcpu->arch.apic); +} + +static inline int kvm_lapic_enabled(struct kvm_vcpu *vcpu) +{ + return kvm_apic_present(vcpu) && kvm_apic_sw_enabled(vcpu->arch.apic); +} + #endif diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7fbd0d273ea8..d289fee1ffb8 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -556,6 +556,14 @@ static int mmu_spte_clear_track_bits(u64 *sptep) return 0; pfn = spte_to_pfn(old_spte); + + /* + * KVM does not hold the refcount of the page used by + * kvm mmu, before reclaiming the page, we should + * unmap it from mmu first. + */ + WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn))); + if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) kvm_set_pfn_accessed(pfn); if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) @@ -960,13 +968,10 @@ static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn) static unsigned long *__gfn_to_rmap(gfn_t gfn, int level, struct kvm_memory_slot *slot) { - struct kvm_lpage_info *linfo; - - if (likely(level == PT_PAGE_TABLE_LEVEL)) - return &slot->rmap[gfn - slot->base_gfn]; + unsigned long idx; - linfo = lpage_info_slot(gfn, slot, level); - return &linfo->rmap_pde; + idx = gfn_to_index(gfn, slot->base_gfn, level); + return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx]; } /* @@ -1173,7 +1178,8 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, unsigned long *rmapp; while (mask) { - rmapp = &slot->rmap[gfn_offset + __ffs(mask)]; + rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask), + PT_PAGE_TABLE_LEVEL, slot); __rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL, false); /* clear the first set bit */ @@ -1200,7 +1206,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn) } static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator iter; @@ -1218,7 +1224,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, } static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator iter; @@ -1259,43 +1265,67 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, return 0; } -static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, - unsigned long data, - int (*handler)(struct kvm *kvm, unsigned long *rmapp, - unsigned long data)) +static int kvm_handle_hva_range(struct kvm *kvm, + unsigned long start, + unsigned long end, + unsigned long data, + int (*handler)(struct kvm *kvm, + unsigned long *rmapp, + struct kvm_memory_slot *slot, + unsigned long data)) { int j; - int ret; - int retval = 0; + int ret = 0; struct kvm_memslots *slots; struct kvm_memory_slot *memslot; slots = kvm_memslots(kvm); kvm_for_each_memslot(memslot, slots) { - unsigned long start = memslot->userspace_addr; - unsigned long end; + unsigned long hva_start, hva_end; + gfn_t gfn_start, gfn_end; - end = start + (memslot->npages << PAGE_SHIFT); - if (hva >= start && hva < end) { - gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; - gfn_t gfn = memslot->base_gfn + gfn_offset; + hva_start = max(start, memslot->userspace_addr); + hva_end = min(end, memslot->userspace_addr + + (memslot->npages << PAGE_SHIFT)); + if (hva_start >= hva_end) + continue; + /* + * {gfn(page) | page intersects with [hva_start, hva_end)} = + * {gfn_start, gfn_start+1, ..., gfn_end-1}. + */ + gfn_start = hva_to_gfn_memslot(hva_start, memslot); + gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot); - ret = handler(kvm, &memslot->rmap[gfn_offset], data); + for (j = PT_PAGE_TABLE_LEVEL; + j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) { + unsigned long idx, idx_end; + unsigned long *rmapp; - for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { - struct kvm_lpage_info *linfo; + /* + * {idx(page_j) | page_j intersects with + * [hva_start, hva_end)} = {idx, idx+1, ..., idx_end}. + */ + idx = gfn_to_index(gfn_start, memslot->base_gfn, j); + idx_end = gfn_to_index(gfn_end - 1, memslot->base_gfn, j); - linfo = lpage_info_slot(gfn, memslot, - PT_DIRECTORY_LEVEL + j); - ret |= handler(kvm, &linfo->rmap_pde, data); - } - trace_kvm_age_page(hva, memslot, ret); - retval |= ret; + rmapp = __gfn_to_rmap(gfn_start, j, memslot); + + for (; idx <= idx_end; ++idx) + ret |= handler(kvm, rmapp++, memslot, data); } } - return retval; + return ret; +} + +static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, + unsigned long data, + int (*handler)(struct kvm *kvm, unsigned long *rmapp, + struct kvm_memory_slot *slot, + unsigned long data)) +{ + return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler); } int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) @@ -1303,13 +1333,18 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); } +int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) +{ + return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp); +} + void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) { kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp); } static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator uninitialized_var(iter); @@ -1323,8 +1358,10 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, * This has some overhead, but not as much as the cost of swapping * out actively used pages or breaking up actively used hugepages. */ - if (!shadow_accessed_mask) - return kvm_unmap_rmapp(kvm, rmapp, data); + if (!shadow_accessed_mask) { + young = kvm_unmap_rmapp(kvm, rmapp, slot, data); + goto out; + } for (sptep = rmap_get_first(*rmapp, &iter); sptep; sptep = rmap_get_next(&iter)) { @@ -1336,12 +1373,14 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, (unsigned long *)sptep); } } - +out: + /* @data has hva passed to kvm_age_hva(). */ + trace_kvm_age_page(data, slot, young); return young; } static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp, - unsigned long data) + struct kvm_memory_slot *slot, unsigned long data) { u64 *sptep; struct rmap_iterator iter; @@ -1379,13 +1418,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); - kvm_unmap_rmapp(vcpu->kvm, rmapp, 0); + kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, 0); kvm_flush_remote_tlbs(vcpu->kvm); } int kvm_age_hva(struct kvm *kvm, unsigned long hva) { - return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); + return kvm_handle_hva(kvm, hva, hva, kvm_age_rmapp); } int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) @@ -2457,7 +2496,9 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, rmap_recycle(vcpu, sptep, gfn); } } - kvm_release_pfn_clean(pfn); + + if (!is_error_pfn(pfn)) + kvm_release_pfn_clean(pfn); } static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) @@ -2469,17 +2510,12 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, bool no_dirty_log) { struct kvm_memory_slot *slot; - unsigned long hva; slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log); - if (!slot) { - get_page(fault_page); - return page_to_pfn(fault_page); - } + if (!slot) + return KVM_PFN_ERR_FAULT; - hva = gfn_to_hva_memslot(slot, gfn); - - return hva_to_pfn_atomic(vcpu->kvm, hva); + return gfn_to_pfn_memslot_atomic(slot, gfn); } static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, @@ -2580,11 +2616,6 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr, iterator.level - 1, 1, ACC_ALL, iterator.sptep); - if (!sp) { - pgprintk("nonpaging_map: ENOMEM\n"); - kvm_release_pfn_clean(pfn); - return -ENOMEM; - } mmu_spte_set(iterator.sptep, __pa(sp->spt) @@ -2611,8 +2642,16 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct * static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn) { - kvm_release_pfn_clean(pfn); - if (is_hwpoison_pfn(pfn)) { + /* + * Do not cache the mmio info caused by writing the readonly gfn + * into the spte otherwise read access on readonly gfn also can + * caused mmio page fault and treat it as mmio access. + * Return 1 to tell kvm to emulate it. + */ + if (pfn == KVM_PFN_ERR_RO_FAULT) + return 1; + + if (pfn == KVM_PFN_ERR_HWPOISON) { kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current); return 0; } @@ -3236,8 +3275,6 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn, if (!async) return false; /* *pfn has correct page already */ - put_page(pfn_to_page(*pfn)); - if (!prefault && can_do_async_pf(vcpu)) { trace_kvm_try_async_get_page(gva, gfn); if (kvm_find_async_pf_gfn(vcpu, gfn)) { @@ -3371,6 +3408,18 @@ static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level) return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0; } +static inline void protect_clean_gpte(unsigned *access, unsigned gpte) +{ + unsigned mask; + + BUILD_BUG_ON(PT_WRITABLE_MASK != ACC_WRITE_MASK); + + mask = (unsigned)~ACC_WRITE_MASK; + /* Allow write access to dirty gptes */ + mask |= (gpte >> (PT_DIRTY_SHIFT - PT_WRITABLE_SHIFT)) & PT_WRITABLE_MASK; + *access &= mask; +} + static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access, int *nr_present) { @@ -3388,6 +3437,25 @@ static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access, return false; } +static inline unsigned gpte_access(struct kvm_vcpu *vcpu, u64 gpte) +{ + unsigned access; + + access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK; + access &= ~(gpte >> PT64_NX_SHIFT); + + return access; +} + +static inline bool is_last_gpte(struct kvm_mmu *mmu, unsigned level, unsigned gpte) +{ + unsigned index; + + index = level - 1; + index |= (gpte & PT_PAGE_SIZE_MASK) >> (PT_PAGE_SIZE_SHIFT - 2); + return mmu->last_pte_bitmap & (1 << index); +} + #define PTTYPE 64 #include "paging_tmpl.h" #undef PTTYPE @@ -3457,6 +3525,56 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, } } +static void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu) +{ + unsigned bit, byte, pfec; + u8 map; + bool fault, x, w, u, wf, uf, ff, smep; + + smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); + for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) { + pfec = byte << 1; + map = 0; + wf = pfec & PFERR_WRITE_MASK; + uf = pfec & PFERR_USER_MASK; + ff = pfec & PFERR_FETCH_MASK; + for (bit = 0; bit < 8; ++bit) { + x = bit & ACC_EXEC_MASK; + w = bit & ACC_WRITE_MASK; + u = bit & ACC_USER_MASK; + + /* Not really needed: !nx will cause pte.nx to fault */ + x |= !mmu->nx; + /* Allow supervisor writes if !cr0.wp */ + w |= !is_write_protection(vcpu) && !uf; + /* Disallow supervisor fetches of user code if cr4.smep */ + x &= !(smep && u && !uf); + + fault = (ff && !x) || (uf && !u) || (wf && !w); + map |= fault << bit; + } + mmu->permissions[byte] = map; + } +} + +static void update_last_pte_bitmap(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu) +{ + u8 map; + unsigned level, root_level = mmu->root_level; + const unsigned ps_set_index = 1 << 2; /* bit 2 of index: ps */ + + if (root_level == PT32E_ROOT_LEVEL) + --root_level; + /* PT_PAGE_TABLE_LEVEL always terminates */ + map = 1 | (1 << ps_set_index); + for (level = PT_DIRECTORY_LEVEL; level <= root_level; ++level) { + if (level <= PT_PDPE_LEVEL + && (mmu->root_level >= PT32E_ROOT_LEVEL || is_pse(vcpu))) + map |= 1 << (ps_set_index | (level - 1)); + } + mmu->last_pte_bitmap = map; +} + static int paging64_init_context_common(struct kvm_vcpu *vcpu, struct kvm_mmu *context, int level) @@ -3465,6 +3583,8 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, context->root_level = level; reset_rsvds_bits_mask(vcpu, context); + update_permission_bitmask(vcpu, context); + update_last_pte_bitmap(vcpu, context); ASSERT(is_pae(vcpu)); context->new_cr3 = paging_new_cr3; @@ -3493,6 +3613,8 @@ static int paging32_init_context(struct kvm_vcpu *vcpu, context->root_level = PT32_ROOT_LEVEL; reset_rsvds_bits_mask(vcpu, context); + update_permission_bitmask(vcpu, context); + update_last_pte_bitmap(vcpu, context); context->new_cr3 = paging_new_cr3; context->page_fault = paging32_page_fault; @@ -3553,6 +3675,9 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu) context->gva_to_gpa = paging32_gva_to_gpa; } + update_permission_bitmask(vcpu, context); + update_last_pte_bitmap(vcpu, context); + return 0; } @@ -3628,6 +3753,9 @@ static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu) g_context->gva_to_gpa = paging32_gva_to_gpa_nested; } + update_permission_bitmask(vcpu, g_context); + update_last_pte_bitmap(vcpu, g_context); + return 0; } diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index e374db9af021..69871080e866 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -18,8 +18,10 @@ #define PT_PCD_MASK (1ULL << 4) #define PT_ACCESSED_SHIFT 5 #define PT_ACCESSED_MASK (1ULL << PT_ACCESSED_SHIFT) -#define PT_DIRTY_MASK (1ULL << 6) -#define PT_PAGE_SIZE_MASK (1ULL << 7) +#define PT_DIRTY_SHIFT 6 +#define PT_DIRTY_MASK (1ULL << PT_DIRTY_SHIFT) +#define PT_PAGE_SIZE_SHIFT 7 +#define PT_PAGE_SIZE_MASK (1ULL << PT_PAGE_SIZE_SHIFT) #define PT_PAT_MASK (1ULL << 7) #define PT_GLOBAL_MASK (1ULL << 8) #define PT64_NX_SHIFT 63 @@ -88,17 +90,14 @@ static inline bool is_write_protection(struct kvm_vcpu *vcpu) return kvm_read_cr0_bits(vcpu, X86_CR0_WP); } -static inline bool check_write_user_access(struct kvm_vcpu *vcpu, - bool write_fault, bool user_fault, - unsigned long pte) +/* + * Will a fault with a given page-fault error code (pfec) cause a permission + * fault with the given access (in ACC_* format)? + */ +static inline bool permission_fault(struct kvm_mmu *mmu, unsigned pte_access, + unsigned pfec) { - if (unlikely(write_fault && !is_writable_pte(pte) - && (user_fault || is_write_protection(vcpu)))) - return false; - - if (unlikely(user_fault && !(pte & PT_USER_MASK))) - return false; - - return true; + return (mmu->permissions[pfec >> 1] >> pte_access) & 1; } + #endif diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c index 7d7d0b9e23eb..daff69e21150 100644 --- a/arch/x86/kvm/mmu_audit.c +++ b/arch/x86/kvm/mmu_audit.c @@ -116,10 +116,8 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level) gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt); pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn); - if (is_error_pfn(pfn)) { - kvm_release_pfn_clean(pfn); + if (is_error_pfn(pfn)) return; - } hpa = pfn << PAGE_SHIFT; if ((*sptep & PT64_BASE_ADDR_MASK) != hpa) @@ -190,7 +188,6 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp) static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) { - struct kvm_memory_slot *slot; unsigned long *rmapp; u64 *sptep; struct rmap_iterator iter; @@ -198,8 +195,7 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp) if (sp->role.direct || sp->unsync || sp->role.invalid) return; - slot = gfn_to_memslot(kvm, sp->gfn); - rmapp = &slot->rmap[sp->gfn - slot->base_gfn]; + rmapp = gfn_to_rmap(kvm, sp->gfn, PT_PAGE_TABLE_LEVEL); for (sptep = rmap_get_first(*rmapp, &iter); sptep; sptep = rmap_get_next(&iter)) { diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index bb7cf01cae76..714e2c01a6fe 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -63,10 +63,12 @@ */ struct guest_walker { int level; + unsigned max_level; gfn_t table_gfn[PT_MAX_FULL_LEVELS]; pt_element_t ptes[PT_MAX_FULL_LEVELS]; pt_element_t prefetch_ptes[PTE_PREFETCH_NUM]; gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; + pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS]; unsigned pt_access; unsigned pte_access; gfn_t gfn; @@ -101,38 +103,41 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, return (ret != orig_pte); } -static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte, - bool last) +static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, + struct kvm_mmu *mmu, + struct guest_walker *walker, + int write_fault) { - unsigned access; - - access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK; - if (last && !is_dirty_gpte(gpte)) - access &= ~ACC_WRITE_MASK; - -#if PTTYPE == 64 - if (vcpu->arch.mmu.nx) - access &= ~(gpte >> PT64_NX_SHIFT); -#endif - return access; -} - -static bool FNAME(is_last_gpte)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - pt_element_t gpte) -{ - if (walker->level == PT_PAGE_TABLE_LEVEL) - return true; - - if ((walker->level == PT_DIRECTORY_LEVEL) && is_large_pte(gpte) && - (PTTYPE == 64 || is_pse(vcpu))) - return true; + unsigned level, index; + pt_element_t pte, orig_pte; + pt_element_t __user *ptep_user; + gfn_t table_gfn; + int ret; + + for (level = walker->max_level; level >= walker->level; --level) { + pte = orig_pte = walker->ptes[level - 1]; + table_gfn = walker->table_gfn[level - 1]; + ptep_user = walker->ptep_user[level - 1]; + index = offset_in_page(ptep_user) / sizeof(pt_element_t); + if (!(pte & PT_ACCESSED_MASK)) { + trace_kvm_mmu_set_accessed_bit(table_gfn, index, sizeof(pte)); + pte |= PT_ACCESSED_MASK; + } + if (level == walker->level && write_fault && !is_dirty_gpte(pte)) { + trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte)); + pte |= PT_DIRTY_MASK; + } + if (pte == orig_pte) + continue; - if ((walker->level == PT_PDPE_LEVEL) && is_large_pte(gpte) && - (mmu->root_level == PT64_ROOT_LEVEL)) - return true; + ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, orig_pte, pte); + if (ret) + return ret; - return false; + mark_page_dirty(vcpu->kvm, table_gfn); + walker->ptes[level] = pte; + } + return 0; } /* @@ -142,21 +147,22 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gva_t addr, u32 access) { + int ret; pt_element_t pte; pt_element_t __user *uninitialized_var(ptep_user); gfn_t table_gfn; - unsigned index, pt_access, uninitialized_var(pte_access); + unsigned index, pt_access, pte_access, accessed_dirty, shift; gpa_t pte_gpa; - bool eperm, last_gpte; int offset; const int write_fault = access & PFERR_WRITE_MASK; const int user_fault = access & PFERR_USER_MASK; const int fetch_fault = access & PFERR_FETCH_MASK; u16 errcode = 0; + gpa_t real_gpa; + gfn_t gfn; trace_kvm_mmu_pagetable_walk(addr, access); retry_walk: - eperm = false; walker->level = mmu->root_level; pte = mmu->get_cr3(vcpu); @@ -169,15 +175,21 @@ retry_walk: --walker->level; } #endif + walker->max_level = walker->level; ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0); - pt_access = ACC_ALL; + accessed_dirty = PT_ACCESSED_MASK; + pt_access = pte_access = ACC_ALL; + ++walker->level; - for (;;) { + do { gfn_t real_gfn; unsigned long host_addr; + pt_access &= pte_access; + --walker->level; + index = PT_INDEX(addr, walker->level); table_gfn = gpte_to_gfn(pte); @@ -199,6 +211,7 @@ retry_walk: ptep_user = (pt_element_t __user *)((void *)host_addr + offset); if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte)))) goto error; + walker->ptep_user[walker->level - 1] = ptep_user; trace_kvm_mmu_paging_element(pte, walker->level); @@ -211,92 +224,48 @@ retry_walk: goto error; } - if (!check_write_user_access(vcpu, write_fault, user_fault, - pte)) - eperm = true; - -#if PTTYPE == 64 - if (unlikely(fetch_fault && (pte & PT64_NX_MASK))) - eperm = true; -#endif - - last_gpte = FNAME(is_last_gpte)(walker, vcpu, mmu, pte); - if (last_gpte) { - pte_access = pt_access & - FNAME(gpte_access)(vcpu, pte, true); - /* check if the kernel is fetching from user page */ - if (unlikely(pte_access & PT_USER_MASK) && - kvm_read_cr4_bits(vcpu, X86_CR4_SMEP)) - if (fetch_fault && !user_fault) - eperm = true; - } - - if (!eperm && unlikely(!(pte & PT_ACCESSED_MASK))) { - int ret; - trace_kvm_mmu_set_accessed_bit(table_gfn, index, - sizeof(pte)); - ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, - pte, pte|PT_ACCESSED_MASK); - if (unlikely(ret < 0)) - goto error; - else if (ret) - goto retry_walk; - - mark_page_dirty(vcpu->kvm, table_gfn); - pte |= PT_ACCESSED_MASK; - } + accessed_dirty &= pte; + pte_access = pt_access & gpte_access(vcpu, pte); walker->ptes[walker->level - 1] = pte; + } while (!is_last_gpte(mmu, walker->level, pte)); - if (last_gpte) { - int lvl = walker->level; - gpa_t real_gpa; - gfn_t gfn; - u32 ac; - - gfn = gpte_to_gfn_lvl(pte, lvl); - gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT; - - if (PTTYPE == 32 && - walker->level == PT_DIRECTORY_LEVEL && - is_cpuid_PSE36()) - gfn += pse36_gfn_delta(pte); - - ac = write_fault | fetch_fault | user_fault; + if (unlikely(permission_fault(mmu, pte_access, access))) { + errcode |= PFERR_PRESENT_MASK; + goto error; + } - real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn), - ac); - if (real_gpa == UNMAPPED_GVA) - return 0; + gfn = gpte_to_gfn_lvl(pte, walker->level); + gfn += (addr & PT_LVL_OFFSET_MASK(walker->level)) >> PAGE_SHIFT; - walker->gfn = real_gpa >> PAGE_SHIFT; + if (PTTYPE == 32 && walker->level == PT_DIRECTORY_LEVEL && is_cpuid_PSE36()) + gfn += pse36_gfn_delta(pte); - break; - } + real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn), access); + if (real_gpa == UNMAPPED_GVA) + return 0; - pt_access &= FNAME(gpte_access)(vcpu, pte, false); - --walker->level; - } + walker->gfn = real_gpa >> PAGE_SHIFT; - if (unlikely(eperm)) { - errcode |= PFERR_PRESENT_MASK; - goto error; - } + if (!write_fault) + protect_clean_gpte(&pte_access, pte); - if (write_fault && unlikely(!is_dirty_gpte(pte))) { - int ret; + /* + * On a write fault, fold the dirty bit into accessed_dirty by shifting it one + * place right. + * + * On a read fault, do nothing. + */ + shift = write_fault >> ilog2(PFERR_WRITE_MASK); + shift *= PT_DIRTY_SHIFT - PT_ACCESSED_SHIFT; + accessed_dirty &= pte >> shift; - trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte)); - ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, - pte, pte|PT_DIRTY_MASK); + if (unlikely(!accessed_dirty)) { + ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault); if (unlikely(ret < 0)) goto error; else if (ret) goto retry_walk; - - mark_page_dirty(vcpu->kvm, table_gfn); - pte |= PT_DIRTY_MASK; - walker->ptes[walker->level - 1] = pte; } walker->pt_access = pt_access; @@ -368,12 +337,11 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, return; pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); - pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true); + pte_access = sp->role.access & gpte_access(vcpu, gpte); + protect_clean_gpte(&pte_access, gpte); pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte)); - if (mmu_invalid_pfn(pfn)) { - kvm_release_pfn_clean(pfn); + if (mmu_invalid_pfn(pfn)) return; - } /* * we call mmu_set_spte() with host_writable = true because that @@ -443,15 +411,13 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte)) continue; - pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, - true); + pte_access = sp->role.access & gpte_access(vcpu, gpte); + protect_clean_gpte(&pte_access, gpte); gfn = gpte_to_gfn(gpte); pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn, pte_access & ACC_WRITE_MASK); - if (mmu_invalid_pfn(pfn)) { - kvm_release_pfn_clean(pfn); + if (mmu_invalid_pfn(pfn)) break; - } mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, NULL, PT_PAGE_TABLE_LEVEL, gfn, @@ -798,7 +764,8 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) gfn = gpte_to_gfn(gpte); pte_access = sp->role.access; - pte_access &= FNAME(gpte_access)(vcpu, gpte, true); + pte_access &= gpte_access(vcpu, gpte); + protect_clean_gpte(&pte_access, gpte); if (sync_mmio_spte(&sp->spt[i], gfn, pte_access, &nr_present)) continue; diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 9b7ec1150ab0..cfc258a6bf97 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -1,5 +1,5 @@ /* - * Kernel-based Virtual Machine -- Performane Monitoring Unit support + * Kernel-based Virtual Machine -- Performance Monitoring Unit support * * Copyright 2011 Red Hat, Inc. and/or its affiliates. * diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index baead950d6c8..d017df3899ef 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -163,7 +163,7 @@ static DEFINE_PER_CPU(u64, current_tsc_ratio); #define MSR_INVALID 0xffffffffU -static struct svm_direct_access_msrs { +static const struct svm_direct_access_msrs { u32 index; /* Index of the MSR */ bool always; /* True if intercept is always on */ } direct_access_msrs[] = { @@ -400,7 +400,7 @@ struct svm_init_data { int r; }; -static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; +static const u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; #define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges) #define MSRS_RANGE_SIZE 2048 @@ -1146,7 +1146,6 @@ static void init_vmcb(struct vcpu_svm *svm) svm_set_efer(&svm->vcpu, 0); save->dr6 = 0xffff0ff0; - save->dr7 = 0x400; kvm_set_rflags(&svm->vcpu, 2); save->rip = 0x0000fff0; svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip; @@ -1643,7 +1642,7 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, mark_dirty(svm->vmcb, VMCB_SEG); } -static void update_db_intercept(struct kvm_vcpu *vcpu) +static void update_db_bp_intercept(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -1663,20 +1662,6 @@ static void update_db_intercept(struct kvm_vcpu *vcpu) vcpu->guest_debug = 0; } -static void svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) - svm->vmcb->save.dr7 = dbg->arch.debugreg[7]; - else - svm->vmcb->save.dr7 = vcpu->arch.dr7; - - mark_dirty(svm->vmcb, VMCB_DR); - - update_db_intercept(vcpu); -} - static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) { if (sd->next_asid > sd->max_asid) { @@ -1748,7 +1733,7 @@ static int db_interception(struct vcpu_svm *svm) if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) svm->vmcb->save.rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); - update_db_intercept(&svm->vcpu); + update_db_bp_intercept(&svm->vcpu); } if (svm->vcpu.guest_debug & @@ -2063,7 +2048,7 @@ static inline bool nested_svm_intr(struct vcpu_svm *svm) if (svm->nested.intercept & 1ULL) { /* * The #vmexit can't be emulated here directly because this - * code path runs with irqs and preemtion disabled. A + * code path runs with irqs and preemption disabled. A * #vmexit emulation might sleep. Only signal request for * the #vmexit here. */ @@ -2105,7 +2090,6 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page) return kmap(page); error: - kvm_release_page_clean(page); kvm_inject_gp(&svm->vcpu, 0); return NULL; @@ -2409,7 +2393,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) { /* * This function merges the msr permission bitmaps of kvm and the - * nested vmcb. It is omptimized in that it only merges the parts where + * nested vmcb. It is optimized in that it only merges the parts where * the kvm msr permission bitmap may contain zero bits */ int i; @@ -3268,7 +3252,7 @@ static int pause_interception(struct vcpu_svm *svm) return 1; } -static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = { +static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_CR0] = cr_interception, [SVM_EXIT_READ_CR3] = cr_interception, [SVM_EXIT_READ_CR4] = cr_interception, @@ -3660,7 +3644,7 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu) */ svm->nmi_singlestep = true; svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); - update_db_intercept(vcpu); + update_db_bp_intercept(vcpu); } static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) @@ -3783,12 +3767,6 @@ static void svm_cancel_injection(struct kvm_vcpu *vcpu) svm_complete_interrupts(svm); } -#ifdef CONFIG_X86_64 -#define R "r" -#else -#define R "e" -#endif - static void svm_vcpu_run(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3815,13 +3793,13 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) local_irq_enable(); asm volatile ( - "push %%"R"bp; \n\t" - "mov %c[rbx](%[svm]), %%"R"bx \n\t" - "mov %c[rcx](%[svm]), %%"R"cx \n\t" - "mov %c[rdx](%[svm]), %%"R"dx \n\t" - "mov %c[rsi](%[svm]), %%"R"si \n\t" - "mov %c[rdi](%[svm]), %%"R"di \n\t" - "mov %c[rbp](%[svm]), %%"R"bp \n\t" + "push %%" _ASM_BP "; \n\t" + "mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t" + "mov %c[rcx](%[svm]), %%" _ASM_CX " \n\t" + "mov %c[rdx](%[svm]), %%" _ASM_DX " \n\t" + "mov %c[rsi](%[svm]), %%" _ASM_SI " \n\t" + "mov %c[rdi](%[svm]), %%" _ASM_DI " \n\t" + "mov %c[rbp](%[svm]), %%" _ASM_BP " \n\t" #ifdef CONFIG_X86_64 "mov %c[r8](%[svm]), %%r8 \n\t" "mov %c[r9](%[svm]), %%r9 \n\t" @@ -3834,20 +3812,20 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) #endif /* Enter guest mode */ - "push %%"R"ax \n\t" - "mov %c[vmcb](%[svm]), %%"R"ax \n\t" + "push %%" _ASM_AX " \n\t" + "mov %c[vmcb](%[svm]), %%" _ASM_AX " \n\t" __ex(SVM_VMLOAD) "\n\t" __ex(SVM_VMRUN) "\n\t" __ex(SVM_VMSAVE) "\n\t" - "pop %%"R"ax \n\t" + "pop %%" _ASM_AX " \n\t" /* Save guest registers, load host registers */ - "mov %%"R"bx, %c[rbx](%[svm]) \n\t" - "mov %%"R"cx, %c[rcx](%[svm]) \n\t" - "mov %%"R"dx, %c[rdx](%[svm]) \n\t" - "mov %%"R"si, %c[rsi](%[svm]) \n\t" - "mov %%"R"di, %c[rdi](%[svm]) \n\t" - "mov %%"R"bp, %c[rbp](%[svm]) \n\t" + "mov %%" _ASM_BX ", %c[rbx](%[svm]) \n\t" + "mov %%" _ASM_CX ", %c[rcx](%[svm]) \n\t" + "mov %%" _ASM_DX ", %c[rdx](%[svm]) \n\t" + "mov %%" _ASM_SI ", %c[rsi](%[svm]) \n\t" + "mov %%" _ASM_DI ", %c[rdi](%[svm]) \n\t" + "mov %%" _ASM_BP ", %c[rbp](%[svm]) \n\t" #ifdef CONFIG_X86_64 "mov %%r8, %c[r8](%[svm]) \n\t" "mov %%r9, %c[r9](%[svm]) \n\t" @@ -3858,7 +3836,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r14, %c[r14](%[svm]) \n\t" "mov %%r15, %c[r15](%[svm]) \n\t" #endif - "pop %%"R"bp" + "pop %%" _ASM_BP : : [svm]"a"(svm), [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), @@ -3879,9 +3857,11 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) [r15]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R15])) #endif : "cc", "memory" - , R"bx", R"cx", R"dx", R"si", R"di" #ifdef CONFIG_X86_64 + , "rbx", "rcx", "rdx", "rsi", "rdi" , "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15" +#else + , "ebx", "ecx", "edx", "esi", "edi" #endif ); @@ -3941,8 +3921,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) mark_all_clean(svm->vmcb); } -#undef R - static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) { struct vcpu_svm *svm = to_svm(vcpu); @@ -4069,7 +4047,7 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu) #define POST_MEM(exit) { .exit_code = (exit), \ .stage = X86_ICPT_POST_MEMACCESS, } -static struct __x86_intercept { +static const struct __x86_intercept { u32 exit_code; enum x86_intercept_stage stage; } x86_intercept_map[] = { @@ -4260,7 +4238,7 @@ static struct kvm_x86_ops svm_x86_ops = { .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, - .set_guest_debug = svm_guest_debug, + .update_db_bp_intercept = update_db_bp_intercept, .get_msr = svm_get_msr, .set_msr = svm_set_msr, .get_segment_base = svm_get_segment_base, diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c deleted file mode 100644 index 6b85cc647f34..000000000000 --- a/arch/x86/kvm/timer.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. - * - * timer support - * - * Copyright 2010 Red Hat, Inc. and/or its affiliates. - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include <linux/kvm_host.h> -#include <linux/kvm.h> -#include <linux/hrtimer.h> -#include <linux/atomic.h> -#include "kvm_timer.h" - -enum hrtimer_restart kvm_timer_fn(struct hrtimer *data) -{ - struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); - struct kvm_vcpu *vcpu = ktimer->vcpu; - wait_queue_head_t *q = &vcpu->wq; - - /* - * There is a race window between reading and incrementing, but we do - * not care about potentially losing timer events in the !reinject - * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked - * in vcpu_enter_guest. - */ - if (ktimer->reinject || !atomic_read(&ktimer->pending)) { - atomic_inc(&ktimer->pending); - /* FIXME: this code should not know anything about vcpus */ - kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); - } - - if (waitqueue_active(q)) - wake_up_interruptible(q); - - if (ktimer->t_ops->is_periodic(ktimer)) { - hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); - return HRTIMER_RESTART; - } else - return HRTIMER_NORESTART; -} diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 851aa7c3b890..ad6b1dd06f8b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -127,6 +127,8 @@ module_param(ple_gap, int, S_IRUGO); static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW; module_param(ple_window, int, S_IRUGO); +extern const ulong vmx_return; + #define NR_AUTOLOAD_MSRS 8 #define VMCS02_POOL_SIZE 1 @@ -405,16 +407,16 @@ struct vcpu_vmx { struct { int vm86_active; ulong save_rflags; + struct kvm_segment segs[8]; + } rmode; + struct { + u32 bitmask; /* 4 bits per segment (1 bit per field) */ struct kvm_save_segment { u16 selector; unsigned long base; u32 limit; u32 ar; - } tr, es, ds, fs, gs; - } rmode; - struct { - u32 bitmask; /* 4 bits per segment (1 bit per field) */ - struct kvm_save_segment seg[8]; + } seg[8]; } segment_cache; int vpid; bool emulation_required; @@ -450,7 +452,7 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) #define FIELD64(number, name) [number] = VMCS12_OFFSET(name), \ [number##_HIGH] = VMCS12_OFFSET(name)+4 -static unsigned short vmcs_field_to_offset_table[] = { +static const unsigned short vmcs_field_to_offset_table[] = { FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id), FIELD(GUEST_ES_SELECTOR, guest_es_selector), FIELD(GUEST_CS_SELECTOR, guest_cs_selector), @@ -596,10 +598,9 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu) static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr) { struct page *page = gfn_to_page(vcpu->kvm, addr >> PAGE_SHIFT); - if (is_error_page(page)) { - kvm_release_page_clean(page); + if (is_error_page(page)) return NULL; - } + return page; } @@ -667,7 +668,7 @@ static struct vmx_capability { .ar_bytes = GUEST_##seg##_AR_BYTES, \ } -static struct kvm_vmx_segment_field { +static const struct kvm_vmx_segment_field { unsigned selector; unsigned base; unsigned limit; @@ -1343,7 +1344,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) guest_efer = vmx->vcpu.arch.efer; /* - * NX is emulated; LMA and LME handled by hardware; SCE meaninless + * NX is emulated; LMA and LME handled by hardware; SCE meaningless * outside long mode */ ignore_bits = EFER_NX | EFER_SCE; @@ -1995,7 +1996,7 @@ static __init void nested_vmx_setup_ctls_msrs(void) #endif CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING | CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING | - CPU_BASED_RDPMC_EXITING | + CPU_BASED_RDPMC_EXITING | CPU_BASED_RDTSC_EXITING | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; /* * We can allow some features even when not supported by the @@ -2291,16 +2292,6 @@ static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) } } -static void set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) -{ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) - vmcs_writel(GUEST_DR7, dbg->arch.debugreg[7]); - else - vmcs_writel(GUEST_DR7, vcpu->arch.dr7); - - update_exception_bitmap(vcpu); -} - static __init int cpu_has_kvm_support(void) { return cpu_has_vmx(); @@ -2698,20 +2689,17 @@ static __exit void hardware_unsetup(void) free_kvm_area(); } -static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save) +static void fix_pmode_dataseg(struct kvm_vcpu *vcpu, int seg, struct kvm_segment *save) { - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + struct kvm_segment tmp = *save; - if (vmcs_readl(sf->base) == save->base && (save->base & AR_S_MASK)) { - vmcs_write16(sf->selector, save->selector); - vmcs_writel(sf->base, save->base); - vmcs_write32(sf->limit, save->limit); - vmcs_write32(sf->ar_bytes, save->ar); - } else { - u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK) - << AR_DPL_SHIFT; - vmcs_write32(sf->ar_bytes, 0x93 | dpl); + if (!(vmcs_readl(sf->base) == tmp.base && tmp.s)) { + tmp.base = vmcs_readl(sf->base); + tmp.selector = vmcs_read16(sf->selector); + tmp.s = 1; } + vmx_set_segment(vcpu, &tmp, seg); } static void enter_pmode(struct kvm_vcpu *vcpu) @@ -2724,10 +2712,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu) vmx_segment_cache_clear(vmx); - vmcs_write16(GUEST_TR_SELECTOR, vmx->rmode.tr.selector); - vmcs_writel(GUEST_TR_BASE, vmx->rmode.tr.base); - vmcs_write32(GUEST_TR_LIMIT, vmx->rmode.tr.limit); - vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar); + vmx_set_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_TR], VCPU_SREG_TR); flags = vmcs_readl(GUEST_RFLAGS); flags &= RMODE_GUEST_OWNED_EFLAGS_BITS; @@ -2742,10 +2727,10 @@ static void enter_pmode(struct kvm_vcpu *vcpu) if (emulate_invalid_guest_state) return; - fix_pmode_dataseg(VCPU_SREG_ES, &vmx->rmode.es); - fix_pmode_dataseg(VCPU_SREG_DS, &vmx->rmode.ds); - fix_pmode_dataseg(VCPU_SREG_GS, &vmx->rmode.gs); - fix_pmode_dataseg(VCPU_SREG_FS, &vmx->rmode.fs); + fix_pmode_dataseg(vcpu, VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]); + fix_pmode_dataseg(vcpu, VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]); + fix_pmode_dataseg(vcpu, VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]); + fix_pmode_dataseg(vcpu, VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]); vmx_segment_cache_clear(vmx); @@ -2773,14 +2758,10 @@ static gva_t rmode_tss_base(struct kvm *kvm) return kvm->arch.tss_addr; } -static void fix_rmode_seg(int seg, struct kvm_save_segment *save) +static void fix_rmode_seg(int seg, struct kvm_segment *save) { - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - save->selector = vmcs_read16(sf->selector); - save->base = vmcs_readl(sf->base); - save->limit = vmcs_read32(sf->limit); - save->ar = vmcs_read32(sf->ar_bytes); vmcs_write16(sf->selector, save->base >> 4); vmcs_write32(sf->base, save->base & 0xffff0); vmcs_write32(sf->limit, 0xffff); @@ -2800,9 +2781,16 @@ static void enter_rmode(struct kvm_vcpu *vcpu) if (enable_unrestricted_guest) return; + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_TR], VCPU_SREG_TR); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_DS], VCPU_SREG_DS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_FS], VCPU_SREG_FS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_GS], VCPU_SREG_GS); + vmx->emulation_required = 1; vmx->rmode.vm86_active = 1; + /* * Very old userspace does not call KVM_SET_TSS_ADDR before entering * vcpu. Call it here with phys address pointing 16M below 4G. @@ -2817,14 +2805,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu) vmx_segment_cache_clear(vmx); - vmx->rmode.tr.selector = vmcs_read16(GUEST_TR_SELECTOR); - vmx->rmode.tr.base = vmcs_readl(GUEST_TR_BASE); vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); - - vmx->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT); vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); - - vmx->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES); vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); flags = vmcs_readl(GUEST_RFLAGS); @@ -3117,35 +3099,24 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { struct vcpu_vmx *vmx = to_vmx(vcpu); - struct kvm_save_segment *save; u32 ar; if (vmx->rmode.vm86_active && (seg == VCPU_SREG_TR || seg == VCPU_SREG_ES || seg == VCPU_SREG_DS || seg == VCPU_SREG_FS - || seg == VCPU_SREG_GS) - && !emulate_invalid_guest_state) { - switch (seg) { - case VCPU_SREG_TR: save = &vmx->rmode.tr; break; - case VCPU_SREG_ES: save = &vmx->rmode.es; break; - case VCPU_SREG_DS: save = &vmx->rmode.ds; break; - case VCPU_SREG_FS: save = &vmx->rmode.fs; break; - case VCPU_SREG_GS: save = &vmx->rmode.gs; break; - default: BUG(); - } - var->selector = save->selector; - var->base = save->base; - var->limit = save->limit; - ar = save->ar; + || seg == VCPU_SREG_GS)) { + *var = vmx->rmode.segs[seg]; if (seg == VCPU_SREG_TR || var->selector == vmx_read_guest_seg_selector(vmx, seg)) - goto use_saved_rmode_seg; + return; + var->base = vmx_read_guest_seg_base(vmx, seg); + var->selector = vmx_read_guest_seg_selector(vmx, seg); + return; } var->base = vmx_read_guest_seg_base(vmx, seg); var->limit = vmx_read_guest_seg_limit(vmx, seg); var->selector = vmx_read_guest_seg_selector(vmx, seg); ar = vmx_read_guest_seg_ar(vmx, seg); -use_saved_rmode_seg: if ((ar & AR_UNUSABLE_MASK) && !emulate_invalid_guest_state) ar = 0; var->type = ar & 15; @@ -3227,23 +3198,21 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg) { struct vcpu_vmx *vmx = to_vmx(vcpu); - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; u32 ar; vmx_segment_cache_clear(vmx); if (vmx->rmode.vm86_active && seg == VCPU_SREG_TR) { vmcs_write16(sf->selector, var->selector); - vmx->rmode.tr.selector = var->selector; - vmx->rmode.tr.base = var->base; - vmx->rmode.tr.limit = var->limit; - vmx->rmode.tr.ar = vmx_segment_access_rights(var); + vmx->rmode.segs[VCPU_SREG_TR] = *var; return; } vmcs_writel(sf->base, var->base); vmcs_write32(sf->limit, var->limit); vmcs_write16(sf->selector, var->selector); if (vmx->rmode.vm86_active && var->s) { + vmx->rmode.segs[seg] = *var; /* * Hack real-mode segments into vm86 compatibility. */ @@ -3258,7 +3227,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, * qemu binaries. * IA32 arch specifies that at the time of processor reset the * "Accessed" bit in the AR field of segment registers is 1. And qemu - * is setting it to 0 in the usedland code. This causes invalid guest + * is setting it to 0 in the userland code. This causes invalid guest * state vmexit when "unrestricted guest" mode is turned on. * Fix for this setup issue in cpu_reset is being pushed in the qemu * tree. Newer qemu binaries with that qemu fix would not need this @@ -3288,16 +3257,10 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu, vmcs_readl(GUEST_CS_BASE) >> 4); break; case VCPU_SREG_ES: - fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.es); - break; case VCPU_SREG_DS: - fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.ds); - break; case VCPU_SREG_GS: - fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.gs); - break; case VCPU_SREG_FS: - fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.fs); + fix_rmode_seg(seg, &vmx->rmode.segs[seg]); break; case VCPU_SREG_SS: vmcs_write16(GUEST_SS_SELECTOR, @@ -3351,9 +3314,9 @@ static bool rmode_segment_valid(struct kvm_vcpu *vcpu, int seg) if (var.base != (var.selector << 4)) return false; - if (var.limit != 0xffff) + if (var.limit < 0xffff) return false; - if (ar != 0xf3) + if (((ar | (3 << AR_DPL_SHIFT)) & ~(AR_G_MASK | AR_DB_MASK)) != 0xf3) return false; return true; @@ -3605,7 +3568,7 @@ out: static void seg_setup(int seg) { - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; unsigned int ar; vmcs_write16(sf->selector, 0); @@ -3770,8 +3733,7 @@ static void vmx_set_constant_host_state(void) native_store_idt(&dt); vmcs_writel(HOST_IDTR_BASE, dt.address); /* 22.2.4 */ - asm("mov $.Lkvm_vmx_return, %0" : "=r"(tmpl)); - vmcs_writel(HOST_RIP, tmpl); /* 22.2.5 */ + vmcs_writel(HOST_RIP, vmx_return); /* 22.2.5 */ rdmsr(MSR_IA32_SYSENTER_CS, low32, high32); vmcs_write32(HOST_IA32_SYSENTER_CS, low32); @@ -4005,8 +3967,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) kvm_rip_write(vcpu, 0); kvm_register_write(vcpu, VCPU_REGS_RSP, 0); - vmcs_writel(GUEST_DR7, 0x400); - vmcs_writel(GUEST_GDTR_BASE, 0); vmcs_write32(GUEST_GDTR_LIMIT, 0xffff); @@ -4456,7 +4416,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) hypercall[2] = 0xc1; } -/* called to set cr0 as approriate for a mov-to-cr0 exit. */ +/* called to set cr0 as appropriate for a mov-to-cr0 exit. */ static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val) { if (to_vmx(vcpu)->nested.vmxon && @@ -5701,7 +5661,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) * may resume. Otherwise they set the kvm_run parameter to indicate what needs * to be done to userspace and return 0. */ -static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { +static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_EXCEPTION_NMI] = handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, @@ -6229,17 +6189,10 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) msrs[i].host); } -#ifdef CONFIG_X86_64 -#define R "r" -#define Q "q" -#else -#define R "e" -#define Q "l" -#endif - static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long debugctlmsr; if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) { struct vmcs12 *vmcs12 = get_vmcs12(vcpu); @@ -6279,34 +6232,35 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx_set_interrupt_shadow(vcpu, 0); atomic_switch_perf_msrs(vmx); + debugctlmsr = get_debugctlmsr(); vmx->__launched = vmx->loaded_vmcs->launched; asm( /* Store host registers */ - "push %%"R"dx; push %%"R"bp;" - "push %%"R"cx \n\t" /* placeholder for guest rcx */ - "push %%"R"cx \n\t" - "cmp %%"R"sp, %c[host_rsp](%0) \n\t" + "push %%" _ASM_DX "; push %%" _ASM_BP ";" + "push %%" _ASM_CX " \n\t" /* placeholder for guest rcx */ + "push %%" _ASM_CX " \n\t" + "cmp %%" _ASM_SP ", %c[host_rsp](%0) \n\t" "je 1f \n\t" - "mov %%"R"sp, %c[host_rsp](%0) \n\t" + "mov %%" _ASM_SP ", %c[host_rsp](%0) \n\t" __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t" "1: \n\t" /* Reload cr2 if changed */ - "mov %c[cr2](%0), %%"R"ax \n\t" - "mov %%cr2, %%"R"dx \n\t" - "cmp %%"R"ax, %%"R"dx \n\t" + "mov %c[cr2](%0), %%" _ASM_AX " \n\t" + "mov %%cr2, %%" _ASM_DX " \n\t" + "cmp %%" _ASM_AX ", %%" _ASM_DX " \n\t" "je 2f \n\t" - "mov %%"R"ax, %%cr2 \n\t" + "mov %%" _ASM_AX", %%cr2 \n\t" "2: \n\t" /* Check if vmlaunch of vmresume is needed */ "cmpl $0, %c[launched](%0) \n\t" /* Load guest registers. Don't clobber flags. */ - "mov %c[rax](%0), %%"R"ax \n\t" - "mov %c[rbx](%0), %%"R"bx \n\t" - "mov %c[rdx](%0), %%"R"dx \n\t" - "mov %c[rsi](%0), %%"R"si \n\t" - "mov %c[rdi](%0), %%"R"di \n\t" - "mov %c[rbp](%0), %%"R"bp \n\t" + "mov %c[rax](%0), %%" _ASM_AX " \n\t" + "mov %c[rbx](%0), %%" _ASM_BX " \n\t" + "mov %c[rdx](%0), %%" _ASM_DX " \n\t" + "mov %c[rsi](%0), %%" _ASM_SI " \n\t" + "mov %c[rdi](%0), %%" _ASM_DI " \n\t" + "mov %c[rbp](%0), %%" _ASM_BP " \n\t" #ifdef CONFIG_X86_64 "mov %c[r8](%0), %%r8 \n\t" "mov %c[r9](%0), %%r9 \n\t" @@ -6317,24 +6271,24 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %c[r14](%0), %%r14 \n\t" "mov %c[r15](%0), %%r15 \n\t" #endif - "mov %c[rcx](%0), %%"R"cx \n\t" /* kills %0 (ecx) */ + "mov %c[rcx](%0), %%" _ASM_CX " \n\t" /* kills %0 (ecx) */ /* Enter guest mode */ - "jne .Llaunched \n\t" + "jne 1f \n\t" __ex(ASM_VMX_VMLAUNCH) "\n\t" - "jmp .Lkvm_vmx_return \n\t" - ".Llaunched: " __ex(ASM_VMX_VMRESUME) "\n\t" - ".Lkvm_vmx_return: " + "jmp 2f \n\t" + "1: " __ex(ASM_VMX_VMRESUME) "\n\t" + "2: " /* Save guest registers, load host registers, keep flags */ - "mov %0, %c[wordsize](%%"R"sp) \n\t" + "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t" "pop %0 \n\t" - "mov %%"R"ax, %c[rax](%0) \n\t" - "mov %%"R"bx, %c[rbx](%0) \n\t" - "pop"Q" %c[rcx](%0) \n\t" - "mov %%"R"dx, %c[rdx](%0) \n\t" - "mov %%"R"si, %c[rsi](%0) \n\t" - "mov %%"R"di, %c[rdi](%0) \n\t" - "mov %%"R"bp, %c[rbp](%0) \n\t" + "mov %%" _ASM_AX ", %c[rax](%0) \n\t" + "mov %%" _ASM_BX ", %c[rbx](%0) \n\t" + __ASM_SIZE(pop) " %c[rcx](%0) \n\t" + "mov %%" _ASM_DX ", %c[rdx](%0) \n\t" + "mov %%" _ASM_SI ", %c[rsi](%0) \n\t" + "mov %%" _ASM_DI ", %c[rdi](%0) \n\t" + "mov %%" _ASM_BP ", %c[rbp](%0) \n\t" #ifdef CONFIG_X86_64 "mov %%r8, %c[r8](%0) \n\t" "mov %%r9, %c[r9](%0) \n\t" @@ -6345,11 +6299,15 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) "mov %%r14, %c[r14](%0) \n\t" "mov %%r15, %c[r15](%0) \n\t" #endif - "mov %%cr2, %%"R"ax \n\t" - "mov %%"R"ax, %c[cr2](%0) \n\t" + "mov %%cr2, %%" _ASM_AX " \n\t" + "mov %%" _ASM_AX ", %c[cr2](%0) \n\t" - "pop %%"R"bp; pop %%"R"dx \n\t" + "pop %%" _ASM_BP "; pop %%" _ASM_DX " \n\t" "setbe %c[fail](%0) \n\t" + ".pushsection .rodata \n\t" + ".global vmx_return \n\t" + "vmx_return: " _ASM_PTR " 2b \n\t" + ".popsection" : : "c"(vmx), "d"((unsigned long)HOST_RSP), [launched]"i"(offsetof(struct vcpu_vmx, __launched)), [fail]"i"(offsetof(struct vcpu_vmx, fail)), @@ -6374,12 +6332,18 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)), [wordsize]"i"(sizeof(ulong)) : "cc", "memory" - , R"ax", R"bx", R"di", R"si" #ifdef CONFIG_X86_64 + , "rax", "rbx", "rdi", "rsi" , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +#else + , "eax", "ebx", "edi", "esi" #endif ); + /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */ + if (debugctlmsr) + update_debugctlmsr(debugctlmsr); + #ifndef CONFIG_X86_64 /* * The sysexit path does not restore ds/es, so we must set them to @@ -6424,9 +6388,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx_complete_interrupts(vmx); } -#undef R -#undef Q - static void vmx_free_vcpu(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -7281,7 +7242,7 @@ static struct kvm_x86_ops vmx_x86_ops = { .vcpu_load = vmx_vcpu_load, .vcpu_put = vmx_vcpu_put, - .set_guest_debug = set_guest_debug, + .update_db_bp_intercept = update_exception_bitmap, .get_msr = vmx_get_msr, .set_msr = vmx_set_msr, .get_segment_base = vmx_get_segment_base, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1f09552572fa..1eefebe5d727 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -246,20 +246,14 @@ static void drop_user_return_notifiers(void *ignore) u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) { - if (irqchip_in_kernel(vcpu->kvm)) - return vcpu->arch.apic_base; - else - return vcpu->arch.apic_base; + return vcpu->arch.apic_base; } EXPORT_SYMBOL_GPL(kvm_get_apic_base); void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) { /* TODO: reserve bits check */ - if (irqchip_in_kernel(vcpu->kvm)) - kvm_lapic_set_base(vcpu, data); - else - vcpu->arch.apic_base = data; + kvm_lapic_set_base(vcpu, data); } EXPORT_SYMBOL_GPL(kvm_set_apic_base); @@ -698,6 +692,18 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_get_cr8); +static void kvm_update_dr7(struct kvm_vcpu *vcpu) +{ + unsigned long dr7; + + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) + dr7 = vcpu->arch.guest_debug_dr7; + else + dr7 = vcpu->arch.dr7; + kvm_x86_ops->set_dr7(vcpu, dr7); + vcpu->arch.switch_db_regs = (dr7 & DR7_BP_EN_MASK); +} + static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val) { switch (dr) { @@ -723,10 +729,7 @@ static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val) if (val & 0xffffffff00000000ULL) return -1; /* #GP */ vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1; - if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) { - kvm_x86_ops->set_dr7(vcpu, vcpu->arch.dr7); - vcpu->arch.switch_db_regs = (val & DR7_BP_EN_MASK); - } + kvm_update_dr7(vcpu); break; } @@ -823,7 +826,7 @@ static u32 msrs_to_save[] = { static unsigned num_msrs_to_save; -static u32 emulated_msrs[] = { +static const u32 emulated_msrs[] = { MSR_IA32_TSCDEADLINE, MSR_IA32_MISC_ENABLE, MSR_IA32_MCG_STATUS, @@ -1097,7 +1100,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data) * For each generation, we track the original measured * nanosecond time, offset, and write, so if TSCs are in * sync, we can match exact offset, and if not, we can match - * exact software computaion in compute_guest_tsc() + * exact software computation in compute_guest_tsc() * * These values are tracked in kvm->arch.cur_xxx variables. */ @@ -1140,6 +1143,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) unsigned long this_tsc_khz; s64 kernel_ns, max_kernel_ns; u64 tsc_timestamp; + u8 pvclock_flags; /* Keep irq disabled to prevent changes to the clock */ local_irq_save(flags); @@ -1221,7 +1225,14 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset; vcpu->last_kernel_ns = kernel_ns; vcpu->last_guest_tsc = tsc_timestamp; - vcpu->hv_clock.flags = 0; + + pvclock_flags = 0; + if (vcpu->pvclock_set_guest_stopped_request) { + pvclock_flags |= PVCLOCK_GUEST_STOPPED; + vcpu->pvclock_set_guest_stopped_request = false; + } + + vcpu->hv_clock.flags = pvclock_flags; /* * The interface expects us to write an even number signaling that the @@ -1504,7 +1515,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data) { gpa_t gpa = data & ~0x3f; - /* Bits 2:5 are resrved, Should be zero */ + /* Bits 2:5 are reserved, Should be zero */ if (data & 0x3c) return 1; @@ -1639,10 +1650,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) vcpu->arch.time_page = gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); - if (is_error_page(vcpu->arch.time_page)) { - kvm_release_page_clean(vcpu->arch.time_page); + if (is_error_page(vcpu->arch.time_page)) vcpu->arch.time_page = NULL; - } + break; } case MSR_KVM_ASYNC_PF_EN: @@ -1727,7 +1737,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) * Ignore all writes to this no longer documented MSR. * Writes are only relevant for old K7 processors, * all pre-dating SVM, but a recommended workaround from - * AMD for these chips. It is possible to speicify the + * AMD for these chips. It is possible to specify the * affected processor models on the command line, hence * the need to ignore the workaround. */ @@ -2177,6 +2187,8 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_GET_TSC_KHZ: case KVM_CAP_PCI_2_3: case KVM_CAP_KVMCLOCK_CTRL: + case KVM_CAP_READONLY_MEM: + case KVM_CAP_IRQFD_RESAMPLE: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -2358,8 +2370,7 @@ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) { - memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s); - kvm_apic_post_state_restore(vcpu); + kvm_apic_post_state_restore(vcpu, s); update_cr8_intercept(vcpu); return 0; @@ -2368,7 +2379,7 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - if (irq->irq < 0 || irq->irq >= 256) + if (irq->irq < 0 || irq->irq >= KVM_NR_INTERRUPTS) return -EINVAL; if (irqchip_in_kernel(vcpu->kvm)) return -ENXIO; @@ -2635,11 +2646,9 @@ static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu, */ static int kvm_set_guest_paused(struct kvm_vcpu *vcpu) { - struct pvclock_vcpu_time_info *src = &vcpu->arch.hv_clock; if (!vcpu->arch.time_page) return -EINVAL; - src->flags |= PVCLOCK_GUEST_STOPPED; - mark_page_dirty(vcpu->kvm, vcpu->arch.time >> PAGE_SHIFT); + vcpu->arch.pvclock_set_guest_stopped_request = true; kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); return 0; } @@ -3090,7 +3099,7 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm, if (!kvm->arch.vpit) return -ENXIO; mutex_lock(&kvm->arch.vpit->pit_state.lock); - kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject; + kvm->arch.vpit->pit_state.reinject = control->pit_reinject; mutex_unlock(&kvm->arch.vpit->pit_state.lock); return 0; } @@ -3173,6 +3182,16 @@ out: return r; } +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event) +{ + if (!irqchip_in_kernel(kvm)) + return -ENXIO; + + irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, + irq_event->irq, irq_event->level); + return 0; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -3279,29 +3298,6 @@ long kvm_arch_vm_ioctl(struct file *filp, create_pit_unlock: mutex_unlock(&kvm->slots_lock); break; - case KVM_IRQ_LINE_STATUS: - case KVM_IRQ_LINE: { - struct kvm_irq_level irq_event; - - r = -EFAULT; - if (copy_from_user(&irq_event, argp, sizeof irq_event)) - goto out; - r = -ENXIO; - if (irqchip_in_kernel(kvm)) { - __s32 status; - status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, - irq_event.irq, irq_event.level); - if (ioctl == KVM_IRQ_LINE_STATUS) { - r = -EFAULT; - irq_event.status = status; - if (copy_to_user(argp, &irq_event, - sizeof irq_event)) - goto out; - } - r = 0; - } - break; - } case KVM_GET_IRQCHIP: { /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ struct kvm_irqchip *chip; @@ -3689,20 +3685,17 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, gpa_t *gpa, struct x86_exception *exception, bool write) { - u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; + u32 access = ((kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0) + | (write ? PFERR_WRITE_MASK : 0); - if (vcpu_match_mmio_gva(vcpu, gva) && - check_write_user_access(vcpu, write, access, - vcpu->arch.access)) { + if (vcpu_match_mmio_gva(vcpu, gva) + && !permission_fault(vcpu->arch.walk_mmu, vcpu->arch.access, access)) { *gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT | (gva & (PAGE_SIZE - 1)); trace_vcpu_match_mmio(gva, *gpa, write, false); return 1; } - if (write) - access |= PFERR_WRITE_MASK; - *gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception); if (*gpa == UNMAPPED_GVA) @@ -3790,14 +3783,14 @@ static int write_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, return X86EMUL_CONTINUE; } -static struct read_write_emulator_ops read_emultor = { +static const struct read_write_emulator_ops read_emultor = { .read_write_prepare = read_prepare, .read_write_emulate = read_emulate, .read_write_mmio = vcpu_mmio_read, .read_write_exit_mmio = read_exit_mmio, }; -static struct read_write_emulator_ops write_emultor = { +static const struct read_write_emulator_ops write_emultor = { .read_write_emulate = write_emulate, .read_write_mmio = write_mmio, .read_write_exit_mmio = write_exit_mmio, @@ -3808,7 +3801,7 @@ static int emulator_read_write_onepage(unsigned long addr, void *val, unsigned int bytes, struct x86_exception *exception, struct kvm_vcpu *vcpu, - struct read_write_emulator_ops *ops) + const struct read_write_emulator_ops *ops) { gpa_t gpa; int handled, ret; @@ -3857,7 +3850,7 @@ mmio: int emulator_read_write(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, struct x86_exception *exception, - struct read_write_emulator_ops *ops) + const struct read_write_emulator_ops *ops) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); gpa_t gpa; @@ -3962,10 +3955,8 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, goto emul_write; page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); - if (is_error_page(page)) { - kvm_release_page_clean(page); + if (is_error_page(page)) goto emul_write; - } kaddr = kmap_atomic(page); kaddr += offset_in_page(gpa); @@ -4332,7 +4323,19 @@ static void emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, kvm_cpuid(emul_to_vcpu(ctxt), eax, ebx, ecx, edx); } -static struct x86_emulate_ops emulate_ops = { +static ulong emulator_read_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg) +{ + return kvm_register_read(emul_to_vcpu(ctxt), reg); +} + +static void emulator_write_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg, ulong val) +{ + kvm_register_write(emul_to_vcpu(ctxt), reg, val); +} + +static const struct x86_emulate_ops emulate_ops = { + .read_gpr = emulator_read_gpr, + .write_gpr = emulator_write_gpr, .read_std = kvm_read_guest_virt_system, .write_std = kvm_write_guest_virt_system, .fetch = kvm_fetch_guest_virt, @@ -4367,14 +4370,6 @@ static struct x86_emulate_ops emulate_ops = { .get_cpuid = emulator_get_cpuid, }; -static void cache_all_regs(struct kvm_vcpu *vcpu) -{ - kvm_register_read(vcpu, VCPU_REGS_RAX); - kvm_register_read(vcpu, VCPU_REGS_RSP); - kvm_register_read(vcpu, VCPU_REGS_RIP); - vcpu->arch.regs_dirty = ~0; -} - static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) { u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(vcpu, mask); @@ -4401,12 +4396,10 @@ static void inject_emulated_exception(struct kvm_vcpu *vcpu) kvm_queue_exception(vcpu, ctxt->exception.vector); } -static void init_decode_cache(struct x86_emulate_ctxt *ctxt, - const unsigned long *regs) +static void init_decode_cache(struct x86_emulate_ctxt *ctxt) { memset(&ctxt->twobyte, 0, - (void *)&ctxt->regs - (void *)&ctxt->twobyte); - memcpy(ctxt->regs, regs, sizeof(ctxt->regs)); + (void *)&ctxt->_regs - (void *)&ctxt->twobyte); ctxt->fetch.start = 0; ctxt->fetch.end = 0; @@ -4421,14 +4414,6 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; int cs_db, cs_l; - /* - * TODO: fix emulate.c to use guest_read/write_register - * instead of direct ->regs accesses, can save hundred cycles - * on Intel for instructions that don't read/change RSP, for - * for example. - */ - cache_all_regs(vcpu); - kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); ctxt->eflags = kvm_get_rflags(vcpu); @@ -4440,7 +4425,7 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) X86EMUL_MODE_PROT16; ctxt->guest_mode = is_guest_mode(vcpu); - init_decode_cache(ctxt, vcpu->arch.regs); + init_decode_cache(ctxt); vcpu->arch.emulate_regs_need_sync_from_vcpu = false; } @@ -4460,7 +4445,6 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip) return EMULATE_FAIL; ctxt->eip = ctxt->_eip; - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); kvm_rip_write(vcpu, ctxt->eip); kvm_set_rflags(vcpu, ctxt->eflags); @@ -4493,13 +4477,14 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu) static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva) { gpa_t gpa; + pfn_t pfn; if (tdp_enabled) return false; /* * if emulation was due to access to shadowed page table - * and it failed try to unshadow page and re-entetr the + * and it failed try to unshadow page and re-enter the * guest to let CPU execute the instruction. */ if (kvm_mmu_unprotect_page_virt(vcpu, gva)) @@ -4510,8 +4495,17 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva) if (gpa == UNMAPPED_GVA) return true; /* let cpu generate fault */ - if (!kvm_is_error_hva(gfn_to_hva(vcpu->kvm, gpa >> PAGE_SHIFT))) + /* + * Do not retry the unhandleable instruction if it faults on the + * readonly host memory, otherwise it will goto a infinite loop: + * retry instruction -> write #PF -> emulation fail -> retry + * instruction -> ... + */ + pfn = gfn_to_pfn(vcpu->kvm, gpa_to_gfn(gpa)); + if (!is_error_pfn(pfn)) { + kvm_release_pfn_clean(pfn); return true; + } return false; } @@ -4560,6 +4554,9 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt, return true; } +static int complete_emulated_mmio(struct kvm_vcpu *vcpu); +static int complete_emulated_pio(struct kvm_vcpu *vcpu); + int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2, int emulation_type, @@ -4608,7 +4605,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, changes registers values during IO operation */ if (vcpu->arch.emulate_regs_need_sync_from_vcpu) { vcpu->arch.emulate_regs_need_sync_from_vcpu = false; - memcpy(ctxt->regs, vcpu->arch.regs, sizeof ctxt->regs); + emulator_invalidate_register_cache(ctxt); } restart: @@ -4630,13 +4627,16 @@ restart: } else if (vcpu->arch.pio.count) { if (!vcpu->arch.pio.in) vcpu->arch.pio.count = 0; - else + else { writeback = false; + vcpu->arch.complete_userspace_io = complete_emulated_pio; + } r = EMULATE_DO_MMIO; } else if (vcpu->mmio_needed) { if (!vcpu->mmio_is_write) writeback = false; r = EMULATE_DO_MMIO; + vcpu->arch.complete_userspace_io = complete_emulated_mmio; } else if (r == EMULATION_RESTART) goto restart; else @@ -4646,7 +4646,6 @@ restart: toggle_interruptibility(vcpu, ctxt->interruptibility); kvm_set_rflags(vcpu, ctxt->eflags); kvm_make_request(KVM_REQ_EVENT, vcpu); - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; kvm_rip_write(vcpu, ctxt->eip); } else @@ -4929,6 +4928,7 @@ int kvm_arch_init(void *opaque) if (cpu_has_xsave) host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); + kvm_lapic_init(); return 0; out: @@ -5499,6 +5499,24 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) return r; } +static inline int complete_emulated_io(struct kvm_vcpu *vcpu) +{ + int r; + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); + r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE); + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); + if (r != EMULATE_DONE) + return 0; + return 1; +} + +static int complete_emulated_pio(struct kvm_vcpu *vcpu) +{ + BUG_ON(!vcpu->arch.pio.count); + + return complete_emulated_io(vcpu); +} + /* * Implements the following, as a state machine: * @@ -5515,47 +5533,37 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) * copy data * exit */ -static int complete_mmio(struct kvm_vcpu *vcpu) +static int complete_emulated_mmio(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; struct kvm_mmio_fragment *frag; - int r; - if (!(vcpu->arch.pio.count || vcpu->mmio_needed)) - return 1; + BUG_ON(!vcpu->mmio_needed); - if (vcpu->mmio_needed) { - /* Complete previous fragment */ - frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++]; - if (!vcpu->mmio_is_write) - memcpy(frag->data, run->mmio.data, frag->len); - if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) { - vcpu->mmio_needed = 0; - if (vcpu->mmio_is_write) - return 1; - vcpu->mmio_read_completed = 1; - goto done; - } - /* Initiate next fragment */ - ++frag; - run->exit_reason = KVM_EXIT_MMIO; - run->mmio.phys_addr = frag->gpa; + /* Complete previous fragment */ + frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++]; + if (!vcpu->mmio_is_write) + memcpy(frag->data, run->mmio.data, frag->len); + if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) { + vcpu->mmio_needed = 0; if (vcpu->mmio_is_write) - memcpy(run->mmio.data, frag->data, frag->len); - run->mmio.len = frag->len; - run->mmio.is_write = vcpu->mmio_is_write; - return 0; - - } -done: - vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); - r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE); - srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); - if (r != EMULATE_DONE) - return 0; - return 1; + return 1; + vcpu->mmio_read_completed = 1; + return complete_emulated_io(vcpu); + } + /* Initiate next fragment */ + ++frag; + run->exit_reason = KVM_EXIT_MMIO; + run->mmio.phys_addr = frag->gpa; + if (vcpu->mmio_is_write) + memcpy(run->mmio.data, frag->data, frag->len); + run->mmio.len = frag->len; + run->mmio.is_write = vcpu->mmio_is_write; + vcpu->arch.complete_userspace_io = complete_emulated_mmio; + return 0; } + int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { int r; @@ -5582,9 +5590,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) } } - r = complete_mmio(vcpu); - if (r <= 0) - goto out; + if (unlikely(vcpu->arch.complete_userspace_io)) { + int (*cui)(struct kvm_vcpu *) = vcpu->arch.complete_userspace_io; + vcpu->arch.complete_userspace_io = NULL; + r = cui(vcpu); + if (r <= 0) + goto out; + } else + WARN_ON(vcpu->arch.pio.count || vcpu->mmio_needed); r = __vcpu_run(vcpu); @@ -5602,12 +5615,11 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) /* * We are here if userspace calls get_regs() in the middle of * instruction emulation. Registers state needs to be copied - * back from emulation context to vcpu. Usrapace shouldn't do + * back from emulation context to vcpu. Userspace shouldn't do * that usually, but some bad designed PV devices (vmware * backdoor interface) need this to work */ - struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); + emulator_writeback_register_cache(&vcpu->arch.emulate_ctxt); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; } regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX); @@ -5747,7 +5759,6 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, if (ret) return EMULATE_FAIL; - memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); kvm_rip_write(vcpu, ctxt->eip); kvm_set_rflags(vcpu, ctxt->eflags); kvm_make_request(KVM_REQ_EVENT, vcpu); @@ -5799,7 +5810,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, if (mmu_reset_needed) kvm_mmu_reset_context(vcpu); - max_bits = (sizeof sregs->interrupt_bitmap) << 3; + max_bits = KVM_NR_INTERRUPTS; pending_vec = find_first_bit( (const unsigned long *)sregs->interrupt_bitmap, max_bits); if (pending_vec < max_bits) { @@ -5859,13 +5870,12 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) { for (i = 0; i < KVM_NR_DB_REGS; ++i) vcpu->arch.eff_db[i] = dbg->arch.debugreg[i]; - vcpu->arch.switch_db_regs = - (dbg->arch.debugreg[7] & DR7_BP_EN_MASK); + vcpu->arch.guest_debug_dr7 = dbg->arch.debugreg[7]; } else { for (i = 0; i < KVM_NR_DB_REGS; i++) vcpu->arch.eff_db[i] = vcpu->arch.db[i]; - vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK); } + kvm_update_dr7(vcpu); if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) vcpu->arch.singlestep_rip = kvm_rip_read(vcpu) + @@ -5877,7 +5887,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, */ kvm_set_rflags(vcpu, rflags); - kvm_x86_ops->set_guest_debug(vcpu, dbg); + kvm_x86_ops->update_db_bp_intercept(vcpu); r = 0; @@ -6023,7 +6033,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) int r; vcpu->arch.mtrr_state.have_fixed = 1; - vcpu_load(vcpu); + r = vcpu_load(vcpu); + if (r) + return r; r = kvm_arch_vcpu_reset(vcpu); if (r == 0) r = kvm_mmu_setup(vcpu); @@ -6034,9 +6046,11 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { + int r; vcpu->arch.apf.msr_val = 0; - vcpu_load(vcpu); + r = vcpu_load(vcpu); + BUG_ON(r); kvm_mmu_unload(vcpu); vcpu_put(vcpu); @@ -6050,10 +6064,10 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) vcpu->arch.nmi_pending = 0; vcpu->arch.nmi_injected = false; - vcpu->arch.switch_db_regs = 0; memset(vcpu->arch.db, 0, sizeof(vcpu->arch.db)); vcpu->arch.dr6 = DR6_FIXED_1; vcpu->arch.dr7 = DR7_FIXED_1; + kvm_update_dr7(vcpu); kvm_make_request(KVM_REQ_EVENT, vcpu); vcpu->arch.apf.msr_val = 0; @@ -6132,7 +6146,7 @@ int kvm_arch_hardware_enable(void *garbage) * as we reset last_host_tsc on all VCPUs to stop this from being * called multiple times (one for each physical CPU bringup). * - * Platforms with unnreliable TSCs don't have to deal with this, they + * Platforms with unreliable TSCs don't have to deal with this, they * will be compensated by the logic in vcpu_load, which sets the TSC to * catchup mode. This will catchup all VCPUs to real time, but cannot * guarantee that they stay in perfect synchronization. @@ -6185,6 +6199,8 @@ bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL); } +struct static_key kvm_no_apic_vcpu __read_mostly; + int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) { struct page *page; @@ -6217,7 +6233,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) r = kvm_create_lapic(vcpu); if (r < 0) goto fail_mmu_destroy; - } + } else + static_key_slow_inc(&kvm_no_apic_vcpu); vcpu->arch.mce_banks = kzalloc(KVM_MAX_MCE_BANKS * sizeof(u64) * 4, GFP_KERNEL); @@ -6257,6 +6274,8 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) kvm_mmu_destroy(vcpu); srcu_read_unlock(&vcpu->kvm->srcu, idx); free_page((unsigned long)vcpu->arch.pio_data); + if (!irqchip_in_kernel(vcpu->kvm)) + static_key_slow_dec(&kvm_no_apic_vcpu); } int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) @@ -6269,15 +6288,21 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */ set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap); + /* Reserve bit 1 of irq_sources_bitmap for irqfd-resampler */ + set_bit(KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, + &kvm->arch.irq_sources_bitmap); raw_spin_lock_init(&kvm->arch.tsc_write_lock); + mutex_init(&kvm->arch.apic_map_lock); return 0; } static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) { - vcpu_load(vcpu); + int r; + r = vcpu_load(vcpu); + BUG_ON(r); kvm_mmu_unload(vcpu); vcpu_put(vcpu); } @@ -6321,6 +6346,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) put_page(kvm->arch.apic_access_page); if (kvm->arch.ept_identity_pagetable) put_page(kvm->arch.ept_identity_pagetable); + kfree(rcu_dereference_check(kvm->arch.apic_map, 1)); } void kvm_arch_free_memslot(struct kvm_memory_slot *free, @@ -6328,10 +6354,18 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free, { int i; - for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { - if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) { - kvm_kvfree(free->arch.lpage_info[i]); - free->arch.lpage_info[i] = NULL; + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { + if (!dont || free->arch.rmap[i] != dont->arch.rmap[i]) { + kvm_kvfree(free->arch.rmap[i]); + free->arch.rmap[i] = NULL; + } + if (i == 0) + continue; + + if (!dont || free->arch.lpage_info[i - 1] != + dont->arch.lpage_info[i - 1]) { + kvm_kvfree(free->arch.lpage_info[i - 1]); + free->arch.lpage_info[i - 1] = NULL; } } } @@ -6340,23 +6374,30 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) { int i; - for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { unsigned long ugfn; int lpages; - int level = i + 2; + int level = i + 1; lpages = gfn_to_index(slot->base_gfn + npages - 1, slot->base_gfn, level) + 1; - slot->arch.lpage_info[i] = - kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i])); - if (!slot->arch.lpage_info[i]) + slot->arch.rmap[i] = + kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap[i])); + if (!slot->arch.rmap[i]) + goto out_free; + if (i == 0) + continue; + + slot->arch.lpage_info[i - 1] = kvm_kvzalloc(lpages * + sizeof(*slot->arch.lpage_info[i - 1])); + if (!slot->arch.lpage_info[i - 1]) goto out_free; if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1)) - slot->arch.lpage_info[i][0].write_count = 1; + slot->arch.lpage_info[i - 1][0].write_count = 1; if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1)) - slot->arch.lpage_info[i][lpages - 1].write_count = 1; + slot->arch.lpage_info[i - 1][lpages - 1].write_count = 1; ugfn = slot->userspace_addr >> PAGE_SHIFT; /* * If the gfn and userspace address are not aligned wrt each @@ -6368,16 +6409,21 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) unsigned long j; for (j = 0; j < lpages; ++j) - slot->arch.lpage_info[i][j].write_count = 1; + slot->arch.lpage_info[i - 1][j].write_count = 1; } } return 0; out_free: - for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) { - kvm_kvfree(slot->arch.lpage_info[i]); - slot->arch.lpage_info[i] = NULL; + for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) { + kvm_kvfree(slot->arch.rmap[i]); + slot->arch.rmap[i] = NULL; + if (i == 0) + continue; + + kvm_kvfree(slot->arch.lpage_info[i - 1]); + slot->arch.lpage_info[i - 1] = NULL; } return -ENOMEM; } @@ -6396,10 +6442,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, map_flags = MAP_SHARED | MAP_ANONYMOUS; /*To keep backward compatibility with older userspace, - *x86 needs to hanlde !user_alloc case. + *x86 needs to handle !user_alloc case. */ if (!user_alloc) { - if (npages && !old.rmap) { + if (npages && !old.npages) { unsigned long userspace_addr; userspace_addr = vm_mmap(NULL, 0, @@ -6427,7 +6473,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT; - if (!user_alloc && !old.user_alloc && old.rmap && !npages) { + if (!user_alloc && !old.user_alloc && old.npages && !npages) { int ret; ret = vm_munmap(old.userspace_addr, @@ -6446,14 +6492,28 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages); kvm_mmu_slot_remove_write_access(kvm, mem->slot); spin_unlock(&kvm->mmu_lock); + /* + * If memory slot is created, or moved, we need to clear all + * mmio sptes. + */ + if (npages && old.base_gfn != mem->guest_phys_addr >> PAGE_SHIFT) { + kvm_mmu_zap_all(kvm); + kvm_reload_remote_mmus(kvm); + } } -void kvm_arch_flush_shadow(struct kvm *kvm) +void kvm_arch_flush_shadow_all(struct kvm *kvm) { kvm_mmu_zap_all(kvm); kvm_reload_remote_mmus(kvm); } +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot) +{ + kvm_arch_flush_shadow_all(kvm); +} + int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) { return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE && diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 3d1134ddb885..2b5219c12ac8 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -124,4 +124,5 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, extern u64 host_xcr0; +extern struct static_key kvm_no_apic_vcpu; #endif diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 2d932c351f91..bf788d34530d 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -33,6 +33,7 @@ #include <linux/memblock.h> #include <xen/xen.h> +#include <xen/events.h> #include <xen/interface/xen.h> #include <xen/interface/version.h> #include <xen/interface/physdev.h> diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c index 157337657971..01a4dc015ae1 100644 --- a/arch/x86/xen/irq.c +++ b/arch/x86/xen/irq.c @@ -5,6 +5,7 @@ #include <xen/interface/xen.h> #include <xen/interface/sched.h> #include <xen/interface/vcpu.h> +#include <xen/events.h> #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index bb5a8105ea86..a95b41744ad0 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -35,7 +35,6 @@ void xen_set_pat(u64); char * __init xen_memory_setup(void); void __init xen_arch_setup(void); -void __init xen_init_IRQ(void); void xen_enable_sysenter(void); void xen_enable_syscall(void); void xen_vcpu_restore(void); diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h index 6e65eadaae14..5293312bc6a4 100644 --- a/arch/xtensa/include/asm/elf.h +++ b/arch/xtensa/include/asm/elf.h @@ -189,7 +189,8 @@ typedef struct { #endif } elf_xtregs_t; -#define SET_PERSONALITY(ex) set_personality(PER_LINUX_32BIT) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX_32BIT | (current->personality & (~PER_MASK))) struct task_struct; diff --git a/crypto/842.c b/crypto/842.c new file mode 100644 index 000000000000..65c7a89cfa09 --- /dev/null +++ b/crypto/842.c @@ -0,0 +1,182 @@ +/* + * Cryptographic API for the 842 compression algorithm. + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2011 + * + * Authors: Robert Jennings <rcj@linux.vnet.ibm.com> + * Seth Jennings <sjenning@linux.vnet.ibm.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/vmalloc.h> +#include <linux/nx842.h> +#include <linux/lzo.h> +#include <linux/timer.h> + +static int nx842_uselzo; + +struct nx842_ctx { + void *nx842_wmem; /* working memory for 842/lzo */ +}; + +enum nx842_crypto_type { + NX842_CRYPTO_TYPE_842, + NX842_CRYPTO_TYPE_LZO +}; + +#define NX842_SENTINEL 0xdeadbeef + +struct nx842_crypto_header { + unsigned int sentinel; /* debug */ + enum nx842_crypto_type type; +}; + +static int nx842_init(struct crypto_tfm *tfm) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + int wmemsize; + + wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS); + ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS); + if (!ctx->nx842_wmem) + return -ENOMEM; + + return 0; +} + +static void nx842_exit(struct crypto_tfm *tfm) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + + kfree(ctx->nx842_wmem); +} + +static void nx842_reset_uselzo(unsigned long data) +{ + nx842_uselzo = 0; +} + +static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0); + +static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + struct nx842_crypto_header *hdr; + unsigned int tmp_len = *dlen; + size_t lzodlen; /* needed for lzo */ + int err; + + *dlen = 0; + hdr = (struct nx842_crypto_header *)dst; + hdr->sentinel = NX842_SENTINEL; /* debug */ + dst += sizeof(struct nx842_crypto_header); + tmp_len -= sizeof(struct nx842_crypto_header); + lzodlen = tmp_len; + + if (likely(!nx842_uselzo)) { + err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem); + + if (likely(!err)) { + hdr->type = NX842_CRYPTO_TYPE_842; + *dlen = tmp_len + sizeof(struct nx842_crypto_header); + return 0; + } + + /* hardware failed */ + nx842_uselzo = 1; + + /* set timer to check for hardware again in 1 second */ + mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000)); + } + + /* no hardware, use lzo */ + err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem); + if (err != LZO_E_OK) + return -EINVAL; + + hdr->type = NX842_CRYPTO_TYPE_LZO; + *dlen = lzodlen + sizeof(struct nx842_crypto_header); + return 0; +} + +static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src, + unsigned int slen, u8 *dst, unsigned int *dlen) +{ + struct nx842_ctx *ctx = crypto_tfm_ctx(tfm); + struct nx842_crypto_header *hdr; + unsigned int tmp_len = *dlen; + size_t lzodlen; /* needed for lzo */ + int err; + + *dlen = 0; + hdr = (struct nx842_crypto_header *)src; + + if (unlikely(hdr->sentinel != NX842_SENTINEL)) + return -EINVAL; + + src += sizeof(struct nx842_crypto_header); + slen -= sizeof(struct nx842_crypto_header); + + if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) { + err = nx842_decompress(src, slen, dst, &tmp_len, + ctx->nx842_wmem); + if (err) + return -EINVAL; + *dlen = tmp_len; + } else if (hdr->type == NX842_CRYPTO_TYPE_LZO) { + lzodlen = tmp_len; + err = lzo1x_decompress_safe(src, slen, dst, &lzodlen); + if (err != LZO_E_OK) + return -EINVAL; + *dlen = lzodlen; + } else + return -EINVAL; + + return 0; +} + +static struct crypto_alg alg = { + .cra_name = "842", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_ctx), + .cra_module = THIS_MODULE, + .cra_init = nx842_init, + .cra_exit = nx842_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } +}; + +static int __init nx842_mod_init(void) +{ + del_timer(&failover_timer); + return crypto_register_alg(&alg); +} + +static void __exit nx842_mod_exit(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(nx842_mod_init); +module_exit(nx842_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("842 Compression Algorithm"); diff --git a/crypto/Kconfig b/crypto/Kconfig index 957cc56ce4b9..50402dc0ea35 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -460,6 +460,15 @@ config CRYPTO_SHA1_SPARC64 SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented using sparc64 crypto instructions, when available. +config CRYPTO_SHA1_ARM + tristate "SHA1 digest algorithm (ARM-asm)" + depends on ARM + select CRYPTO_SHA1 + select CRYPTO_HASH + help + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented + using optimized ARM assembler. + config CRYPTO_SHA256 tristate "SHA224 and SHA256 digest algorithm" select CRYPTO_HASH @@ -609,6 +618,8 @@ config CRYPTO_AES_NI_INTEL select CRYPTO_CRYPTD select CRYPTO_ABLK_HELPER_X86 select CRYPTO_ALGAPI + select CRYPTO_LRW + select CRYPTO_XTS help Use Intel AES-NI instructions for AES algorithm. @@ -661,6 +672,30 @@ config CRYPTO_AES_SPARC64 for some popular block cipher mode is supported too, including ECB and CBC. +config CRYPTO_AES_ARM + tristate "AES cipher algorithms (ARM-asm)" + depends on ARM + select CRYPTO_ALGAPI + select CRYPTO_AES + help + Use optimized AES assembler routines for ARM platforms. + + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + The AES specifies three key sizes: 128, 192 and 256 bits + + See <http://csrc.nist.gov/encryption/aes/> for more information. + config CRYPTO_ANUBIS tristate "Anubis cipher algorithm" select CRYPTO_ALGAPI @@ -781,6 +816,20 @@ config CRYPTO_CAST5 The CAST5 encryption algorithm (synonymous with CAST-128) is described in RFC2144. +config CRYPTO_CAST5_AVX_X86_64 + tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)" + depends on X86 && 64BIT + select CRYPTO_ALGAPI + select CRYPTO_CRYPTD + select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_CAST5 + help + The CAST5 encryption algorithm (synonymous with CAST-128) is + described in RFC2144. + + This module provides the Cast5 cipher algorithm that processes + sixteen blocks parallel using the AVX instruction set. + config CRYPTO_CAST6 tristate "CAST6 (CAST-256) cipher algorithm" select CRYPTO_ALGAPI @@ -788,6 +837,23 @@ config CRYPTO_CAST6 The CAST6 encryption algorithm (synonymous with CAST-256) is described in RFC2612. +config CRYPTO_CAST6_AVX_X86_64 + tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)" + depends on X86 && 64BIT + select CRYPTO_ALGAPI + select CRYPTO_CRYPTD + select CRYPTO_ABLK_HELPER_X86 + select CRYPTO_GLUE_HELPER_X86 + select CRYPTO_CAST6 + select CRYPTO_LRW + select CRYPTO_XTS + help + The CAST6 encryption algorithm (synonymous with CAST-256) is + described in RFC2612. + + This module provides the Cast6 cipher algorithm that processes + eight blocks parallel using the AVX instruction set. + config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" select CRYPTO_ALGAPI @@ -1106,6 +1172,15 @@ config CRYPTO_LZO help This is the LZO algorithm. +config CRYPTO_842 + tristate "842 compression algorithm" + depends on CRYPTO_DEV_NX_COMPRESS + # 842 uses lzo if the hardware becomes unavailable + select LZO_COMPRESS + select LZO_DECOMPRESS + help + This is the 842 algorithm. + comment "Random Number Generation" config CRYPTO_ANSI_CPRNG diff --git a/crypto/Makefile b/crypto/Makefile index 30f33d675330..a301ad2b258c 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -68,8 +68,8 @@ 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_generic.o -obj-$(CONFIG_CRYPTO_CAST5) += cast5.o -obj-$(CONFIG_CRYPTO_CAST6) += cast6.o +obj-$(CONFIG_CRYPTO_CAST5) += cast5_generic.o +obj-$(CONFIG_CRYPTO_CAST6) += cast6_generic.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o @@ -82,6 +82,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o +obj-$(CONFIG_CRYPTO_842) += 842.o obj-$(CONFIG_CRYPTO_RNG2) += rng.o obj-$(CONFIG_CRYPTO_RNG2) += krng.o obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o diff --git a/crypto/aes_generic.c b/crypto/aes_generic.c index a68c73dae15a..47f2e5c71759 100644 --- a/crypto/aes_generic.c +++ b/crypto/aes_generic.c @@ -1448,7 +1448,6 @@ static struct crypto_alg aes_alg = { .cra_ctxsize = sizeof(struct crypto_aes_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 6ddd99e6114b..c0bb3778f1ae 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -382,26 +382,6 @@ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) return 0; } -static struct crypto_alg rng_alg = { - .cra_name = "stdrng", - .cra_driver_name = "ansi_cprng", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_RNG, - .cra_ctxsize = sizeof(struct prng_context), - .cra_type = &crypto_rng_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(rng_alg.cra_list), - .cra_init = cprng_init, - .cra_exit = cprng_exit, - .cra_u = { - .rng = { - .rng_make_random = cprng_get_random, - .rng_reset = cprng_reset, - .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, - } - } -}; - #ifdef CONFIG_CRYPTO_FIPS static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen) @@ -438,8 +418,27 @@ static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen) out: return rc; } +#endif -static struct crypto_alg fips_rng_alg = { +static struct crypto_alg rng_algs[] = { { + .cra_name = "stdrng", + .cra_driver_name = "ansi_cprng", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_RNG, + .cra_ctxsize = sizeof(struct prng_context), + .cra_type = &crypto_rng_type, + .cra_module = THIS_MODULE, + .cra_init = cprng_init, + .cra_exit = cprng_exit, + .cra_u = { + .rng = { + .rng_make_random = cprng_get_random, + .rng_reset = cprng_reset, + .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, + } + } +#ifdef CONFIG_CRYPTO_FIPS +}, { .cra_name = "fips(ansi_cprng)", .cra_driver_name = "fips_ansi_cprng", .cra_priority = 300, @@ -447,7 +446,6 @@ static struct crypto_alg fips_rng_alg = { .cra_ctxsize = sizeof(struct prng_context), .cra_type = &crypto_rng_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(rng_alg.cra_list), .cra_init = cprng_init, .cra_exit = cprng_exit, .cra_u = { @@ -457,33 +455,18 @@ static struct crypto_alg fips_rng_alg = { .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ, } } -}; #endif +} }; /* Module initalization */ static int __init prng_mod_init(void) { - int rc = 0; - - rc = crypto_register_alg(&rng_alg); -#ifdef CONFIG_CRYPTO_FIPS - if (rc) - goto out; - - rc = crypto_register_alg(&fips_rng_alg); - -out: -#endif - return rc; + return crypto_register_algs(rng_algs, ARRAY_SIZE(rng_algs)); } static void __exit prng_mod_fini(void) { - crypto_unregister_alg(&rng_alg); -#ifdef CONFIG_CRYPTO_FIPS - crypto_unregister_alg(&fips_rng_alg); -#endif - return; + crypto_unregister_algs(rng_algs, ARRAY_SIZE(rng_algs)); } MODULE_LICENSE("GPL"); diff --git a/crypto/anubis.c b/crypto/anubis.c index 77530d571c96..008c8a4fb67c 100644 --- a/crypto/anubis.c +++ b/crypto/anubis.c @@ -678,7 +678,6 @@ static struct crypto_alg anubis_alg = { .cra_ctxsize = sizeof (struct anubis_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(anubis_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = ANUBIS_MIN_KEY_SIZE, .cia_max_keysize = ANUBIS_MAX_KEY_SIZE, diff --git a/crypto/blowfish_generic.c b/crypto/blowfish_generic.c index 6f269b5cfa3b..8baf5447d35b 100644 --- a/crypto/blowfish_generic.c +++ b/crypto/blowfish_generic.c @@ -115,7 +115,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct bf_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = BF_MIN_KEY_SIZE, .cia_max_keysize = BF_MAX_KEY_SIZE, diff --git a/crypto/camellia_generic.c b/crypto/camellia_generic.c index f7aaaaf86982..75efa2052305 100644 --- a/crypto/camellia_generic.c +++ b/crypto/camellia_generic.c @@ -1072,7 +1072,6 @@ static struct crypto_alg camellia_alg = { .cra_ctxsize = sizeof(struct camellia_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, diff --git a/crypto/cast5.c b/crypto/cast5_generic.c index 4a230ddec877..bc525dbd8a4b 100644 --- a/crypto/cast5.c +++ b/crypto/cast5_generic.c @@ -4,8 +4,8 @@ * Derived from GnuPG implementation of cast5. * * Major Changes. -* Complete conformance to rfc2144. -* Supports key size from 40 to 128 bits. +* Complete conformance to rfc2144. +* Supports key size from 40 to 128 bits. * * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>. @@ -28,19 +28,10 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/types.h> +#include <crypto/cast5.h> -#define CAST5_BLOCK_SIZE 8 -#define CAST5_MIN_KEY_SIZE 5 -#define CAST5_MAX_KEY_SIZE 16 -struct cast5_ctx { - u32 Km[16]; - u8 Kr[16]; - int rr; /* rr?number of rounds = 16:number of rounds = 12; (rfc 2144) */ -}; - - -static const u32 s1[256] = { +const u32 cast5_s1[256] = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, @@ -106,7 +97,8 @@ static const u32 s1[256] = { 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf }; -static const u32 s2[256] = { +EXPORT_SYMBOL_GPL(cast5_s1); +const u32 cast5_s2[256] = { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, @@ -172,7 +164,8 @@ static const u32 s2[256] = { 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 }; -static const u32 s3[256] = { +EXPORT_SYMBOL_GPL(cast5_s2); +const u32 cast5_s3[256] = { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, @@ -238,7 +231,8 @@ static const u32 s3[256] = { 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 }; -static const u32 s4[256] = { +EXPORT_SYMBOL_GPL(cast5_s3); +const u32 cast5_s4[256] = { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, @@ -304,6 +298,7 @@ static const u32 s4[256] = { 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 }; +EXPORT_SYMBOL_GPL(cast5_s4); static const u32 s5[256] = { 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, @@ -569,17 +564,21 @@ static const u32 sb8[256] = { 0xeaee6801, 0x8db2a283, 0xea8bf59e }; +#define s1 cast5_s1 +#define s2 cast5_s2 +#define s3 cast5_s3 +#define s4 cast5_s4 + #define F1(D, m, r) ((I = ((m) + (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) + (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) #define F2(D, m, r) ((I = ((m) ^ (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) + (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) #define F3(D, m, r) ((I = ((m) - (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) + (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) -static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +void __cast5_encrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast5_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 l, r, t; @@ -628,10 +627,15 @@ static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[0] = cpu_to_be32(r); dst[1] = cpu_to_be32(l); } +EXPORT_SYMBOL_GPL(__cast5_encrypt); -static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast5_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} + +void __cast5_decrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast5_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 l, r, t; @@ -667,6 +671,12 @@ static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[0] = cpu_to_be32(r); dst[1] = cpu_to_be32(l); } +EXPORT_SYMBOL_GPL(__cast5_decrypt); + +static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast5_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} static void key_schedule(u32 *x, u32 *z, u32 *k) { @@ -743,7 +753,7 @@ static void key_schedule(u32 *x, u32 *z, u32 *k) } -static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len) +int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) { struct cast5_ctx *c = crypto_tfm_ctx(tfm); int i; @@ -771,20 +781,22 @@ static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len) c->Kr[i] = k[i] & 0x1f; return 0; } +EXPORT_SYMBOL_GPL(cast5_setkey); static struct crypto_alg alg = { - .cra_name = "cast5", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = CAST5_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct cast5_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), - .cra_u = { + .cra_name = "cast5", + .cra_driver_name = "cast5-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = CAST5_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct cast5_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_u = { .cipher = { .cia_min_keysize = CAST5_MIN_KEY_SIZE, .cia_max_keysize = CAST5_MAX_KEY_SIZE, - .cia_setkey = cast5_setkey, + .cia_setkey = cast5_setkey, .cia_encrypt = cast5_encrypt, .cia_decrypt = cast5_decrypt } @@ -806,4 +818,4 @@ module_exit(cast5_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast5 Cipher Algorithm"); - +MODULE_ALIAS("cast5"); diff --git a/crypto/cast6.c b/crypto/cast6_generic.c index e0c15a6c7c34..1acd2f1c48fc 100644 --- a/crypto/cast6.c +++ b/crypto/cast6_generic.c @@ -25,24 +25,21 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/types.h> +#include <crypto/cast6.h> -#define CAST6_BLOCK_SIZE 16 -#define CAST6_MIN_KEY_SIZE 16 -#define CAST6_MAX_KEY_SIZE 32 - -struct cast6_ctx { - u32 Km[12][4]; - u8 Kr[12][4]; -}; +#define s1 cast6_s1 +#define s2 cast6_s2 +#define s3 cast6_s3 +#define s4 cast6_s4 #define F1(D, r, m) ((I = ((m) + (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) + (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff])) #define F2(D, r, m) ((I = ((m) ^ (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) + (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff])) #define F3(D, r, m) ((I = ((m) - (D))), (I = rol32(I, (r))), \ - (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) + (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff])) -static const u32 s1[256] = { +const u32 cast6_s1[256] = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, @@ -108,8 +105,9 @@ static const u32 s1[256] = { 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf }; +EXPORT_SYMBOL_GPL(cast6_s1); -static const u32 s2[256] = { +const u32 cast6_s2[256] = { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, @@ -175,8 +173,9 @@ static const u32 s2[256] = { 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 }; +EXPORT_SYMBOL_GPL(cast6_s2); -static const u32 s3[256] = { +const u32 cast6_s3[256] = { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, @@ -242,8 +241,9 @@ static const u32 s3[256] = { 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 }; +EXPORT_SYMBOL_GPL(cast6_s3); -static const u32 s4[256] = { +const u32 cast6_s4[256] = { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, @@ -309,6 +309,7 @@ static const u32 s4[256] = { 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 }; +EXPORT_SYMBOL_GPL(cast6_s4); static const u32 Tm[24][8] = { { 0x5a827999, 0xc95c653a, 0x383650db, 0xa7103c7c, 0x15ea281d, @@ -369,7 +370,7 @@ static const u8 Tr[4][8] = { }; /* forward octave */ -static void W(u32 *key, unsigned int i) +static inline void W(u32 *key, unsigned int i) { u32 I; key[6] ^= F1(key[7], Tr[i % 4][0], Tm[i][0]); @@ -382,14 +383,12 @@ static void W(u32 *key, unsigned int i) key[7] ^= F2(key[0], Tr[i % 4][7], Tm[i][7]); } -static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key, - unsigned key_len) +int __cast6_setkey(struct cast6_ctx *c, const u8 *in_key, + unsigned key_len, u32 *flags) { int i; u32 key[8]; __be32 p_key[8]; /* padded key */ - struct cast6_ctx *c = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; if (key_len % 4 != 0) { *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; @@ -425,9 +424,17 @@ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key, return 0; } +EXPORT_SYMBOL_GPL(__cast6_setkey); + +int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + return __cast6_setkey(crypto_tfm_ctx(tfm), key, keylen, + &tfm->crt_flags); +} +EXPORT_SYMBOL_GPL(cast6_setkey); /*forward quad round*/ -static void Q(u32 *block, u8 *Kr, u32 *Km) +static inline void Q(u32 *block, u8 *Kr, u32 *Km) { u32 I; block[2] ^= F1(block[3], Kr[0], Km[0]); @@ -437,7 +444,7 @@ static void Q(u32 *block, u8 *Kr, u32 *Km) } /*reverse quad round*/ -static void QBAR(u32 *block, u8 *Kr, u32 *Km) +static inline void QBAR(u32 *block, u8 *Kr, u32 *Km) { u32 I; block[3] ^= F1(block[0], Kr[3], Km[3]); @@ -446,9 +453,8 @@ static void QBAR(u32 *block, u8 *Kr, u32 *Km) block[2] ^= F1(block[3], Kr[0], Km[0]); } -static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +void __cast6_encrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast6_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 block[4]; @@ -478,10 +484,15 @@ static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[2] = cpu_to_be32(block[2]); dst[3] = cpu_to_be32(block[3]); } +EXPORT_SYMBOL_GPL(__cast6_encrypt); -static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast6_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} + +void __cast6_decrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf) { - struct cast6_ctx *c = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)inbuf; __be32 *dst = (__be32 *)outbuf; u32 block[4]; @@ -511,15 +522,22 @@ static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) dst[2] = cpu_to_be32(block[2]); dst[3] = cpu_to_be32(block[3]); } +EXPORT_SYMBOL_GPL(__cast6_decrypt); + +static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf) +{ + __cast6_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf); +} static struct crypto_alg alg = { .cra_name = "cast6", + .cra_driver_name = "cast6-generic", + .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = CAST6_BLOCK_SIZE, .cra_ctxsize = sizeof(struct cast6_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = CAST6_MIN_KEY_SIZE, @@ -545,3 +563,4 @@ module_exit(cast6_mod_fini); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cast6 Cipher Algorithm"); +MODULE_ALIAS("cast6"); diff --git a/crypto/crypto_null.c b/crypto/crypto_null.c index 07a8a96d46fc..fee7265cd35d 100644 --- a/crypto/crypto_null.c +++ b/crypto/crypto_null.c @@ -94,18 +94,6 @@ static int skcipher_null_crypt(struct blkcipher_desc *desc, return err; } -static struct crypto_alg compress_null = { - .cra_name = "compress_null", - .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(compress_null.cra_list), - .cra_u = { .compress = { - .coa_compress = null_compress, - .coa_decompress = null_compress } } -}; - static struct shash_alg digest_null = { .digestsize = NULL_DIGEST_SIZE, .setkey = null_hash_setkey, @@ -122,22 +110,19 @@ static struct shash_alg digest_null = { } }; -static struct crypto_alg cipher_null = { +static struct crypto_alg null_algs[3] = { { .cra_name = "cipher_null", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = NULL_BLOCK_SIZE, .cra_ctxsize = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cipher_null.cra_list), .cra_u = { .cipher = { .cia_min_keysize = NULL_KEY_SIZE, .cia_max_keysize = NULL_KEY_SIZE, .cia_setkey = null_setkey, .cia_encrypt = null_crypt, .cia_decrypt = null_crypt } } -}; - -static struct crypto_alg skcipher_null = { +}, { .cra_name = "ecb(cipher_null)", .cra_driver_name = "ecb-cipher_null", .cra_priority = 100, @@ -146,7 +131,6 @@ static struct crypto_alg skcipher_null = { .cra_type = &crypto_blkcipher_type, .cra_ctxsize = 0, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(skcipher_null.cra_list), .cra_u = { .blkcipher = { .min_keysize = NULL_KEY_SIZE, .max_keysize = NULL_KEY_SIZE, @@ -154,7 +138,16 @@ static struct crypto_alg skcipher_null = { .setkey = null_setkey, .encrypt = skcipher_null_crypt, .decrypt = skcipher_null_crypt } } -}; +}, { + .cra_name = "compress_null", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_blocksize = NULL_BLOCK_SIZE, + .cra_ctxsize = 0, + .cra_module = THIS_MODULE, + .cra_u = { .compress = { + .coa_compress = null_compress, + .coa_decompress = null_compress } } +} }; MODULE_ALIAS("compress_null"); MODULE_ALIAS("digest_null"); @@ -164,40 +157,26 @@ static int __init crypto_null_mod_init(void) { int ret = 0; - ret = crypto_register_alg(&cipher_null); + ret = crypto_register_algs(null_algs, ARRAY_SIZE(null_algs)); if (ret < 0) goto out; - ret = crypto_register_alg(&skcipher_null); - if (ret < 0) - goto out_unregister_cipher; - ret = crypto_register_shash(&digest_null); if (ret < 0) - goto out_unregister_skcipher; + goto out_unregister_algs; - ret = crypto_register_alg(&compress_null); - if (ret < 0) - goto out_unregister_digest; + return 0; +out_unregister_algs: + crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs)); out: return ret; - -out_unregister_digest: - crypto_unregister_shash(&digest_null); -out_unregister_skcipher: - crypto_unregister_alg(&skcipher_null); -out_unregister_cipher: - crypto_unregister_alg(&cipher_null); - goto out; } static void __exit crypto_null_mod_fini(void) { - crypto_unregister_alg(&compress_null); crypto_unregister_shash(&digest_null); - crypto_unregister_alg(&skcipher_null); - crypto_unregister_alg(&cipher_null); + crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs)); } module_init(crypto_null_mod_init); diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 6bba414d0c61..35d700a97d79 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -30,7 +30,7 @@ #include "internal.h" -DEFINE_MUTEX(crypto_cfg_mutex); +static DEFINE_MUTEX(crypto_cfg_mutex); /* The crypto netlink socket */ static struct sock *crypto_nlsk; diff --git a/crypto/deflate.c b/crypto/deflate.c index b0165ecad0c5..b57d70eb156b 100644 --- a/crypto/deflate.c +++ b/crypto/deflate.c @@ -199,7 +199,6 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, .cra_ctxsize = sizeof(struct deflate_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_init = deflate_init, .cra_exit = deflate_exit, .cra_u = { .compress = { diff --git a/crypto/des_generic.c b/crypto/des_generic.c index 873818d48e86..f6cf63f88468 100644 --- a/crypto/des_generic.c +++ b/crypto/des_generic.c @@ -943,59 +943,44 @@ static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) d[1] = cpu_to_le32(L); } -static struct crypto_alg des_alg = { +static struct crypto_alg des_algs[2] = { { .cra_name = "des", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct des_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(des_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES_KEY_SIZE, .cia_max_keysize = DES_KEY_SIZE, .cia_setkey = des_setkey, .cia_encrypt = des_encrypt, .cia_decrypt = des_decrypt } } -}; - -static struct crypto_alg des3_ede_alg = { +}, { .cra_name = "des3_ede", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct des3_ede_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(des3_ede_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = DES3_EDE_KEY_SIZE, .cia_max_keysize = DES3_EDE_KEY_SIZE, .cia_setkey = des3_ede_setkey, .cia_encrypt = des3_ede_encrypt, .cia_decrypt = des3_ede_decrypt } } -}; +} }; MODULE_ALIAS("des3_ede"); static int __init des_generic_mod_init(void) { - int ret = 0; - - ret = crypto_register_alg(&des_alg); - if (ret < 0) - goto out; - - ret = crypto_register_alg(&des3_ede_alg); - if (ret < 0) - crypto_unregister_alg(&des_alg); -out: - return ret; + return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs)); } static void __exit des_generic_mod_fini(void) { - crypto_unregister_alg(&des3_ede_alg); - crypto_unregister_alg(&des_alg); + crypto_unregister_algs(des_algs, ARRAY_SIZE(des_algs)); } module_init(des_generic_mod_init); diff --git a/crypto/fcrypt.c b/crypto/fcrypt.c index c33107e340b6..3b2cf569c684 100644 --- a/crypto/fcrypt.c +++ b/crypto/fcrypt.c @@ -396,7 +396,6 @@ static struct crypto_alg fcrypt_alg = { .cra_ctxsize = sizeof(struct fcrypt_ctx), .cra_module = THIS_MODULE, .cra_alignmask = 3, - .cra_list = LIST_HEAD_INIT(fcrypt_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = 8, .cia_max_keysize = 8, diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c index 7835b8fc94db..9d3f0c69a86f 100644 --- a/crypto/ghash-generic.c +++ b/crypto/ghash-generic.c @@ -153,7 +153,6 @@ static struct shash_alg ghash_alg = { .cra_blocksize = GHASH_BLOCK_SIZE, .cra_ctxsize = sizeof(struct ghash_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list), .cra_exit = ghash_exit_tfm, }, }; diff --git a/crypto/khazad.c b/crypto/khazad.c index 527e4e395fc3..60e7cd66facc 100644 --- a/crypto/khazad.c +++ b/crypto/khazad.c @@ -853,7 +853,6 @@ static struct crypto_alg khazad_alg = { .cra_ctxsize = sizeof (struct khazad_ctx), .cra_alignmask = 7, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(khazad_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = KHAZAD_KEY_SIZE, .cia_max_keysize = KHAZAD_KEY_SIZE, diff --git a/crypto/krng.c b/crypto/krng.c index 4328bb3430ed..a2d2b72fc135 100644 --- a/crypto/krng.c +++ b/crypto/krng.c @@ -35,7 +35,6 @@ static struct crypto_alg krng_alg = { .cra_ctxsize = 0, .cra_type = &crypto_rng_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(krng_alg.cra_list), .cra_u = { .rng = { .rng_make_random = krng_get_random, diff --git a/crypto/lzo.c b/crypto/lzo.c index b5e77077d751..1c2aa69c54b8 100644 --- a/crypto/lzo.c +++ b/crypto/lzo.c @@ -81,7 +81,6 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, .cra_ctxsize = sizeof(struct lzo_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_init = lzo_init, .cra_exit = lzo_exit, .cra_u = { .compress = { diff --git a/crypto/salsa20_generic.c b/crypto/salsa20_generic.c index eac10c11685c..9a4770c02284 100644 --- a/crypto/salsa20_generic.c +++ b/crypto/salsa20_generic.c @@ -221,7 +221,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct salsa20_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .blkcipher = { .setkey = setkey, diff --git a/crypto/seed.c b/crypto/seed.c index d3e422f60556..9c904d6d2151 100644 --- a/crypto/seed.c +++ b/crypto/seed.c @@ -449,7 +449,6 @@ static struct crypto_alg seed_alg = { .cra_ctxsize = sizeof(struct seed_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(seed_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = SEED_KEY_SIZE, diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c index 8f32cf35e5ce..7ddbd7e88859 100644 --- a/crypto/serpent_generic.c +++ b/crypto/serpent_generic.c @@ -567,24 +567,6 @@ static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) __serpent_decrypt(ctx, dst, src); } -static struct crypto_alg serpent_alg = { - .cra_name = "serpent", - .cra_driver_name = "serpent-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_alg.cra_list), - .cra_u = { .cipher = { - .cia_min_keysize = SERPENT_MIN_KEY_SIZE, - .cia_max_keysize = SERPENT_MAX_KEY_SIZE, - .cia_setkey = serpent_setkey, - .cia_encrypt = serpent_encrypt, - .cia_decrypt = serpent_decrypt } } -}; - static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { @@ -637,41 +619,44 @@ static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) d[3] = swab32(rd[0]); } -static struct crypto_alg tnepres_alg = { +static struct crypto_alg srp_algs[2] = { { + .cra_name = "serpent", + .cra_driver_name = "serpent-generic", + .cra_priority = 100, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_u = { .cipher = { + .cia_min_keysize = SERPENT_MIN_KEY_SIZE, + .cia_max_keysize = SERPENT_MAX_KEY_SIZE, + .cia_setkey = serpent_setkey, + .cia_encrypt = serpent_encrypt, + .cia_decrypt = serpent_decrypt } } +}, { .cra_name = "tnepres", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = SERPENT_BLOCK_SIZE, .cra_ctxsize = sizeof(struct serpent_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = SERPENT_MIN_KEY_SIZE, .cia_max_keysize = SERPENT_MAX_KEY_SIZE, .cia_setkey = tnepres_setkey, .cia_encrypt = tnepres_encrypt, .cia_decrypt = tnepres_decrypt } } -}; +} }; static int __init serpent_mod_init(void) { - int ret = crypto_register_alg(&serpent_alg); - - if (ret) - return ret; - - ret = crypto_register_alg(&tnepres_alg); - - if (ret) - crypto_unregister_alg(&serpent_alg); - - return ret; + return crypto_register_algs(srp_algs, ARRAY_SIZE(srp_algs)); } static void __exit serpent_mod_fini(void) { - crypto_unregister_alg(&tnepres_alg); - crypto_unregister_alg(&serpent_alg); + crypto_unregister_algs(srp_algs, ARRAY_SIZE(srp_algs)); } module_init(serpent_mod_init); diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index c48459ebf05b..c3ed4ec924e1 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -336,7 +336,7 @@ static int sha256_import(struct shash_desc *desc, const void *in) return 0; } -static struct shash_alg sha256 = { +static struct shash_alg sha256_algs[2] = { { .digestsize = SHA256_DIGEST_SIZE, .init = sha256_init, .update = sha256_update, @@ -352,9 +352,7 @@ static struct shash_alg sha256 = { .cra_blocksize = SHA256_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg sha224 = { +}, { .digestsize = SHA224_DIGEST_SIZE, .init = sha224_init, .update = sha256_update, @@ -367,29 +365,16 @@ static struct shash_alg sha224 = { .cra_blocksize = SHA224_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init sha256_generic_mod_init(void) { - int ret = 0; - - ret = crypto_register_shash(&sha224); - - if (ret < 0) - return ret; - - ret = crypto_register_shash(&sha256); - - if (ret < 0) - crypto_unregister_shash(&sha224); - - return ret; + return crypto_register_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); } static void __exit sha256_generic_mod_fini(void) { - crypto_unregister_shash(&sha224); - crypto_unregister_shash(&sha256); + crypto_unregister_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); } module_init(sha256_generic_mod_init); diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index dd30f40af9f5..71fcf361102d 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -242,7 +242,7 @@ static int sha384_final(struct shash_desc *desc, u8 *hash) return 0; } -static struct shash_alg sha512 = { +static struct shash_alg sha512_algs[2] = { { .digestsize = SHA512_DIGEST_SIZE, .init = sha512_init, .update = sha512_update, @@ -254,9 +254,7 @@ static struct shash_alg sha512 = { .cra_blocksize = SHA512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg sha384 = { +}, { .digestsize = SHA384_DIGEST_SIZE, .init = sha384_init, .update = sha512_update, @@ -268,24 +266,16 @@ static struct shash_alg sha384 = { .cra_blocksize = SHA384_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init sha512_generic_mod_init(void) { - int ret = 0; - - if ((ret = crypto_register_shash(&sha384)) < 0) - goto out; - if ((ret = crypto_register_shash(&sha512)) < 0) - crypto_unregister_shash(&sha384); -out: - return ret; + return crypto_register_shashes(sha512_algs, ARRAY_SIZE(sha512_algs)); } static void __exit sha512_generic_mod_fini(void) { - crypto_unregister_shash(&sha384); - crypto_unregister_shash(&sha512); + crypto_unregister_shashes(sha512_algs, ARRAY_SIZE(sha512_algs)); } module_init(sha512_generic_mod_init); diff --git a/crypto/shash.c b/crypto/shash.c index 32067f47e6c7..f426330f1017 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -629,6 +629,42 @@ int crypto_unregister_shash(struct shash_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_shash); +int crypto_register_shashes(struct shash_alg *algs, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = crypto_register_shash(&algs[i]); + if (ret) + goto err; + } + + return 0; + +err: + for (--i; i >= 0; --i) + crypto_unregister_shash(&algs[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(crypto_register_shashes); + +int crypto_unregister_shashes(struct shash_alg *algs, int count) +{ + int i, ret; + + for (i = count - 1; i >= 0; --i) { + ret = crypto_unregister_shash(&algs[i]); + if (ret) + pr_err("Failed to unregister %s %s: %d\n", + algs[i].base.cra_driver_name, + algs[i].base.cra_name, ret); + } + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_unregister_shashes); + int shash_register_instance(struct crypto_template *tmpl, struct shash_instance *inst) { diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 5cf2ccb1540c..e87fa60f5831 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -97,7 +97,6 @@ static int test_cipher_cycles(struct blkcipher_desc *desc, int enc, int ret = 0; int i; - local_bh_disable(); local_irq_disable(); /* Warm-up run. */ @@ -130,7 +129,6 @@ static int test_cipher_cycles(struct blkcipher_desc *desc, int enc, out: local_irq_enable(); - local_bh_enable(); if (ret == 0) printk("1 operation in %lu cycles (%d bytes)\n", @@ -300,7 +298,6 @@ static int test_hash_cycles_digest(struct hash_desc *desc, int i; int ret; - local_bh_disable(); local_irq_disable(); /* Warm-up run. */ @@ -327,7 +324,6 @@ static int test_hash_cycles_digest(struct hash_desc *desc, out: local_irq_enable(); - local_bh_enable(); if (ret) return ret; @@ -348,7 +344,6 @@ static int test_hash_cycles(struct hash_desc *desc, struct scatterlist *sg, if (plen == blen) return test_hash_cycles_digest(desc, sg, blen, out); - local_bh_disable(); local_irq_disable(); /* Warm-up run. */ @@ -391,7 +386,6 @@ static int test_hash_cycles(struct hash_desc *desc, struct scatterlist *sg, out: local_irq_enable(); - local_bh_enable(); if (ret) return ret; @@ -1037,10 +1031,16 @@ static int do_test(int m) case 14: ret += tcrypt_test("ecb(cast5)"); + ret += tcrypt_test("cbc(cast5)"); + ret += tcrypt_test("ctr(cast5)"); break; case 15: ret += tcrypt_test("ecb(cast6)"); + ret += tcrypt_test("cbc(cast6)"); + ret += tcrypt_test("ctr(cast6)"); + ret += tcrypt_test("lrw(cast6)"); + ret += tcrypt_test("xts(cast6)"); break; case 16: @@ -1112,6 +1112,9 @@ static int do_test(int m) case 32: ret += tcrypt_test("ecb(camellia)"); ret += tcrypt_test("cbc(camellia)"); + ret += tcrypt_test("ctr(camellia)"); + ret += tcrypt_test("lrw(camellia)"); + ret += tcrypt_test("xts(camellia)"); break; case 33: ret += tcrypt_test("sha224"); @@ -1165,6 +1168,10 @@ static int do_test(int m) ret += tcrypt_test("rfc4309(ccm(aes))"); break; + case 46: + ret += tcrypt_test("ghash"); + break; + case 100: ret += tcrypt_test("hmac(md5)"); break; @@ -1359,6 +1366,44 @@ static int do_test(int m) speed_template_8); break; + case 209: + test_cipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_cipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + break; + + case 210: + test_cipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_cipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_48); + test_cipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_48); + test_cipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_64); + test_cipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_64); + break; + case 300: /* fall through */ @@ -1639,6 +1684,44 @@ static int do_test(int m) speed_template_8); break; + case 506: + test_acipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0, + speed_template_8_16); + test_acipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0, + speed_template_8_16); + break; + + case 507: + test_acipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0, + speed_template_16_32); + test_acipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_48); + test_acipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_48); + test_acipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0, + speed_template_32_64); + test_acipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0, + speed_template_32_64); + break; + case 1000: test_available(); break; diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h index 5be1fc8c1ab3..cd2068524f3f 100644 --- a/crypto/tcrypt.h +++ b/crypto/tcrypt.h @@ -47,6 +47,7 @@ static struct cipher_speed_template des3_speed_template[] = { */ static u8 speed_template_8[] = {8, 0}; static u8 speed_template_24[] = {24, 0}; +static u8 speed_template_8_16[] = {8, 16, 0}; static u8 speed_template_8_32[] = {8, 32, 0}; static u8 speed_template_16_32[] = {16, 32, 0}; static u8 speed_template_16_24_32[] = {16, 24, 32, 0}; diff --git a/crypto/tea.c b/crypto/tea.c index 412bc74f8179..0a572323ee4a 100644 --- a/crypto/tea.c +++ b/crypto/tea.c @@ -219,84 +219,55 @@ static void xeta_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) out[1] = cpu_to_le32(z); } -static struct crypto_alg tea_alg = { +static struct crypto_alg tea_algs[3] = { { .cra_name = "tea", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = TEA_BLOCK_SIZE, .cra_ctxsize = sizeof (struct tea_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tea_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = TEA_KEY_SIZE, .cia_max_keysize = TEA_KEY_SIZE, .cia_setkey = tea_setkey, .cia_encrypt = tea_encrypt, .cia_decrypt = tea_decrypt } } -}; - -static struct crypto_alg xtea_alg = { +}, { .cra_name = "xtea", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = XTEA_BLOCK_SIZE, .cra_ctxsize = sizeof (struct xtea_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = XTEA_KEY_SIZE, .cia_max_keysize = XTEA_KEY_SIZE, .cia_setkey = xtea_setkey, .cia_encrypt = xtea_encrypt, .cia_decrypt = xtea_decrypt } } -}; - -static struct crypto_alg xeta_alg = { +}, { .cra_name = "xeta", .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = XTEA_BLOCK_SIZE, .cra_ctxsize = sizeof (struct xtea_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = XTEA_KEY_SIZE, .cia_max_keysize = XTEA_KEY_SIZE, .cia_setkey = xtea_setkey, .cia_encrypt = xeta_encrypt, .cia_decrypt = xeta_decrypt } } -}; +} }; static int __init tea_mod_init(void) { - int ret = 0; - - ret = crypto_register_alg(&tea_alg); - if (ret < 0) - goto out; - - ret = crypto_register_alg(&xtea_alg); - if (ret < 0) { - crypto_unregister_alg(&tea_alg); - goto out; - } - - ret = crypto_register_alg(&xeta_alg); - if (ret < 0) { - crypto_unregister_alg(&tea_alg); - crypto_unregister_alg(&xtea_alg); - goto out; - } - -out: - return ret; + return crypto_register_algs(tea_algs, ARRAY_SIZE(tea_algs)); } static void __exit tea_mod_fini(void) { - crypto_unregister_alg(&tea_alg); - crypto_unregister_alg(&xtea_alg); - crypto_unregister_alg(&xeta_alg); + crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs)); } MODULE_ALIAS("xtea"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index a2ca7431760a..941d75cd1f7c 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -358,8 +358,9 @@ out_nobuf: return ret; } -static int test_aead(struct crypto_aead *tfm, int enc, - struct aead_testvec *template, unsigned int tcount) +static int __test_aead(struct crypto_aead *tfm, int enc, + struct aead_testvec *template, unsigned int tcount, + const bool diff_dst) { const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); unsigned int i, j, k, n, temp; @@ -367,15 +368,18 @@ static int test_aead(struct crypto_aead *tfm, int enc, char *q; char *key; struct aead_request *req; - struct scatterlist sg[8]; - struct scatterlist asg[8]; - const char *e; + struct scatterlist *sg; + struct scatterlist *asg; + struct scatterlist *sgout; + const char *e, *d; struct tcrypt_result result; unsigned int authsize; void *input; + void *output; void *assoc; char iv[MAX_IVLEN]; char *xbuf[XBUFSIZE]; + char *xoutbuf[XBUFSIZE]; char *axbuf[XBUFSIZE]; if (testmgr_alloc_buf(xbuf)) @@ -383,6 +387,21 @@ static int test_aead(struct crypto_aead *tfm, int enc, if (testmgr_alloc_buf(axbuf)) goto out_noaxbuf; + if (diff_dst && testmgr_alloc_buf(xoutbuf)) + goto out_nooutbuf; + + /* avoid "the frame size is larger than 1024 bytes" compiler warning */ + sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL); + if (!sg) + goto out_nosg; + asg = &sg[8]; + sgout = &asg[8]; + + if (diff_dst) + d = "-ddst"; + else + d = ""; + if (enc == ENCRYPT) e = "encryption"; else @@ -392,8 +411,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, req = aead_request_alloc(tfm, GFP_KERNEL); if (!req) { - printk(KERN_ERR "alg: aead: Failed to allocate request for " - "%s\n", algo); + pr_err("alg: aead%s: Failed to allocate request for %s\n", + d, algo); goto out; } @@ -432,9 +451,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, ret = crypto_aead_setkey(tfm, key, template[i].klen); if (!ret == template[i].fail) { - printk(KERN_ERR "alg: aead: setkey failed on " - "test %d for %s: flags=%x\n", j, algo, - crypto_aead_get_flags(tfm)); + pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n", + d, j, algo, crypto_aead_get_flags(tfm)); goto out; } else if (ret) continue; @@ -442,18 +460,26 @@ static int test_aead(struct crypto_aead *tfm, int enc, authsize = abs(template[i].rlen - template[i].ilen); ret = crypto_aead_setauthsize(tfm, authsize); if (ret) { - printk(KERN_ERR "alg: aead: Failed to set " - "authsize to %u on test %d for %s\n", - authsize, j, algo); + pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n", + d, authsize, j, algo); goto out; } sg_init_one(&sg[0], input, template[i].ilen + (enc ? authsize : 0)); + if (diff_dst) { + output = xoutbuf[0]; + sg_init_one(&sgout[0], output, + template[i].ilen + + (enc ? authsize : 0)); + } else { + output = input; + } + sg_init_one(&asg[0], assoc, template[i].alen); - aead_request_set_crypt(req, sg, sg, + aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, template[i].ilen, iv); aead_request_set_assoc(req, asg, template[i].alen); @@ -466,10 +492,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, case 0: if (template[i].novrfy) { /* verification was supposed to fail */ - printk(KERN_ERR "alg: aead: %s failed " - "on test %d for %s: ret was 0, " - "expected -EBADMSG\n", - e, j, algo); + pr_err("alg: aead%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n", + d, e, j, algo); /* so really, we got a bad message */ ret = -EBADMSG; goto out; @@ -489,15 +513,15 @@ static int test_aead(struct crypto_aead *tfm, int enc, continue; /* fall through */ default: - printk(KERN_ERR "alg: aead: %s failed on test " - "%d for %s: ret=%d\n", e, j, algo, -ret); + pr_err("alg: aead%s: %s failed on test %d for %s: ret=%d\n", + d, e, j, algo, -ret); goto out; } - q = input; + q = output; if (memcmp(q, template[i].result, template[i].rlen)) { - printk(KERN_ERR "alg: aead: Test %d failed on " - "%s for %s\n", j, e, algo); + pr_err("alg: aead%s: Test %d failed on %s for %s\n", + d, j, e, algo); hexdump(q, template[i].rlen); ret = -EINVAL; goto out; @@ -522,9 +546,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, ret = crypto_aead_setkey(tfm, key, template[i].klen); if (!ret == template[i].fail) { - printk(KERN_ERR "alg: aead: setkey failed on " - "chunk test %d for %s: flags=%x\n", j, - algo, crypto_aead_get_flags(tfm)); + pr_err("alg: aead%s: setkey failed on chunk test %d for %s: flags=%x\n", + d, j, algo, crypto_aead_get_flags(tfm)); goto out; } else if (ret) continue; @@ -533,6 +556,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, ret = -EINVAL; sg_init_table(sg, template[i].np); + if (diff_dst) + sg_init_table(sgout, template[i].np); for (k = 0, temp = 0; k < template[i].np; k++) { if (WARN_ON(offset_in_page(IDX[k]) + template[i].tap[k] > PAGE_SIZE)) @@ -551,14 +576,26 @@ static int test_aead(struct crypto_aead *tfm, int enc, q[n] = 0; sg_set_buf(&sg[k], q, template[i].tap[k]); + + if (diff_dst) { + q = xoutbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]); + + memset(q, 0, template[i].tap[k]); + if (offset_in_page(q) + n < PAGE_SIZE) + q[n] = 0; + + sg_set_buf(&sgout[k], q, + template[i].tap[k]); + } + temp += template[i].tap[k]; } ret = crypto_aead_setauthsize(tfm, authsize); if (ret) { - printk(KERN_ERR "alg: aead: Failed to set " - "authsize to %u on chunk test %d for " - "%s\n", authsize, j, algo); + pr_err("alg: aead%s: Failed to set authsize to %u on chunk test %d for %s\n", + d, authsize, j, algo); goto out; } @@ -571,6 +608,9 @@ static int test_aead(struct crypto_aead *tfm, int enc, } sg[k - 1].length += authsize; + + if (diff_dst) + sgout[k - 1].length += authsize; } sg_init_table(asg, template[i].anp); @@ -588,7 +628,7 @@ static int test_aead(struct crypto_aead *tfm, int enc, temp += template[i].atap[k]; } - aead_request_set_crypt(req, sg, sg, + aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, template[i].ilen, iv); @@ -602,10 +642,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, case 0: if (template[i].novrfy) { /* verification was supposed to fail */ - printk(KERN_ERR "alg: aead: %s failed " - "on chunk test %d for %s: ret " - "was 0, expected -EBADMSG\n", - e, j, algo); + pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret was 0, expected -EBADMSG\n", + d, e, j, algo); /* so really, we got a bad message */ ret = -EBADMSG; goto out; @@ -625,32 +663,35 @@ static int test_aead(struct crypto_aead *tfm, int enc, continue; /* fall through */ default: - printk(KERN_ERR "alg: aead: %s failed on " - "chunk test %d for %s: ret=%d\n", e, j, - algo, -ret); + pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret=%d\n", + d, e, j, algo, -ret); goto out; } ret = -EINVAL; for (k = 0, temp = 0; k < template[i].np; k++) { - q = xbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); + if (diff_dst) + q = xoutbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]); + else + q = xbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]); n = template[i].tap[k]; if (k == template[i].np - 1) n += enc ? authsize : -authsize; if (memcmp(q, template[i].result + temp, n)) { - printk(KERN_ERR "alg: aead: Chunk " - "test %d failed on %s at page " - "%u for %s\n", j, e, k, algo); + pr_err("alg: aead%s: Chunk test %d failed on %s at page %u for %s\n", + d, j, e, k, algo); hexdump(q, n); goto out; } q += n; if (k == template[i].np - 1 && !enc) { - if (memcmp(q, template[i].input + + if (!diff_dst && + memcmp(q, template[i].input + temp + n, authsize)) n = authsize; else @@ -661,11 +702,8 @@ static int test_aead(struct crypto_aead *tfm, int enc, ; } if (n) { - printk(KERN_ERR "alg: aead: Result " - "buffer corruption in chunk " - "test %d on %s at page %u for " - "%s: %u bytes:\n", j, e, k, - algo, n); + pr_err("alg: aead%s: Result buffer corruption in chunk test %d on %s at page %u for %s: %u bytes:\n", + d, j, e, k, algo, n); hexdump(q, n); goto out; } @@ -679,6 +717,11 @@ static int test_aead(struct crypto_aead *tfm, int enc, out: aead_request_free(req); + kfree(sg); +out_nosg: + if (diff_dst) + testmgr_free_buf(xoutbuf); +out_nooutbuf: testmgr_free_buf(axbuf); out_noaxbuf: testmgr_free_buf(xbuf); @@ -686,6 +729,20 @@ out_noxbuf: return ret; } +static int test_aead(struct crypto_aead *tfm, int enc, + struct aead_testvec *template, unsigned int tcount) +{ + int ret; + + /* test 'dst == src' case */ + ret = __test_aead(tfm, enc, template, tcount, false); + if (ret) + return ret; + + /* test 'dst != src' case */ + return __test_aead(tfm, enc, template, tcount, true); +} + static int test_cipher(struct crypto_cipher *tfm, int enc, struct cipher_testvec *template, unsigned int tcount) { @@ -761,8 +818,9 @@ out_nobuf: return ret; } -static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, - struct cipher_testvec *template, unsigned int tcount) +static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc, + struct cipher_testvec *template, unsigned int tcount, + const bool diff_dst) { const char *algo = crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm)); @@ -770,16 +828,26 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, char *q; struct ablkcipher_request *req; struct scatterlist sg[8]; - const char *e; + struct scatterlist sgout[8]; + const char *e, *d; struct tcrypt_result result; void *data; char iv[MAX_IVLEN]; char *xbuf[XBUFSIZE]; + char *xoutbuf[XBUFSIZE]; int ret = -ENOMEM; if (testmgr_alloc_buf(xbuf)) goto out_nobuf; + if (diff_dst && testmgr_alloc_buf(xoutbuf)) + goto out_nooutbuf; + + if (diff_dst) + d = "-ddst"; + else + d = ""; + if (enc == ENCRYPT) e = "encryption"; else @@ -789,8 +857,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, req = ablkcipher_request_alloc(tfm, GFP_KERNEL); if (!req) { - printk(KERN_ERR "alg: skcipher: Failed to allocate request " - "for %s\n", algo); + pr_err("alg: skcipher%s: Failed to allocate request for %s\n", + d, algo); goto out; } @@ -804,7 +872,7 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, else memset(iv, 0, MAX_IVLEN); - if (!(template[i].np)) { + if (!(template[i].np) || (template[i].also_non_np)) { j++; ret = -EINVAL; @@ -822,16 +890,21 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, ret = crypto_ablkcipher_setkey(tfm, template[i].key, template[i].klen); if (!ret == template[i].fail) { - printk(KERN_ERR "alg: skcipher: setkey failed " - "on test %d for %s: flags=%x\n", j, - algo, crypto_ablkcipher_get_flags(tfm)); + pr_err("alg: skcipher%s: setkey failed on test %d for %s: flags=%x\n", + d, j, algo, + crypto_ablkcipher_get_flags(tfm)); goto out; } else if (ret) continue; sg_init_one(&sg[0], data, template[i].ilen); + if (diff_dst) { + data = xoutbuf[0]; + sg_init_one(&sgout[0], data, template[i].ilen); + } - ablkcipher_request_set_crypt(req, sg, sg, + ablkcipher_request_set_crypt(req, sg, + (diff_dst) ? sgout : sg, template[i].ilen, iv); ret = enc ? crypto_ablkcipher_encrypt(req) : @@ -850,16 +923,15 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, } /* fall through */ default: - printk(KERN_ERR "alg: skcipher: %s failed on " - "test %d for %s: ret=%d\n", e, j, algo, - -ret); + pr_err("alg: skcipher%s: %s failed on test %d for %s: ret=%d\n", + d, e, j, algo, -ret); goto out; } q = data; if (memcmp(q, template[i].result, template[i].rlen)) { - printk(KERN_ERR "alg: skcipher: Test %d " - "failed on %s for %s\n", j, e, algo); + pr_err("alg: skcipher%s: Test %d failed on %s for %s\n", + d, j, e, algo); hexdump(q, template[i].rlen); ret = -EINVAL; goto out; @@ -886,9 +958,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, ret = crypto_ablkcipher_setkey(tfm, template[i].key, template[i].klen); if (!ret == template[i].fail) { - printk(KERN_ERR "alg: skcipher: setkey failed " - "on chunk test %d for %s: flags=%x\n", - j, algo, + pr_err("alg: skcipher%s: setkey failed on chunk test %d for %s: flags=%x\n", + d, j, algo, crypto_ablkcipher_get_flags(tfm)); goto out; } else if (ret) @@ -897,6 +968,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, temp = 0; ret = -EINVAL; sg_init_table(sg, template[i].np); + if (diff_dst) + sg_init_table(sgout, template[i].np); for (k = 0; k < template[i].np; k++) { if (WARN_ON(offset_in_page(IDX[k]) + template[i].tap[k] > PAGE_SIZE)) @@ -913,11 +986,24 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, q[template[i].tap[k]] = 0; sg_set_buf(&sg[k], q, template[i].tap[k]); + if (diff_dst) { + q = xoutbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]); + + sg_set_buf(&sgout[k], q, + template[i].tap[k]); + + memset(q, 0, template[i].tap[k]); + if (offset_in_page(q) + + template[i].tap[k] < PAGE_SIZE) + q[template[i].tap[k]] = 0; + } temp += template[i].tap[k]; } - ablkcipher_request_set_crypt(req, sg, sg, + ablkcipher_request_set_crypt(req, sg, + (diff_dst) ? sgout : sg, template[i].ilen, iv); ret = enc ? @@ -937,23 +1023,25 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, } /* fall through */ default: - printk(KERN_ERR "alg: skcipher: %s failed on " - "chunk test %d for %s: ret=%d\n", e, j, - algo, -ret); + pr_err("alg: skcipher%s: %s failed on chunk test %d for %s: ret=%d\n", + d, e, j, algo, -ret); goto out; } temp = 0; ret = -EINVAL; for (k = 0; k < template[i].np; k++) { - q = xbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); + if (diff_dst) + q = xoutbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]); + else + q = xbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]); if (memcmp(q, template[i].result + temp, template[i].tap[k])) { - printk(KERN_ERR "alg: skcipher: Chunk " - "test %d failed on %s at page " - "%u for %s\n", j, e, k, algo); + pr_err("alg: skcipher%s: Chunk test %d failed on %s at page %u for %s\n", + d, j, e, k, algo); hexdump(q, template[i].tap[k]); goto out; } @@ -962,11 +1050,8 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, for (n = 0; offset_in_page(q + n) && q[n]; n++) ; if (n) { - printk(KERN_ERR "alg: skcipher: " - "Result buffer corruption in " - "chunk test %d on %s at page " - "%u for %s: %u bytes:\n", j, e, - k, algo, n); + pr_err("alg: skcipher%s: Result buffer corruption in chunk test %d on %s at page %u for %s: %u bytes:\n", + d, j, e, k, algo, n); hexdump(q, n); goto out; } @@ -979,11 +1064,28 @@ static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, out: ablkcipher_request_free(req); + if (diff_dst) + testmgr_free_buf(xoutbuf); +out_nooutbuf: testmgr_free_buf(xbuf); out_nobuf: return ret; } +static int test_skcipher(struct crypto_ablkcipher *tfm, int enc, + struct cipher_testvec *template, unsigned int tcount) +{ + int ret; + + /* test 'dst == src' case */ + ret = __test_skcipher(tfm, enc, template, tcount, false); + if (ret) + return ret; + + /* test 'dst != src' case */ + return __test_skcipher(tfm, enc, template, tcount, true); +} + static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, struct comp_testvec *dtemplate, int ctcount, int dtcount) { @@ -1534,6 +1636,36 @@ static int alg_test_null(const struct alg_test_desc *desc, /* Please keep this list sorted by algorithm name. */ static const struct alg_test_desc alg_test_descs[] = { { + .alg = "__cbc-cast5-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "__cbc-cast6-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { .alg = "__cbc-serpent-avx", .test = alg_test_null, .suite = { @@ -1595,6 +1727,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "__driver-cbc-cast5-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "__driver-cbc-cast6-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { .alg = "__driver-cbc-serpent-avx", .test = alg_test_null, .suite = { @@ -1656,6 +1818,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "__driver-ecb-cast5-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "__driver-ecb-cast6-avx", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { .alg = "__driver-ecb-serpent-avx", .test = alg_test_null, .suite = { @@ -1818,6 +2010,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "cbc(cast5)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast5_cbc_enc_tv_template, + .count = CAST5_CBC_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast5_cbc_dec_tv_template, + .count = CAST5_CBC_DEC_TEST_VECTORS + } + } + } + }, { + .alg = "cbc(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_cbc_enc_tv_template, + .count = CAST6_CBC_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_cbc_dec_tv_template, + .count = CAST6_CBC_DEC_TEST_VECTORS + } + } + } + }, { .alg = "cbc(des)", .test = alg_test_skcipher, .suite = { @@ -1937,6 +2159,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "cryptd(__driver-ecb-cast5-avx)", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { + .alg = "cryptd(__driver-ecb-cast6-avx)", + .test = alg_test_null, + .suite = { + .cipher = { + .enc = { + .vecs = NULL, + .count = 0 + }, + .dec = { + .vecs = NULL, + .count = 0 + } + } + } + }, { .alg = "cryptd(__driver-ecb-serpent-avx)", .test = alg_test_null, .suite = { @@ -2054,6 +2306,36 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "ctr(cast5)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast5_ctr_enc_tv_template, + .count = CAST5_CTR_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast5_ctr_dec_tv_template, + .count = CAST5_CTR_DEC_TEST_VECTORS + } + } + } + }, { + .alg = "ctr(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_ctr_enc_tv_template, + .count = CAST6_CTR_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_ctr_dec_tv_template, + .count = CAST6_CTR_DEC_TEST_VECTORS + } + } + } + }, { .alg = "ctr(serpent)", .test = alg_test_skcipher, .suite = { @@ -2530,6 +2812,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "lrw(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_lrw_enc_tv_template, + .count = CAST6_LRW_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_lrw_dec_tv_template, + .count = CAST6_LRW_DEC_TEST_VECTORS + } + } + } + }, { .alg = "lrw(serpent)", .test = alg_test_skcipher, .suite = { @@ -2882,6 +3179,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "xts(cast6)", + .test = alg_test_skcipher, + .suite = { + .cipher = { + .enc = { + .vecs = cast6_xts_enc_tv_template, + .count = CAST6_XTS_ENC_TEST_VECTORS + }, + .dec = { + .vecs = cast6_xts_dec_tv_template, + .count = CAST6_XTS_DEC_TEST_VECTORS + } + } + } + }, { .alg = "xts(serpent)", .test = alg_test_skcipher, .suite = { diff --git a/crypto/testmgr.h b/crypto/testmgr.h index f8179e0344ed..76d7f6cc82f5 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -53,6 +53,7 @@ struct cipher_testvec { char *result; unsigned short tap[MAX_TAP]; int np; + unsigned char also_non_np; unsigned char fail; unsigned char wk; /* weak key flag */ unsigned char klen; @@ -2468,6 +2469,9 @@ static struct cipher_testvec bf_enc_tv_template[] = { "\xC2\xF4\x6D\xFF\xF6\xCD\x6B\x40" "\xE1\xB3\xBF\xD4\x38\x2B\xC8\x3B", .rlen = 40, + .also_non_np = 1, + .np = 2, + .tap = { 40 - 8, 8 }, }, }; @@ -2541,6 +2545,9 @@ static struct cipher_testvec bf_dec_tv_template[] = { "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" "\x1E\x92\x29\xC0\x34\xCB\x62\xF9", .rlen = 40, + .also_non_np = 1, + .np = 2, + .tap = { 40 - 8, 8 }, }, }; @@ -2579,6 +2586,9 @@ static struct cipher_testvec bf_cbc_enc_tv_template[] = { "\x1B\xD9\x02\xB6\x48\xB0\x87\x25" "\x01\x9C\x93\x63\x51\x60\x82\xD2", .rlen = 40, + .also_non_np = 1, + .np = 2, + .tap = { 40 - 8, 8 }, }, }; @@ -2617,6 +2627,9 @@ static struct cipher_testvec bf_cbc_dec_tv_template[] = { "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" "\x1E\x92\x29\xC0\x34\xCB\x62\xF9", .rlen = 40, + .also_non_np = 1, + .np = 2, + .tap = { 40 - 8, 8 }, }, }; @@ -2661,6 +2674,144 @@ static struct cipher_testvec bf_ctr_enc_tv_template[] = { "\xE4\x1F\x5E\xA5\x89\xAC\x32\xBC" "\x3D\xA7\xE9", .rlen = 43, + .also_non_np = 1, + .np = 2, + .tap = { 43 - 8, 8 }, + }, { /* 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 = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7" + "\x2B\xC2\x59\xF0\x64\xFB\x92\x06", + .ilen = 504, + .result = "\x5F\x58\x6E\x60\x51\x6E\xDC\x3D" + "\xD1\xBB\xF7\xB7\xFD\x04\x44\x82" + "\xDC\x9F\x4B\x02\xF1\xD2\x5A\x6F" + "\x25\xF9\x27\x21\xF2\xD2\x9A\x01" + "\xBD\xAD\x3D\x93\x87\xCA\x0D\xFE" + "\xB7\x2C\x17\x1F\x42\x8C\x13\xB2" + "\x62\x44\x72\xB9\x5D\xC0\xF8\x37" + "\xDF\xEA\x78\x81\x8F\xA6\x34\xB2" + "\x07\x09\x7C\xB9\x3A\xA0\x2B\x18" + "\x34\x6A\x9D\x3D\xA5\xEB\xF4\x60" + "\xF8\x98\xA2\x39\x81\x23\x6C\xA9" + "\x70\xCA\xCC\x45\xD8\x1F\xDF\x44" + "\x2A\x67\x7A\x88\x28\xDC\x36\x83" + "\x18\xD7\x48\x43\x17\x2B\x1B\xE6" + "\x0B\x82\x59\x14\x26\x67\x08\x09" + "\x5B\x5D\x38\xD0\x81\xCE\x54\x2A" + "\xCD\x22\x94\x42\xF5\xBA\x74\x7E" + "\xD9\x00\x40\xA9\x0D\x0B\xBD\x8E" + "\xC4\x8E\x5E\x17\x8F\x48\xE2\xB8" + "\xF4\xCC\x19\x76\xAB\x48\x29\xAA" + "\x81\xD5\xCE\xD5\x8A\x3B\xC9\x21" + "\xEF\x50\x4F\x04\x02\xBF\xE1\x1F" + "\x59\x28\x1A\xE4\x18\x16\xA0\x29" + "\xBF\x34\xA9\x2D\x28\x83\xC0\x5E" + "\xEA\x44\xC4\x6E\xAB\x24\x79\x9D" + "\x2D\xA1\xE8\x55\xCA\x74\xFC\xBD" + "\xFE\xDD\xDA\xA5\xFB\x34\x90\x31" + "\x0E\x62\x28\x9B\xDC\xD7\xA1\xBB" + "\xF0\x1A\xB3\xE2\xD0\xFA\xBD\xE8" + "\x5C\x5A\x10\x67\xF6\x6A\x17\x3F" + "\xC5\xE9\x09\x08\xDD\x22\x77\x42" + "\x26\x6A\x6A\x7A\x3F\x87\x80\x0C" + "\xF0\xFF\x15\x8E\x84\x86\xC0\x10" + "\x0F\x8D\x33\x06\xB8\x72\xA4\x47" + "\x6B\xED\x2E\x05\x94\x6C\x5C\x5B" + "\x13\xF6\x77\xEE\x3B\x16\xDF\xC2" + "\x63\x66\x07\x6D\x3F\x6C\x51\x7C" + "\x1C\xAC\x80\xB6\x58\x48\xB7\x9D" + "\xB4\x19\xD8\x19\x45\x66\x27\x02" + "\xA1\xA9\x99\xF3\x1F\xE5\xA7\x1D" + "\x31\xE7\x1B\x0D\xFF\xBB\xB5\xA1" + "\xF5\x9C\x45\x1E\x18\x19\xA1\xE7" + "\xC2\xF1\xBF\x68\xC3\xEC\xCF\x53" + "\x67\xA6\x2B\x7D\x3C\x6D\x24\xC3" + "\xE8\xE6\x07\x5A\x09\xE0\x32\xA8" + "\x52\xF6\xE9\xED\x0E\xC6\x0A\x6A" + "\xFC\x60\x2A\xE0\x93\xCE\xB8\x2E" + "\xA2\xA8\x0E\x79\x9E\x34\x5D\x37" + "\x6F\x12\xFE\x48\x7B\xE7\xB9\x22" + "\x29\xE8\xD7\xBE\x5D\xD1\x8B\xD9" + "\x91\x51\x4E\x71\xF2\x98\x85\x16" + "\x25\x7A\x76\x8A\x51\x0E\x65\x14" + "\x81\xB5\x3A\x37\xFD\xEC\xB5\x8A" + "\xE1\xCF\x41\x72\x14\x29\x4C\xF0" + "\x20\xD9\x9A\xC5\x66\xA4\x03\x76" + "\x5B\xA4\x15\x4F\x0E\x64\x39\x40" + "\x25\xF9\x20\x22\xF5\x88\xF5\xBA" + "\xE4\xDF\x45\x61\xBF\x8D\x7A\x24" + "\x4B\x92\x71\xD9\x2F\x77\xA7\x95" + "\xA8\x7F\x61\xD5\xA4\x57\xB0\xFB" + "\xB5\x77\xBA\x1C\xEE\x71\xFA\xB0" + "\x16\x4C\x18\x6B\xF2\x69\xA0\x07" + "\xEF\xBE\xEC\x69\xAC\xA8\x63\x9E", + .rlen = 504, }, }; @@ -2705,6 +2856,144 @@ static struct cipher_testvec bf_ctr_dec_tv_template[] = { "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" "\x6D\x04\x9B", .rlen = 43, + .also_non_np = 1, + .np = 2, + .tap = { 43 - 8, 8 }, + }, { /* 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 = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .input = "\x5F\x58\x6E\x60\x51\x6E\xDC\x3D" + "\xD1\xBB\xF7\xB7\xFD\x04\x44\x82" + "\xDC\x9F\x4B\x02\xF1\xD2\x5A\x6F" + "\x25\xF9\x27\x21\xF2\xD2\x9A\x01" + "\xBD\xAD\x3D\x93\x87\xCA\x0D\xFE" + "\xB7\x2C\x17\x1F\x42\x8C\x13\xB2" + "\x62\x44\x72\xB9\x5D\xC0\xF8\x37" + "\xDF\xEA\x78\x81\x8F\xA6\x34\xB2" + "\x07\x09\x7C\xB9\x3A\xA0\x2B\x18" + "\x34\x6A\x9D\x3D\xA5\xEB\xF4\x60" + "\xF8\x98\xA2\x39\x81\x23\x6C\xA9" + "\x70\xCA\xCC\x45\xD8\x1F\xDF\x44" + "\x2A\x67\x7A\x88\x28\xDC\x36\x83" + "\x18\xD7\x48\x43\x17\x2B\x1B\xE6" + "\x0B\x82\x59\x14\x26\x67\x08\x09" + "\x5B\x5D\x38\xD0\x81\xCE\x54\x2A" + "\xCD\x22\x94\x42\xF5\xBA\x74\x7E" + "\xD9\x00\x40\xA9\x0D\x0B\xBD\x8E" + "\xC4\x8E\x5E\x17\x8F\x48\xE2\xB8" + "\xF4\xCC\x19\x76\xAB\x48\x29\xAA" + "\x81\xD5\xCE\xD5\x8A\x3B\xC9\x21" + "\xEF\x50\x4F\x04\x02\xBF\xE1\x1F" + "\x59\x28\x1A\xE4\x18\x16\xA0\x29" + "\xBF\x34\xA9\x2D\x28\x83\xC0\x5E" + "\xEA\x44\xC4\x6E\xAB\x24\x79\x9D" + "\x2D\xA1\xE8\x55\xCA\x74\xFC\xBD" + "\xFE\xDD\xDA\xA5\xFB\x34\x90\x31" + "\x0E\x62\x28\x9B\xDC\xD7\xA1\xBB" + "\xF0\x1A\xB3\xE2\xD0\xFA\xBD\xE8" + "\x5C\x5A\x10\x67\xF6\x6A\x17\x3F" + "\xC5\xE9\x09\x08\xDD\x22\x77\x42" + "\x26\x6A\x6A\x7A\x3F\x87\x80\x0C" + "\xF0\xFF\x15\x8E\x84\x86\xC0\x10" + "\x0F\x8D\x33\x06\xB8\x72\xA4\x47" + "\x6B\xED\x2E\x05\x94\x6C\x5C\x5B" + "\x13\xF6\x77\xEE\x3B\x16\xDF\xC2" + "\x63\x66\x07\x6D\x3F\x6C\x51\x7C" + "\x1C\xAC\x80\xB6\x58\x48\xB7\x9D" + "\xB4\x19\xD8\x19\x45\x66\x27\x02" + "\xA1\xA9\x99\xF3\x1F\xE5\xA7\x1D" + "\x31\xE7\x1B\x0D\xFF\xBB\xB5\xA1" + "\xF5\x9C\x45\x1E\x18\x19\xA1\xE7" + "\xC2\xF1\xBF\x68\xC3\xEC\xCF\x53" + "\x67\xA6\x2B\x7D\x3C\x6D\x24\xC3" + "\xE8\xE6\x07\x5A\x09\xE0\x32\xA8" + "\x52\xF6\xE9\xED\x0E\xC6\x0A\x6A" + "\xFC\x60\x2A\xE0\x93\xCE\xB8\x2E" + "\xA2\xA8\x0E\x79\x9E\x34\x5D\x37" + "\x6F\x12\xFE\x48\x7B\xE7\xB9\x22" + "\x29\xE8\xD7\xBE\x5D\xD1\x8B\xD9" + "\x91\x51\x4E\x71\xF2\x98\x85\x16" + "\x25\x7A\x76\x8A\x51\x0E\x65\x14" + "\x81\xB5\x3A\x37\xFD\xEC\xB5\x8A" + "\xE1\xCF\x41\x72\x14\x29\x4C\xF0" + "\x20\xD9\x9A\xC5\x66\xA4\x03\x76" + "\x5B\xA4\x15\x4F\x0E\x64\x39\x40" + "\x25\xF9\x20\x22\xF5\x88\xF5\xBA" + "\xE4\xDF\x45\x61\xBF\x8D\x7A\x24" + "\x4B\x92\x71\xD9\x2F\x77\xA7\x95" + "\xA8\x7F\x61\xD5\xA4\x57\xB0\xFB" + "\xB5\x77\xBA\x1C\xEE\x71\xFA\xB0" + "\x16\x4C\x18\x6B\xF2\x69\xA0\x07" + "\xEF\xBE\xEC\x69\xAC\xA8\x63\x9E", + .ilen = 504, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7" + "\x2B\xC2\x59\xF0\x64\xFB\x92\x06", + .rlen = 504, }, }; @@ -2884,6 +3173,9 @@ static struct cipher_testvec tf_enc_tv_template[] = { "\x58\x33\x9B\x78\xC7\x58\x48\x6B" "\x2C\x75\x64\xC4\xCA\xC1\x7E\xD5", .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -3049,6 +3341,9 @@ static struct cipher_testvec tf_dec_tv_template[] = { "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -3229,6 +3524,9 @@ static struct cipher_testvec tf_cbc_enc_tv_template[] = { "\x30\x70\x56\xA4\x37\xDD\x7C\xC0" "\x0A\xA3\x30\x10\x26\x25\x41\x2C", .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -3409,6 +3707,9 @@ static struct cipher_testvec tf_cbc_dec_tv_template[] = { "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -3553,6 +3854,140 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = { "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" "\x78\xBE\x9B\x78\x55\x32\x0F\x55", .klen = 32, + .iv = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xEB\x44\xAF\x49\x27\xB8\xFB\x44" + "\x4C\xA6\xC3\x0C\x8B\xD0\x01\x0C" + "\x53\xC8\x16\x38\xDE\x40\x4F\x91" + "\x25\x6D\x4C\xA0\x9A\x87\x1E\xDA" + "\x88\x7E\x89\xE9\x67\x2B\x83\xA2" + "\x5F\x2E\x23\x3E\x45\xB9\x77\x7B" + "\xA6\x7E\x47\x36\x81\x9F\x9B\xF3" + "\xE0\xF0\xD7\x47\xA9\xC8\xEF\x33" + "\x0C\x43\xFE\x67\x50\x0A\x2C\x3E" + "\xA0\xE1\x25\x8E\x80\x07\x4A\xC0" + "\x64\x89\x9F\x6A\x27\x96\x07\xA6" + "\x9B\xC8\x1B\x21\x60\xAE\x5D\x01" + "\xE2\xCD\xC8\xAA\x6C\x9D\x1C\x34" + "\x39\x18\x09\xA4\x82\x59\x78\xE7" + "\xFC\x59\x65\xF2\x94\xFF\xFB\xE2" + "\x3C\xDA\xB1\x90\x95\xBF\x91\xE3" + "\xE6\x87\x31\x9E\x16\x85\xAD\xB1" + "\x4C\xAE\x43\x4D\x19\x58\xB5\x5E" + "\x2E\xF5\x09\xAA\x39\xF4\xC0\xB3" + "\xD4\x4D\xDB\x73\x7A\xD4\xF1\xBF" + "\x89\x16\x4D\x2D\xA2\x26\x33\x72" + "\x18\x33\x7E\xD6\xD2\x16\xA4\x54" + "\xF4\x8C\xB3\x52\xDF\x21\x9C\xEB" + "\xBF\x49\xD3\xF9\x05\x06\xCB\xD2" + "\xA9\xD2\x3B\x6E\x19\x8C\xBC\x19" + "\xAB\x89\xD6\xD8\xCD\x56\x89\x5E" + "\xAC\x00\xE3\x50\x63\x4A\x80\x9A" + "\x05\xBC\x50\x39\xD3\x32\xD9\x0D" + "\xE3\x20\x0D\x75\x54\xEC\xE6\x31" + "\x14\xB9\x3A\x59\x00\x43\x37\x8E" + "\x8C\x5A\x79\x62\x14\x76\x8A\xAE" + "\x8F\xCC\xA1\x6C\x38\x78\xDD\x2D" + "\x8B\x6D\xEA\xBD\x7B\x25\xFF\x60" + "\xC9\x87\xB1\x79\x1E\xA5\x86\x68" + "\x81\xB4\xE2\xC1\x05\x7D\x3A\x73" + "\xD0\xDA\x75\x77\x9E\x05\x27\xF1" + "\x08\xA9\x66\x64\x6C\xBC\x82\x17" + "\x2C\x23\x5F\x62\x4D\x02\x1A\x58" + "\xE7\xB7\x23\x6D\xE2\x20\xDA\xEF" + "\xB4\xB3\x3F\xB2\x2B\x69\x98\x83" + "\x95\x87\x13\x57\x60\xD7\xB5\xB1" + "\xEE\x0A\x2F\x95\x36\x4C\x76\x5D" + "\x5F\xD9\x19\xED\xB9\xA5\x48\xBF" + "\xC8\xAB\x0F\x71\xCC\x61\x8E\x0A" + "\xD0\x29\x44\xA8\xB9\xC1\xE8\xC8" + "\xC9\xA8\x28\x81\xFB\x50\xF2\xF0" + "\x26\xAE\x39\xB8\x91\xCD\xA8\xAC" + "\xDE\x55\x1B\x50\x14\x53\x44\x17" + "\x54\x46\xFC\xB1\xE4\x07\x6B\x9A" + "\x01\x14\xF0\x2E\x2E\xDB\x46\x1B" + "\x1A\x09\x97\xA9\xB6\x97\x79\x06" + "\xFB\xCB\x85\xCF\xDD\xA1\x41\xB1" + "\x00\xAA\xF7\xE0\x89\x73\xFB\xE5" + "\xBF\x84\xDB\xC9\xCD\xC4\xA2\x0D" + "\x3B\xAC\xF9\xDF\x96\xBF\x88\x23" + "\x41\x67\xA1\x24\x99\x7E\xCC\x9B" + "\x02\x8F\x6A\x49\xF6\x25\xBA\x7A" + "\xF4\x78\xFD\x79\x62\x63\x4F\x14" + "\xD6\x11\x11\x04\x05\x5F\x7E\xEA" + "\x4C\xB6\xF8\xF4\x5F\x48\x52\x54" + "\x94\x63\xA8\x4E\xCF\xD2\x1B\x1B" + "\x22\x18\x6A\xAF\x6E\x3E\xE1\x0D", + .rlen = 496, + }, { /* 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" @@ -3683,6 +4118,9 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = { "\xC5\xC9\x7F\x9E\xCF\x33\x7A\xDF" "\x6C\x82\x9D", .rlen = 499, + .also_non_np = 1, + .np = 2, + .tap = { 499 - 16, 16 }, }, }; @@ -3827,6 +4265,140 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = { "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" "\x78\xBE\x9B\x78\x55\x32\x0F\x55", .klen = 32, + .iv = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .input = "\xEB\x44\xAF\x49\x27\xB8\xFB\x44" + "\x4C\xA6\xC3\x0C\x8B\xD0\x01\x0C" + "\x53\xC8\x16\x38\xDE\x40\x4F\x91" + "\x25\x6D\x4C\xA0\x9A\x87\x1E\xDA" + "\x88\x7E\x89\xE9\x67\x2B\x83\xA2" + "\x5F\x2E\x23\x3E\x45\xB9\x77\x7B" + "\xA6\x7E\x47\x36\x81\x9F\x9B\xF3" + "\xE0\xF0\xD7\x47\xA9\xC8\xEF\x33" + "\x0C\x43\xFE\x67\x50\x0A\x2C\x3E" + "\xA0\xE1\x25\x8E\x80\x07\x4A\xC0" + "\x64\x89\x9F\x6A\x27\x96\x07\xA6" + "\x9B\xC8\x1B\x21\x60\xAE\x5D\x01" + "\xE2\xCD\xC8\xAA\x6C\x9D\x1C\x34" + "\x39\x18\x09\xA4\x82\x59\x78\xE7" + "\xFC\x59\x65\xF2\x94\xFF\xFB\xE2" + "\x3C\xDA\xB1\x90\x95\xBF\x91\xE3" + "\xE6\x87\x31\x9E\x16\x85\xAD\xB1" + "\x4C\xAE\x43\x4D\x19\x58\xB5\x5E" + "\x2E\xF5\x09\xAA\x39\xF4\xC0\xB3" + "\xD4\x4D\xDB\x73\x7A\xD4\xF1\xBF" + "\x89\x16\x4D\x2D\xA2\x26\x33\x72" + "\x18\x33\x7E\xD6\xD2\x16\xA4\x54" + "\xF4\x8C\xB3\x52\xDF\x21\x9C\xEB" + "\xBF\x49\xD3\xF9\x05\x06\xCB\xD2" + "\xA9\xD2\x3B\x6E\x19\x8C\xBC\x19" + "\xAB\x89\xD6\xD8\xCD\x56\x89\x5E" + "\xAC\x00\xE3\x50\x63\x4A\x80\x9A" + "\x05\xBC\x50\x39\xD3\x32\xD9\x0D" + "\xE3\x20\x0D\x75\x54\xEC\xE6\x31" + "\x14\xB9\x3A\x59\x00\x43\x37\x8E" + "\x8C\x5A\x79\x62\x14\x76\x8A\xAE" + "\x8F\xCC\xA1\x6C\x38\x78\xDD\x2D" + "\x8B\x6D\xEA\xBD\x7B\x25\xFF\x60" + "\xC9\x87\xB1\x79\x1E\xA5\x86\x68" + "\x81\xB4\xE2\xC1\x05\x7D\x3A\x73" + "\xD0\xDA\x75\x77\x9E\x05\x27\xF1" + "\x08\xA9\x66\x64\x6C\xBC\x82\x17" + "\x2C\x23\x5F\x62\x4D\x02\x1A\x58" + "\xE7\xB7\x23\x6D\xE2\x20\xDA\xEF" + "\xB4\xB3\x3F\xB2\x2B\x69\x98\x83" + "\x95\x87\x13\x57\x60\xD7\xB5\xB1" + "\xEE\x0A\x2F\x95\x36\x4C\x76\x5D" + "\x5F\xD9\x19\xED\xB9\xA5\x48\xBF" + "\xC8\xAB\x0F\x71\xCC\x61\x8E\x0A" + "\xD0\x29\x44\xA8\xB9\xC1\xE8\xC8" + "\xC9\xA8\x28\x81\xFB\x50\xF2\xF0" + "\x26\xAE\x39\xB8\x91\xCD\xA8\xAC" + "\xDE\x55\x1B\x50\x14\x53\x44\x17" + "\x54\x46\xFC\xB1\xE4\x07\x6B\x9A" + "\x01\x14\xF0\x2E\x2E\xDB\x46\x1B" + "\x1A\x09\x97\xA9\xB6\x97\x79\x06" + "\xFB\xCB\x85\xCF\xDD\xA1\x41\xB1" + "\x00\xAA\xF7\xE0\x89\x73\xFB\xE5" + "\xBF\x84\xDB\xC9\xCD\xC4\xA2\x0D" + "\x3B\xAC\xF9\xDF\x96\xBF\x88\x23" + "\x41\x67\xA1\x24\x99\x7E\xCC\x9B" + "\x02\x8F\x6A\x49\xF6\x25\xBA\x7A" + "\xF4\x78\xFD\x79\x62\x63\x4F\x14" + "\xD6\x11\x11\x04\x05\x5F\x7E\xEA" + "\x4C\xB6\xF8\xF4\x5F\x48\x52\x54" + "\x94\x63\xA8\x4E\xCF\xD2\x1B\x1B" + "\x22\x18\x6A\xAF\x6E\x3E\xE1\x0D", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + }, { /* 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 = "\xDF\xDD\x69\xFA\xB0\x2E\xFD\xFE" @@ -3957,6 +4529,9 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = { "\xDC\x50\xE7\x7E\x15\x89\x20\xB7" "\x2B\xC2\x59", .rlen = 499, + .also_non_np = 1, + .np = 2, + .tap = { 499 - 16, 16 }, }, }; @@ -4206,6 +4781,9 @@ static struct cipher_testvec tf_lrw_enc_tv_template[] = { "\x80\x18\xc4\x6c\x03\xd3\xb7\xba" "\x11\xd7\xb8\x6e\xea\xe1\x80\x30", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -4456,6 +5034,9 @@ static struct cipher_testvec tf_lrw_dec_tv_template[] = { "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" "\x21\xc4\xc2\x75\x67\x89\x37\x0a", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -4795,6 +5376,9 @@ static struct cipher_testvec tf_xts_enc_tv_template[] = { "\xa4\x05\x0b\xb2\xb3\xa8\x30\x97" "\x37\x30\xe1\x91\x8d\xb3\x2a\xff", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -5135,6 +5719,9 @@ static struct cipher_testvec tf_xts_dec_tv_template[] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -5242,6 +5829,9 @@ static struct cipher_testvec serpent_enc_tv_template[] = { "\x30\xD4\x2C\xF2\x8E\x06\x4B\x39" "\xB3\x12\x1D\xB3\x17\x46\xE6\xD6", .rlen = 144, + .also_non_np = 1, + .np = 2, + .tap = { 144 - 16, 16 }, }, }; @@ -5377,6 +5967,9 @@ static struct cipher_testvec serpent_dec_tv_template[] = { "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A", .rlen = 144, + .also_non_np = 1, + .np = 2, + .tap = { 144 - 16, 16 }, }, }; @@ -5468,6 +6061,9 @@ static struct cipher_testvec serpent_cbc_enc_tv_template[] = { "\x27\xDF\x89\x1D\x86\x3E\xF7\x5A" "\xF6\xE3\x0F\xC7\x6B\x4C\x96\x7C", .rlen = 144, + .also_non_np = 1, + .np = 2, + .tap = { 144 - 16, 16 }, }, }; @@ -5518,6 +6114,9 @@ static struct cipher_testvec serpent_cbc_dec_tv_template[] = { "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A", .rlen = 144, + .also_non_np = 1, + .np = 2, + .tap = { 144 - 16, 16 }, }, }; @@ -5616,6 +6215,143 @@ static struct cipher_testvec serpent_ctr_enc_tv_template[] = { "\x5D\xE1\x4F\xA1\xEA\xB3\xCA\xB9" "\xE6\xD0\x97", .rlen = 147, + .also_non_np = 1, + .np = 2, + .tap = { 147 - 16, 16 }, + }, { /* 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 = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x06\x9A\xF8\xB4\x53\x88\x62\xFC" + "\x68\xB8\x2E\xDF\xC1\x05\x0F\x3D" + "\xAF\x4D\x95\xAE\xC4\xE9\x1C\xDC" + "\xF6\x2B\x8F\x90\x89\xF6\x7E\x1A" + "\xA6\xB9\xE4\xF4\xFA\xCA\xE5\x7E" + "\x71\x28\x06\x4F\xE8\x08\x39\xDA" + "\xA5\x0E\xC8\xC0\xB8\x16\xE5\x69" + "\xE5\xCA\xEC\x4F\x63\x2C\xC0\x9B" + "\x9F\x3E\x39\x79\xF0\xCD\x64\x35" + "\x4A\xD3\xC8\xA9\x31\xCD\x48\x5B" + "\x92\x3D\x8F\x3F\x96\xBD\xB3\x18" + "\x74\x2A\x5D\x29\x3F\x57\x8F\xE2" + "\x67\x9A\xE0\xE5\xD4\x4A\xE2\x47" + "\xBC\xF6\xEB\x14\xF3\x8C\x20\xC2" + "\x7D\xE2\x43\x81\x86\x72\x2E\xB1" + "\x39\xF6\x95\xE1\x1F\xCB\x76\x33" + "\x5B\x7D\x23\x0F\x3A\x67\x2A\x2F" + "\xB9\x37\x9D\xDD\x1F\x16\xA1\x3C" + "\x70\xFE\x52\xAA\x93\x3C\xC4\x46" + "\xB1\xE5\xFF\xDA\xAF\xE2\x84\xFE" + "\x25\x92\xB2\x63\xBD\x49\x77\xB4" + "\x22\xA4\x6A\xD5\x04\xE0\x45\x58" + "\x1C\x34\x96\x7C\x03\x0C\x13\xA2" + "\x05\x22\xE2\xCB\x5A\x35\x03\x09" + "\x40\xD2\x82\x05\xCA\x58\x73\xF2" + "\x29\x5E\x01\x47\x13\x32\x78\xBE" + "\x06\xB0\x51\xDB\x6C\x31\xA0\x1C" + "\x74\xBC\x8D\x25\xDF\xF8\x65\xD1" + "\x38\x35\x11\x26\x4A\xB4\x06\x32" + "\xFA\xD2\x07\x77\xB3\x74\x98\x80" + "\x61\x59\xA8\x9F\xF3\x6F\x2A\xBF" + "\xE6\xA5\x9A\xC4\x6B\xA6\x49\x6F" + "\xBC\x47\xD9\xFB\xC6\xEF\x25\x65" + "\x96\xAC\x9F\xE4\x81\x4B\xD8\xBA" + "\xD6\x9B\xC9\x6D\x58\x40\x81\x02" + "\x73\x44\x4E\x43\x6E\x37\xBB\x11" + "\xE3\xF9\xB8\x2F\xEC\x76\x34\xEA" + "\x90\xCD\xB7\x2E\x0E\x32\x71\xE8" + "\xBB\x4E\x0B\x98\xA4\x17\x17\x5B" + "\x07\xB5\x82\x3A\xC4\xE8\x42\x51" + "\x5A\x4C\x4E\x7D\xBF\xC4\xC0\x4F" + "\x68\xB8\xC6\x4A\x32\x6F\x0B\xD7" + "\x85\xED\x6B\xFB\x72\xD2\xA5\x8F" + "\xBF\xF9\xAC\x59\x50\xA8\x08\x70" + "\xEC\xBD\x0A\xBF\xE5\x87\xA1\xC2" + "\x92\x14\x78\xAF\xE8\xEA\x2E\xDD" + "\xC1\x03\x9A\xAA\x89\x8B\x32\x46" + "\x5B\x18\x27\xBA\x46\xAA\x64\xDE" + "\xE3\xD5\xA3\xFC\x7B\x5B\x61\xDB" + "\x7E\xDA\xEC\x30\x17\x19\xF8\x80" + "\xB5\x5E\x27\xB5\x37\x3A\x1F\x28" + "\x07\x73\xC3\x63\xCE\xFF\x8C\xFE" + "\x81\x4E\xF8\x24\xF3\xB8\xC7\xE8" + "\x16\x9A\xCC\x58\x2F\x88\x1C\x4B" + "\xBB\x33\xA2\x73\xF0\x1C\x89\x0E" + "\xDC\x34\x27\x89\x98\xCE\x1C\xA2" + "\xD8\xB8\x90\xBE\xEC\x72\x28\x13" + "\xAC\x7B\xF1\xD0\x7F\x7A\x28\x50" + "\xB7\x99\x65\x8A\xC9\xC6\x21\x34" + "\x7F\x67\x9D\xB7\x2C\xCC\xF5\x17" + "\x2B\x89\xAC\xB0\xD7\x1E\x47\xB0" + "\x61\xAF\xD4\x63\x6D\xB8\x2D\x20", + .rlen = 496, }, }; @@ -5714,6 +6450,143 @@ static struct cipher_testvec serpent_ctr_dec_tv_template[] = { "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" "\xF1\x65\xFC", .rlen = 147, + .also_non_np = 1, + .np = 2, + .tap = { 147 - 16, 16 }, + }, { /* 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 = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .input = "\x06\x9A\xF8\xB4\x53\x88\x62\xFC" + "\x68\xB8\x2E\xDF\xC1\x05\x0F\x3D" + "\xAF\x4D\x95\xAE\xC4\xE9\x1C\xDC" + "\xF6\x2B\x8F\x90\x89\xF6\x7E\x1A" + "\xA6\xB9\xE4\xF4\xFA\xCA\xE5\x7E" + "\x71\x28\x06\x4F\xE8\x08\x39\xDA" + "\xA5\x0E\xC8\xC0\xB8\x16\xE5\x69" + "\xE5\xCA\xEC\x4F\x63\x2C\xC0\x9B" + "\x9F\x3E\x39\x79\xF0\xCD\x64\x35" + "\x4A\xD3\xC8\xA9\x31\xCD\x48\x5B" + "\x92\x3D\x8F\x3F\x96\xBD\xB3\x18" + "\x74\x2A\x5D\x29\x3F\x57\x8F\xE2" + "\x67\x9A\xE0\xE5\xD4\x4A\xE2\x47" + "\xBC\xF6\xEB\x14\xF3\x8C\x20\xC2" + "\x7D\xE2\x43\x81\x86\x72\x2E\xB1" + "\x39\xF6\x95\xE1\x1F\xCB\x76\x33" + "\x5B\x7D\x23\x0F\x3A\x67\x2A\x2F" + "\xB9\x37\x9D\xDD\x1F\x16\xA1\x3C" + "\x70\xFE\x52\xAA\x93\x3C\xC4\x46" + "\xB1\xE5\xFF\xDA\xAF\xE2\x84\xFE" + "\x25\x92\xB2\x63\xBD\x49\x77\xB4" + "\x22\xA4\x6A\xD5\x04\xE0\x45\x58" + "\x1C\x34\x96\x7C\x03\x0C\x13\xA2" + "\x05\x22\xE2\xCB\x5A\x35\x03\x09" + "\x40\xD2\x82\x05\xCA\x58\x73\xF2" + "\x29\x5E\x01\x47\x13\x32\x78\xBE" + "\x06\xB0\x51\xDB\x6C\x31\xA0\x1C" + "\x74\xBC\x8D\x25\xDF\xF8\x65\xD1" + "\x38\x35\x11\x26\x4A\xB4\x06\x32" + "\xFA\xD2\x07\x77\xB3\x74\x98\x80" + "\x61\x59\xA8\x9F\xF3\x6F\x2A\xBF" + "\xE6\xA5\x9A\xC4\x6B\xA6\x49\x6F" + "\xBC\x47\xD9\xFB\xC6\xEF\x25\x65" + "\x96\xAC\x9F\xE4\x81\x4B\xD8\xBA" + "\xD6\x9B\xC9\x6D\x58\x40\x81\x02" + "\x73\x44\x4E\x43\x6E\x37\xBB\x11" + "\xE3\xF9\xB8\x2F\xEC\x76\x34\xEA" + "\x90\xCD\xB7\x2E\x0E\x32\x71\xE8" + "\xBB\x4E\x0B\x98\xA4\x17\x17\x5B" + "\x07\xB5\x82\x3A\xC4\xE8\x42\x51" + "\x5A\x4C\x4E\x7D\xBF\xC4\xC0\x4F" + "\x68\xB8\xC6\x4A\x32\x6F\x0B\xD7" + "\x85\xED\x6B\xFB\x72\xD2\xA5\x8F" + "\xBF\xF9\xAC\x59\x50\xA8\x08\x70" + "\xEC\xBD\x0A\xBF\xE5\x87\xA1\xC2" + "\x92\x14\x78\xAF\xE8\xEA\x2E\xDD" + "\xC1\x03\x9A\xAA\x89\x8B\x32\x46" + "\x5B\x18\x27\xBA\x46\xAA\x64\xDE" + "\xE3\xD5\xA3\xFC\x7B\x5B\x61\xDB" + "\x7E\xDA\xEC\x30\x17\x19\xF8\x80" + "\xB5\x5E\x27\xB5\x37\x3A\x1F\x28" + "\x07\x73\xC3\x63\xCE\xFF\x8C\xFE" + "\x81\x4E\xF8\x24\xF3\xB8\xC7\xE8" + "\x16\x9A\xCC\x58\x2F\x88\x1C\x4B" + "\xBB\x33\xA2\x73\xF0\x1C\x89\x0E" + "\xDC\x34\x27\x89\x98\xCE\x1C\xA2" + "\xD8\xB8\x90\xBE\xEC\x72\x28\x13" + "\xAC\x7B\xF1\xD0\x7F\x7A\x28\x50" + "\xB7\x99\x65\x8A\xC9\xC6\x21\x34" + "\x7F\x67\x9D\xB7\x2C\xCC\xF5\x17" + "\x2B\x89\xAC\xB0\xD7\x1E\x47\xB0" + "\x61\xAF\xD4\x63\x6D\xB8\x2D\x20", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, }, }; @@ -5963,6 +6836,9 @@ static struct cipher_testvec serpent_lrw_enc_tv_template[] = { "\x5c\xc6\x84\xfe\x7c\xcb\x26\xfd" "\xd9\x51\x0f\xd7\x94\x2f\xc5\xa7", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -6213,6 +7089,9 @@ static struct cipher_testvec serpent_lrw_dec_tv_template[] = { "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" "\x21\xc4\xc2\x75\x67\x89\x37\x0a", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -6552,6 +7431,9 @@ static struct cipher_testvec serpent_xts_enc_tv_template[] = { "\xaf\x43\x0b\xc5\x20\x41\x92\x20" "\xd4\xa0\x91\x98\x11\x5f\x4d\xb1", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -6892,12 +7774,23 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; /* Cast6 test vectors from RFC 2612 */ -#define CAST6_ENC_TEST_VECTORS 3 -#define CAST6_DEC_TEST_VECTORS 3 +#define CAST6_ENC_TEST_VECTORS 4 +#define CAST6_DEC_TEST_VECTORS 4 +#define CAST6_CBC_ENC_TEST_VECTORS 1 +#define CAST6_CBC_DEC_TEST_VECTORS 1 +#define CAST6_CTR_ENC_TEST_VECTORS 2 +#define CAST6_CTR_DEC_TEST_VECTORS 2 +#define CAST6_LRW_ENC_TEST_VECTORS 1 +#define CAST6_LRW_DEC_TEST_VECTORS 1 +#define CAST6_XTS_ENC_TEST_VECTORS 1 +#define CAST6_XTS_DEC_TEST_VECTORS 1 static struct cipher_testvec cast6_enc_tv_template[] = { { @@ -6930,6 +7823,143 @@ static struct cipher_testvec cast6_enc_tv_template[] = { .result = "\x4f\x6a\x20\x38\x28\x68\x97\xb9" "\xc9\x87\x01\x36\x55\x33\x17\xfa", .rlen = 16, + }, { /* Generated from TF test vectors */ + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xC3\x70\x22\x32\xF5\x80\xCB\x54" + "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6" + "\xB6\xB9\xC5\xA4\x91\x55\x14\x97" + "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA" + "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE" + "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C" + "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C" + "\xD0\x6A\x99\x10\x72\xF8\x47\x62" + "\x81\x42\xF8\xD8\xF5\xBB\x94\x08" + "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E" + "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58" + "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12" + "\x5A\x72\x85\x47\x8B\xEC\x9F\x26" + "\x84\xB6\xED\x10\x33\x63\x9B\x5F" + "\x4D\x53\xEE\x94\x45\x8B\x60\x58" + "\x86\x20\xF9\x1E\x82\x08\x3E\x58" + "\x60\x1B\x34\x19\x02\xBE\x4E\x09" + "\xBB\x7C\x15\xCC\x60\x27\x55\x7A" + "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3" + "\xF1\xDD\xA7\x07\xA3\x12\x85\x28" + "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A" + "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43" + "\x92\xE4\x7C\x26\x69\x4D\x83\x68" + "\x14\x96\x42\x47\xBD\xA9\xE4\x8A" + "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E" + "\x91\x51\xB5\x36\x08\xDE\x1C\x06" + "\x03\xBD\xDE\x81\x26\xF7\x99\xC2" + "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF" + "\xC1\xF5\x27\x05\xB8\x02\x57\x72" + "\xE6\x42\x13\x0B\xC6\x47\x05\x74" + "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9" + "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C" + "\x98\x82\x67\x67\xB4\xD7\xD3\x43" + "\x23\x08\x02\xB7\x9B\x99\x05\xFB" + "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6" + "\x2E\x49\x58\xD0\xA8\x57\x29\x7F" + "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67" + "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D" + "\x17\xE2\x58\x2B\x88\x0D\x68\x62" + "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62" + "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08" + "\xEB\x84\x1D\x25\xA7\x38\x94\x06" + "\x93\x9D\xF8\xFE\x88\x71\xE7\x84" + "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29" + "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB" + "\x8E\x75\x3D\x73\xEB\x6A\xED\x29" + "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA" + "\x41\xE2\x10\x4C\x01\x8B\x69\x2B" + "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B" + "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6" + "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06" + "\x59\x28\x1D\x86\x43\x04\x5D\x3B" + "\x99\x4C\x04\x5A\x21\x17\x8B\x76" + "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3" + "\x65\xA2\x58\x2A\xC5\x66\x24\xBF" + "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8" + "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9" + "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E" + "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1" + "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C" + "\x84\x52\x6D\x68\xDE\xC6\x64\xB2" + "\x11\x74\x93\x57\xB4\x7E\xC6\x00", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -6964,6 +7994,1331 @@ static struct cipher_testvec cast6_dec_tv_template[] = { .ilen = 16, .result = zeroed_string, .rlen = 16, + }, { /* Generated from TF test vectors */ + .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 = "\xC3\x70\x22\x32\xF5\x80\xCB\x54" + "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6" + "\xB6\xB9\xC5\xA4\x91\x55\x14\x97" + "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA" + "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE" + "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C" + "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C" + "\xD0\x6A\x99\x10\x72\xF8\x47\x62" + "\x81\x42\xF8\xD8\xF5\xBB\x94\x08" + "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E" + "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58" + "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12" + "\x5A\x72\x85\x47\x8B\xEC\x9F\x26" + "\x84\xB6\xED\x10\x33\x63\x9B\x5F" + "\x4D\x53\xEE\x94\x45\x8B\x60\x58" + "\x86\x20\xF9\x1E\x82\x08\x3E\x58" + "\x60\x1B\x34\x19\x02\xBE\x4E\x09" + "\xBB\x7C\x15\xCC\x60\x27\x55\x7A" + "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3" + "\xF1\xDD\xA7\x07\xA3\x12\x85\x28" + "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A" + "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43" + "\x92\xE4\x7C\x26\x69\x4D\x83\x68" + "\x14\x96\x42\x47\xBD\xA9\xE4\x8A" + "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E" + "\x91\x51\xB5\x36\x08\xDE\x1C\x06" + "\x03\xBD\xDE\x81\x26\xF7\x99\xC2" + "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF" + "\xC1\xF5\x27\x05\xB8\x02\x57\x72" + "\xE6\x42\x13\x0B\xC6\x47\x05\x74" + "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9" + "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C" + "\x98\x82\x67\x67\xB4\xD7\xD3\x43" + "\x23\x08\x02\xB7\x9B\x99\x05\xFB" + "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6" + "\x2E\x49\x58\xD0\xA8\x57\x29\x7F" + "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67" + "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D" + "\x17\xE2\x58\x2B\x88\x0D\x68\x62" + "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62" + "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08" + "\xEB\x84\x1D\x25\xA7\x38\x94\x06" + "\x93\x9D\xF8\xFE\x88\x71\xE7\x84" + "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29" + "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB" + "\x8E\x75\x3D\x73\xEB\x6A\xED\x29" + "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA" + "\x41\xE2\x10\x4C\x01\x8B\x69\x2B" + "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B" + "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6" + "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06" + "\x59\x28\x1D\x86\x43\x04\x5D\x3B" + "\x99\x4C\x04\x5A\x21\x17\x8B\x76" + "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3" + "\x65\xA2\x58\x2A\xC5\x66\x24\xBF" + "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8" + "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9" + "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E" + "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1" + "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C" + "\x84\x52\x6D\x68\xDE\xC6\x64\xB2" + "\x11\x74\x93\x57\xB4\x7E\xC6\x00", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_cbc_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2" + "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F" + "\xA0\x73\xB3\x70\xC3\x68\x64\x70" + "\xAD\x33\x02\xFB\x88\x74\xAA\x78" + "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F" + "\x7E\x6F\xDF\x05\x13\x76\xA6\x72" + "\xB7\x13\x09\x0F\x7D\x38\xDF\x25" + "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0" + "\x57\x95\xE1\x21\x26\x10\x9A\x21" + "\xA1\x8A\x51\x05\xD1\xB1\x78\x35" + "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF" + "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B" + "\x23\x16\x47\x72\x81\x13\x3A\x72" + "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8" + "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E" + "\xA3\x63\x98\x7D\x35\xE4\xD9\x83" + "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3" + "\x41\x1A\x93\x8D\x76\x31\x9F\xF2" + "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9" + "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1" + "\x21\x9C\x1A\xCA\x65\xDE\x44\x03" + "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37" + "\x53\x50\x23\xA4\x81\x6E\xDA\xFB" + "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8" + "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7" + "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3" + "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2" + "\xC1\x03\xE6\x5A\x37\xD8\x64\x18" + "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB" + "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4" + "\x89\x05\x81\x6E\x71\x4F\xC3\x28" + "\x10\xC1\x62\xC4\x41\xE9\xD2\x39" + "\xF3\x22\x39\x12\x2C\xC2\x95\x2D" + "\xBF\x93\x58\x4B\x04\xD1\x8D\x57" + "\xAE\xEB\x60\x03\x56\x35\xAD\x5A" + "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8" + "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E" + "\x07\x09\x82\xBA\xF0\x80\x8A\xD0" + "\xA0\x3F\x6A\xE9\x24\x87\x19\x65" + "\x73\x3F\x12\x91\x47\x54\xBA\x39" + "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF" + "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76" + "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47" + "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1" + "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12" + "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D" + "\x23\xFA\x7D\x77\xB8\x46\x75\xFE" + "\x4F\x10\xD3\x09\x60\xA1\x36\x96" + "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14" + "\x80\x21\x83\x58\x3C\x76\xFD\x28" + "\x1D\xF9\x93\x13\xD7\x0E\x62\x14" + "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C" + "\x68\x93\x44\x70\xDF\xCF\x4A\x51" + "\x0B\x81\x29\x41\xE5\x62\x4D\x36" + "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09" + "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6" + "\x01\x91\xB4\x27\xDA\x59\xD6\x17" + "\x56\x4D\x82\x62\x37\xA3\x48\x01" + "\x99\x91\x77\xB2\x08\x6B\x2C\x37" + "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3" + "\x4D\x59\x7D\xC5\x28\x69\xFA\x92" + "\x22\x46\x89\x2D\x0F\x2B\x08\x24", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_cbc_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .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 = "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2" + "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F" + "\xA0\x73\xB3\x70\xC3\x68\x64\x70" + "\xAD\x33\x02\xFB\x88\x74\xAA\x78" + "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F" + "\x7E\x6F\xDF\x05\x13\x76\xA6\x72" + "\xB7\x13\x09\x0F\x7D\x38\xDF\x25" + "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0" + "\x57\x95\xE1\x21\x26\x10\x9A\x21" + "\xA1\x8A\x51\x05\xD1\xB1\x78\x35" + "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF" + "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B" + "\x23\x16\x47\x72\x81\x13\x3A\x72" + "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8" + "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E" + "\xA3\x63\x98\x7D\x35\xE4\xD9\x83" + "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3" + "\x41\x1A\x93\x8D\x76\x31\x9F\xF2" + "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9" + "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1" + "\x21\x9C\x1A\xCA\x65\xDE\x44\x03" + "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37" + "\x53\x50\x23\xA4\x81\x6E\xDA\xFB" + "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8" + "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7" + "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3" + "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2" + "\xC1\x03\xE6\x5A\x37\xD8\x64\x18" + "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB" + "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4" + "\x89\x05\x81\x6E\x71\x4F\xC3\x28" + "\x10\xC1\x62\xC4\x41\xE9\xD2\x39" + "\xF3\x22\x39\x12\x2C\xC2\x95\x2D" + "\xBF\x93\x58\x4B\x04\xD1\x8D\x57" + "\xAE\xEB\x60\x03\x56\x35\xAD\x5A" + "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8" + "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E" + "\x07\x09\x82\xBA\xF0\x80\x8A\xD0" + "\xA0\x3F\x6A\xE9\x24\x87\x19\x65" + "\x73\x3F\x12\x91\x47\x54\xBA\x39" + "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF" + "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76" + "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47" + "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1" + "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12" + "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D" + "\x23\xFA\x7D\x77\xB8\x46\x75\xFE" + "\x4F\x10\xD3\x09\x60\xA1\x36\x96" + "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14" + "\x80\x21\x83\x58\x3C\x76\xFD\x28" + "\x1D\xF9\x93\x13\xD7\x0E\x62\x14" + "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C" + "\x68\x93\x44\x70\xDF\xCF\x4A\x51" + "\x0B\x81\x29\x41\xE5\x62\x4D\x36" + "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09" + "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6" + "\x01\x91\xB4\x27\xDA\x59\xD6\x17" + "\x56\x4D\x82\x62\x37\xA3\x48\x01" + "\x99\x91\x77\xB2\x08\x6B\x2C\x37" + "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3" + "\x4D\x59\x7D\xC5\x28\x69\xFA\x92" + "\x22\x46\x89\x2D\x0F\x2B\x08\x24", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_ctr_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .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", + .ilen = 17, + .result = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3" + "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A" + "\x57", + .rlen = 17, + }, { /* Generated from TF test vectors */ + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3" + "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A" + "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7" + "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56" + "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8" + "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3" + "\xE3\xF3\xFA\xC2\x23\x55\x98\x20" + "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5" + "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30" + "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D" + "\x66\x45\xEE\xC8\x19\xBE\x50\xF0" + "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9" + "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5" + "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C" + "\x81\xDF\x82\x12\xC7\x4C\x1B\x07" + "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA" + "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6" + "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5" + "\x49\x61\x22\x52\x64\x8C\x46\x41" + "\x1F\x48\x5F\x4F\xA2\x89\x36\x17" + "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0" + "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3" + "\x00\x14\x15\x59\xC1\x30\x64\xAF" + "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C" + "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4" + "\x02\x37\xC4\x69\xEF\x36\xC1\xF3" + "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0" + "\x51\x73\xA3\x22\x42\x41\xAB\xD2" + "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA" + "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF" + "\xC9\x3F\x07\x87\x42\x4B\x3A\x54" + "\x34\x8E\x37\xA3\x03\x6F\x65\x66" + "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD" + "\x61\xB4\x2B\x80\xA3\x98\x13\xF5" + "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8" + "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D" + "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE" + "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A" + "\x60\x40\x38\x90\x20\x46\xC7\xB3" + "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4" + "\x11\x41\x76\x6B\xB3\x60\x82\x3C" + "\x84\xFB\x08\x2E\x92\x25\xCB\x79" + "\x6F\x58\xC5\x94\x00\x00\x47\xB6" + "\x9E\xDC\x0F\x29\x70\x46\x20\x76" + "\x65\x75\x66\x5C\x00\x96\xB3\xE1" + "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45" + "\x73\xFC\x91\xAB\x79\x41\x23\x14" + "\x13\xB6\x72\x6C\x46\xB3\x03\x11" + "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32" + "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7" + "\x15\x48\x44\x99\x09\xF6\xE0\xD7" + "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2" + "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2" + "\x12\x53\x35\x9C\xF9\xE7\x35\x5D" + "\x81\xE4\x86\x42\xC3\x58\xFB\xF0" + "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F" + "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4" + "\x19\x35\x88\x22\x45\x59\x0E\x8F" + "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41" + "\x9B\x66\x8D\x32\xBA\x81\x34\x87" + "\x0E\x74\x33\x30\x62\xB9\x89\xDF" + "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_ctr_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .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 = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3" + "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A" + "\x57", + .ilen = 17, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A", + .rlen = 17, + }, { /* Generated from TF test vectors */ + .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 = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3" + "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A" + "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7" + "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56" + "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8" + "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3" + "\xE3\xF3\xFA\xC2\x23\x55\x98\x20" + "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5" + "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30" + "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D" + "\x66\x45\xEE\xC8\x19\xBE\x50\xF0" + "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9" + "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5" + "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C" + "\x81\xDF\x82\x12\xC7\x4C\x1B\x07" + "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA" + "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6" + "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5" + "\x49\x61\x22\x52\x64\x8C\x46\x41" + "\x1F\x48\x5F\x4F\xA2\x89\x36\x17" + "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0" + "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3" + "\x00\x14\x15\x59\xC1\x30\x64\xAF" + "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C" + "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4" + "\x02\x37\xC4\x69\xEF\x36\xC1\xF3" + "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0" + "\x51\x73\xA3\x22\x42\x41\xAB\xD2" + "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA" + "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF" + "\xC9\x3F\x07\x87\x42\x4B\x3A\x54" + "\x34\x8E\x37\xA3\x03\x6F\x65\x66" + "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD" + "\x61\xB4\x2B\x80\xA3\x98\x13\xF5" + "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8" + "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D" + "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE" + "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A" + "\x60\x40\x38\x90\x20\x46\xC7\xB3" + "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4" + "\x11\x41\x76\x6B\xB3\x60\x82\x3C" + "\x84\xFB\x08\x2E\x92\x25\xCB\x79" + "\x6F\x58\xC5\x94\x00\x00\x47\xB6" + "\x9E\xDC\x0F\x29\x70\x46\x20\x76" + "\x65\x75\x66\x5C\x00\x96\xB3\xE1" + "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45" + "\x73\xFC\x91\xAB\x79\x41\x23\x14" + "\x13\xB6\x72\x6C\x46\xB3\x03\x11" + "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32" + "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7" + "\x15\x48\x44\x99\x09\xF6\xE0\xD7" + "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2" + "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2" + "\x12\x53\x35\x9C\xF9\xE7\x35\x5D" + "\x81\xE4\x86\x42\xC3\x58\xFB\xF0" + "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F" + "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4" + "\x19\x35\x88\x22\x45\x59\x0E\x8F" + "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41" + "\x9B\x66\x8D\x32\xBA\x81\x34\x87" + "\x0E\x74\x33\x30\x62\xB9\x89\xDF" + "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_lrw_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .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 = "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF" + "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB" + "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA" + "\x58\xB6\x73\xF0\xD7\x52\x34\xEF" + "\xFB\x3E\x96\x81\xB7\x71\x34\xA4" + "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1" + "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7" + "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B" + "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08" + "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D" + "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE" + "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA" + "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D" + "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28" + "\x80\x1D\xF0\x30\xBA\x62\x77\x7D" + "\xDB\x15\x69\xDF\xFA\x2A\x81\x64" + "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30" + "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7" + "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B" + "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61" + "\x5E\xDB\xFC\x11\x74\x25\x96\x65" + "\xE8\xE2\x34\x57\x77\x15\x5E\x70" + "\xFF\x10\x90\xC3\x64\xF0\x11\x0A" + "\x63\x3A\xD3\x55\x92\x15\x4B\x0C" + "\xC7\x08\x89\x17\x3B\x99\xAD\x63" + "\xE7\x06\xDF\x52\xBC\x15\x64\x45" + "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9" + "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23" + "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E" + "\xBD\xAB\x60\x1A\x51\x17\x54\x27" + "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19" + "\x2F\x6F\x20\xA7\x47\xED\x74\x6C" + "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F" + "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1" + "\x07\x16\xDE\x76\xCC\x5E\x94\x02" + "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F" + "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7" + "\x6E\x21\x58\x36\x06\xDE\xB3\xD4" + "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23" + "\x51\x21\x2B\x32\x68\xAA\xF8\xA8" + "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7" + "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25" + "\x30\xC7\x10\x3F\x97\x27\x01\x8E" + "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB" + "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8" + "\x22\xE2\xE6\x92\xA7\x5F\x11\x32" + "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54" + "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC" + "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5" + "\x96\x3D\x69\x91\x20\x4E\xF2\x61" + "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A" + "\x78\x39\xB0\xE0\xCF\x12\x56\xD6" + "\x05\xDC\xF9\x19\x66\x44\x1D\xF9" + "\x82\x37\xD4\xC2\x60\xB6\x31\xDF" + "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D" + "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9" + "\x9B\x8D\xA7\x00\x86\x25\xB6\x14" + "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3" + "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6" + "\x15\xB7\x94\x7D\x4E\x70\x4C\x75" + "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A" + "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5" + "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7" + "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46", + .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_lrw_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .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 = "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF" + "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB" + "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA" + "\x58\xB6\x73\xF0\xD7\x52\x34\xEF" + "\xFB\x3E\x96\x81\xB7\x71\x34\xA4" + "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1" + "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7" + "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B" + "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08" + "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D" + "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE" + "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA" + "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D" + "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28" + "\x80\x1D\xF0\x30\xBA\x62\x77\x7D" + "\xDB\x15\x69\xDF\xFA\x2A\x81\x64" + "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30" + "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7" + "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B" + "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61" + "\x5E\xDB\xFC\x11\x74\x25\x96\x65" + "\xE8\xE2\x34\x57\x77\x15\x5E\x70" + "\xFF\x10\x90\xC3\x64\xF0\x11\x0A" + "\x63\x3A\xD3\x55\x92\x15\x4B\x0C" + "\xC7\x08\x89\x17\x3B\x99\xAD\x63" + "\xE7\x06\xDF\x52\xBC\x15\x64\x45" + "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9" + "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23" + "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E" + "\xBD\xAB\x60\x1A\x51\x17\x54\x27" + "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19" + "\x2F\x6F\x20\xA7\x47\xED\x74\x6C" + "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F" + "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1" + "\x07\x16\xDE\x76\xCC\x5E\x94\x02" + "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F" + "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7" + "\x6E\x21\x58\x36\x06\xDE\xB3\xD4" + "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23" + "\x51\x21\x2B\x32\x68\xAA\xF8\xA8" + "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7" + "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25" + "\x30\xC7\x10\x3F\x97\x27\x01\x8E" + "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB" + "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8" + "\x22\xE2\xE6\x92\xA7\x5F\x11\x32" + "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54" + "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC" + "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5" + "\x96\x3D\x69\x91\x20\x4E\xF2\x61" + "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A" + "\x78\x39\xB0\xE0\xCF\x12\x56\xD6" + "\x05\xDC\xF9\x19\x66\x44\x1D\xF9" + "\x82\x37\xD4\xC2\x60\xB6\x31\xDF" + "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D" + "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9" + "\x9B\x8D\xA7\x00\x86\x25\xB6\x14" + "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3" + "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6" + "\x15\xB7\x94\x7D\x4E\x70\x4C\x75" + "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A" + "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5" + "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7" + "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46", + .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, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_xts_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .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 = "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78" + "\x88\x5A\x4F\x8D\x82\x76\x52\x6D" + "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6" + "\xE2\xC5\x62\x8D\x61\xA1\x01\xED" + "\xD9\x38\x01\xC1\x43\x63\x4E\x88" + "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71" + "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13" + "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81" + "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6" + "\x60\x54\x09\x32\xFE\x6A\x76\x2E" + "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D" + "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB" + "\xB8\x25\x70\xF8\x40\xBC\x90\x1B" + "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD" + "\xD3\x3B\xCF\x60\xA1\x78\x94\x57" + "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98" + "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA" + "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67" + "\x05\xDD\x1D\x58\x6E\x2F\x95\x08" + "\x3A\xF8\x78\x76\x82\x56\xA7\xEC" + "\x51\x4B\x85\x77\xC2\x4C\x4A\x34" + "\x71\x38\x17\x91\x44\xE8\xFC\x65" + "\x99\x0D\x52\x91\xEE\xF8\xEF\x27" + "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4" + "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D" + "\x59\x22\x9B\x29\x5C\x18\xF0\xC3" + "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1" + "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3" + "\x91\x3B\x49\x73\x18\xAB\xD4\xC9" + "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A" + "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E" + "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24" + "\xE6\x87\xEA\xFE\x96\x25\x67\x8E" + "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C" + "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9" + "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97" + "\x49\xF7\x04\xCB\xEF\x84\x98\x33" + "\xAF\x38\xD3\x04\x1C\x24\x71\x38" + "\xC7\x71\xDD\x43\x0D\x12\x4A\x18" + "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95" + "\x02\x43\x5D\xCE\x19\xCC\xCD\x66" + "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C" + "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB" + "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B" + "\x30\x45\xA9\xB7\xAF\x80\x64\x6F" + "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE" + "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE" + "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8" + "\x97\xA3\xE1\x6F\x38\x24\x34\x88" + "\xCE\xBD\x32\x52\xE0\x00\x6C\x94" + "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F" + "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59" + "\x34\x39\xA8\x35\x12\xB7\xBC\xAC" + "\xEA\x52\x9C\x78\x02\x6D\x92\x36" + "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83" + "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64" + "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3" + "\xB0\xEB\x31\xE4\x69\x95\xAB\x35" + "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82" + "\xF8\xD9\x47\x82\xA9\x82\x03\x91" + "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F" + "\x45\x72\x80\x17\x81\xBD\x9D\x62" + "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC" + "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9", + .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast6_xts_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .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 = "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78" + "\x88\x5A\x4F\x8D\x82\x76\x52\x6D" + "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6" + "\xE2\xC5\x62\x8D\x61\xA1\x01\xED" + "\xD9\x38\x01\xC1\x43\x63\x4E\x88" + "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71" + "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13" + "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81" + "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6" + "\x60\x54\x09\x32\xFE\x6A\x76\x2E" + "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D" + "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB" + "\xB8\x25\x70\xF8\x40\xBC\x90\x1B" + "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD" + "\xD3\x3B\xCF\x60\xA1\x78\x94\x57" + "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98" + "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA" + "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67" + "\x05\xDD\x1D\x58\x6E\x2F\x95\x08" + "\x3A\xF8\x78\x76\x82\x56\xA7\xEC" + "\x51\x4B\x85\x77\xC2\x4C\x4A\x34" + "\x71\x38\x17\x91\x44\xE8\xFC\x65" + "\x99\x0D\x52\x91\xEE\xF8\xEF\x27" + "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4" + "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D" + "\x59\x22\x9B\x29\x5C\x18\xF0\xC3" + "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1" + "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3" + "\x91\x3B\x49\x73\x18\xAB\xD4\xC9" + "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A" + "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E" + "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24" + "\xE6\x87\xEA\xFE\x96\x25\x67\x8E" + "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C" + "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9" + "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97" + "\x49\xF7\x04\xCB\xEF\x84\x98\x33" + "\xAF\x38\xD3\x04\x1C\x24\x71\x38" + "\xC7\x71\xDD\x43\x0D\x12\x4A\x18" + "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95" + "\x02\x43\x5D\xCE\x19\xCC\xCD\x66" + "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C" + "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB" + "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B" + "\x30\x45\xA9\xB7\xAF\x80\x64\x6F" + "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE" + "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE" + "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8" + "\x97\xA3\xE1\x6F\x38\x24\x34\x88" + "\xCE\xBD\x32\x52\xE0\x00\x6C\x94" + "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F" + "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59" + "\x34\x39\xA8\x35\x12\xB7\xBC\xAC" + "\xEA\x52\x9C\x78\x02\x6D\x92\x36" + "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83" + "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64" + "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3" + "\xB0\xEB\x31\xE4\x69\x95\xAB\x35" + "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82" + "\xF8\xD9\x47\x82\xA9\x82\x03\x91" + "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F" + "\x45\x72\x80\x17\x81\xBD\x9D\x62" + "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC" + "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9", + .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, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -8313,6 +10668,9 @@ static struct cipher_testvec aes_lrw_enc_tv_template[] = { "\xcd\x7e\x2b\x5d\x43\xea\x42\xe7" "\x74\x3f\x7d\x58\x88\x75\xde\x3e", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, } }; @@ -8564,6 +10922,9 @@ static struct cipher_testvec aes_lrw_dec_tv_template[] = { "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" "\x21\xc4\xc2\x75\x67\x89\x37\x0a", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, } }; @@ -8905,6 +11266,9 @@ static struct cipher_testvec aes_xts_enc_tv_template[] = { "\xc4\xf3\x6f\xfd\xa9\xfc\xea\x70" "\xb9\xc6\xe6\x93\xe1\x48\xc1\x51", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, } }; @@ -9246,7 +11610,9 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", .rlen = 512, - + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, } }; @@ -12125,8 +14491,12 @@ static struct cprng_testvec ansi_cprng_aes_tv_template[] = { }; /* Cast5 test vectors from RFC 2144 */ -#define CAST5_ENC_TEST_VECTORS 3 -#define CAST5_DEC_TEST_VECTORS 3 +#define CAST5_ENC_TEST_VECTORS 4 +#define CAST5_DEC_TEST_VECTORS 4 +#define CAST5_CBC_ENC_TEST_VECTORS 1 +#define CAST5_CBC_DEC_TEST_VECTORS 1 +#define CAST5_CTR_ENC_TEST_VECTORS 2 +#define CAST5_CTR_DEC_TEST_VECTORS 2 static struct cipher_testvec cast5_enc_tv_template[] = { { @@ -12152,6 +14522,140 @@ static struct cipher_testvec cast5_enc_tv_template[] = { .ilen = 8, .result = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e", .rlen = 8, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C" + "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA" + "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E" + "\xD1\x39\x34\x92\x8F\xFA\x14\xF1" + "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2" + "\x20\xD9\x42\x06\xC9\x0B\x10\x04" + "\xF8\x79\xCD\x32\x86\x75\x4C\xB6" + "\x7B\x1C\x52\xB1\x91\x64\x22\x4B" + "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F" + "\x3F\xF4\x43\x96\x73\x0D\xA2\x05" + "\xDB\xFD\x28\x90\x2C\x56\xB9\x37" + "\x5B\x69\x0C\xAD\x84\x67\xFF\x15" + "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A" + "\xED\x34\x35\x78\x6B\x91\xC9\x32" + "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39" + "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2" + "\x1C\xFD\x0E\x05\x07\xF4\x10\xED" + "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22" + "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9" + "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77" + "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC" + "\xBA\x5C\x80\xD1\x91\x65\x51\x1B" + "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6" + "\x78\x75\x37\x55\xC1\xF5\x90\x40" + "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E" + "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E" + "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD" + "\xE0\x69\x77\x50\xC7\x0C\x99\xCA" + "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C" + "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9" + "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48" + "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9" + "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6" + "\x55\xF4\x06\xBB\x49\x53\x8B\x1B" + "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC" + "\x93\x85\x90\x0F\x0A\x68\x40\x2A" + "\x95\xED\x2D\x88\xBF\x71\xD0\xBB" + "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05" + "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2" + "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8" + "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF" + "\xDD\x70\x37\x63\xAA\xA5\x83\x20" + "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6" + "\x79\x03\xA0\xDA\xA3\x79\x21\xBD" + "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE" + "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06" + "\xBB\xE3\xAB\x06\x21\x82\xB8\x32" + "\x31\x34\x2A\xA7\x1F\x64\x99\xBF" + "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48" + "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59" + "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF" + "\xF0\x40\x5F\xCF\xE3\x58\x52\x67" + "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F" + "\x58\x56\xDD\x94\x1F\x71\x8D\xF4" + "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF" + "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57" + "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84" + "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37" + "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33" + "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE" + "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57" + "\xF5\xBC\x25\xD6\x02\x56\x57\x1C", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -12179,6 +14683,718 @@ static struct cipher_testvec cast5_dec_tv_template[] = { .ilen = 8, .result = "\x01\x23\x45\x67\x89\xab\xcd\xef", .rlen = 8, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C" + "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA" + "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E" + "\xD1\x39\x34\x92\x8F\xFA\x14\xF1" + "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2" + "\x20\xD9\x42\x06\xC9\x0B\x10\x04" + "\xF8\x79\xCD\x32\x86\x75\x4C\xB6" + "\x7B\x1C\x52\xB1\x91\x64\x22\x4B" + "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F" + "\x3F\xF4\x43\x96\x73\x0D\xA2\x05" + "\xDB\xFD\x28\x90\x2C\x56\xB9\x37" + "\x5B\x69\x0C\xAD\x84\x67\xFF\x15" + "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A" + "\xED\x34\x35\x78\x6B\x91\xC9\x32" + "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39" + "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2" + "\x1C\xFD\x0E\x05\x07\xF4\x10\xED" + "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22" + "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9" + "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77" + "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC" + "\xBA\x5C\x80\xD1\x91\x65\x51\x1B" + "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6" + "\x78\x75\x37\x55\xC1\xF5\x90\x40" + "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E" + "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E" + "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD" + "\xE0\x69\x77\x50\xC7\x0C\x99\xCA" + "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C" + "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9" + "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48" + "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9" + "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6" + "\x55\xF4\x06\xBB\x49\x53\x8B\x1B" + "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC" + "\x93\x85\x90\x0F\x0A\x68\x40\x2A" + "\x95\xED\x2D\x88\xBF\x71\xD0\xBB" + "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05" + "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2" + "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8" + "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF" + "\xDD\x70\x37\x63\xAA\xA5\x83\x20" + "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6" + "\x79\x03\xA0\xDA\xA3\x79\x21\xBD" + "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE" + "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06" + "\xBB\xE3\xAB\x06\x21\x82\xB8\x32" + "\x31\x34\x2A\xA7\x1F\x64\x99\xBF" + "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48" + "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59" + "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF" + "\xF0\x40\x5F\xCF\xE3\x58\x52\x67" + "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F" + "\x58\x56\xDD\x94\x1F\x71\x8D\xF4" + "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF" + "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57" + "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84" + "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37" + "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33" + "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE" + "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57" + "\xF5\xBC\x25\xD6\x02\x56\x57\x1C", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast5_cbc_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x05\x28\xCE\x61\x90\x80\xE1\x78" + "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A" + "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB" + "\xDA\xF0\x6E\x77\x14\x47\x82\xBA" + "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F" + "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39" + "\xA7\xFB\x0D\x05\x00\xF3\x58\x67" + "\x60\xEC\x73\x77\x46\x85\x9B\x6A" + "\x08\x3E\xBE\x59\xFB\xE4\x96\x34" + "\xB4\x05\x49\x1A\x97\x43\xAD\xA0" + "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8" + "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA" + "\xA7\xF1\x33\x67\x90\x23\x0D\xEE" + "\x81\xD5\x78\x4F\xD3\x63\xEA\x46" + "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10" + "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D" + "\x36\x7C\x56\x14\x54\x83\xFA\xA1" + "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6" + "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8" + "\xA7\xD9\x67\x92\x5C\x13\xB4\x71" + "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C" + "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37" + "\xC8\x52\x60\xD9\xE7\xCA\x60\x98" + "\xED\xCD\xE8\x60\x83\xAD\x34\x4D" + "\x96\x4A\x99\x2B\xB7\x14\x75\x66" + "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56" + "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3" + "\x18\x38\x09\x9C\x0E\x8B\x86\x07" + "\x90\x12\x37\x49\x27\x98\x69\x18" + "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85" + "\x4B\x22\x97\x07\xB6\x97\xE9\x95" + "\x0F\x88\x36\xA9\x44\x00\xC6\xE9" + "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE" + "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49" + "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97" + "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE" + "\x03\x55\x0E\x02\x41\x4A\x45\x06" + "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20" + "\x94\x02\x30\xD2\xFC\x29\xFA\x8E" + "\x34\xA0\x31\xB8\x34\xBA\xAE\x54" + "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F" + "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A" + "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3" + "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A" + "\xB6\x37\x21\x19\x55\xC2\xBD\x99" + "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2" + "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2" + "\x11\xB4\x18\x17\x1A\x65\x92\x56" + "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1" + "\x1A\x01\x22\x45\x17\x62\x52\x6C" + "\x91\x44\xCF\x98\xC7\xC0\x79\x26" + "\x32\x66\x6F\x23\x7F\x94\x36\x88" + "\x3C\xC9\xD0\xB7\x45\x30\x31\x86" + "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B" + "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86" + "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA" + "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9" + "\x7C\xEF\x53\xB7\x60\x72\x41\xBF" + "\x29\x00\x87\x02\xAF\x44\x4C\xB7" + "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7" + "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6" + "\x1D\x18\x66\x44\x5B\x8F\x14\xEB", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast5_cbc_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x05\x28\xCE\x61\x90\x80\xE1\x78" + "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A" + "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB" + "\xDA\xF0\x6E\x77\x14\x47\x82\xBA" + "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F" + "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39" + "\xA7\xFB\x0D\x05\x00\xF3\x58\x67" + "\x60\xEC\x73\x77\x46\x85\x9B\x6A" + "\x08\x3E\xBE\x59\xFB\xE4\x96\x34" + "\xB4\x05\x49\x1A\x97\x43\xAD\xA0" + "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8" + "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA" + "\xA7\xF1\x33\x67\x90\x23\x0D\xEE" + "\x81\xD5\x78\x4F\xD3\x63\xEA\x46" + "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10" + "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D" + "\x36\x7C\x56\x14\x54\x83\xFA\xA1" + "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6" + "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8" + "\xA7\xD9\x67\x92\x5C\x13\xB4\x71" + "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C" + "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37" + "\xC8\x52\x60\xD9\xE7\xCA\x60\x98" + "\xED\xCD\xE8\x60\x83\xAD\x34\x4D" + "\x96\x4A\x99\x2B\xB7\x14\x75\x66" + "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56" + "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3" + "\x18\x38\x09\x9C\x0E\x8B\x86\x07" + "\x90\x12\x37\x49\x27\x98\x69\x18" + "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85" + "\x4B\x22\x97\x07\xB6\x97\xE9\x95" + "\x0F\x88\x36\xA9\x44\x00\xC6\xE9" + "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE" + "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49" + "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97" + "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE" + "\x03\x55\x0E\x02\x41\x4A\x45\x06" + "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20" + "\x94\x02\x30\xD2\xFC\x29\xFA\x8E" + "\x34\xA0\x31\xB8\x34\xBA\xAE\x54" + "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F" + "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A" + "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3" + "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A" + "\xB6\x37\x21\x19\x55\xC2\xBD\x99" + "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2" + "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2" + "\x11\xB4\x18\x17\x1A\x65\x92\x56" + "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1" + "\x1A\x01\x22\x45\x17\x62\x52\x6C" + "\x91\x44\xCF\x98\xC7\xC0\x79\x26" + "\x32\x66\x6F\x23\x7F\x94\x36\x88" + "\x3C\xC9\xD0\xB7\x45\x30\x31\x86" + "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B" + "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86" + "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA" + "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9" + "\x7C\xEF\x53\xB7\x60\x72\x41\xBF" + "\x29\x00\x87\x02\xAF\x44\x4C\xB7" + "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7" + "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6" + "\x1D\x18\x66\x44\x5B\x8F\x14\xEB", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast5_ctr_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A", + .ilen = 17, + .result = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39" + "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8" + "\x0C", + .rlen = 17, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39" + "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8" + "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F" + "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF" + "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44" + "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C" + "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF" + "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B" + "\x64\xB0\x7B\x86\x29\x1D\x9F\x17" + "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3" + "\x88\x18\x52\x56\x48\x58\xD1\x6B" + "\xE8\x74\x6E\x48\xB0\x2E\x69\x63" + "\x32\xAA\xAC\x26\x55\x45\x94\xDE" + "\x30\x26\x26\xE6\x08\x82\x2F\x5F" + "\xA7\x15\x94\x07\x75\x2D\xC6\x3A" + "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56" + "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B" + "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7" + "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5" + "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F" + "\x3B\x29\xF9\xB4\x32\x62\x69\xBF" + "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3" + "\x44\x67\x90\x20\xAC\x41\xDF\x43" + "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB" + "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60" + "\xC7\xC9\x71\x34\x44\xCE\x05\xFD" + "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C" + "\xAE\x59\x0F\x07\x88\x79\x53\x26" + "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62" + "\xD0\x82\x65\x66\xE4\x2A\x29\x1C" + "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9" + "\xED\xC4\x13\x52\x75\xDC\xE4\xF9" + "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA" + "\x49\xA1\x86\x86\x37\x5C\x6B\x3D" + "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8" + "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0" + "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2" + "\x23\xD3\xC7\x27\x15\x04\x2C\x27" + "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D" + "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14" + "\x4B\x78\xC4\xDE\x07\x6A\x12\x02" + "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02" + "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18" + "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06" + "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E" + "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66" + "\x16\xB5\xC8\x45\x21\x37\xBD\x24" + "\xA9\xD5\x36\x12\x9F\x6E\x67\x80" + "\x87\x54\xD5\xAF\x97\xE1\x15\xA7" + "\x11\xF0\x63\x7B\xE1\x44\x14\x1C" + "\x06\x32\x05\x8C\x6C\xDB\x9B\x36" + "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C" + "\x76\x36\x43\xE8\x16\x60\xB5\xF3" + "\xDF\x5A\xC6\xA5\x69\x78\x59\x51" + "\x54\x68\x65\x06\x84\xDE\x3D\xAE" + "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6" + "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE" + "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B" + "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1" + "\x91\x01\xD7\x21\x23\x28\x1E\xCC" + "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA" + "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, + }, +}; + +static struct cipher_testvec cast5_ctr_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39" + "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8" + "\x0C", + .ilen = 17, + .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" + "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" + "\x3A", + .rlen = 17, + }, { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", + .klen = 16, + .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F", + .input = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39" + "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8" + "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F" + "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF" + "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44" + "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C" + "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF" + "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B" + "\x64\xB0\x7B\x86\x29\x1D\x9F\x17" + "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3" + "\x88\x18\x52\x56\x48\x58\xD1\x6B" + "\xE8\x74\x6E\x48\xB0\x2E\x69\x63" + "\x32\xAA\xAC\x26\x55\x45\x94\xDE" + "\x30\x26\x26\xE6\x08\x82\x2F\x5F" + "\xA7\x15\x94\x07\x75\x2D\xC6\x3A" + "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56" + "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B" + "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7" + "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5" + "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F" + "\x3B\x29\xF9\xB4\x32\x62\x69\xBF" + "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3" + "\x44\x67\x90\x20\xAC\x41\xDF\x43" + "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB" + "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60" + "\xC7\xC9\x71\x34\x44\xCE\x05\xFD" + "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C" + "\xAE\x59\x0F\x07\x88\x79\x53\x26" + "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62" + "\xD0\x82\x65\x66\xE4\x2A\x29\x1C" + "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9" + "\xED\xC4\x13\x52\x75\xDC\xE4\xF9" + "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA" + "\x49\xA1\x86\x86\x37\x5C\x6B\x3D" + "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8" + "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0" + "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2" + "\x23\xD3\xC7\x27\x15\x04\x2C\x27" + "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D" + "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14" + "\x4B\x78\xC4\xDE\x07\x6A\x12\x02" + "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02" + "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18" + "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06" + "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E" + "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66" + "\x16\xB5\xC8\x45\x21\x37\xBD\x24" + "\xA9\xD5\x36\x12\x9F\x6E\x67\x80" + "\x87\x54\xD5\xAF\x97\xE1\x15\xA7" + "\x11\xF0\x63\x7B\xE1\x44\x14\x1C" + "\x06\x32\x05\x8C\x6C\xDB\x9B\x36" + "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C" + "\x76\x36\x43\xE8\x16\x60\xB5\xF3" + "\xDF\x5A\xC6\xA5\x69\x78\x59\x51" + "\x54\x68\x65\x06\x84\xDE\x3D\xAE" + "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6" + "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE" + "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B" + "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1" + "\x91\x01\xD7\x21\x23\x28\x1E\xCC" + "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA" + "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, + .also_non_np = 1, + .np = 2, + .tap = { 496 - 16, 16 }, }, }; @@ -13096,6 +16312,9 @@ static struct cipher_testvec camellia_enc_tv_template[] = { "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9" "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A", .rlen = 48, + .also_non_np = 1, + .np = 2, + .tap = { 48 - 16, 16 }, }, }; @@ -13154,6 +16373,9 @@ static struct cipher_testvec camellia_dec_tv_template[] = { "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", .rlen = 48, + .also_non_np = 1, + .np = 2, + .tap = { 48 - 16, 16 }, }, }; @@ -13208,6 +16430,9 @@ static struct cipher_testvec camellia_cbc_enc_tv_template[] = { "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27" "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01", .rlen = 48, + .also_non_np = 1, + .np = 2, + .tap = { 48 - 16, 16 }, }, }; @@ -13262,6 +16487,9 @@ static struct cipher_testvec camellia_cbc_dec_tv_template[] = { "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", .rlen = 48, + .also_non_np = 1, + .np = 2, + .tap = { 48 - 16, 16 }, }, }; @@ -13313,6 +16541,143 @@ static struct cipher_testvec camellia_ctr_enc_tv_template[] = { "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C" "\x1E\x43\xEF", .rlen = 51, + .also_non_np = 1, + .np = 2, + .tap = { 51 - 16, 16 }, + }, { /* 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 = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .ilen = 496, + .result = "\x85\x79\x6C\x8B\x2B\x6D\x14\xF9" + "\xA6\x83\xB6\x80\x5B\x3A\xF3\x7E" + "\x30\x29\xEB\x1F\xDC\x19\x5F\xEB" + "\xF7\xC4\x27\x04\x51\x87\xD7\x6F" + "\xB8\x4E\x07\xFB\xAC\x3B\x08\xB4" + "\x4D\xCB\xE8\xE1\x71\x7D\x4F\x48" + "\xCD\x81\x64\xA5\xC4\x07\x1A\x9A" + "\x4B\x62\x90\x0E\xC8\xB3\x2B\x6B" + "\x8F\x9C\x6E\x72\x4B\xBA\xEF\x07" + "\x2C\x56\x07\x5E\x37\x30\x60\xA9" + "\xE3\xEF\xD6\x69\xE1\xA1\x77\x64" + "\x93\x75\x7A\xB7\x7A\x3B\xE9\x43" + "\x23\x35\x95\x91\x80\x8A\xC7\xCF" + "\xC3\xD5\xBF\xE7\xFE\x4C\x06\x6B" + "\x05\x19\x48\xE2\x62\xBA\x4F\xF2" + "\xFB\xEE\xE4\xCB\x79\x9D\xA3\x10" + "\x1D\x29\x8C\x1D\x7A\x88\x5A\xDD" + "\x4E\xB6\x18\xAA\xCD\xE6\x33\x96" + "\xD9\x0F\x90\x5A\x78\x76\x4D\x77" + "\x3C\x20\x89\x3B\xA3\xF9\x07\xFD" + "\xE4\xE8\x20\x2D\x15\x0A\x63\x49" + "\xF5\x4F\x89\xD8\xDE\xA1\x28\x78" + "\x28\x07\x09\x1B\x03\x94\x1D\x4B" + "\x82\x28\x1E\x1D\x95\xBA\xAC\x85" + "\x71\x6E\x3C\x18\x4B\x77\x74\x79" + "\xBF\x67\x0A\x53\x3C\x94\xD9\x60" + "\xE9\x6D\x40\x34\xA0\x2A\x53\x5D" + "\x27\xD5\x47\xF9\xC3\x4B\x27\x29" + "\xE4\x76\x9C\x3F\xA7\x1C\x87\xFC" + "\x6E\x0F\xCF\x9B\x60\xF0\xF0\x8B" + "\x70\x1C\x84\x81\x72\x4D\xB4\x98" + "\x23\x62\xE7\x6A\x2B\xFC\xA5\xB2" + "\xFF\xF5\x71\x07\xCD\x90\x23\x13" + "\x19\xD7\x79\x36\x6C\x9D\x55\x8B" + "\x93\x78\x86\x05\x69\x46\xD0\xC5" + "\x39\x09\xEB\x79\xEF\xFA\x9F\xAE" + "\xF3\xD5\x44\xC3\xFD\x86\xD2\x7C" + "\x83\x4B\xD8\x75\x9C\x18\x04\x7B" + "\x73\xAD\x72\xA4\xF6\xAB\xCF\x4B" + "\xCC\x01\x45\x90\xA6\x43\x05\x0C" + "\x6C\x4F\x62\x77\x57\x97\x9F\xEE" + "\x75\xA7\x3C\x38\xD1\x0F\x3D\x0E" + "\x2C\x43\x98\xFB\x13\x65\x73\xE4" + "\x3C\x1E\xD6\x90\x08\xF7\xE0\x99" + "\x3B\xF1\x9D\x6C\x48\xA9\x0E\x32" + "\x17\xC2\xCC\x20\xA1\x19\x26\xAA" + "\xE0\x75\x2F\xFB\x54\x66\x0A\xDF" + "\xB5\xF2\x1F\xC1\x34\x3C\x30\x56" + "\xE8\xDC\xF7\x92\x6B\xBF\x17\x24" + "\xEC\x94\xB5\x3B\xD6\xCE\xA2\x54" + "\x10\x7F\x50\xDE\x69\x77\xD5\x37" + "\xFE\x9C\x10\x83\xC5\xEB\xC9\x53" + "\xB7\xF3\xC4\x20\xAF\x0A\x7E\x57" + "\x3A\xE6\x75\xFE\x89\x00\x6E\x48" + "\xFB\x99\x17\x2C\xF6\x64\x40\x95" + "\x5E\xDC\x7A\xA6\x70\xC7\xF4\xDD" + "\x52\x05\x24\x34\xF9\x0E\xC8\x64" + "\x6D\xE2\xD8\x80\x53\x31\x4C\xFE" + "\xB4\x3A\x5F\x19\xCF\x42\x1B\x22" + "\x0B\x2D\x7B\xF1\xC5\x43\xF7\x5E" + "\x12\xA8\x01\x64\x16\x0B\x26\x5A" + "\x0C\x95\x0F\x40\xC5\x5A\x06\x7C", + .rlen = 496, }, }; @@ -13364,8 +16729,144 @@ static struct cipher_testvec camellia_ctr_dec_tv_template[] = { "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" "\xDF\x76\x0D", .rlen = 51, + .also_non_np = 1, + .np = 2, + .tap = { 51 - 16, 16 }, + }, { /* 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 = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD", + .input = "\x85\x79\x6C\x8B\x2B\x6D\x14\xF9" + "\xA6\x83\xB6\x80\x5B\x3A\xF3\x7E" + "\x30\x29\xEB\x1F\xDC\x19\x5F\xEB" + "\xF7\xC4\x27\x04\x51\x87\xD7\x6F" + "\xB8\x4E\x07\xFB\xAC\x3B\x08\xB4" + "\x4D\xCB\xE8\xE1\x71\x7D\x4F\x48" + "\xCD\x81\x64\xA5\xC4\x07\x1A\x9A" + "\x4B\x62\x90\x0E\xC8\xB3\x2B\x6B" + "\x8F\x9C\x6E\x72\x4B\xBA\xEF\x07" + "\x2C\x56\x07\x5E\x37\x30\x60\xA9" + "\xE3\xEF\xD6\x69\xE1\xA1\x77\x64" + "\x93\x75\x7A\xB7\x7A\x3B\xE9\x43" + "\x23\x35\x95\x91\x80\x8A\xC7\xCF" + "\xC3\xD5\xBF\xE7\xFE\x4C\x06\x6B" + "\x05\x19\x48\xE2\x62\xBA\x4F\xF2" + "\xFB\xEE\xE4\xCB\x79\x9D\xA3\x10" + "\x1D\x29\x8C\x1D\x7A\x88\x5A\xDD" + "\x4E\xB6\x18\xAA\xCD\xE6\x33\x96" + "\xD9\x0F\x90\x5A\x78\x76\x4D\x77" + "\x3C\x20\x89\x3B\xA3\xF9\x07\xFD" + "\xE4\xE8\x20\x2D\x15\x0A\x63\x49" + "\xF5\x4F\x89\xD8\xDE\xA1\x28\x78" + "\x28\x07\x09\x1B\x03\x94\x1D\x4B" + "\x82\x28\x1E\x1D\x95\xBA\xAC\x85" + "\x71\x6E\x3C\x18\x4B\x77\x74\x79" + "\xBF\x67\x0A\x53\x3C\x94\xD9\x60" + "\xE9\x6D\x40\x34\xA0\x2A\x53\x5D" + "\x27\xD5\x47\xF9\xC3\x4B\x27\x29" + "\xE4\x76\x9C\x3F\xA7\x1C\x87\xFC" + "\x6E\x0F\xCF\x9B\x60\xF0\xF0\x8B" + "\x70\x1C\x84\x81\x72\x4D\xB4\x98" + "\x23\x62\xE7\x6A\x2B\xFC\xA5\xB2" + "\xFF\xF5\x71\x07\xCD\x90\x23\x13" + "\x19\xD7\x79\x36\x6C\x9D\x55\x8B" + "\x93\x78\x86\x05\x69\x46\xD0\xC5" + "\x39\x09\xEB\x79\xEF\xFA\x9F\xAE" + "\xF3\xD5\x44\xC3\xFD\x86\xD2\x7C" + "\x83\x4B\xD8\x75\x9C\x18\x04\x7B" + "\x73\xAD\x72\xA4\xF6\xAB\xCF\x4B" + "\xCC\x01\x45\x90\xA6\x43\x05\x0C" + "\x6C\x4F\x62\x77\x57\x97\x9F\xEE" + "\x75\xA7\x3C\x38\xD1\x0F\x3D\x0E" + "\x2C\x43\x98\xFB\x13\x65\x73\xE4" + "\x3C\x1E\xD6\x90\x08\xF7\xE0\x99" + "\x3B\xF1\x9D\x6C\x48\xA9\x0E\x32" + "\x17\xC2\xCC\x20\xA1\x19\x26\xAA" + "\xE0\x75\x2F\xFB\x54\x66\x0A\xDF" + "\xB5\xF2\x1F\xC1\x34\x3C\x30\x56" + "\xE8\xDC\xF7\x92\x6B\xBF\x17\x24" + "\xEC\x94\xB5\x3B\xD6\xCE\xA2\x54" + "\x10\x7F\x50\xDE\x69\x77\xD5\x37" + "\xFE\x9C\x10\x83\xC5\xEB\xC9\x53" + "\xB7\xF3\xC4\x20\xAF\x0A\x7E\x57" + "\x3A\xE6\x75\xFE\x89\x00\x6E\x48" + "\xFB\x99\x17\x2C\xF6\x64\x40\x95" + "\x5E\xDC\x7A\xA6\x70\xC7\xF4\xDD" + "\x52\x05\x24\x34\xF9\x0E\xC8\x64" + "\x6D\xE2\xD8\x80\x53\x31\x4C\xFE" + "\xB4\x3A\x5F\x19\xCF\x42\x1B\x22" + "\x0B\x2D\x7B\xF1\xC5\x43\xF7\x5E" + "\x12\xA8\x01\x64\x16\x0B\x26\x5A" + "\x0C\x95\x0F\x40\xC5\x5A\x06\x7C", + .ilen = 496, + .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\x81\x18\xAF\x23\xBA" + "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C" + "\xC3\x37\xCE\x65\xFC\x70\x07\x9E" + "\x12\xA9\x40\xD7\x4B\xE2\x79\x10" + "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F" + "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1" + "\x68\xFF\x73\x0A\xA1\x15\xAC\x43" + "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5" + "\x29\xC0\x57\xEE\x62\xF9\x90\x04" + "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76" + "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8" + "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A" + "\xF1\x65\xFC\x93\x07\x9E\x35\xCC" + "\x40\xD7\x6E\x05\x79\x10\xA7\x1B" + "\xB2\x49\xE0\x54\xEB\x82\x19\x8D" + "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF" + "\x96\x0A\xA1\x38\xCF\x43\xDA\x71" + "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3" + "\x57\xEE\x85\x1C\x90\x27\xBE\x32" + "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4" + "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16" + "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88" + "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA" + "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49" + "\xE0\x77\x0E\x82\x19\xB0\x24\xBB" + "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D" + "\xC4\x38\xCF\x66\xFD\x71\x08\x9F" + "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11" + "\x85\x1C\xB3\x27\xBE\x55\xEC\x60" + "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2" + "\x69\x00\x74\x0B\xA2\x16\xAD\x44" + "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6" + "\x2A\xC1\x58\xEF\x63\xFA\x91\x05" + "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77" + "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9" + "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B" + "\xF2\x66\xFD\x94\x08\x9F\x36\xCD" + "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C" + "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E" + "\x25\xBC\x30\xC7\x5E\xF5\x69\x00" + "\x97\x0B\xA2\x39\xD0\x44\xDB\x72" + "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4" + "\x58\xEF\x86\x1D\x91\x28\xBF\x33" + "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5" + "\x3C\xD3\x47\xDE\x75\x0C\x80\x17" + "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89" + "\x20\x94\x2B\xC2\x36\xCD\x64\xFB" + "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A" + "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC" + "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E" + "\xC5\x39\xD0\x67\xFE\x72\x09\xA0" + "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12" + "\x86\x1D\xB4\x28\xBF\x56\xED\x61" + "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3" + "\x6A\x01\x75\x0C\xA3\x17\xAE\x45" + "\xDC\x50\xE7\x7E\x15\x89\x20\xB7", + .rlen = 496, }, - }; static struct cipher_testvec camellia_lrw_enc_tv_template[] = { @@ -13614,6 +17115,9 @@ static struct cipher_testvec camellia_lrw_enc_tv_template[] = { "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9" "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -13864,6 +17368,9 @@ static struct cipher_testvec camellia_lrw_dec_tv_template[] = { "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" "\x21\xc4\xc2\x75\x67\x89\x37\x0a", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -14203,6 +17710,9 @@ static struct cipher_testvec camellia_xts_enc_tv_template[] = { "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e" "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; @@ -14543,6 +18053,9 @@ static struct cipher_testvec camellia_xts_dec_tv_template[] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", .rlen = 512, + .also_non_np = 1, + .np = 2, + .tap = { 512 - 16, 16 }, }, }; diff --git a/crypto/tgr192.c b/crypto/tgr192.c index cbca4f208c9f..87403556fd0b 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -628,7 +628,7 @@ static int tgr128_final(struct shash_desc *desc, u8 * out) return 0; } -static struct shash_alg tgr192 = { +static struct shash_alg tgr_algs[3] = { { .digestsize = TGR192_DIGEST_SIZE, .init = tgr192_init, .update = tgr192_update, @@ -640,9 +640,7 @@ static struct shash_alg tgr192 = { .cra_blocksize = TGR192_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg tgr160 = { +}, { .digestsize = TGR160_DIGEST_SIZE, .init = tgr192_init, .update = tgr192_update, @@ -654,9 +652,7 @@ static struct shash_alg tgr160 = { .cra_blocksize = TGR192_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg tgr128 = { +}, { .digestsize = TGR128_DIGEST_SIZE, .init = tgr192_init, .update = tgr192_update, @@ -668,38 +664,16 @@ static struct shash_alg tgr128 = { .cra_blocksize = TGR192_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init tgr192_mod_init(void) { - int ret = 0; - - ret = crypto_register_shash(&tgr192); - - if (ret < 0) { - goto out; - } - - ret = crypto_register_shash(&tgr160); - if (ret < 0) { - crypto_unregister_shash(&tgr192); - goto out; - } - - ret = crypto_register_shash(&tgr128); - if (ret < 0) { - crypto_unregister_shash(&tgr192); - crypto_unregister_shash(&tgr160); - } - out: - return ret; + return crypto_register_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); } static void __exit tgr192_mod_fini(void) { - crypto_unregister_shash(&tgr192); - crypto_unregister_shash(&tgr160); - crypto_unregister_shash(&tgr128); + crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs)); } MODULE_ALIAS("tgr160"); diff --git a/crypto/twofish_generic.c b/crypto/twofish_generic.c index 1f07b843e07c..2d5000552d0f 100644 --- a/crypto/twofish_generic.c +++ b/crypto/twofish_generic.c @@ -188,7 +188,6 @@ static struct crypto_alg alg = { .cra_ctxsize = sizeof(struct twofish_ctx), .cra_alignmask = 3, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = TF_MIN_KEY_SIZE, .cia_max_keysize = TF_MAX_KEY_SIZE, diff --git a/crypto/vmac.c b/crypto/vmac.c index 4243905ba135..f2338ca98368 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -38,11 +38,11 @@ * Constants and masks */ #define UINT64_C(x) x##ULL -const u64 p64 = UINT64_C(0xfffffffffffffeff); /* 2^64 - 257 prime */ -const u64 m62 = UINT64_C(0x3fffffffffffffff); /* 62-bit mask */ -const u64 m63 = UINT64_C(0x7fffffffffffffff); /* 63-bit mask */ -const u64 m64 = UINT64_C(0xffffffffffffffff); /* 64-bit mask */ -const u64 mpoly = UINT64_C(0x1fffffff1fffffff); /* Poly key mask */ +static const u64 p64 = UINT64_C(0xfffffffffffffeff); /* 2^64 - 257 prime */ +static const u64 m62 = UINT64_C(0x3fffffffffffffff); /* 62-bit mask */ +static const u64 m63 = UINT64_C(0x7fffffffffffffff); /* 63-bit mask */ +static const u64 m64 = UINT64_C(0xffffffffffffffff); /* 64-bit mask */ +static const u64 mpoly = UINT64_C(0x1fffffff1fffffff); /* Poly key mask */ #define pe64_to_cpup le64_to_cpup /* Prefer little endian */ diff --git a/crypto/wp512.c b/crypto/wp512.c index 71719a2be25a..180f1d6e03f4 100644 --- a/crypto/wp512.c +++ b/crypto/wp512.c @@ -1119,7 +1119,7 @@ static int wp256_final(struct shash_desc *desc, u8 *out) return 0; } -static struct shash_alg wp512 = { +static struct shash_alg wp_algs[3] = { { .digestsize = WP512_DIGEST_SIZE, .init = wp512_init, .update = wp512_update, @@ -1131,9 +1131,7 @@ static struct shash_alg wp512 = { .cra_blocksize = WP512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg wp384 = { +}, { .digestsize = WP384_DIGEST_SIZE, .init = wp512_init, .update = wp512_update, @@ -1145,9 +1143,7 @@ static struct shash_alg wp384 = { .cra_blocksize = WP512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; - -static struct shash_alg wp256 = { +}, { .digestsize = WP256_DIGEST_SIZE, .init = wp512_init, .update = wp512_update, @@ -1159,39 +1155,16 @@ static struct shash_alg wp256 = { .cra_blocksize = WP512_BLOCK_SIZE, .cra_module = THIS_MODULE, } -}; +} }; static int __init wp512_mod_init(void) { - int ret = 0; - - ret = crypto_register_shash(&wp512); - - if (ret < 0) - goto out; - - ret = crypto_register_shash(&wp384); - if (ret < 0) - { - crypto_unregister_shash(&wp512); - goto out; - } - - ret = crypto_register_shash(&wp256); - if (ret < 0) - { - crypto_unregister_shash(&wp512); - crypto_unregister_shash(&wp384); - } -out: - return ret; + return crypto_register_shashes(wp_algs, ARRAY_SIZE(wp_algs)); } static void __exit wp512_mod_fini(void) { - crypto_unregister_shash(&wp512); - crypto_unregister_shash(&wp384); - crypto_unregister_shash(&wp256); + crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs)); } MODULE_ALIAS("wp384"); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 2059ee460b0c..81e44f7b0ab6 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1567,7 +1567,7 @@ tx_complete++; /*--------------------------------- entries ---------------------------------*/ -static const char *media_name[] __devinitdata = { +static char * const media_name[] __devinitconst = { "MMF", "SMF", "MMF", "03?", /* 0- 3 */ "UTP", "05?", "06?", "07?", /* 4- 7 */ "TAXI","09?", "10?", "11?", /* 8-11 */ diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index e85763de928f..81541452887b 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -58,7 +58,6 @@ static noinline long fw_file_size(struct file *file) static bool fw_read_file_contents(struct file *file, struct firmware *fw) { - loff_t pos; long size; char *buf; @@ -68,8 +67,7 @@ static bool fw_read_file_contents(struct file *file, struct firmware *fw) buf = vmalloc(size); if (!buf) return false; - pos = 0; - if (vfs_read(file, buf, size, &pos) != size) { + if (kernel_read(file, 0, buf, size) != size) { vfree(buf); return false; } diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index db195abad698..d2ed7f18d1ac 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ -#define VERSION "47" +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ +#define VERSION "50" #define AOE_MAJOR 152 #define DEVICE_NAME "aoe" @@ -10,9 +10,6 @@ #define AOE_PARTITIONS (16) #endif -#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * NPERSHELF + (aoeminor)) -#define AOEMAJOR(sysminor) ((sysminor) / NPERSHELF) -#define AOEMINOR(sysminor) ((sysminor) % NPERSHELF) #define WHITESPACE " \t\v\f\n" enum { @@ -75,72 +72,67 @@ enum { DEVFL_UP = 1, /* device is installed in system and ready for AoE->ATA commands */ DEVFL_TKILL = (1<<1), /* flag for timer to know when to kill self */ DEVFL_EXT = (1<<2), /* device accepts lba48 commands */ - DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */ - DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */ - DEVFL_KICKME = (1<<5), /* slow polling network card catch */ - DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */ - - BUFFL_FAIL = 1, + DEVFL_GDALLOC = (1<<3), /* need to alloc gendisk */ + DEVFL_KICKME = (1<<4), /* slow polling network card catch */ + DEVFL_NEWSIZE = (1<<5), /* need to update dev size in block layer */ }; enum { DEFAULTBCNT = 2 * 512, /* 2 sectors */ - NPERSHELF = 16, /* number of slots per shelf address */ - FREETAG = -1, MIN_BUFS = 16, NTARGETS = 8, NAOEIFS = 8, - NSKBPOOLMAX = 128, + NSKBPOOLMAX = 256, + NFACTIVE = 61, TIMERTICK = HZ / 10, MINTIMER = HZ >> 2, MAXTIMER = HZ << 1, - HELPWAIT = 20, }; struct buf { - struct list_head bufs; - ulong stime; /* for disk stats */ - ulong flags; ulong nframesout; ulong resid; ulong bv_resid; - ulong bv_off; sector_t sector; struct bio *bio; struct bio_vec *bv; + struct request *rq; }; struct frame { - int tag; + struct list_head head; + u32 tag; ulong waited; + struct aoetgt *t; /* parent target I belong to */ + sector_t lba; + struct sk_buff *skb; /* command skb freed on module exit */ + struct sk_buff *r_skb; /* response skb for async processing */ struct buf *buf; - char *bufaddr; + struct bio_vec *bv; ulong bcnt; - sector_t lba; - struct sk_buff *skb; + ulong bv_off; }; struct aoeif { struct net_device *nd; - unsigned char lost; - unsigned char lostjumbo; - ushort maxbcnt; + ulong lost; + int bcnt; }; struct aoetgt { unsigned char addr[6]; ushort nframes; - struct frame *frames; + struct aoedev *d; /* parent device I belong to */ + struct list_head ffree; /* list of free frames */ struct aoeif ifs[NAOEIFS]; struct aoeif *ifp; /* current aoeif in use */ ushort nout; ushort maxout; - u16 lasttag; /* last tag sent */ - u16 useme; + ulong falloc; ulong lastwadj; /* last window adjustment */ + int minbcnt; int wpkts, rpkts; - int dataref; }; struct aoedev { @@ -153,6 +145,9 @@ struct aoedev { u16 rttavg; /* round trip average of requests/responses */ u16 mintimer; u16 fw_ver; /* version of blade's firmware */ + u16 lasttag; /* last tag sent */ + u16 useme; + ulong ref; struct work_struct work;/* disk create work struct */ struct gendisk *gd; struct request_queue *blkq; @@ -160,16 +155,31 @@ struct aoedev { sector_t ssize; struct timer_list timer; spinlock_t lock; - struct sk_buff_head sendq; struct sk_buff_head skbpool; mempool_t *bufpool; /* for deadlock-free Buf allocation */ - struct list_head bufq; /* queue of bios to work on */ - struct buf *inprocess; /* the one we're currently working on */ + struct { /* pointers to work in progress */ + struct buf *buf; + struct bio *nxbio; + struct request *rq; + } ip; + ulong maxbcnt; + struct list_head factive[NFACTIVE]; /* hash of active frames */ struct aoetgt *targets[NTARGETS]; struct aoetgt **tgt; /* target in use when working */ - struct aoetgt **htgt; /* target needing rexmit assistance */ + struct aoetgt *htgt; /* target needing rexmit assistance */ + ulong ntargets; + ulong kicked; }; +/* kthread tracking */ +struct ktstate { + struct completion rendez; + struct task_struct *task; + wait_queue_head_t *waitq; + int (*fn) (void); + char *name; + spinlock_t *lock; +}; int aoeblk_init(void); void aoeblk_exit(void); @@ -182,22 +192,29 @@ void aoechr_error(char *); void aoecmd_work(struct aoedev *d); void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor); -void aoecmd_ata_rsp(struct sk_buff *); +struct sk_buff *aoecmd_ata_rsp(struct sk_buff *); void aoecmd_cfg_rsp(struct sk_buff *); void aoecmd_sleepwork(struct work_struct *); void aoecmd_cleanslate(struct aoedev *); +void aoecmd_exit(void); +int aoecmd_init(void); struct sk_buff *aoecmd_ata_id(struct aoedev *); +void aoe_freetframe(struct frame *); +void aoe_flush_iocq(void); +void aoe_end_request(struct aoedev *, struct request *, int); +int aoe_ktstart(struct ktstate *k); +void aoe_ktstop(struct ktstate *k); int aoedev_init(void); void aoedev_exit(void); -struct aoedev *aoedev_by_aoeaddr(int maj, int min); -struct aoedev *aoedev_by_sysminor_m(ulong sysminor); +struct aoedev *aoedev_by_aoeaddr(ulong maj, int min, int do_alloc); void aoedev_downdev(struct aoedev *d); int aoedev_flush(const char __user *str, size_t size); +void aoe_failbuf(struct aoedev *, struct buf *); +void aoedev_put(struct aoedev *); int aoenet_init(void); void aoenet_exit(void); void aoenet_xmit(struct sk_buff_head *); int is_aoe_netif(struct net_device *ifp); int set_aoe_iflist(const char __user *str, size_t size); - diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 321de7b6c442..00dfc5008ad4 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ /* * aoeblk.c * block device routines @@ -161,68 +161,22 @@ aoeblk_release(struct gendisk *disk, fmode_t mode) } static void -aoeblk_make_request(struct request_queue *q, struct bio *bio) +aoeblk_request(struct request_queue *q) { - struct sk_buff_head queue; struct aoedev *d; - struct buf *buf; - ulong flags; - - blk_queue_bounce(q, &bio); - - if (bio == NULL) { - printk(KERN_ERR "aoe: bio is NULL\n"); - BUG(); - return; - } - d = bio->bi_bdev->bd_disk->private_data; - if (d == NULL) { - printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n"); - BUG(); - bio_endio(bio, -ENXIO); - return; - } else if (bio->bi_io_vec == NULL) { - printk(KERN_ERR "aoe: bi_io_vec is NULL\n"); - BUG(); - bio_endio(bio, -ENXIO); - return; - } - buf = mempool_alloc(d->bufpool, GFP_NOIO); - if (buf == NULL) { - printk(KERN_INFO "aoe: buf allocation failure\n"); - bio_endio(bio, -ENOMEM); - return; - } - memset(buf, 0, sizeof(*buf)); - INIT_LIST_HEAD(&buf->bufs); - buf->stime = jiffies; - buf->bio = bio; - buf->resid = bio->bi_size; - buf->sector = bio->bi_sector; - buf->bv = &bio->bi_io_vec[bio->bi_idx]; - buf->bv_resid = buf->bv->bv_len; - WARN_ON(buf->bv_resid == 0); - buf->bv_off = buf->bv->bv_offset; - - spin_lock_irqsave(&d->lock, flags); + struct request *rq; + d = q->queuedata; if ((d->flags & DEVFL_UP) == 0) { pr_info_ratelimited("aoe: device %ld.%d is not up\n", d->aoemajor, d->aoeminor); - spin_unlock_irqrestore(&d->lock, flags); - mempool_free(buf, d->bufpool); - bio_endio(bio, -ENXIO); + while ((rq = blk_peek_request(q))) { + blk_start_request(rq); + aoe_end_request(d, rq, 1); + } return; } - - list_add_tail(&buf->bufs, &d->bufq); - aoecmd_work(d); - __skb_queue_head_init(&queue); - skb_queue_splice_init(&d->sendq, &queue); - - spin_unlock_irqrestore(&d->lock, flags); - aoenet_xmit(&queue); } static int @@ -254,41 +208,54 @@ aoeblk_gdalloc(void *vp) { struct aoedev *d = vp; struct gendisk *gd; + mempool_t *mp; + struct request_queue *q; + enum { KB = 1024, MB = KB * KB, READ_AHEAD = 2 * MB, }; ulong flags; gd = alloc_disk(AOE_PARTITIONS); if (gd == NULL) { - printk(KERN_ERR - "aoe: cannot allocate disk structure for %ld.%d\n", + pr_err("aoe: cannot allocate disk structure for %ld.%d\n", d->aoemajor, d->aoeminor); goto err; } - d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache); - if (d->bufpool == NULL) { + mp = mempool_create(MIN_BUFS, mempool_alloc_slab, mempool_free_slab, + buf_pool_cache); + if (mp == NULL) { printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n", d->aoemajor, d->aoeminor); goto err_disk; } + q = blk_init_queue(aoeblk_request, &d->lock); + if (q == NULL) { + pr_err("aoe: cannot allocate block queue for %ld.%d\n", + d->aoemajor, d->aoeminor); + mempool_destroy(mp); + goto err_disk; + } d->blkq = blk_alloc_queue(GFP_KERNEL); if (!d->blkq) goto err_mempool; - blk_queue_make_request(d->blkq, aoeblk_make_request); d->blkq->backing_dev_info.name = "aoe"; if (bdi_init(&d->blkq->backing_dev_info)) goto err_blkq; spin_lock_irqsave(&d->lock, flags); + blk_queue_max_hw_sectors(d->blkq, BLK_DEF_MAX_SECTORS); + q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_CACHE_SIZE; + d->bufpool = mp; + d->blkq = gd->queue = q; + q->queuedata = d; + d->gd = gd; gd->major = AOE_MAJOR; - gd->first_minor = d->sysminor * AOE_PARTITIONS; + gd->first_minor = d->sysminor; gd->fops = &aoe_bdops; gd->private_data = d; set_capacity(gd, d->ssize); snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", d->aoemajor, d->aoeminor); - gd->queue = d->blkq; - d->gd = gd; d->flags &= ~DEVFL_GDALLOC; d->flags |= DEVFL_UP; diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index e86d2062a164..ed57a890c643 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ /* * aoechr.c * AoE character device driver @@ -86,34 +86,34 @@ revalidate(const char __user *str, size_t size) if (copy_from_user(buf, str, size)) return -EFAULT; - /* should be e%d.%d format */ n = sscanf(buf, "e%d.%d", &major, &minor); if (n != 2) { - printk(KERN_ERR "aoe: invalid device specification\n"); + pr_err("aoe: invalid device specification %s\n", buf); return -EINVAL; } - d = aoedev_by_aoeaddr(major, minor); + d = aoedev_by_aoeaddr(major, minor, 0); if (!d) return -EINVAL; spin_lock_irqsave(&d->lock, flags); aoecmd_cleanslate(d); + aoecmd_cfg(major, minor); loop: skb = aoecmd_ata_id(d); spin_unlock_irqrestore(&d->lock, flags); /* try again if we are able to sleep a bit, * otherwise give up this revalidation */ - if (!skb && !msleep_interruptible(200)) { + if (!skb && !msleep_interruptible(250)) { spin_lock_irqsave(&d->lock, flags); goto loop; } + aoedev_put(d); if (skb) { struct sk_buff_head queue; __skb_queue_head_init(&queue); __skb_queue_tail(&queue, skb); aoenet_xmit(&queue); } - aoecmd_cfg(major, minor); return 0; } @@ -174,6 +174,7 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp break; case MINOR_FLUSH: ret = aoedev_flush(buf, cnt); + break; } if (ret == 0) ret = cnt; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 887f68f6d79a..3804a0af3ef1 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ /* * aoecmd.c * Filesystem request handling methods @@ -12,10 +12,19 @@ #include <linux/netdevice.h> #include <linux/genhd.h> #include <linux/moduleparam.h> +#include <linux/workqueue.h> +#include <linux/kthread.h> #include <net/net_namespace.h> #include <asm/unaligned.h> +#include <linux/uio.h> #include "aoe.h" +#define MAXIOC (8192) /* default meant to avoid most soft lockups */ + +static void ktcomplete(struct frame *, struct sk_buff *); + +static struct buf *nextbuf(struct aoedev *); + static int aoe_deadsecs = 60 * 3; module_param(aoe_deadsecs, int, 0644); MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev."); @@ -25,6 +34,15 @@ module_param(aoe_maxout, int, 0644); MODULE_PARM_DESC(aoe_maxout, "Only aoe_maxout outstanding packets for every MAC on eX.Y."); +static wait_queue_head_t ktiowq; +static struct ktstate kts; + +/* io completion queue */ +static struct { + struct list_head head; + spinlock_t lock; +} iocq; + static struct sk_buff * new_skb(ulong len) { @@ -41,15 +59,21 @@ new_skb(ulong len) } static struct frame * -getframe(struct aoetgt *t, int tag) +getframe(struct aoedev *d, u32 tag) { - struct frame *f, *e; + struct frame *f; + struct list_head *head, *pos, *nx; + u32 n; - f = t->frames; - e = f + t->nframes; - for (; f<e; f++) - if (f->tag == tag) + n = tag % NFACTIVE; + head = &d->factive[n]; + list_for_each_safe(pos, nx, head) { + f = list_entry(pos, struct frame, head); + if (f->tag == tag) { + list_del(pos); return f; + } + } return NULL; } @@ -59,18 +83,18 @@ getframe(struct aoetgt *t, int tag) * This driver reserves tag -1 to mean "unused frame." */ static int -newtag(struct aoetgt *t) +newtag(struct aoedev *d) { register ulong n; n = jiffies & 0xffff; - return n |= (++t->lasttag & 0x7fff) << 16; + return n |= (++d->lasttag & 0x7fff) << 16; } -static int +static u32 aoehdr_atainit(struct aoedev *d, struct aoetgt *t, struct aoe_hdr *h) { - u32 host_tag = newtag(t); + u32 host_tag = newtag(d); memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); memcpy(h->dst, t->addr, sizeof h->dst); @@ -95,16 +119,18 @@ put_lba(struct aoe_atahdr *ah, sector_t lba) ah->lba5 = lba >>= 8; } -static void +static struct aoeif * ifrotate(struct aoetgt *t) { - t->ifp++; - if (t->ifp >= &t->ifs[NAOEIFS] || t->ifp->nd == NULL) - t->ifp = t->ifs; - if (t->ifp->nd == NULL) { - printk(KERN_INFO "aoe: no interface to rotate to\n"); - BUG(); - } + struct aoeif *ifp; + + ifp = t->ifp; + ifp++; + if (ifp >= &t->ifs[NAOEIFS] || ifp->nd == NULL) + ifp = t->ifs; + if (ifp->nd == NULL) + return NULL; + return t->ifp = ifp; } static void @@ -129,78 +155,128 @@ skb_pool_get(struct aoedev *d) return NULL; } -/* freeframe is where we do our load balancing so it's a little hairy. */ +void +aoe_freetframe(struct frame *f) +{ + struct aoetgt *t; + + t = f->t; + f->buf = NULL; + f->bv = NULL; + f->r_skb = NULL; + list_add(&f->head, &t->ffree); +} + static struct frame * -freeframe(struct aoedev *d) +newtframe(struct aoedev *d, struct aoetgt *t) { - struct frame *f, *e, *rf; - struct aoetgt **t; + struct frame *f; struct sk_buff *skb; + struct list_head *pos; + + if (list_empty(&t->ffree)) { + if (t->falloc >= NSKBPOOLMAX*2) + return NULL; + f = kcalloc(1, sizeof(*f), GFP_ATOMIC); + if (f == NULL) + return NULL; + t->falloc++; + f->t = t; + } else { + pos = t->ffree.next; + list_del(pos); + f = list_entry(pos, struct frame, head); + } + + skb = f->skb; + if (skb == NULL) { + f->skb = skb = new_skb(ETH_ZLEN); + if (!skb) { +bail: aoe_freetframe(f); + return NULL; + } + } + + if (atomic_read(&skb_shinfo(skb)->dataref) != 1) { + skb = skb_pool_get(d); + if (skb == NULL) + goto bail; + skb_pool_put(d, f->skb); + f->skb = skb; + } + + skb->truesize -= skb->data_len; + skb_shinfo(skb)->nr_frags = skb->data_len = 0; + skb_trim(skb, 0); + return f; +} + +static struct frame * +newframe(struct aoedev *d) +{ + struct frame *f; + struct aoetgt *t, **tt; + int totout = 0; if (d->targets[0] == NULL) { /* shouldn't happen, but I'm paranoid */ printk(KERN_ERR "aoe: NULL TARGETS!\n"); return NULL; } - t = d->tgt; - t++; - if (t >= &d->targets[NTARGETS] || !*t) - t = d->targets; + tt = d->tgt; /* last used target */ for (;;) { - if ((*t)->nout < (*t)->maxout + tt++; + if (tt >= &d->targets[NTARGETS] || !*tt) + tt = d->targets; + t = *tt; + totout += t->nout; + if (t->nout < t->maxout && t != d->htgt - && (*t)->ifp->nd) { - rf = NULL; - f = (*t)->frames; - e = f + (*t)->nframes; - for (; f < e; f++) { - if (f->tag != FREETAG) - continue; - skb = f->skb; - if (!skb - && !(f->skb = skb = new_skb(ETH_ZLEN))) - continue; - if (atomic_read(&skb_shinfo(skb)->dataref) - != 1) { - if (!rf) - rf = f; - continue; - } -gotone: skb_shinfo(skb)->nr_frags = skb->data_len = 0; - skb_trim(skb, 0); - d->tgt = t; - ifrotate(*t); + && t->ifp->nd) { + f = newtframe(d, t); + if (f) { + ifrotate(t); + d->tgt = tt; return f; } - /* Work can be done, but the network layer is - holding our precious packets. Try to grab - one from the pool. */ - f = rf; - if (f == NULL) { /* more paranoia */ - printk(KERN_ERR - "aoe: freeframe: %s.\n", - "unexpected null rf"); - d->flags |= DEVFL_KICKME; - return NULL; - } - skb = skb_pool_get(d); - if (skb) { - skb_pool_put(d, f->skb); - f->skb = skb; - goto gotone; - } - (*t)->dataref++; - if ((*t)->nout == 0) - d->flags |= DEVFL_KICKME; } - if (t == d->tgt) /* we've looped and found nada */ + if (tt == d->tgt) /* we've looped and found nada */ break; - t++; - if (t >= &d->targets[NTARGETS] || !*t) - t = d->targets; + } + if (totout == 0) { + d->kicked++; + d->flags |= DEVFL_KICKME; } return NULL; } +static void +skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt) +{ + int frag = 0; + ulong fcnt; +loop: + fcnt = bv->bv_len - (off - bv->bv_offset); + if (fcnt > cnt) + fcnt = cnt; + skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt); + cnt -= fcnt; + if (cnt <= 0) + return; + bv++; + off = bv->bv_offset; + goto loop; +} + +static void +fhash(struct frame *f) +{ + struct aoedev *d = f->t->d; + u32 n; + + n = f->tag % NFACTIVE; + list_add_tail(&f->head, &d->factive[n]); +} + static int aoecmd_ata_rw(struct aoedev *d) { @@ -208,26 +284,47 @@ aoecmd_ata_rw(struct aoedev *d) struct aoe_hdr *h; struct aoe_atahdr *ah; struct buf *buf; - struct bio_vec *bv; struct aoetgt *t; struct sk_buff *skb; - ulong bcnt; + struct sk_buff_head queue; + ulong bcnt, fbcnt; char writebit, extbit; writebit = 0x10; extbit = 0x4; - f = freeframe(d); + buf = nextbuf(d); + if (buf == NULL) + return 0; + f = newframe(d); if (f == NULL) return 0; t = *d->tgt; - buf = d->inprocess; - bv = buf->bv; - bcnt = t->ifp->maxbcnt; + bcnt = d->maxbcnt; if (bcnt == 0) bcnt = DEFAULTBCNT; - if (bcnt > buf->bv_resid) - bcnt = buf->bv_resid; + if (bcnt > buf->resid) + bcnt = buf->resid; + fbcnt = bcnt; + f->bv = buf->bv; + f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid); + do { + if (fbcnt < buf->bv_resid) { + buf->bv_resid -= fbcnt; + buf->resid -= fbcnt; + break; + } + fbcnt -= buf->bv_resid; + buf->resid -= buf->bv_resid; + if (buf->resid == 0) { + d->ip.buf = NULL; + break; + } + buf->bv++; + buf->bv_resid = buf->bv->bv_len; + WARN_ON(buf->bv_resid == 0); + } while (fbcnt); + /* initialize the headers & frame */ skb = f->skb; h = (struct aoe_hdr *) skb_mac_header(skb); @@ -235,10 +332,10 @@ aoecmd_ata_rw(struct aoedev *d) skb_put(skb, sizeof *h + sizeof *ah); memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, t, h); + fhash(f); t->nout++; f->waited = 0; f->buf = buf; - f->bufaddr = page_address(bv->bv_page) + buf->bv_off; f->bcnt = bcnt; f->lba = buf->sector; @@ -253,10 +350,11 @@ aoecmd_ata_rw(struct aoedev *d) ah->lba3 |= 0xe0; /* LBA bit + obsolete 0xa0 */ } if (bio_data_dir(buf->bio) == WRITE) { - skb_fill_page_desc(skb, 0, bv->bv_page, buf->bv_off, bcnt); + skb_fillup(skb, f->bv, f->bv_off, bcnt); ah->aflags |= AOEAFL_WRITE; skb->len += bcnt; skb->data_len = bcnt; + skb->truesize += bcnt; t->wpkts++; } else { t->rpkts++; @@ -267,23 +365,15 @@ aoecmd_ata_rw(struct aoedev *d) /* mark all tracking fields and load out */ buf->nframesout += 1; - buf->bv_off += bcnt; - buf->bv_resid -= bcnt; - buf->resid -= bcnt; buf->sector += bcnt >> 9; - if (buf->resid == 0) { - d->inprocess = NULL; - } else if (buf->bv_resid == 0) { - buf->bv = ++bv; - buf->bv_resid = bv->bv_len; - WARN_ON(buf->bv_resid == 0); - buf->bv_off = bv->bv_offset; - } skb->dev = t->ifp->nd; skb = skb_clone(skb, GFP_ATOMIC); - if (skb) - __skb_queue_tail(&d->sendq, skb); + if (skb) { + __skb_queue_head_init(&queue); + __skb_queue_tail(&queue, skb); + aoenet_xmit(&queue); + } return 1; } @@ -330,17 +420,25 @@ cont: } static void -resend(struct aoedev *d, struct aoetgt *t, struct frame *f) +resend(struct aoedev *d, struct frame *f) { struct sk_buff *skb; + struct sk_buff_head queue; struct aoe_hdr *h; struct aoe_atahdr *ah; + struct aoetgt *t; char buf[128]; u32 n; - ifrotate(t); - n = newtag(t); + t = f->t; + n = newtag(d); skb = f->skb; + if (ifrotate(t) == NULL) { + /* probably can't happen, but set it up to fail anyway */ + pr_info("aoe: resend: no interfaces to rotate to.\n"); + ktcomplete(f, NULL); + return; + } h = (struct aoe_hdr *) skb_mac_header(skb); ah = (struct aoe_atahdr *) (h+1); @@ -351,39 +449,22 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f) aoechr_error(buf); f->tag = n; + fhash(f); h->tag = cpu_to_be32(n); memcpy(h->dst, t->addr, sizeof h->dst); memcpy(h->src, t->ifp->nd->dev_addr, sizeof h->src); - switch (ah->cmdstat) { - default: - break; - case ATA_CMD_PIO_READ: - case ATA_CMD_PIO_READ_EXT: - case ATA_CMD_PIO_WRITE: - case ATA_CMD_PIO_WRITE_EXT: - put_lba(ah, f->lba); - - n = f->bcnt; - if (n > DEFAULTBCNT) - n = DEFAULTBCNT; - ah->scnt = n >> 9; - if (ah->aflags & AOEAFL_WRITE) { - skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), - offset_in_page(f->bufaddr), n); - skb->len = sizeof *h + sizeof *ah + n; - skb->data_len = n; - } - } skb->dev = t->ifp->nd; skb = skb_clone(skb, GFP_ATOMIC); if (skb == NULL) return; - __skb_queue_tail(&d->sendq, skb); + __skb_queue_head_init(&queue); + __skb_queue_tail(&queue, skb); + aoenet_xmit(&queue); } static int -tsince(int tag) +tsince(u32 tag) { int n; @@ -407,58 +488,65 @@ getif(struct aoetgt *t, struct net_device *nd) return NULL; } -static struct aoeif * -addif(struct aoetgt *t, struct net_device *nd) -{ - struct aoeif *p; - - p = getif(t, NULL); - if (!p) - return NULL; - p->nd = nd; - p->maxbcnt = DEFAULTBCNT; - p->lost = 0; - p->lostjumbo = 0; - return p; -} - static void ejectif(struct aoetgt *t, struct aoeif *ifp) { struct aoeif *e; + struct net_device *nd; ulong n; + nd = ifp->nd; e = t->ifs + NAOEIFS - 1; n = (e - ifp) * sizeof *ifp; memmove(ifp, ifp+1, n); e->nd = NULL; + dev_put(nd); } static int sthtith(struct aoedev *d) { - struct frame *f, *e, *nf; + struct frame *f, *nf; + struct list_head *nx, *pos, *head; struct sk_buff *skb; - struct aoetgt *ht = *d->htgt; - - f = ht->frames; - e = f + ht->nframes; - for (; f < e; f++) { - if (f->tag == FREETAG) - continue; - nf = freeframe(d); - if (!nf) - return 0; - skb = nf->skb; - *nf = *f; - f->skb = skb; - f->tag = FREETAG; - nf->waited = 0; - ht->nout--; - (*d->tgt)->nout++; - resend(d, *d->tgt, nf); + struct aoetgt *ht = d->htgt; + int i; + + for (i = 0; i < NFACTIVE; i++) { + head = &d->factive[i]; + list_for_each_safe(pos, nx, head) { + f = list_entry(pos, struct frame, head); + if (f->t != ht) + continue; + + nf = newframe(d); + if (!nf) + return 0; + + /* remove frame from active list */ + list_del(pos); + + /* reassign all pertinent bits to new outbound frame */ + skb = nf->skb; + nf->skb = f->skb; + nf->buf = f->buf; + nf->bcnt = f->bcnt; + nf->lba = f->lba; + nf->bv = f->bv; + nf->bv_off = f->bv_off; + nf->waited = 0; + f->skb = skb; + aoe_freetframe(f); + ht->nout--; + nf->t->nout++; + resend(d, nf); + } } - /* he's clean, he's useless. take away his interfaces */ + /* We've cleaned up the outstanding so take away his + * interfaces so he won't be used. We should remove him from + * the target array here, but cleaning up a target is + * involved. PUNT! + */ memset(ht->ifs, 0, sizeof ht->ifs); d->htgt = NULL; return 1; @@ -477,13 +565,15 @@ ata_scnt(unsigned char *packet) { static void rexmit_timer(ulong vp) { - struct sk_buff_head queue; struct aoedev *d; struct aoetgt *t, **tt, **te; struct aoeif *ifp; - struct frame *f, *e; + struct frame *f; + struct list_head *head, *pos, *nx; + LIST_HEAD(flist); register long timeout; ulong flags, n; + int i; d = (struct aoedev *) vp; @@ -497,58 +587,22 @@ rexmit_timer(ulong vp) spin_unlock_irqrestore(&d->lock, flags); return; } - tt = d->targets; - te = tt + NTARGETS; - for (; tt < te && *tt; tt++) { - t = *tt; - f = t->frames; - e = f + t->nframes; - for (; f < e; f++) { - if (f->tag == FREETAG - || tsince(f->tag) < timeout) - continue; - n = f->waited += timeout; - n /= HZ; - if (n > aoe_deadsecs) { - /* waited too long. device failure. */ - aoedev_downdev(d); - break; - } - - if (n > HELPWAIT /* see if another target can help */ - && (tt != d->targets || d->targets[1])) - d->htgt = tt; - - if (t->nout == t->maxout) { - if (t->maxout > 1) - t->maxout--; - t->lastwadj = jiffies; - } - - ifp = getif(t, f->skb->dev); - if (ifp && ++ifp->lost > (t->nframes << 1) - && (ifp != t->ifs || t->ifs[1].nd)) { - ejectif(t, ifp); - ifp = NULL; - } - if (ata_scnt(skb_mac_header(f->skb)) > DEFAULTBCNT / 512 - && ifp && ++ifp->lostjumbo > (t->nframes << 1) - && ifp->maxbcnt != DEFAULTBCNT) { - printk(KERN_INFO - "aoe: e%ld.%d: " - "too many lost jumbo on " - "%s:%pm - " - "falling back to %d frames.\n", - d->aoemajor, d->aoeminor, - ifp->nd->name, t->addr, - DEFAULTBCNT); - ifp->maxbcnt = 0; - } - resend(d, t, f); + /* collect all frames to rexmit into flist */ + for (i = 0; i < NFACTIVE; i++) { + head = &d->factive[i]; + list_for_each_safe(pos, nx, head) { + f = list_entry(pos, struct frame, head); + if (tsince(f->tag) < timeout) + break; /* end of expired frames */ + /* move to flist for later processing */ + list_move_tail(pos, &flist); } - - /* window check */ + } + /* window check */ + tt = d->targets; + te = tt + d->ntargets; + for (; tt < te && (t = *tt); tt++) { if (t->nout == t->maxout && t->maxout < t->nframes && (jiffies - t->lastwadj)/HZ > 10) { @@ -557,45 +611,173 @@ rexmit_timer(ulong vp) } } - if (!skb_queue_empty(&d->sendq)) { + if (!list_empty(&flist)) { /* retransmissions necessary */ n = d->rttavg <<= 1; if (n > MAXTIMER) d->rttavg = MAXTIMER; } - if (d->flags & DEVFL_KICKME || d->htgt) { - d->flags &= ~DEVFL_KICKME; - aoecmd_work(d); + /* process expired frames */ + while (!list_empty(&flist)) { + pos = flist.next; + f = list_entry(pos, struct frame, head); + n = f->waited += timeout; + n /= HZ; + if (n > aoe_deadsecs) { + /* Waited too long. Device failure. + * Hang all frames on first hash bucket for downdev + * to clean up. + */ + list_splice(&flist, &d->factive[0]); + aoedev_downdev(d); + break; + } + list_del(pos); + + t = f->t; + if (n > aoe_deadsecs/2) + d->htgt = t; /* see if another target can help */ + + if (t->nout == t->maxout) { + if (t->maxout > 1) + t->maxout--; + t->lastwadj = jiffies; + } + + ifp = getif(t, f->skb->dev); + if (ifp && ++ifp->lost > (t->nframes << 1) + && (ifp != t->ifs || t->ifs[1].nd)) { + ejectif(t, ifp); + ifp = NULL; + } + resend(d, f); } - __skb_queue_head_init(&queue); - skb_queue_splice_init(&d->sendq, &queue); + if ((d->flags & DEVFL_KICKME || d->htgt) && d->blkq) { + d->flags &= ~DEVFL_KICKME; + d->blkq->request_fn(d->blkq); + } d->timer.expires = jiffies + TIMERTICK; add_timer(&d->timer); spin_unlock_irqrestore(&d->lock, flags); +} - aoenet_xmit(&queue); +static unsigned long +rqbiocnt(struct request *r) +{ + struct bio *bio; + unsigned long n = 0; + + __rq_for_each_bio(bio, r) + n++; + return n; +} + +/* This can be removed if we are certain that no users of the block + * layer will ever use zero-count pages in bios. Otherwise we have to + * protect against the put_page sometimes done by the network layer. + * + * See http://oss.sgi.com/archives/xfs/2007-01/msg00594.html for + * discussion. + * + * We cannot use get_page in the workaround, because it insists on a + * positive page count as a precondition. So we use _count directly. + */ +static void +bio_pageinc(struct bio *bio) +{ + struct bio_vec *bv; + struct page *page; + int i; + + bio_for_each_segment(bv, bio, i) { + page = bv->bv_page; + /* Non-zero page count for non-head members of + * compound pages is no longer allowed by the kernel, + * but this has never been seen here. + */ + if (unlikely(PageCompound(page))) + if (compound_trans_head(page) != page) { + pr_crit("page tail used for block I/O\n"); + BUG(); + } + atomic_inc(&page->_count); + } +} + +static void +bio_pagedec(struct bio *bio) +{ + struct bio_vec *bv; + int i; + + bio_for_each_segment(bv, bio, i) + atomic_dec(&bv->bv_page->_count); +} + +static void +bufinit(struct buf *buf, struct request *rq, struct bio *bio) +{ + struct bio_vec *bv; + + memset(buf, 0, sizeof(*buf)); + buf->rq = rq; + buf->bio = bio; + buf->resid = bio->bi_size; + buf->sector = bio->bi_sector; + bio_pageinc(bio); + buf->bv = bv = &bio->bi_io_vec[bio->bi_idx]; + buf->bv_resid = bv->bv_len; + WARN_ON(buf->bv_resid == 0); +} + +static struct buf * +nextbuf(struct aoedev *d) +{ + struct request *rq; + struct request_queue *q; + struct buf *buf; + struct bio *bio; + + q = d->blkq; + if (q == NULL) + return NULL; /* initializing */ + if (d->ip.buf) + return d->ip.buf; + rq = d->ip.rq; + if (rq == NULL) { + rq = blk_peek_request(q); + if (rq == NULL) + return NULL; + blk_start_request(rq); + d->ip.rq = rq; + d->ip.nxbio = rq->bio; + rq->special = (void *) rqbiocnt(rq); + } + buf = mempool_alloc(d->bufpool, GFP_ATOMIC); + if (buf == NULL) { + pr_err("aoe: nextbuf: unable to mempool_alloc!\n"); + return NULL; + } + bio = d->ip.nxbio; + bufinit(buf, rq, bio); + bio = bio->bi_next; + d->ip.nxbio = bio; + if (bio == NULL) + d->ip.rq = NULL; + return d->ip.buf = buf; } /* enters with d->lock held */ void aoecmd_work(struct aoedev *d) { - struct buf *buf; -loop: if (d->htgt && !sthtith(d)) return; - if (d->inprocess == NULL) { - if (list_empty(&d->bufq)) - return; - buf = container_of(d->bufq.next, struct buf, bufs); - list_del(d->bufq.next); - d->inprocess = buf; - } - if (aoecmd_ata_rw(d)) - goto loop; + while (aoecmd_ata_rw(d)) + ; } /* this function performs work that has been deferred until sleeping is OK @@ -604,28 +786,25 @@ void aoecmd_sleepwork(struct work_struct *work) { struct aoedev *d = container_of(work, struct aoedev, work); + struct block_device *bd; + u64 ssize; if (d->flags & DEVFL_GDALLOC) aoeblk_gdalloc(d); if (d->flags & DEVFL_NEWSIZE) { - struct block_device *bd; - unsigned long flags; - u64 ssize; - ssize = get_capacity(d->gd); bd = bdget_disk(d->gd, 0); - if (bd) { mutex_lock(&bd->bd_inode->i_mutex); i_size_write(bd->bd_inode, (loff_t)ssize<<9); mutex_unlock(&bd->bd_inode->i_mutex); bdput(bd); } - spin_lock_irqsave(&d->lock, flags); + spin_lock_irq(&d->lock); d->flags |= DEVFL_UP; d->flags &= ~DEVFL_NEWSIZE; - spin_unlock_irqrestore(&d->lock, flags); + spin_unlock_irq(&d->lock); } } @@ -718,163 +897,299 @@ gettgt(struct aoedev *d, char *addr) return NULL; } -static inline void -diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector) +static void +bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, long cnt) +{ + ulong fcnt; + char *p; + int soff = 0; +loop: + fcnt = bv->bv_len - (off - bv->bv_offset); + if (fcnt > cnt) + fcnt = cnt; + p = page_address(bv->bv_page) + off; + skb_copy_bits(skb, soff, p, fcnt); + soff += fcnt; + cnt -= fcnt; + if (cnt <= 0) + return; + bv++; + off = bv->bv_offset; + goto loop; +} + +void +aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) +{ + struct bio *bio; + int bok; + struct request_queue *q; + + q = d->blkq; + if (rq == d->ip.rq) + d->ip.rq = NULL; + do { + bio = rq->bio; + bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); + } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size)); + + /* cf. http://lkml.org/lkml/2006/10/31/28 */ + if (!fastfail) + q->request_fn(q); +} + +static void +aoe_end_buf(struct aoedev *d, struct buf *buf) +{ + struct request *rq; + unsigned long n; + + if (buf == d->ip.buf) + d->ip.buf = NULL; + rq = buf->rq; + bio_pagedec(buf->bio); + mempool_free(buf, d->bufpool); + n = (unsigned long) rq->special; + rq->special = (void *) --n; + if (n == 0) + aoe_end_request(d, rq, 0); +} + +static void +ktiocomplete(struct frame *f) { - unsigned long n_sect = bio->bi_size >> 9; - const int rw = bio_data_dir(bio); - struct hd_struct *part; - int cpu; + struct aoe_hdr *hin, *hout; + struct aoe_atahdr *ahin, *ahout; + struct buf *buf; + struct sk_buff *skb; + struct aoetgt *t; + struct aoeif *ifp; + struct aoedev *d; + long n; + + if (f == NULL) + return; + + t = f->t; + d = t->d; + + hout = (struct aoe_hdr *) skb_mac_header(f->skb); + ahout = (struct aoe_atahdr *) (hout+1); + buf = f->buf; + skb = f->r_skb; + if (skb == NULL) + goto noskb; /* just fail the buf. */ + + hin = (struct aoe_hdr *) skb->data; + skb_pull(skb, sizeof(*hin)); + ahin = (struct aoe_atahdr *) skb->data; + skb_pull(skb, sizeof(*ahin)); + if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ + pr_err("aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", + ahout->cmdstat, ahin->cmdstat, + d->aoemajor, d->aoeminor); +noskb: if (buf) + clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + goto badrsp; + } - cpu = part_stat_lock(); - part = disk_map_sector_rcu(disk, sector); + n = ahout->scnt << 9; + switch (ahout->cmdstat) { + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: + if (skb->len < n) { + pr_err("aoe: runt data size in read. skb->len=%d need=%ld\n", + skb->len, n); + clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + break; + } + bvcpy(f->bv, f->bv_off, skb, n); + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: + spin_lock_irq(&d->lock); + ifp = getif(t, skb->dev); + if (ifp) + ifp->lost = 0; + if (d->htgt == t) /* I'll help myself, thank you. */ + d->htgt = NULL; + spin_unlock_irq(&d->lock); + break; + case ATA_CMD_ID_ATA: + if (skb->len < 512) { + pr_info("aoe: runt data size in ataid. skb->len=%d\n", + skb->len); + break; + } + if (skb_linearize(skb)) + break; + spin_lock_irq(&d->lock); + ataid_complete(d, t, skb->data); + spin_unlock_irq(&d->lock); + break; + default: + pr_info("aoe: unrecognized ata command %2.2Xh for %d.%d\n", + ahout->cmdstat, + be16_to_cpu(get_unaligned(&hin->major)), + hin->minor); + } +badrsp: + spin_lock_irq(&d->lock); + + aoe_freetframe(f); + + if (buf && --buf->nframesout == 0 && buf->resid == 0) + aoe_end_buf(d, buf); + + aoecmd_work(d); + + spin_unlock_irq(&d->lock); + aoedev_put(d); + dev_kfree_skb(skb); +} + +/* Enters with iocq.lock held. + * Returns true iff responses needing processing remain. + */ +static int +ktio(void) +{ + struct frame *f; + struct list_head *pos; + int i; - part_stat_inc(cpu, part, ios[rw]); - part_stat_add(cpu, part, ticks[rw], duration); - part_stat_add(cpu, part, sectors[rw], n_sect); - part_stat_add(cpu, part, io_ticks, duration); + for (i = 0; ; ++i) { + if (i == MAXIOC) + return 1; + if (list_empty(&iocq.head)) + return 0; + pos = iocq.head.next; + list_del(pos); + spin_unlock_irq(&iocq.lock); + f = list_entry(pos, struct frame, head); + ktiocomplete(f); + spin_lock_irq(&iocq.lock); + } +} - part_stat_unlock(); +static int +kthread(void *vp) +{ + struct ktstate *k; + DECLARE_WAITQUEUE(wait, current); + int more; + + k = vp; + current->flags |= PF_NOFREEZE; + set_user_nice(current, -10); + complete(&k->rendez); /* tell spawner we're running */ + do { + spin_lock_irq(k->lock); + more = k->fn(); + if (!more) { + add_wait_queue(k->waitq, &wait); + __set_current_state(TASK_INTERRUPTIBLE); + } + spin_unlock_irq(k->lock); + if (!more) { + schedule(); + remove_wait_queue(k->waitq, &wait); + } else + cond_resched(); + } while (!kthread_should_stop()); + complete(&k->rendez); /* tell spawner we're stopping */ + return 0; } void +aoe_ktstop(struct ktstate *k) +{ + kthread_stop(k->task); + wait_for_completion(&k->rendez); +} + +int +aoe_ktstart(struct ktstate *k) +{ + struct task_struct *task; + + init_completion(&k->rendez); + task = kthread_run(kthread, k, k->name); + if (task == NULL || IS_ERR(task)) + return -ENOMEM; + k->task = task; + wait_for_completion(&k->rendez); /* allow kthread to start */ + init_completion(&k->rendez); /* for waiting for exit later */ + return 0; +} + +/* pass it off to kthreads for processing */ +static void +ktcomplete(struct frame *f, struct sk_buff *skb) +{ + ulong flags; + + f->r_skb = skb; + spin_lock_irqsave(&iocq.lock, flags); + list_add_tail(&f->head, &iocq.head); + spin_unlock_irqrestore(&iocq.lock, flags); + wake_up(&ktiowq); +} + +struct sk_buff * aoecmd_ata_rsp(struct sk_buff *skb) { - struct sk_buff_head queue; struct aoedev *d; - struct aoe_hdr *hin, *hout; - struct aoe_atahdr *ahin, *ahout; + struct aoe_hdr *h; struct frame *f; - struct buf *buf; struct aoetgt *t; - struct aoeif *ifp; - register long n; + u32 n; ulong flags; char ebuf[128]; u16 aoemajor; - hin = (struct aoe_hdr *) skb_mac_header(skb); - aoemajor = get_unaligned_be16(&hin->major); - d = aoedev_by_aoeaddr(aoemajor, hin->minor); + h = (struct aoe_hdr *) skb->data; + aoemajor = be16_to_cpu(get_unaligned(&h->major)); + d = aoedev_by_aoeaddr(aoemajor, h->minor, 0); if (d == NULL) { snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " "for unknown device %d.%d\n", - aoemajor, hin->minor); + aoemajor, h->minor); aoechr_error(ebuf); - return; + return skb; } spin_lock_irqsave(&d->lock, flags); - n = get_unaligned_be32(&hin->tag); - t = gettgt(d, hin->src); - if (t == NULL) { - printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n", - d->aoemajor, d->aoeminor, hin->src); - spin_unlock_irqrestore(&d->lock, flags); - return; - } - f = getframe(t, n); + n = be32_to_cpu(get_unaligned(&h->tag)); + f = getframe(d, n); if (f == NULL) { calc_rttavg(d, -tsince(n)); spin_unlock_irqrestore(&d->lock, flags); + aoedev_put(d); snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", "unexpected rsp", - get_unaligned_be16(&hin->major), - hin->minor, - get_unaligned_be32(&hin->tag), + get_unaligned_be16(&h->major), + h->minor, + get_unaligned_be32(&h->tag), jiffies); aoechr_error(ebuf); - return; + return skb; } - + t = f->t; calc_rttavg(d, tsince(f->tag)); - - ahin = (struct aoe_atahdr *) (hin+1); - hout = (struct aoe_hdr *) skb_mac_header(f->skb); - ahout = (struct aoe_atahdr *) (hout+1); - buf = f->buf; - - if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */ - printk(KERN_ERR - "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%d\n", - ahout->cmdstat, ahin->cmdstat, - d->aoemajor, d->aoeminor); - if (buf) - buf->flags |= BUFFL_FAIL; - } else { - if (d->htgt && t == *d->htgt) /* I'll help myself, thank you. */ - d->htgt = NULL; - n = ahout->scnt << 9; - switch (ahout->cmdstat) { - case ATA_CMD_PIO_READ: - case ATA_CMD_PIO_READ_EXT: - if (skb->len - sizeof *hin - sizeof *ahin < n) { - printk(KERN_ERR - "aoe: %s. skb->len=%d need=%ld\n", - "runt data size in read", skb->len, n); - /* fail frame f? just returning will rexmit. */ - spin_unlock_irqrestore(&d->lock, flags); - return; - } - memcpy(f->bufaddr, ahin+1, n); - case ATA_CMD_PIO_WRITE: - case ATA_CMD_PIO_WRITE_EXT: - ifp = getif(t, skb->dev); - if (ifp) { - ifp->lost = 0; - if (n > DEFAULTBCNT) - ifp->lostjumbo = 0; - } - if (f->bcnt -= n) { - f->lba += n >> 9; - f->bufaddr += n; - resend(d, t, f); - goto xmit; - } - break; - case ATA_CMD_ID_ATA: - if (skb->len - sizeof *hin - sizeof *ahin < 512) { - printk(KERN_INFO - "aoe: runt data size in ataid. skb->len=%d\n", - skb->len); - spin_unlock_irqrestore(&d->lock, flags); - return; - } - ataid_complete(d, t, (char *) (ahin+1)); - break; - default: - printk(KERN_INFO - "aoe: unrecognized ata command %2.2Xh for %d.%d\n", - ahout->cmdstat, - get_unaligned_be16(&hin->major), - hin->minor); - } - } - - if (buf && --buf->nframesout == 0 && buf->resid == 0) { - diskstats(d->gd, buf->bio, jiffies - buf->stime, buf->sector); - if (buf->flags & BUFFL_FAIL) - bio_endio(buf->bio, -EIO); - else { - bio_flush_dcache_pages(buf->bio); - bio_endio(buf->bio, 0); - } - mempool_free(buf, d->bufpool); - } - - f->buf = NULL; - f->tag = FREETAG; t->nout--; - aoecmd_work(d); -xmit: - __skb_queue_head_init(&queue); - skb_queue_splice_init(&d->sendq, &queue); spin_unlock_irqrestore(&d->lock, flags); - aoenet_xmit(&queue); + + ktcomplete(f, skb); + + /* + * Note here that we do not perform an aoedev_put, as we are + * leaving this reference for the ktio to release. + */ + return NULL; } void @@ -896,7 +1211,7 @@ aoecmd_ata_id(struct aoedev *d) struct sk_buff *skb; struct aoetgt *t; - f = freeframe(d); + f = newframe(d); if (f == NULL) return NULL; @@ -909,6 +1224,7 @@ aoecmd_ata_id(struct aoedev *d) skb_put(skb, sizeof *h + sizeof *ah); memset(h, 0, skb->len); f->tag = aoehdr_atainit(d, t, h); + fhash(f); t->nout++; f->waited = 0; @@ -929,7 +1245,6 @@ static struct aoetgt * addtgt(struct aoedev *d, char *addr, ulong nframes) { struct aoetgt *t, **tt, **te; - struct frame *f, *e; tt = d->targets; te = tt + NTARGETS; @@ -941,26 +1256,73 @@ addtgt(struct aoedev *d, char *addr, ulong nframes) "aoe: device addtgt failure; too many targets\n"); return NULL; } - t = kcalloc(1, sizeof *t, GFP_ATOMIC); - f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); - if (!t || !f) { - kfree(f); - kfree(t); + t = kzalloc(sizeof(*t), GFP_ATOMIC); + if (!t) { printk(KERN_INFO "aoe: cannot allocate memory to add target\n"); return NULL; } + d->ntargets++; t->nframes = nframes; - t->frames = f; - e = f + nframes; - for (; f < e; f++) - f->tag = FREETAG; + t->d = d; memcpy(t->addr, addr, sizeof t->addr); t->ifp = t->ifs; t->maxout = t->nframes; + INIT_LIST_HEAD(&t->ffree); return *tt = t; } +static void +setdbcnt(struct aoedev *d) +{ + struct aoetgt **t, **e; + int bcnt = 0; + + t = d->targets; + e = t + NTARGETS; + for (; t < e && *t; t++) + if (bcnt == 0 || bcnt > (*t)->minbcnt) + bcnt = (*t)->minbcnt; + if (bcnt != d->maxbcnt) { + d->maxbcnt = bcnt; + pr_info("aoe: e%ld.%d: setting %d byte data frames\n", + d->aoemajor, d->aoeminor, bcnt); + } +} + +static void +setifbcnt(struct aoetgt *t, struct net_device *nd, int bcnt) +{ + struct aoedev *d; + struct aoeif *p, *e; + int minbcnt; + + d = t->d; + minbcnt = bcnt; + p = t->ifs; + e = p + NAOEIFS; + for (; p < e; p++) { + if (p->nd == NULL) + break; /* end of the valid interfaces */ + if (p->nd == nd) { + p->bcnt = bcnt; /* we're updating */ + nd = NULL; + } else if (minbcnt > p->bcnt) + minbcnt = p->bcnt; /* find the min interface */ + } + if (nd) { + if (p == e) { + pr_err("aoe: device setifbcnt failure; too many interfaces.\n"); + return; + } + dev_hold(nd); + p->nd = nd; + p->bcnt = bcnt; + } + t->minbcnt = minbcnt; + setdbcnt(d); +} + void aoecmd_cfg_rsp(struct sk_buff *skb) { @@ -968,11 +1330,12 @@ aoecmd_cfg_rsp(struct sk_buff *skb) struct aoe_hdr *h; struct aoe_cfghdr *ch; struct aoetgt *t; - struct aoeif *ifp; - ulong flags, sysminor, aoemajor; + ulong flags, aoemajor; struct sk_buff *sl; + struct sk_buff_head queue; u16 n; + sl = NULL; h = (struct aoe_hdr *) skb_mac_header(skb); ch = (struct aoe_cfghdr *) (h+1); @@ -986,10 +1349,13 @@ aoecmd_cfg_rsp(struct sk_buff *skb) "Check shelf dip switches.\n"); return; } - - sysminor = SYSMINOR(aoemajor, h->minor); - if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) { - printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n", + if (aoemajor == 0xffff) { + pr_info("aoe: e%ld.%d: broadcast shelf number invalid\n", + aoemajor, (int) h->minor); + return; + } + if (h->minor == 0xff) { + pr_info("aoe: e%ld.%d: broadcast slot number invalid\n", aoemajor, (int) h->minor); return; } @@ -998,9 +1364,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb) if (n > aoe_maxout) /* keep it reasonable */ n = aoe_maxout; - d = aoedev_by_sysminor_m(sysminor); + d = aoedev_by_aoeaddr(aoemajor, h->minor, 1); if (d == NULL) { - printk(KERN_INFO "aoe: device sysminor_m failure\n"); + pr_info("aoe: device allocation failure\n"); return; } @@ -1009,52 +1375,26 @@ aoecmd_cfg_rsp(struct sk_buff *skb) t = gettgt(d, h->src); if (!t) { t = addtgt(d, h->src, n); - if (!t) { - spin_unlock_irqrestore(&d->lock, flags); - return; - } - } - ifp = getif(t, skb->dev); - if (!ifp) { - ifp = addif(t, skb->dev); - if (!ifp) { - printk(KERN_INFO - "aoe: device addif failure; " - "too many interfaces?\n"); - spin_unlock_irqrestore(&d->lock, flags); - return; - } - } - if (ifp->maxbcnt) { - n = ifp->nd->mtu; - n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); - n /= 512; - if (n > ch->scnt) - n = ch->scnt; - n = n ? n * 512 : DEFAULTBCNT; - if (n != ifp->maxbcnt) { - printk(KERN_INFO - "aoe: e%ld.%d: setting %d%s%s:%pm\n", - d->aoemajor, d->aoeminor, n, - " byte data frames on ", ifp->nd->name, - t->addr); - ifp->maxbcnt = n; - } + if (!t) + goto bail; } + n = skb->dev->mtu; + n -= sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr); + n /= 512; + if (n > ch->scnt) + n = ch->scnt; + n = n ? n * 512 : DEFAULTBCNT; + setifbcnt(t, skb->dev, n); /* don't change users' perspective */ - if (d->nopen) { - spin_unlock_irqrestore(&d->lock, flags); - return; + if (d->nopen == 0) { + d->fw_ver = be16_to_cpu(ch->fwver); + sl = aoecmd_ata_id(d); } - d->fw_ver = be16_to_cpu(ch->fwver); - - sl = aoecmd_ata_id(d); - +bail: spin_unlock_irqrestore(&d->lock, flags); - + aoedev_put(d); if (sl) { - struct sk_buff_head queue; __skb_queue_head_init(&queue); __skb_queue_tail(&queue, sl); aoenet_xmit(&queue); @@ -1065,20 +1405,74 @@ void aoecmd_cleanslate(struct aoedev *d) { struct aoetgt **t, **te; - struct aoeif *p, *e; d->mintimer = MINTIMER; + d->maxbcnt = 0; t = d->targets; te = t + NTARGETS; - for (; t < te && *t; t++) { + for (; t < te && *t; t++) (*t)->maxout = (*t)->nframes; - p = (*t)->ifs; - e = p + NAOEIFS; - for (; p < e; p++) { - p->lostjumbo = 0; - p->lost = 0; - p->maxbcnt = DEFAULTBCNT; +} + +void +aoe_failbuf(struct aoedev *d, struct buf *buf) +{ + if (buf == NULL) + return; + buf->resid = 0; + clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + if (buf->nframesout == 0) + aoe_end_buf(d, buf); +} + +void +aoe_flush_iocq(void) +{ + struct frame *f; + struct aoedev *d; + LIST_HEAD(flist); + struct list_head *pos; + struct sk_buff *skb; + ulong flags; + + spin_lock_irqsave(&iocq.lock, flags); + list_splice_init(&iocq.head, &flist); + spin_unlock_irqrestore(&iocq.lock, flags); + while (!list_empty(&flist)) { + pos = flist.next; + list_del(pos); + f = list_entry(pos, struct frame, head); + d = f->t->d; + skb = f->r_skb; + spin_lock_irqsave(&d->lock, flags); + if (f->buf) { + f->buf->nframesout--; + aoe_failbuf(d, f->buf); } + aoe_freetframe(f); + spin_unlock_irqrestore(&d->lock, flags); + dev_kfree_skb(skb); + aoedev_put(d); } } + +int __init +aoecmd_init(void) +{ + INIT_LIST_HEAD(&iocq.head); + spin_lock_init(&iocq.lock); + init_waitqueue_head(&ktiowq); + kts.name = "aoe_ktio"; + kts.fn = ktio; + kts.waitq = &ktiowq; + kts.lock = &iocq.lock; + return aoe_ktstart(&kts); +} + +void +aoecmd_exit(void) +{ + aoe_ktstop(&kts); + aoe_flush_iocq(); +} diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index 6b5110a47458..90e5b537f94b 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ /* * aoedev.c * AoE device utility functions; maintains device list. @@ -9,6 +9,9 @@ #include <linux/netdevice.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/bitmap.h> +#include <linux/kdev_t.h> +#include <linux/moduleparam.h> #include "aoe.h" static void dummy_timer(ulong); @@ -16,23 +19,121 @@ static void aoedev_freedev(struct aoedev *); static void freetgt(struct aoedev *d, struct aoetgt *t); static void skbpoolfree(struct aoedev *d); +static int aoe_dyndevs = 1; +module_param(aoe_dyndevs, int, 0644); +MODULE_PARM_DESC(aoe_dyndevs, "Use dynamic minor numbers for devices."); + static struct aoedev *devlist; static DEFINE_SPINLOCK(devlist_lock); -struct aoedev * -aoedev_by_aoeaddr(int maj, int min) +/* Because some systems will have one, many, or no + * - partitions, + * - slots per shelf, + * - or shelves, + * we need some flexibility in the way the minor numbers + * are allocated. So they are dynamic. + */ +#define N_DEVS ((1U<<MINORBITS)/AOE_PARTITIONS) + +static DEFINE_SPINLOCK(used_minors_lock); +static DECLARE_BITMAP(used_minors, N_DEVS); + +static int +minor_get_dyn(ulong *sysminor) { - struct aoedev *d; ulong flags; + ulong n; + int error = 0; + + spin_lock_irqsave(&used_minors_lock, flags); + n = find_first_zero_bit(used_minors, N_DEVS); + if (n < N_DEVS) + set_bit(n, used_minors); + else + error = -1; + spin_unlock_irqrestore(&used_minors_lock, flags); + + *sysminor = n * AOE_PARTITIONS; + return error; +} - spin_lock_irqsave(&devlist_lock, flags); +static int +minor_get_static(ulong *sysminor, ulong aoemaj, int aoemin) +{ + ulong flags; + ulong n; + int error = 0; + enum { + /* for backwards compatibility when !aoe_dyndevs, + * a static number of supported slots per shelf */ + NPERSHELF = 16, + }; + + n = aoemaj * NPERSHELF + aoemin; + if (aoemin >= NPERSHELF || n >= N_DEVS) { + pr_err("aoe: %s with e%ld.%d\n", + "cannot use static minor device numbers", + aoemaj, aoemin); + error = -1; + } else { + spin_lock_irqsave(&used_minors_lock, flags); + if (test_bit(n, used_minors)) { + pr_err("aoe: %s %lu\n", + "existing device already has static minor number", + n); + error = -1; + } else + set_bit(n, used_minors); + spin_unlock_irqrestore(&used_minors_lock, flags); + } - for (d=devlist; d; d=d->next) - if (d->aoemajor == maj && d->aoeminor == min) - break; + *sysminor = n; + return error; +} + +static int +minor_get(ulong *sysminor, ulong aoemaj, int aoemin) +{ + if (aoe_dyndevs) + return minor_get_dyn(sysminor); + else + return minor_get_static(sysminor, aoemaj, aoemin); +} + +static void +minor_free(ulong minor) +{ + ulong flags; + + minor /= AOE_PARTITIONS; + BUG_ON(minor >= N_DEVS); + + spin_lock_irqsave(&used_minors_lock, flags); + BUG_ON(!test_bit(minor, used_minors)); + clear_bit(minor, used_minors); + spin_unlock_irqrestore(&used_minors_lock, flags); +} + +/* + * Users who grab a pointer to the device with aoedev_by_aoeaddr + * automatically get a reference count and must be responsible + * for performing a aoedev_put. With the addition of async + * kthread processing I'm no longer confident that we can + * guarantee consistency in the face of device flushes. + * + * For the time being, we only bother to add extra references for + * frames sitting on the iocq. When the kthreads finish processing + * these frames, they will aoedev_put the device. + */ + +void +aoedev_put(struct aoedev *d) +{ + ulong flags; + spin_lock_irqsave(&devlist_lock, flags); + d->ref--; spin_unlock_irqrestore(&devlist_lock, flags); - return d; } static void @@ -47,54 +148,74 @@ dummy_timer(ulong vp) add_timer(&d->timer); } +static void +aoe_failip(struct aoedev *d) +{ + struct request *rq; + struct bio *bio; + unsigned long n; + + aoe_failbuf(d, d->ip.buf); + + rq = d->ip.rq; + if (rq == NULL) + return; + while ((bio = d->ip.nxbio)) { + clear_bit(BIO_UPTODATE, &bio->bi_flags); + d->ip.nxbio = bio->bi_next; + n = (unsigned long) rq->special; + rq->special = (void *) --n; + } + if ((unsigned long) rq->special == 0) + aoe_end_request(d, rq, 0); +} + void aoedev_downdev(struct aoedev *d) { - struct aoetgt **t, **te; - struct frame *f, *e; - struct buf *buf; - struct bio *bio; + struct aoetgt *t, **tt, **te; + struct frame *f; + struct list_head *head, *pos, *nx; + struct request *rq; + int i; - t = d->targets; - te = t + NTARGETS; - for (; t < te && *t; t++) { - f = (*t)->frames; - e = f + (*t)->nframes; - for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) { - if (f->tag == FREETAG || f->buf == NULL) - continue; - buf = f->buf; - bio = buf->bio; - if (--buf->nframesout == 0 - && buf != d->inprocess) { - mempool_free(buf, d->bufpool); - bio_endio(bio, -EIO); + d->flags &= ~DEVFL_UP; + + /* clean out active buffers */ + for (i = 0; i < NFACTIVE; i++) { + head = &d->factive[i]; + list_for_each_safe(pos, nx, head) { + f = list_entry(pos, struct frame, head); + list_del(pos); + if (f->buf) { + f->buf->nframesout--; + aoe_failbuf(d, f->buf); } + aoe_freetframe(f); } - (*t)->maxout = (*t)->nframes; - (*t)->nout = 0; } - buf = d->inprocess; - if (buf) { - bio = buf->bio; - mempool_free(buf, d->bufpool); - bio_endio(bio, -EIO); + /* reset window dressings */ + tt = d->targets; + te = tt + NTARGETS; + for (; tt < te && (t = *tt); tt++) { + t->maxout = t->nframes; + t->nout = 0; } - d->inprocess = NULL; + + /* clean out the in-process request (if any) */ + aoe_failip(d); d->htgt = NULL; - while (!list_empty(&d->bufq)) { - buf = container_of(d->bufq.next, struct buf, bufs); - list_del(d->bufq.next); - bio = buf->bio; - mempool_free(buf, d->bufpool); - bio_endio(bio, -EIO); + /* fast fail all pending I/O */ + if (d->blkq) { + while ((rq = blk_peek_request(d->blkq))) { + blk_start_request(rq); + aoe_end_request(d, rq, 1); + } } if (d->gd) set_capacity(d->gd, 0); - - d->flags &= ~DEVFL_UP; } static void @@ -107,6 +228,7 @@ aoedev_freedev(struct aoedev *d) aoedisk_rm_sysfs(d); del_gendisk(d->gd); put_disk(d->gd); + blk_cleanup_queue(d->blkq); } t = d->targets; e = t + NTARGETS; @@ -115,7 +237,7 @@ aoedev_freedev(struct aoedev *d) if (d->bufpool) mempool_destroy(d->bufpool); skbpoolfree(d); - blk_cleanup_queue(d->blkq); + minor_free(d->sysminor); kfree(d); } @@ -142,7 +264,8 @@ aoedev_flush(const char __user *str, size_t cnt) spin_lock(&d->lock); if ((!all && (d->flags & DEVFL_UP)) || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE)) - || d->nopen) { + || d->nopen + || d->ref) { spin_unlock(&d->lock); dd = &d->next; continue; @@ -163,12 +286,15 @@ aoedev_flush(const char __user *str, size_t cnt) return 0; } -/* I'm not really sure that this is a realistic problem, but if the -network driver goes gonzo let's just leak memory after complaining. */ +/* This has been confirmed to occur once with Tms=3*1000 due to the + * driver changing link and not processing its transmit ring. The + * problem is hard enough to solve by returning an error that I'm + * still punting on "solving" this. + */ static void skbfree(struct sk_buff *skb) { - enum { Sms = 100, Tms = 3*1000}; + enum { Sms = 250, Tms = 30 * 1000}; int i = Tms / Sms; if (skb == NULL) @@ -182,6 +308,7 @@ skbfree(struct sk_buff *skb) "cannot free skb -- memory leaked."); return; } + skb->truesize -= skb->data_len; skb_shinfo(skb)->nr_frags = skb->data_len = 0; skb_trim(skb, 0); dev_kfree_skb(skb); @@ -198,26 +325,29 @@ skbpoolfree(struct aoedev *d) __skb_queue_head_init(&d->skbpool); } -/* find it or malloc it */ +/* find it or allocate it */ struct aoedev * -aoedev_by_sysminor_m(ulong sysminor) +aoedev_by_aoeaddr(ulong maj, int min, int do_alloc) { struct aoedev *d; + int i; ulong flags; + ulong sysminor; spin_lock_irqsave(&devlist_lock, flags); for (d=devlist; d; d=d->next) - if (d->sysminor == sysminor) + if (d->aoemajor == maj && d->aoeminor == min) { + d->ref++; break; - if (d) + } + if (d || !do_alloc || minor_get(&sysminor, maj, min) < 0) goto out; d = kcalloc(1, sizeof *d, GFP_ATOMIC); if (!d) goto out; INIT_WORK(&d->work, aoecmd_sleepwork); spin_lock_init(&d->lock); - skb_queue_head_init(&d->sendq); skb_queue_head_init(&d->skbpool); init_timer(&d->timer); d->timer.data = (ulong) d; @@ -226,10 +356,12 @@ aoedev_by_sysminor_m(ulong sysminor) add_timer(&d->timer); d->bufpool = NULL; /* defer to aoeblk_gdalloc */ d->tgt = d->targets; - INIT_LIST_HEAD(&d->bufq); + d->ref = 1; + for (i = 0; i < NFACTIVE; i++) + INIT_LIST_HEAD(&d->factive[i]); d->sysminor = sysminor; - d->aoemajor = AOEMAJOR(sysminor); - d->aoeminor = AOEMINOR(sysminor); + d->aoemajor = maj; + d->aoeminor = min; d->mintimer = MINTIMER; d->next = devlist; devlist = d; @@ -241,13 +373,23 @@ aoedev_by_sysminor_m(ulong sysminor) static void freetgt(struct aoedev *d, struct aoetgt *t) { - struct frame *f, *e; + struct frame *f; + struct list_head *pos, *nx, *head; + struct aoeif *ifp; - f = t->frames; - e = f + t->nframes; - for (; f < e; f++) + for (ifp = t->ifs; ifp < &t->ifs[NAOEIFS]; ++ifp) { + if (!ifp->nd) + break; + dev_put(ifp->nd); + } + + head = &t->ffree; + list_for_each_safe(pos, nx, head) { + list_del(pos); + f = list_entry(pos, struct frame, head); skbfree(f->skb); - kfree(t->frames); + kfree(f); + } kfree(t); } @@ -257,6 +399,7 @@ aoedev_exit(void) struct aoedev *d; ulong flags; + aoe_flush_iocq(); while ((d = devlist)) { devlist = d->next; diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c index 7f83ad90e76f..04793c2c701b 100644 --- a/drivers/block/aoe/aoemain.c +++ b/drivers/block/aoe/aoemain.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ /* * aoemain.c * Module initialization routines, discover timer @@ -61,6 +61,7 @@ aoe_exit(void) aoenet_exit(); unregister_blkdev(AOE_MAJOR, DEVICE_NAME); + aoecmd_exit(); aoechr_exit(); aoedev_exit(); aoeblk_exit(); /* free cache after de-allocating bufs */ @@ -83,17 +84,20 @@ aoe_init(void) ret = aoenet_init(); if (ret) goto net_fail; + ret = aoecmd_init(); + if (ret) + goto cmd_fail; ret = register_blkdev(AOE_MAJOR, DEVICE_NAME); if (ret < 0) { printk(KERN_ERR "aoe: can't register major\n"); goto blkreg_fail; } - printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION); discover_timer(TINIT); return 0; - blkreg_fail: + aoecmd_exit(); + cmd_fail: aoenet_exit(); net_fail: aoeblk_exit(); diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 4d3bc0d49df5..162c6471275c 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */ /* * aoenet.c * Ethernet portion of AoE driver @@ -33,6 +33,9 @@ static char aoe_iflist[IFLISTSZ]; module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\""); +static wait_queue_head_t txwq; +static struct ktstate kts; + #ifndef MODULE static int __init aoe_iflist_setup(char *str) { @@ -44,6 +47,23 @@ static int __init aoe_iflist_setup(char *str) __setup("aoe_iflist=", aoe_iflist_setup); #endif +static spinlock_t txlock; +static struct sk_buff_head skbtxq; + +/* enters with txlock held */ +static int +tx(void) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&skbtxq))) { + spin_unlock_irq(&txlock); + dev_queue_xmit(skb); + spin_lock_irq(&txlock); + } + return 0; +} + int is_aoe_netif(struct net_device *ifp) { @@ -88,10 +108,14 @@ void aoenet_xmit(struct sk_buff_head *queue) { struct sk_buff *skb, *tmp; + ulong flags; skb_queue_walk_safe(queue, skb, tmp) { __skb_unlink(skb, queue); - dev_queue_xmit(skb); + spin_lock_irqsave(&txlock, flags); + skb_queue_tail(&skbtxq, skb); + spin_unlock_irqrestore(&txlock, flags); + wake_up(&txwq); } } @@ -102,7 +126,9 @@ static int aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev) { struct aoe_hdr *h; + struct aoe_atahdr *ah; u32 n; + int sn; if (dev_net(ifp) != &init_net) goto exit; @@ -110,13 +136,16 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, skb = skb_share_check(skb, GFP_ATOMIC); if (skb == NULL) return 0; - if (skb_linearize(skb)) - goto exit; if (!is_aoe_netif(ifp)) goto exit; skb_push(skb, ETH_HLEN); /* (1) */ - - h = (struct aoe_hdr *) skb_mac_header(skb); + sn = sizeof(*h) + sizeof(*ah); + if (skb->len >= sn) { + sn -= skb_headlen(skb); + if (sn > 0 && !__pskb_pull_tail(skb, sn)) + goto exit; + } + h = (struct aoe_hdr *) skb->data; n = get_unaligned_be32(&h->tag); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; @@ -137,7 +166,8 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, switch (h->cmd) { case AOECMD_ATA: - aoecmd_ata_rsp(skb); + /* ata_rsp may keep skb for later processing or give it back */ + skb = aoecmd_ata_rsp(skb); break; case AOECMD_CFG: aoecmd_cfg_rsp(skb); @@ -145,8 +175,12 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, default: if (h->cmd >= AOECMD_VEND_MIN) break; /* don't complain about vendor commands */ - printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd); + pr_info("aoe: unknown AoE command type 0x%02x\n", h->cmd); + break; } + + if (!skb) + return 0; exit: dev_kfree_skb(skb); return 0; @@ -160,6 +194,15 @@ static struct packet_type aoe_pt __read_mostly = { int __init aoenet_init(void) { + skb_queue_head_init(&skbtxq); + init_waitqueue_head(&txwq); + spin_lock_init(&txlock); + kts.lock = &txlock; + kts.fn = tx; + kts.waitq = &txwq; + kts.name = "aoe_tx"; + if (aoe_ktstart(&kts)) + return -EAGAIN; dev_add_pack(&aoe_pt); return 0; } @@ -167,6 +210,8 @@ aoenet_init(void) void aoenet_exit(void) { + aoe_ktstop(&kts); + skb_queue_purge(&skbtxq); dev_remove_pack(&aoe_pt); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 0c03411c59eb..043ddcca4abf 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -78,6 +78,8 @@ static const char *ioctl_cmd_to_ascii(int cmd) case NBD_SET_SOCK: return "set-sock"; case NBD_SET_BLKSIZE: return "set-blksize"; case NBD_SET_SIZE: return "set-size"; + case NBD_SET_TIMEOUT: return "set-timeout"; + case NBD_SET_FLAGS: return "set-flags"; case NBD_DO_IT: return "do-it"; case NBD_CLEAR_SOCK: return "clear-sock"; case NBD_CLEAR_QUE: return "clear-que"; @@ -96,6 +98,7 @@ static const char *nbdcmd_to_ascii(int cmd) case NBD_CMD_READ: return "read"; case NBD_CMD_WRITE: return "write"; case NBD_CMD_DISC: return "disconnect"; + case NBD_CMD_TRIM: return "trim/discard"; } return "invalid"; } @@ -467,8 +470,12 @@ static void nbd_handle_req(struct nbd_device *nbd, struct request *req) nbd_cmd(req) = NBD_CMD_READ; if (rq_data_dir(req) == WRITE) { - nbd_cmd(req) = NBD_CMD_WRITE; - if (nbd->flags & NBD_READ_ONLY) { + if ((req->cmd_flags & REQ_DISCARD)) { + WARN_ON(!(nbd->flags & NBD_FLAG_SEND_TRIM)); + nbd_cmd(req) = NBD_CMD_TRIM; + } else + nbd_cmd(req) = NBD_CMD_WRITE; + if (nbd->flags & NBD_FLAG_READ_ONLY) { dev_err(disk_to_dev(nbd->disk), "Write on read-only\n"); goto error_out; @@ -651,6 +658,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd->xmit_timeout = arg * HZ; return 0; + case NBD_SET_FLAGS: + nbd->flags = arg; + return 0; + case NBD_SET_SIZE_BLOCKS: nbd->bytesize = ((u64) arg) * nbd->blksize; bdev->bd_inode->i_size = nbd->bytesize; @@ -670,6 +681,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, mutex_unlock(&nbd->tx_lock); + if (nbd->flags & NBD_FLAG_SEND_TRIM) + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, + nbd->disk->queue); + thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name); if (IS_ERR(thread)) { mutex_lock(&nbd->tx_lock); @@ -687,6 +702,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd->file = NULL; nbd_clear_que(nbd); dev_warn(disk_to_dev(nbd->disk), "queue cleared\n"); + queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue); if (file) fput(file); nbd->bytesize = 0; @@ -805,6 +821,9 @@ static int __init nbd_init(void) * Tell the block layer that we are not a rotational device */ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); + disk->queue->limits.discard_granularity = 512; + disk->queue->limits.max_discard_sectors = UINT_MAX; + disk->queue->limits.discard_zeroes_data = 0; } if (register_blkdev(NBD_MAJOR, "nbd")) { diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index c6decb901e5e..280a13846e6c 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -42,6 +42,7 @@ #include <xen/events.h> #include <xen/page.h> +#include <xen/xen.h> #include <asm/xen/hypervisor.h> #include <asm/xen/hypercall.h> #include "common.h" diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index 85074de5042e..f05d85713fd3 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c @@ -59,16 +59,21 @@ #define RNGA_STATUS_LAST_READ_STATUS 0x00000002 #define RNGA_STATUS_SECURITY_VIOLATION 0x00000001 -static struct platform_device *rng_dev; +struct mxc_rng { + struct device *dev; + struct hwrng rng; + void __iomem *mem; + struct clk *clk; +}; static int mxc_rnga_data_present(struct hwrng *rng, int wait) { - void __iomem *rng_base = (void __iomem *)rng->priv; int i; + struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); for (i = 0; i < 20; i++) { /* how many random numbers are in FIFO? [0-16] */ - int level = (__raw_readl(rng_base + RNGA_STATUS) & + int level = (__raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_LEVEL_MASK) >> 8; if (level || !wait) return !!level; @@ -81,20 +86,20 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) { int err; u32 ctrl; - void __iomem *rng_base = (void __iomem *)rng->priv; + struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); /* retrieve a random number from FIFO */ - *data = __raw_readl(rng_base + RNGA_OUTPUT_FIFO); + *data = __raw_readl(mxc_rng->mem + RNGA_OUTPUT_FIFO); /* some error while reading this random number? */ - err = __raw_readl(rng_base + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; + err = __raw_readl(mxc_rng->mem + RNGA_STATUS) & RNGA_STATUS_ERROR_INT; /* if error: clear error interrupt, but doesn't return random number */ if (err) { - dev_dbg(&rng_dev->dev, "Error while reading random number!\n"); - ctrl = __raw_readl(rng_base + RNGA_CONTROL); + dev_dbg(mxc_rng->dev, "Error while reading random number!\n"); + ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); __raw_writel(ctrl | RNGA_CONTROL_CLEAR_INT, - rng_base + RNGA_CONTROL); + mxc_rng->mem + RNGA_CONTROL); return 0; } else return 4; @@ -103,22 +108,22 @@ static int mxc_rnga_data_read(struct hwrng *rng, u32 * data) static int mxc_rnga_init(struct hwrng *rng) { u32 ctrl, osc; - void __iomem *rng_base = (void __iomem *)rng->priv; + struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); /* wake up */ - ctrl = __raw_readl(rng_base + RNGA_CONTROL); - __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, rng_base + RNGA_CONTROL); + ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); + __raw_writel(ctrl & ~RNGA_CONTROL_SLEEP, mxc_rng->mem + RNGA_CONTROL); /* verify if oscillator is working */ - osc = __raw_readl(rng_base + RNGA_STATUS); + osc = __raw_readl(mxc_rng->mem + RNGA_STATUS); if (osc & RNGA_STATUS_OSC_DEAD) { - dev_err(&rng_dev->dev, "RNGA Oscillator is dead!\n"); + dev_err(mxc_rng->dev, "RNGA Oscillator is dead!\n"); return -ENODEV; } /* go running */ - ctrl = __raw_readl(rng_base + RNGA_CONTROL); - __raw_writel(ctrl | RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); + ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); + __raw_writel(ctrl | RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); return 0; } @@ -126,40 +131,40 @@ static int mxc_rnga_init(struct hwrng *rng) static void mxc_rnga_cleanup(struct hwrng *rng) { u32 ctrl; - void __iomem *rng_base = (void __iomem *)rng->priv; + struct mxc_rng *mxc_rng = container_of(rng, struct mxc_rng, rng); - ctrl = __raw_readl(rng_base + RNGA_CONTROL); + ctrl = __raw_readl(mxc_rng->mem + RNGA_CONTROL); /* stop rnga */ - __raw_writel(ctrl & ~RNGA_CONTROL_GO, rng_base + RNGA_CONTROL); + __raw_writel(ctrl & ~RNGA_CONTROL_GO, mxc_rng->mem + RNGA_CONTROL); } -static struct hwrng mxc_rnga = { - .name = "mxc-rnga", - .init = mxc_rnga_init, - .cleanup = mxc_rnga_cleanup, - .data_present = mxc_rnga_data_present, - .data_read = mxc_rnga_data_read -}; - static int __init mxc_rnga_probe(struct platform_device *pdev) { int err = -ENODEV; - struct clk *clk; struct resource *res, *mem; - void __iomem *rng_base = NULL; - - if (rng_dev) - return -EBUSY; - - clk = clk_get(&pdev->dev, "rng"); - if (IS_ERR(clk)) { + struct mxc_rng *mxc_rng; + + mxc_rng = devm_kzalloc(&pdev->dev, sizeof(struct mxc_rng), + GFP_KERNEL); + if (!mxc_rng) + return -ENOMEM; + + mxc_rng->dev = &pdev->dev; + mxc_rng->rng.name = "mxc-rnga"; + mxc_rng->rng.init = mxc_rnga_init; + mxc_rng->rng.cleanup = mxc_rnga_cleanup, + mxc_rng->rng.data_present = mxc_rnga_data_present, + mxc_rng->rng.data_read = mxc_rnga_data_read, + + mxc_rng->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mxc_rng->clk)) { dev_err(&pdev->dev, "Could not get rng_clk!\n"); - err = PTR_ERR(clk); + err = PTR_ERR(mxc_rng->clk); goto out; } - clk_enable(clk); + clk_prepare_enable(mxc_rng->clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -173,36 +178,27 @@ static int __init mxc_rnga_probe(struct platform_device *pdev) goto err_region; } - rng_base = ioremap(res->start, resource_size(res)); - if (!rng_base) { + mxc_rng->mem = ioremap(res->start, resource_size(res)); + if (!mxc_rng->mem) { err = -ENOMEM; goto err_ioremap; } - mxc_rnga.priv = (unsigned long)rng_base; - - err = hwrng_register(&mxc_rnga); + err = hwrng_register(&mxc_rng->rng); if (err) { dev_err(&pdev->dev, "MXC RNGA registering failed (%d)\n", err); - goto err_register; + goto err_ioremap; } - rng_dev = pdev; - dev_info(&pdev->dev, "MXC RNGA Registered.\n"); return 0; -err_register: - iounmap(rng_base); - rng_base = NULL; - err_ioremap: release_mem_region(res->start, resource_size(res)); err_region: - clk_disable(clk); - clk_put(clk); + clk_disable_unprepare(mxc_rng->clk); out: return err; @@ -211,17 +207,15 @@ out: static int __exit mxc_rnga_remove(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - void __iomem *rng_base = (void __iomem *)mxc_rnga.priv; - struct clk *clk = clk_get(&pdev->dev, "rng"); + struct mxc_rng *mxc_rng = platform_get_drvdata(pdev); - hwrng_unregister(&mxc_rnga); + hwrng_unregister(&mxc_rng->rng); - iounmap(rng_base); + iounmap(mxc_rng->mem); release_mem_region(res->start, resource_size(res)); - clk_disable(clk); - clk_put(clk); + clk_disable_unprepare(mxc_rng->clk); return 0; } diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c index 0943edc782a1..5c34c092af71 100644 --- a/drivers/char/hw_random/octeon-rng.c +++ b/drivers/char/hw_random/octeon-rng.c @@ -75,42 +75,35 @@ static int __devinit octeon_rng_probe(struct platform_device *pdev) res_ports = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_ports) - goto err_ports; + return -ENOENT; res_result = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res_result) - goto err_ports; + return -ENOENT; rng->control_status = devm_ioremap_nocache(&pdev->dev, res_ports->start, sizeof(u64)); if (!rng->control_status) - goto err_ports; + return -ENOENT; rng->result = devm_ioremap_nocache(&pdev->dev, res_result->start, sizeof(u64)); if (!rng->result) - goto err_r; + return -ENOENT; rng->ops = ops; dev_set_drvdata(&pdev->dev, &rng->ops); ret = hwrng_register(&rng->ops); if (ret) - goto err; + return -ENOENT; dev_info(&pdev->dev, "Octeon Random Number Generator\n"); return 0; -err: - devm_iounmap(&pdev->dev, rng->control_status); -err_r: - devm_iounmap(&pdev->dev, rng->result); -err_ports: - devm_kfree(&pdev->dev, rng); - return -ENOENT; } static int __exit octeon_rng_remove(struct platform_device *pdev) diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 47ff7e470d87..0c7d340b9ab9 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -799,7 +799,7 @@ static int mbcs_remove(struct cx_dev *dev) return 0; } -static const struct cx_device_id __devinitdata mbcs_id_table[] = { +static const struct cx_device_id __devinitconst mbcs_id_table[] = { { .part_num = MBCS_PART_NUM, .mfg_num = MBCS_MFG_NUM, diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 7d74d092aa8f..308c7fb92a60 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -298,21 +298,15 @@ config CRYPTO_DEV_TEGRA_AES will be called tegra-aes. config CRYPTO_DEV_NX - tristate "Support for Power7+ in-Nest cryptographic acceleration" + bool "Support for IBM Power7+ in-Nest cryptographic acceleration" depends on PPC64 && IBMVIO - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_CCM - select CRYPTO_GCM - select CRYPTO_AUTHENC - select CRYPTO_XCBC - select CRYPTO_SHA256 - select CRYPTO_SHA512 + default n help - Support for Power7+ in-Nest cryptographic acceleration. This - module supports acceleration for AES and SHA2 algorithms. If you - choose 'M' here, this module will be called nx_crypto. + Support for Power7+ in-Nest cryptographic acceleration. + +if CRYPTO_DEV_NX + source "drivers/crypto/nx/Kconfig" +endif config CRYPTO_DEV_UX500 tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration" @@ -340,7 +334,7 @@ config CRYPTO_DEV_ATMEL_AES select CRYPTO_AES select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER - select CONFIG_AT_HDMAC + select AT_HDMAC help Some Atmel processors have AES hw accelerator. Select this if you want to use the Atmel module for diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 802e85102c32..f88e3d8f6b64 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1226,6 +1226,7 @@ static int __init crypto4xx_probe(struct platform_device *ofdev) core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); if (!core_dev->dev->ce_base) { dev_err(dev, "failed to of_iomap\n"); + rc = -ENOMEM; goto err_iomap; } diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 6bb20fffbf49..8061336e07e7 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -24,15 +24,10 @@ #include <linux/platform_device.h> #include <linux/device.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/clk.h> #include <linux/irq.h> -#include <linux/io.h> -#include <linux/platform_device.h> #include <linux/scatterlist.h> #include <linux/dma-mapping.h> #include <linux/delay.h> @@ -1017,7 +1012,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) int err, i, j; for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { - INIT_LIST_HEAD(&aes_algs[i].cra_list); err = crypto_register_alg(&aes_algs[i]); if (err) goto err_aes_algs; @@ -1026,7 +1020,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) atmel_aes_hw_version_init(dd); if (dd->hw_version >= 0x130) { - INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list); err = crypto_register_alg(&aes_cfb64_alg[0]); if (err) goto err_aes_cfb64_alg; diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index f938b9d79b66..bcdf55fdc623 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -24,15 +24,10 @@ #include <linux/platform_device.h> #include <linux/device.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/clk.h> #include <linux/irq.h> -#include <linux/io.h> -#include <linux/platform_device.h> #include <linux/scatterlist.h> #include <linux/dma-mapping.h> #include <linux/delay.h> diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index eb2b61e57e2d..7495f98c7221 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -24,15 +24,10 @@ #include <linux/platform_device.h> #include <linux/device.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/clk.h> #include <linux/irq.h> -#include <linux/io.h> -#include <linux/platform_device.h> #include <linux/scatterlist.h> #include <linux/dma-mapping.h> #include <linux/delay.h> @@ -1044,7 +1039,6 @@ static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) int err, i, j; for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { - INIT_LIST_HEAD(&tdes_algs[i].cra_list); err = crypto_register_alg(&tdes_algs[i]); if (err) goto err_tdes_algs; diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 0c1ea8492eff..b2a0a0726a54 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -205,7 +205,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, { u32 *key_jump_cmd; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | @@ -224,7 +224,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) struct aead_tfm *tfm = &aead->base.crt_aead; struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = 0; + bool keys_fit_inline = false; u32 *key_jump_cmd, *jump_cmd; u32 geniv, moveiv; u32 *desc; @@ -239,7 +239,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) if (DESC_AEAD_ENC_LEN + DESC_JOB_IO_LEN + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = 1; + keys_fit_inline = true; /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; @@ -297,12 +297,12 @@ static int aead_set_sh_desc(struct crypto_aead *aead) if (DESC_AEAD_DEC_LEN + DESC_JOB_IO_LEN + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = 1; + keys_fit_inline = true; desc = ctx->sh_desc_dec; /* aead_decrypt shared descriptor */ - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | @@ -365,7 +365,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) if (DESC_AEAD_GIVENC_LEN + DESC_JOB_IO_LEN + ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = 1; + keys_fit_inline = true; /* aead_givencrypt shared descriptor */ desc = ctx->sh_desc_givenc; @@ -564,7 +564,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); @@ -605,7 +605,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* ablkcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); @@ -1354,10 +1354,10 @@ static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request contig &= ~GIV_SRC_CONTIG; if (dst_nents || iv_dma + ivsize != sg_dma_address(req->dst)) contig &= ~GIV_DST_CONTIG; - if (unlikely(req->src != req->dst)) { - dst_nents = dst_nents ? : 1; - sec4_sg_len += 1; - } + if (unlikely(req->src != req->dst)) { + dst_nents = dst_nents ? : 1; + sec4_sg_len += 1; + } if (!(contig & GIV_SRC_CONTIG)) { assoc_nents = assoc_nents ? : 1; src_nents = src_nents ? : 1; @@ -1650,7 +1650,11 @@ struct caam_alg_template { }; static struct caam_alg_template driver_algs[] = { - /* single-pass ipsec_esp descriptor */ + /* + * single-pass ipsec_esp descriptor + * authencesn(*,*) is also registered, although not present + * explicitly here. + */ { .name = "authenc(hmac(md5),cbc(aes))", .driver_name = "authenc-hmac-md5-cbc-aes-caam", @@ -2213,7 +2217,9 @@ static int __init caam_algapi_init(void) for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { /* TODO: check if h/w supports alg */ struct caam_crypto_alg *t_alg; + bool done = false; +authencesn: t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); @@ -2227,8 +2233,25 @@ 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); + if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD && + !memcmp(driver_algs[i].name, "authenc", 7) && + !done) { + char *name; + + name = driver_algs[i].name; + memmove(name + 10, name + 7, strlen(name) - 7); + memcpy(name + 7, "esn", 3); + + name = driver_algs[i].driver_name; + memmove(name + 10, name + 7, strlen(name) - 7); + memcpy(name + 7, "esn", 3); + + done = true; + goto authencesn; + } + } } if (!list_empty(&priv->alg_list)) dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 895aaf2bca92..32aba7a61503 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -225,7 +225,7 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) { u32 *key_jump_cmd; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); if (ctx->split_key_len) { /* Skip if already shared */ @@ -311,7 +311,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update shared descriptor */ desc = ctx->sh_desc_update; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Import context from software */ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | @@ -430,6 +430,10 @@ static u32 hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, int ret = 0; desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); + if (!desc) { + dev_err(jrdev, "unable to allocate key input memory\n"); + return -ENOMEM; + } init_job_desc(desc, 0); @@ -1736,8 +1740,11 @@ static void __exit caam_algapi_hash_exit(void) struct caam_hash_alg *t_alg, *n; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) - return; + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return; + } pdev = of_find_device_by_node(dev_node); if (!pdev) @@ -1812,8 +1819,11 @@ static int __init caam_algapi_hash_init(void) int i = 0, err = 0; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) - return -ENODEV; + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + } pdev = of_find_device_by_node(dev_node); if (!pdev) diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index e2bfe161dece..d1939a9539c0 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -193,7 +193,7 @@ static inline void rng_create_sh_desc(struct caam_rng_ctx *ctx) struct device *jrdev = ctx->jrdev; u32 *desc = ctx->sh_desc; - init_sh_desc(desc, HDR_SHARE_WAIT); + init_sh_desc(desc, HDR_SHARE_SERIAL); /* Propagate errors from shared to job descriptor */ append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); @@ -284,8 +284,11 @@ static int __init caam_rng_init(void) struct caam_drv_private *priv; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); - if (!dev_node) - return -ENODEV; + if (!dev_node) { + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); + if (!dev_node) + return -ENODEV; + } pdev = of_find_device_by_node(dev_node); if (!pdev) diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index 762aeff626ac..cf15e7813801 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/debugfs.h> #include <linux/circ_buf.h> +#include <linux/string.h> #include <net/xfrm.h> #include <crypto/algapi.h> diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 414ba20c05a1..bf20dd891705 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -129,7 +129,7 @@ static int instantiate_rng(struct device *jrdev) /* * By default, the TRNG runs for 200 clocks per sample; - * 800 clocks per sample generates better entropy. + * 1600 clocks per sample generates better entropy. */ static void kick_trng(struct platform_device *pdev) { @@ -144,9 +144,9 @@ static void kick_trng(struct platform_device *pdev) /* put RNG4 into program mode */ setbits32(&r4tst->rtmctl, RTMCTL_PRGM); - /* 800 clocks per sample */ + /* 1600 clocks per sample */ val = rd_reg32(&r4tst->rtsdctl); - val = (val & ~RTSDCTL_ENT_DLY_MASK) | (800 << RTSDCTL_ENT_DLY_SHIFT); + val = (val & ~RTSDCTL_ENT_DLY_MASK) | (1600 << RTSDCTL_ENT_DLY_SHIFT); wr_reg32(&r4tst->rtsdctl, val); /* min. freq. count */ wr_reg32(&r4tst->rtfrqmin, 400); diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 9955ed9643e6..30b8f74833d4 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -77,10 +77,8 @@ static void report_ccb_status(u32 status, char *outstr) "Not instantiated", "Test instantiate", "Prediction resistance", - "", "Prediction resistance and test request", "Uninstantiate", - "", "Secure key generation", }; u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >> diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index d216cd3cc569..f6dba10246c3 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -54,6 +54,10 @@ u32 gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, int ret = 0; desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); + if (!desc) { + dev_err(jrdev, "unable to allocate key input memory\n"); + return -ENOMEM; + } init_job_desc(desc, 0); diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index f3e36c86b6c3..51f196d77f21 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -289,7 +289,6 @@ static struct crypto_alg geode_alg = { .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, @@ -402,7 +401,6 @@ static struct crypto_alg geode_cbc_alg = { .cra_alignmask = 15, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -489,7 +487,6 @@ static struct crypto_alg geode_ecb_alg = { .cra_alignmask = 15, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -588,21 +585,8 @@ static struct pci_driver geode_aes_driver = { .remove = __devexit_p(geode_aes_remove) }; -static int __init -geode_aes_init(void) -{ - return pci_register_driver(&geode_aes_driver); -} - -static void __exit -geode_aes_exit(void) -{ - pci_unregister_driver(&geode_aes_driver); -} +module_pci_driver(geode_aes_driver); MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION("Geode LX Hardware AES driver"); MODULE_LICENSE("GPL"); - -module_init(geode_aes_init); -module_exit(geode_aes_exit); diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index df14358d7fa1..fda32968a66b 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -2611,14 +2611,17 @@ static int __devinit hifn_probe(struct pci_dev *pdev, const struct pci_device_id size = pci_resource_len(pdev, i); dev->bar[i] = ioremap_nocache(addr, size); - if (!dev->bar[i]) + if (!dev->bar[i]) { + err = -ENOMEM; goto err_out_unmap_bars; + } } dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma), &dev->desc_dma); if (!dev->desc_virt) { dprintk("Failed to allocate descriptor rings.\n"); + err = -ENOMEM; goto err_out_unmap_bars; } memset(dev->desc_virt, 0, sizeof(struct hifn_dma)); diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig new file mode 100644 index 000000000000..f82616621ae1 --- /dev/null +++ b/drivers/crypto/nx/Kconfig @@ -0,0 +1,26 @@ +config CRYPTO_DEV_NX_ENCRYPT + tristate "Encryption acceleration support" + depends on PPC64 && IBMVIO + default y + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_ECB + select CRYPTO_CCM + select CRYPTO_GCM + select CRYPTO_AUTHENC + select CRYPTO_XCBC + select CRYPTO_SHA256 + select CRYPTO_SHA512 + help + Support for Power7+ in-Nest encryption acceleration. This + module supports acceleration for AES and SHA2 algorithms. If you + choose 'M' here, this module will be called nx_crypto. + +config CRYPTO_DEV_NX_COMPRESS + tristate "Compression acceleration support" + depends on PPC64 && IBMVIO + default y + help + Support for Power7+ in-Nest compression acceleration. This + module supports acceleration for AES and SHA2 algorithms. If you + choose 'M' here, this module will be called nx_compress. diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index 411ce59c80d1..bb770ea45ce9 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o +obj-$(CONFIG_CRYPTO_DEV_NX_ENCRYPT) += nx-crypto.o nx-crypto-objs := nx.o \ nx_debugfs.o \ nx-aes-cbc.o \ @@ -9,3 +9,6 @@ nx-crypto-objs := nx.o \ nx-aes-xcbc.o \ nx-sha256.o \ nx-sha512.o + +obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o +nx-compress-objs := nx-842.o diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c new file mode 100644 index 000000000000..0ce625738677 --- /dev/null +++ b/drivers/crypto/nx/nx-842.c @@ -0,0 +1,1617 @@ +/* + * Driver for IBM Power 842 compression accelerator + * + * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corporation, 2012 + * + * Authors: Robert Jennings <rcj@linux.vnet.ibm.com> + * Seth Jennings <sjenning@linux.vnet.ibm.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/nx842.h> +#include <linux/of.h> +#include <linux/slab.h> + +#include <asm/page.h> +#include <asm/pSeries_reconfig.h> +#include <asm/vio.h> + +#include "nx_csbcpb.h" /* struct nx_csbcpb */ + +#define MODULE_NAME "nx-compress" +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Jennings <rcj@linux.vnet.ibm.com>"); +MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors"); + +#define SHIFT_4K 12 +#define SHIFT_64K 16 +#define SIZE_4K (1UL << SHIFT_4K) +#define SIZE_64K (1UL << SHIFT_64K) + +/* IO buffer must be 128 byte aligned */ +#define IO_BUFFER_ALIGN 128 + +struct nx842_header { + int blocks_nr; /* number of compressed blocks */ + int offset; /* offset of the first block (from beginning of header) */ + int sizes[0]; /* size of compressed blocks */ +}; + +static inline int nx842_header_size(const struct nx842_header *hdr) +{ + return sizeof(struct nx842_header) + + hdr->blocks_nr * sizeof(hdr->sizes[0]); +} + +/* Macros for fields within nx_csbcpb */ +/* Check the valid bit within the csbcpb valid field */ +#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7)) + +/* CE macros operate on the completion_extension field bits in the csbcpb. + * CE0 0=full completion, 1=partial completion + * CE1 0=CE0 indicates completion, 1=termination (output may be modified) + * CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */ +#define NX842_CSBCPB_CE0(x) (x & BIT_MASK(7)) +#define NX842_CSBCPB_CE1(x) (x & BIT_MASK(6)) +#define NX842_CSBCPB_CE2(x) (x & BIT_MASK(5)) + +/* The NX unit accepts data only on 4K page boundaries */ +#define NX842_HW_PAGE_SHIFT SHIFT_4K +#define NX842_HW_PAGE_SIZE (ASM_CONST(1) << NX842_HW_PAGE_SHIFT) +#define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1)) + +enum nx842_status { + UNAVAILABLE, + AVAILABLE +}; + +struct ibm_nx842_counters { + atomic64_t comp_complete; + atomic64_t comp_failed; + atomic64_t decomp_complete; + atomic64_t decomp_failed; + atomic64_t swdecomp; + atomic64_t comp_times[32]; + atomic64_t decomp_times[32]; +}; + +static struct nx842_devdata { + struct vio_dev *vdev; + struct device *dev; + struct ibm_nx842_counters *counters; + unsigned int max_sg_len; + unsigned int max_sync_size; + unsigned int max_sync_sg; + enum nx842_status status; +} __rcu *devdata; +static DEFINE_SPINLOCK(devdata_mutex); + +#define NX842_COUNTER_INC(_x) \ +static inline void nx842_inc_##_x( \ + const struct nx842_devdata *dev) { \ + if (dev) \ + atomic64_inc(&dev->counters->_x); \ +} +NX842_COUNTER_INC(comp_complete); +NX842_COUNTER_INC(comp_failed); +NX842_COUNTER_INC(decomp_complete); +NX842_COUNTER_INC(decomp_failed); +NX842_COUNTER_INC(swdecomp); + +#define NX842_HIST_SLOTS 16 + +static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time) +{ + int bucket = fls(time); + + if (bucket) + bucket = min((NX842_HIST_SLOTS - 1), bucket - 1); + + atomic64_inc(×[bucket]); +} + +/* NX unit operation flags */ +#define NX842_OP_COMPRESS 0x0 +#define NX842_OP_CRC 0x1 +#define NX842_OP_DECOMPRESS 0x2 +#define NX842_OP_COMPRESS_CRC (NX842_OP_COMPRESS | NX842_OP_CRC) +#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC) +#define NX842_OP_ASYNC (1<<23) +#define NX842_OP_NOTIFY (1<<22) +#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8) + +static unsigned long nx842_get_desired_dma(struct vio_dev *viodev) +{ + /* No use of DMA mappings within the driver. */ + return 0; +} + +struct nx842_slentry { + unsigned long ptr; /* Real address (use __pa()) */ + unsigned long len; +}; + +/* pHyp scatterlist entry */ +struct nx842_scatterlist { + int entry_nr; /* number of slentries */ + struct nx842_slentry *entries; /* ptr to array of slentries */ +}; + +/* Does not include sizeof(entry_nr) in the size */ +static inline unsigned long nx842_get_scatterlist_size( + struct nx842_scatterlist *sl) +{ + return sl->entry_nr * sizeof(struct nx842_slentry); +} + +static int nx842_build_scatterlist(unsigned long buf, int len, + struct nx842_scatterlist *sl) +{ + unsigned long nextpage; + struct nx842_slentry *entry; + + sl->entry_nr = 0; + + entry = sl->entries; + while (len) { + entry->ptr = __pa(buf); + nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE); + if (nextpage < buf + len) { + /* we aren't at the end yet */ + if (IS_ALIGNED(buf, NX842_HW_PAGE_SIZE)) + /* we are in the middle (or beginning) */ + entry->len = NX842_HW_PAGE_SIZE; + else + /* we are at the beginning */ + entry->len = nextpage - buf; + } else { + /* at the end */ + entry->len = len; + } + + len -= entry->len; + buf += entry->len; + sl->entry_nr++; + entry++; + } + + return 0; +} + +/* + * Working memory for software decompression + */ +struct sw842_fifo { + union { + char f8[256][8]; + char f4[512][4]; + }; + char f2[256][2]; + unsigned char f84_full; + unsigned char f2_full; + unsigned char f8_count; + unsigned char f2_count; + unsigned int f4_count; +}; + +/* + * Working memory for crypto API + */ +struct nx842_workmem { + char bounce[PAGE_SIZE]; /* bounce buffer for decompression input */ + union { + /* hardware working memory */ + struct { + /* scatterlist */ + char slin[SIZE_4K]; + char slout[SIZE_4K]; + /* coprocessor status/parameter block */ + struct nx_csbcpb csbcpb; + }; + /* software working memory */ + struct sw842_fifo swfifo; /* software decompression fifo */ + }; +}; + +int nx842_get_workmem_size(void) +{ + return sizeof(struct nx842_workmem) + NX842_HW_PAGE_SIZE; +} +EXPORT_SYMBOL_GPL(nx842_get_workmem_size); + +int nx842_get_workmem_size_aligned(void) +{ + return sizeof(struct nx842_workmem); +} +EXPORT_SYMBOL_GPL(nx842_get_workmem_size_aligned); + +static int nx842_validate_result(struct device *dev, + struct cop_status_block *csb) +{ + /* The csb must be valid after returning from vio_h_cop_sync */ + if (!NX842_CSBCBP_VALID_CHK(csb->valid)) { + dev_err(dev, "%s: cspcbp not valid upon completion.\n", + __func__); + dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n", + csb->valid, + csb->crb_seq_number, + csb->completion_code, + csb->completion_extension); + dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n", + csb->processed_byte_count, + (unsigned long)csb->address); + return -EIO; + } + + /* Check return values from the hardware in the CSB */ + switch (csb->completion_code) { + case 0: /* Completed without error */ + break; + case 64: /* Target bytes > Source bytes during compression */ + case 13: /* Output buffer too small */ + dev_dbg(dev, "%s: Compression output larger than input\n", + __func__); + return -ENOSPC; + case 66: /* Input data contains an illegal template field */ + case 67: /* Template indicates data past the end of the input stream */ + dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n", + __func__, csb->completion_code); + return -EINVAL; + default: + dev_dbg(dev, "%s: Unspecified error (code:%d)\n", + __func__, csb->completion_code); + return -EIO; + } + + /* Hardware sanity check */ + if (!NX842_CSBCPB_CE2(csb->completion_extension)) { + dev_err(dev, "%s: No error returned by hardware, but " + "data returned is unusable, contact support.\n" + "(Additional info: csbcbp->processed bytes " + "does not specify processed bytes for the " + "target buffer.)\n", __func__); + return -EIO; + } + + return 0; +} + +/** + * nx842_compress - Compress data using the 842 algorithm + * + * Compression provide by the NX842 coprocessor on IBM Power systems. + * The input buffer is compressed and the result is stored in the + * provided output buffer. + * + * Upon return from this function @outlen contains the length of the + * compressed data. If there is an error then @outlen will be 0 and an + * error will be specified by the return code from this function. + * + * @in: Pointer to input buffer, must be page aligned + * @inlen: Length of input buffer, must be PAGE_SIZE + * @out: Pointer to output buffer + * @outlen: Length of output buffer + * @wrkmem: ptr to buffer for working memory, size determined by + * nx842_get_workmem_size() + * + * Returns: + * 0 Success, output of length @outlen stored in the buffer at @out + * -ENOMEM Unable to allocate internal buffers + * -ENOSPC Output buffer is to small + * -EMSGSIZE XXX Difficult to describe this limitation + * -EIO Internal error + * -ENODEV Hardware unavailable + */ +int nx842_compress(const unsigned char *in, unsigned int inlen, + unsigned char *out, unsigned int *outlen, void *wmem) +{ + struct nx842_header *hdr; + struct nx842_devdata *local_devdata; + struct device *dev = NULL; + struct nx842_workmem *workmem; + struct nx842_scatterlist slin, slout; + struct nx_csbcpb *csbcpb; + int ret = 0, max_sync_size, i, bytesleft, size, hdrsize; + unsigned long inbuf, outbuf, padding; + struct vio_pfo_op op = { + .done = NULL, + .handle = 0, + .timeout = 0, + }; + unsigned long start_time = get_tb(); + + /* + * Make sure input buffer is 64k page aligned. This is assumed since + * this driver is designed for page compression only (for now). This + * is very nice since we can now use direct DDE(s) for the input and + * the alignment is guaranteed. + */ + inbuf = (unsigned long)in; + if (!IS_ALIGNED(inbuf, PAGE_SIZE) || inlen != PAGE_SIZE) + return -EINVAL; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (!local_devdata || !local_devdata->dev) { + rcu_read_unlock(); + return -ENODEV; + } + max_sync_size = local_devdata->max_sync_size; + dev = local_devdata->dev; + + /* Create the header */ + hdr = (struct nx842_header *)out; + hdr->blocks_nr = PAGE_SIZE / max_sync_size; + hdrsize = nx842_header_size(hdr); + outbuf = (unsigned long)out + hdrsize; + bytesleft = *outlen - hdrsize; + + /* Init scatterlist */ + workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem, + NX842_HW_PAGE_SIZE); + slin.entries = (struct nx842_slentry *)workmem->slin; + slout.entries = (struct nx842_slentry *)workmem->slout; + + /* Init operation */ + op.flags = NX842_OP_COMPRESS; + csbcpb = &workmem->csbcpb; + memset(csbcpb, 0, sizeof(*csbcpb)); + op.csbcpb = __pa(csbcpb); + op.out = __pa(slout.entries); + + for (i = 0; i < hdr->blocks_nr; i++) { + /* + * Aligning the output blocks to 128 bytes does waste space, + * but it prevents the need for bounce buffers and memory + * copies. It also simplifies the code a lot. In the worst + * case (64k page, 4k max_sync_size), you lose up to + * (128*16)/64k = ~3% the compression factor. For 64k + * max_sync_size, the loss would be at most 128/64k = ~0.2%. + */ + padding = ALIGN(outbuf, IO_BUFFER_ALIGN) - outbuf; + outbuf += padding; + bytesleft -= padding; + if (i == 0) + /* save offset into first block in header */ + hdr->offset = padding + hdrsize; + + if (bytesleft <= 0) { + ret = -ENOSPC; + goto unlock; + } + + /* + * NOTE: If the default max_sync_size is changed from 4k + * to 64k, remove the "likely" case below, since a + * scatterlist will always be needed. + */ + if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { + /* Create direct DDE */ + op.in = __pa(inbuf); + op.inlen = max_sync_size; + + } else { + /* Create indirect DDE (scatterlist) */ + nx842_build_scatterlist(inbuf, max_sync_size, &slin); + op.in = __pa(slin.entries); + op.inlen = -nx842_get_scatterlist_size(&slin); + } + + /* + * If max_sync_size != NX842_HW_PAGE_SIZE, an indirect + * DDE is required for the outbuf. + * If max_sync_size == NX842_HW_PAGE_SIZE, outbuf must + * also be page aligned (1 in 128/4k=32 chance) in order + * to use a direct DDE. + * This is unlikely, just use an indirect DDE always. + */ + nx842_build_scatterlist(outbuf, + min(bytesleft, max_sync_size), &slout); + /* op.out set before loop */ + op.outlen = -nx842_get_scatterlist_size(&slout); + + /* Send request to pHyp */ + ret = vio_h_cop_sync(local_devdata->vdev, &op); + + /* Check for pHyp error */ + if (ret) { + dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n", + __func__, ret, op.hcall_err); + ret = -EIO; + goto unlock; + } + + /* Check for hardware error */ + ret = nx842_validate_result(dev, &csbcpb->csb); + if (ret && ret != -ENOSPC) + goto unlock; + + /* Handle incompressible data */ + if (unlikely(ret == -ENOSPC)) { + if (bytesleft < max_sync_size) { + /* + * Not enough space left in the output buffer + * to store uncompressed block + */ + goto unlock; + } else { + /* Store incompressible block */ + memcpy((void *)outbuf, (void *)inbuf, + max_sync_size); + hdr->sizes[i] = -max_sync_size; + outbuf += max_sync_size; + bytesleft -= max_sync_size; + /* Reset ret, incompressible data handled */ + ret = 0; + } + } else { + /* Normal case, compression was successful */ + size = csbcpb->csb.processed_byte_count; + dev_dbg(dev, "%s: processed_bytes=%d\n", + __func__, size); + hdr->sizes[i] = size; + outbuf += size; + bytesleft -= size; + } + + inbuf += max_sync_size; + } + + *outlen = (unsigned int)(outbuf - (unsigned long)out); + +unlock: + if (ret) + nx842_inc_comp_failed(local_devdata); + else { + nx842_inc_comp_complete(local_devdata); + ibm_nx842_incr_hist(local_devdata->counters->comp_times, + (get_tb() - start_time) / tb_ticks_per_usec); + } + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(nx842_compress); + +static int sw842_decompress(const unsigned char *, int, unsigned char *, int *, + const void *); + +/** + * nx842_decompress - Decompress data using the 842 algorithm + * + * Decompression provide by the NX842 coprocessor on IBM Power systems. + * The input buffer is decompressed and the result is stored in the + * provided output buffer. The size allocated to the output buffer is + * provided by the caller of this function in @outlen. Upon return from + * this function @outlen contains the length of the decompressed data. + * If there is an error then @outlen will be 0 and an error will be + * specified by the return code from this function. + * + * @in: Pointer to input buffer, will use bounce buffer if not 128 byte + * aligned + * @inlen: Length of input buffer + * @out: Pointer to output buffer, must be page aligned + * @outlen: Length of output buffer, must be PAGE_SIZE + * @wrkmem: ptr to buffer for working memory, size determined by + * nx842_get_workmem_size() + * + * Returns: + * 0 Success, output of length @outlen stored in the buffer at @out + * -ENODEV Hardware decompression device is unavailable + * -ENOMEM Unable to allocate internal buffers + * -ENOSPC Output buffer is to small + * -EINVAL Bad input data encountered when attempting decompress + * -EIO Internal error + */ +int nx842_decompress(const unsigned char *in, unsigned int inlen, + unsigned char *out, unsigned int *outlen, void *wmem) +{ + struct nx842_header *hdr; + struct nx842_devdata *local_devdata; + struct device *dev = NULL; + struct nx842_workmem *workmem; + struct nx842_scatterlist slin, slout; + struct nx_csbcpb *csbcpb; + int ret = 0, i, size, max_sync_size; + unsigned long inbuf, outbuf; + struct vio_pfo_op op = { + .done = NULL, + .handle = 0, + .timeout = 0, + }; + unsigned long start_time = get_tb(); + + /* Ensure page alignment and size */ + outbuf = (unsigned long)out; + if (!IS_ALIGNED(outbuf, PAGE_SIZE) || *outlen != PAGE_SIZE) + return -EINVAL; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (local_devdata) + dev = local_devdata->dev; + + /* Get header */ + hdr = (struct nx842_header *)in; + + workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem, + NX842_HW_PAGE_SIZE); + + inbuf = (unsigned long)in + hdr->offset; + if (likely(!IS_ALIGNED(inbuf, IO_BUFFER_ALIGN))) { + /* Copy block(s) into bounce buffer for alignment */ + memcpy(workmem->bounce, in + hdr->offset, inlen - hdr->offset); + inbuf = (unsigned long)workmem->bounce; + } + + /* Init scatterlist */ + slin.entries = (struct nx842_slentry *)workmem->slin; + slout.entries = (struct nx842_slentry *)workmem->slout; + + /* Init operation */ + op.flags = NX842_OP_DECOMPRESS; + csbcpb = &workmem->csbcpb; + memset(csbcpb, 0, sizeof(*csbcpb)); + op.csbcpb = __pa(csbcpb); + + /* + * max_sync_size may have changed since compression, + * so we can't read it from the device info. We need + * to derive it from hdr->blocks_nr. + */ + max_sync_size = PAGE_SIZE / hdr->blocks_nr; + + for (i = 0; i < hdr->blocks_nr; i++) { + /* Skip padding */ + inbuf = ALIGN(inbuf, IO_BUFFER_ALIGN); + + if (hdr->sizes[i] < 0) { + /* Negative sizes indicate uncompressed data blocks */ + size = abs(hdr->sizes[i]); + memcpy((void *)outbuf, (void *)inbuf, size); + outbuf += size; + inbuf += size; + continue; + } + + if (!dev) + goto sw; + + /* + * The better the compression, the more likely the "likely" + * case becomes. + */ + if (likely((inbuf & NX842_HW_PAGE_MASK) == + ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) { + /* Create direct DDE */ + op.in = __pa(inbuf); + op.inlen = hdr->sizes[i]; + } else { + /* Create indirect DDE (scatterlist) */ + nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin); + op.in = __pa(slin.entries); + op.inlen = -nx842_get_scatterlist_size(&slin); + } + + /* + * NOTE: If the default max_sync_size is changed from 4k + * to 64k, remove the "likely" case below, since a + * scatterlist will always be needed. + */ + if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { + /* Create direct DDE */ + op.out = __pa(outbuf); + op.outlen = max_sync_size; + } else { + /* Create indirect DDE (scatterlist) */ + nx842_build_scatterlist(outbuf, max_sync_size, &slout); + op.out = __pa(slout.entries); + op.outlen = -nx842_get_scatterlist_size(&slout); + } + + /* Send request to pHyp */ + ret = vio_h_cop_sync(local_devdata->vdev, &op); + + /* Check for pHyp error */ + if (ret) { + dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n", + __func__, ret, op.hcall_err); + dev = NULL; + goto sw; + } + + /* Check for hardware error */ + ret = nx842_validate_result(dev, &csbcpb->csb); + if (ret) { + dev = NULL; + goto sw; + } + + /* HW decompression success */ + inbuf += hdr->sizes[i]; + outbuf += csbcpb->csb.processed_byte_count; + continue; + +sw: + /* software decompression */ + size = max_sync_size; + ret = sw842_decompress( + (unsigned char *)inbuf, hdr->sizes[i], + (unsigned char *)outbuf, &size, wmem); + if (ret) + pr_debug("%s: sw842_decompress failed with %d\n", + __func__, ret); + + if (ret) { + if (ret != -ENOSPC && ret != -EINVAL && + ret != -EMSGSIZE) + ret = -EIO; + goto unlock; + } + + /* SW decompression success */ + inbuf += hdr->sizes[i]; + outbuf += size; + } + + *outlen = (unsigned int)(outbuf - (unsigned long)out); + +unlock: + if (ret) + /* decompress fail */ + nx842_inc_decomp_failed(local_devdata); + else { + if (!dev) + /* software decompress */ + nx842_inc_swdecomp(local_devdata); + nx842_inc_decomp_complete(local_devdata); + ibm_nx842_incr_hist(local_devdata->counters->decomp_times, + (get_tb() - start_time) / tb_ticks_per_usec); + } + + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL_GPL(nx842_decompress); + +/** + * nx842_OF_set_defaults -- Set default (disabled) values for devdata + * + * @devdata - struct nx842_devdata to update + * + * Returns: + * 0 on success + * -ENOENT if @devdata ptr is NULL + */ +static int nx842_OF_set_defaults(struct nx842_devdata *devdata) +{ + if (devdata) { + devdata->max_sync_size = 0; + devdata->max_sync_sg = 0; + devdata->max_sg_len = 0; + devdata->status = UNAVAILABLE; + return 0; + } else + return -ENOENT; +} + +/** + * nx842_OF_upd_status -- Update the device info from OF status prop + * + * The status property indicates if the accelerator is enabled. If the + * device is in the OF tree it indicates that the hardware is present. + * The status field indicates if the device is enabled when the status + * is 'okay'. Otherwise the device driver will be disabled. + * + * @devdata - struct nx842_devdata to update + * @prop - struct property point containing the maxsyncop for the update + * + * Returns: + * 0 - Device is available + * -EINVAL - Device is not available + */ +static int nx842_OF_upd_status(struct nx842_devdata *devdata, + struct property *prop) { + int ret = 0; + const char *status = (const char *)prop->value; + + if (!strncmp(status, "okay", (size_t)prop->length)) { + devdata->status = AVAILABLE; + } else { + dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n", + __func__, status); + devdata->status = UNAVAILABLE; + } + + return ret; +} + +/** + * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop + * + * Definition of the 'ibm,max-sg-len' OF property: + * This field indicates the maximum byte length of a scatter list + * for the platform facility. It is a single cell encoded as with encode-int. + * + * Example: + * # od -x ibm,max-sg-len + * 0000000 0000 0ff0 + * + * In this example, the maximum byte length of a scatter list is + * 0x0ff0 (4,080). + * + * @devdata - struct nx842_devdata to update + * @prop - struct property point containing the maxsyncop for the update + * + * Returns: + * 0 on success + * -EINVAL on failure + */ +static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata, + struct property *prop) { + int ret = 0; + const int *maxsglen = prop->value; + + if (prop->length != sizeof(*maxsglen)) { + dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__); + dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__, + prop->length, sizeof(*maxsglen)); + ret = -EINVAL; + } else { + devdata->max_sg_len = (unsigned int)min(*maxsglen, + (int)NX842_HW_PAGE_SIZE); + } + + return ret; +} + +/** + * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop + * + * Definition of the 'ibm,max-sync-cop' OF property: + * Two series of cells. The first series of cells represents the maximums + * that can be synchronously compressed. The second series of cells + * represents the maximums that can be synchronously decompressed. + * 1. The first cell in each series contains the count of the number of + * data length, scatter list elements pairs that follow – each being + * of the form + * a. One cell data byte length + * b. One cell total number of scatter list elements + * + * Example: + * # od -x ibm,max-sync-cop + * 0000000 0000 0001 0000 1000 0000 01fe 0000 0001 + * 0000020 0000 1000 0000 01fe + * + * In this example, compression supports 0x1000 (4,096) data byte length + * and 0x1fe (510) total scatter list elements. Decompression supports + * 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list + * elements. + * + * @devdata - struct nx842_devdata to update + * @prop - struct property point containing the maxsyncop for the update + * + * Returns: + * 0 on success + * -EINVAL on failure + */ +static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata, + struct property *prop) { + int ret = 0; + const struct maxsynccop_t { + int comp_elements; + int comp_data_limit; + int comp_sg_limit; + int decomp_elements; + int decomp_data_limit; + int decomp_sg_limit; + } *maxsynccop; + + if (prop->length != sizeof(*maxsynccop)) { + dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__); + dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length, + sizeof(*maxsynccop)); + ret = -EINVAL; + goto out; + } + + maxsynccop = (const struct maxsynccop_t *)prop->value; + + /* Use one limit rather than separate limits for compression and + * decompression. Set a maximum for this so as not to exceed the + * size that the header can support and round the value down to + * the hardware page size (4K) */ + devdata->max_sync_size = + (unsigned int)min(maxsynccop->comp_data_limit, + maxsynccop->decomp_data_limit); + + devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size, + SIZE_64K); + + if (devdata->max_sync_size < SIZE_4K) { + dev_err(devdata->dev, "%s: hardware max data size (%u) is " + "less than the driver minimum, unable to use " + "the hardware device\n", + __func__, devdata->max_sync_size); + ret = -EINVAL; + goto out; + } + + devdata->max_sync_sg = (unsigned int)min(maxsynccop->comp_sg_limit, + maxsynccop->decomp_sg_limit); + if (devdata->max_sync_sg < 1) { + dev_err(devdata->dev, "%s: hardware max sg size (%u) is " + "less than the driver minimum, unable to use " + "the hardware device\n", + __func__, devdata->max_sync_sg); + ret = -EINVAL; + goto out; + } + +out: + return ret; +} + +/** + * + * nx842_OF_upd -- Handle OF properties updates for the device. + * + * Set all properties from the OF tree. Optionally, a new property + * can be provided by the @new_prop pointer to overwrite an existing value. + * The device will remain disabled until all values are valid, this function + * will return an error for updates unless all values are valid. + * + * @new_prop: If not NULL, this property is being updated. If NULL, update + * all properties from the current values in the OF tree. + * + * Returns: + * 0 - Success + * -ENOMEM - Could not allocate memory for new devdata structure + * -EINVAL - property value not found, new_prop is not a recognized + * property for the device or property value is not valid. + * -ENODEV - Device is not available + */ +static int nx842_OF_upd(struct property *new_prop) +{ + struct nx842_devdata *old_devdata = NULL; + struct nx842_devdata *new_devdata = NULL; + struct device_node *of_node = NULL; + struct property *status = NULL; + struct property *maxsglen = NULL; + struct property *maxsyncop = NULL; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + if (old_devdata) + of_node = old_devdata->dev->of_node; + + if (!old_devdata || !of_node) { + pr_err("%s: device is not available\n", __func__); + spin_unlock_irqrestore(&devdata_mutex, flags); + return -ENODEV; + } + + new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); + if (!new_devdata) { + dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__); + ret = -ENOMEM; + goto error_out; + } + + memcpy(new_devdata, old_devdata, sizeof(*old_devdata)); + new_devdata->counters = old_devdata->counters; + + /* Set ptrs for existing properties */ + status = of_find_property(of_node, "status", NULL); + maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL); + maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL); + if (!status || !maxsglen || !maxsyncop) { + dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__); + ret = -EINVAL; + goto error_out; + } + + /* Set ptr to new property if provided */ + if (new_prop) { + /* Single property */ + if (!strncmp(new_prop->name, "status", new_prop->length)) { + status = new_prop; + + } else if (!strncmp(new_prop->name, "ibm,max-sg-len", + new_prop->length)) { + maxsglen = new_prop; + + } else if (!strncmp(new_prop->name, "ibm,max-sync-cop", + new_prop->length)) { + maxsyncop = new_prop; + + } else { + /* + * Skip the update, the property being updated + * has no impact. + */ + goto out; + } + } + + /* Perform property updates */ + ret = nx842_OF_upd_status(new_devdata, status); + if (ret) + goto error_out; + + ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen); + if (ret) + goto error_out; + + ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop); + if (ret) + goto error_out; + +out: + dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n", + __func__, new_devdata->max_sync_size, + old_devdata->max_sync_size); + dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n", + __func__, new_devdata->max_sync_sg, + old_devdata->max_sync_sg); + dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n", + __func__, new_devdata->max_sg_len, + old_devdata->max_sg_len); + + rcu_assign_pointer(devdata, new_devdata); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + dev_set_drvdata(new_devdata->dev, new_devdata); + kfree(old_devdata); + return 0; + +error_out: + if (new_devdata) { + dev_info(old_devdata->dev, "%s: device disabled\n", __func__); + nx842_OF_set_defaults(new_devdata); + rcu_assign_pointer(devdata, new_devdata); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + dev_set_drvdata(new_devdata->dev, new_devdata); + kfree(old_devdata); + } else { + dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__); + spin_unlock_irqrestore(&devdata_mutex, flags); + } + + if (!ret) + ret = -EINVAL; + return ret; +} + +/** + * nx842_OF_notifier - Process updates to OF properties for the device + * + * @np: notifier block + * @action: notifier action + * @update: struct pSeries_reconfig_prop_update pointer if action is + * PSERIES_UPDATE_PROPERTY + * + * Returns: + * NOTIFY_OK on success + * NOTIFY_BAD encoded with error number on failure, use + * notifier_to_errno() to decode this value + */ +static int nx842_OF_notifier(struct notifier_block *np, + unsigned long action, + void *update) +{ + struct pSeries_reconfig_prop_update *upd; + struct nx842_devdata *local_devdata; + struct device_node *node = NULL; + + upd = (struct pSeries_reconfig_prop_update *)update; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (local_devdata) + node = local_devdata->dev->of_node; + + if (local_devdata && + action == PSERIES_UPDATE_PROPERTY && + !strcmp(upd->node->name, node->name)) { + rcu_read_unlock(); + nx842_OF_upd(upd->property); + } else + rcu_read_unlock(); + + return NOTIFY_OK; +} + +static struct notifier_block nx842_of_nb = { + .notifier_call = nx842_OF_notifier, +}; + +#define nx842_counter_read(_name) \ +static ssize_t nx842_##_name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) { \ + struct nx842_devdata *local_devdata; \ + int p = 0; \ + rcu_read_lock(); \ + local_devdata = rcu_dereference(devdata); \ + if (local_devdata) \ + p = snprintf(buf, PAGE_SIZE, "%ld\n", \ + atomic64_read(&local_devdata->counters->_name)); \ + rcu_read_unlock(); \ + return p; \ +} + +#define NX842DEV_COUNTER_ATTR_RO(_name) \ + nx842_counter_read(_name); \ + static struct device_attribute dev_attr_##_name = __ATTR(_name, \ + 0444, \ + nx842_##_name##_show,\ + NULL); + +NX842DEV_COUNTER_ATTR_RO(comp_complete); +NX842DEV_COUNTER_ATTR_RO(comp_failed); +NX842DEV_COUNTER_ATTR_RO(decomp_complete); +NX842DEV_COUNTER_ATTR_RO(decomp_failed); +NX842DEV_COUNTER_ATTR_RO(swdecomp); + +static ssize_t nx842_timehist_show(struct device *, + struct device_attribute *, char *); + +static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444, + nx842_timehist_show, NULL); +static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times, + 0444, nx842_timehist_show, NULL); + +static ssize_t nx842_timehist_show(struct device *dev, + struct device_attribute *attr, char *buf) { + char *p = buf; + struct nx842_devdata *local_devdata; + atomic64_t *times; + int bytes_remain = PAGE_SIZE; + int bytes; + int i; + + rcu_read_lock(); + local_devdata = rcu_dereference(devdata); + if (!local_devdata) { + rcu_read_unlock(); + return 0; + } + + if (attr == &dev_attr_comp_times) + times = local_devdata->counters->comp_times; + else if (attr == &dev_attr_decomp_times) + times = local_devdata->counters->decomp_times; + else { + rcu_read_unlock(); + return 0; + } + + for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) { + bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n", + i ? (2<<(i-1)) : 0, (2<<i)-1, + atomic64_read(×[i])); + bytes_remain -= bytes; + p += bytes; + } + /* The last bucket holds everything over + * 2<<(NX842_HIST_SLOTS - 2) us */ + bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n", + 2<<(NX842_HIST_SLOTS - 2), + atomic64_read(×[(NX842_HIST_SLOTS - 1)])); + p += bytes; + + rcu_read_unlock(); + return p - buf; +} + +static struct attribute *nx842_sysfs_entries[] = { + &dev_attr_comp_complete.attr, + &dev_attr_comp_failed.attr, + &dev_attr_decomp_complete.attr, + &dev_attr_decomp_failed.attr, + &dev_attr_swdecomp.attr, + &dev_attr_comp_times.attr, + &dev_attr_decomp_times.attr, + NULL, +}; + +static struct attribute_group nx842_attribute_group = { + .name = NULL, /* put in device directory */ + .attrs = nx842_sysfs_entries, +}; + +static int __init nx842_probe(struct vio_dev *viodev, + const struct vio_device_id *id) +{ + struct nx842_devdata *old_devdata, *new_devdata = NULL; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + + if (old_devdata && old_devdata->vdev != NULL) { + dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__); + ret = -1; + goto error_unlock; + } + + dev_set_drvdata(&viodev->dev, NULL); + + new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); + if (!new_devdata) { + dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__); + ret = -ENOMEM; + goto error_unlock; + } + + new_devdata->counters = kzalloc(sizeof(*new_devdata->counters), + GFP_NOFS); + if (!new_devdata->counters) { + dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__); + ret = -ENOMEM; + goto error_unlock; + } + + new_devdata->vdev = viodev; + new_devdata->dev = &viodev->dev; + nx842_OF_set_defaults(new_devdata); + + rcu_assign_pointer(devdata, new_devdata); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + kfree(old_devdata); + + pSeries_reconfig_notifier_register(&nx842_of_nb); + + ret = nx842_OF_upd(NULL); + if (ret && ret != -ENODEV) { + dev_err(&viodev->dev, "could not parse device tree. %d\n", ret); + ret = -1; + goto error; + } + + rcu_read_lock(); + if (dev_set_drvdata(&viodev->dev, rcu_dereference(devdata))) { + rcu_read_unlock(); + dev_err(&viodev->dev, "failed to set driver data for device\n"); + ret = -1; + goto error; + } + rcu_read_unlock(); + + if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) { + dev_err(&viodev->dev, "could not create sysfs device attributes\n"); + ret = -1; + goto error; + } + + return 0; + +error_unlock: + spin_unlock_irqrestore(&devdata_mutex, flags); + if (new_devdata) + kfree(new_devdata->counters); + kfree(new_devdata); +error: + return ret; +} + +static int __exit nx842_remove(struct vio_dev *viodev) +{ + struct nx842_devdata *old_devdata; + unsigned long flags; + + pr_info("Removing IBM Power 842 compression device\n"); + sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group); + + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + pSeries_reconfig_notifier_unregister(&nx842_of_nb); + rcu_assign_pointer(devdata, NULL); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + dev_set_drvdata(&viodev->dev, NULL); + if (old_devdata) + kfree(old_devdata->counters); + kfree(old_devdata); + return 0; +} + +static struct vio_device_id nx842_driver_ids[] = { + {"ibm,compression-v1", "ibm,compression"}, + {"", ""}, +}; + +static struct vio_driver nx842_driver = { + .name = MODULE_NAME, + .probe = nx842_probe, + .remove = nx842_remove, + .get_desired_dma = nx842_get_desired_dma, + .id_table = nx842_driver_ids, +}; + +static int __init nx842_init(void) +{ + struct nx842_devdata *new_devdata; + pr_info("Registering IBM Power 842 compression driver\n"); + + RCU_INIT_POINTER(devdata, NULL); + new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL); + if (!new_devdata) { + pr_err("Could not allocate memory for device data\n"); + return -ENOMEM; + } + new_devdata->status = UNAVAILABLE; + RCU_INIT_POINTER(devdata, new_devdata); + + return vio_register_driver(&nx842_driver); +} + +module_init(nx842_init); + +static void __exit nx842_exit(void) +{ + struct nx842_devdata *old_devdata; + unsigned long flags; + + pr_info("Exiting IBM Power 842 compression driver\n"); + spin_lock_irqsave(&devdata_mutex, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_mutex)); + rcu_assign_pointer(devdata, NULL); + spin_unlock_irqrestore(&devdata_mutex, flags); + synchronize_rcu(); + if (old_devdata) + dev_set_drvdata(old_devdata->dev, NULL); + kfree(old_devdata); + vio_unregister_driver(&nx842_driver); +} + +module_exit(nx842_exit); + +/********************************* + * 842 software decompressor +*********************************/ +typedef int (*sw842_template_op)(const char **, int *, unsigned char **, + struct sw842_fifo *); + +static int sw842_data8(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_data4(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_data2(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_ptr8(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_ptr4(const char **, int *, unsigned char **, + struct sw842_fifo *); +static int sw842_ptr2(const char **, int *, unsigned char **, + struct sw842_fifo *); + +/* special templates */ +#define SW842_TMPL_REPEAT 0x1B +#define SW842_TMPL_ZEROS 0x1C +#define SW842_TMPL_EOF 0x1E + +static sw842_template_op sw842_tmpl_ops[26][4] = { + { sw842_data8, NULL}, /* 0 (00000) */ + { sw842_data4, sw842_data2, sw842_ptr2, NULL}, + { sw842_data4, sw842_ptr2, sw842_data2, NULL}, + { sw842_data4, sw842_ptr2, sw842_ptr2, NULL}, + { sw842_data4, sw842_ptr4, NULL}, + { sw842_data2, sw842_ptr2, sw842_data4, NULL}, + { sw842_data2, sw842_ptr2, sw842_data2, sw842_ptr2}, + { sw842_data2, sw842_ptr2, sw842_ptr2, sw842_data2}, + { sw842_data2, sw842_ptr2, sw842_ptr2, sw842_ptr2,}, + { sw842_data2, sw842_ptr2, sw842_ptr4, NULL}, + { sw842_ptr2, sw842_data2, sw842_data4, NULL}, /* 10 (01010) */ + { sw842_ptr2, sw842_data4, sw842_ptr2, NULL}, + { sw842_ptr2, sw842_data2, sw842_ptr2, sw842_data2}, + { sw842_ptr2, sw842_data2, sw842_ptr2, sw842_ptr2}, + { sw842_ptr2, sw842_data2, sw842_ptr4, NULL}, + { sw842_ptr2, sw842_ptr2, sw842_data4, NULL}, + { sw842_ptr2, sw842_ptr2, sw842_data2, sw842_ptr2}, + { sw842_ptr2, sw842_ptr2, sw842_ptr2, sw842_data2}, + { sw842_ptr2, sw842_ptr2, sw842_ptr2, sw842_ptr2}, + { sw842_ptr2, sw842_ptr2, sw842_ptr4, NULL}, + { sw842_ptr4, sw842_data4, NULL}, /* 20 (10100) */ + { sw842_ptr4, sw842_data2, sw842_ptr2, NULL}, + { sw842_ptr4, sw842_ptr2, sw842_data2, NULL}, + { sw842_ptr4, sw842_ptr2, sw842_ptr2, NULL}, + { sw842_ptr4, sw842_ptr4, NULL}, + { sw842_ptr8, NULL} +}; + +/* Software decompress helpers */ + +static uint8_t sw842_get_byte(const char *buf, int bit) +{ + uint8_t tmpl; + uint16_t tmp; + tmp = htons(*(uint16_t *)(buf)); + tmp = (uint16_t)(tmp << bit); + tmp = ntohs(tmp); + memcpy(&tmpl, &tmp, 1); + return tmpl; +} + +static uint8_t sw842_get_template(const char **buf, int *bit) +{ + uint8_t byte; + byte = sw842_get_byte(*buf, *bit); + byte = byte >> 3; + byte &= 0x1F; + *buf += (*bit + 5) / 8; + *bit = (*bit + 5) % 8; + return byte; +} + +/* repeat_count happens to be 5-bit too (like the template) */ +static uint8_t sw842_get_repeat_count(const char **buf, int *bit) +{ + uint8_t byte; + byte = sw842_get_byte(*buf, *bit); + byte = byte >> 2; + byte &= 0x3F; + *buf += (*bit + 6) / 8; + *bit = (*bit + 6) % 8; + return byte; +} + +static uint8_t sw842_get_ptr2(const char **buf, int *bit) +{ + uint8_t ptr; + ptr = sw842_get_byte(*buf, *bit); + (*buf)++; + return ptr; +} + +static uint16_t sw842_get_ptr4(const char **buf, int *bit, + struct sw842_fifo *fifo) +{ + uint16_t ptr; + ptr = htons(*(uint16_t *)(*buf)); + ptr = (uint16_t)(ptr << *bit); + ptr = ptr >> 7; + ptr &= 0x01FF; + *buf += (*bit + 9) / 8; + *bit = (*bit + 9) % 8; + return ptr; +} + +static uint8_t sw842_get_ptr8(const char **buf, int *bit, + struct sw842_fifo *fifo) +{ + return sw842_get_ptr2(buf, bit); +} + +/* Software decompress template ops */ + +static int sw842_data8(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + int ret; + + ret = sw842_data4(inbuf, inbit, outbuf, fifo); + if (ret) + return ret; + ret = sw842_data4(inbuf, inbit, outbuf, fifo); + return ret; +} + +static int sw842_data4(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + int ret; + + ret = sw842_data2(inbuf, inbit, outbuf, fifo); + if (ret) + return ret; + ret = sw842_data2(inbuf, inbit, outbuf, fifo); + return ret; +} + +static int sw842_data2(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + **outbuf = sw842_get_byte(*inbuf, *inbit); + (*inbuf)++; + (*outbuf)++; + **outbuf = sw842_get_byte(*inbuf, *inbit); + (*inbuf)++; + (*outbuf)++; + return 0; +} + +static int sw842_ptr8(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + uint8_t ptr; + ptr = sw842_get_ptr8(inbuf, inbit, fifo); + if (!fifo->f84_full && (ptr >= fifo->f8_count)) + return 1; + memcpy(*outbuf, fifo->f8[ptr], 8); + *outbuf += 8; + return 0; +} + +static int sw842_ptr4(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + uint16_t ptr; + ptr = sw842_get_ptr4(inbuf, inbit, fifo); + if (!fifo->f84_full && (ptr >= fifo->f4_count)) + return 1; + memcpy(*outbuf, fifo->f4[ptr], 4); + *outbuf += 4; + return 0; +} + +static int sw842_ptr2(const char **inbuf, int *inbit, + unsigned char **outbuf, struct sw842_fifo *fifo) +{ + uint8_t ptr; + ptr = sw842_get_ptr2(inbuf, inbit); + if (!fifo->f2_full && (ptr >= fifo->f2_count)) + return 1; + memcpy(*outbuf, fifo->f2[ptr], 2); + *outbuf += 2; + return 0; +} + +static void sw842_copy_to_fifo(const char *buf, struct sw842_fifo *fifo) +{ + unsigned char initial_f2count = fifo->f2_count; + + memcpy(fifo->f8[fifo->f8_count], buf, 8); + fifo->f4_count += 2; + fifo->f8_count += 1; + + if (!fifo->f84_full && fifo->f4_count >= 512) { + fifo->f84_full = 1; + fifo->f4_count /= 512; + } + + memcpy(fifo->f2[fifo->f2_count++], buf, 2); + memcpy(fifo->f2[fifo->f2_count++], buf + 2, 2); + memcpy(fifo->f2[fifo->f2_count++], buf + 4, 2); + memcpy(fifo->f2[fifo->f2_count++], buf + 6, 2); + if (fifo->f2_count < initial_f2count) + fifo->f2_full = 1; +} + +static int sw842_decompress(const unsigned char *src, int srclen, + unsigned char *dst, int *destlen, + const void *wrkmem) +{ + uint8_t tmpl; + const char *inbuf; + int inbit = 0; + unsigned char *outbuf, *outbuf_end, *origbuf, *prevbuf; + const char *inbuf_end; + sw842_template_op op; + int opindex; + int i, repeat_count; + struct sw842_fifo *fifo; + int ret = 0; + + fifo = &((struct nx842_workmem *)(wrkmem))->swfifo; + memset(fifo, 0, sizeof(*fifo)); + + origbuf = NULL; + inbuf = src; + inbuf_end = src + srclen; + outbuf = dst; + outbuf_end = dst + *destlen; + + while ((tmpl = sw842_get_template(&inbuf, &inbit)) != SW842_TMPL_EOF) { + if (inbuf >= inbuf_end) { + ret = -EINVAL; + goto out; + } + + opindex = 0; + prevbuf = origbuf; + origbuf = outbuf; + switch (tmpl) { + case SW842_TMPL_REPEAT: + if (prevbuf == NULL) { + ret = -EINVAL; + goto out; + } + + repeat_count = sw842_get_repeat_count(&inbuf, + &inbit) + 1; + + /* Did the repeat count advance past the end of input */ + if (inbuf > inbuf_end) { + ret = -EINVAL; + goto out; + } + + for (i = 0; i < repeat_count; i++) { + /* Would this overflow the output buffer */ + if ((outbuf + 8) > outbuf_end) { + ret = -ENOSPC; + goto out; + } + + memcpy(outbuf, prevbuf, 8); + sw842_copy_to_fifo(outbuf, fifo); + outbuf += 8; + } + break; + + case SW842_TMPL_ZEROS: + /* Would this overflow the output buffer */ + if ((outbuf + 8) > outbuf_end) { + ret = -ENOSPC; + goto out; + } + + memset(outbuf, 0, 8); + sw842_copy_to_fifo(outbuf, fifo); + outbuf += 8; + break; + + default: + if (tmpl > 25) { + ret = -EINVAL; + goto out; + } + + /* Does this go past the end of the input buffer */ + if ((inbuf + 2) > inbuf_end) { + ret = -EINVAL; + goto out; + } + + /* Would this overflow the output buffer */ + if ((outbuf + 8) > outbuf_end) { + ret = -ENOSPC; + goto out; + } + + while (opindex < 4 && + (op = sw842_tmpl_ops[tmpl][opindex++]) + != NULL) { + ret = (*op)(&inbuf, &inbit, &outbuf, fifo); + if (ret) { + ret = -EINVAL; + goto out; + } + sw842_copy_to_fifo(origbuf, fifo); + } + } + } + +out: + if (!ret) + *destlen = (unsigned int)(outbuf - dst); + else + *destlen = 0; + + return ret; +} diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c index 69ed796ee327..a76d4c4f29f5 100644 --- a/drivers/crypto/nx/nx-aes-cbc.c +++ b/drivers/crypto/nx/nx-aes-cbc.c @@ -127,7 +127,6 @@ struct crypto_alg nx_cbc_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_cbc_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 7aeac678b9c0..ef5eae6d1400 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -430,7 +430,6 @@ struct crypto_alg nx_ccm_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_aead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ccm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { @@ -453,7 +452,6 @@ struct crypto_alg nx_ccm4309_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_nivaead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ccm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c index 52d4eb05e8f7..b6286f14680b 100644 --- a/drivers/crypto/nx/nx-aes-ctr.c +++ b/drivers/crypto/nx/nx-aes-ctr.c @@ -141,7 +141,6 @@ struct crypto_alg nx_ctr_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ctr_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { @@ -163,7 +162,6 @@ struct crypto_alg nx_ctr3686_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ctr_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c index 7b77bc2d1df4..ba5f1611336f 100644 --- a/drivers/crypto/nx/nx-aes-ecb.c +++ b/drivers/crypto/nx/nx-aes-ecb.c @@ -126,7 +126,6 @@ struct crypto_alg nx_ecb_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_ecb_init, .cra_exit = nx_crypto_ctx_exit, .cra_blkcipher = { diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index 9ab1c7341dac..c8109edc5cfb 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -316,7 +316,6 @@ struct crypto_alg nx_gcm_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_aead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_gcm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { @@ -338,7 +337,6 @@ struct crypto_alg nx_gcm4106_aes_alg = { .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_nivaead_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list), .cra_init = nx_crypto_ctx_aes_gcm_init, .cra_exit = nx_crypto_ctx_exit, .cra_aead = { diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index d7f179cc2e98..638110efae9b 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -34,7 +34,6 @@ #include <linux/device.h> #include <linux/of.h> #include <asm/pSeries_reconfig.h> -#include <asm/abs_addr.h> #include <asm/hvcall.h> #include <asm/vio.h> @@ -104,10 +103,10 @@ struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head, /* determine the start and end for this address range - slightly * different if this is in VMALLOC_REGION */ if (is_vmalloc_addr(start_addr)) - sg_addr = phys_to_abs(page_to_phys(vmalloc_to_page(start_addr))) + sg_addr = page_to_phys(vmalloc_to_page(start_addr)) + offset_in_page(sg_addr); else - sg_addr = virt_to_abs(sg_addr); + sg_addr = __pa(sg_addr); end_addr = sg_addr + len; @@ -265,17 +264,17 @@ void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function) nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT; nx_ctx->op.flags = function; - nx_ctx->op.csbcpb = virt_to_abs(nx_ctx->csbcpb); - nx_ctx->op.in = virt_to_abs(nx_ctx->in_sg); - nx_ctx->op.out = virt_to_abs(nx_ctx->out_sg); + nx_ctx->op.csbcpb = __pa(nx_ctx->csbcpb); + nx_ctx->op.in = __pa(nx_ctx->in_sg); + nx_ctx->op.out = __pa(nx_ctx->out_sg); if (nx_ctx->csbcpb_aead) { nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT; nx_ctx->op_aead.flags = function; - nx_ctx->op_aead.csbcpb = virt_to_abs(nx_ctx->csbcpb_aead); - nx_ctx->op_aead.in = virt_to_abs(nx_ctx->in_sg); - nx_ctx->op_aead.out = virt_to_abs(nx_ctx->out_sg); + nx_ctx->op_aead.csbcpb = __pa(nx_ctx->csbcpb_aead); + nx_ctx->op_aead.in = __pa(nx_ctx->in_sg); + nx_ctx->op_aead.out = __pa(nx_ctx->out_sg); } } diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 63e57b57a12c..093a8af59cbe 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -876,7 +876,6 @@ static int omap_aes_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(algs); i++) { pr_debug("i: %d\n", i); - INIT_LIST_HEAD(&algs[i].cra_list); err = crypto_register_alg(&algs[i]); if (err) goto err_algs; diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 37b2e9406af6..633ba945e153 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -328,7 +328,6 @@ static struct crypto_alg aes_alg = { .cra_ctxsize = sizeof(struct aes_ctx), .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_u = { .cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, @@ -408,7 +407,6 @@ static struct crypto_alg ecb_aes_alg = { .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, @@ -491,7 +489,6 @@ static struct crypto_alg cbc_aes_alg = { .cra_alignmask = PADLOCK_ALIGNMENT - 1, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = AES_MIN_KEY_SIZE, diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index bc986f806086..a22714412cda 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -626,7 +626,6 @@ static int s5p_aes_probe(struct platform_device *pdev) crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); for (i = 0; i < ARRAY_SIZE(algs); i++) { - INIT_LIST_HEAD(&algs[i].cra_list); err = crypto_register_alg(&algs[i]); if (err) goto err_algs; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index efff788d2f1d..da1112765a44 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -38,6 +38,7 @@ #include <linux/spinlock.h> #include <linux/rtnetlink.h> #include <linux/slab.h> +#include <linux/string.h> #include <crypto/algapi.h> #include <crypto/aes.h> @@ -714,8 +715,13 @@ badkey: /* * talitos_edesc - s/w-extended descriptor + * @assoc_nents: number of segments in associated data scatterlist * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist + * @assoc_chained: whether assoc is chained or not + * @src_chained: whether src is chained or not + * @dst_chained: whether dst is chained or not + * @iv_dma: dma address of iv for checking continuity and link table * @dma_len: length of dma mapped link_tbl space * @dma_link_tbl: bus physical address of link_tbl * @desc: h/w descriptor @@ -726,10 +732,13 @@ badkey: * of link_tbl data */ struct talitos_edesc { + int assoc_nents; int src_nents; int dst_nents; - int src_is_chained; - int dst_is_chained; + bool assoc_chained; + bool src_chained; + bool dst_chained; + dma_addr_t iv_dma; int dma_len; dma_addr_t dma_link_tbl; struct talitos_desc desc; @@ -738,7 +747,7 @@ struct talitos_edesc { static int talitos_map_sg(struct device *dev, struct scatterlist *sg, unsigned int nents, enum dma_data_direction dir, - int chained) + bool chained) { if (unlikely(chained)) while (sg) { @@ -768,13 +777,13 @@ static void talitos_sg_unmap(struct device *dev, unsigned int dst_nents = edesc->dst_nents ? : 1; if (src != dst) { - if (edesc->src_is_chained) + if (edesc->src_chained) talitos_unmap_sg_chain(dev, src, DMA_TO_DEVICE); else dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); if (dst) { - if (edesc->dst_is_chained) + if (edesc->dst_chained) talitos_unmap_sg_chain(dev, dst, DMA_FROM_DEVICE); else @@ -782,7 +791,7 @@ static void talitos_sg_unmap(struct device *dev, DMA_FROM_DEVICE); } } else - if (edesc->src_is_chained) + if (edesc->src_chained) talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL); else dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); @@ -797,7 +806,13 @@ static void ipsec_esp_unmap(struct device *dev, unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE); unmap_single_talitos_ptr(dev, &edesc->desc.ptr[0], DMA_TO_DEVICE); - dma_unmap_sg(dev, areq->assoc, 1, DMA_TO_DEVICE); + if (edesc->assoc_chained) + talitos_unmap_sg_chain(dev, areq->assoc, DMA_TO_DEVICE); + else + /* assoc_nents counts also for IV in non-contiguous cases */ + dma_unmap_sg(dev, areq->assoc, + edesc->assoc_nents ? edesc->assoc_nents - 1 : 1, + DMA_TO_DEVICE); talitos_sg_unmap(dev, edesc, areq->src, areq->dst); @@ -825,9 +840,10 @@ static void ipsec_esp_encrypt_done(struct device *dev, ipsec_esp_unmap(dev, edesc, areq); /* copy the generated ICV to dst */ - if (edesc->dma_len) { + if (edesc->dst_nents) { icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; + edesc->dst_nents + 2 + + edesc->assoc_nents]; sg = sg_last(areq->dst, edesc->dst_nents); memcpy((char *)sg_virt(sg) + sg->length - ctx->authsize, icvdata, ctx->authsize); @@ -857,7 +873,8 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, /* auth check */ if (edesc->dma_len) icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; + edesc->dst_nents + 2 + + edesc->assoc_nents]; else icvdata = &edesc->link_tbl[0]; @@ -932,10 +949,9 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, * fill in and submit ipsec_esp descriptor */ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, - u8 *giv, u64 seq, - void (*callback) (struct device *dev, - struct talitos_desc *desc, - void *context, int error)) + u64 seq, void (*callback) (struct device *dev, + struct talitos_desc *desc, + void *context, int error)) { struct crypto_aead *aead = crypto_aead_reqtfm(areq); struct talitos_ctx *ctx = crypto_aead_ctx(aead); @@ -950,12 +966,42 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, /* hmac key */ map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, 0, DMA_TO_DEVICE); + /* hmac data */ - map_single_talitos_ptr(dev, &desc->ptr[1], areq->assoclen + ivsize, - sg_virt(areq->assoc), 0, DMA_TO_DEVICE); + desc->ptr[1].len = cpu_to_be16(areq->assoclen + ivsize); + if (edesc->assoc_nents) { + int tbl_off = edesc->src_nents + edesc->dst_nents + 2; + struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; + + to_talitos_ptr(&desc->ptr[1], edesc->dma_link_tbl + tbl_off * + sizeof(struct talitos_ptr)); + desc->ptr[1].j_extent = DESC_PTR_LNKTBL_JUMP; + + /* assoc_nents - 1 entries for assoc, 1 for IV */ + sg_count = sg_to_link_tbl(areq->assoc, edesc->assoc_nents - 1, + areq->assoclen, tbl_ptr); + + /* add IV to link table */ + tbl_ptr += sg_count - 1; + tbl_ptr->j_extent = 0; + tbl_ptr++; + to_talitos_ptr(tbl_ptr, edesc->iv_dma); + tbl_ptr->len = cpu_to_be16(ivsize); + tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; + + dma_sync_single_for_device(dev, edesc->dma_link_tbl, + edesc->dma_len, DMA_BIDIRECTIONAL); + } else { + to_talitos_ptr(&desc->ptr[1], sg_dma_address(areq->assoc)); + desc->ptr[1].j_extent = 0; + } + /* cipher iv */ - map_single_talitos_ptr(dev, &desc->ptr[2], ivsize, giv ?: areq->iv, 0, - DMA_TO_DEVICE); + to_talitos_ptr(&desc->ptr[2], edesc->iv_dma); + desc->ptr[2].len = cpu_to_be16(ivsize); + desc->ptr[2].j_extent = 0; + /* Sync needed for the aead_givencrypt case */ + dma_sync_single_for_device(dev, edesc->iv_dma, ivsize, DMA_TO_DEVICE); /* cipher key */ map_single_talitos_ptr(dev, &desc->ptr[3], ctx->enckeylen, @@ -974,7 +1020,7 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE, - edesc->src_is_chained); + edesc->src_chained); if (sg_count == 1) { to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src)); @@ -1006,32 +1052,30 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, if (areq->src != areq->dst) sg_count = talitos_map_sg(dev, areq->dst, edesc->dst_nents ? : 1, - DMA_FROM_DEVICE, - edesc->dst_is_chained); + DMA_FROM_DEVICE, edesc->dst_chained); if (sg_count == 1) { to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst)); } else { - struct talitos_ptr *link_tbl_ptr = - &edesc->link_tbl[edesc->src_nents + 1]; + int tbl_off = edesc->src_nents + 1; + struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl + - (edesc->src_nents + 1) * - sizeof(struct talitos_ptr)); + tbl_off * sizeof(struct talitos_ptr)); sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, - link_tbl_ptr); + tbl_ptr); /* Add an entry to the link table for ICV data */ - link_tbl_ptr += sg_count - 1; - link_tbl_ptr->j_extent = 0; - sg_count++; - link_tbl_ptr++; - link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; - link_tbl_ptr->len = cpu_to_be16(authsize); + tbl_ptr += sg_count - 1; + tbl_ptr->j_extent = 0; + tbl_ptr++; + tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; + tbl_ptr->len = cpu_to_be16(authsize); /* icv data follows link tables */ - to_talitos_ptr(link_tbl_ptr, edesc->dma_link_tbl + - (edesc->src_nents + edesc->dst_nents + 2) * + to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + + (tbl_off + edesc->dst_nents + 1 + + edesc->assoc_nents) * sizeof(struct talitos_ptr)); desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP; dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, @@ -1053,17 +1097,17 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, /* * derive number of elements in scatterlist */ -static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained) +static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained) { struct scatterlist *sg = sg_list; int sg_nents = 0; - *chained = 0; + *chained = false; while (nbytes > 0) { sg_nents++; nbytes -= sg->length; if (!sg_is_last(sg) && (sg + 1)->length == 0) - *chained = 1; + *chained = true; sg = scatterwalk_sg_next(sg); } @@ -1132,17 +1176,21 @@ static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents, * allocate and map the extended descriptor */ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, + struct scatterlist *assoc, struct scatterlist *src, struct scatterlist *dst, - int hash_result, + u8 *iv, + unsigned int assoclen, unsigned int cryptlen, unsigned int authsize, + unsigned int ivsize, int icv_stashing, u32 cryptoflags) { struct talitos_edesc *edesc; - int src_nents, dst_nents, alloc_len, dma_len; - int src_chained, dst_chained = 0; + int assoc_nents = 0, src_nents, dst_nents, alloc_len, dma_len; + bool assoc_chained = false, src_chained = false, dst_chained = false; + dma_addr_t iv_dma = 0; gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; @@ -1151,10 +1199,29 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, return ERR_PTR(-EINVAL); } + if (iv) + iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); + + if (assoc) { + /* + * Currently it is assumed that iv is provided whenever assoc + * is. + */ + BUG_ON(!iv); + + assoc_nents = sg_count(assoc, assoclen, &assoc_chained); + talitos_map_sg(dev, assoc, assoc_nents, DMA_TO_DEVICE, + assoc_chained); + assoc_nents = (assoc_nents == 1) ? 0 : assoc_nents; + + if (assoc_nents || sg_dma_address(assoc) + assoclen != iv_dma) + assoc_nents = assoc_nents ? assoc_nents + 1 : 2; + } + src_nents = sg_count(src, cryptlen + authsize, &src_chained); src_nents = (src_nents == 1) ? 0 : src_nents; - if (hash_result) { + if (!dst) { dst_nents = 0; } else { if (dst == src) { @@ -1172,9 +1239,9 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, * and the ICV data itself */ alloc_len = sizeof(struct talitos_edesc); - if (src_nents || dst_nents) { - dma_len = (src_nents + dst_nents + 2) * - sizeof(struct talitos_ptr) + authsize; + if (assoc_nents || src_nents || dst_nents) { + dma_len = (src_nents + dst_nents + 2 + assoc_nents) * + sizeof(struct talitos_ptr) + authsize; alloc_len += dma_len; } else { dma_len = 0; @@ -1183,14 +1250,20 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc = kmalloc(alloc_len, GFP_DMA | flags); if (!edesc) { + talitos_unmap_sg_chain(dev, assoc, DMA_TO_DEVICE); + if (iv_dma) + dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); dev_err(dev, "could not allocate edescriptor\n"); return ERR_PTR(-ENOMEM); } + edesc->assoc_nents = assoc_nents; edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; - edesc->src_is_chained = src_chained; - edesc->dst_is_chained = dst_chained; + edesc->assoc_chained = assoc_chained; + edesc->src_chained = src_chained; + edesc->dst_chained = dst_chained; + edesc->iv_dma = iv_dma; edesc->dma_len = dma_len; if (dma_len) edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0], @@ -1200,14 +1273,16 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, return edesc; } -static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, +static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, u8 *iv, int icv_stashing) { struct crypto_aead *authenc = crypto_aead_reqtfm(areq); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); + unsigned int ivsize = crypto_aead_ivsize(authenc); - return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, 0, - areq->cryptlen, ctx->authsize, icv_stashing, + return talitos_edesc_alloc(ctx->dev, areq->assoc, areq->src, areq->dst, + iv, areq->assoclen, areq->cryptlen, + ctx->authsize, ivsize, icv_stashing, areq->base.flags); } @@ -1218,14 +1293,14 @@ static int aead_encrypt(struct aead_request *req) struct talitos_edesc *edesc; /* allocate extended descriptor */ - edesc = aead_edesc_alloc(req, 0); + edesc = aead_edesc_alloc(req, req->iv, 0); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* set encrypt */ edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT; - return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done); + return ipsec_esp(edesc, req, 0, ipsec_esp_encrypt_done); } static int aead_decrypt(struct aead_request *req) @@ -1241,7 +1316,7 @@ static int aead_decrypt(struct aead_request *req) req->cryptlen -= authsize; /* allocate extended descriptor */ - edesc = aead_edesc_alloc(req, 1); + edesc = aead_edesc_alloc(req, req->iv, 1); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -1257,9 +1332,7 @@ static int aead_decrypt(struct aead_request *req) /* reset integrity check result bits */ edesc->desc.hdr_lo = 0; - return ipsec_esp(edesc, req, NULL, 0, - ipsec_esp_decrypt_hwauth_done); - + return ipsec_esp(edesc, req, 0, ipsec_esp_decrypt_hwauth_done); } /* Have to check the ICV with software */ @@ -1268,7 +1341,8 @@ static int aead_decrypt(struct aead_request *req) /* stash incoming ICV for later cmp with ICV generated by the h/w */ if (edesc->dma_len) icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2]; + edesc->dst_nents + 2 + + edesc->assoc_nents]; else icvdata = &edesc->link_tbl[0]; @@ -1277,7 +1351,7 @@ static int aead_decrypt(struct aead_request *req) memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, ctx->authsize); - return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done); + return ipsec_esp(edesc, req, 0, ipsec_esp_decrypt_swauth_done); } static int aead_givencrypt(struct aead_givcrypt_request *req) @@ -1288,7 +1362,7 @@ static int aead_givencrypt(struct aead_givcrypt_request *req) struct talitos_edesc *edesc; /* allocate extended descriptor */ - edesc = aead_edesc_alloc(areq, 0); + edesc = aead_edesc_alloc(areq, req->giv, 0); if (IS_ERR(edesc)) return PTR_ERR(edesc); @@ -1299,8 +1373,7 @@ static int aead_givencrypt(struct aead_givcrypt_request *req) /* avoid consecutive packets going out with same IV */ *(__be64 *)req->giv ^= cpu_to_be64(req->seq); - return ipsec_esp(edesc, areq, req->giv, req->seq, - ipsec_esp_encrypt_done); + return ipsec_esp(edesc, areq, req->seq, ipsec_esp_encrypt_done); } static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, @@ -1356,7 +1429,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, struct device *dev = ctx->dev; struct talitos_desc *desc = &edesc->desc; unsigned int cryptlen = areq->nbytes; - unsigned int ivsize; + unsigned int ivsize = crypto_ablkcipher_ivsize(cipher); int sg_count, ret; /* first DWORD empty */ @@ -1365,9 +1438,9 @@ static int common_nonsnoop(struct talitos_edesc *edesc, desc->ptr[0].j_extent = 0; /* cipher iv */ - ivsize = crypto_ablkcipher_ivsize(cipher); - map_single_talitos_ptr(dev, &desc->ptr[1], ivsize, areq->info, 0, - DMA_TO_DEVICE); + to_talitos_ptr(&desc->ptr[1], edesc->iv_dma); + desc->ptr[1].len = cpu_to_be16(ivsize); + desc->ptr[1].j_extent = 0; /* cipher key */ map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen, @@ -1382,7 +1455,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1, (areq->src == areq->dst) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE, - edesc->src_is_chained); + edesc->src_chained); if (sg_count == 1) { to_talitos_ptr(&desc->ptr[3], sg_dma_address(areq->src)); @@ -1409,8 +1482,7 @@ static int common_nonsnoop(struct talitos_edesc *edesc, if (areq->src != areq->dst) sg_count = talitos_map_sg(dev, areq->dst, edesc->dst_nents ? : 1, - DMA_FROM_DEVICE, - edesc->dst_is_chained); + DMA_FROM_DEVICE, edesc->dst_chained); if (sg_count == 1) { to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->dst)); @@ -1450,9 +1522,11 @@ static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request * { struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq); struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); + unsigned int ivsize = crypto_ablkcipher_ivsize(cipher); - return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, 0, - areq->nbytes, 0, 0, areq->base.flags); + return talitos_edesc_alloc(ctx->dev, NULL, areq->src, areq->dst, + areq->info, 0, areq->nbytes, 0, ivsize, 0, + areq->base.flags); } static int ablkcipher_encrypt(struct ablkcipher_request *areq) @@ -1578,8 +1652,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc, sg_count = talitos_map_sg(dev, req_ctx->psrc, edesc->src_nents ? : 1, - DMA_TO_DEVICE, - edesc->src_is_chained); + DMA_TO_DEVICE, edesc->src_chained); if (sg_count == 1) { to_talitos_ptr(&desc->ptr[3], sg_dma_address(req_ctx->psrc)); @@ -1631,8 +1704,8 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq, struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); - return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, 1, - nbytes, 0, 0, areq->base.flags); + return talitos_edesc_alloc(ctx->dev, NULL, req_ctx->psrc, NULL, NULL, 0, + nbytes, 0, 0, 0, areq->base.flags); } static int ahash_init(struct ahash_request *areq) @@ -1690,7 +1763,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes) unsigned int nbytes_to_hash; unsigned int to_hash_later; unsigned int nsg; - int chained; + bool chained; if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) { /* Buffer up to one whole block */ @@ -1902,21 +1975,18 @@ struct talitos_alg_template { }; static struct talitos_alg_template driver_algs[] = { - /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */ + /* + * AEAD algorithms. These use a single-pass ipsec_esp descriptor. + * authencesn(*,*) is also registered, although not present + * explicitly here. + */ { .type = CRYPTO_ALG_TYPE_AEAD, .alg.crypto = { .cra_name = "authenc(hmac(sha1),cbc(aes))", .cra_driver_name = "authenc-hmac-sha1-cbc-aes-talitos", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "<built-in>", .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, } @@ -1935,14 +2005,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha1-cbc-3des-talitos", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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 = SHA1_DIGEST_SIZE, } @@ -1962,14 +2025,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha224-cbc-aes-talitos", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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, } @@ -1988,14 +2044,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha224-cbc-3des-talitos", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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, } @@ -2015,14 +2064,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha256-cbc-aes-talitos", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "<built-in>", .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, } @@ -2041,14 +2083,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha256-cbc-3des-talitos", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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 = SHA256_DIGEST_SIZE, } @@ -2068,14 +2103,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha384-cbc-aes-talitos", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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, } @@ -2094,14 +2122,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha384-cbc-3des-talitos", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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, } @@ -2121,14 +2142,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha512-cbc-aes-talitos", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "<built-in>", .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, } @@ -2147,14 +2161,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-sha512-cbc-3des-talitos", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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 = SHA512_DIGEST_SIZE, } @@ -2174,14 +2181,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-md5-cbc-aes-talitos", .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "<built-in>", .ivsize = AES_BLOCK_SIZE, .maxauthsize = MD5_DIGEST_SIZE, } @@ -2200,14 +2200,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_driver_name = "authenc-hmac-md5-cbc-3des-talitos", .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_aead_type, .cra_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 = MD5_DIGEST_SIZE, } @@ -2229,12 +2222,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = AES_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ablkcipher_type, .cra_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, @@ -2251,12 +2239,7 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ablkcipher_type, .cra_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "eseqiv", .min_keysize = DES3_EDE_KEY_SIZE, .max_keysize = DES3_EDE_KEY_SIZE, .ivsize = DES3_EDE_BLOCK_SIZE, @@ -2270,11 +2253,6 @@ static struct talitos_alg_template driver_algs[] = { /* AHASH algorithms. */ { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, .halg.digestsize = MD5_DIGEST_SIZE, .halg.base = { .cra_name = "md5", @@ -2282,7 +2260,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = MD5_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2291,11 +2268,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, .halg.digestsize = SHA1_DIGEST_SIZE, .halg.base = { .cra_name = "sha1", @@ -2303,7 +2275,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA1_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2312,11 +2283,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, .halg.digestsize = SHA224_DIGEST_SIZE, .halg.base = { .cra_name = "sha224", @@ -2324,7 +2290,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA224_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2333,11 +2298,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, .halg.digestsize = SHA256_DIGEST_SIZE, .halg.base = { .cra_name = "sha256", @@ -2345,7 +2305,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA256_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2354,11 +2313,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, .halg.digestsize = SHA384_DIGEST_SIZE, .halg.base = { .cra_name = "sha384", @@ -2366,7 +2320,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA384_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2375,11 +2328,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, .halg.digestsize = SHA512_DIGEST_SIZE, .halg.base = { .cra_name = "sha512", @@ -2387,7 +2335,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA512_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2396,12 +2343,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, - .setkey = ahash_setkey, .halg.digestsize = MD5_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(md5)", @@ -2409,7 +2350,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = MD5_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2418,12 +2358,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, - .setkey = ahash_setkey, .halg.digestsize = SHA1_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha1)", @@ -2431,7 +2365,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA1_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2440,12 +2373,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, - .setkey = ahash_setkey, .halg.digestsize = SHA224_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha224)", @@ -2453,7 +2380,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA224_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2462,12 +2388,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, - .setkey = ahash_setkey, .halg.digestsize = SHA256_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha256)", @@ -2475,7 +2395,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA256_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2484,12 +2403,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, - .setkey = ahash_setkey, .halg.digestsize = SHA384_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha384)", @@ -2497,7 +2410,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA384_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2506,12 +2418,6 @@ static struct talitos_alg_template driver_algs[] = { }, { .type = CRYPTO_ALG_TYPE_AHASH, .alg.hash = { - .init = ahash_init, - .update = ahash_update, - .final = ahash_final, - .finup = ahash_finup, - .digest = ahash_digest, - .setkey = ahash_setkey, .halg.digestsize = SHA512_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha512)", @@ -2519,7 +2425,6 @@ static struct talitos_alg_template driver_algs[] = { .cra_blocksize = SHA512_BLOCK_SIZE, .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, - .cra_type = &crypto_ahash_type } }, .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU | @@ -2677,14 +2582,34 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, case CRYPTO_ALG_TYPE_ABLKCIPHER: alg = &t_alg->algt.alg.crypto; alg->cra_init = talitos_cra_init; + alg->cra_type = &crypto_ablkcipher_type; + alg->cra_ablkcipher.setkey = ablkcipher_setkey; + alg->cra_ablkcipher.encrypt = ablkcipher_encrypt; + alg->cra_ablkcipher.decrypt = ablkcipher_decrypt; + alg->cra_ablkcipher.geniv = "eseqiv"; break; case CRYPTO_ALG_TYPE_AEAD: alg = &t_alg->algt.alg.crypto; alg->cra_init = talitos_cra_init_aead; + alg->cra_type = &crypto_aead_type; + alg->cra_aead.setkey = aead_setkey; + alg->cra_aead.setauthsize = aead_setauthsize; + alg->cra_aead.encrypt = aead_encrypt; + alg->cra_aead.decrypt = aead_decrypt; + alg->cra_aead.givencrypt = aead_givencrypt; + alg->cra_aead.geniv = "<built-in>"; break; case CRYPTO_ALG_TYPE_AHASH: alg = &t_alg->algt.alg.hash.halg.base; alg->cra_init = talitos_cra_init_ahash; + alg->cra_type = &crypto_ahash_type; + t_alg->algt.alg.hash.init = ahash_init; + t_alg->algt.alg.hash.update = ahash_update; + t_alg->algt.alg.hash.final = ahash_final; + t_alg->algt.alg.hash.finup = ahash_finup; + t_alg->algt.alg.hash.digest = ahash_digest; + t_alg->algt.alg.hash.setkey = ahash_setkey; + if (!(priv->features & TALITOS_FTR_HMAC_OK) && !strncmp(alg->cra_name, "hmac", 4)) { kfree(t_alg); @@ -2896,7 +2821,9 @@ static int talitos_probe(struct platform_device *ofdev) if (hw_supports(dev, driver_algs[i].desc_hdr_template)) { struct talitos_crypto_alg *t_alg; char *name = NULL; + bool authenc = false; +authencesn: t_alg = talitos_alg_alloc(dev, &driver_algs[i]); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); @@ -2911,6 +2838,8 @@ static int talitos_probe(struct platform_device *ofdev) err = crypto_register_alg( &t_alg->algt.alg.crypto); name = t_alg->algt.alg.crypto.cra_driver_name; + authenc = authenc ? !authenc : + !(bool)memcmp(name, "authenc", 7); break; case CRYPTO_ALG_TYPE_AHASH: err = crypto_register_ahash( @@ -2923,8 +2852,25 @@ static int talitos_probe(struct platform_device *ofdev) dev_err(dev, "%s alg registration failed\n", name); kfree(t_alg); - } else + } else { list_add_tail(&t_alg->entry, &priv->alg_list); + if (authenc) { + struct crypto_alg *alg = + &driver_algs[i].alg.crypto; + + name = alg->cra_name; + memmove(name + 10, name + 7, + strlen(name) - 7); + memcpy(name + 7, "esn", 3); + + name = alg->cra_driver_name; + memmove(name + 10, name + 7, + strlen(name) - 7); + memcpy(name + 7, "esn", 3); + + goto authencesn; + } + } } } if (!list_empty(&priv->alg_list)) diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c index ac236f6724f4..37185e6630cd 100644 --- a/drivers/crypto/tegra-aes.c +++ b/drivers/crypto/tegra-aes.c @@ -969,6 +969,7 @@ static int tegra_aes_probe(struct platform_device *pdev) aes_wq = alloc_workqueue("tegra_aes_wq", WQ_HIGHPRI | WQ_UNBOUND, 1); if (!aes_wq) { dev_err(dev, "alloc_workqueue failed\n"); + err = -ENOMEM; goto out; } @@ -1004,8 +1005,6 @@ static int tegra_aes_probe(struct platform_device *pdev) 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; diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c index ef17e3871c71..bc615cc56266 100644 --- a/drivers/crypto/ux500/cryp/cryp_core.c +++ b/drivers/crypto/ux500/cryp/cryp_core.c @@ -1486,6 +1486,7 @@ static int ux500_cryp_probe(struct platform_device *pdev) if (!res_irq) { dev_err(dev, "[%s]: IORESOURCE_IRQ unavailable", __func__); + ret = -ENODEV; goto out_power; } diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c index 08765072a2b3..632c3339895f 100644 --- a/drivers/crypto/ux500/hash/hash_core.c +++ b/drivers/crypto/ux500/hash/hash_core.c @@ -1991,7 +1991,6 @@ static int __init ux500_hash_mod_init(void) static void __exit ux500_hash_mod_fini(void) { platform_driver_unregister(&hash_driver); - return; } module_init(ux500_hash_mod_init); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 3491654cdf7b..a815d44c70a4 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -582,7 +582,7 @@ void dmaengine_get(void) list_del_rcu(&device->global_node); break; } else if (err) - pr_err("%s: failed to get %s: (%d)\n", + pr_debug("%s: failed to get %s: (%d)\n", __func__, dma_chan_name(chan), err); } } diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index a1e791ec25d3..4fe66fa183ec 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -212,7 +212,7 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit mpc85xx_pci_err_probe(struct platform_device *op) +int __devinit mpc85xx_pci_err_probe(struct platform_device *op) { struct edac_pci_ctl_info *pci; struct mpc85xx_pci_pdata *pdata; @@ -226,6 +226,16 @@ static int __devinit mpc85xx_pci_err_probe(struct platform_device *op) if (!pci) return -ENOMEM; + /* make sure error reporting method is sane */ + switch (edac_op_state) { + case EDAC_OPSTATE_POLL: + case EDAC_OPSTATE_INT: + break; + default: + edac_op_state = EDAC_OPSTATE_INT; + break; + } + pdata = pci->pvt_info; pdata->name = "mpc85xx_pci_err"; pdata->irq = NO_IRQ; @@ -315,6 +325,7 @@ err: devres_release_group(&op->dev, mpc85xx_pci_err_probe); return res; } +EXPORT_SYMBOL(mpc85xx_pci_err_probe); static int mpc85xx_pci_err_remove(struct platform_device *op) { @@ -338,27 +349,6 @@ static int mpc85xx_pci_err_remove(struct platform_device *op) return 0; } -static struct of_device_id mpc85xx_pci_err_of_match[] = { - { - .compatible = "fsl,mpc8540-pcix", - }, - { - .compatible = "fsl,mpc8540-pci", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, mpc85xx_pci_err_of_match); - -static struct platform_driver mpc85xx_pci_err_driver = { - .probe = mpc85xx_pci_err_probe, - .remove = __devexit_p(mpc85xx_pci_err_remove), - .driver = { - .name = "mpc85xx_pci_err", - .owner = THIS_MODULE, - .of_match_table = mpc85xx_pci_err_of_match, - }, -}; - #endif /* CONFIG_PCI */ /**************************** L2 Err device ***************************/ @@ -1210,12 +1200,6 @@ static int __init mpc85xx_mc_init(void) if (res) printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n"); -#ifdef CONFIG_PCI - res = platform_driver_register(&mpc85xx_pci_err_driver); - if (res) - printk(KERN_WARNING EDAC_MOD_STR "PCI fails to register\n"); -#endif - #ifdef CONFIG_FSL_SOC_BOOKE pvr = mfspr(SPRN_PVR); @@ -1252,9 +1236,6 @@ static void __exit mpc85xx_mc_exit(void) on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); } #endif -#ifdef CONFIG_PCI - platform_driver_unregister(&mpc85xx_pci_err_driver); -#endif platform_driver_unregister(&mpc85xx_l2_err_driver); platform_driver_unregister(&mpc85xx_mc_err_driver); } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8382dc832929..aa73ef3233b8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -409,6 +409,13 @@ config GPIO_TWL4030 Say yes here to access the GPIO signals of various multi-function power management chips from Texas Instruments. +config GPIO_TWL6040 + tristate "TWL6040 GPO" + depends on TWL6040_CORE + help + Say yes here to access the GPO signals of twl6040 + audio chip from Texas Instruments. + config GPIO_WM831X tristate "WM831x GPIOs" depends on MFD_WM831X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0ffaa8423e87..b2c109d1303d 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o +obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index b7c06517403d..d4d617966696 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -49,6 +49,10 @@ static const u8 ichx_regs[3][3] = { {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ }; +static const u8 ichx_reglen[3] = { + 0x30, 0x10, 0x10, +}; + #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) #define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) @@ -75,6 +79,7 @@ static struct { struct resource *pm_base; /* Power Mangagment IO base */ struct ichx_desc *desc; /* Pointer to chipset-specific description */ u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ + u8 use_gpio; /* Which GPIO groups are usable */ } ichx_priv; static int modparam_gpiobase = -1; /* dynamic */ @@ -123,8 +128,16 @@ static int ichx_read_bit(int reg, unsigned nr) return data & (1 << bit) ? 1 : 0; } +static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) +{ + return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO; +} + static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { + if (!ichx_gpio_check_available(gpio, nr)) + return -ENXIO; + /* * Try setting pin as an input and verify it worked since many pins * are output-only. @@ -138,6 +151,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { + if (!ichx_gpio_check_available(gpio, nr)) + return -ENXIO; + /* Set GPIO output value. */ ichx_write_bit(GPIO_LVL, nr, val, 0); @@ -153,6 +169,9 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) { + if (!ichx_gpio_check_available(chip, nr)) + return -ENXIO; + return ichx_read_bit(GPIO_LVL, nr); } @@ -161,6 +180,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) unsigned long flags; u32 data; + if (!ichx_gpio_check_available(chip, nr)) + return -ENXIO; + /* * GPI 0 - 15 need to be read from the power management registers on * a ICH6/3100 bridge. @@ -291,6 +313,46 @@ static struct ichx_desc intel5_desc = { .ngpio = 76, }; +static int __devinit ichx_gpio_request_regions(struct resource *res_base, + const char *name, u8 use_gpio) +{ + int i; + + if (!res_base || !res_base->start || !res_base->end) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + if (!(use_gpio & (1 << i))) + continue; + if (!request_region(res_base->start + ichx_regs[0][i], + ichx_reglen[i], name)) + goto request_err; + } + return 0; + +request_err: + /* Clean up: release already requested regions, if any */ + for (i--; i >= 0; i--) { + if (!(use_gpio & (1 << i))) + continue; + release_region(res_base->start + ichx_regs[0][i], + ichx_reglen[i]); + } + return -EBUSY; +} + +static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + if (!(use_gpio & (1 << i))) + continue; + release_region(res_base->start + ichx_regs[0][i], + ichx_reglen[i]); + } +} + static int __devinit ichx_gpio_probe(struct platform_device *pdev) { struct resource *res_base, *res_pm; @@ -329,12 +391,11 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev) } res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); - if (!res_base || !res_base->start || !res_base->end) - return -ENODEV; - - if (!request_region(res_base->start, resource_size(res_base), - pdev->name)) - return -EBUSY; + ichx_priv.use_gpio = ich_info->use_gpio; + err = ichx_gpio_request_regions(res_base, pdev->name, + ichx_priv.use_gpio); + if (err) + return err; ichx_priv.gpio_base = res_base; @@ -374,8 +435,7 @@ init: return 0; add_err: - release_region(ichx_priv.gpio_base->start, - resource_size(ichx_priv.gpio_base)); + ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); if (ichx_priv.pm_base) release_region(ichx_priv.pm_base->start, resource_size(ichx_priv.pm_base)); @@ -393,8 +453,7 @@ static int __devexit ichx_gpio_remove(struct platform_device *pdev) return err; } - release_region(ichx_priv.gpio_base->start, - resource_size(ichx_priv.gpio_base)); + ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); if (ichx_priv.pm_base) release_region(ichx_priv.pm_base->start, resource_size(ichx_priv.pm_base)); diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c new file mode 100644 index 000000000000..dd58e8b25043 --- /dev/null +++ b/drivers/gpio/gpio-twl6040.c @@ -0,0 +1,137 @@ +/* + * Access to GPOs on TWL6040 chip + * + * Copyright (C) 2012 Texas Instruments, Inc. + * + * Authors: + * Sergio Aguirre <saaguirre@ti.com> + * Peter Ujfalusi <peter.ujfalusi@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; 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 <linux/module.h> +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include <linux/mfd/twl6040.h> + +static struct gpio_chip twl6040gpo_chip; + +static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) +{ + struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent); + int ret = 0; + + ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL); + if (ret < 0) + return ret; + + return (ret >> offset) & 1; +} + +static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + /* This only drives GPOs, and can't change direction */ + return 0; +} + +static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent); + int ret; + u8 gpoctl; + + ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL); + if (ret < 0) + return; + + if (value) + gpoctl = ret | (1 << offset); + else + gpoctl = ret & ~(1 << offset); + + twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl); +} + +static struct gpio_chip twl6040gpo_chip = { + .label = "twl6040", + .owner = THIS_MODULE, + .get = twl6040gpo_get, + .direction_output = twl6040gpo_direction_out, + .set = twl6040gpo_set, + .can_sleep = 1, +}; + +/*----------------------------------------------------------------------*/ + +static int __devinit gpo_twl6040_probe(struct platform_device *pdev) +{ + struct twl6040_gpo_data *pdata = pdev->dev.platform_data; + struct device *twl6040_core_dev = pdev->dev.parent; + struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev); + int ret; + + if (pdata) + twl6040gpo_chip.base = pdata->gpio_base; + else + twl6040gpo_chip.base = -1; + + if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0) + twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */ + else + twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */ + + twl6040gpo_chip.dev = &pdev->dev; +#ifdef CONFIG_OF_GPIO + twl6040gpo_chip.of_node = twl6040_core_dev->of_node; +#endif + + ret = gpiochip_add(&twl6040gpo_chip); + if (ret < 0) { + dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); + twl6040gpo_chip.ngpio = 0; + } + + return ret; +} + +static int __devexit gpo_twl6040_remove(struct platform_device *pdev) +{ + return gpiochip_remove(&twl6040gpo_chip); +} + +/* Note: this hardware lives inside an I2C-based multi-function device. */ +MODULE_ALIAS("platform:twl6040-gpo"); + +static struct platform_driver gpo_twl6040_driver = { + .driver = { + .name = "twl6040-gpo", + .owner = THIS_MODULE, + }, + .probe = gpo_twl6040_probe, + .remove = gpo_twl6040_remove, +}; + +module_platform_driver(gpo_twl6040_driver); + +MODULE_AUTHOR("Texas Instruments, Inc."); +MODULE_DESCRIPTION("GPO interface for TWL6040"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 2091ae8f539a..2421d95130d4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -982,7 +982,7 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap) if (adap->nr == -1) /* -1 means dynamically assign bus id */ return i2c_add_adapter(adap); - if (adap->nr & ~MAX_ID_MASK) + if (adap->nr & ~MAX_IDR_MASK) return -EINVAL; retry: diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c index 57d00caefc86..01451940393b 100644 --- a/drivers/ide/aec62xx.c +++ b/drivers/ide/aec62xx.c @@ -181,7 +181,7 @@ static const struct ide_port_ops atp86x_port_ops = { .cable_detect = atp86x_cable_detect, }; -static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { +static const struct ide_port_info aec62xx_chipsets[] __devinitconst = { { /* 0: AEC6210 */ .name = DRV_NAME, .init_chipset = init_chipset_aec62xx, diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c index d3be99fb4154..8f3570ee64c3 100644 --- a/drivers/ide/ali14xx.c +++ b/drivers/ide/ali14xx.c @@ -52,13 +52,13 @@ /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static const int ports[ALI_NUM_PORTS] __initdata = +static const int ports[ALI_NUM_PORTS] __initconst = { 0x074, 0x0f4, 0x034, 0x0e4 }; /* register initialization data */ typedef struct { u8 reg, data; } RegInitializer; -static const RegInitializer initData[] __initdata = { +static const RegInitializer initData[] __initconst = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c index 2c8016ad0e26..911a27ca356b 100644 --- a/drivers/ide/alim15x3.c +++ b/drivers/ide/alim15x3.c @@ -512,7 +512,7 @@ static const struct ide_dma_ops ali_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_port_info ali15x3_chipset __devinitdata = { +static const struct ide_port_info ali15x3_chipset __devinitconst = { .name = DRV_NAME, .init_chipset = init_chipset_ali15x3, .init_hwif = init_hwif_ali15x3, diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c index 3747b2561f09..56fc99557ba2 100644 --- a/drivers/ide/amd74xx.c +++ b/drivers/ide/amd74xx.c @@ -223,7 +223,7 @@ static const struct ide_port_ops amd_port_ops = { .udma_mask = udma, \ } -static const struct ide_port_info amd74xx_chipsets[] __devinitdata = { +static const struct ide_port_info amd74xx_chipsets[] __devinitconst = { /* 0: AMD7401 */ DECLARE_AMD_DEV(0x00, ATA_UDMA2), /* 1: AMD7409 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4), /* 2: AMD7411/7441 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5), diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c index 15f0ead89f5c..cb43480b1bd5 100644 --- a/drivers/ide/atiixp.c +++ b/drivers/ide/atiixp.c @@ -139,7 +139,7 @@ static const struct ide_port_ops atiixp_port_ops = { .cable_detect = atiixp_cable_detect, }; -static const struct ide_port_info atiixp_pci_info[] __devinitdata = { +static const struct ide_port_info atiixp_pci_info[] __devinitconst = { { /* 0: IXP200/300/400/700 */ .name = DRV_NAME, .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index 14717304b388..70f0a2754c13 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -685,7 +685,7 @@ static int pci_conf2(void) return 0; } -static const struct ide_port_info cmd640_port_info __initdata = { +static const struct ide_port_info cmd640_port_info __initconst = { .chipset = ide_cmd640, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA | diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 5f80312e636b..d1fc43802f5d 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -327,7 +327,7 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { +static const struct ide_port_info cmd64x_chipsets[] __devinitconst = { { /* 0: CMD643 */ .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c index 2c1e5f7cd261..14447621e60b 100644 --- a/drivers/ide/cs5520.c +++ b/drivers/ide/cs5520.c @@ -94,7 +94,7 @@ static const struct ide_port_ops cs5520_port_ops = { .set_dma_mode = cs5520_set_dma_mode, }; -static const struct ide_port_info cyrix_chipset __devinitdata = { +static const struct ide_port_info cyrix_chipset __devinitconst = { .name = DRV_NAME, .enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } }, .port_ops = &cs5520_port_ops, diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c index 4dc4eb92b076..49b40ad59d1a 100644 --- a/drivers/ide/cs5530.c +++ b/drivers/ide/cs5530.c @@ -245,7 +245,7 @@ static const struct ide_port_ops cs5530_port_ops = { .udma_filter = cs5530_udma_filter, }; -static const struct ide_port_info cs5530_chipset __devinitdata = { +static const struct ide_port_info cs5530_chipset __devinitconst = { .name = DRV_NAME, .init_chipset = init_chipset_cs5530, .init_hwif = init_hwif_cs5530, diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c index 5059fafadf29..18d4c852602b 100644 --- a/drivers/ide/cs5535.c +++ b/drivers/ide/cs5535.c @@ -170,7 +170,7 @@ static const struct ide_port_ops cs5535_port_ops = { .cable_detect = cs5535_cable_detect, }; -static const struct ide_port_info cs5535_chipset __devinitdata = { +static const struct ide_port_info cs5535_chipset __devinitconst = { .name = DRV_NAME, .port_ops = &cs5535_port_ops, .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE, diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c index 847553fd8b96..3ffb49dab574 100644 --- a/drivers/ide/cy82c693.c +++ b/drivers/ide/cy82c693.c @@ -163,7 +163,7 @@ static const struct ide_port_ops cy82c693_port_ops = { .set_dma_mode = cy82c693_set_dma_mode, }; -static const struct ide_port_info cy82c693_chipset __devinitdata = { +static const struct ide_port_info cy82c693_chipset __devinitconst = { .name = DRV_NAME, .init_iops = init_iops_cy82c693, .port_ops = &cy82c693_port_ops, diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c index 46af4743b3e6..8722df329cbe 100644 --- a/drivers/ide/dtc2278.c +++ b/drivers/ide/dtc2278.c @@ -91,7 +91,7 @@ static const struct ide_port_ops dtc2278_port_ops = { .set_pio_mode = dtc2278_set_pio_mode, }; -static const struct ide_port_info dtc2278_port_info __initdata = { +static const struct ide_port_info dtc2278_port_info __initconst = { .name = DRV_NAME, .chipset = ide_dtc2278, .port_ops = &dtc2278_port_ops, diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 58c51cddc100..4aec3b87ff91 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -443,7 +443,7 @@ static struct hpt_timings hpt37x_timings = { } }; -static const struct hpt_info hpt36x __devinitdata = { +static const struct hpt_info hpt36x __devinitconst = { .chip_name = "HPT36x", .chip_type = HPT36x, .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2, @@ -451,7 +451,7 @@ static const struct hpt_info hpt36x __devinitdata = { .timings = &hpt36x_timings }; -static const struct hpt_info hpt370 __devinitdata = { +static const struct hpt_info hpt370 __devinitconst = { .chip_name = "HPT370", .chip_type = HPT370, .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, @@ -459,7 +459,7 @@ static const struct hpt_info hpt370 __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt370a __devinitdata = { +static const struct hpt_info hpt370a __devinitconst = { .chip_name = "HPT370A", .chip_type = HPT370A, .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, @@ -467,7 +467,7 @@ static const struct hpt_info hpt370a __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt374 __devinitdata = { +static const struct hpt_info hpt374 __devinitconst = { .chip_name = "HPT374", .chip_type = HPT374, .udma_mask = ATA_UDMA5, @@ -475,7 +475,7 @@ static const struct hpt_info hpt374 __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt372 __devinitdata = { +static const struct hpt_info hpt372 __devinitconst = { .chip_name = "HPT372", .chip_type = HPT372, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -483,7 +483,7 @@ static const struct hpt_info hpt372 __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt372a __devinitdata = { +static const struct hpt_info hpt372a __devinitconst = { .chip_name = "HPT372A", .chip_type = HPT372A, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -491,7 +491,7 @@ static const struct hpt_info hpt372a __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt302 __devinitdata = { +static const struct hpt_info hpt302 __devinitconst = { .chip_name = "HPT302", .chip_type = HPT302, .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -499,7 +499,7 @@ static const struct hpt_info hpt302 __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt371 __devinitdata = { +static const struct hpt_info hpt371 __devinitconst = { .chip_name = "HPT371", .chip_type = HPT371, .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -507,7 +507,7 @@ static const struct hpt_info hpt371 __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt372n __devinitdata = { +static const struct hpt_info hpt372n __devinitconst = { .chip_name = "HPT372N", .chip_type = HPT372N, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -515,7 +515,7 @@ static const struct hpt_info hpt372n __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt302n __devinitdata = { +static const struct hpt_info hpt302n __devinitconst = { .chip_name = "HPT302N", .chip_type = HPT302N, .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -523,7 +523,7 @@ static const struct hpt_info hpt302n __devinitdata = { .timings = &hpt37x_timings }; -static const struct hpt_info hpt371n __devinitdata = { +static const struct hpt_info hpt371n __devinitconst = { .chip_name = "HPT371N", .chip_type = HPT371N, .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, @@ -1361,7 +1361,7 @@ static const struct ide_dma_ops hpt36x_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_port_info hpt366_chipsets[] __devinitdata = { +static const struct ide_port_info hpt366_chipsets[] __devinitconst = { { /* 0: HPT36x */ .name = DRV_NAME, .init_chipset = init_chipset_hpt366, diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c index 986f2513eab4..1e0fd3aa962d 100644 --- a/drivers/ide/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -341,7 +341,7 @@ static const struct ide_port_ops ht6560b_port_ops = { .set_pio_mode = ht6560b_set_pio_mode, }; -static const struct ide_port_info ht6560b_port_info __initdata = { +static const struct ide_port_info ht6560b_port_info __initconst = { .name = DRV_NAME, .chipset = ide_ht6560b, .tp_ops = &ht6560b_tp_ops, diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index bcb507b0cfd4..e640d0ac3af6 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -451,7 +451,7 @@ err_free: return ret; } -static const struct ide_port_info icside_v6_port_info __initdata = { +static const struct ide_port_info icside_v6_port_info __initconst = { .init_dma = icside_dma_off_init, .port_ops = &icside_v6_no_dma_port_ops, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c index 7f56b738d762..dab5b670bfbf 100644 --- a/drivers/ide/ide-pci-generic.c +++ b/drivers/ide/ide-pci-generic.c @@ -53,7 +53,7 @@ static const struct ide_port_ops netcell_port_ops = { .udma_mask = ATA_UDMA6, \ } -static const struct ide_port_info generic_chipsets[] __devinitdata = { +static const struct ide_port_info generic_chipsets[] __devinitconst = { /* 0: Unknown */ DECLARE_GENERIC_PCI_DEV(0), diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c index 560e66d07659..d5dd180c4b85 100644 --- a/drivers/ide/it8172.c +++ b/drivers/ide/it8172.c @@ -115,7 +115,7 @@ static const struct ide_port_ops it8172_port_ops = { .set_dma_mode = it8172_set_dma_mode, }; -static const struct ide_port_info it8172_port_info __devinitdata = { +static const struct ide_port_info it8172_port_info __devinitconst = { .name = DRV_NAME, .port_ops = &it8172_port_ops, .enablebits = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} }, diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c index 46816ba26416..1847aeb5450a 100644 --- a/drivers/ide/it8213.c +++ b/drivers/ide/it8213.c @@ -156,7 +156,7 @@ static const struct ide_port_ops it8213_port_ops = { .cable_detect = it8213_cable_detect, }; -static const struct ide_port_info it8213_chipset __devinitdata = { +static const struct ide_port_info it8213_chipset __devinitconst = { .name = DRV_NAME, .enablebits = { {0x41, 0x80, 0x80} }, .port_ops = &it8213_port_ops, diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c index 2e3169f2acda..c5611dbca342 100644 --- a/drivers/ide/it821x.c +++ b/drivers/ide/it821x.c @@ -630,7 +630,7 @@ static const struct ide_port_ops it821x_port_ops = { .cable_detect = it821x_cable_detect, }; -static const struct ide_port_info it821x_chipset __devinitdata = { +static const struct ide_port_info it821x_chipset __devinitconst = { .name = DRV_NAME, .init_chipset = init_chipset_it821x, .init_hwif = init_hwif_it821x, diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c index 74c2c4a6d909..efddd7d9f92d 100644 --- a/drivers/ide/jmicron.c +++ b/drivers/ide/jmicron.c @@ -102,7 +102,7 @@ static const struct ide_port_ops jmicron_port_ops = { .cable_detect = jmicron_cable_detect, }; -static const struct ide_port_info jmicron_chipset __devinitdata = { +static const struct ide_port_info jmicron_chipset __devinitconst = { .name = DRV_NAME, .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } }, .port_ops = &jmicron_port_ops, diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c index 95327a2c2422..73f78d872d55 100644 --- a/drivers/ide/ns87415.c +++ b/drivers/ide/ns87415.c @@ -293,7 +293,7 @@ static const struct ide_dma_ops ns87415_dma_ops = { .dma_sff_read_status = superio_dma_sff_read_status, }; -static const struct ide_port_info ns87415_chipset __devinitdata = { +static const struct ide_port_info ns87415_chipset __devinitconst = { .name = DRV_NAME, .init_hwif = init_hwif_ns87415, .tp_ops = &ns87415_tp_ops, diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c index 1a53a4c375ed..39edc66cb96c 100644 --- a/drivers/ide/opti621.c +++ b/drivers/ide/opti621.c @@ -131,7 +131,7 @@ static const struct ide_port_ops opti621_port_ops = { .set_pio_mode = opti621_set_pio_mode, }; -static const struct ide_port_info opti621_chipset __devinitdata = { +static const struct ide_port_info opti621_chipset __devinitconst = { .name = DRV_NAME, .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, .port_ops = &opti621_port_ops, diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c index 9546fe2a93f7..2e5ceb62fb3b 100644 --- a/drivers/ide/pdc202xx_new.c +++ b/drivers/ide/pdc202xx_new.c @@ -465,7 +465,7 @@ static const struct ide_port_ops pdcnew_port_ops = { .udma_mask = udma, \ } -static const struct ide_port_info pdcnew_chipsets[] __devinitdata = { +static const struct ide_port_info pdcnew_chipsets[] __devinitconst = { /* 0: PDC202{68,70} */ DECLARE_PDCNEW_DEV(ATA_UDMA5), /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6), }; diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c index 3a35ec6193d2..563451096812 100644 --- a/drivers/ide/pdc202xx_old.c +++ b/drivers/ide/pdc202xx_old.c @@ -270,7 +270,7 @@ static const struct ide_dma_ops pdc2026x_dma_ops = { .max_sectors = sectors, \ } -static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = { +static const struct ide_port_info pdc202xx_chipsets[] __devinitconst = { { /* 0: PDC20246 */ .name = DRV_NAME, .init_chipset = init_chipset_pdc202xx, diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index 1892e81fb00f..fe0fd60cfc09 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -344,7 +344,7 @@ static const struct ide_port_ops ich_port_ops = { .udma_mask = udma, \ } -static const struct ide_port_info piix_pci_info[] __devinitdata = { +static const struct ide_port_info piix_pci_info[] __devinitconst = { /* 0: MPIIX */ { /* * MPIIX actually has only a single IDE channel mapped to diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index e03f4f19c1d6..a6fb6a894c7b 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -335,7 +335,7 @@ static const struct ide_port_ops qd6580_port_ops = { .set_pio_mode = qd6580_set_pio_mode, }; -static const struct ide_port_info qd65xx_port_info __initdata = { +static const struct ide_port_info qd65xx_port_info __initconst = { .name = DRV_NAME, .tp_ops = &qd65xx_tp_ops, .chipset = ide_qd65xx, diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c index a6414a884eb1..c04173e9fc38 100644 --- a/drivers/ide/rz1000.c +++ b/drivers/ide/rz1000.c @@ -38,7 +38,7 @@ static int __devinit rz1000_disable_readahead(struct pci_dev *dev) } } -static const struct ide_port_info rz1000_chipset __devinitdata = { +static const struct ide_port_info rz1000_chipset __devinitconst = { .name = DRV_NAME, .host_flags = IDE_HFLAG_NO_DMA, }; diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c index 356b9b504ffd..d4758ebe77da 100644 --- a/drivers/ide/sc1200.c +++ b/drivers/ide/sc1200.c @@ -291,7 +291,7 @@ static const struct ide_dma_ops sc1200_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_port_info sc1200_chipset __devinitdata = { +static const struct ide_port_info sc1200_chipset __devinitconst = { .name = DRV_NAME, .port_ops = &sc1200_port_ops, .dma_ops = &sc1200_dma_ops, diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c index b7f5b0c4310c..970103810021 100644 --- a/drivers/ide/scc_pata.c +++ b/drivers/ide/scc_pata.c @@ -811,7 +811,7 @@ static const struct ide_dma_ops scc_dma_ops = { .dma_sff_read_status = scc_dma_sff_read_status, }; -static const struct ide_port_info scc_chipset __devinitdata = { +static const struct ide_port_info scc_chipset __devinitconst = { .name = "sccIDE", .init_iops = init_iops_scc, .init_dma = scc_init_dma, diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c index 35fb8dabb55d..24d72ef23df7 100644 --- a/drivers/ide/serverworks.c +++ b/drivers/ide/serverworks.c @@ -337,7 +337,7 @@ static const struct ide_port_ops svwks_port_ops = { .cable_detect = svwks_cable_detect, }; -static const struct ide_port_info serverworks_chipsets[] __devinitdata = { +static const struct ide_port_info serverworks_chipsets[] __devinitconst = { { /* 0: OSB4 */ .name = DRV_NAME, .init_chipset = init_chipset_svwks, diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c index ddeda444a27a..46f7e30d3790 100644 --- a/drivers/ide/siimage.c +++ b/drivers/ide/siimage.c @@ -719,7 +719,7 @@ static const struct ide_dma_ops sil_dma_ops = { .udma_mask = ATA_UDMA6, \ } -static const struct ide_port_info siimage_chipsets[] __devinitdata = { +static const struct ide_port_info siimage_chipsets[] __devinitconst = { /* 0: SiI680 */ DECLARE_SII_DEV(&sil_pata_port_ops), /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops) }; diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index 4a0022567758..09e61b4c5e94 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -563,7 +563,7 @@ static const struct ide_port_ops sis_ata133_port_ops = { .cable_detect = sis_cable_detect, }; -static const struct ide_port_info sis5513_chipset __devinitdata = { +static const struct ide_port_info sis5513_chipset __devinitconst = { .name = DRV_NAME, .init_chipset = init_chipset_sis5513, .enablebits = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} }, diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c index f21dc2ad7682..d051cd224bdb 100644 --- a/drivers/ide/sl82c105.c +++ b/drivers/ide/sl82c105.c @@ -299,7 +299,7 @@ static const struct ide_dma_ops sl82c105_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_port_info sl82c105_chipset __devinitdata = { +static const struct ide_port_info sl82c105_chipset __devinitconst = { .name = DRV_NAME, .init_chipset = init_chipset_sl82c105, .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c index 864ffe0e26d9..863a5e9283ca 100644 --- a/drivers/ide/slc90e66.c +++ b/drivers/ide/slc90e66.c @@ -132,7 +132,7 @@ static const struct ide_port_ops slc90e66_port_ops = { .cable_detect = slc90e66_cable_detect, }; -static const struct ide_port_info slc90e66_chipset __devinitdata = { +static const struct ide_port_info slc90e66_chipset __devinitconst = { .name = DRV_NAME, .enablebits = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} }, .port_ops = &slc90e66_port_ops, diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c index 4799d5c384e7..17946785ebf6 100644 --- a/drivers/ide/tc86c001.c +++ b/drivers/ide/tc86c001.c @@ -192,7 +192,7 @@ static const struct ide_dma_ops tc86c001_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_port_info tc86c001_chipset __devinitdata = { +static const struct ide_port_info tc86c001_chipset __devinitconst = { .name = DRV_NAME, .init_hwif = init_hwif_tc86c001, .port_ops = &tc86c001_port_ops, diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c index 281c91426345..55ce1b80efcb 100644 --- a/drivers/ide/triflex.c +++ b/drivers/ide/triflex.c @@ -92,7 +92,7 @@ static const struct ide_port_ops triflex_port_ops = { .set_dma_mode = triflex_set_mode, }; -static const struct ide_port_info triflex_device __devinitdata = { +static const struct ide_port_info triflex_device __devinitconst = { .name = DRV_NAME, .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}}, .port_ops = &triflex_port_ops, diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c index 4b42ca091534..e494a98a43a9 100644 --- a/drivers/ide/trm290.c +++ b/drivers/ide/trm290.c @@ -324,7 +324,7 @@ static struct ide_dma_ops trm290_dma_ops = { .dma_check = trm290_dma_check, }; -static const struct ide_port_info trm290_chipset __devinitdata = { +static const struct ide_port_info trm290_chipset __devinitconst = { .name = DRV_NAME, .init_hwif = init_hwif_trm290, .tp_ops = &trm290_tp_ops, diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c index 7002765b593c..91d49dd957ef 100644 --- a/drivers/ide/tx4938ide.c +++ b/drivers/ide/tx4938ide.c @@ -117,7 +117,7 @@ static const struct ide_port_ops tx4938ide_port_ops = { .set_pio_mode = tx4938ide_set_pio_mode, }; -static const struct ide_port_info tx4938ide_port_info __initdata = { +static const struct ide_port_info tx4938ide_port_info __initconst = { .port_ops = &tx4938ide_port_ops, #ifdef __BIG_ENDIAN .tp_ops = &tx4938ide_tp_ops, diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c index 71c231954972..c0ab800b7bb3 100644 --- a/drivers/ide/tx4939ide.c +++ b/drivers/ide/tx4939ide.c @@ -522,7 +522,7 @@ static const struct ide_dma_ops tx4939ide_dma_ops = { .dma_sff_read_status = tx4939ide_dma_sff_read_status, }; -static const struct ide_port_info tx4939ide_port_info __initdata = { +static const struct ide_port_info tx4939ide_port_info __initconst = { .init_hwif = tx4939ide_init_hwif, .init_dma = tx4939ide_init_dma, .port_ops = &tx4939ide_port_ops, diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c index 5cfb78120669..3aa0fea0f3d9 100644 --- a/drivers/ide/umc8672.c +++ b/drivers/ide/umc8672.c @@ -128,7 +128,7 @@ static const struct ide_port_ops umc8672_port_ops = { .set_pio_mode = umc_set_pio_mode, }; -static const struct ide_port_info umc8672_port_info __initdata = { +static const struct ide_port_info umc8672_port_info __initconst = { .name = DRV_NAME, .chipset = ide_umc8672, .port_ops = &umc8672_port_ops, diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index f46f49cfcc28..eb7767864d10 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -403,7 +403,7 @@ static const struct ide_port_ops via_port_ops = { .cable_detect = via82cxxx_cable_detect, }; -static const struct ide_port_info via82cxxx_chipset __devinitdata = { +static const struct ide_port_info via82cxxx_chipset __devinitconst = { .name = DRV_NAME, .init_chipset = init_chipset_via82cxxx, .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index d67999f6e34a..394fea2ba1bc 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -390,7 +390,7 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv) ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id, &id); if (!ret) - next_id = ((unsigned) id + 1) & MAX_ID_MASK; + next_id = ((unsigned) id + 1) & MAX_IDR_MASK; spin_unlock_irqrestore(&cm.lock, flags); } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index d9b0ebcb67d7..8f5290147e8a 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -220,7 +220,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, cq = ERR_PTR(-EAGAIN); goto create_cq_exit4; } - rpage = virt_to_abs(vpage); + rpage = __pa(vpage); h_ret = hipz_h_register_rpage_cq(adapter_handle, my_cq->ipz_cq_handle, diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index 818d721fc448..90da6747d395 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -101,7 +101,7 @@ int ehca_create_eq(struct ehca_shca *shca, if (!vpage) goto create_eq_exit2; - rpage = virt_to_abs(vpage); + rpage = __pa(vpage); h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, eq->ipz_eq_handle, &eq->pf, diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index b781b2cb0624..87844869dcc2 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -1136,7 +1136,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca, } if (rnum > 1) { - rpage = virt_to_abs(kpage); + rpage = __pa(kpage); if (!rpage) { ehca_err(&shca->ib_device, "kpage=%p i=%x", kpage, i); @@ -1231,7 +1231,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca, pginfo->num_kpages, pginfo->num_hwpages, kpage); goto ehca_rereg_mr_rereg1_exit1; } - rpage = virt_to_abs(kpage); + rpage = __pa(kpage); if (!rpage) { ehca_err(&shca->ib_device, "kpage=%p", kpage); ret = -EFAULT; @@ -1525,7 +1525,7 @@ static inline void *ehca_calc_sectbase(int top, int dir, int idx) unsigned long ret = idx; ret |= dir << EHCA_DIR_INDEX_SHIFT; ret |= top << EHCA_TOP_INDEX_SHIFT; - return abs_to_virt(ret << SECTION_SIZE_BITS); + return __va(ret << SECTION_SIZE_BITS); } #define ehca_bmap_valid(entry) \ @@ -1537,7 +1537,7 @@ static u64 ehca_reg_mr_section(int top, int dir, int idx, u64 *kpage, { u64 h_ret = 0; unsigned long page = 0; - u64 rpage = virt_to_abs(kpage); + u64 rpage = __pa(kpage); int page_count; void *sectbase = ehca_calc_sectbase(top, dir, idx); @@ -1553,7 +1553,7 @@ static u64 ehca_reg_mr_section(int top, int dir, int idx, u64 *kpage, for (rnum = 0; (rnum < MAX_RPAGES) && (page < page_count); rnum++) { void *pg = sectbase + ((page++) * pginfo->hwpage_size); - kpage[rnum] = virt_to_abs(pg); + kpage[rnum] = __pa(pg); } h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, mr, @@ -1870,9 +1870,8 @@ static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo, for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) { pgaddr = page_to_pfn(sg_page(&chunk->page_list[i])) << PAGE_SHIFT ; - *kpage = phys_to_abs(pgaddr + - (pginfo->next_hwpage * - pginfo->hwpage_size)); + *kpage = pgaddr + (pginfo->next_hwpage * + pginfo->hwpage_size); if ( !(*kpage) ) { ehca_gen_err("pgaddr=%llx " "chunk->page_list[i]=%llx " @@ -1927,7 +1926,7 @@ static int ehca_check_kpages_per_ate(struct scatterlist *page_list, u64 pgaddr = page_to_pfn(sg_page(&page_list[t])) << PAGE_SHIFT; if (ehca_debug_level >= 3) ehca_gen_dbg("chunk_page=%llx value=%016llx", pgaddr, - *(u64 *)abs_to_virt(phys_to_abs(pgaddr))); + *(u64 *)__va(pgaddr)); if (pgaddr - PAGE_SIZE != *prev_pgaddr) { ehca_gen_err("uncontiguous page found pgaddr=%llx " "prev_pgaddr=%llx page_list_i=%x", @@ -1962,7 +1961,7 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo, if (nr_kpages == kpages_per_hwpage) { pgaddr = ( page_to_pfn(sg_page(&chunk->page_list[i])) << PAGE_SHIFT ); - *kpage = phys_to_abs(pgaddr); + *kpage = pgaddr; if ( !(*kpage) ) { ehca_gen_err("pgaddr=%llx i=%x", pgaddr, i); @@ -1990,13 +1989,11 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo, (pginfo->hwpage_size - 1)) >> PAGE_SHIFT; nr_kpages -= pginfo->kpage_cnt; - *kpage = phys_to_abs( - pgaddr & - ~(pginfo->hwpage_size - 1)); + *kpage = pgaddr & + ~(pginfo->hwpage_size - 1); } if (ehca_debug_level >= 3) { - u64 val = *(u64 *)abs_to_virt( - phys_to_abs(pgaddr)); + u64 val = *(u64 *)__va(pgaddr); ehca_gen_dbg("kpage=%llx chunk_page=%llx " "value=%016llx", *kpage, pgaddr, val); @@ -2084,9 +2081,8 @@ static int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo, pginfo->num_hwpages, i); return -EFAULT; } - *kpage = phys_to_abs( - (pbuf->addr & ~(pginfo->hwpage_size - 1)) + - (pginfo->next_hwpage * pginfo->hwpage_size)); + *kpage = (pbuf->addr & ~(pginfo->hwpage_size - 1)) + + (pginfo->next_hwpage * pginfo->hwpage_size); if ( !(*kpage) && pbuf->addr ) { ehca_gen_err("pbuf->addr=%llx pbuf->size=%llx " "next_hwpage=%llx", pbuf->addr, @@ -2124,8 +2120,8 @@ static int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo, /* loop over desired page_list entries */ fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem; for (i = 0; i < number; i++) { - *kpage = phys_to_abs((*fmrlist & ~(pginfo->hwpage_size - 1)) + - pginfo->next_hwpage * pginfo->hwpage_size); + *kpage = (*fmrlist & ~(pginfo->hwpage_size - 1)) + + pginfo->next_hwpage * pginfo->hwpage_size; if ( !(*kpage) ) { ehca_gen_err("*fmrlist=%llx fmrlist=%p " "next_listelem=%llx next_hwpage=%llx", @@ -2152,8 +2148,7 @@ static int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo, u64 prev = *kpage; /* check if adrs are contiguous */ for (j = 1; j < cnt_per_hwpage; j++) { - u64 p = phys_to_abs(fmrlist[j] & - ~(pginfo->hwpage_size - 1)); + u64 p = fmrlist[j] & ~(pginfo->hwpage_size - 1); if (prev + pginfo->u.fmr.fmr_pgsize != p) { ehca_gen_err("uncontiguous fmr pages " "found prev=%llx p=%llx " @@ -2388,8 +2383,8 @@ static int ehca_update_busmap(unsigned long pfn, unsigned long nr_pages) memset(ehca_bmap, 0xFF, EHCA_TOP_MAP_SIZE); } - start_section = phys_to_abs(pfn * PAGE_SIZE) / EHCA_SECTSIZE; - end_section = phys_to_abs((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE; + start_section = (pfn * PAGE_SIZE) / EHCA_SECTSIZE; + end_section = ((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE; for (i = start_section; i < end_section; i++) { int ret; top = ehca_calc_index(i, EHCA_TOP_INDEX_SHIFT); @@ -2508,7 +2503,7 @@ static u64 ehca_map_vaddr(void *caddr) if (!ehca_bmap) return EHCA_INVAL_ADDR; - abs_addr = virt_to_abs(caddr); + abs_addr = __pa(caddr); top = ehca_calc_index(abs_addr, EHCA_TOP_INDEX_SHIFT + EHCA_SECTSHIFT); if (!ehca_bmap_valid(ehca_bmap->top[top])) return EHCA_INVAL_ADDR; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 964f85520798..149393915ae5 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -321,7 +321,7 @@ static inline int init_qp_queue(struct ehca_shca *shca, ret = -EINVAL; goto init_qp_queue1; } - rpage = virt_to_abs(vpage); + rpage = __pa(vpage); h_ret = hipz_h_register_rpage_qp(ipz_hca_handle, my_qp->ipz_qp_handle, @@ -1094,7 +1094,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca, ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p", qp_num, bad_send_wqe_p); /* convert wqe pointer to vadr */ - bad_send_wqe_v = abs_to_virt((u64)bad_send_wqe_p); + bad_send_wqe_v = __va((u64)bad_send_wqe_p); if (ehca_debug_level >= 2) ehca_dmp(bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num); squeue = &my_qp->ipz_squeue; @@ -1138,7 +1138,7 @@ static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue, /* convert real to abs address */ wqe_p = wqe_p & (~(1UL << 63)); - wqe_v = abs_to_virt(wqe_p); + wqe_v = __va(wqe_p); if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) { ehca_gen_err("Invalid offset for calculating left cqes " diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index fd05f48f6b0b..47f94984353d 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -135,7 +135,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) mad_hdr->attr_mod); } for (j = 0; j < send_wr->num_sge; j++) { - u8 *data = (u8 *)abs_to_virt(sge->addr); + u8 *data = __va(sge->addr); ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x " "lkey=%x", idx, j, data, sge->length, sge->lkey); diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h index 54c0d23bad92..d280b12aae64 100644 --- a/drivers/infiniband/hw/ehca/ehca_tools.h +++ b/drivers/infiniband/hw/ehca/ehca_tools.h @@ -59,7 +59,6 @@ #include <linux/device.h> #include <linux/atomic.h> -#include <asm/abs_addr.h> #include <asm/ibmebus.h> #include <asm/io.h> #include <asm/pgtable.h> diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c index e6f9cdd94c7a..2d41d04fd959 100644 --- a/drivers/infiniband/hw/ehca/hcp_if.c +++ b/drivers/infiniband/hw/ehca/hcp_if.c @@ -396,7 +396,7 @@ u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle, struct hipz_query_port *query_port_response_block) { u64 ret; - u64 r_cb = virt_to_abs(query_port_response_block); + u64 r_cb = __pa(query_port_response_block); if (r_cb & (EHCA_PAGESIZE-1)) { ehca_gen_err("response block not page aligned"); @@ -438,7 +438,7 @@ u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle, u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle, struct hipz_query_hca *query_hca_rblock) { - u64 r_cb = virt_to_abs(query_hca_rblock); + u64 r_cb = __pa(query_hca_rblock); if (r_cb & (EHCA_PAGESIZE-1)) { ehca_gen_err("response_block=%p not page aligned", @@ -577,7 +577,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle, adapter_handle.handle, /* r4 */ qp_handle.handle, /* r5 */ update_mask, /* r6 */ - virt_to_abs(mqpcb), /* r7 */ + __pa(mqpcb), /* r7 */ 0, 0, 0, 0, 0); if (ret == H_NOT_ENOUGH_RESOURCES) @@ -595,7 +595,7 @@ u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle, return ehca_plpar_hcall_norets(H_QUERY_QP, adapter_handle.handle, /* r4 */ qp_handle.handle, /* r5 */ - virt_to_abs(qqpcb), /* r6 */ + __pa(qqpcb), /* r6 */ 0, 0, 0, 0); } @@ -787,7 +787,7 @@ u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle, if (count > 1) { u64 *kpage; int i; - kpage = (u64 *)abs_to_virt(logical_address_of_page); + kpage = __va(logical_address_of_page); for (i = 0; i < count; i++) ehca_gen_dbg("kpage[%d]=%p", i, (void *)kpage[i]); @@ -944,7 +944,7 @@ u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle, void *rblock, unsigned long *byte_count) { - u64 r_cb = virt_to_abs(rblock); + u64 r_cb = __pa(rblock); if (r_cb & (EHCA_PAGESIZE-1)) { ehca_gen_err("rblock not page aligned."); diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c index 1898d6e7cce5..62c71fadb4d9 100644 --- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c @@ -81,7 +81,7 @@ int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset) { int i; for (i = 0; i < queue->queue_length / queue->pagesize; i++) { - u64 page = (u64)virt_to_abs(queue->queue_pages[i]); + u64 page = __pa(queue->queue_pages[i]); if (addr >= page && addr < page + queue->pagesize) { *q_offset = addr - page + i * queue->pagesize; return 0; diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c index e25e4dafb8a8..80079e5a2e30 100644 --- a/drivers/infiniband/hw/mlx4/cm.c +++ b/drivers/infiniband/hw/mlx4/cm.c @@ -225,7 +225,7 @@ id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id) ret = idr_get_new_above(&sriov->pv_id_table, ent, next_id, &id); if (!ret) { - next_id = ((unsigned) id + 1) & MAX_ID_MASK; + next_id = ((unsigned) id + 1) & MAX_IDR_MASK; ent->pv_cm_id = (u32)id; sl_id_map_add(ibdev, ent); } diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index fc0ed9b43424..2194a3c7236a 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <linux/workqueue.h> #include <linux/i2c/twl.h> #include <linux/mfd/twl4030-audio.h> @@ -194,13 +195,26 @@ static int twl4030_vibra_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, twl4030_vibra_suspend, twl4030_vibra_resume); +static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata, + struct device_node *node) +{ + if (pdata && pdata->coexist) + return true; + + if (of_find_node_by_name(node, "codec")) + return true; + + return false; +} + static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { struct twl4030_vibra_data *pdata = pdev->dev.platform_data; + struct device_node *twl4030_core_node = pdev->dev.parent->of_node; struct vibra_info *info; int ret; - if (!pdata) { + if (!pdata && !twl4030_core_node) { dev_dbg(&pdev->dev, "platform_data not available\n"); return -EINVAL; } @@ -210,7 +224,7 @@ static int __devinit twl4030_vibra_probe(struct platform_device *pdev) return -ENOMEM; info->dev = &pdev->dev; - info->coexist = pdata->coexist; + info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node); INIT_WORK(&info->play_work, vibra_play_work); info->input_dev = input_allocate_device(); diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 05f30b73c3c3..326218dbd6e6 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -10,6 +10,7 @@ */ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/input.h> @@ -113,14 +114,69 @@ static void pm860x_touch_close(struct input_dev *dev) pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0); } +#ifdef CONFIG_OF +static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, + struct pm860x_chip *chip, + int *res_x) +{ + struct device_node *np = pdev->dev.parent->of_node; + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int data, n, ret; + if (!np) + return -ENODEV; + np = of_find_node_by_name(np, "touch"); + if (!np) { + dev_err(&pdev->dev, "Can't find touch node\n"); + return -EINVAL; + } + /* set GPADC MISC1 register */ + data = 0; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-prebias", &n)) + data |= (n << 1) & PM8607_GPADC_PREBIAS_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-slot-cycle", &n)) + data |= (n << 3) & PM8607_GPADC_SLOT_CYCLE_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-off-scale", &n)) + data |= (n << 5) & PM8607_GPADC_OFF_SCALE_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-sw-cal", &n)) + data |= (n << 7) & PM8607_GPADC_SW_CAL_MASK; + if (data) { + ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); + if (ret < 0) + return -EINVAL; + } + /* set tsi prebias time */ + if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) { + ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } + /* set prebias & prechg time of pen detect */ + data = 0; + if (!of_property_read_u32(np, "marvell,88pm860x-pen-prebias", &n)) + data |= n & PM8607_PD_PREBIAS_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-pen-prechg", &n)) + data |= n & PM8607_PD_PRECHG_MASK; + if (data) { + ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } + of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); + return 0; +} +#else +#define pm860x_touch_dt_init(x, y, z) (-1) +#endif + static int __devinit pm860x_touch_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_platform_data *pm860x_pdata = \ - pdev->dev.parent->platform_data; - struct pm860x_touch_pdata *pdata = NULL; + struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; struct pm860x_touch *touch; - int irq, ret; + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int irq, ret, res_x = 0, data = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -128,16 +184,55 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) return -EINVAL; } - if (!pm860x_pdata) { - dev_err(&pdev->dev, "platform data is missing\n"); - return -EINVAL; - } - - pdata = pm860x_pdata->touch; - if (!pdata) { - dev_err(&pdev->dev, "touchscreen data is missing\n"); - return -EINVAL; + if (pm860x_touch_dt_init(pdev, chip, &res_x)) { + if (pdata) { + /* set GPADC MISC1 register */ + data = 0; + data |= (pdata->gpadc_prebias << 1) + & PM8607_GPADC_PREBIAS_MASK; + data |= (pdata->slot_cycle << 3) + & PM8607_GPADC_SLOT_CYCLE_MASK; + data |= (pdata->off_scale << 5) + & PM8607_GPADC_OFF_SCALE_MASK; + data |= (pdata->sw_cal << 7) + & PM8607_GPADC_SW_CAL_MASK; + if (data) { + ret = pm860x_reg_write(i2c, + PM8607_GPADC_MISC1, data); + if (ret < 0) + return -EINVAL; + } + /* set tsi prebias time */ + if (pdata->tsi_prebias) { + data = pdata->tsi_prebias; + ret = pm860x_reg_write(i2c, + PM8607_TSI_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } + /* set prebias & prechg time of pen detect */ + data = 0; + data |= pdata->pen_prebias + & PM8607_PD_PREBIAS_MASK; + data |= (pdata->pen_prechg << 5) + & PM8607_PD_PRECHG_MASK; + if (data) { + ret = pm860x_reg_write(i2c, + PM8607_PD_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } + res_x = pdata->res_x; + } else { + dev_err(&pdev->dev, "failed to get platform data\n"); + return -EINVAL; + } } + /* enable GPADC */ + ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, PM8607_GPADC_EN, + PM8607_GPADC_EN); + if (ret) + return ret; touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); if (touch == NULL) @@ -158,9 +253,9 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) touch->idev->open = pm860x_touch_open; touch->idev->close = pm860x_touch_close; touch->chip = chip; - touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; - touch->irq = irq + chip->irq_base; - touch->res_x = pdata->res_x; + touch->i2c = i2c; + touch->irq = irq; + touch->res_x = res_x; input_set_drvdata(touch->idev, touch); ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 61897cfeeda6..b7e8cc0957fc 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/leds.h> @@ -20,18 +21,12 @@ #include <linux/mfd/88pm860x.h> #include <linux/module.h> -#define LED_PWM_SHIFT (3) #define LED_PWM_MASK (0x1F) #define LED_CURRENT_MASK (0x07 << 5) -#define LED_BLINK_ON_MASK (0x07) #define LED_BLINK_MASK (0x7F) -#define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66) -#define LED_BLINK_ON_MIN LED_BLINK_ON(0) -#define LED_BLINK_ON_MAX LED_BLINK_ON(0x7) #define LED_ON_CONTINUOUS (0x0F << 3) -#define LED_TO_ON(x) ((x - 66) / 66) #define LED1_BLINK_EN (1 << 1) #define LED2_BLINK_EN (1 << 2) @@ -49,85 +44,25 @@ struct pm860x_led { unsigned char brightness; unsigned char current_brightness; - int blink_data; - int blink_time; - int blink_on; - int blink_off; + int reg_control; + int reg_blink; + int blink_mask; }; -/* return offset of color register */ -static inline int __led_off(int port) -{ - int ret = -EINVAL; - - switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: - ret = port - PM8606_LED1_RED + PM8606_RGB1B; - break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: - ret = port - PM8606_LED2_RED + PM8606_RGB2B; - break; - } - return ret; -} - -/* return offset of blink register */ -static inline int __blink_off(int port) -{ - int ret = -EINVAL; - - switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: - ret = PM8606_RGB1A; - break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: - ret = PM8606_RGB2A; - break; - } - return ret; -} - -static inline int __blink_ctl_mask(int port) -{ - int ret = -EINVAL; - - switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: - ret = LED1_BLINK_EN; - break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: - ret = LED2_BLINK_EN; - break; - } - return ret; -} - static int led_power_set(struct pm860x_chip *chip, int port, int on) { int ret = -EINVAL; switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: + case 0: + case 1: + case 2: ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) : pm8606_osc_disable(chip, RGB1_ENABLE); break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: + case 3: + case 4: + case 5: ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) : pm8606_osc_disable(chip, RGB2_ENABLE); break; @@ -141,7 +76,7 @@ static void pm860x_led_work(struct work_struct *work) struct pm860x_led *led; struct pm860x_chip *chip; unsigned char buf[3]; - int mask, ret; + int ret; led = container_of(work, struct pm860x_led, work); chip = led->chip; @@ -149,34 +84,34 @@ static void pm860x_led_work(struct work_struct *work) if ((led->current_brightness == 0) && led->brightness) { led_power_set(chip, led->port, 1); if (led->iset) { - pm860x_set_bits(led->i2c, __led_off(led->port), + pm860x_set_bits(led->i2c, led->reg_control, LED_CURRENT_MASK, led->iset); } - pm860x_set_bits(led->i2c, __blink_off(led->port), + pm860x_set_bits(led->i2c, led->reg_blink, LED_BLINK_MASK, LED_ON_CONTINUOUS); - mask = __blink_ctl_mask(led->port); - pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); + pm860x_set_bits(led->i2c, PM8606_WLED3B, led->blink_mask, + led->blink_mask); } - pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, + pm860x_set_bits(led->i2c, led->reg_control, LED_PWM_MASK, led->brightness); if (led->brightness == 0) { - pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf); + pm860x_bulk_read(led->i2c, led->reg_control, 3, buf); ret = buf[0] & LED_PWM_MASK; ret |= buf[1] & LED_PWM_MASK; ret |= buf[2] & LED_PWM_MASK; if (ret == 0) { /* unset current since no led is lighting */ - pm860x_set_bits(led->i2c, __led_off(led->port), + pm860x_set_bits(led->i2c, led->reg_control, LED_CURRENT_MASK, 0); - mask = __blink_ctl_mask(led->port); - pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); + pm860x_set_bits(led->i2c, PM8606_WLED3B, + led->blink_mask, 0); led_power_set(chip, led->port, 0); } } led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", - __led_off(led->port), led->brightness); + led->reg_control, led->brightness); mutex_unlock(&led->lock); } @@ -189,39 +124,92 @@ static void pm860x_led_set(struct led_classdev *cdev, schedule_work(&data->work); } +#ifdef CONFIG_OF +static int pm860x_led_dt_init(struct platform_device *pdev, + struct pm860x_led *data) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "leds"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find leds node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, data->name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_LED_CURRENT(iset); + break; + } + } + return 0; +} +#else +#define pm860x_led_dt_init(x, y) (-1) +#endif + static int pm860x_led_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_led_pdata *pdata; + struct pm860x_led_pdata *pdata = pdev->dev.platform_data; struct pm860x_led *data; struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "No platform data!\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_led), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(data->name, res->name, MFD_NAME_SIZE - 1); + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "control"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for control\n"); + ret = -ENXIO; + goto out; + } + data->reg_control = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "blink"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for blink\n"); + ret = -ENXIO; + goto out; + } + data->reg_blink = res->start; + memset(data->name, 0, MFD_NAME_SIZE); + switch (pdev->id) { + case 0: + data->blink_mask = LED1_BLINK_EN; + sprintf(data->name, "led0-red"); + break; + case 1: + data->blink_mask = LED1_BLINK_EN; + sprintf(data->name, "led0-green"); + break; + case 2: + data->blink_mask = LED1_BLINK_EN; + sprintf(data->name, "led0-blue"); + break; + case 3: + data->blink_mask = LED2_BLINK_EN; + sprintf(data->name, "led1-red"); + break; + case 4: + data->blink_mask = LED2_BLINK_EN; + sprintf(data->name, "led1-green"); + break; + case 5: + data->blink_mask = LED2_BLINK_EN; + sprintf(data->name, "led1-blue"); + break; + } dev_set_drvdata(&pdev->dev, data); data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; - data->iset = pdata->iset; - data->port = pdata->flags; - if (data->port < 0) { - dev_err(&pdev->dev, "check device failed\n"); - return -EINVAL; - } + data->port = pdev->id; + if (pm860x_led_dt_init(pdev, data)) + if (pdata) + data->iset = pdata->iset; data->current_brightness = 0; data->cdev.name = data->name; @@ -236,6 +224,9 @@ static int pm860x_led_probe(struct platform_device *pdev) } pm860x_led_set(&data->cdev, 0); return 0; +out: + devm_kfree(&pdev->dev, data); + return ret; } static int pm860x_led_remove(struct platform_device *pdev) diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index 20e5c2cda430..ef87310b7662 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -748,7 +748,7 @@ static void __devexit macio_pci_remove(struct pci_dev* pdev) * MacIO is matched against any Apple ID, it's probe() function * will then decide wether it applies or not */ -static const struct pci_device_id __devinitdata pci_ids [] = { { +static const struct pci_device_id __devinitconst pci_ids[] = { { .vendor = PCI_VENDOR_ID_APPLE, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 54ac7ffacb40..7d5a6b40b31c 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -45,7 +45,6 @@ #include <asm/pmac_feature.h> #include <asm/smu.h> #include <asm/sections.h> -#include <asm/abs_addr.h> #include <asm/uaccess.h> #define VERSION "0.7" @@ -502,7 +501,7 @@ int __init smu_init (void) * 32 bits value safely */ smu->cmd_buf_abs = (u32)smu_cmdbuf_abs; - smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs); + smu->cmd_buf = __va(smu_cmdbuf_abs); smu->db_node = of_find_node_by_name(NULL, "smu-doorbell"); if (smu->db_node == NULL) { diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index b73f033b2c60..59d117e9fa31 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -11,50 +11,116 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/err.h> #include <linux/i2c.h> #include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> #include <linux/mfd/core.h> #include <linux/mfd/88pm860x.h> #include <linux/regulator/machine.h> #define INT_STATUS_NUM 3 -static struct resource bk_resources[] __devinitdata = { - {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, - {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, - {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, -}; - -static struct resource led_resources[] __devinitdata = { - {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, - {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, - {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, - {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, - {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, - {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, -}; - -static struct resource regulator_resources[] __devinitdata = { - {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,}, - {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,}, - {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,}, - {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,}, - {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,}, - {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,}, - {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,}, - {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,}, - {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,}, - {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,}, - {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,}, - {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,}, - {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,}, - {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,}, - {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,}, - {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,}, - {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,}, - {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, +static struct resource bk0_resources[] __devinitdata = { + {2, 2, "duty cycle", IORESOURCE_REG, }, + {3, 3, "always on", IORESOURCE_REG, }, + {3, 3, "current", IORESOURCE_REG, }, +}; +static struct resource bk1_resources[] __devinitdata = { + {4, 4, "duty cycle", IORESOURCE_REG, }, + {5, 5, "always on", IORESOURCE_REG, }, + {5, 5, "current", IORESOURCE_REG, }, +}; +static struct resource bk2_resources[] __devinitdata = { + {6, 6, "duty cycle", IORESOURCE_REG, }, + {7, 7, "always on", IORESOURCE_REG, }, + {5, 5, "current", IORESOURCE_REG, }, +}; + +static struct resource led0_resources[] __devinitdata = { + /* RGB1 Red LED */ + {0xd, 0xd, "control", IORESOURCE_REG, }, + {0xc, 0xc, "blink", IORESOURCE_REG, }, +}; +static struct resource led1_resources[] __devinitdata = { + /* RGB1 Green LED */ + {0xe, 0xe, "control", IORESOURCE_REG, }, + {0xc, 0xc, "blink", IORESOURCE_REG, }, +}; +static struct resource led2_resources[] __devinitdata = { + /* RGB1 Blue LED */ + {0xf, 0xf, "control", IORESOURCE_REG, }, + {0xc, 0xc, "blink", IORESOURCE_REG, }, +}; +static struct resource led3_resources[] __devinitdata = { + /* RGB2 Red LED */ + {0x9, 0x9, "control", IORESOURCE_REG, }, + {0x8, 0x8, "blink", IORESOURCE_REG, }, +}; +static struct resource led4_resources[] __devinitdata = { + /* RGB2 Green LED */ + {0xa, 0xa, "control", IORESOURCE_REG, }, + {0x8, 0x8, "blink", IORESOURCE_REG, }, +}; +static struct resource led5_resources[] __devinitdata = { + /* RGB2 Blue LED */ + {0xb, 0xb, "control", IORESOURCE_REG, }, + {0x8, 0x8, "blink", IORESOURCE_REG, }, +}; + +static struct resource buck1_resources[] __devinitdata = { + {0x24, 0x24, "buck set", IORESOURCE_REG, }, +}; +static struct resource buck2_resources[] __devinitdata = { + {0x25, 0x25, "buck set", IORESOURCE_REG, }, +}; +static struct resource buck3_resources[] __devinitdata = { + {0x26, 0x26, "buck set", IORESOURCE_REG, }, +}; +static struct resource ldo1_resources[] __devinitdata = { + {0x10, 0x10, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo2_resources[] __devinitdata = { + {0x11, 0x11, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo3_resources[] __devinitdata = { + {0x12, 0x12, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo4_resources[] __devinitdata = { + {0x13, 0x13, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo5_resources[] __devinitdata = { + {0x14, 0x14, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo6_resources[] __devinitdata = { + {0x15, 0x15, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo7_resources[] __devinitdata = { + {0x16, 0x16, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo8_resources[] __devinitdata = { + {0x17, 0x17, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo9_resources[] __devinitdata = { + {0x18, 0x18, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo10_resources[] __devinitdata = { + {0x19, 0x19, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo12_resources[] __devinitdata = { + {0x1a, 0x1a, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo_vibrator_resources[] __devinitdata = { + {0x28, 0x28, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo14_resources[] __devinitdata = { + {0x1b, 0x1b, "ldo set", IORESOURCE_REG, }, }; static struct resource touch_resources[] __devinitdata = { @@ -90,48 +156,145 @@ static struct resource charger_resources[] __devinitdata = { {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, }; -static struct resource preg_resources[] __devinitdata = { - {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO,}, -}; - static struct resource rtc_resources[] __devinitdata = { {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, }; -static struct mfd_cell bk_devs[] = { - {"88pm860x-backlight", 0,}, - {"88pm860x-backlight", 1,}, - {"88pm860x-backlight", 2,}, -}; - -static struct mfd_cell led_devs[] = { - {"88pm860x-led", 0,}, - {"88pm860x-led", 1,}, - {"88pm860x-led", 2,}, - {"88pm860x-led", 3,}, - {"88pm860x-led", 4,}, - {"88pm860x-led", 5,}, -}; - -static struct mfd_cell regulator_devs[] = { - {"88pm860x-regulator", 0,}, - {"88pm860x-regulator", 1,}, - {"88pm860x-regulator", 2,}, - {"88pm860x-regulator", 3,}, - {"88pm860x-regulator", 4,}, - {"88pm860x-regulator", 5,}, - {"88pm860x-regulator", 6,}, - {"88pm860x-regulator", 7,}, - {"88pm860x-regulator", 8,}, - {"88pm860x-regulator", 9,}, - {"88pm860x-regulator", 10,}, - {"88pm860x-regulator", 11,}, - {"88pm860x-regulator", 12,}, - {"88pm860x-regulator", 13,}, - {"88pm860x-regulator", 14,}, - {"88pm860x-regulator", 15,}, - {"88pm860x-regulator", 16,}, - {"88pm860x-regulator", 17,}, +static struct mfd_cell bk_devs[] __devinitdata = { + { + .name = "88pm860x-backlight", + .id = 0, + .num_resources = ARRAY_SIZE(bk0_resources), + .resources = bk0_resources, + }, { + .name = "88pm860x-backlight", + .id = 1, + .num_resources = ARRAY_SIZE(bk1_resources), + .resources = bk1_resources, + }, { + .name = "88pm860x-backlight", + .id = 2, + .num_resources = ARRAY_SIZE(bk2_resources), + .resources = bk2_resources, + }, +}; + +static struct mfd_cell led_devs[] __devinitdata = { + { + .name = "88pm860x-led", + .id = 0, + .num_resources = ARRAY_SIZE(led0_resources), + .resources = led0_resources, + }, { + .name = "88pm860x-led", + .id = 1, + .num_resources = ARRAY_SIZE(led1_resources), + .resources = led1_resources, + }, { + .name = "88pm860x-led", + .id = 2, + .num_resources = ARRAY_SIZE(led2_resources), + .resources = led2_resources, + }, { + .name = "88pm860x-led", + .id = 3, + .num_resources = ARRAY_SIZE(led3_resources), + .resources = led3_resources, + }, { + .name = "88pm860x-led", + .id = 4, + .num_resources = ARRAY_SIZE(led4_resources), + .resources = led4_resources, + }, { + .name = "88pm860x-led", + .id = 5, + .num_resources = ARRAY_SIZE(led5_resources), + .resources = led5_resources, + }, +}; + +static struct mfd_cell reg_devs[] __devinitdata = { + { + .name = "88pm860x-regulator", + .id = 0, + .num_resources = ARRAY_SIZE(buck1_resources), + .resources = buck1_resources, + }, { + .name = "88pm860x-regulator", + .id = 1, + .num_resources = ARRAY_SIZE(buck2_resources), + .resources = buck2_resources, + }, { + .name = "88pm860x-regulator", + .id = 2, + .num_resources = ARRAY_SIZE(buck3_resources), + .resources = buck3_resources, + }, { + .name = "88pm860x-regulator", + .id = 3, + .num_resources = ARRAY_SIZE(ldo1_resources), + .resources = ldo1_resources, + }, { + .name = "88pm860x-regulator", + .id = 4, + .num_resources = ARRAY_SIZE(ldo2_resources), + .resources = ldo2_resources, + }, { + .name = "88pm860x-regulator", + .id = 5, + .num_resources = ARRAY_SIZE(ldo3_resources), + .resources = ldo3_resources, + }, { + .name = "88pm860x-regulator", + .id = 6, + .num_resources = ARRAY_SIZE(ldo4_resources), + .resources = ldo4_resources, + }, { + .name = "88pm860x-regulator", + .id = 7, + .num_resources = ARRAY_SIZE(ldo5_resources), + .resources = ldo5_resources, + }, { + .name = "88pm860x-regulator", + .id = 8, + .num_resources = ARRAY_SIZE(ldo6_resources), + .resources = ldo6_resources, + }, { + .name = "88pm860x-regulator", + .id = 9, + .num_resources = ARRAY_SIZE(ldo7_resources), + .resources = ldo7_resources, + }, { + .name = "88pm860x-regulator", + .id = 10, + .num_resources = ARRAY_SIZE(ldo8_resources), + .resources = ldo8_resources, + }, { + .name = "88pm860x-regulator", + .id = 11, + .num_resources = ARRAY_SIZE(ldo9_resources), + .resources = ldo9_resources, + }, { + .name = "88pm860x-regulator", + .id = 12, + .num_resources = ARRAY_SIZE(ldo10_resources), + .resources = ldo10_resources, + }, { + .name = "88pm860x-regulator", + .id = 13, + .num_resources = ARRAY_SIZE(ldo12_resources), + .resources = ldo12_resources, + }, { + .name = "88pm860x-regulator", + .id = 14, + .num_resources = ARRAY_SIZE(ldo_vibrator_resources), + .resources = ldo_vibrator_resources, + }, { + .name = "88pm860x-regulator", + .id = 15, + .num_resources = ARRAY_SIZE(ldo14_resources), + .resources = ldo14_resources, + }, }; static struct mfd_cell touch_devs[] = { @@ -360,15 +523,12 @@ static void pm860x_irq_sync_unlock(struct irq_data *data) static void pm860x_irq_enable(struct irq_data *data) { - struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); - pm860x_irqs[data->irq - chip->irq_base].enable - = pm860x_irqs[data->irq - chip->irq_base].offs; + pm860x_irqs[data->hwirq].enable = pm860x_irqs[data->hwirq].offs; } static void pm860x_irq_disable(struct irq_data *data) { - struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); - pm860x_irqs[data->irq - chip->irq_base].enable = 0; + pm860x_irqs[data->hwirq].enable = 0; } static struct irq_chip pm860x_irq_chip = { @@ -379,53 +539,25 @@ static struct irq_chip pm860x_irq_chip = { .irq_disable = pm860x_irq_disable, }; -static int __devinit device_gpadc_init(struct pm860x_chip *chip, - struct pm860x_platform_data *pdata) +static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) { - struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ - : chip->companion; - int data; - int ret; - - /* initialize GPADC without activating it */ - - if (!pdata || !pdata->touch) - return -EINVAL; - - /* set GPADC MISC1 register */ - data = 0; - data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK; - data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK; - data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK; - data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK; - if (data) { - ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); - if (ret < 0) - goto out; - } - /* set tsi prebias time */ - if (pdata->touch->tsi_prebias) { - data = pdata->touch->tsi_prebias; - ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); - if (ret < 0) - goto out; - } - /* set prebias & prechg time of pen detect */ - data = 0; - data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK; - data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK; - if (data) { - ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); - if (ret < 0) - goto out; - } - - ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, - PM8607_GPADC_EN, PM8607_GPADC_EN); -out: - return ret; + irq_set_chip_data(virq, d->host_data); + irq_set_chip_and_handler(virq, &pm860x_irq_chip, handle_edge_irq); + irq_set_nested_thread(virq, 1); +#ifdef CONFIG_ARM + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + return 0; } +static struct irq_domain_ops pm860x_irq_domain_ops = { + .map = pm860x_irq_domain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + static int __devinit device_irq_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { @@ -433,13 +565,9 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, : chip->companion; unsigned char status_buf[INT_STATUS_NUM]; unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; - int i, data, mask, ret = -EINVAL; - int __irq; - - if (!pdata || !pdata->irq_base) { - dev_warn(chip->dev, "No interrupt support on IRQ base\n"); - return -EINVAL; - } + int data, mask, ret = -EINVAL; + int nr_irqs, irq_base = -1; + struct device_node *node = i2c->dev.of_node; mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR | PM8607_B0_MISC1_INT_MASK; @@ -479,26 +607,24 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, goto out; mutex_init(&chip->irq_lock); - chip->irq_base = pdata->irq_base; + + if (pdata && pdata->irq_base) + irq_base = pdata->irq_base; + nr_irqs = ARRAY_SIZE(pm860x_irqs); + chip->irq_base = irq_alloc_descs(irq_base, 0, nr_irqs, 0); + if (chip->irq_base < 0) { + dev_err(&i2c->dev, "Failed to allocate interrupts, ret:%d\n", + chip->irq_base); + ret = -EBUSY; + goto out; + } + irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0, + &pm860x_irq_domain_ops, chip); chip->core_irq = i2c->irq; if (!chip->core_irq) goto out; - /* register IRQ by genirq */ - for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { - __irq = i + chip->irq_base; - irq_set_chip_data(__irq, chip); - irq_set_chip_and_handler(__irq, &pm860x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(__irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(__irq, IRQF_VALID); -#else - irq_set_noprobe(__irq); -#endif - } - - ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags, + ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags | IRQF_ONESHOT, "88pm860x", chip); if (ret) { dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); @@ -615,108 +741,122 @@ static void __devinit device_osc_init(struct i2c_client *i2c) static void __devinit device_bk_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - int ret; - int i, j, id; - - if ((pdata == NULL) || (pdata->backlight == NULL)) - return; - - if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) - pdata->num_backlights = ARRAY_SIZE(bk_devs); - - for (i = 0; i < pdata->num_backlights; i++) { - bk_devs[i].platform_data = &pdata->backlight[i]; - bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); - - for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { - id = bk_resources[j].start; - if (pdata->backlight[i].flags != id) - continue; - - bk_devs[i].num_resources = 1; - bk_devs[i].resources = &bk_resources[j]; - ret = mfd_add_devices(chip->dev, 0, - &bk_devs[i], 1, - &bk_resources[j], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add " - "backlight subdev\n"); - return; - } + int ret, i; + + if (pdata && pdata->backlight) { + if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) + pdata->num_backlights = ARRAY_SIZE(bk_devs); + for (i = 0; i < pdata->num_backlights; i++) { + bk_devs[i].platform_data = &pdata->backlight[i]; + bk_devs[i].pdata_size = + sizeof(struct pm860x_backlight_pdata); } } + ret = mfd_add_devices(chip->dev, 0, bk_devs, + ARRAY_SIZE(bk_devs), NULL, 0, NULL); + if (ret < 0) + dev_err(chip->dev, "Failed to add backlight subdev\n"); } static void __devinit device_led_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - int ret; - int i, j, id; - - if ((pdata == NULL) || (pdata->led == NULL)) - return; - - if (pdata->num_leds > ARRAY_SIZE(led_devs)) - pdata->num_leds = ARRAY_SIZE(led_devs); - - for (i = 0; i < pdata->num_leds; i++) { - led_devs[i].platform_data = &pdata->led[i]; - led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata); - - for (j = 0; j < ARRAY_SIZE(led_devs); j++) { - id = led_resources[j].start; - if (pdata->led[i].flags != id) - continue; - - led_devs[i].num_resources = 1; - led_devs[i].resources = &led_resources[j], - ret = mfd_add_devices(chip->dev, 0, - &led_devs[i], 1, - &led_resources[j], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add " - "led subdev\n"); - return; - } + int ret, i; + + if (pdata && pdata->led) { + if (pdata->num_leds > ARRAY_SIZE(led_devs)) + pdata->num_leds = ARRAY_SIZE(led_devs); + for (i = 0; i < pdata->num_leds; i++) { + led_devs[i].platform_data = &pdata->led[i]; + led_devs[i].pdata_size = + sizeof(struct pm860x_led_pdata); } } + ret = mfd_add_devices(chip->dev, 0, led_devs, + ARRAY_SIZE(led_devs), NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add led subdev\n"); + return; + } } static void __devinit device_regulator_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - struct regulator_init_data *initdata; int ret; - int i, seq; - if ((pdata == NULL) || (pdata->regulator == NULL)) + if (pdata == NULL) + return; + if (pdata->buck1) { + reg_devs[0].platform_data = pdata->buck1; + reg_devs[0].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->buck2) { + reg_devs[1].platform_data = pdata->buck2; + reg_devs[1].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->buck3) { + reg_devs[2].platform_data = pdata->buck3; + reg_devs[2].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo1) { + reg_devs[3].platform_data = pdata->ldo1; + reg_devs[3].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo2) { + reg_devs[4].platform_data = pdata->ldo2; + reg_devs[4].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo3) { + reg_devs[5].platform_data = pdata->ldo3; + reg_devs[5].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo4) { + reg_devs[6].platform_data = pdata->ldo4; + reg_devs[6].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo5) { + reg_devs[7].platform_data = pdata->ldo5; + reg_devs[7].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo6) { + reg_devs[8].platform_data = pdata->ldo6; + reg_devs[8].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo7) { + reg_devs[9].platform_data = pdata->ldo7; + reg_devs[9].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo8) { + reg_devs[10].platform_data = pdata->ldo8; + reg_devs[10].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo9) { + reg_devs[11].platform_data = pdata->ldo9; + reg_devs[11].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo10) { + reg_devs[12].platform_data = pdata->ldo10; + reg_devs[12].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo12) { + reg_devs[13].platform_data = pdata->ldo12; + reg_devs[13].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo_vibrator) { + reg_devs[14].platform_data = pdata->ldo_vibrator; + reg_devs[14].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo14) { + reg_devs[15].platform_data = pdata->ldo14; + reg_devs[15].pdata_size = sizeof(struct regulator_init_data); + } + ret = mfd_add_devices(chip->dev, 0, reg_devs, + ARRAY_SIZE(reg_devs), NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); return; - - if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) - pdata->num_regulators = ARRAY_SIZE(regulator_devs); - - for (i = 0, seq = -1; i < pdata->num_regulators; i++) { - initdata = &pdata->regulator[i]; - seq = *(unsigned int *)initdata->driver_data; - if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) { - dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n", - seq, initdata->constraints.name); - goto out; - } - regulator_devs[i].platform_data = &pdata->regulator[i]; - regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); - regulator_devs[i].num_resources = 1; - regulator_devs[i].resources = ®ulator_resources[seq]; - - ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, - ®ulator_resources[seq], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add regulator subdev\n"); - goto out; - } } -out: - return; } static void __devinit device_rtc_init(struct pm860x_chip *chip, @@ -785,10 +925,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip, power_devs[2].platform_data = &preg_init_data; power_devs[2].pdata_size = sizeof(struct regulator_init_data); - power_devs[2].num_resources = ARRAY_SIZE(preg_resources); - power_devs[2].resources = &preg_resources[0], ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, - &preg_resources[0], chip->irq_base, NULL); + NULL, chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add preg subdev\n"); } @@ -868,10 +1006,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, goto out; } - ret = device_gpadc_init(chip, pdata); - if (ret < 0) - goto out; - ret = device_irq_init(chip, pdata); if (ret < 0) goto out; @@ -895,8 +1029,8 @@ static void __devinit device_8606_init(struct pm860x_chip *chip, device_led_init(chip, pdata); } -int __devinit pm860x_device_init(struct pm860x_chip *chip, - struct pm860x_platform_data *pdata) +static int __devinit pm860x_device_init(struct pm860x_chip *chip, + struct pm860x_platform_data *pdata) { chip->core_irq = 0; @@ -923,12 +1057,207 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, return 0; } -void __devexit pm860x_device_exit(struct pm860x_chip *chip) +static void __devexit pm860x_device_exit(struct pm860x_chip *chip) { device_irq_exit(chip); mfd_remove_devices(chip->dev); } +static int verify_addr(struct i2c_client *i2c) +{ + unsigned short addr_8607[] = {0x30, 0x34}; + unsigned short addr_8606[] = {0x10, 0x11}; + int size, i; + + if (i2c == NULL) + return 0; + size = ARRAY_SIZE(addr_8606); + for (i = 0; i < size; i++) { + if (i2c->addr == *(addr_8606 + i)) + return CHIP_PM8606; + } + size = ARRAY_SIZE(addr_8607); + for (i = 0; i < size; i++) { + if (i2c->addr == *(addr_8607 + i)) + return CHIP_PM8607; + } + return 0; +} + +static struct regmap_config pm860x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int __devinit pm860x_dt_init(struct device_node *np, + struct device *dev, + struct pm860x_platform_data *pdata) +{ + int ret; + + if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) + pdata->irq_mode = 1; + ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", + &pdata->companion_addr); + if (ret) { + dev_err(dev, "Not found \"marvell,88pm860x-slave-addr\" " + "property\n"); + pdata->companion_addr = 0; + } + return 0; +} + +static int __devinit pm860x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pm860x_platform_data *pdata = client->dev.platform_data; + struct device_node *node = client->dev.of_node; + struct pm860x_chip *chip; + int ret; + + if (node && !pdata) { + /* parse DT to get platform data */ + pdata = devm_kzalloc(&client->dev, + sizeof(struct pm860x_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + ret = pm860x_dt_init(node, &client->dev, pdata); + if (ret) + goto err; + } else if (!pdata) { + pr_info("No platform data in %s!\n", __func__); + return -EINVAL; + } + + chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); + if (chip == NULL) { + ret = -ENOMEM; + goto err; + } + + chip->id = verify_addr(client); + chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + kfree(chip); + return ret; + } + chip->client = client; + i2c_set_clientdata(client, chip); + chip->dev = &client->dev; + dev_set_drvdata(chip->dev, chip); + + /* + * Both client and companion client shares same platform driver. + * Driver distinguishes them by pdata->companion_addr. + * pdata->companion_addr is only assigned if companion chip exists. + * At the same time, the companion_addr shouldn't equal to client + * address. + */ + if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { + chip->companion_addr = pdata->companion_addr; + chip->companion = i2c_new_dummy(chip->client->adapter, + chip->companion_addr); + chip->regmap_companion = regmap_init_i2c(chip->companion, + &pm860x_regmap_config); + if (IS_ERR(chip->regmap_companion)) { + ret = PTR_ERR(chip->regmap_companion); + dev_err(&chip->companion->dev, + "Failed to allocate register map: %d\n", ret); + return ret; + } + i2c_set_clientdata(chip->companion, chip); + } + + pm860x_device_init(chip, pdata); + return 0; +err: + if (node) + devm_kfree(&client->dev, pdata); + return ret; +} + +static int __devexit pm860x_remove(struct i2c_client *client) +{ + struct pm860x_chip *chip = i2c_get_clientdata(client); + + pm860x_device_exit(chip); + if (chip->companion) { + regmap_exit(chip->regmap_companion); + i2c_unregister_device(chip->companion); + } + regmap_exit(chip->regmap); + kfree(chip); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pm860x_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct pm860x_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + enable_irq_wake(chip->core_irq); + return 0; +} + +static int pm860x_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct pm860x_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + disable_irq_wake(chip->core_irq); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); + +static const struct i2c_device_id pm860x_id_table[] = { + { "88PM860x", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pm860x_id_table); + +static const struct of_device_id pm860x_dt_ids[] = { + { .compatible = "marvell,88pm860x", }, + {}, +}; +MODULE_DEVICE_TABLE(of, pm860x_dt_ids); + +static struct i2c_driver pm860x_driver = { + .driver = { + .name = "88PM860x", + .owner = THIS_MODULE, + .pm = &pm860x_pm_ops, + .of_match_table = of_match_ptr(pm860x_dt_ids), + }, + .probe = pm860x_probe, + .remove = __devexit_p(pm860x_remove), + .id_table = pm860x_id_table, +}; + +static int __init pm860x_i2c_init(void) +{ + int ret; + ret = i2c_add_driver(&pm860x_driver); + if (ret != 0) + pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); + return ret; +} +subsys_initcall(pm860x_i2c_init); + +static void __exit pm860x_i2c_exit(void) +{ + i2c_del_driver(&pm860x_driver); +} +module_exit(pm860x_i2c_exit); + MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index b2cfdc458561..ff8f803ce833 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -10,12 +10,9 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/platform_device.h> #include <linux/i2c.h> -#include <linux/err.h> #include <linux/regmap.h> #include <linux/mfd/88pm860x.h> -#include <linux/slab.h> int pm860x_reg_read(struct i2c_client *i2c, int reg) { @@ -91,8 +88,18 @@ static int read_device(struct i2c_client *i2c, int reg, unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; struct i2c_adapter *adap = i2c->adapter; - struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0}, - {i2c->addr, I2C_M_RD, 0, msgbuf1}, + struct i2c_msg msg[2] = { + { + .addr = i2c->addr, + .flags = 0, + .len = 1, + .buf = msgbuf0 + }, + { .addr = i2c->addr, + .flags = I2C_M_RD, + .len = 0, + .buf = msgbuf1 + }, }; int num = 1, ret = 0; @@ -231,160 +238,3 @@ out: return ret; } EXPORT_SYMBOL(pm860x_page_set_bits); - -static const struct i2c_device_id pm860x_id_table[] = { - { "88PM860x", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, pm860x_id_table); - -static int verify_addr(struct i2c_client *i2c) -{ - unsigned short addr_8607[] = {0x30, 0x34}; - unsigned short addr_8606[] = {0x10, 0x11}; - int size, i; - - if (i2c == NULL) - return 0; - size = ARRAY_SIZE(addr_8606); - for (i = 0; i < size; i++) { - if (i2c->addr == *(addr_8606 + i)) - return CHIP_PM8606; - } - size = ARRAY_SIZE(addr_8607); - for (i = 0; i < size; i++) { - if (i2c->addr == *(addr_8607 + i)) - return CHIP_PM8607; - } - return 0; -} - -static struct regmap_config pm860x_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - -static int __devinit pm860x_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct pm860x_platform_data *pdata = client->dev.platform_data; - struct pm860x_chip *chip; - int ret; - - if (!pdata) { - pr_info("No platform data in %s!\n", __func__); - return -EINVAL; - } - - chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->id = verify_addr(client); - chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); - if (IS_ERR(chip->regmap)) { - ret = PTR_ERR(chip->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - ret); - kfree(chip); - return ret; - } - chip->client = client; - i2c_set_clientdata(client, chip); - chip->dev = &client->dev; - dev_set_drvdata(chip->dev, chip); - - /* - * Both client and companion client shares same platform driver. - * Driver distinguishes them by pdata->companion_addr. - * pdata->companion_addr is only assigned if companion chip exists. - * At the same time, the companion_addr shouldn't equal to client - * address. - */ - if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { - chip->companion_addr = pdata->companion_addr; - chip->companion = i2c_new_dummy(chip->client->adapter, - chip->companion_addr); - chip->regmap_companion = regmap_init_i2c(chip->companion, - &pm860x_regmap_config); - if (IS_ERR(chip->regmap_companion)) { - ret = PTR_ERR(chip->regmap_companion); - dev_err(&chip->companion->dev, - "Failed to allocate register map: %d\n", ret); - return ret; - } - i2c_set_clientdata(chip->companion, chip); - } - - pm860x_device_init(chip, pdata); - return 0; -} - -static int __devexit pm860x_remove(struct i2c_client *client) -{ - struct pm860x_chip *chip = i2c_get_clientdata(client); - - pm860x_device_exit(chip); - if (chip->companion) { - regmap_exit(chip->regmap_companion); - i2c_unregister_device(chip->companion); - } - regmap_exit(chip->regmap); - kfree(chip); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int pm860x_suspend(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct pm860x_chip *chip = i2c_get_clientdata(client); - - if (device_may_wakeup(dev) && chip->wakeup_flag) - enable_irq_wake(chip->core_irq); - return 0; -} - -static int pm860x_resume(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct pm860x_chip *chip = i2c_get_clientdata(client); - - if (device_may_wakeup(dev) && chip->wakeup_flag) - disable_irq_wake(chip->core_irq); - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); - -static struct i2c_driver pm860x_driver = { - .driver = { - .name = "88PM860x", - .owner = THIS_MODULE, - .pm = &pm860x_pm_ops, - }, - .probe = pm860x_probe, - .remove = __devexit_p(pm860x_remove), - .id_table = pm860x_id_table, -}; - -static int __init pm860x_i2c_init(void) -{ - int ret; - ret = i2c_add_driver(&pm860x_driver); - if (ret != 0) - pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); - return ret; -} -subsys_initcall(pm860x_i2c_init); - -static void __exit pm860x_i2c_exit(void) -{ - i2c_del_driver(&pm860x_driver); -} -module_exit(pm860x_i2c_exit); - -MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x"); -MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b1a146205c08..acab3ef8a310 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -298,16 +298,6 @@ config MFD_TWL4030_AUDIO select MFD_CORE default n -config TWL6030_PWM - tristate "TWL6030 PWM (Pulse Width Modulator) Support" - depends on TWL4030_CORE - select HAVE_PWM - depends on !PWM - default n - help - Say yes here if you want support for TWL6030 PWM. - This is used to control charging LED brightness. - config TWL6040_CORE bool "Support for TWL6040 audio codec" depends on I2C=y && GENERIC_HARDIRQS @@ -385,6 +375,18 @@ config MFD_T7L66XB help Support for Toshiba Mobile IO Controller T7L66XB +config MFD_SMSC + bool "Support for the SMSC ECE1099 series chips" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + help + If you say yes here you get support for the + ece1099 chips from SMSC. + + To compile this driver as a module, choose M here: the + module will be called smsc. + config MFD_TC6387XB bool "Support Toshiba TC6387XB" depends on ARM && HAVE_CLK @@ -441,6 +443,23 @@ config MFD_DA9052_I2C for accessing the device, additional drivers must be enabled in order to use the functionality of the device. +config MFD_DA9055 + bool "Dialog Semiconductor DA9055 PMIC Support" + select REGMAP_I2C + select REGMAP_IRQ + select PMIC_DA9055 + select MFD_CORE + depends on I2C=y + help + Say yes here for support of Dialog Semiconductor DA9055. This is + a Power Management IC. This driver provides common support for + accessing the device as well as the I2C interface to the chip itself. + Additional drivers must be enabled in order to use the functionality + of the device. + + This driver can be built as a module. If built as a module it will be + called "da9055" + config PMIC_ADP5520 bool "Analog Devices ADP5520/01 MFD PMIC Core Support" depends on I2C=y @@ -451,6 +470,16 @@ config PMIC_ADP5520 individual components like LCD backlight, LEDs, GPIOs and Kepad under the corresponding menus. +config MFD_LP8788 + bool "Texas Instruments LP8788 Power Management Unit Driver" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + select IRQ_DOMAIN + help + TI LP8788 PMU supports regulators, battery charger, RTC, + ADC, backlight driver and current sinks. + config MFD_MAX77686 bool "Maxim Semiconductor MAX77686 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS @@ -477,6 +506,18 @@ config MFD_MAX77693 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX8907 + tristate "Maxim Semiconductor MAX8907 PMIC Support" + select MFD_CORE + depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to support for Maxim Semiconductor MAX8907. This is + a Power Management IC. This driver provides common support for + accessing the device; additional drivers must be enabled in order + to use the functionality of the device. + config MFD_MAX8925 bool "Maxim Semiconductor MAX8925 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS @@ -896,7 +937,7 @@ config MFD_WL1273_CORE audio codec. config MFD_OMAP_USB_HOST - bool "Support OMAP USBHS core driver" + bool "Support OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 default y help @@ -985,13 +1026,13 @@ config MFD_STA2X11 depends on STA2X11 select MFD_CORE -config MFD_ANATOP - bool "Support for Freescale i.MX on-chip ANATOP controller" - depends on SOC_IMX6Q +config MFD_SYSCON + bool "System Controller Register R/W Based on Regmap" + depends on OF + select REGMAP_MMIO help - Select this option to enable Freescale i.MX on-chip ANATOP - MFD controller. This controller embeds regulator and - thermal devices for Freescale i.MX platforms. + Select this option to enable accessing system control registers + via regmap. config MFD_PALMAS bool "Support for the TI Palmas series chips" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 79dd22d1dc3d..d8ccb630ddb0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -63,7 +63,6 @@ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o -obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o @@ -77,6 +76,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o +obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ifeq ($(CONFIG_SA1100_ASSABET),y) @@ -90,8 +90,14 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o +obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o + +da9055-objs := da9055-core.o da9055-i2c.o +obj-$(CONFIG_MFD_DA9055) += da9055.o + obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o +obj-$(CONFIG_MFD_MAX8907) += max8907.o max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o @@ -120,7 +126,7 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o -obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o +obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o @@ -130,5 +136,5 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o -obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o +obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 01781ae5d0d7..2b3dde571a50 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -21,6 +21,7 @@ #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/mfd/core.h> +#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h> /* These are the only registers inside AB3100 used in this main file */ diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 47adf800024e..1667c77b5cde 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -472,6 +472,22 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) return IRQ_HANDLED; } +/** + * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * + * @ab8500: ab8500_irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs + * + * Useful for drivers to request their own IRQs. + */ +static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) +{ + if (!ab8500) + return -EINVAL; + + return irq_create_mapping(ab8500->domain, irq); +} + static irqreturn_t ab8500_irq(int irq, void *dev) { struct ab8500 *ab8500 = dev; @@ -501,8 +517,9 @@ static irqreturn_t ab8500_irq(int irq, void *dev) do { int bit = __ffs(value); int line = i * 8 + bit; + int virq = ab8500_irq_get_virq(ab8500, line); - handle_nested_irq(ab8500->irq_base + line); + handle_nested_irq(virq); value &= ~(1 << bit); } while (value); @@ -511,23 +528,6 @@ static irqreturn_t ab8500_irq(int irq, void *dev) return IRQ_HANDLED; } -/** - * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ - * - * @ab8500: ab8500_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs - * - * Useful for drivers to request their own IRQs. - */ -int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) -{ - if (!ab8500) - return -EINVAL; - - return irq_create_mapping(ab8500->domain, irq); -} -EXPORT_SYMBOL_GPL(ab8500_irq_get_virq); - static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { @@ -1076,6 +1076,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = { }, { .name = "ab8500-codec", + .of_compatible = "stericsson,ab8500-codec", }, }; diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c deleted file mode 100644 index 5576e07576de..000000000000 --- a/drivers/mfd/anatop-mfd.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Anatop MFD driver - * - * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> - * Copyright (C) 2012 Linaro - * - * 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. - * 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/io.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/mfd/anatop.h> - -u32 anatop_read_reg(struct anatop *adata, u32 addr) -{ - return readl(adata->ioreg + addr); -} -EXPORT_SYMBOL_GPL(anatop_read_reg); - -void anatop_write_reg(struct anatop *adata, u32 addr, u32 data, u32 mask) -{ - u32 val; - - data &= mask; - - spin_lock(&adata->reglock); - val = readl(adata->ioreg + addr); - val &= ~mask; - val |= data; - writel(val, adata->ioreg + addr); - spin_unlock(&adata->reglock); -} -EXPORT_SYMBOL_GPL(anatop_write_reg); - -static const struct of_device_id of_anatop_match[] = { - { .compatible = "fsl,imx6q-anatop", }, - { }, -}; - -static int __devinit of_anatop_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - void *ioreg; - struct anatop *drvdata; - - ioreg = of_iomap(np, 0); - if (!ioreg) - return -EADDRNOTAVAIL; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - drvdata->ioreg = ioreg; - spin_lock_init(&drvdata->reglock); - platform_set_drvdata(pdev, drvdata); - of_platform_populate(np, NULL, NULL, dev); - - return 0; -} - -static int __devexit of_anatop_remove(struct platform_device *pdev) -{ - struct anatop *drvdata; - drvdata = platform_get_drvdata(pdev); - iounmap(drvdata->ioreg); - - return 0; -} - -static struct platform_driver anatop_of_driver = { - .driver = { - .name = "anatop-mfd", - .owner = THIS_MODULE, - .of_match_table = of_anatop_match, - }, - .probe = of_anatop_probe, - .remove = of_anatop_remove, -}; - -static int __init anatop_init(void) -{ - return platform_driver_register(&anatop_of_driver); -} -postcore_initcall(anatop_init); - -static void __exit anatop_exit(void) -{ - platform_driver_unregister(&anatop_of_driver); -} -module_exit(anatop_exit); - -MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); -MODULE_DESCRIPTION("ANATOP MFD driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 98ac345f468e..ef0f2d001df2 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -94,7 +94,8 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) static irqreturn_t arizona_irq_thread(int irq, void *data) { struct arizona *arizona = data; - int i, ret; + unsigned int val; + int ret; ret = pm_runtime_get_sync(arizona->dev); if (ret < 0) { @@ -102,9 +103,20 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) return IRQ_NONE; } - /* Check both domains */ - for (i = 0; i < 2; i++) - handle_nested_irq(irq_find_mapping(arizona->virq, i)); + /* Always handle the AoD domain */ + handle_nested_irq(irq_find_mapping(arizona->virq, 0)); + + /* + * Check if one of the main interrupts is asserted and only + * check that domain if it is. + */ + ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); + if (ret == 0 && val & ARIZONA_IRQ1_STS) { + handle_nested_irq(irq_find_mapping(arizona->virq, 1)); + } else if (ret != 0) { + dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", + ret); + } pm_runtime_mark_last_busy(arizona->dev); pm_runtime_put_autosuspend(arizona->dev); @@ -156,18 +168,36 @@ int arizona_irq_init(struct arizona *arizona) int flags = IRQF_ONESHOT; int ret, i; const struct regmap_irq_chip *aod, *irq; + bool ctrlif_error = true; switch (arizona->type) { #ifdef CONFIG_MFD_WM5102 case WM5102: aod = &wm5102_aod; irq = &wm5102_irq; + + switch (arizona->rev) { + case 0: + ctrlif_error = false; + break; + default: + break; + } break; #endif #ifdef CONFIG_MFD_WM5110 case WM5110: aod = &wm5110_aod; irq = &wm5110_irq; + + switch (arizona->rev) { + case 0: + case 1: + ctrlif_error = false; + break; + default: + break; + } break; #endif default: @@ -226,13 +256,17 @@ int arizona_irq_init(struct arizona *arizona) } /* Handle control interface errors in the core */ - i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); - ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, IRQF_ONESHOT, - "Control interface error", arizona); - if (ret != 0) { - dev_err(arizona->dev, "Failed to request boot done %d: %d\n", - arizona->irq, ret); - goto err_ctrlif; + if (ctrlif_error) { + i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); + ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, + IRQF_ONESHOT, + "Control interface error", arizona); + if (ret != 0) { + dev_err(arizona->dev, + "Failed to request CTRLIF_ERR %d: %d\n", + arizona->irq, ret); + goto err_ctrlif; + } } ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c new file mode 100644 index 000000000000..ff6c77f392bd --- /dev/null +++ b/drivers/mfd/da9055-core.c @@ -0,0 +1,423 @@ +/* + * Device access for Dialog DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.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/module.h> +#include <linux/device.h> +#include <linux/input.h> +#include <linux/irq.h> +#include <linux/mutex.h> + +#include <linux/mfd/core.h> +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/pdata.h> +#include <linux/mfd/da9055/reg.h> + +#define DA9055_IRQ_NONKEY_MASK 0x01 +#define DA9055_IRQ_ALM_MASK 0x02 +#define DA9055_IRQ_TICK_MASK 0x04 +#define DA9055_IRQ_ADC_MASK 0x08 +#define DA9055_IRQ_BUCK_ILIM_MASK 0x08 + +static bool da9055_register_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA9055_REG_STATUS_A: + case DA9055_REG_STATUS_B: + case DA9055_REG_EVENT_A: + case DA9055_REG_EVENT_B: + case DA9055_REG_EVENT_C: + case DA9055_REG_IRQ_MASK_A: + case DA9055_REG_IRQ_MASK_B: + case DA9055_REG_IRQ_MASK_C: + + case DA9055_REG_CONTROL_A: + case DA9055_REG_CONTROL_B: + case DA9055_REG_CONTROL_C: + case DA9055_REG_CONTROL_D: + case DA9055_REG_CONTROL_E: + + case DA9055_REG_ADC_MAN: + case DA9055_REG_ADC_CONT: + case DA9055_REG_VSYS_MON: + case DA9055_REG_ADC_RES_L: + case DA9055_REG_ADC_RES_H: + case DA9055_REG_VSYS_RES: + case DA9055_REG_ADCIN1_RES: + case DA9055_REG_ADCIN2_RES: + case DA9055_REG_ADCIN3_RES: + + case DA9055_REG_COUNT_S: + case DA9055_REG_COUNT_MI: + case DA9055_REG_COUNT_H: + case DA9055_REG_COUNT_D: + case DA9055_REG_COUNT_MO: + case DA9055_REG_COUNT_Y: + case DA9055_REG_ALARM_H: + case DA9055_REG_ALARM_D: + case DA9055_REG_ALARM_MI: + case DA9055_REG_ALARM_MO: + case DA9055_REG_ALARM_Y: + + case DA9055_REG_GPIO0_1: + case DA9055_REG_GPIO2: + case DA9055_REG_GPIO_MODE0_2: + + case DA9055_REG_BCORE_CONT: + case DA9055_REG_BMEM_CONT: + case DA9055_REG_LDO1_CONT: + case DA9055_REG_LDO2_CONT: + case DA9055_REG_LDO3_CONT: + case DA9055_REG_LDO4_CONT: + case DA9055_REG_LDO5_CONT: + case DA9055_REG_LDO6_CONT: + case DA9055_REG_BUCK_LIM: + case DA9055_REG_BCORE_MODE: + case DA9055_REG_VBCORE_A: + case DA9055_REG_VBMEM_A: + case DA9055_REG_VLDO1_A: + case DA9055_REG_VLDO2_A: + case DA9055_REG_VLDO3_A: + case DA9055_REG_VLDO4_A: + case DA9055_REG_VLDO5_A: + case DA9055_REG_VLDO6_A: + case DA9055_REG_VBCORE_B: + case DA9055_REG_VBMEM_B: + case DA9055_REG_VLDO1_B: + case DA9055_REG_VLDO2_B: + case DA9055_REG_VLDO3_B: + case DA9055_REG_VLDO4_B: + case DA9055_REG_VLDO5_B: + case DA9055_REG_VLDO6_B: + return true; + default: + return false; + } +} + +static bool da9055_register_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA9055_REG_STATUS_A: + case DA9055_REG_STATUS_B: + case DA9055_REG_EVENT_A: + case DA9055_REG_EVENT_B: + case DA9055_REG_EVENT_C: + case DA9055_REG_IRQ_MASK_A: + case DA9055_REG_IRQ_MASK_B: + case DA9055_REG_IRQ_MASK_C: + + case DA9055_REG_CONTROL_A: + case DA9055_REG_CONTROL_B: + case DA9055_REG_CONTROL_C: + case DA9055_REG_CONTROL_D: + case DA9055_REG_CONTROL_E: + + case DA9055_REG_ADC_MAN: + case DA9055_REG_ADC_CONT: + case DA9055_REG_VSYS_MON: + case DA9055_REG_ADC_RES_L: + case DA9055_REG_ADC_RES_H: + case DA9055_REG_VSYS_RES: + case DA9055_REG_ADCIN1_RES: + case DA9055_REG_ADCIN2_RES: + case DA9055_REG_ADCIN3_RES: + + case DA9055_REG_COUNT_S: + case DA9055_REG_COUNT_MI: + case DA9055_REG_COUNT_H: + case DA9055_REG_COUNT_D: + case DA9055_REG_COUNT_MO: + case DA9055_REG_COUNT_Y: + case DA9055_REG_ALARM_H: + case DA9055_REG_ALARM_D: + case DA9055_REG_ALARM_MI: + case DA9055_REG_ALARM_MO: + case DA9055_REG_ALARM_Y: + + case DA9055_REG_GPIO0_1: + case DA9055_REG_GPIO2: + case DA9055_REG_GPIO_MODE0_2: + + case DA9055_REG_BCORE_CONT: + case DA9055_REG_BMEM_CONT: + case DA9055_REG_LDO1_CONT: + case DA9055_REG_LDO2_CONT: + case DA9055_REG_LDO3_CONT: + case DA9055_REG_LDO4_CONT: + case DA9055_REG_LDO5_CONT: + case DA9055_REG_LDO6_CONT: + case DA9055_REG_BUCK_LIM: + case DA9055_REG_BCORE_MODE: + case DA9055_REG_VBCORE_A: + case DA9055_REG_VBMEM_A: + case DA9055_REG_VLDO1_A: + case DA9055_REG_VLDO2_A: + case DA9055_REG_VLDO3_A: + case DA9055_REG_VLDO4_A: + case DA9055_REG_VLDO5_A: + case DA9055_REG_VLDO6_A: + case DA9055_REG_VBCORE_B: + case DA9055_REG_VBMEM_B: + case DA9055_REG_VLDO1_B: + case DA9055_REG_VLDO2_B: + case DA9055_REG_VLDO3_B: + case DA9055_REG_VLDO4_B: + case DA9055_REG_VLDO5_B: + case DA9055_REG_VLDO6_B: + return true; + default: + return false; + } +} + +static bool da9055_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA9055_REG_STATUS_A: + case DA9055_REG_STATUS_B: + case DA9055_REG_EVENT_A: + case DA9055_REG_EVENT_B: + case DA9055_REG_EVENT_C: + + case DA9055_REG_CONTROL_A: + case DA9055_REG_CONTROL_E: + + case DA9055_REG_ADC_MAN: + case DA9055_REG_ADC_RES_L: + case DA9055_REG_ADC_RES_H: + case DA9055_REG_VSYS_RES: + case DA9055_REG_ADCIN1_RES: + case DA9055_REG_ADCIN2_RES: + case DA9055_REG_ADCIN3_RES: + + case DA9055_REG_COUNT_S: + case DA9055_REG_COUNT_MI: + case DA9055_REG_COUNT_H: + case DA9055_REG_COUNT_D: + case DA9055_REG_COUNT_MO: + case DA9055_REG_COUNT_Y: + case DA9055_REG_ALARM_MI: + + case DA9055_REG_BCORE_CONT: + case DA9055_REG_BMEM_CONT: + case DA9055_REG_LDO1_CONT: + case DA9055_REG_LDO2_CONT: + case DA9055_REG_LDO3_CONT: + case DA9055_REG_LDO4_CONT: + case DA9055_REG_LDO5_CONT: + case DA9055_REG_LDO6_CONT: + return true; + default: + return false; + } +} + +static struct regmap_irq da9055_irqs[] = { + [DA9055_IRQ_NONKEY] = { + .reg_offset = 0, + .mask = DA9055_IRQ_NONKEY_MASK, + }, + [DA9055_IRQ_ALARM] = { + .reg_offset = 0, + .mask = DA9055_IRQ_ALM_MASK, + }, + [DA9055_IRQ_TICK] = { + .reg_offset = 0, + .mask = DA9055_IRQ_TICK_MASK, + }, + [DA9055_IRQ_HWMON] = { + .reg_offset = 0, + .mask = DA9055_IRQ_ADC_MASK, + }, + [DA9055_IRQ_REGULATOR] = { + .reg_offset = 1, + .mask = DA9055_IRQ_BUCK_ILIM_MASK, + }, +}; + +struct regmap_config da9055_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .cache_type = REGCACHE_RBTREE, + + .max_register = DA9055_MAX_REGISTER_CNT, + .readable_reg = da9055_register_readable, + .writeable_reg = da9055_register_writeable, + .volatile_reg = da9055_register_volatile, +}; +EXPORT_SYMBOL_GPL(da9055_regmap_config); + +static struct resource da9055_onkey_resource = { + .name = "ONKEY", + .start = DA9055_IRQ_NONKEY, + .end = DA9055_IRQ_NONKEY, + .flags = IORESOURCE_IRQ, +}; + +static struct resource da9055_rtc_resource[] = { + { + .name = "ALM", + .start = DA9055_IRQ_ALARM, + .end = DA9055_IRQ_ALARM, + .flags = IORESOURCE_IRQ, + }, + { + .name = "TICK", + .start = DA9055_IRQ_TICK, + .end = DA9055_IRQ_TICK, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource da9055_hwmon_resource = { + .name = "HWMON", + .start = DA9055_IRQ_HWMON, + .end = DA9055_IRQ_HWMON, + .flags = IORESOURCE_IRQ, +}; + +static struct resource da9055_ld05_6_resource = { + .name = "REGULATOR", + .start = DA9055_IRQ_REGULATOR, + .end = DA9055_IRQ_REGULATOR, + .flags = IORESOURCE_IRQ, +}; + +static struct mfd_cell da9055_devs[] = { + { + .of_compatible = "dialog,da9055-gpio", + .name = "da9055-gpio", + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 1, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 2, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 3, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 4, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 5, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 6, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 7, + .resources = &da9055_ld05_6_resource, + .num_resources = 1, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .resources = &da9055_ld05_6_resource, + .num_resources = 1, + .id = 8, + }, + { + .of_compatible = "dialog,da9055-onkey", + .name = "da9055-onkey", + .resources = &da9055_onkey_resource, + .num_resources = 1, + }, + { + .of_compatible = "dialog,da9055-rtc", + .name = "da9055-rtc", + .resources = da9055_rtc_resource, + .num_resources = ARRAY_SIZE(da9055_rtc_resource), + }, + { + .of_compatible = "dialog,da9055-hwmon", + .name = "da9055-hwmon", + .resources = &da9055_hwmon_resource, + .num_resources = 1, + }, + { + .of_compatible = "dialog,da9055-watchdog", + .name = "da9055-watchdog", + }, +}; + +static struct regmap_irq_chip da9055_regmap_irq_chip = { + .name = "da9055_irq", + .status_base = DA9055_REG_EVENT_A, + .mask_base = DA9055_REG_IRQ_MASK_A, + .ack_base = DA9055_REG_EVENT_A, + .num_regs = 3, + .irqs = da9055_irqs, + .num_irqs = ARRAY_SIZE(da9055_irqs), +}; + +int __devinit da9055_device_init(struct da9055 *da9055) +{ + struct da9055_pdata *pdata = da9055->dev->platform_data; + int ret; + + if (pdata && pdata->init != NULL) + pdata->init(da9055); + + if (!pdata || !pdata->irq_base) + da9055->irq_base = -1; + else + da9055->irq_base = pdata->irq_base; + + ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + da9055->irq_base, &da9055_regmap_irq_chip, + &da9055->irq_data); + if (ret < 0) + return ret; + + da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data); + + ret = mfd_add_devices(da9055->dev, -1, + da9055_devs, ARRAY_SIZE(da9055_devs), + NULL, da9055->irq_base, NULL); + if (ret) + goto err; + + return 0; + +err: + mfd_remove_devices(da9055->dev); + return ret; +} + +void __devexit da9055_device_exit(struct da9055 *da9055) +{ + regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); + mfd_remove_devices(da9055->dev); +} + +MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c new file mode 100644 index 000000000000..88f6dca53bac --- /dev/null +++ b/drivers/mfd/da9055-i2c.c @@ -0,0 +1,93 @@ + /* I2C access for DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.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/module.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/err.h> + +#include <linux/mfd/da9055/core.h> + +static int __devinit da9055_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da9055 *da9055; + int ret; + + da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055), GFP_KERNEL); + if (!da9055) + return -ENOMEM; + + da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config); + if (IS_ERR(da9055->regmap)) { + ret = PTR_ERR(da9055->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + da9055->dev = &i2c->dev; + da9055->chip_irq = i2c->irq; + + i2c_set_clientdata(i2c, da9055); + + return da9055_device_init(da9055); +} + +static int __devexit da9055_i2c_remove(struct i2c_client *i2c) +{ + struct da9055 *da9055 = i2c_get_clientdata(i2c); + + da9055_device_exit(da9055); + + return 0; +} + +static struct i2c_device_id da9055_i2c_id[] = { + {"da9055-pmic", 0}, + { } +}; + +static struct i2c_driver da9055_i2c_driver = { + .probe = da9055_i2c_probe, + .remove = __devexit_p(da9055_i2c_remove), + .id_table = da9055_i2c_id, + .driver = { + .name = "da9055", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_i2c_init(void) +{ + int ret; + + ret = i2c_add_driver(&da9055_i2c_driver); + if (ret != 0) { + pr_err("DA9055 I2C registration failed %d\n", ret); + return ret; + } + + return 0; +} +subsys_initcall(da9055_i2c_init); + +static void __exit da9055_i2c_exit(void) +{ + i2c_del_driver(&da9055_i2c_driver); +} +module_exit(da9055_i2c_exit); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 6b67edbdbd01..00b8b0f3dfb6 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -270,6 +270,8 @@ static struct { struct prcmu_fw_version version; } fw_info; +static struct irq_domain *db8500_irq_domain; + /* * This vector maps irq numbers to the bits in the bit field used in * communication with the PRCMU firmware. @@ -2624,7 +2626,7 @@ static void prcmu_irq_mask(struct irq_data *d) spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); - mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; + mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq]; spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); @@ -2638,7 +2640,7 @@ static void prcmu_irq_unmask(struct irq_data *d) spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); - mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; + mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->hwirq]; spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); @@ -2678,9 +2680,37 @@ static char *fw_project_name(u8 project) } } +static int db8500_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(virq, &prcmu_irq_chip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops db8500_irq_ops = { + .map = db8500_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int db8500_irq_init(struct device_node *np) +{ + db8500_irq_domain = irq_domain_add_legacy( + np, NUM_PRCMU_WAKEUPS, IRQ_PRCMU_BASE, + 0, &db8500_irq_ops, NULL); + + if (!db8500_irq_domain) { + pr_err("Failed to create irqdomain\n"); + return -ENOSYS; + } + + return 0; +} + void __init db8500_prcmu_early_init(void) { - unsigned int i; if (cpu_is_u8500v2()) { void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); @@ -2725,15 +2755,6 @@ void __init db8500_prcmu_early_init(void) INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); - /* Initalize irqs. */ - for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) { - unsigned int irq; - - irq = IRQ_PRCMU_BASE + i; - irq_set_chip_and_handler(irq, &prcmu_irq_chip, - handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); - } compute_armss_rate(); } @@ -3041,6 +3062,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) goto no_irq_return; } + db8500_irq_init(np); + for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) { if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) { db8500_prcmu_devs[i].platform_data = ab8500_platdata; diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c new file mode 100644 index 000000000000..c84ded5f8ece --- /dev/null +++ b/drivers/mfd/lp8788-irq.c @@ -0,0 +1,198 @@ +/* + * TI LP8788 MFD - interrupt handler + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * 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/delay.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/device.h> +#include <linux/mfd/lp8788.h> +#include <linux/module.h> +#include <linux/slab.h> + +/* register address */ +#define LP8788_INT_1 0x00 +#define LP8788_INTEN_1 0x03 + +#define BASE_INTEN_ADDR LP8788_INTEN_1 +#define SIZE_REG 8 +#define NUM_REGS 3 + +/* + * struct lp8788_irq_data + * @lp : used for accessing to lp8788 registers + * @irq_lock : mutex for enabling/disabling the interrupt + * @domain : IRQ domain for handling nested interrupt + * @enabled : status of enabled interrupt + */ +struct lp8788_irq_data { + struct lp8788 *lp; + struct mutex irq_lock; + struct irq_domain *domain; + int enabled[LP8788_INT_MAX]; +}; + +static inline u8 _irq_to_addr(enum lp8788_int_id id) +{ + return id / SIZE_REG; +} + +static inline u8 _irq_to_enable_addr(enum lp8788_int_id id) +{ + return _irq_to_addr(id) + BASE_INTEN_ADDR; +} + +static inline u8 _irq_to_mask(enum lp8788_int_id id) +{ + return 1 << (id % SIZE_REG); +} + +static inline u8 _irq_to_val(enum lp8788_int_id id, int enable) +{ + return enable << (id % SIZE_REG); +} + +static void lp8788_irq_enable(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + irqd->enabled[data->hwirq] = 1; +} + +static void lp8788_irq_disable(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + irqd->enabled[data->hwirq] = 0; +} + +static void lp8788_irq_bus_lock(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + + mutex_lock(&irqd->irq_lock); +} + +static void lp8788_irq_bus_sync_unlock(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + enum lp8788_int_id irq = data->hwirq; + u8 addr, mask, val; + + addr = _irq_to_enable_addr(irq); + mask = _irq_to_mask(irq); + val = _irq_to_val(irq, irqd->enabled[irq]); + + lp8788_update_bits(irqd->lp, addr, mask, val); + + mutex_unlock(&irqd->irq_lock); +} + +static struct irq_chip lp8788_irq_chip = { + .name = "lp8788", + .irq_enable = lp8788_irq_enable, + .irq_disable = lp8788_irq_disable, + .irq_bus_lock = lp8788_irq_bus_lock, + .irq_bus_sync_unlock = lp8788_irq_bus_sync_unlock, +}; + +static irqreturn_t lp8788_irq_handler(int irq, void *ptr) +{ + struct lp8788_irq_data *irqd = ptr; + struct lp8788 *lp = irqd->lp; + u8 status[NUM_REGS], addr, mask; + bool handled; + int i; + + if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS)) + return IRQ_NONE; + + for (i = 0 ; i < LP8788_INT_MAX ; i++) { + addr = _irq_to_addr(i); + mask = _irq_to_mask(i); + + /* reporting only if the irq is enabled */ + if (status[addr] & mask) { + handle_nested_irq(irq_find_mapping(irqd->domain, i)); + handled = true; + } + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int lp8788_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct lp8788_irq_data *irqd = d->host_data; + struct irq_chip *chip = &lp8788_irq_chip; + + irq_set_chip_data(virq, irqd); + irq_set_chip_and_handler(virq, chip, handle_edge_irq); + irq_set_nested_thread(virq, 1); + +#ifdef CONFIG_ARM + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + + return 0; +} + +static struct irq_domain_ops lp8788_domain_ops = { + .map = lp8788_irq_map, +}; + +int lp8788_irq_init(struct lp8788 *lp, int irq) +{ + struct lp8788_irq_data *irqd; + int ret; + + if (irq <= 0) { + dev_warn(lp->dev, "invalid irq number: %d\n", irq); + return 0; + } + + irqd = devm_kzalloc(lp->dev, sizeof(*irqd), GFP_KERNEL); + if (!irqd) + return -ENOMEM; + + irqd->lp = lp; + irqd->domain = irq_domain_add_linear(lp->dev->of_node, LP8788_INT_MAX, + &lp8788_domain_ops, irqd); + if (!irqd->domain) { + dev_err(lp->dev, "failed to add irq domain err\n"); + return -EINVAL; + } + + lp->irqdm = irqd->domain; + mutex_init(&irqd->irq_lock); + + ret = request_threaded_irq(irq, NULL, lp8788_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "lp8788-irq", irqd); + if (ret) { + dev_err(lp->dev, "failed to create a thread for IRQ_N\n"); + return ret; + } + + lp->irq = irq; + + return 0; +} + +void lp8788_irq_exit(struct lp8788 *lp) +{ + if (lp->irq) + free_irq(lp->irq, lp->irqdm); +} diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c new file mode 100644 index 000000000000..3e94a699833c --- /dev/null +++ b/drivers/mfd/lp8788.c @@ -0,0 +1,245 @@ +/* + * TI LP8788 MFD - core interface + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * 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/err.h> +#include <linux/i2c.h> +#include <linux/mfd/core.h> +#include <linux/mfd/lp8788.h> +#include <linux/module.h> +#include <linux/slab.h> + +#define MAX_LP8788_REGISTERS 0xA2 + +#define MFD_DEV_SIMPLE(_name) \ +{ \ + .name = LP8788_DEV_##_name, \ +} + +#define MFD_DEV_WITH_ID(_name, _id) \ +{ \ + .name = LP8788_DEV_##_name, \ + .id = _id, \ +} + +#define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \ +{ \ + .name = LP8788_DEV_##_name, \ + .resources = _resource, \ + .num_resources = num_resource, \ +} + +static struct resource chg_irqs[] = { + /* Charger Interrupts */ + { + .start = LP8788_INT_CHG_INPUT_STATE, + .end = LP8788_INT_PRECHG_TIMEOUT, + .name = LP8788_CHG_IRQ, + .flags = IORESOURCE_IRQ, + }, + /* Power Routing Switch Interrupts */ + { + .start = LP8788_INT_ENTER_SYS_SUPPORT, + .end = LP8788_INT_EXIT_SYS_SUPPORT, + .name = LP8788_PRSW_IRQ, + .flags = IORESOURCE_IRQ, + }, + /* Battery Interrupts */ + { + .start = LP8788_INT_BATT_LOW, + .end = LP8788_INT_NO_BATT, + .name = LP8788_BATT_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource rtc_irqs[] = { + { + .start = LP8788_INT_RTC_ALARM1, + .end = LP8788_INT_RTC_ALARM2, + .name = LP8788_ALM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell lp8788_devs[] = { + /* 4 bucks */ + MFD_DEV_WITH_ID(BUCK, 1), + MFD_DEV_WITH_ID(BUCK, 2), + MFD_DEV_WITH_ID(BUCK, 3), + MFD_DEV_WITH_ID(BUCK, 4), + + /* 12 digital ldos */ + MFD_DEV_WITH_ID(DLDO, 1), + MFD_DEV_WITH_ID(DLDO, 2), + MFD_DEV_WITH_ID(DLDO, 3), + MFD_DEV_WITH_ID(DLDO, 4), + MFD_DEV_WITH_ID(DLDO, 5), + MFD_DEV_WITH_ID(DLDO, 6), + MFD_DEV_WITH_ID(DLDO, 7), + MFD_DEV_WITH_ID(DLDO, 8), + MFD_DEV_WITH_ID(DLDO, 9), + MFD_DEV_WITH_ID(DLDO, 10), + MFD_DEV_WITH_ID(DLDO, 11), + MFD_DEV_WITH_ID(DLDO, 12), + + /* 10 analog ldos */ + MFD_DEV_WITH_ID(ALDO, 1), + MFD_DEV_WITH_ID(ALDO, 2), + MFD_DEV_WITH_ID(ALDO, 3), + MFD_DEV_WITH_ID(ALDO, 4), + MFD_DEV_WITH_ID(ALDO, 5), + MFD_DEV_WITH_ID(ALDO, 6), + MFD_DEV_WITH_ID(ALDO, 7), + MFD_DEV_WITH_ID(ALDO, 8), + MFD_DEV_WITH_ID(ALDO, 9), + MFD_DEV_WITH_ID(ALDO, 10), + + /* ADC */ + MFD_DEV_SIMPLE(ADC), + + /* battery charger */ + MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)), + + /* rtc */ + MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)), + + /* backlight */ + MFD_DEV_SIMPLE(BACKLIGHT), + + /* current sink for vibrator */ + MFD_DEV_SIMPLE(VIBRATOR), + + /* current sink for keypad LED */ + MFD_DEV_SIMPLE(KEYLED), +}; + +int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data) +{ + int ret; + unsigned int val; + + ret = regmap_read(lp->regmap, reg, &val); + if (ret < 0) { + dev_err(lp->dev, "failed to read 0x%.2x\n", reg); + return ret; + } + + *data = (u8)val; + return 0; +} +EXPORT_SYMBOL_GPL(lp8788_read_byte); + +int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count) +{ + return regmap_bulk_read(lp->regmap, reg, data, count); +} +EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes); + +int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data) +{ + return regmap_write(lp->regmap, reg, data); +} +EXPORT_SYMBOL_GPL(lp8788_write_byte); + +int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data) +{ + return regmap_update_bits(lp->regmap, reg, mask, data); +} +EXPORT_SYMBOL_GPL(lp8788_update_bits); + +static int lp8788_platform_init(struct lp8788 *lp) +{ + struct lp8788_platform_data *pdata = lp->pdata; + + return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0; +} + +static const struct regmap_config lp8788_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX_LP8788_REGISTERS, +}; + +static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) +{ + struct lp8788 *lp; + struct lp8788_platform_data *pdata = cl->dev.platform_data; + int ret; + + lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL); + if (!lp) + return -ENOMEM; + + lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config); + if (IS_ERR(lp->regmap)) { + ret = PTR_ERR(lp->regmap); + dev_err(&cl->dev, "regmap init i2c err: %d\n", ret); + return ret; + } + + lp->pdata = pdata; + lp->dev = &cl->dev; + i2c_set_clientdata(cl, lp); + + ret = lp8788_platform_init(lp); + if (ret) + return ret; + + ret = lp8788_irq_init(lp, cl->irq); + if (ret) + return ret; + + return mfd_add_devices(lp->dev, -1, lp8788_devs, + ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); +} + +static int __devexit lp8788_remove(struct i2c_client *cl) +{ + struct lp8788 *lp = i2c_get_clientdata(cl); + + mfd_remove_devices(lp->dev); + lp8788_irq_exit(lp); + return 0; +} + +static const struct i2c_device_id lp8788_ids[] = { + {"lp8788", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp8788_ids); + +static struct i2c_driver lp8788_driver = { + .driver = { + .name = "lp8788", + .owner = THIS_MODULE, + }, + .probe = lp8788_probe, + .remove = __devexit_p(lp8788_remove), + .id_table = lp8788_ids, +}; + +static int __init lp8788_init(void) +{ + return i2c_add_driver(&lp8788_driver); +} +subsys_initcall(lp8788_init); + +static void __exit lp8788_exit(void) +{ + i2c_del_driver(&lp8788_driver); +} +module_exit(lp8788_exit); + +MODULE_DESCRIPTION("TI LP8788 MFD Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 092ad4b44b6d..a22544fe5319 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -49,6 +49,7 @@ * document number TBD : DH89xxCC * document number TBD : Panther Point * document number TBD : Lynx Point + * document number TBD : Lynx Point-LP */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -192,6 +193,7 @@ enum lpc_chipsets { LPC_DH89XXCC, /* DH89xxCC */ LPC_PPT, /* Panther Point */ LPC_LPT, /* Lynx Point */ + LPC_LPT_LP, /* Lynx Point-LP */ }; struct lpc_ich_info lpc_chipset_info[] __devinitdata = { @@ -468,6 +470,10 @@ struct lpc_ich_info lpc_chipset_info[] __devinitdata = { .name = "Lynx Point", .iTCO_version = 2, }, + [LPC_LPT_LP] = { + .name = "Lynx Point_LP", + .iTCO_version = 2, + }, }; /* @@ -641,6 +647,14 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = { { PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x9c40), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c41), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c42), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c43), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c44), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, lpc_ich_ids); @@ -683,6 +697,30 @@ static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell, cell->pdata_size = sizeof(struct lpc_ich_info); } +/* + * We don't check for resource conflict globally. There are 2 or 3 independent + * GPIO groups and it's enough to have access to one of these to instantiate + * the device. + */ +static int __devinit lpc_ich_check_conflict_gpio(struct resource *res) +{ + int ret; + u8 use_gpio = 0; + + if (resource_size(res) >= 0x50 && + !acpi_check_region(res->start + 0x40, 0x10, "LPC ICH GPIO3")) + use_gpio |= 1 << 2; + + if (!acpi_check_region(res->start + 0x30, 0x10, "LPC ICH GPIO2")) + use_gpio |= 1 << 1; + + ret = acpi_check_region(res->start + 0x00, 0x30, "LPC ICH GPIO1"); + if (!ret) + use_gpio |= 1 << 0; + + return use_gpio ? use_gpio : ret; +} + static int __devinit lpc_ich_init_gpio(struct pci_dev *dev, const struct pci_device_id *id) { @@ -740,12 +778,13 @@ gpe0_done: break; } - ret = acpi_check_resource_conflict(res); - if (ret) { + ret = lpc_ich_check_conflict_gpio(res); + if (ret < 0) { /* this isn't necessarily fatal for the GPIO */ acpi_conflict = true; goto gpio_done; } + lpc_chipset_info[id->driver_data].use_gpio = ret; lpc_ich_enable_gpio_space(dev); lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c new file mode 100644 index 000000000000..17f2593d82b8 --- /dev/null +++ b/drivers/mfd/max8907.c @@ -0,0 +1,351 @@ +/* + * max8907.c - mfd driver for MAX8907 + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * Copyright (C) 2010-2012, NVIDIA CORPORATION. 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 version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max8907.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +static struct mfd_cell max8907_cells[] = { + { .name = "max8907-regulator", }, + { .name = "max8907-rtc", }, +}; + +static bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_ON_OFF_IRQ1: + case MAX8907_REG_ON_OFF_STAT: + case MAX8907_REG_ON_OFF_IRQ2: + case MAX8907_REG_CHG_IRQ1: + case MAX8907_REG_CHG_IRQ2: + case MAX8907_REG_CHG_STAT: + return true; + default: + return false; + } +} + +static bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_ON_OFF_IRQ1: + case MAX8907_REG_ON_OFF_IRQ2: + case MAX8907_REG_CHG_IRQ1: + case MAX8907_REG_CHG_IRQ2: + return true; + default: + return false; + } +} + +static bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return !max8907_gen_is_volatile_reg(dev, reg); +} + +static const struct regmap_config max8907_regmap_gen_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max8907_gen_is_volatile_reg, + .precious_reg = max8907_gen_is_precious_reg, + .writeable_reg = max8907_gen_is_writeable_reg, + .max_register = MAX8907_REG_LDO20VOUT, + .cache_type = REGCACHE_RBTREE, +}; + +static bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg <= MAX8907_REG_RTC_YEAR2) + return true; + + switch (reg) { + case MAX8907_REG_RTC_STATUS: + case MAX8907_REG_RTC_IRQ: + return true; + default: + return false; + } +} + +static bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_RTC_IRQ: + return true; + default: + return false; + } +} + +static bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_RTC_STATUS: + case MAX8907_REG_RTC_IRQ: + return false; + default: + return true; + } +} + +static const struct regmap_config max8907_regmap_rtc_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max8907_rtc_is_volatile_reg, + .precious_reg = max8907_rtc_is_precious_reg, + .writeable_reg = max8907_rtc_is_writeable_reg, + .max_register = MAX8907_REG_MPL_CNTL, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_irq max8907_chg_irqs[] = { + { .reg_offset = 0, .mask = 1 << 0, }, + { .reg_offset = 0, .mask = 1 << 1, }, + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 1, .mask = 1 << 0, }, + { .reg_offset = 1, .mask = 1 << 1, }, + { .reg_offset = 1, .mask = 1 << 2, }, + { .reg_offset = 1, .mask = 1 << 3, }, + { .reg_offset = 1, .mask = 1 << 4, }, + { .reg_offset = 1, .mask = 1 << 5, }, + { .reg_offset = 1, .mask = 1 << 6, }, + { .reg_offset = 1, .mask = 1 << 7, }, +}; + +static const struct regmap_irq_chip max8907_chg_irq_chip = { + .name = "max8907 chg", + .status_base = MAX8907_REG_CHG_IRQ1, + .mask_base = MAX8907_REG_CHG_IRQ1_MASK, + .wake_base = MAX8907_REG_CHG_IRQ1_MASK, + .irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1, + .num_regs = 2, + .irqs = max8907_chg_irqs, + .num_irqs = ARRAY_SIZE(max8907_chg_irqs), +}; + +static const struct regmap_irq max8907_on_off_irqs[] = { + { .reg_offset = 0, .mask = 1 << 0, }, + { .reg_offset = 0, .mask = 1 << 1, }, + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 0, .mask = 1 << 3, }, + { .reg_offset = 0, .mask = 1 << 4, }, + { .reg_offset = 0, .mask = 1 << 5, }, + { .reg_offset = 0, .mask = 1 << 6, }, + { .reg_offset = 0, .mask = 1 << 7, }, + { .reg_offset = 1, .mask = 1 << 0, }, + { .reg_offset = 1, .mask = 1 << 1, }, +}; + +static const struct regmap_irq_chip max8907_on_off_irq_chip = { + .name = "max8907 on_off", + .status_base = MAX8907_REG_ON_OFF_IRQ1, + .mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK, + .irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1, + .num_regs = 2, + .irqs = max8907_on_off_irqs, + .num_irqs = ARRAY_SIZE(max8907_on_off_irqs), +}; + +static const struct regmap_irq max8907_rtc_irqs[] = { + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 0, .mask = 1 << 3, }, +}; + +static const struct regmap_irq_chip max8907_rtc_irq_chip = { + .name = "max8907 rtc", + .status_base = MAX8907_REG_RTC_IRQ, + .mask_base = MAX8907_REG_RTC_IRQ_MASK, + .num_regs = 1, + .irqs = max8907_rtc_irqs, + .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), +}; + +static struct max8907 *max8907_pm_off; +static void max8907_power_off(void) +{ + regmap_update_bits(max8907_pm_off->regmap_gen, MAX8907_REG_RESET_CNFG, + MAX8907_MASK_POWER_OFF, MAX8907_MASK_POWER_OFF); +} + +static __devinit int max8907_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max8907 *max8907; + int ret; + struct max8907_platform_data *pdata = dev_get_platdata(&i2c->dev); + bool pm_off = false; + + if (pdata) + pm_off = pdata->pm_off; + else if (i2c->dev.of_node) + pm_off = of_property_read_bool(i2c->dev.of_node, + "maxim,system-power-controller"); + + max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL); + if (!max8907) { + ret = -ENOMEM; + goto err_alloc_drvdata; + } + + max8907->dev = &i2c->dev; + dev_set_drvdata(max8907->dev, max8907); + + max8907->i2c_gen = i2c; + i2c_set_clientdata(i2c, max8907); + max8907->regmap_gen = devm_regmap_init_i2c(i2c, + &max8907_regmap_gen_config); + if (IS_ERR(max8907->regmap_gen)) { + ret = PTR_ERR(max8907->regmap_gen); + dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret); + goto err_regmap_gen; + } + + max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR); + if (!max8907->i2c_rtc) { + ret = -ENOMEM; + goto err_dummy_rtc; + } + i2c_set_clientdata(max8907->i2c_rtc, max8907); + max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc, + &max8907_regmap_rtc_config); + if (IS_ERR(max8907->regmap_rtc)) { + ret = PTR_ERR(max8907->regmap_rtc); + dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret); + goto err_regmap_rtc; + } + + irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN); + + ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_chg_irq_chip, + &max8907->irqc_chg); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret); + goto err_irqc_chg; + } + ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_on_off_irq_chip, + &max8907->irqc_on_off); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret); + goto err_irqc_on_off; + } + ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_rtc_irq_chip, + &max8907->irqc_rtc); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret); + goto err_irqc_rtc; + } + + enable_irq(max8907->i2c_gen->irq); + + ret = mfd_add_devices(max8907->dev, -1, max8907_cells, + ARRAY_SIZE(max8907_cells), NULL, 0, NULL); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret); + goto err_add_devices; + } + + if (pm_off && !pm_power_off) { + max8907_pm_off = max8907; + pm_power_off = max8907_power_off; + } + + return 0; + +err_add_devices: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); +err_irqc_rtc: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); +err_irqc_on_off: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); +err_irqc_chg: +err_regmap_rtc: + i2c_unregister_device(max8907->i2c_rtc); +err_dummy_rtc: +err_regmap_gen: +err_alloc_drvdata: + return ret; +} + +static __devexit int max8907_i2c_remove(struct i2c_client *i2c) +{ + struct max8907 *max8907 = i2c_get_clientdata(i2c); + + mfd_remove_devices(max8907->dev); + + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); + + i2c_unregister_device(max8907->i2c_rtc); + + return 0; +} + +#ifdef CONFIG_OF +static struct of_device_id max8907_of_match[] = { + { .compatible = "maxim,max8907" }, + { }, +}; +MODULE_DEVICE_TABLE(of, max8907_of_match); +#endif + +static const struct i2c_device_id max8907_i2c_id[] = { + {"max8907", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, max8907_i2c_id); + +static struct i2c_driver max8907_i2c_driver = { + .driver = { + .name = "max8907", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max8907_of_match), + }, + .probe = max8907_i2c_probe, + .remove = max8907_i2c_remove, + .id_table = max8907_i2c_id, +}; + +static int __init max8907_i2c_init(void) +{ + int ret = -ENODEV; + + ret = i2c_add_driver(&max8907_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} +subsys_initcall(max8907_i2c_init); + +static void __exit max8907_i2c_exit(void) +{ + i2c_del_driver(&max8907_i2c_driver); +} +module_exit(max8907_i2c_exit); + +MODULE_DESCRIPTION("MAX8907 multi-function core driver"); +MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index ee53757beca7..9f54c04912f2 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -15,23 +15,20 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/regulator/machine.h> #include <linux/mfd/core.h> #include <linux/mfd/max8925.h> -static struct resource backlight_resources[] = { - { - .name = "max8925-backlight", - .start = MAX8925_WLED_MODE_CNTL, - .end = MAX8925_WLED_CNTL, - .flags = IORESOURCE_IO, - }, +static struct resource bk_resources[] __devinitdata = { + { 0x84, 0x84, "mode control", IORESOURCE_REG, }, + { 0x85, 0x85, "control", IORESOURCE_REG, }, }; -static struct mfd_cell backlight_devs[] = { +static struct mfd_cell bk_devs[] __devinitdata = { { .name = "max8925-backlight", - .num_resources = 1, - .resources = &backlight_resources[0], + .num_resources = ARRAY_SIZE(bk_resources), + .resources = &bk_resources[0], .id = -1, }, }; @@ -41,7 +38,7 @@ static struct resource touch_resources[] = { .name = "max8925-tsc", .start = MAX8925_TSC_IRQ, .end = MAX8925_ADC_RES_END, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; @@ -59,7 +56,7 @@ static struct resource power_supply_resources[] = { .name = "max8925-power", .start = MAX8925_CHG_IRQ1, .end = MAX8925_CHG_IRQ1_MASK, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; @@ -113,71 +110,215 @@ static struct mfd_cell onkey_devs[] = { }, }; -#define MAX8925_REG_RESOURCE(_start, _end) \ -{ \ - .start = MAX8925_##_start, \ - .end = MAX8925_##_end, \ - .flags = IORESOURCE_IO, \ -} +static struct resource sd1_resources[] __devinitdata = { + {0x06, 0x06, "sdv", IORESOURCE_REG, }, +}; -static struct resource regulator_resources[] = { - MAX8925_REG_RESOURCE(SDCTL1, SDCTL1), - MAX8925_REG_RESOURCE(SDCTL2, SDCTL2), - MAX8925_REG_RESOURCE(SDCTL3, SDCTL3), - MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1), - MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2), - MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3), - MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4), - MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5), - MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6), - MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7), - MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8), - MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9), - MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10), - MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11), - MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12), - MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13), - MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14), - MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15), - MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16), - MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17), - MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18), - MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19), - MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20), -}; - -#define MAX8925_REG_DEVS(_id) \ -{ \ - .name = "max8925-regulator", \ - .num_resources = 1, \ - .resources = ®ulator_resources[MAX8925_ID_##_id], \ - .id = MAX8925_ID_##_id, \ -} +static struct resource sd2_resources[] __devinitdata = { + {0x09, 0x09, "sdv", IORESOURCE_REG, }, +}; + +static struct resource sd3_resources[] __devinitdata = { + {0x0c, 0x0c, "sdv", IORESOURCE_REG, }, +}; + +static struct resource ldo1_resources[] __devinitdata = { + {0x1a, 0x1a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo2_resources[] __devinitdata = { + {0x1e, 0x1e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo3_resources[] __devinitdata = { + {0x22, 0x22, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo4_resources[] __devinitdata = { + {0x26, 0x26, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo5_resources[] __devinitdata = { + {0x2a, 0x2a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo6_resources[] __devinitdata = { + {0x2e, 0x2e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo7_resources[] __devinitdata = { + {0x32, 0x32, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo8_resources[] __devinitdata = { + {0x36, 0x36, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo9_resources[] __devinitdata = { + {0x3a, 0x3a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo10_resources[] __devinitdata = { + {0x3e, 0x3e, "ldov", IORESOURCE_REG, }, +}; -static struct mfd_cell regulator_devs[] = { - MAX8925_REG_DEVS(SD1), - MAX8925_REG_DEVS(SD2), - MAX8925_REG_DEVS(SD3), - MAX8925_REG_DEVS(LDO1), - MAX8925_REG_DEVS(LDO2), - MAX8925_REG_DEVS(LDO3), - MAX8925_REG_DEVS(LDO4), - MAX8925_REG_DEVS(LDO5), - MAX8925_REG_DEVS(LDO6), - MAX8925_REG_DEVS(LDO7), - MAX8925_REG_DEVS(LDO8), - MAX8925_REG_DEVS(LDO9), - MAX8925_REG_DEVS(LDO10), - MAX8925_REG_DEVS(LDO11), - MAX8925_REG_DEVS(LDO12), - MAX8925_REG_DEVS(LDO13), - MAX8925_REG_DEVS(LDO14), - MAX8925_REG_DEVS(LDO15), - MAX8925_REG_DEVS(LDO16), - MAX8925_REG_DEVS(LDO17), - MAX8925_REG_DEVS(LDO18), - MAX8925_REG_DEVS(LDO19), - MAX8925_REG_DEVS(LDO20), +static struct resource ldo11_resources[] __devinitdata = { + {0x42, 0x42, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo12_resources[] __devinitdata = { + {0x46, 0x46, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo13_resources[] __devinitdata = { + {0x4a, 0x4a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo14_resources[] __devinitdata = { + {0x4e, 0x4e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo15_resources[] __devinitdata = { + {0x52, 0x52, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo16_resources[] __devinitdata = { + {0x12, 0x12, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo17_resources[] __devinitdata = { + {0x16, 0x16, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo18_resources[] __devinitdata = { + {0x74, 0x74, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo19_resources[] __devinitdata = { + {0x5e, 0x5e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo20_resources[] __devinitdata = { + {0x9e, 0x9e, "ldov", IORESOURCE_REG, }, +}; + +static struct mfd_cell reg_devs[] __devinitdata = { + { + .name = "max8925-regulator", + .id = 0, + .num_resources = ARRAY_SIZE(sd1_resources), + .resources = sd1_resources, + }, { + .name = "max8925-regulator", + .id = 1, + .num_resources = ARRAY_SIZE(sd2_resources), + .resources = sd2_resources, + }, { + .name = "max8925-regulator", + .id = 2, + .num_resources = ARRAY_SIZE(sd3_resources), + .resources = sd3_resources, + }, { + .name = "max8925-regulator", + .id = 3, + .num_resources = ARRAY_SIZE(ldo1_resources), + .resources = ldo1_resources, + }, { + .name = "max8925-regulator", + .id = 4, + .num_resources = ARRAY_SIZE(ldo2_resources), + .resources = ldo2_resources, + }, { + .name = "max8925-regulator", + .id = 5, + .num_resources = ARRAY_SIZE(ldo3_resources), + .resources = ldo3_resources, + }, { + .name = "max8925-regulator", + .id = 6, + .num_resources = ARRAY_SIZE(ldo4_resources), + .resources = ldo4_resources, + }, { + .name = "max8925-regulator", + .id = 7, + .num_resources = ARRAY_SIZE(ldo5_resources), + .resources = ldo5_resources, + }, { + .name = "max8925-regulator", + .id = 8, + .num_resources = ARRAY_SIZE(ldo6_resources), + .resources = ldo6_resources, + }, { + .name = "max8925-regulator", + .id = 9, + .num_resources = ARRAY_SIZE(ldo7_resources), + .resources = ldo7_resources, + }, { + .name = "max8925-regulator", + .id = 10, + .num_resources = ARRAY_SIZE(ldo8_resources), + .resources = ldo8_resources, + }, { + .name = "max8925-regulator", + .id = 11, + .num_resources = ARRAY_SIZE(ldo9_resources), + .resources = ldo9_resources, + }, { + .name = "max8925-regulator", + .id = 12, + .num_resources = ARRAY_SIZE(ldo10_resources), + .resources = ldo10_resources, + }, { + .name = "max8925-regulator", + .id = 13, + .num_resources = ARRAY_SIZE(ldo11_resources), + .resources = ldo11_resources, + }, { + .name = "max8925-regulator", + .id = 14, + .num_resources = ARRAY_SIZE(ldo12_resources), + .resources = ldo12_resources, + }, { + .name = "max8925-regulator", + .id = 15, + .num_resources = ARRAY_SIZE(ldo13_resources), + .resources = ldo13_resources, + }, { + .name = "max8925-regulator", + .id = 16, + .num_resources = ARRAY_SIZE(ldo14_resources), + .resources = ldo14_resources, + }, { + .name = "max8925-regulator", + .id = 17, + .num_resources = ARRAY_SIZE(ldo15_resources), + .resources = ldo15_resources, + }, { + .name = "max8925-regulator", + .id = 18, + .num_resources = ARRAY_SIZE(ldo16_resources), + .resources = ldo16_resources, + }, { + .name = "max8925-regulator", + .id = 19, + .num_resources = ARRAY_SIZE(ldo17_resources), + .resources = ldo17_resources, + }, { + .name = "max8925-regulator", + .id = 20, + .num_resources = ARRAY_SIZE(ldo18_resources), + .resources = ldo18_resources, + }, { + .name = "max8925-regulator", + .id = 21, + .num_resources = ARRAY_SIZE(ldo19_resources), + .resources = ldo19_resources, + }, { + .name = "max8925-regulator", + .id = 22, + .num_resources = ARRAY_SIZE(ldo20_resources), + .resources = ldo20_resources, + }, }; enum { @@ -547,7 +688,7 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, goto tsc_irq; } - ret = request_threaded_irq(irq, NULL, max8925_irq, flags, + ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT, "max8925", chip); if (ret) { dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); @@ -565,7 +706,7 @@ tsc_irq: chip->tsc_irq = pdata->tsc_irq; ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, - flags, "max8925-tsc", chip); + flags | IRQF_ONESHOT, "max8925-tsc", chip); if (ret) { dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); chip->tsc_irq = 0; @@ -573,6 +714,113 @@ tsc_irq: return 0; } +static void __devinit init_regulator(struct max8925_chip *chip, + struct max8925_platform_data *pdata) +{ + int ret; + + if (!pdata) + return; + if (pdata->sd1) { + reg_devs[0].platform_data = pdata->sd1; + reg_devs[0].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->sd2) { + reg_devs[1].platform_data = pdata->sd2; + reg_devs[1].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->sd3) { + reg_devs[2].platform_data = pdata->sd3; + reg_devs[2].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo1) { + reg_devs[3].platform_data = pdata->ldo1; + reg_devs[3].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo2) { + reg_devs[4].platform_data = pdata->ldo2; + reg_devs[4].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo3) { + reg_devs[5].platform_data = pdata->ldo3; + reg_devs[5].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo4) { + reg_devs[6].platform_data = pdata->ldo4; + reg_devs[6].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo5) { + reg_devs[7].platform_data = pdata->ldo5; + reg_devs[7].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo6) { + reg_devs[8].platform_data = pdata->ldo6; + reg_devs[8].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo7) { + reg_devs[9].platform_data = pdata->ldo7; + reg_devs[9].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo8) { + reg_devs[10].platform_data = pdata->ldo8; + reg_devs[10].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo9) { + reg_devs[11].platform_data = pdata->ldo9; + reg_devs[11].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo10) { + reg_devs[12].platform_data = pdata->ldo10; + reg_devs[12].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo11) { + reg_devs[13].platform_data = pdata->ldo11; + reg_devs[13].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo12) { + reg_devs[14].platform_data = pdata->ldo12; + reg_devs[14].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo13) { + reg_devs[15].platform_data = pdata->ldo13; + reg_devs[15].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo14) { + reg_devs[16].platform_data = pdata->ldo14; + reg_devs[16].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo15) { + reg_devs[17].platform_data = pdata->ldo15; + reg_devs[17].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo16) { + reg_devs[18].platform_data = pdata->ldo16; + reg_devs[18].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo17) { + reg_devs[19].platform_data = pdata->ldo17; + reg_devs[19].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo18) { + reg_devs[20].platform_data = pdata->ldo18; + reg_devs[20].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo19) { + reg_devs[21].platform_data = pdata->ldo19; + reg_devs[21].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo20) { + reg_devs[22].platform_data = pdata->ldo20; + reg_devs[22].pdata_size = sizeof(struct regulator_init_data); + } + ret = mfd_add_devices(chip->dev, 0, reg_devs, ARRAY_SIZE(reg_devs), + NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); + return; + } +} + int __devinit max8925_device_init(struct max8925_chip *chip, struct max8925_platform_data *pdata) { @@ -612,24 +860,17 @@ int __devinit max8925_device_init(struct max8925_chip *chip, goto out_dev; } - if (pdata) { - ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], - ARRAY_SIZE(regulator_devs), - ®ulator_resources[0], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add regulator subdev\n"); - goto out_dev; - } - } + init_regulator(chip, pdata); if (pdata && pdata->backlight) { - ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], - ARRAY_SIZE(backlight_devs), - &backlight_resources[0], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add backlight subdev\n"); - goto out_dev; - } + bk_devs[0].platform_data = &pdata->backlight; + bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata); + } + ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs), + NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add backlight subdev\n"); + goto out_dev; } if (pdata && pdata->power) { diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 1ec79b54bd2f..1aba0238f426 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -676,7 +676,6 @@ int mc13xxx_common_init(struct mc13xxx *mc13xxx, err_mask: err_revision: mc13xxx_unlock(mc13xxx); - kfree(mc13xxx); return ret; } diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 41088ecbb2a9..23cec57c02ba 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -21,7 +21,6 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/platform_device.h> #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/spinlock.h> @@ -36,63 +35,6 @@ /* OMAP USBHOST Register addresses */ -/* TLL Register Set */ -#define OMAP_USBTLL_REVISION (0x00) -#define OMAP_USBTLL_SYSCONFIG (0x10) -#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) -#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) -#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) -#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) -#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) - -#define OMAP_USBTLL_SYSSTATUS (0x14) -#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) - -#define OMAP_USBTLL_IRQSTATUS (0x18) -#define OMAP_USBTLL_IRQENABLE (0x1C) - -#define OMAP_TLL_SHARED_CONF (0x30) -#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) -#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) -#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) -#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) -#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) - -#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) -#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 -#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) -#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) -#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) -#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) -#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) -#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) - -#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 -#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 -#define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 -#define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 -#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 -#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 -#define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 -#define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 -#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA -#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB - -#define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) -#define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) -#define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) -#define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) -#define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) -#define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) -#define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) -#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) -#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) - -#define OMAP_TLL_CHANNEL_COUNT 3 -#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) -#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) -#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) - /* UHH Register Set */ #define OMAP_UHH_REVISION (0x00) #define OMAP_UHH_SYSCONFIG (0x10) @@ -132,8 +74,6 @@ #define OMAP4_P2_MODE_TLL (1 << 18) #define OMAP4_P2_MODE_HSIC (3 << 18) -#define OMAP_REV2_TLL_CHANNEL_COUNT 2 - #define OMAP_UHH_DEBUG_CSR (0x44) /* Values of UHH_REVISION - Note: these are not given in the TRM */ @@ -153,15 +93,12 @@ struct usbhs_hcd_omap { struct clk *xclk60mhsp2_ck; struct clk *utmi_p1_fck; struct clk *usbhost_p1_fck; - struct clk *usbtll_p1_fck; struct clk *utmi_p2_fck; struct clk *usbhost_p2_fck; - struct clk *usbtll_p2_fck; struct clk *init_60m_fclk; struct clk *ehci_logic_fck; void __iomem *uhh_base; - void __iomem *tll_base; struct usbhs_omap_platform_data platdata; @@ -336,93 +273,6 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) } } -/* - * convert the port-mode enum to a value we can use in the FSLSMODE - * field of USBTLL_CHANNEL_CONF - */ -static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) -{ - switch (mode) { - case OMAP_USBHS_PORT_MODE_UNUSED: - case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: - return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; - - case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: - return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; - - case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: - return OMAP_TLL_FSLSMODE_3PIN_PHY; - - case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: - return OMAP_TLL_FSLSMODE_4PIN_PHY; - - case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: - return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; - - case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: - return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; - - case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: - return OMAP_TLL_FSLSMODE_3PIN_TLL; - - case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: - return OMAP_TLL_FSLSMODE_4PIN_TLL; - - case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: - return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; - - case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: - return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; - default: - pr_warning("Invalid port mode, using default\n"); - return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; - } -} - -static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) -{ - struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); - struct usbhs_omap_platform_data *pdata = dev->platform_data; - unsigned reg; - int i; - - /* Program Common TLL register */ - reg = usbhs_read(omap->tll_base, OMAP_TLL_SHARED_CONF); - reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON - | OMAP_TLL_SHARED_CONF_USB_DIVRATION); - reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; - reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; - - usbhs_write(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); - - /* Enable channels now */ - for (i = 0; i < tll_channel_count; i++) { - reg = usbhs_read(omap->tll_base, - OMAP_TLL_CHANNEL_CONF(i)); - - if (is_ohci_port(pdata->port_mode[i])) { - reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) - << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; - reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; - } else if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_TLL) { - - /* Disable AutoIdle, BitStuffing and use SDR Mode */ - reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE - | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF - | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); - - } else - continue; - - reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; - usbhs_write(omap->tll_base, - OMAP_TLL_CHANNEL_CONF(i), reg); - - usbhs_writeb(omap->tll_base, - OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); - } -} - static int usbhs_runtime_resume(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); @@ -436,19 +286,17 @@ static int usbhs_runtime_resume(struct device *dev) return -ENODEV; } + omap_tll_enable(); spin_lock_irqsave(&omap->lock, flags); if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) clk_enable(omap->ehci_logic_fck); - if (is_ehci_tll_mode(pdata->port_mode[0])) { + if (is_ehci_tll_mode(pdata->port_mode[0])) clk_enable(omap->usbhost_p1_fck); - clk_enable(omap->usbtll_p1_fck); - } - if (is_ehci_tll_mode(pdata->port_mode[1])) { + if (is_ehci_tll_mode(pdata->port_mode[1])) clk_enable(omap->usbhost_p2_fck); - clk_enable(omap->usbtll_p2_fck); - } + clk_enable(omap->utmi_p1_fck); clk_enable(omap->utmi_p2_fck); @@ -472,14 +320,11 @@ static int usbhs_runtime_suspend(struct device *dev) spin_lock_irqsave(&omap->lock, flags); - if (is_ehci_tll_mode(pdata->port_mode[0])) { + if (is_ehci_tll_mode(pdata->port_mode[0])) clk_disable(omap->usbhost_p1_fck); - clk_disable(omap->usbtll_p1_fck); - } - if (is_ehci_tll_mode(pdata->port_mode[1])) { + if (is_ehci_tll_mode(pdata->port_mode[1])) clk_disable(omap->usbhost_p2_fck); - clk_disable(omap->usbtll_p2_fck); - } + clk_disable(omap->utmi_p2_fck); clk_disable(omap->utmi_p1_fck); @@ -487,6 +332,7 @@ static int usbhs_runtime_suspend(struct device *dev) clk_disable(omap->ehci_logic_fck); spin_unlock_irqrestore(&omap->lock, flags); + omap_tll_disable(); return 0; } @@ -500,8 +346,6 @@ static void omap_usbhs_init(struct device *dev) dev_dbg(dev, "starting TI HSUSB Controller\n"); - pm_runtime_get_sync(dev); - if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_request_one(pdata->ehci_data->reset_gpio_port[0], @@ -515,6 +359,7 @@ static void omap_usbhs_init(struct device *dev) udelay(10); } + pm_runtime_get_sync(dev); spin_lock_irqsave(&omap->lock, flags); omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); @@ -580,22 +425,9 @@ static void omap_usbhs_init(struct device *dev) usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); - if (is_ehci_tll_mode(pdata->port_mode[0]) || - is_ehci_tll_mode(pdata->port_mode[1]) || - is_ehci_tll_mode(pdata->port_mode[2]) || - (is_ohci_port(pdata->port_mode[0])) || - (is_ohci_port(pdata->port_mode[1])) || - (is_ohci_port(pdata->port_mode[2]))) { - - /* Enable UTMI mode for required TLL channels */ - if (is_omap_usbhs_rev2(omap)) - usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); - else - usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); - } - spin_unlock_irqrestore(&omap->lock, flags); + pm_runtime_put_sync(dev); if (pdata->ehci_data->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready @@ -610,8 +442,6 @@ static void omap_usbhs_init(struct device *dev) gpio_set_value_cansleep (pdata->ehci_data->reset_gpio_port[1], 1); } - - pm_runtime_put_sync(dev); } static void omap_usbhs_deinit(struct device *dev) @@ -714,32 +544,18 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) goto err_xclk60mhsp2_ck; } - omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); - if (IS_ERR(omap->usbtll_p1_fck)) { - ret = PTR_ERR(omap->usbtll_p1_fck); - dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); - goto err_usbhost_p1_fck; - } - omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); if (IS_ERR(omap->usbhost_p2_fck)) { ret = PTR_ERR(omap->usbhost_p2_fck); dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); - goto err_usbtll_p1_fck; - } - - omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); - if (IS_ERR(omap->usbtll_p2_fck)) { - ret = PTR_ERR(omap->usbtll_p2_fck); - dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); - goto err_usbhost_p2_fck; + goto err_usbhost_p1_fck; } omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); if (IS_ERR(omap->init_60m_fclk)) { ret = PTR_ERR(omap->init_60m_fclk); dev_err(dev, "init_60m_fclk failed error:%d\n", ret); - goto err_usbtll_p2_fck; + goto err_usbhost_p2_fck; } if (is_ehci_phy_mode(pdata->port_mode[0])) { @@ -785,20 +601,6 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) goto err_init_60m_fclk; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); - if (!res) { - dev_err(dev, "UHH EHCI get resource failed\n"); - ret = -ENODEV; - goto err_tll; - } - - omap->tll_base = ioremap(res->start, resource_size(res)); - if (!omap->tll_base) { - dev_err(dev, "TLL ioremap failed\n"); - ret = -ENOMEM; - goto err_tll; - } - platform_set_drvdata(pdev, omap); omap_usbhs_init(dev); @@ -812,23 +614,14 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) err_alloc: omap_usbhs_deinit(&pdev->dev); - iounmap(omap->tll_base); - -err_tll: iounmap(omap->uhh_base); err_init_60m_fclk: clk_put(omap->init_60m_fclk); -err_usbtll_p2_fck: - clk_put(omap->usbtll_p2_fck); - err_usbhost_p2_fck: clk_put(omap->usbhost_p2_fck); -err_usbtll_p1_fck: - clk_put(omap->usbtll_p1_fck); - err_usbhost_p1_fck: clk_put(omap->usbhost_p1_fck); @@ -864,12 +657,9 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); omap_usbhs_deinit(&pdev->dev); - iounmap(omap->tll_base); iounmap(omap->uhh_base); clk_put(omap->init_60m_fclk); - clk_put(omap->usbtll_p2_fck); clk_put(omap->usbhost_p2_fck); - clk_put(omap->usbtll_p1_fck); clk_put(omap->usbhost_p1_fck); clk_put(omap->xclk60mhsp2_ck); clk_put(omap->utmi_p2_fck); @@ -910,8 +700,10 @@ static int __init omap_usbhs_drvinit(void) * init before ehci and ohci drivers; * The usbhs core driver should be initialized much before * the omap ehci and ohci probe functions are called. + * This usbhs core driver should be initialized after + * usb tll driver */ -fs_initcall(omap_usbhs_drvinit); +fs_initcall_sync(omap_usbhs_drvinit); static void __exit omap_usbhs_drvexit(void) { diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c new file mode 100644 index 000000000000..4b7757b84301 --- /dev/null +++ b/drivers/mfd/omap-usb-tll.c @@ -0,0 +1,471 @@ +/** + * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * Author: Keshava Munegowda <keshava_mgowda@ti.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * 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, see <http://www.gnu.org/licenses/>. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/err.h> +#include <plat/usb.h> +#include <linux/pm_runtime.h> + +#define USBTLL_DRIVER_NAME "usbhs_tll" + +/* TLL Register Set */ +#define OMAP_USBTLL_REVISION (0x00) +#define OMAP_USBTLL_SYSCONFIG (0x10) +#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) +#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) +#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) +#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) +#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) + +#define OMAP_USBTLL_SYSSTATUS (0x14) +#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) + +#define OMAP_USBTLL_IRQSTATUS (0x18) +#define OMAP_USBTLL_IRQENABLE (0x1C) + +#define OMAP_TLL_SHARED_CONF (0x30) +#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) +#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) +#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) +#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) +#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) + +#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) +#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 +#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) +#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) +#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) +#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) +#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) +#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) + +#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 +#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 +#define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 +#define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 +#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 +#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 +#define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 +#define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 +#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA +#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB + +#define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) +#define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) +#define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) +#define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) +#define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) +#define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) +#define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) +#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) +#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) + +#define OMAP_REV2_TLL_CHANNEL_COUNT 2 +#define OMAP_TLL_CHANNEL_COUNT 3 +#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) +#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) +#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) + +/* Values of USBTLL_REVISION - Note: these are not given in the TRM */ +#define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ +#define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ +#define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ + +#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) + +struct usbtll_omap { + struct clk *usbtll_p1_fck; + struct clk *usbtll_p2_fck; + struct usbtll_omap_platform_data platdata; + /* secure the register updates */ + spinlock_t lock; +}; + +/*-------------------------------------------------------------------------*/ + +const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; +struct platform_device *tll_pdev; + +/*-------------------------------------------------------------------------*/ + +static inline void usbtll_write(void __iomem *base, u32 reg, u32 val) +{ + __raw_writel(val, base + reg); +} + +static inline u32 usbtll_read(void __iomem *base, u32 reg) +{ + return __raw_readl(base + reg); +} + +static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) +{ + __raw_writeb(val, base + reg); +} + +static inline u8 usbtll_readb(void __iomem *base, u8 reg) +{ + return __raw_readb(base + reg); +} + +/*-------------------------------------------------------------------------*/ + +static bool is_ohci_port(enum usbhs_omap_port_mode pmode) +{ + switch (pmode) { + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: + case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: + case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: + return true; + + default: + return false; + } +} + +/* + * convert the port-mode enum to a value we can use in the FSLSMODE + * field of USBTLL_CHANNEL_CONF + */ +static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) +{ + switch (mode) { + case OMAP_USBHS_PORT_MODE_UNUSED: + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: + return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; + + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: + return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; + + case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: + return OMAP_TLL_FSLSMODE_3PIN_PHY; + + case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: + return OMAP_TLL_FSLSMODE_4PIN_PHY; + + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: + return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; + + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: + return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; + + case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: + return OMAP_TLL_FSLSMODE_3PIN_TLL; + + case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: + return OMAP_TLL_FSLSMODE_4PIN_TLL; + + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: + return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; + + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: + return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; + default: + pr_warn("Invalid port mode, using default\n"); + return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; + } +} + +/** + * usbtll_omap_probe - initialize TI-based HCDs + * + * Allocates basic resources for this USB host controller. + */ +static int __devinit usbtll_omap_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usbtll_omap_platform_data *pdata = dev->platform_data; + void __iomem *base; + struct resource *res; + struct usbtll_omap *tll; + unsigned reg; + unsigned long flags; + int ret = 0; + int i, ver, count; + + dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); + + tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL); + if (!tll) { + dev_err(dev, "Memory allocation failed\n"); + ret = -ENOMEM; + goto end; + } + + spin_lock_init(&tll->lock); + + for (i = 0; i < OMAP3_HS_USB_PORTS; i++) + tll->platdata.port_mode[i] = pdata->port_mode[i]; + + tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); + if (IS_ERR(tll->usbtll_p1_fck)) { + ret = PTR_ERR(tll->usbtll_p1_fck); + dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); + goto err_tll; + } + + tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); + if (IS_ERR(tll->usbtll_p2_fck)) { + ret = PTR_ERR(tll->usbtll_p2_fck); + dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); + goto err_usbtll_p1_fck; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "usb tll get resource failed\n"); + ret = -ENODEV; + goto err_usbtll_p2_fck; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + dev_err(dev, "TLL ioremap failed\n"); + ret = -ENOMEM; + goto err_usbtll_p2_fck; + } + + platform_set_drvdata(pdev, tll); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + spin_lock_irqsave(&tll->lock, flags); + + ver = usbtll_read(base, OMAP_USBTLL_REVISION); + switch (ver) { + case OMAP_USBTLL_REV1: + case OMAP_USBTLL_REV2: + count = OMAP_TLL_CHANNEL_COUNT; + break; + case OMAP_USBTLL_REV3: + count = OMAP_REV2_TLL_CHANNEL_COUNT; + break; + default: + dev_err(dev, "TLL version failed\n"); + ret = -ENODEV; + goto err_ioremap; + } + + if (is_ehci_tll_mode(pdata->port_mode[0]) || + is_ehci_tll_mode(pdata->port_mode[1]) || + is_ehci_tll_mode(pdata->port_mode[2]) || + is_ohci_port(pdata->port_mode[0]) || + is_ohci_port(pdata->port_mode[1]) || + is_ohci_port(pdata->port_mode[2])) { + + /* Program Common TLL register */ + reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); + reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON + | OMAP_TLL_SHARED_CONF_USB_DIVRATION); + reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; + reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; + + usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); + + /* Enable channels now */ + for (i = 0; i < count; i++) { + reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); + + if (is_ohci_port(pdata->port_mode[i])) { + reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) + << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; + reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; + } else if (pdata->port_mode[i] == + OMAP_EHCI_PORT_MODE_TLL) { + /* + * Disable AutoIdle, BitStuffing + * and use SDR Mode + */ + reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE + | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF + | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); + } else { + continue; + } + reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; + usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg); + + usbtll_writeb(base, + OMAP_TLL_ULPI_SCRATCH_REGISTER(i), + 0xbe); + } + } + +err_ioremap: + spin_unlock_irqrestore(&tll->lock, flags); + iounmap(base); + pm_runtime_put_sync(dev); + tll_pdev = pdev; + if (!ret) + goto end; + pm_runtime_disable(dev); + +err_usbtll_p2_fck: + clk_put(tll->usbtll_p2_fck); + +err_usbtll_p1_fck: + clk_put(tll->usbtll_p1_fck); + +err_tll: + kfree(tll); + +end: + return ret; +} + +/** + * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs + * @pdev: USB Host Controller being removed + * + * Reverses the effect of usbtll_omap_probe(). + */ +static int __devexit usbtll_omap_remove(struct platform_device *pdev) +{ + struct usbtll_omap *tll = platform_get_drvdata(pdev); + + clk_put(tll->usbtll_p2_fck); + clk_put(tll->usbtll_p1_fck); + pm_runtime_disable(&pdev->dev); + kfree(tll); + return 0; +} + +static int usbtll_runtime_resume(struct device *dev) +{ + struct usbtll_omap *tll = dev_get_drvdata(dev); + struct usbtll_omap_platform_data *pdata = &tll->platdata; + unsigned long flags; + + dev_dbg(dev, "usbtll_runtime_resume\n"); + + if (!pdata) { + dev_dbg(dev, "missing platform_data\n"); + return -ENODEV; + } + + spin_lock_irqsave(&tll->lock, flags); + + if (is_ehci_tll_mode(pdata->port_mode[0])) + clk_enable(tll->usbtll_p1_fck); + + if (is_ehci_tll_mode(pdata->port_mode[1])) + clk_enable(tll->usbtll_p2_fck); + + spin_unlock_irqrestore(&tll->lock, flags); + + return 0; +} + +static int usbtll_runtime_suspend(struct device *dev) +{ + struct usbtll_omap *tll = dev_get_drvdata(dev); + struct usbtll_omap_platform_data *pdata = &tll->platdata; + unsigned long flags; + + dev_dbg(dev, "usbtll_runtime_suspend\n"); + + if (!pdata) { + dev_dbg(dev, "missing platform_data\n"); + return -ENODEV; + } + + spin_lock_irqsave(&tll->lock, flags); + + if (is_ehci_tll_mode(pdata->port_mode[0])) + clk_disable(tll->usbtll_p1_fck); + + if (is_ehci_tll_mode(pdata->port_mode[1])) + clk_disable(tll->usbtll_p2_fck); + + spin_unlock_irqrestore(&tll->lock, flags); + + return 0; +} + +static const struct dev_pm_ops usbtllomap_dev_pm_ops = { + SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, + usbtll_runtime_resume, + NULL) +}; + +static struct platform_driver usbtll_omap_driver = { + .driver = { + .name = (char *)usbtll_driver_name, + .owner = THIS_MODULE, + .pm = &usbtllomap_dev_pm_ops, + }, + .probe = usbtll_omap_probe, + .remove = __devexit_p(usbtll_omap_remove), +}; + +int omap_tll_enable(void) +{ + if (!tll_pdev) { + pr_err("missing omap usbhs tll platform_data\n"); + return -ENODEV; + } + return pm_runtime_get_sync(&tll_pdev->dev); +} +EXPORT_SYMBOL_GPL(omap_tll_enable); + +int omap_tll_disable(void) +{ + if (!tll_pdev) { + pr_err("missing omap usbhs tll platform_data\n"); + return -ENODEV; + } + return pm_runtime_put_sync(&tll_pdev->dev); +} +EXPORT_SYMBOL_GPL(omap_tll_disable); + +MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); +MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); + +static int __init omap_usbtll_drvinit(void) +{ + return platform_driver_register(&usbtll_omap_driver); +} + +/* + * init before usbhs core driver; + * The usbtll driver should be initialized before + * the usbhs core driver probe function is called. + */ +fs_initcall(omap_usbtll_drvinit); + +static void __exit omap_usbtll_drvexit(void) +{ + platform_driver_unregister(&usbtll_omap_driver); +} +module_exit(omap_usbtll_drvexit); diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index a345f9bb7b47..4f8d6e6b19aa 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -23,60 +23,7 @@ #include <linux/err.h> #include <linux/mfd/core.h> #include <linux/mfd/palmas.h> - -static const struct resource gpadc_resource[] = { - { - .name = "EOC_SW", - .start = PALMAS_GPADC_EOC_SW_IRQ, - .end = PALMAS_GPADC_EOC_SW_IRQ, - .flags = IORESOURCE_IRQ, - } -}; - -static const struct resource usb_resource[] = { - { - .name = "ID", - .start = PALMAS_ID_OTG_IRQ, - .end = PALMAS_ID_OTG_IRQ, - .flags = IORESOURCE_IRQ, - }, - { - .name = "ID_WAKEUP", - .start = PALMAS_ID_IRQ, - .end = PALMAS_ID_IRQ, - .flags = IORESOURCE_IRQ, - }, - { - .name = "VBUS", - .start = PALMAS_VBUS_OTG_IRQ, - .end = PALMAS_VBUS_OTG_IRQ, - .flags = IORESOURCE_IRQ, - }, - { - .name = "VBUS_WAKEUP", - .start = PALMAS_VBUS_IRQ, - .end = PALMAS_VBUS_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource rtc_resource[] = { - { - .name = "RTC_ALARM", - .start = PALMAS_RTC_ALARM_IRQ, - .end = PALMAS_RTC_ALARM_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource pwron_resource[] = { - { - .name = "PWRON_BUTTON", - .start = PALMAS_PWRON_IRQ, - .end = PALMAS_PWRON_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; +#include <linux/of_platform.h> enum palmas_ids { PALMAS_PMIC_ID, @@ -111,20 +58,14 @@ static const struct mfd_cell palmas_children[] = { }, { .name = "palmas-rtc", - .num_resources = ARRAY_SIZE(rtc_resource), - .resources = rtc_resource, .id = PALMAS_RTC_ID, }, { .name = "palmas-pwrbutton", - .num_resources = ARRAY_SIZE(pwron_resource), - .resources = pwron_resource, .id = PALMAS_PWRBUTTON_ID, }, { .name = "palmas-gpadc", - .num_resources = ARRAY_SIZE(gpadc_resource), - .resources = gpadc_resource, .id = PALMAS_GPADC_ID, }, { @@ -141,8 +82,6 @@ static const struct mfd_cell palmas_children[] = { }, { .name = "palmas-usb", - .num_resources = ARRAY_SIZE(usb_resource), - .resources = usb_resource, .id = PALMAS_USB_ID, } }; @@ -308,17 +247,56 @@ static struct regmap_irq_chip palmas_irq_chip = { PALMAS_INT1_MASK), }; +static void __devinit palmas_dt_to_pdata(struct device_node *node, + struct palmas_platform_data *pdata) +{ + int ret; + u32 prop; + + ret = of_property_read_u32(node, "ti,mux_pad1", &prop); + if (!ret) { + pdata->mux_from_pdata = 1; + pdata->pad1 = prop; + } + + ret = of_property_read_u32(node, "ti,mux_pad2", &prop); + if (!ret) { + pdata->mux_from_pdata = 1; + pdata->pad2 = prop; + } + + /* The default for this register is all masked */ + ret = of_property_read_u32(node, "ti,power_ctrl", &prop); + if (!ret) + pdata->power_ctrl = prop; + else + pdata->power_ctrl = PALMAS_POWER_CTRL_NSLEEP_MASK | + PALMAS_POWER_CTRL_ENABLE1_MASK | + PALMAS_POWER_CTRL_ENABLE2_MASK; +} + static int __devinit palmas_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct palmas *palmas; struct palmas_platform_data *pdata; + struct device_node *node = i2c->dev.of_node; int ret = 0, i; unsigned int reg, addr; int slave; struct mfd_cell *children; pdata = dev_get_platdata(&i2c->dev); + + if (node && !pdata) { + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + + if (!pdata) + return -ENOMEM; + + palmas_dt_to_pdata(node, pdata); + } + if (!pdata) return -EINVAL; @@ -364,7 +342,7 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, regmap_write(palmas->regmap[slave], addr, reg); ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, 0, &palmas_irq_chip, &palmas->irq_data); if (ret < 0) goto err; @@ -377,11 +355,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, reg = pdata->pad1; ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) - goto err; + goto err_irq; } else { ret = regmap_read(palmas->regmap[slave], addr, ®); if (ret) - goto err; + goto err_irq; } if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) @@ -412,11 +390,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, reg = pdata->pad2; ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) - goto err; + goto err_irq; } else { ret = regmap_read(palmas->regmap[slave], addr, ®); if (ret) - goto err; + goto err_irq; } if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) @@ -439,18 +417,43 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) - goto err; + goto err_irq; + + /* + * If we are probing with DT do this the DT way and return here + * otherwise continue and add devices using mfd helpers. + */ + if (node) { + ret = of_platform_populate(node, NULL, NULL, &i2c->dev); + if (ret < 0) + goto err_irq; + else + return ret; + } children = kmemdup(palmas_children, sizeof(palmas_children), GFP_KERNEL); if (!children) { ret = -ENOMEM; - goto err; + goto err_irq; } children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata); + children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata; + children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata); + + children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata; + children[PALMAS_RESOURCE_ID].pdata_size = + sizeof(*pdata->resource_pdata); + + children[PALMAS_USB_ID].platform_data = pdata->usb_pdata; + children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata); + + children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata; + children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata); + ret = mfd_add_devices(palmas->dev, -1, children, ARRAY_SIZE(palmas_children), NULL, regmap_irq_chip_get_base(palmas->irq_data), @@ -458,13 +461,15 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, kfree(children); if (ret < 0) - goto err; + goto err_devices; return ret; -err: +err_devices: mfd_remove_devices(palmas->dev); - kfree(palmas); +err_irq: + regmap_del_irq_chip(palmas->irq, palmas->irq_data); +err: return ret; } diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c index fa6f80fad5f1..fe00cdd6f83d 100644 --- a/drivers/mfd/rc5t583-irq.c +++ b/drivers/mfd/rc5t583-irq.c @@ -255,7 +255,7 @@ static irqreturn_t rc5t583_irq(int irq, void *data) { struct rc5t583 *rc5t583 = data; uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS]; - uint8_t master_int; + uint8_t master_int = 0; int i; int ret; unsigned int rtc_int_sts = 0; diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index ff61efc76ce2..f1a024ecdb1e 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -85,7 +85,7 @@ static int __rc5t583_set_ext_pwrreq1_control(struct device *dev, int id, int ext_pwr, int slots) { int ret; - uint8_t sleepseq_val; + uint8_t sleepseq_val = 0; unsigned int en_bit; unsigned int slot_bit; diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c new file mode 100644 index 000000000000..24ae3d8421c5 --- /dev/null +++ b/drivers/mfd/smsc-ece1099.c @@ -0,0 +1,113 @@ +/* + * TI SMSC MFD Driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Sourav Poddar <sourav.poddar@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; GPL v2. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/regmap.h> +#include <linux/err.h> +#include <linux/mfd/core.h> +#include <linux/mfd/smsc.h> +#include <linux/of_platform.h> + +static struct regmap_config smsc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = SMSC_VEN_ID_H, + .cache_type = REGCACHE_RBTREE, +}; + +static int smsc_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct smsc *smsc; + int devid, rev, venid_l, venid_h; + int ret = 0; + + smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), + GFP_KERNEL); + if (!smsc) { + dev_err(&i2c->dev, "smsc mfd driver memory allocation failed\n"); + return -ENOMEM; + } + + smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); + if (IS_ERR(smsc->regmap)) { + ret = PTR_ERR(smsc->regmap); + goto err; + } + + i2c_set_clientdata(i2c, smsc); + smsc->dev = &i2c->dev; + +#ifdef CONFIG_OF + of_property_read_u32(i2c->dev.of_node, "clock", &smsc->clk); +#endif + + regmap_read(smsc->regmap, SMSC_DEV_ID, &devid); + regmap_read(smsc->regmap, SMSC_DEV_REV, &rev); + regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l); + regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h); + + dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n", + devid, rev, (venid_h << 8) | venid_l); + + ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); + if (ret) + goto err; + +#ifdef CONFIG_OF + if (i2c->dev.of_node) + ret = of_platform_populate(i2c->dev.of_node, + NULL, NULL, &i2c->dev); +#endif + +err: + return ret; +} + +static int smsc_i2c_remove(struct i2c_client *i2c) +{ + struct smsc *smsc = i2c_get_clientdata(i2c); + + mfd_remove_devices(smsc->dev); + + return 0; +} + +static const struct i2c_device_id smsc_i2c_id[] = { + { "smscece1099", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, smsc_i2c_id); + +static struct i2c_driver smsc_i2c_driver = { + .driver = { + .name = "smsc", + .owner = THIS_MODULE, + }, + .probe = smsc_i2c_probe, + .remove = smsc_i2c_remove, + .id_table = smsc_i2c_id, +}; + +module_i2c_driver(smsc_i2c_driver); + +MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); +MODULE_DESCRIPTION("SMSC chip multi-function driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c new file mode 100644 index 000000000000..65fe609026cc --- /dev/null +++ b/drivers/mfd/syscon.c @@ -0,0 +1,176 @@ +/* + * System Control Driver + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng <dong.aisheng@linaro.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. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +static struct platform_driver syscon_driver; + +struct syscon { + struct device *dev; + void __iomem *base; + struct regmap *regmap; +}; + +static int syscon_match(struct device *dev, void *data) +{ + struct syscon *syscon = dev_get_drvdata(dev); + struct device_node *dn = data; + + return (syscon->dev->of_node == dn) ? 1 : 0; +} + +struct regmap *syscon_node_to_regmap(struct device_node *np) +{ + struct syscon *syscon; + struct device *dev; + + dev = driver_find_device(&syscon_driver.driver, NULL, np, + syscon_match); + if (!dev) + return ERR_PTR(-EPROBE_DEFER); + + syscon = dev_get_drvdata(dev); + + return syscon->regmap; +} +EXPORT_SYMBOL_GPL(syscon_node_to_regmap); + +struct regmap *syscon_regmap_lookup_by_compatible(const char *s) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + syscon_np = of_find_compatible_node(NULL, NULL, s); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); + +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + const char *property) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + syscon_np = of_parse_phandle(np, property, 0); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); + +static const struct of_device_id of_syscon_match[] = { + { .compatible = "syscon", }, + { }, +}; + +static struct regmap_config syscon_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int __devinit syscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct syscon *syscon; + struct resource res; + int ret; + + if (!np) + return -ENOENT; + + syscon = devm_kzalloc(dev, sizeof(struct syscon), + GFP_KERNEL); + if (!syscon) + return -ENOMEM; + + syscon->base = of_iomap(np, 0); + if (!syscon->base) + return -EADDRNOTAVAIL; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + syscon_regmap_config.max_register = res.end - res.start - 3; + syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, + &syscon_regmap_config); + if (IS_ERR(syscon->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(syscon->regmap); + } + + syscon->dev = dev; + platform_set_drvdata(pdev, syscon); + + dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", + res.start, res.end); + + return 0; +} + +static int __devexit syscon_remove(struct platform_device *pdev) +{ + struct syscon *syscon; + + syscon = platform_get_drvdata(pdev); + iounmap(syscon->base); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver syscon_driver = { + .driver = { + .name = "syscon", + .owner = THIS_MODULE, + .of_match_table = of_syscon_match, + }, + .probe = syscon_probe, + .remove = __devexit_p(syscon_remove), +}; + +static int __init syscon_init(void) +{ + return platform_driver_register(&syscon_driver); +} +postcore_initcall(syscon_init); + +static void __exit syscon_exit(void) +{ + platform_driver_unregister(&syscon_driver); +} +module_exit(syscon_exit); + +MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>"); +MODULE_DESCRIPTION("System Control driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index b56ba6b43294..8f4c853ca116 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -9,8 +9,10 @@ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/of.h> #include <linux/mfd/core.h> #include <linux/mfd/tc3589x.h> @@ -145,6 +147,7 @@ static struct mfd_cell tc3589x_dev_gpio[] = { .name = "tc3589x-gpio", .num_resources = ARRAY_SIZE(gpio_resources), .resources = &gpio_resources[0], + .of_compatible = "tc3589x-gpio", }, }; @@ -153,6 +156,7 @@ static struct mfd_cell tc3589x_dev_keypad[] = { .name = "tc3589x-keypad", .num_resources = ARRAY_SIZE(keypad_resources), .resources = &keypad_resources[0], + .of_compatible = "tc3589x-keypad", }, }; @@ -168,8 +172,9 @@ again: while (status) { int bit = __ffs(status); + int virq = irq_create_mapping(tc3589x->domain, bit); - handle_nested_irq(tc3589x->irq_base + bit); + handle_nested_irq(virq); status &= ~(1 << bit); } @@ -186,38 +191,60 @@ again: return IRQ_HANDLED; } -static int tc3589x_irq_init(struct tc3589x *tc3589x) +static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - int base = tc3589x->irq_base; - int irq; + struct tc3589x *tc3589x = d->host_data; - for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { - irq_set_chip_data(irq, tc3589x); - irq_set_chip_and_handler(irq, &dummy_irq_chip, - handle_edge_irq); - irq_set_nested_thread(irq, 1); + irq_set_chip_data(virq, tc3589x); + irq_set_chip_and_handler(virq, &dummy_irq_chip, + handle_edge_irq); + irq_set_nested_thread(virq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(virq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(virq); #endif - } return 0; } -static void tc3589x_irq_remove(struct tc3589x *tc3589x) +static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq) { - int base = tc3589x->irq_base; - int irq; - - for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { #ifdef CONFIG_ARM - set_irq_flags(irq, 0); + set_irq_flags(virq, 0); #endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static struct irq_domain_ops tc3589x_irq_ops = { + .map = tc3589x_irq_map, + .unmap = tc3589x_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) +{ + int base = tc3589x->irq_base; + + if (base) { + tc3589x->domain = irq_domain_add_legacy( + NULL, TC3589x_NR_INTERNAL_IRQS, base, + 0, &tc3589x_irq_ops, tc3589x); + } + else { + tc3589x->domain = irq_domain_add_linear( + np, TC3589x_NR_INTERNAL_IRQS, + &tc3589x_irq_ops, tc3589x); } + + if (!tc3589x->domain) { + dev_err(tc3589x->dev, "Failed to create irqdomain\n"); + return -ENOSYS; + } + + return 0; } static int tc3589x_chip_init(struct tc3589x *tc3589x) @@ -263,7 +290,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) if (blocks & TC3589x_BLOCK_GPIO) { ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, ARRAY_SIZE(tc3589x_dev_gpio), NULL, - tc3589x->irq_base, NULL); + tc3589x->irq_base, tc3589x->domain); if (ret) { dev_err(tc3589x->dev, "failed to add gpio child\n"); return ret; @@ -274,7 +301,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) if (blocks & TC3589x_BLOCK_KEYPAD) { ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, ARRAY_SIZE(tc3589x_dev_keypad), NULL, - tc3589x->irq_base, NULL); + tc3589x->irq_base, tc3589x->domain); if (ret) { dev_err(tc3589x->dev, "failed to keypad child\n"); return ret; @@ -285,13 +312,47 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) return ret; } +static int tc3589x_of_probe(struct device_node *np, + struct tc3589x_platform_data *pdata) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (!strcmp(child->name, "tc3589x_gpio")) { + pdata->block |= TC3589x_BLOCK_GPIO; + } + if (!strcmp(child->name, "tc3589x_keypad")) { + pdata->block |= TC3589x_BLOCK_KEYPAD; + } + } + + return 0; +} + static int __devinit tc3589x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct tc3589x_platform_data *pdata = i2c->dev.platform_data; + struct device_node *np = i2c->dev.of_node; struct tc3589x *tc3589x; int ret; + if (!pdata) { + if (np) { + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = tc3589x_of_probe(np, pdata); + if (ret) + return ret; + } + else { + dev_err(&i2c->dev, "No platform data or DT found\n"); + return -EINVAL; + } + } + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; @@ -314,7 +375,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, if (ret) goto out_free; - ret = tc3589x_irq_init(tc3589x); + ret = tc3589x_irq_init(tc3589x, np); if (ret) goto out_free; @@ -323,7 +384,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, "tc3589x", tc3589x); if (ret) { dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); - goto out_removeirq; + goto out_free; } ret = tc3589x_device_init(tc3589x); @@ -336,8 +397,6 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, out_freeirq: free_irq(tc3589x->i2c->irq, tc3589x); -out_removeirq: - tc3589x_irq_remove(tc3589x); out_free: kfree(tc3589x); return ret; @@ -350,7 +409,6 @@ static int __devexit tc3589x_remove(struct i2c_client *client) mfd_remove_devices(tc3589x->dev); free_irq(tc3589x->i2c->irq, tc3589x); - tc3589x_irq_remove(tc3589x); kfree(tc3589x); diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 50fd87c87a1c..074ae32b0d2a 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -236,7 +236,7 @@ static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq, static bool is_volatile_reg(struct device *dev, unsigned int reg) { - if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS)) + if (reg == TPS65090_INT_STS) return true; else return false; diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index a95e9421b735..3fb32e655254 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -34,6 +34,9 @@ static struct mfd_cell tps65217s[] = { { .name = "tps65217-pmic", }, + { + .name = "tps65217-bl", + }, }; /** diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 345960ca2fd8..467464368773 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -30,6 +30,10 @@ #include <linux/mfd/core.h> #include <linux/mfd/tps6586x.h> +#define TPS6586X_SUPPLYENE 0x14 +#define EXITSLREQ_BIT BIT(1) +#define SLEEP_MODE_BIT BIT(3) + /* interrupt control registers */ #define TPS6586X_INT_ACK1 0xb5 #define TPS6586X_INT_ACK2 0xb6 @@ -422,6 +426,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien pdata->subdevs = devs; pdata->gpio_base = -1; pdata->irq_base = -1; + pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller"); return pdata; } @@ -454,6 +459,15 @@ static const struct regmap_config tps6586x_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static struct device *tps6586x_dev; +static void tps6586x_power_off(void) +{ + if (tps6586x_clr_bits(tps6586x_dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT)) + return; + + tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); +} + static int __devinit tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -519,6 +533,11 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, goto err_add_devs; } + if (pdata->pm_off && !pm_power_off) { + tps6586x_dev = &client->dev; + pm_power_off = tps6586x_power_off; + } + return 0; err_add_devs: diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index d3ce4d569deb..0d79ce2b5014 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -24,6 +24,14 @@ #include <linux/mfd/tps65910.h> #include <linux/of_device.h> +static struct resource rtc_resources[] = { + { + .start = TPS65910_IRQ_RTC_ALARM, + .end = TPS65910_IRQ_RTC_ALARM, + .flags = IORESOURCE_IRQ, + } +}; + static struct mfd_cell tps65910s[] = { { .name = "tps65910-gpio", @@ -33,6 +41,8 @@ static struct mfd_cell tps65910s[] = { }, { .name = "tps65910-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), + .resources = &rtc_resources[0], }, { .name = "tps65910-power", @@ -198,6 +208,8 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, board_info->irq = client->irq; board_info->irq_base = -1; + board_info->pm_off = of_property_read_bool(np, + "ti,system-power-controller"); return board_info; } @@ -210,6 +222,21 @@ struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, } #endif +static struct i2c_client *tps65910_i2c_client; +static void tps65910_power_off(void) +{ + struct tps65910 *tps65910; + + tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev); + + if (tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_PWR_OFF_MASK) < 0) + return; + + tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_ON_MASK); +} + static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -267,6 +294,11 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_ck32k_init(tps65910, pmic_plat_data); tps65910_sleepinit(tps65910, pmic_plat_data); + if (pmic_plat_data->pm_off && !pm_power_off) { + tps65910_i2c_client = i2c; + pm_power_off = tps65910_power_off; + } + return ret; } diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 9d3a0bc1a65f..4ae642320205 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -63,70 +63,6 @@ #define DRIVER_NAME "twl" -#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE) -#define twl_has_keypad() true -#else -#define twl_has_keypad() false -#endif - -#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE) -#define twl_has_gpio() true -#else -#define twl_has_gpio() false -#endif - -#if defined(CONFIG_REGULATOR_TWL4030) \ - || defined(CONFIG_REGULATOR_TWL4030_MODULE) -#define twl_has_regulator() true -#else -#define twl_has_regulator() false -#endif - -#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) -#define twl_has_madc() true -#else -#define twl_has_madc() false -#endif - -#ifdef CONFIG_TWL4030_POWER -#define twl_has_power() true -#else -#define twl_has_power() false -#endif - -#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE) -#define twl_has_rtc() true -#else -#define twl_has_rtc() false -#endif - -#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\ - defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE) -#define twl_has_usb() true -#else -#define twl_has_usb() false -#endif - -#if defined(CONFIG_TWL4030_WATCHDOG) || \ - defined(CONFIG_TWL4030_WATCHDOG_MODULE) -#define twl_has_watchdog() true -#else -#define twl_has_watchdog() false -#endif - -#if defined(CONFIG_MFD_TWL4030_AUDIO) || \ - defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) -#define twl_has_codec() true -#else -#define twl_has_codec() false -#endif - -#if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) -#define twl_has_bci() true -#else -#define twl_has_bci() false -#endif - /* Triton Core internal information (BEGIN) */ /* Last - for index max*/ @@ -134,13 +70,6 @@ #define TWL_NUM_SLAVES 4 -#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ - || defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE) -#define twl_has_pwrbutton() true -#else -#define twl_has_pwrbutton() false -#endif - #define SUB_CHIP_ID0 0 #define SUB_CHIP_ID1 1 #define SUB_CHIP_ID2 2 @@ -552,6 +481,38 @@ int twl_get_version(void) } EXPORT_SYMBOL_GPL(twl_get_version); +/** + * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. + * + * Api to get the TWL HFCLK rate based on BOOT_CFG register. + */ +int twl_get_hfclk_rate(void) +{ + u8 ctrl; + int rate; + + twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); + + switch (ctrl & 0x3) { + case HFCLK_FREQ_19p2_MHZ: + rate = 19200000; + break; + case HFCLK_FREQ_26_MHZ: + rate = 26000000; + break; + case HFCLK_FREQ_38p4_MHZ: + rate = 38400000; + break; + default: + pr_err("TWL4030: HFCLK is not configured\n"); + rate = -EINVAL; + break; + } + + return rate; +} +EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); + static struct device * add_numbered_child(unsigned chip, const char *name, int num, void *pdata, unsigned pdata_len, @@ -669,7 +630,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, struct device *child; unsigned sub_chip_id; - if (twl_has_gpio() && pdata->gpio) { + if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { child = add_child(SUB_CHIP_ID1, "twl4030_gpio", pdata->gpio, sizeof(*pdata->gpio), false, irq_base + GPIO_INTR_OFFSET, 0); @@ -677,7 +638,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_keypad() && pdata->keypad) { + if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { child = add_child(SUB_CHIP_ID2, "twl4030_keypad", pdata->keypad, sizeof(*pdata->keypad), true, irq_base + KEYPAD_INTR_OFFSET, 0); @@ -685,7 +646,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_madc() && pdata->madc) { + if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc) { child = add_child(2, "twl4030_madc", pdata->madc, sizeof(*pdata->madc), true, irq_base + MADC_INTR_OFFSET, 0); @@ -693,7 +654,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_rtc()) { + if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { /* * REVISIT platform_data here currently might expose the * "msecure" line ... but for now we just expect board @@ -709,7 +670,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_usb() && pdata->usb && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { + child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, + false, 0, 0); + if (IS_ERR(child)) + return PTR_ERR(child); + } + + if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && + twl_class_is_4030()) { static struct regulator_consumer_supply usb1v5 = { .supply = "usb1v5", @@ -723,7 +692,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, }; /* First add the regulators so that they can be used by transceiver */ - if (twl_has_regulator()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { /* this is a template that gets copied */ struct regulator_init_data usb_fixed = { .constraints.valid_modes_mask = @@ -765,18 +734,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); /* we need to connect regulators to this transceiver */ - if (twl_has_regulator() && child) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { usb1v5.dev_name = dev_name(child); usb1v8.dev_name = dev_name(child); usb3v1[0].dev_name = dev_name(child); } } - if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { + if (IS_ENABLED(CONFIG_TWL6030_USB) && pdata->usb && + twl_class_is_6030()) { static struct regulator_consumer_supply usb3v3; int regulator; - if (twl_has_regulator()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { /* this is a template that gets copied */ struct regulator_init_data usb_fixed = { .constraints.valid_modes_mask = @@ -813,9 +783,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, if (IS_ERR(child)) return PTR_ERR(child); /* we need to connect regulators to this transceiver */ - if (twl_has_regulator() && child) + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) usb3v3.dev_name = dev_name(child); - } else if (twl_has_regulator() && twl_class_is_6030()) { + } else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && + twl_class_is_6030()) { if (features & TWL6025_SUBCLASS) child = add_regulator(TWL6025_REG_LDOUSB, pdata->ldousb, features); @@ -827,20 +798,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_watchdog() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_pwrbutton() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { child = add_child(1, "twl4030_pwrbutton", NULL, 0, true, irq_base + 8 + 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_codec() && pdata->audio && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && + twl_class_is_4030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; child = add_child(sub_chip_id, "twl4030-audio", pdata->audio, sizeof(*pdata->audio), @@ -850,7 +822,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl4030 regulators */ - if (twl_has_regulator() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, features); if (IS_ERR(child)) @@ -905,7 +877,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* maybe add LDOs that are omitted on cost-reduced parts */ - if (twl_has_regulator() && !(features & TPS_SUBSET) + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) && twl_class_is_4030()) { child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, features); @@ -939,7 +911,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl6030 regulators */ - if (twl_has_regulator() && twl_class_is_6030() && + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && !(features & TWL6025_SUBCLASS)) { child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, features); @@ -1013,7 +985,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* 6030 and 6025 share this regulator */ - if (twl_has_regulator() && twl_class_is_6030()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030()) { child = add_regulator(TWL6030_REG_VANA, pdata->vana, features); if (IS_ERR(child)) @@ -1021,7 +993,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl6025 regulators */ - if (twl_has_regulator() && twl_class_is_6030() && + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && (features & TWL6025_SUBCLASS)) { child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, features); @@ -1080,7 +1052,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } - if (twl_has_bci() && pdata->bci && + if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && !(features & (TPS_SUBSET | TWL5031))) { child = add_child(3, "twl4030_bci", pdata->bci, sizeof(*pdata->bci), false, @@ -1295,7 +1267,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* load power event scripts */ - if (twl_has_power() && pdata->power) + if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) twl4030_power_init(pdata->power); /* Maybe init the T2 Interrupt subsystem */ diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 77c9acb14583..5c11acf9e0fd 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -28,6 +28,8 @@ #include <linux/kernel.h> #include <linux/fs.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <linux/i2c/twl.h> #include <linux/mfd/core.h> #include <linux/mfd/twl4030-audio.h> @@ -156,47 +158,70 @@ unsigned int twl4030_audio_get_mclk(void) } EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); +static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata, + struct device_node *node) +{ + if (pdata && pdata->codec) + return true; + + if (of_find_node_by_name(node, "codec")) + return true; + + return false; +} + +static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata, + struct device_node *node) +{ + int vibra; + + if (pdata && pdata->vibra) + return true; + + if (!of_property_read_u32(node, "ti,enable-vibra", &vibra) && vibra) + return true; + + return false; +} + static int __devinit twl4030_audio_probe(struct platform_device *pdev) { struct twl4030_audio *audio; struct twl4030_audio_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; struct mfd_cell *cell = NULL; int ret, childs = 0; u8 val; - if (!pdata) { + if (!pdata && !node) { dev_err(&pdev->dev, "Platform data is missing\n"); return -EINVAL; } + audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio), + GFP_KERNEL); + if (!audio) + return -ENOMEM; + + mutex_init(&audio->mutex); + audio->audio_mclk = twl_get_hfclk_rate(); + /* Configure APLL_INFREQ and disable APLL if enabled */ - val = 0; - switch (pdata->audio_mclk) { + switch (audio->audio_mclk) { case 19200000: - val |= TWL4030_APLL_INFREQ_19200KHZ; + val = TWL4030_APLL_INFREQ_19200KHZ; break; case 26000000: - val |= TWL4030_APLL_INFREQ_26000KHZ; + val = TWL4030_APLL_INFREQ_26000KHZ; break; case 38400000: - val |= TWL4030_APLL_INFREQ_38400KHZ; + val = TWL4030_APLL_INFREQ_38400KHZ; break; default: dev_err(&pdev->dev, "Invalid audio_mclk\n"); return -EINVAL; } - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - val, TWL4030_REG_APLL_CTL); - - audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL); - if (!audio) - return -ENOMEM; - - platform_set_drvdata(pdev, audio); - - twl4030_audio_dev = pdev; - mutex_init(&audio->mutex); - audio->audio_mclk = pdata->audio_mclk; + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, val, TWL4030_REG_APLL_CTL); /* Codec power */ audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE; @@ -206,21 +231,28 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; - if (pdata->codec) { + if (twl4030_audio_has_codec(pdata, node)) { cell = &audio->cells[childs]; cell->name = "twl4030-codec"; - cell->platform_data = pdata->codec; - cell->pdata_size = sizeof(*pdata->codec); + if (pdata) { + cell->platform_data = pdata->codec; + cell->pdata_size = sizeof(*pdata->codec); + } childs++; } - if (pdata->vibra) { + if (twl4030_audio_has_vibra(pdata, node)) { cell = &audio->cells[childs]; cell->name = "twl4030-vibra"; - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); + if (pdata) { + cell->platform_data = pdata->vibra; + cell->pdata_size = sizeof(*pdata->vibra); + } childs++; } + platform_set_drvdata(pdev, audio); + twl4030_audio_dev = pdev; + if (childs) ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, childs, NULL, 0, NULL); @@ -229,39 +261,42 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) ret = -ENODEV; } - if (!ret) - return 0; + if (ret) { + platform_set_drvdata(pdev, NULL); + twl4030_audio_dev = NULL; + } - platform_set_drvdata(pdev, NULL); - kfree(audio); - twl4030_audio_dev = NULL; return ret; } static int __devexit twl4030_audio_remove(struct platform_device *pdev) { - struct twl4030_audio *audio = platform_get_drvdata(pdev); - mfd_remove_devices(&pdev->dev); platform_set_drvdata(pdev, NULL); - kfree(audio); twl4030_audio_dev = NULL; return 0; } -MODULE_ALIAS("platform:twl4030-audio"); +static const struct of_device_id twl4030_audio_of_match[] = { + {.compatible = "ti,twl4030-audio", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl4030_audio_of_match); static struct platform_driver twl4030_audio_driver = { - .probe = twl4030_audio_probe, - .remove = __devexit_p(twl4030_audio_remove), .driver = { .owner = THIS_MODULE, .name = "twl4030-audio", + .of_match_table = twl4030_audio_of_match, }, + .probe = twl4030_audio_probe, + .remove = __devexit_p(twl4030_audio_remove), }; module_platform_driver(twl4030_audio_driver); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); +MODULE_DESCRIPTION("TWL4030 audio block MFD driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:twl4030-audio"); diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 3dca5c195a20..3f2a1cf02fc0 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -584,7 +584,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, goto irq_init_err; ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, - NULL, twl6040_naudint_handler, 0, + NULL, twl6040_naudint_handler, IRQF_ONESHOT, "twl6040_irq_ready", twl6040); if (ret) { dev_err(twl6040->dev, "READY IRQ request failed: %d\n", @@ -631,6 +631,21 @@ static int __devinit twl6040_probe(struct i2c_client *client, children++; } + /* + * Enable the GPO driver in the following cases: + * DT booted kernel or legacy boot with valid gpo platform_data + */ + if (!pdata || (pdata && pdata->gpo)) { + cell = &twl6040->cells[children]; + cell->name = "twl6040-gpo"; + + if (pdata) { + cell->platform_data = pdata->gpo; + cell->pdata_size = sizeof(*pdata->gpo); + } + children++; + } + ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, NULL, 0, NULL); if (ret) diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index bd8782c8896b..adda6b10b90d 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -133,15 +133,109 @@ static const struct reg_default wm5110_reva_patch[] = { { 0x209, 0x002A }, }; +static const struct reg_default wm5110_revb_patch[] = { + { 0x80, 0x3 }, + { 0x36e, 0x0210 }, + { 0x370, 0x0210 }, + { 0x372, 0x0210 }, + { 0x374, 0x0210 }, + { 0x376, 0x0210 }, + { 0x378, 0x0210 }, + { 0x36d, 0x0028 }, + { 0x36f, 0x0028 }, + { 0x371, 0x0028 }, + { 0x373, 0x0028 }, + { 0x375, 0x0028 }, + { 0x377, 0x0028 }, + { 0x280, 0x2002 }, + { 0x44, 0x20 }, + { 0x45, 0x40 }, + { 0x46, 0x60 }, + { 0x47, 0x80 }, + { 0x48, 0xa0 }, + { 0x51, 0x13 }, + { 0x52, 0x33 }, + { 0x53, 0x53 }, + { 0x54, 0x73 }, + { 0x55, 0x93 }, + { 0x56, 0xb3 }, + { 0xc30, 0x3e3e }, + { 0xc31, 0x3e }, + { 0xc32, 0x3e3e }, + { 0xc33, 0x3e3e }, + { 0xc34, 0x3e3e }, + { 0xc35, 0x3e3e }, + { 0xc36, 0x3e3e }, + { 0xc37, 0x3e3e }, + { 0xc38, 0x3e3e }, + { 0xc39, 0x3e3e }, + { 0xc3a, 0x3e3e }, + { 0xc3b, 0x3e3e }, + { 0xc3c, 0x3e }, + { 0x201, 0x18a5 }, + { 0x202, 0x4100 }, + { 0x460, 0x0c40 }, + { 0x461, 0x8000 }, + { 0x462, 0x0c41 }, + { 0x463, 0x4820 }, + { 0x464, 0x0c41 }, + { 0x465, 0x4040 }, + { 0x466, 0x0841 }, + { 0x467, 0x3940 }, + { 0x468, 0x0841 }, + { 0x469, 0x2030 }, + { 0x46a, 0x0842 }, + { 0x46b, 0x1990 }, + { 0x46c, 0x08c2 }, + { 0x46d, 0x1450 }, + { 0x46e, 0x08c6 }, + { 0x46f, 0x1020 }, + { 0x470, 0x08c6 }, + { 0x471, 0x0cd0 }, + { 0x472, 0x08c6 }, + { 0x473, 0x0a30 }, + { 0x474, 0x0442 }, + { 0x475, 0x0660 }, + { 0x476, 0x0446 }, + { 0x477, 0x0510 }, + { 0x478, 0x04c6 }, + { 0x479, 0x0400 }, + { 0x47a, 0x04ce }, + { 0x47b, 0x0330 }, + { 0x47c, 0x05df }, + { 0x47d, 0x0001 }, + { 0x47e, 0x07ff }, + { 0x2db, 0x0a00 }, + { 0x2dd, 0x0023 }, + { 0x2df, 0x0102 }, + { 0x2ef, 0x924 }, + { 0x2f0, 0x924 }, + { 0x2f1, 0x924 }, + { 0x2f2, 0x924 }, + { 0x2f3, 0x924 }, + { 0x2f4, 0x924 }, + { 0x2eb, 0x60 }, + { 0x2ec, 0x60 }, + { 0x2ed, 0x60 }, + { 0x4f2, 0x33e }, + { 0x458, 0x0000 }, + { 0x15a, 0x0003 }, + { 0x80, 0x0 }, +}; + /* We use a function so we can use ARRAY_SIZE() */ int wm5110_patch(struct arizona *arizona) { switch (arizona->rev) { case 0: - case 1: return regmap_register_patch(arizona->regmap, wm5110_reva_patch, ARRAY_SIZE(wm5110_reva_patch)); + case 1: + return regmap_register_patch(arizona->regmap, + wm5110_revb_patch, + ARRAY_SIZE(wm5110_revb_patch)); + default: return 0; } diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 301731035940..521340a708d3 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -614,18 +614,11 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, } EXPORT_SYMBOL_GPL(wm831x_set_bits); -static struct resource wm831x_io_parent = { - .start = 0, - .end = 0xffffffff, - .flags = IORESOURCE_IO, -}; - static struct resource wm831x_dcdc1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC1_CONTROL_1, .end = WM831X_DC1_DVS_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -644,10 +637,9 @@ static struct resource wm831x_dcdc1_resources[] = { static struct resource wm831x_dcdc2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC2_CONTROL_1, .end = WM831X_DC2_DVS_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -665,10 +657,9 @@ static struct resource wm831x_dcdc2_resources[] = { static struct resource wm831x_dcdc3_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC3_CONTROL_1, .end = WM831X_DC3_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -680,10 +671,9 @@ static struct resource wm831x_dcdc3_resources[] = { static struct resource wm831x_dcdc4_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC4_CONTROL, .end = WM831X_DC4_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -695,10 +685,9 @@ static struct resource wm831x_dcdc4_resources[] = { static struct resource wm8320_dcdc4_buck_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC4_CONTROL, .end = WM832X_DC4_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -718,10 +707,9 @@ static struct resource wm831x_gpio_resources[] = { static struct resource wm831x_isink1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_CURRENT_SINK_1, .end = WM831X_CURRENT_SINK_1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .start = WM831X_IRQ_CS1, @@ -732,10 +720,9 @@ static struct resource wm831x_isink1_resources[] = { static struct resource wm831x_isink2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_CURRENT_SINK_2, .end = WM831X_CURRENT_SINK_2, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .start = WM831X_IRQ_CS2, @@ -746,10 +733,9 @@ static struct resource wm831x_isink2_resources[] = { static struct resource wm831x_ldo1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO1_CONTROL, .end = WM831X_LDO1_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -761,10 +747,9 @@ static struct resource wm831x_ldo1_resources[] = { static struct resource wm831x_ldo2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO2_CONTROL, .end = WM831X_LDO2_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -776,10 +761,9 @@ static struct resource wm831x_ldo2_resources[] = { static struct resource wm831x_ldo3_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO3_CONTROL, .end = WM831X_LDO3_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -791,10 +775,9 @@ static struct resource wm831x_ldo3_resources[] = { static struct resource wm831x_ldo4_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO4_CONTROL, .end = WM831X_LDO4_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -806,10 +789,9 @@ static struct resource wm831x_ldo4_resources[] = { static struct resource wm831x_ldo5_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO5_CONTROL, .end = WM831X_LDO5_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -821,10 +803,9 @@ static struct resource wm831x_ldo5_resources[] = { static struct resource wm831x_ldo6_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO6_CONTROL, .end = WM831X_LDO6_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -836,10 +817,9 @@ static struct resource wm831x_ldo6_resources[] = { static struct resource wm831x_ldo7_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO7_CONTROL, .end = WM831X_LDO7_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -851,10 +831,9 @@ static struct resource wm831x_ldo7_resources[] = { static struct resource wm831x_ldo8_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO8_CONTROL, .end = WM831X_LDO8_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -866,10 +845,9 @@ static struct resource wm831x_ldo8_resources[] = { static struct resource wm831x_ldo9_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO9_CONTROL, .end = WM831X_LDO9_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -881,10 +859,9 @@ static struct resource wm831x_ldo9_resources[] = { static struct resource wm831x_ldo10_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO10_CONTROL, .end = WM831X_LDO10_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -896,10 +873,9 @@ static struct resource wm831x_ldo10_resources[] = { static struct resource wm831x_ldo11_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO11_ON_CONTROL, .end = WM831X_LDO11_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; @@ -998,19 +974,17 @@ static struct resource wm831x_rtc_resources[] = { static struct resource wm831x_status1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_STATUS_LED_1, .end = WM831X_STATUS_LED_1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; static struct resource wm831x_status2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_STATUS_LED_2, .end = WM831X_STATUS_LED_2, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 2febf88cfce8..8fefc961ec06 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -374,23 +374,23 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) } #endif -static const __devinitdata struct reg_default wm8994_revc_patch[] = { +static const __devinitconst struct reg_default wm8994_revc_patch[] = { { 0x102, 0x3 }, { 0x56, 0x3 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const __devinitdata struct reg_default wm8958_reva_patch[] = { +static const __devinitconst struct reg_default wm8958_reva_patch[] = { { 0x102, 0x3 }, { 0xcb, 0x81 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const __devinitdata struct reg_default wm1811_reva_patch[] = { +static const __devinitconst struct reg_default wm1811_reva_patch[] = { { 0x102, 0x3 }, - { 0x56, 0x7 }, + { 0x56, 0xc07 }, { 0x5d, 0x7e }, { 0x5e, 0x0 }, { 0x102, 0x0 }, diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c index 52e9e2944940..2fbce9c5950b 100644 --- a/drivers/mfd/wm8994-regmap.c +++ b/drivers/mfd/wm8994-regmap.c @@ -1136,7 +1136,7 @@ static bool wm1811_volatile_register(struct device *dev, unsigned int reg) switch (reg) { case WM8994_GPIO_6: - if (wm8994->revision > 1) + if (wm8994->cust_id > 1 || wm8994->revision > 1) return true; else return false; diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 504da715a41a..9722d43d6140 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -653,7 +653,7 @@ static const struct sdhci_pci_fixes sdhci_via = { .probe = via_probe, }; -static const struct pci_device_id pci_ids[] __devinitdata = { +static const struct pci_device_id pci_ids[] __devinitconst = { { .vendor = PCI_VENDOR_ID_RICOH, .device = PCI_DEVICE_ID_RICOH_R5C822, diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 9602c1b7e27e..01e2f2e87d8c 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -31,6 +31,7 @@ #include <linux/mtd/nand_ecc.h> #include <asm/fsl_ifc.h> +#define FSL_IFC_V1_1_0 0x01010000 #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ #define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait @@ -773,13 +774,62 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd) return 0; } +static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) +{ + struct fsl_ifc_ctrl *ctrl = priv->ctrl; + struct fsl_ifc_regs __iomem *ifc = ctrl->regs; + uint32_t csor = 0, csor_8k = 0, csor_ext = 0; + uint32_t cs = priv->bank; + + /* Save CSOR and CSOR_ext */ + csor = in_be32(&ifc->csor_cs[cs].csor); + csor_ext = in_be32(&ifc->csor_cs[cs].csor_ext); + + /* chage PageSize 8K and SpareSize 1K*/ + csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; + out_be32(&ifc->csor_cs[cs].csor, csor_8k); + out_be32(&ifc->csor_cs[cs].csor_ext, 0x0000400); + + /* READID */ + out_be32(&ifc->ifc_nand.nand_fir0, + (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); + out_be32(&ifc->ifc_nand.nand_fcr0, + NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); + out_be32(&ifc->ifc_nand.row3, 0x0); + + out_be32(&ifc->ifc_nand.nand_fbcr, 0x0); + + /* Program ROW0/COL0 */ + out_be32(&ifc->ifc_nand.row0, 0x0); + out_be32(&ifc->ifc_nand.col0, 0x0); + + /* set the chip select for NAND Transaction */ + out_be32(&ifc->ifc_nand.nand_csel, cs << IFC_NAND_CSEL_SHIFT); + + /* start read seq */ + out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); + + /* wait for command complete flag or timeout */ + wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, + IFC_TIMEOUT_MSECS * HZ/1000); + + if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) + printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); + + /* Restore CSOR and CSOR_ext */ + out_be32(&ifc->csor_cs[cs].csor, csor); + out_be32(&ifc->csor_cs[cs].csor_ext, csor_ext); +} + static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) { struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_regs __iomem *ifc = ctrl->regs; struct nand_chip *chip = &priv->chip; struct nand_ecclayout *layout; - u32 csor; + u32 csor, ver; /* Fill in fsl_ifc_mtd structure */ priv->mtd.priv = chip; @@ -874,6 +924,10 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) chip->ecc.mode = NAND_ECC_SOFT; } + ver = in_be32(&ifc->ifc_rev); + if (ver == FSL_IFC_V1_1_0) + fsl_ifc_sram_init(priv); + return 0; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 7858c58df4a3..b721902bb6b4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4826,6 +4826,7 @@ static int bond_check_params(struct bond_params *params) static struct lock_class_key bonding_netdev_xmit_lock_key; static struct lock_class_key bonding_netdev_addr_lock_key; +static struct lock_class_key bonding_tx_busylock_key; static void bond_set_lockdep_class_one(struct net_device *dev, struct netdev_queue *txq, @@ -4840,6 +4841,7 @@ static void bond_set_lockdep_class(struct net_device *dev) lockdep_set_class(&dev->addr_list_lock, &bonding_netdev_addr_lock_key); netdev_for_each_tx_queue(dev, bond_set_lockdep_class_one, NULL); + dev->qdisc_tx_busylock = &bonding_tx_busylock_key; } /* diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index c975999bb055..799c354083c4 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -247,7 +247,7 @@ static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev, } #endif /* CONFIG_PPC_MPC512x */ -static struct of_device_id mpc5xxx_can_table[]; +static const struct of_device_id mpc5xxx_can_table[]; static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) { const struct of_device_id *match; @@ -380,17 +380,17 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev) } #endif -static const struct mpc5xxx_can_data __devinitdata mpc5200_can_data = { +static const struct mpc5xxx_can_data __devinitconst mpc5200_can_data = { .type = MSCAN_TYPE_MPC5200, .get_clock = mpc52xx_can_get_clock, }; -static const struct mpc5xxx_can_data __devinitdata mpc5121_can_data = { +static const struct mpc5xxx_can_data __devinitconst mpc5121_can_data = { .type = MSCAN_TYPE_MPC5121, .get_clock = mpc512x_can_get_clock, }; -static struct of_device_id __devinitdata mpc5xxx_can_table[] = { +static const struct of_device_id __devinitconst mpc5xxx_can_table[] = { { .compatible = "fsl,mpc5200-mscan", .data = &mpc5200_can_data, }, /* Note that only MPC5121 Rev. 2 (and later) is supported */ { .compatible = "fsl,mpc5121-mscan", .data = &mpc5121_can_data, }, diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index f0a12962f7b6..f5b82aeb2540 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -583,12 +583,14 @@ static int __devinit peak_pci_probe(struct pci_dev *pdev, cfg_base = pci_iomap(pdev, 0, PEAK_PCI_CFG_SIZE); if (!cfg_base) { dev_err(&pdev->dev, "failed to map PCI resource #0\n"); + err = -ENOMEM; goto failure_release_regions; } reg_base = pci_iomap(pdev, 1, PEAK_PCI_CHAN_SIZE * channels); if (!reg_base) { dev_err(&pdev->dev, "failed to map PCI resource #1\n"); + err = -ENOMEM; goto failure_unmap_cfg_base; } diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c index ec6bd9d1b2af..272a85f32b14 100644 --- a/drivers/net/can/sja1000/peak_pcmcia.c +++ b/drivers/net/can/sja1000/peak_pcmcia.c @@ -686,8 +686,10 @@ static int __devinit pcan_probe(struct pcmcia_device *pdev) /* detect available channels */ pcan_add_channels(card); - if (!card->chan_count) + if (!card->chan_count) { + err = -ENOMEM; goto probe_err_4; + } /* init the timer which controls the leds */ init_timer(&card->led_timer); diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 034c16b60e96..adc3708d8829 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -56,7 +56,7 @@ #include <linux/kernel.h> #include <linux/can.h> -static __initdata const char banner[] = +static __initconst const char banner[] = KERN_INFO "slcan: serial line CAN interface driver\n"; MODULE_ALIAS_LDISC(N_SLCAN); diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 4f93c0be0053..0a2a5ee79a17 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -49,7 +49,7 @@ #include <linux/slab.h> #include <net/rtnetlink.h> -static __initdata const char banner[] = +static __initconst const char banner[] = KERN_INFO "vcan: Virtual CAN interface driver\n"; MODULE_DESCRIPTION("virtual CAN interface"); diff --git a/drivers/net/ethernet/8390/ne3210.c b/drivers/net/ethernet/8390/ne3210.c index a2f8b2b8e27c..e3f57427d5c5 100644 --- a/drivers/net/ethernet/8390/ne3210.c +++ b/drivers/net/ethernet/8390/ne3210.c @@ -81,7 +81,7 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3}; static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0}; -static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"}; +static const char * const ifmap[] __initconst = {"UTP", "?", "BNC", "AUI"}; static int ifmap_val[] __initdata = { IF_PORT_10BASET, IF_PORT_UNKNOWN, diff --git a/drivers/net/ethernet/adaptec/starfire.c b/drivers/net/ethernet/adaptec/starfire.c index d920a529ba22..5b65992c2a0a 100644 --- a/drivers/net/ethernet/adaptec/starfire.c +++ b/drivers/net/ethernet/adaptec/starfire.c @@ -295,7 +295,7 @@ MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); static const struct chip_info { const char *name; int drv_flags; -} netdrv_tbl[] __devinitdata = { +} netdrv_tbl[] __devinitconst = { { "Adaptec Starfire 6915", CanHaveMII }, }; diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 55a2e3795055..d19f82f7597a 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -702,7 +702,7 @@ struct atl1c_platform_patch { u32 patch_flag; #define ATL1C_LINK_PATCH 0x1 }; -static const struct atl1c_platform_patch plats[] __devinitdata = { +static const struct atl1c_platform_patch plats[] __devinitconst = { {0x2060, 0xC1, 0x1019, 0x8152, 0x1}, {0x2060, 0xC1, 0x1019, 0x2060, 0x1}, {0x2060, 0xC1, 0x1019, 0xE000, 0x1}, diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index 57d64b80fd72..623dd8635c46 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -2845,7 +2845,7 @@ static void atl2_force_ps(struct atl2_hw *hw) */ #define ATL2_PARAM(X, desc) \ - static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ + static const int __devinitconst X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ MODULE_PARM_DESC(X, desc); #else diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 30f04a389227..24220992413f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3523,15 +3523,18 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) } else #endif if (!bp->rx_ring_size) { - u32 cfg = SHMEM_RD(bp, - dev_info.port_hw_config[BP_PORT(bp)].default_cfg); - rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp); - /* Dercease ring size for 1G functions */ - if ((cfg & PORT_HW_CFG_NET_SERDES_IF_MASK) == - PORT_HW_CFG_NET_SERDES_IF_SGMII) - rx_ring_size /= 10; + if (CHIP_IS_E3(bp)) { + u32 cfg = SHMEM_RD(bp, + dev_info.port_hw_config[BP_PORT(bp)]. + default_cfg); + + /* Decrease ring size for 1G functions */ + if ((cfg & PORT_HW_CFG_NET_SERDES_IF_MASK) == + PORT_HW_CFG_NET_SERDES_IF_SGMII) + rx_ring_size /= 10; + } /* allocate at least number of buffers required by FW */ rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA : diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index f7ed122f4071..d5648fc666bd 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -3052,9 +3052,8 @@ static void bnx2x_drv_info_ether_stat(struct bnx2x *bp) struct eth_stats_info *ether_stat = &bp->slowpath->drv_info_to_mcp.ether_stat; - /* leave last char as NULL */ - memcpy(ether_stat->version, DRV_MODULE_VERSION, - ETH_STAT_INFO_VERSION_LEN - 1); + strlcpy(ether_stat->version, DRV_MODULE_VERSION, + ETH_STAT_INFO_VERSION_LEN); bp->sp_objs[0].mac_obj.get_n_elements(bp, &bp->sp_objs[0].mac_obj, DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED, diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 46280ba4c5d4..a8800ac10df9 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -782,7 +782,8 @@ static int tg3_ape_wait_for_event(struct tg3 *tp, u32 timeout_us) return i == timeout_us / 10; } -int tg3_ape_scratchpad_read(struct tg3 *tp, u32 *data, u32 base_off, u32 len) +static int tg3_ape_scratchpad_read(struct tg3 *tp, u32 *data, u32 base_off, + u32 len) { int err; u32 i, bufoff, msgoff, maxlen, apedata; @@ -7763,7 +7764,7 @@ static int tg3_alloc_consistent(struct tg3 *tp) sblk = tnapi->hw_status; if (tg3_flag(tp, ENABLE_RSS)) { - u16 *prodptr = 0; + u16 *prodptr = NULL; /* * When RSS is enabled, the status block format changes @@ -8103,11 +8104,11 @@ static int tg3_chip_reset(struct tg3 *tp) u16 val16; if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { - int i; + int j; u32 cfg_val; /* Wait for link training to complete. */ - for (i = 0; i < 5000; i++) + for (j = 0; j < 5000; j++) udelay(100); pci_read_config_dword(tp->pdev, 0xc4, &cfg_val); @@ -10206,7 +10207,7 @@ static u32 tg3_irq_count(struct tg3 *tp) static bool tg3_enable_msix(struct tg3 *tp) { int i, rc; - struct msix_entry msix_ent[tp->irq_max]; + struct msix_entry msix_ent[TG3_IRQ_MAX_VECS]; tp->txq_cnt = tp->txq_req; tp->rxq_cnt = tp->rxq_req; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 745a1f53361f..31752b24434e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -43,6 +43,7 @@ #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/timer.h> +#include <linux/vmalloc.h> #include <asm/io.h> #include "cxgb4_uld.h" #include "t4_hw.h" diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 35b81d8b59e9..137a24438d9c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -408,7 +408,8 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, __be32 *buf, int dir) { u32 pos, start, end, offset, memoffset; - int ret; + int ret = 0; + __be32 *data; /* * Argument sanity checks ... @@ -416,6 +417,10 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, if ((addr & 0x3) || (len & 0x3)) return -EINVAL; + data = vmalloc(MEMWIN0_APERTURE/sizeof(__be32)); + if (!data) + return -ENOMEM; + /* * Offset into the region of memory which is being accessed * MEM_EDC0 = 0 @@ -438,7 +443,6 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, offset = (addr - start)/sizeof(__be32); for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) { - __be32 data[MEMWIN0_APERTURE/sizeof(__be32)]; /* * If we're writing, copy the data from the caller's memory @@ -452,7 +456,7 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, if (offset || len < MEMWIN0_APERTURE) { ret = t4_mem_win_rw(adap, pos, data, 1); if (ret) - return ret; + break; } while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) && len > 0) { @@ -466,7 +470,7 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, */ ret = t4_mem_win_rw(adap, pos, data, dir); if (ret) - return ret; + break; /* * If we're reading, copy the data into the caller's memory @@ -480,7 +484,8 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len, } } - return 0; + vfree(data); + return ret; } int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len, @@ -519,16 +524,21 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) u32 cclk_param, cclk_val; int i, ret; int ec, sn; - u8 vpd[VPD_LEN], csum; + u8 *vpd, csum; unsigned int vpdr_len, kw_offset, id_len; - ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd); + vpd = vmalloc(VPD_LEN); + if (!vpd) + return -ENOMEM; + + ret = pci_read_vpd(adapter->pdev, VPD_BASE, VPD_LEN, vpd); if (ret < 0) - return ret; + goto out; if (vpd[0] != PCI_VPD_LRDT_ID_STRING) { dev_err(adapter->pdev_dev, "missing VPD ID string\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } id_len = pci_vpd_lrdt_size(vpd); @@ -538,21 +548,24 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) i = pci_vpd_find_tag(vpd, 0, VPD_LEN, PCI_VPD_LRDT_RO_DATA); if (i < 0) { dev_err(adapter->pdev_dev, "missing VPD-R section\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } vpdr_len = pci_vpd_lrdt_size(&vpd[i]); kw_offset = i + PCI_VPD_LRDT_TAG_SIZE; if (vpdr_len + kw_offset > VPD_LEN) { dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len); - return -EINVAL; + ret = -EINVAL; + goto out; } #define FIND_VPD_KW(var, name) do { \ var = pci_vpd_find_info_keyword(vpd, kw_offset, vpdr_len, name); \ if (var < 0) { \ dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \ - return -EINVAL; \ + ret = -EINVAL; \ + goto out; \ } \ var += PCI_VPD_INFO_FLD_HDR_SIZE; \ } while (0) @@ -564,7 +577,8 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) if (csum) { dev_err(adapter->pdev_dev, "corrupted VPD EEPROM, actual csum %u\n", csum); - return -EINVAL; + ret = -EINVAL; + goto out; } FIND_VPD_KW(ec, "EC"); @@ -587,6 +601,9 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK)); ret = t4_query_params(adapter, adapter->mbox, 0, 0, 1, &cclk_param, &cclk_val); + +out: + vfree(vpd); if (ret) return ret; p->cclk = cclk_val; diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c index 61cc09342865..77335853ac36 100644 --- a/drivers/net/ethernet/dec/tulip/de2104x.c +++ b/drivers/net/ethernet/dec/tulip/de2104x.c @@ -661,9 +661,6 @@ static netdev_tx_t de_start_xmit (struct sk_buff *skb, new frame, not around filling de->setup_frame. This is non-deterministic when re-entered but still correct. */ -#undef set_bit_le -#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0) - static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) { struct de_private *de = netdev_priv(dev); @@ -673,12 +670,12 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) u16 *eaddrs; memset(hash_table, 0, sizeof(hash_table)); - set_bit_le(255, hash_table); /* Broadcast entry */ + __set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ netdev_for_each_mc_addr(ha, dev) { int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff; - set_bit_le(index, hash_table); + __set_bit_le(index, hash_table); } for (i = 0; i < 32; i++) { diff --git a/drivers/net/ethernet/dec/tulip/eeprom.c b/drivers/net/ethernet/dec/tulip/eeprom.c index ed7d1dcd9566..44f7e8e82d85 100644 --- a/drivers/net/ethernet/dec/tulip/eeprom.c +++ b/drivers/net/ethernet/dec/tulip/eeprom.c @@ -79,7 +79,7 @@ static struct eeprom_fixup eeprom_fixups[] __devinitdata = { {NULL}}; -static const char *block_name[] __devinitdata = { +static const char *const block_name[] __devinitconst = { "21140 non-MII", "21140 MII PHY", "21142 Serial PHY", diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index c4f37aca2269..885700a19978 100644 --- a/drivers/net/ethernet/dec/tulip/tulip_core.c +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c @@ -1010,9 +1010,6 @@ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) new frame, not around filling tp->setup_frame. This is non-deterministic when re-entered but still correct. */ -#undef set_bit_le -#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0) - static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) { struct tulip_private *tp = netdev_priv(dev); @@ -1022,12 +1019,12 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) u16 *eaddrs; memset(hash_table, 0, sizeof(hash_table)); - set_bit_le(255, hash_table); /* Broadcast entry */ + __set_bit_le(255, hash_table); /* Broadcast entry */ /* This should work on big-endian machines as well. */ netdev_for_each_mc_addr(ha, dev) { int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff; - set_bit_le(index, hash_table); + __set_bit_le(index, hash_table); } for (i = 0; i < 32; i++) { *setup_frm++ = hash_table[i]; diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index 4d1ffca83c82..7c1ec4d7920b 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -236,7 +236,7 @@ struct pci_id_info { int drv_flags; /* Driver use, intended as capability flags. */ }; -static const struct pci_id_info pci_id_tbl[] __devinitdata = { +static const struct pci_id_info pci_id_tbl[] __devinitconst = { { /* Sometime a Level-One switch card. */ "Winbond W89c840", CanHaveMII | HasBrokenTx | FDXOnNoMII}, { "Winbond W89c840", CanHaveMII | HasBrokenTx}, diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index d7bb52a7bda1..3b83588e51f6 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -218,7 +218,7 @@ enum { struct pci_id_info { const char *name; }; -static const struct pci_id_info pci_id_tbl[] __devinitdata = { +static const struct pci_id_info pci_id_tbl[] __devinitconst = { {"D-Link DFE-550TX FAST Ethernet Adapter"}, {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, {"D-Link DFE-580TX 4 port Server Adapter"}, diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 9d71c9cc300b..0e4a0ac86aa8 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -150,7 +150,7 @@ struct chip_info { int flags; }; -static const struct chip_info skel_netdrv_tbl[] __devinitdata = { +static const struct chip_info skel_netdrv_tbl[] __devinitconst = { { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR }, { "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR }, { "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR }, diff --git a/drivers/net/ethernet/ibm/ehea/ehea.h b/drivers/net/ethernet/ibm/ehea/ehea.h index b8e46cc31e53..6be7b9839f35 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea.h +++ b/drivers/net/ethernet/ibm/ehea/ehea.h @@ -35,7 +35,6 @@ #include <linux/if_vlan.h> #include <asm/ibmebus.h> -#include <asm/abs_addr.h> #include <asm/io.h> #define DRV_NAME "ehea" diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.c b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c index 30f903332e92..d3a130ccdcc8 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.c @@ -141,7 +141,7 @@ u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, qp_category, /* R5 */ qp_handle, /* R6 */ sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ + __pa(cb_addr), /* R8 */ 0, 0); } @@ -415,7 +415,7 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat, (u64) cat, /* R5 */ qp_handle, /* R6 */ sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ + __pa(cb_addr), /* R8 */ 0, 0, 0, 0); /* R9-R12 */ *inv_attr_id = outs[0]; @@ -528,7 +528,7 @@ u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr) { u64 hret, cb_logaddr; - cb_logaddr = virt_to_abs(cb_addr); + cb_logaddr = __pa(cb_addr); hret = ehea_plpar_hcall_norets(H_QUERY_HEA, adapter_handle, /* R4 */ @@ -545,7 +545,7 @@ u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num, void *cb_addr) { u64 port_info; - u64 cb_logaddr = virt_to_abs(cb_addr); + u64 cb_logaddr = __pa(cb_addr); u64 arr_index = 0; port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat) @@ -567,7 +567,7 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, unsigned long outs[PLPAR_HCALL9_BUFSIZE]; u64 port_info; u64 arr_index = 0; - u64 cb_logaddr = virt_to_abs(cb_addr); + u64 cb_logaddr = __pa(cb_addr); port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat) | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num); @@ -621,6 +621,6 @@ u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle, return ehea_plpar_hcall_norets(H_ERROR_DATA, adapter_handle, /* R4 */ ressource_handle, /* R5 */ - virt_to_abs(rblock), /* R6 */ + __pa(rblock), /* R6 */ 0, 0, 0, 0); /* R7-R12 */ } diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c index cb66f574dc97..27f881758d16 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c @@ -163,7 +163,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, goto out_kill_hwq; } - rpage = virt_to_abs(vpage); + rpage = __pa(vpage); hret = ehea_h_register_rpage(adapter->handle, 0, EHEA_CQ_REGISTER_ORIG, cq->fw_handle, rpage, 1); @@ -290,7 +290,7 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter, goto out_kill_hwq; } - rpage = virt_to_abs(vpage); + rpage = __pa(vpage); hret = ehea_h_register_rpage(adapter->handle, 0, EHEA_EQ_REGISTER_ORIG, @@ -395,7 +395,7 @@ static int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue, pr_err("hw_qpageit_get_inc failed\n"); goto out_kill_hwq; } - rpage = virt_to_abs(vpage); + rpage = __pa(vpage); hret = ehea_h_register_rpage(adapter->handle, 0, h_call_q_selector, qp->fw_handle, rpage, 1); @@ -790,7 +790,7 @@ u64 ehea_map_vaddr(void *caddr) if (!ehea_bmap) return EHEA_INVAL_ADDR; - index = virt_to_abs(caddr) >> SECTION_SIZE_BITS; + index = __pa(caddr) >> SECTION_SIZE_BITS; top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK; if (!ehea_bmap->top[top]) return EHEA_INVAL_ADDR; @@ -812,7 +812,7 @@ static inline void *ehea_calc_sectbase(int top, int dir, int idx) unsigned long ret = idx; ret |= dir << EHEA_DIR_INDEX_SHIFT; ret |= top << EHEA_TOP_INDEX_SHIFT; - return abs_to_virt(ret << SECTION_SIZE_BITS); + return __va(ret << SECTION_SIZE_BITS); } static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt, @@ -822,7 +822,7 @@ static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt, void *pg; u64 j, m, hret; unsigned long k = 0; - u64 pt_abs = virt_to_abs(pt); + u64 pt_abs = __pa(pt); void *sectbase = ehea_calc_sectbase(top, dir, idx); @@ -830,7 +830,7 @@ static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt, for (m = 0; m < EHEA_MAX_RPAGE; m++) { pg = sectbase + ((k++) * EHEA_PAGESIZE); - pt[m] = virt_to_abs(pg); + pt[m] = __pa(pg); } hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0, 0, pt_abs, EHEA_MAX_RPAGE); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 18bf08c9d7a4..1077cb2b38db 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1099,7 +1099,7 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - udelay(10); + usleep_range(1000, 2000); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) { hw_dbg(hw, "Flow Director Signature poll time exceeded!\n"); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 90e41db3cb69..dbf37e4a45fd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -70,6 +70,7 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) switch (hw->device_id) { case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540T1: return 0; case IXGBE_DEV_ID_82599_T3_LOM: return 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 4104ea25d818..56b20d17d0e4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2690,10 +2690,7 @@ static int ixgbe_get_ts_info(struct net_device *dev, (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_SOME); + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); break; #endif /* CONFIG_IXGBE_PTP */ default: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 868af6938219..fa3d552e1f4a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -114,6 +114,7 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599EN_SFP), board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF_QP), board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T1), board_X540 }, /* required last entry */ {0, } }; @@ -2322,6 +2323,12 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter, bool queues, default: break; } + +#ifdef CONFIG_IXGBE_PTP + if (adapter->hw.mac.type == ixgbe_mac_X540) + mask |= IXGBE_EIMS_TIMESYNC; +#endif + if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) && !(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT)) mask |= IXGBE_EIMS_FLOW_DIR; @@ -2385,8 +2392,10 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data) } ixgbe_check_fan_failure(adapter, eicr); + #ifdef CONFIG_IXGBE_PTP - ixgbe_ptp_check_pps_event(adapter, eicr); + if (unlikely(eicr & IXGBE_EICR_TIMESYNC)) + ixgbe_ptp_check_pps_event(adapter, eicr); #endif /* re-enable the original interrupt state, no lsc, no queues */ @@ -2580,7 +2589,8 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_fan_failure(adapter, eicr); #ifdef CONFIG_IXGBE_PTP - ixgbe_ptp_check_pps_event(adapter, eicr); + if (unlikely(eicr & IXGBE_EICR_TIMESYNC)) + ixgbe_ptp_check_pps_event(adapter, eicr); #endif /* would disable interrupts here but EIAM disabled it */ @@ -7045,6 +7055,7 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, is_wol_supported = 1; break; case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540T1: /* check eeprom to see if enabled wol */ if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) || ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) && diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 39881cb17a4b..d9291316ee9f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -106,6 +106,83 @@ static struct sock_filter ptp_filter[] = { }; /** + * ixgbe_ptp_setup_sdp + * @hw: the hardware private structure + * + * this function enables or disables the clock out feature on SDP0 for + * the X540 device. It will create a 1second periodic output that can + * be used as the PPS (via an interrupt). + * + * It calculates when the systime will be on an exact second, and then + * aligns the start of the PPS signal to that value. The shift is + * necessary because it can change based on the link speed. + */ +static void ixgbe_ptp_setup_sdp(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + int shift = adapter->cc.shift; + u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh, rem; + u64 ns = 0, clock_edge = 0; + + if ((adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED) && + (hw->mac.type == ixgbe_mac_X540)) { + + /* disable the pin first */ + IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0); + IXGBE_WRITE_FLUSH(hw); + + esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); + + /* + * enable the SDP0 pin as output, and connected to the + * native function for Timesync (ClockOut) + */ + esdp |= (IXGBE_ESDP_SDP0_DIR | + IXGBE_ESDP_SDP0_NATIVE); + + /* + * enable the Clock Out feature on SDP0, and allow + * interrupts to occur when the pin changes + */ + tsauxc = (IXGBE_TSAUXC_EN_CLK | + IXGBE_TSAUXC_SYNCLK | + IXGBE_TSAUXC_SDP0_INT); + + /* clock period (or pulse length) */ + clktiml = (u32)(NSECS_PER_SEC << shift); + clktimh = (u32)((NSECS_PER_SEC << shift) >> 32); + + /* + * Account for the cyclecounter wrap-around value by + * using the converted ns value of the current time to + * check for when the next aligned second would occur. + */ + clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML); + clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; + ns = timecounter_cyc2time(&adapter->tc, clock_edge); + + div_u64_rem(ns, NSECS_PER_SEC, &rem); + clock_edge += ((NSECS_PER_SEC - (u64)rem) << shift); + + /* specify the initial clock start time */ + trgttiml = (u32)clock_edge; + trgttimh = (u32)(clock_edge >> 32); + + IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml); + IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh); + IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml); + IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh); + + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); + IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc); + } else { + IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0); + } + + IXGBE_WRITE_FLUSH(hw); +} + +/** * ixgbe_ptp_read - read raw cycle counter (to be used by time counter) * @cc: the cyclecounter structure * @@ -198,6 +275,9 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) now); spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + ixgbe_ptp_setup_sdp(adapter); + return 0; } @@ -251,6 +331,7 @@ static int ixgbe_ptp_settime(struct ptp_clock_info *ptp, timecounter_init(&adapter->tc, &adapter->cc, ns); spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + ixgbe_ptp_setup_sdp(adapter); return 0; } @@ -281,8 +362,9 @@ static int ixgbe_ptp_enable(struct ptp_clock_info *ptp, if (on) adapter->flags2 |= IXGBE_FLAG2_PTP_PPS_ENABLED; else - adapter->flags2 &= - ~IXGBE_FLAG2_PTP_PPS_ENABLED; + adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED; + + ixgbe_ptp_setup_sdp(adapter); return 0; default: break; @@ -305,109 +387,15 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr) struct ixgbe_hw *hw = &adapter->hw; struct ptp_clock_event event; - event.type = PTP_CLOCK_PPS; - - /* Make sure ptp clock is valid, and PPS event enabled */ - if (!adapter->ptp_clock || - !(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED)) - return; - - if (unlikely(eicr & IXGBE_EICR_TIMESYNC)) { - switch (hw->mac.type) { - case ixgbe_mac_X540: - ptp_clock_event(adapter->ptp_clock, &event); - break; - default: - break; - } - } -} - -/** - * ixgbe_ptp_enable_sdp - * @hw: the hardware private structure - * @shift: the clock shift for calculating nanoseconds - * - * this function enables the clock out feature on the sdp0 for the - * X540 device. It will create a 1second periodic output that can be - * used as the PPS (via an interrupt). - * - * It calculates when the systime will be on an exact second, and then - * aligns the start of the PPS signal to that value. The shift is - * necessary because it can change based on the link speed. - */ -static void ixgbe_ptp_enable_sdp(struct ixgbe_hw *hw, int shift) -{ - u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh; - u64 clock_edge = 0; - u32 rem; - switch (hw->mac.type) { case ixgbe_mac_X540: - esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); - - /* - * enable the SDP0 pin as output, and connected to the native - * function for Timesync (ClockOut) - */ - esdp |= (IXGBE_ESDP_SDP0_DIR | - IXGBE_ESDP_SDP0_NATIVE); - - /* - * enable the Clock Out feature on SDP0, and allow interrupts - * to occur when the pin changes - */ - tsauxc = (IXGBE_TSAUXC_EN_CLK | - IXGBE_TSAUXC_SYNCLK | - IXGBE_TSAUXC_SDP0_INT); - - /* clock period (or pulse length) */ - clktiml = (u32)(NSECS_PER_SEC << shift); - clktimh = (u32)((NSECS_PER_SEC << shift) >> 32); - - clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML); - clock_edge |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; - - /* - * account for the fact that we can't do u64 division - * with remainder, by converting the clock values into - * nanoseconds first - */ - clock_edge >>= shift; - div_u64_rem(clock_edge, NSECS_PER_SEC, &rem); - clock_edge += (NSECS_PER_SEC - rem); - clock_edge <<= shift; - - /* specify the initial clock start time */ - trgttiml = (u32)clock_edge; - trgttimh = (u32)(clock_edge >> 32); - - IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml); - IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh); - IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml); - IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh); - - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); - IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc); - - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_TIMESYNC); + ptp_clock_event(adapter->ptp_clock, &event); break; default: break; } } -/** - * ixgbe_ptp_disable_sdp - * @hw: the private hardware structure - * - * this function disables the auxiliary SDP clock out feature - */ -static void ixgbe_ptp_disable_sdp(struct ixgbe_hw *hw) -{ - IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_TIMESYNC); - IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0); -} /** * ixgbe_ptp_overflow_check - delayed work to detect SYSTIME overflow @@ -822,9 +810,6 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) if (adapter->cycle_speed == cycle_speed && timinca) return; - /* disable the SDP clock out */ - ixgbe_ptp_disable_sdp(hw); - /** * Scale the NIC cycle counter by a large factor so that * relatively small corrections to the frequency can be added @@ -877,10 +862,6 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000); IXGBE_WRITE_FLUSH(hw); - /* now that the shift has been calculated and the systime - * registers reset, (re-)enable the Clock out feature*/ - ixgbe_ptp_enable_sdp(hw, shift); - /* store the new cycle speed */ adapter->cycle_speed = cycle_speed; @@ -901,6 +882,12 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) ktime_to_ns(ktime_get_real())); spin_unlock_irqrestore(&adapter->tmreg_lock, flags); + + /* + * Now that the shift has been calculated and the systime + * registers reset, (re-)enable the Clock out feature + */ + ixgbe_ptp_setup_sdp(adapter); } /** @@ -979,10 +966,11 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter) */ void ixgbe_ptp_stop(struct ixgbe_adapter *adapter) { - ixgbe_ptp_disable_sdp(&adapter->hw); - /* stop the overflow check task */ - adapter->flags2 &= ~IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED; + adapter->flags2 &= ~(IXGBE_FLAG2_OVERFLOW_CHECK_ENABLED | + IXGBE_FLAG2_PTP_PPS_ENABLED); + + ixgbe_ptp_setup_sdp(adapter); if (adapter->ptp_clock) { ptp_clock_unregister(adapter->ptp_clock); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 400f86a31174..0722f3368092 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -65,6 +65,7 @@ #define IXGBE_DEV_ID_82599_LS 0x154F #define IXGBE_DEV_ID_X540T 0x1528 #define IXGBE_DEV_ID_82599_SFP_SF_QP 0x154A +#define IXGBE_DEV_ID_X540T1 0x1560 /* VF Device IDs */ #define IXGBE_DEV_ID_82599_VF 0x10ED diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig index bce01641ee6b..97302419a377 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig +++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig @@ -26,7 +26,7 @@ if PCH_GBE config PCH_PTP bool "PCH PTP clock support" default n - depends on PTP_1588_CLOCK_PCH + select PTP_1588_CLOCK_PCH ---help--- Say Y here if you want to use Precision Time Protocol (PTP) in the driver. PTP is a method to precisely synchronize distributed clocks diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index b528e52a8ee1..2a0c9dc48eb3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -38,7 +38,7 @@ static inline void writeq(u64 val, void __iomem *addr) } #endif -static const struct crb_128M_2M_block_map +static struct crb_128M_2M_block_map crb_128M_2M_map[64] __cacheline_aligned_in_smp = { {{{0, 0, 0, 0} } }, /* 0: PCI */ {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 1d83565cc6af..3ed7add23c12 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -228,7 +228,7 @@ typedef enum { static const struct { const char *name; u32 hw_flags; -} board_info[] __devinitdata = { +} board_info[] __devinitconst = { { "RealTek RTL8139", RTL8139_CAPS }, { "RealTek RTL8129", RTL8129_CAPS }, }; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 96bd980e828d..4f86d0cd516a 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -2019,14 +2019,14 @@ static void efx_set_rx_mode(struct net_device *net_dev) netdev_for_each_mc_addr(ha, net_dev) { crc = ether_crc_le(ETH_ALEN, ha->addr); bit = crc & (EFX_MCAST_HASH_ENTRIES - 1); - set_bit_le(bit, mc_hash->byte); + __set_bit_le(bit, mc_hash); } /* Broadcast packets go through the multicast hash filter. * ether_crc_le() of the broadcast address is 0xbe2612ff * so we always add bit 0xff to the mask. */ - set_bit_le(0xff, mc_hash->byte); + __set_bit_le(0xff, mc_hash); } if (efx->port_enabled) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index c1a010cda89b..576a31091165 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1101,18 +1101,6 @@ static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue, return &rx_queue->buffer[index]; } -/* Set bit in a little-endian bitfield */ -static inline void set_bit_le(unsigned nr, unsigned char *addr) -{ - addr[nr / 8] |= (1 << (nr % 8)); -} - -/* Clear bit in a little-endian bitfield */ -static inline void clear_bit_le(unsigned nr, unsigned char *addr) -{ - addr[nr / 8] &= ~(1 << (nr % 8)); -} - /** * EFX_MAX_FRAME_LEN - calculate maximum frame length diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index cdff40b65729..aab7cacb2e34 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -472,9 +472,9 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) efx_reado(efx, ®, FR_AA_TX_CHKSM_CFG); if (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD) - clear_bit_le(tx_queue->queue, (void *)®); + __clear_bit_le(tx_queue->queue, ®); else - set_bit_le(tx_queue->queue, (void *)®); + __set_bit_le(tx_queue->queue, ®); efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); } diff --git a/drivers/net/ethernet/sis/sis190.c b/drivers/net/ethernet/sis/sis190.c index 4613591b43e7..d8166012b7d4 100644 --- a/drivers/net/ethernet/sis/sis190.c +++ b/drivers/net/ethernet/sis/sis190.c @@ -1618,7 +1618,7 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev, struct net_device *dev) { - static const u16 __devinitdata ids[] = { 0x0965, 0x0966, 0x0968 }; + static const u16 __devinitconst ids[] = { 0x0965, 0x0966, 0x0968 }; struct sis190_private *tp = netdev_priv(dev); struct pci_dev *isa_bridge; u8 reg, tmp8; diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index d15c888e9df8..49956730cd8d 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -863,6 +863,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) next_dma = desc_read(desc, hw_next); chan->head = desc_from_phys(pool, next_dma); + chan->count--; chan->stats.teardown_dequeue++; /* issue callback without locks held */ diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 64783a0d545a..1450e33fc250 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -811,9 +811,9 @@ static struct tty_ldisc_ops sp_ldisc = { /* Initialize 6pack control device -- register 6pack line discipline */ -static const char msg_banner[] __initdata = KERN_INFO \ +static const char msg_banner[] __initconst = KERN_INFO \ "AX.25: 6pack driver, " SIXPACK_VERSION "\n"; -static const char msg_regfail[] __initdata = KERN_ERR \ +static const char msg_regfail[] __initconst = KERN_ERR \ "6pack: can't register line discipline (err = %d)\n"; static int __init sixpack_init_driver(void) @@ -829,7 +829,7 @@ static int __init sixpack_init_driver(void) return status; } -static const char msg_unregfail[] __exitdata = KERN_ERR \ +static const char msg_unregfail[] = KERN_ERR \ "6pack: can't unregister line discipline (err = %d)\n"; static void __exit sixpack_exit_driver(void) diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 76d54774ba82..c2e5497397d5 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -87,7 +87,7 @@ #include <linux/bpqether.h> -static const char banner[] __initdata = KERN_INFO \ +static const char banner[] __initconst = KERN_INFO \ "AX.25: bpqether driver version 004\n"; static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 2c0894a92abd..8e01c457015b 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -997,9 +997,9 @@ static struct tty_ldisc_ops ax_ldisc = { .write_wakeup = mkiss_write_wakeup }; -static const char banner[] __initdata = KERN_INFO \ +static const char banner[] __initconst = KERN_INFO \ "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; -static const char msg_regfail[] __initdata = KERN_ERR \ +static const char msg_regfail[] __initconst = KERN_ERR \ "mkiss: can't register line discipline (err = %d)\n"; static int __init mkiss_init_driver(void) @@ -1015,7 +1015,7 @@ static int __init mkiss_init_driver(void) return status; } -static const char msg_unregfail[] __exitdata = KERN_ERR \ +static const char msg_unregfail[] = KERN_ERR \ "mkiss: can't unregister line discipline (err = %d)\n"; static void __exit mkiss_exit_driver(void) diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index efc6c97163a7..1b4a47bd32b7 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -182,7 +182,7 @@ #include "z8530.h" -static const char banner[] __initdata = KERN_INFO \ +static const char banner[] __initconst = KERN_INFO \ "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n"; static void t_dwait(unsigned long); diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 5a6412ecce73..c6645f1017af 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -76,7 +76,7 @@ /* --------------------------------------------------------------------- */ static const char yam_drvname[] = "yam"; -static const char yam_drvinfo[] __initdata = KERN_INFO \ +static const char yam_drvinfo[] __initconst = KERN_INFO \ "YAM driver version 0.8 by F1OAT/F6FBB\n"; /* --------------------------------------------------------------------- */ diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 91d25888a1b9..d8b9b1e8ee02 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -26,7 +26,7 @@ #include <linux/ethtool.h> #define DRV_NAME "rionet" -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3" #define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" #define DRV_DESC "Ethernet over RapidIO" @@ -47,8 +47,7 @@ MODULE_LICENSE("GPL"); #define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE #define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE - -static LIST_HEAD(rionet_peers); +#define RIONET_MAX_NETS 8 struct rionet_private { struct rio_mport *mport; @@ -69,16 +68,14 @@ struct rionet_peer { struct resource *res; }; -static int rionet_check = 0; -static int rionet_capable = 1; +struct rionet_net { + struct net_device *ndev; + struct list_head peers; + struct rio_dev **active; + int nact; /* number of active peers */ +}; -/* - * This is a fast lookup table for translating TX - * Ethernet packets into a destination RIO device. It - * could be made into a hash table to save memory depending - * on system trade-offs. - */ -static struct rio_dev **rionet_active; +static struct rionet_net nets[RIONET_MAX_NETS]; #define is_rionet_capable(src_ops, dst_ops) \ ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ @@ -175,6 +172,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct ethhdr *eth = (struct ethhdr *)skb->data; u16 destid; unsigned long flags; + int add_num = 1; local_irq_save(flags); if (!spin_trylock(&rnet->tx_lock)) { @@ -182,7 +180,10 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_LOCKED; } - if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) { + if (is_multicast_ether_addr(eth->h_dest)) + add_num = nets[rnet->mport->id].nact; + + if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { netif_stop_queue(ndev); spin_unlock_irqrestore(&rnet->tx_lock, flags); printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", @@ -191,15 +192,22 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) } if (is_multicast_ether_addr(eth->h_dest)) { + int count = 0; + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); i++) - if (rionet_active[i]) + if (nets[rnet->mport->id].active[i]) { rionet_queue_tx_msg(skb, ndev, - rionet_active[i]); + nets[rnet->mport->id].active[i]); + if (count) + atomic_inc(&skb->users); + count++; + } } else if (RIONET_MAC_MATCH(eth->h_dest)) { destid = RIONET_GET_DESTID(eth->h_dest); - if (rionet_active[destid]) - rionet_queue_tx_msg(skb, ndev, rionet_active[destid]); + if (nets[rnet->mport->id].active[destid]) + rionet_queue_tx_msg(skb, ndev, + nets[rnet->mport->id].active[destid]); } spin_unlock_irqrestore(&rnet->tx_lock, flags); @@ -218,16 +226,21 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", DRV_NAME, sid, tid, info); if (info == RIONET_DOORBELL_JOIN) { - if (!rionet_active[sid]) { - list_for_each_entry(peer, &rionet_peers, node) { - if (peer->rdev->destid == sid) - rionet_active[sid] = peer->rdev; + if (!nets[rnet->mport->id].active[sid]) { + list_for_each_entry(peer, + &nets[rnet->mport->id].peers, node) { + if (peer->rdev->destid == sid) { + nets[rnet->mport->id].active[sid] = + peer->rdev; + nets[rnet->mport->id].nact++; + } } rio_mport_send_doorbell(mport, sid, RIONET_DOORBELL_JOIN); } } else if (info == RIONET_DOORBELL_LEAVE) { - rionet_active[sid] = NULL; + nets[rnet->mport->id].active[sid] = NULL; + nets[rnet->mport->id].nact--; } else { if (netif_msg_intr(rnet)) printk(KERN_WARNING "%s: unhandled doorbell\n", @@ -321,7 +334,8 @@ static int rionet_open(struct net_device *ndev) netif_carrier_on(ndev); netif_start_queue(ndev); - list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + list_for_each_entry_safe(peer, tmp, + &nets[rnet->mport->id].peers, node) { if (!(peer->res = rio_request_outb_dbell(peer->rdev, RIONET_DOORBELL_JOIN, RIONET_DOORBELL_LEAVE))) @@ -346,7 +360,7 @@ static int rionet_close(struct net_device *ndev) int i; if (netif_msg_ifup(rnet)) - printk(KERN_INFO "%s: close\n", DRV_NAME); + printk(KERN_INFO "%s: close %s\n", DRV_NAME, ndev->name); netif_stop_queue(ndev); netif_carrier_off(ndev); @@ -354,10 +368,11 @@ static int rionet_close(struct net_device *ndev) for (i = 0; i < RIONET_RX_RING_SIZE; i++) kfree_skb(rnet->rx_skb[i]); - list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { - if (rionet_active[peer->rdev->destid]) { + list_for_each_entry_safe(peer, tmp, + &nets[rnet->mport->id].peers, node) { + if (nets[rnet->mport->id].active[peer->rdev->destid]) { rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); - rionet_active[peer->rdev->destid] = NULL; + nets[rnet->mport->id].active[peer->rdev->destid] = NULL; } rio_release_outb_dbell(peer->rdev, peer->res); } @@ -373,17 +388,21 @@ static int rionet_close(struct net_device *ndev) static void rionet_remove(struct rio_dev *rdev) { struct net_device *ndev = rio_get_drvdata(rdev); + unsigned char netid = rdev->net->hport->id; struct rionet_peer *peer, *tmp; - free_pages((unsigned long)rionet_active, get_order(sizeof(void *) * - RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size))); unregister_netdev(ndev); - free_netdev(ndev); - list_for_each_entry_safe(peer, tmp, &rionet_peers, node) { + free_pages((unsigned long)nets[netid].active, get_order(sizeof(void *) * + RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size))); + nets[netid].active = NULL; + + list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) { list_del(&peer->node); kfree(peer); } + + free_netdev(ndev); } static void rionet_get_drvinfo(struct net_device *ndev, @@ -435,13 +454,13 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) const size_t rionet_active_bytes = sizeof(void *) * RIO_MAX_ROUTE_ENTRIES(mport->sys_size); - rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, - get_order(rionet_active_bytes)); - if (!rionet_active) { + nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, + get_order(rionet_active_bytes)); + if (!nets[mport->id].active) { rc = -ENOMEM; goto out; } - memset((void *)rionet_active, 0, rionet_active_bytes); + memset((void *)nets[mport->id].active, 0, rionet_active_bytes); /* Set up private area */ rnet = netdev_priv(ndev); @@ -470,60 +489,62 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) if (rc != 0) goto out; - printk("%s: %s %s Version %s, MAC %pM\n", + printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n", ndev->name, DRV_NAME, DRV_DESC, DRV_VERSION, - ndev->dev_addr); + ndev->dev_addr, + mport->name); out: return rc; } -/* - * XXX Make multi-net safe - */ +static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1]; + static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) { int rc = -ENODEV; u32 lsrc_ops, ldst_ops; struct rionet_peer *peer; struct net_device *ndev = NULL; + unsigned char netid = rdev->net->hport->id; + int oldnet; - /* If local device is not rionet capable, give up quickly */ - if (!rionet_capable) - goto out; + if (netid >= RIONET_MAX_NETS) + return rc; - /* Allocate our net_device structure */ - ndev = alloc_etherdev(sizeof(struct rionet_private)); - if (ndev == NULL) { - rc = -ENOMEM; - goto out; - } + oldnet = test_and_set_bit(netid, net_table); /* * First time through, make sure local device is rionet - * capable, setup netdev, and set flags so this is skipped - * on later probes + * capable, setup netdev (will be skipped on later probes) */ - if (!rionet_check) { + if (!oldnet) { rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, &lsrc_ops); rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, &ldst_ops); if (!is_rionet_capable(lsrc_ops, ldst_ops)) { printk(KERN_ERR - "%s: local device is not network capable\n", - DRV_NAME); - rionet_check = 1; - rionet_capable = 0; + "%s: local device %s is not network capable\n", + DRV_NAME, rdev->net->hport->name); goto out; } + /* Allocate our net_device structure */ + ndev = alloc_etherdev(sizeof(struct rionet_private)); + if (ndev == NULL) { + rc = -ENOMEM; + goto out; + } + nets[netid].ndev = ndev; rc = rionet_setup_netdev(rdev->net->hport, ndev); - rionet_check = 1; - } + INIT_LIST_HEAD(&nets[netid].peers); + nets[netid].nact = 0; + } else if (nets[netid].ndev == NULL) + goto out; /* * If the remote device has mailbox/doorbell capabilities, @@ -535,10 +556,10 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id) goto out; } peer->rdev = rdev; - list_add_tail(&peer->node, &rionet_peers); + list_add_tail(&peer->node, &nets[netid].peers); } - rio_set_drvdata(rdev, ndev); + rio_set_drvdata(rdev, nets[netid].ndev); out: return rc; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 5c7547c4f802..d44cca327588 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1315,6 +1315,7 @@ static const struct team_option team_options[] = { static struct lock_class_key team_netdev_xmit_lock_key; static struct lock_class_key team_netdev_addr_lock_key; +static struct lock_class_key team_tx_busylock_key; static void team_set_lockdep_class_one(struct net_device *dev, struct netdev_queue *txq, @@ -1327,6 +1328,7 @@ static void team_set_lockdep_class(struct net_device *dev) { lockdep_set_class(&dev->addr_list_lock, &team_netdev_addr_lock_key); netdev_for_each_tx_queue(dev, team_set_lockdep_class_one, NULL); + dev->qdisc_tx_busylock = &team_tx_busylock_key; } static int team_init(struct net_device *dev) diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 0e5769061702..feacc3b994b7 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -1775,7 +1775,7 @@ EXPORT_SYMBOL(z8530_queue_xmit); /* * Module support */ -static const char banner[] __initdata = +static const char banner[] __initconst = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"; static int __init z85230_init_driver(void) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 05593d882023..4ebfcf3d8a3b 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -40,6 +40,7 @@ #include <net/tcp.h> +#include <xen/xen.h> #include <xen/events.h> #include <xen/interface/memory.h> diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index c934fe8583f5..caa011008cd0 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -43,6 +43,7 @@ #include <linux/slab.h> #include <net/ip.h> +#include <asm/xen/page.h> #include <xen/xen.h> #include <xen/xenbus.h> #include <xen/events.h> diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index 1e117c2a3cad..b29e20b7862f 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -388,7 +388,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) /* Remove the EADS bridge device itself */ BUG_ON(!bus->self); pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); - eeh_remove_bus_device(bus->self); + eeh_remove_bus_device(bus->self, true); pci_stop_and_remove_bus_device(bus->self); return 0; diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c index a514bf66fdd7..1deca7f6c4ea 100644 --- a/drivers/platform/x86/amilo-rfkill.c +++ b/drivers/platform/x86/amilo-rfkill.c @@ -74,7 +74,7 @@ static const struct rfkill_ops amilo_m7440_rfkill_ops = { .set_block = amilo_m7440_rfkill_set_block }; -static const struct dmi_system_id __devinitdata amilo_rfkill_id_table[] = { +static const struct dmi_system_id __devinitconst amilo_rfkill_id_table[] = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c index 7acae3f85f3b..f77484528b1b 100644 --- a/drivers/platform/x86/fujitsu-tablet.c +++ b/drivers/platform/x86/fujitsu-tablet.c @@ -52,7 +52,7 @@ struct fujitsu_config { unsigned int quirks; }; -static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initconst = { +static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = { KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, @@ -71,7 +71,7 @@ static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initconst = { KEY_LEFTALT }; -static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initconst = { +static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = { KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, @@ -90,7 +90,7 @@ static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initconst = { KEY_LEFTALT }; -static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initconst = { +static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initdata = { KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, @@ -109,7 +109,7 @@ static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initconst = { KEY_LEFTALT }; -static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initconst = { +static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initdata = { KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, @@ -299,7 +299,7 @@ static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) return 1; } -static struct dmi_system_id dmi_ids[] __initconst = { +static const struct dmi_system_id dmi_ids[] __initconst = { { .callback = fujitsu_dmi_lifebook, .ident = "Fujitsu Siemens P/T Series", diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9da5fe715e6a..75dd651664ae 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -522,7 +522,7 @@ static acpi_handle ec_handle; #define TPACPI_HANDLE(object, parent, paths...) \ static acpi_handle object##_handle; \ - static const acpi_handle *object##_parent __initdata = \ + static const acpi_handle * const object##_parent __initconst = \ &parent##_handle; \ static char *object##_paths[] __initdata = { paths } diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index e771487132f7..2420d5af0583 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -306,7 +306,7 @@ int pps_register_cdev(struct pps_device *pps) if (err < 0) return err; - pps->id &= MAX_ID_MASK; + pps->id &= MAX_IDR_MASK; if (pps->id >= PPS_MAX_SOURCES) { pr_err("%s: too many PPS sources in the system\n", pps->info.name); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 90c5c7357a50..d7c6b83097c1 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -115,6 +115,15 @@ config PWM_TIEHRPWM To compile this driver as a module, choose M here: the module will be called pwm-tiehrpwm. +config PWM_TWL6030 + tristate "TWL6030 PWM support" + depends on TWL4030_CORE + help + Generic PWM framework driver for TWL6030. + + To compile this driver as a module, choose M here: the module + will be called pwm-twl6030. + config PWM_VT8500 tristate "vt8500 pwm support" depends on ARCH_VT8500 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index e4b2c898964d..78f123dca30d 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o +obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/pwm/pwm-twl6030.c index e8fee147678d..8e6387864ca2 100644 --- a/drivers/mfd/twl6030-pwm.c +++ b/drivers/pwm/pwm-twl6030.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pwm.h> #include <linux/i2c/twl.h> #include <linux/slab.h> @@ -45,40 +46,54 @@ #define PWM_CTRL2_MODE_MASK 0x3 -struct pwm_device { - const char *label; - unsigned int pwm_id; +struct twl6030_pwm_chip { + struct pwm_chip chip; }; -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) +static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { - u8 duty_cycle; int ret; + u8 val; - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) - return -EINVAL; + /* Configure PWM */ + val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | + PWM_CTRL2_MODE_HW; - duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n", + pwm->label, ret); + return ret; + } - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); + return 0; +} +static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; + int ret; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); if (ret < 0) { pr_err("%s: Failed to configure PWM, Error %d\n", pwm->label, ret); return ret; } + return 0; } -EXPORT_SYMBOL(pwm_config); -int pwm_enable(struct pwm_device *pwm) +static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { - u8 val; int ret; + u8 val; ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); if (ret < 0) { - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); + dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", + pwm->label, ret); return ret; } @@ -88,23 +103,23 @@ int pwm_enable(struct pwm_device *pwm) ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); if (ret < 0) { - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); + dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", + pwm->label, ret); return ret; } twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); return 0; } -EXPORT_SYMBOL(pwm_enable); -void pwm_disable(struct pwm_device *pwm) +static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { - u8 val; int ret; + u8 val; ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); if (ret < 0) { - pr_err("%s: Failed to disable PWM, Error %d\n", + dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", pwm->label, ret); return; } @@ -114,52 +129,56 @@ void pwm_disable(struct pwm_device *pwm) ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); if (ret < 0) { - pr_err("%s: Failed to disable PWM, Error %d\n", + dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", pwm->label, ret); - return; } - return; } -EXPORT_SYMBOL(pwm_disable); -struct pwm_device *pwm_request(int pwm_id, const char *label) +static const struct pwm_ops twl6030_pwm_ops = { + .request = twl6030_pwm_request, + .config = twl6030_pwm_config, + .enable = twl6030_pwm_enable, + .disable = twl6030_pwm_disable, +}; + +static int twl6030_pwm_probe(struct platform_device *pdev) { - u8 val; + struct twl6030_pwm_chip *twl6030; int ret; - struct pwm_device *pwm; - - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); - if (pwm == NULL) { - pr_err("%s: failed to allocate memory\n", label); - return NULL; - } - pwm->label = label; - pwm->pwm_id = pwm_id; - - /* Configure PWM */ - val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | - PWM_CTRL2_MODE_HW; + twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL); + if (!twl6030) + return -ENOMEM; - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); + twl6030->chip.dev = &pdev->dev; + twl6030->chip.ops = &twl6030_pwm_ops; + twl6030->chip.base = -1; + twl6030->chip.npwm = 1; - if (ret < 0) { - pr_err("%s: Failed to configure PWM, Error %d\n", - pwm->label, ret); + ret = pwmchip_add(&twl6030->chip); + if (ret < 0) + return ret; - kfree(pwm); - return NULL; - } + platform_set_drvdata(pdev, twl6030); - return pwm; + return 0; } -EXPORT_SYMBOL(pwm_request); -void pwm_free(struct pwm_device *pwm) +static int twl6030_pwm_remove(struct platform_device *pdev) { - pwm_disable(pwm); - kfree(pwm); + struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev); + + return pwmchip_remove(&twl6030->chip); } -EXPORT_SYMBOL(pwm_free); +static struct platform_driver twl6030_pwm_driver = { + .driver = { + .name = "twl6030-pwm", + }, + .probe = twl6030_pwm_probe, + .remove = __devexit_p(twl6030_pwm_remove), +}; +module_platform_driver(twl6030_pwm_driver); + +MODULE_ALIAS("platform:twl6030-pwm"); MODULE_LICENSE("GPL"); diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index d5e1625bbac2..38ecd8f4d60e 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -862,6 +862,90 @@ static void tsi721_init_pc2sr_mapping(struct tsi721_device *priv) } /** + * tsi721_rio_map_inb_mem -- Mapping inbound memory region. + * @mport: RapidIO master port + * @lstart: Local memory space start address. + * @rstart: RapidIO space start address. + * @size: The mapping region size. + * @flags: Flags for mapping. 0 for using default flags. + * + * Return: 0 -- Success. + * + * This function will create the inbound mapping + * from rstart to lstart. + */ +static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, + u64 rstart, u32 size, u32 flags) +{ + struct tsi721_device *priv = mport->priv; + int i; + u32 regval; + + if (!is_power_of_2(size) || size < 0x1000 || + ((u64)lstart & (size - 1)) || (rstart & (size - 1))) + return -EINVAL; + + /* Search for free inbound translation window */ + for (i = 0; i < TSI721_IBWIN_NUM; i++) { + regval = ioread32(priv->regs + TSI721_IBWIN_LB(i)); + if (!(regval & TSI721_IBWIN_LB_WEN)) + break; + } + + if (i >= TSI721_IBWIN_NUM) { + dev_err(&priv->pdev->dev, + "Unable to find free inbound window\n"); + return -EBUSY; + } + + iowrite32(TSI721_IBWIN_SIZE(size) << 8, + priv->regs + TSI721_IBWIN_SZ(i)); + + iowrite32(((u64)lstart >> 32), priv->regs + TSI721_IBWIN_TUA(i)); + iowrite32(((u64)lstart & TSI721_IBWIN_TLA_ADD), + priv->regs + TSI721_IBWIN_TLA(i)); + + iowrite32(rstart >> 32, priv->regs + TSI721_IBWIN_UB(i)); + iowrite32((rstart & TSI721_IBWIN_LB_BA) | TSI721_IBWIN_LB_WEN, + priv->regs + TSI721_IBWIN_LB(i)); + dev_dbg(&priv->pdev->dev, + "Configured IBWIN%d mapping (RIO_0x%llx -> PCIe_0x%llx)\n", + i, rstart, (unsigned long long)lstart); + + return 0; +} + +/** + * fsl_rio_unmap_inb_mem -- Unmapping inbound memory region. + * @mport: RapidIO master port + * @lstart: Local memory space start address. + */ +static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport, + dma_addr_t lstart) +{ + struct tsi721_device *priv = mport->priv; + int i; + u64 addr; + u32 regval; + + /* Search for matching active inbound translation window */ + for (i = 0; i < TSI721_IBWIN_NUM; i++) { + regval = ioread32(priv->regs + TSI721_IBWIN_LB(i)); + if (regval & TSI721_IBWIN_LB_WEN) { + regval = ioread32(priv->regs + TSI721_IBWIN_TUA(i)); + addr = (u64)regval << 32; + regval = ioread32(priv->regs + TSI721_IBWIN_TLA(i)); + addr |= regval & TSI721_IBWIN_TLA_ADD; + + if (addr == (u64)lstart) { + iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); + break; + } + } + } +} + +/** * tsi721_init_sr2pc_mapping - initializes inbound (SRIO->PCIe) * translation regions. * @priv: pointer to tsi721 private data @@ -874,7 +958,7 @@ static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv) /* Disable all SR2PC inbound windows */ for (i = 0; i < TSI721_IBWIN_NUM; i++) - iowrite32(0, priv->regs + TSI721_IBWINLB(i)); + iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); } /** @@ -2144,6 +2228,8 @@ static int __devinit tsi721_setup_mport(struct tsi721_device *priv) ops->add_outb_message = tsi721_add_outb_message; ops->add_inb_buffer = tsi721_add_inb_buffer; ops->get_inb_message = tsi721_get_inb_message; + ops->map_inb = tsi721_rio_map_inb_mem; + ops->unmap_inb = tsi721_rio_unmap_inb_mem; mport = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); if (!mport) { @@ -2165,7 +2251,8 @@ static int __devinit tsi721_setup_mport(struct tsi721_device *priv) rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3); rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3); - strcpy(mport->name, "Tsi721 mport"); + snprintf(mport->name, RIO_MAX_MPORT_NAME, "%s(%s)", + dev_driver_string(&pdev->dev), dev_name(&pdev->dev)); /* Hook up interrupt handler */ @@ -2315,7 +2402,8 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, /* Configure DMA attributes. */ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { dev_info(&pdev->dev, "Unable to set DMA mask\n"); goto err_unmap_bars; } diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h index 59de9d7be346..7d5b13ba8d4f 100644 --- a/drivers/rapidio/devices/tsi721.h +++ b/drivers/rapidio/devices/tsi721.h @@ -156,9 +156,18 @@ #define TSI721_IBWIN_NUM 8 -#define TSI721_IBWINLB(x) (0x29000 + (x) * 0x20) -#define TSI721_IBWINLB_BA 0xfffff000 -#define TSI721_IBWINLB_WEN 0x00000001 +#define TSI721_IBWIN_LB(x) (0x29000 + (x) * 0x20) +#define TSI721_IBWIN_LB_BA 0xfffff000 +#define TSI721_IBWIN_LB_WEN 0x00000001 + +#define TSI721_IBWIN_UB(x) (0x29004 + (x) * 0x20) +#define TSI721_IBWIN_SZ(x) (0x29008 + (x) * 0x20) +#define TSI721_IBWIN_SZ_SIZE 0x00001f00 +#define TSI721_IBWIN_SIZE(size) (__fls(size) - 12) + +#define TSI721_IBWIN_TLA(x) (0x2900c + (x) * 0x20) +#define TSI721_IBWIN_TLA_ADD 0xfffff000 +#define TSI721_IBWIN_TUA(x) (0x29010 + (x) * 0x20) #define TSI721_SR2PC_GEN_INTE 0x29800 #define TSI721_SR2PC_PWE 0x29804 diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 2bebd791a092..48e9041dd1e2 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -31,27 +31,21 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/timer.h> +#include <linux/sched.h> #include <linux/jiffies.h> #include <linux/slab.h> #include "rio.h" LIST_HEAD(rio_devices); -static LIST_HEAD(rio_switches); - -static void rio_enum_timeout(unsigned long); static void rio_init_em(struct rio_dev *rdev); DEFINE_SPINLOCK(rio_global_list_lock); static int next_destid = 0; -static int next_net = 0; static int next_comptag = 1; -static struct timer_list rio_enum_timer = -TIMER_INITIALIZER(rio_enum_timeout, 0, 0); - static int rio_mport_phys_table[] = { RIO_EFB_PAR_EP_ID, RIO_EFB_PAR_EP_REC_ID, @@ -60,6 +54,114 @@ static int rio_mport_phys_table[] = { -1, }; + +/* + * rio_destid_alloc - Allocate next available destID for given network + * net: RIO network + * + * Returns next available device destination ID for the specified RIO network. + * Marks allocated ID as one in use. + * Returns RIO_INVALID_DESTID if new destID is not available. + */ +static u16 rio_destid_alloc(struct rio_net *net) +{ + int destid; + struct rio_id_table *idtab = &net->destid_table; + + spin_lock(&idtab->lock); + destid = find_next_zero_bit(idtab->table, idtab->max, idtab->next); + if (destid >= idtab->max) + destid = find_first_zero_bit(idtab->table, idtab->max); + + if (destid < idtab->max) { + idtab->next = destid + 1; + if (idtab->next >= idtab->max) + idtab->next = 0; + set_bit(destid, idtab->table); + destid += idtab->start; + } else + destid = RIO_INVALID_DESTID; + + spin_unlock(&idtab->lock); + return (u16)destid; +} + +/* + * rio_destid_reserve - Reserve the specivied destID + * net: RIO network + * destid: destID to reserve + * + * Tries to reserve the specified destID. + * Returns 0 if successfull. + */ +static int rio_destid_reserve(struct rio_net *net, u16 destid) +{ + int oldbit; + struct rio_id_table *idtab = &net->destid_table; + + destid -= idtab->start; + spin_lock(&idtab->lock); + oldbit = test_and_set_bit(destid, idtab->table); + spin_unlock(&idtab->lock); + return oldbit; +} + +/* + * rio_destid_free - free a previously allocated destID + * net: RIO network + * destid: destID to free + * + * Makes the specified destID available for use. + */ +static void rio_destid_free(struct rio_net *net, u16 destid) +{ + struct rio_id_table *idtab = &net->destid_table; + + destid -= idtab->start; + spin_lock(&idtab->lock); + clear_bit(destid, idtab->table); + spin_unlock(&idtab->lock); +} + +/* + * rio_destid_first - return first destID in use + * net: RIO network + */ +static u16 rio_destid_first(struct rio_net *net) +{ + int destid; + struct rio_id_table *idtab = &net->destid_table; + + spin_lock(&idtab->lock); + destid = find_first_bit(idtab->table, idtab->max); + if (destid >= idtab->max) + destid = RIO_INVALID_DESTID; + else + destid += idtab->start; + spin_unlock(&idtab->lock); + return (u16)destid; +} + +/* + * rio_destid_next - return next destID in use + * net: RIO network + * from: destination ID from which search shall continue + */ +static u16 rio_destid_next(struct rio_net *net, u16 from) +{ + int destid; + struct rio_id_table *idtab = &net->destid_table; + + spin_lock(&idtab->lock); + destid = find_next_bit(idtab->table, idtab->max, from); + if (destid >= idtab->max) + destid = RIO_INVALID_DESTID; + else + destid += idtab->start; + spin_unlock(&idtab->lock); + return (u16)destid; +} + /** * rio_get_device_id - Get the base/extended device id for a device * @port: RIO master port @@ -108,14 +210,15 @@ static void rio_local_set_device_id(struct rio_mport *port, u16 did) /** * rio_clear_locks- Release all host locks and signal enumeration complete - * @port: Master port to issue transaction + * @net: RIO network to run on * * Marks the component tag CSR on each device with the enumeration * complete flag. When complete, it then release the host locks on * each device. Returns 0 on success or %-EINVAL on failure. */ -static int rio_clear_locks(struct rio_mport *port) +static int rio_clear_locks(struct rio_net *net) { + struct rio_mport *port = net->hport; struct rio_dev *rdev; u32 result; int ret = 0; @@ -130,7 +233,7 @@ static int rio_clear_locks(struct rio_mport *port) result); ret = -EINVAL; } - list_for_each_entry(rdev, &rio_devices, global_list) { + list_for_each_entry(rdev, &net->devices, net_list) { rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, port->host_deviceid); rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); @@ -176,10 +279,6 @@ static int rio_enum_host(struct rio_mport *port) /* Set master port destid and init destid ctr */ rio_local_set_device_id(port, port->host_deviceid); - - if (next_destid == port->host_deviceid) - next_destid++; - return 0; } @@ -446,9 +545,8 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { if (do_enum) { rio_set_device_id(port, destid, hopcount, next_destid); - rdev->destid = next_destid++; - if (next_destid == port->host_deviceid) - next_destid++; + rdev->destid = next_destid; + next_destid = rio_destid_alloc(net); } else rdev->destid = rio_get_device_id(port, destid, hopcount); @@ -483,7 +581,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, rswitch->clr_table(port, destid, hopcount, RIO_GLOBAL_TABLE); - list_add_tail(&rswitch->node, &rio_switches); + list_add_tail(&rswitch->node, &net->switches); } else { if (do_enum) @@ -747,12 +845,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, u8 hopcount, struct rio_dev *prev, int prev_port) { - int port_num; - int cur_destid; - int sw_destid; - int sw_inport; struct rio_dev *rdev; - u16 destid; u32 regval; int tmp; @@ -818,19 +911,26 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, return -1; if (rio_is_switch(rdev)) { + int sw_destid; + int cur_destid; + int sw_inport; + u16 destid; + int port_num; + sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport, 0); rdev->rswitch->route_table[port->host_deviceid] = sw_inport; - for (destid = 0; destid < next_destid; destid++) { - if (destid == port->host_deviceid) - continue; - rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, - destid, sw_inport, 0); - rdev->rswitch->route_table[destid] = sw_inport; + destid = rio_destid_first(net); + while (destid != RIO_INVALID_DESTID && destid < next_destid) { + if (destid != port->host_deviceid) { + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, + destid, sw_inport, 0); + rdev->rswitch->route_table[destid] = sw_inport; + } + destid = rio_destid_next(net, destid + 1); } - pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", rio_name(rdev), rdev->vid, rdev->did, @@ -839,12 +939,10 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, for (port_num = 0; port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); port_num++) { - /*Enable Input Output Port (transmitter reviever)*/ - rio_enable_rx_tx_port(port, 0, + if (sw_inport == port_num) { + rio_enable_rx_tx_port(port, 0, RIO_ANY_DESTID(port->sys_size), hopcount, port_num); - - if (sw_inport == port_num) { rdev->rswitch->port_ok |= (1 << port_num); continue; } @@ -857,6 +955,9 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, pr_debug( "RIO: scanning device on port %d\n", port_num); + rio_enable_rx_tx_port(port, 0, + RIO_ANY_DESTID(port->sys_size), + hopcount, port_num); rdev->rswitch->port_ok |= (1 << port_num); rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, RIO_ANY_DESTID(port->sys_size), @@ -867,19 +968,22 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, return -1; /* Update routing tables */ - if (next_destid > cur_destid) { + destid = rio_destid_next(net, cur_destid + 1); + if (destid != RIO_INVALID_DESTID) { for (destid = cur_destid; - destid < next_destid; destid++) { - if (destid == port->host_deviceid) - continue; - rio_route_add_entry(rdev, + destid < next_destid;) { + if (destid != port->host_deviceid) { + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, destid, port_num, 0); - rdev->rswitch-> - route_table[destid] = - port_num; + rdev->rswitch-> + route_table[destid] = + port_num; + } + destid = rio_destid_next(net, + destid + 1); } } } else { @@ -905,11 +1009,8 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, rio_init_em(rdev); /* Check for empty switch */ - if (next_destid == sw_destid) { - next_destid++; - if (next_destid == port->host_deviceid) - next_destid++; - } + if (next_destid == sw_destid) + next_destid = rio_destid_alloc(net); rdev->destid = sw_destid; } else @@ -1047,48 +1148,71 @@ static int rio_mport_is_active(struct rio_mport *port) /** * rio_alloc_net- Allocate and configure a new RIO network * @port: Master port associated with the RIO network + * @do_enum: Enumeration/Discovery mode flag + * @start: logical minimal start id for new net * * Allocates a RIO network structure, initializes per-network * list heads, and adds the associated master port to the * network list of associated master ports. Returns a * RIO network pointer on success or %NULL on failure. */ -static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) +static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port, + int do_enum, u16 start) { struct rio_net *net; net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); + if (net && do_enum) { + net->destid_table.table = kzalloc( + BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)) * + sizeof(long), + GFP_KERNEL); + + if (net->destid_table.table == NULL) { + pr_err("RIO: failed to allocate destID table\n"); + kfree(net); + net = NULL; + } else { + net->destid_table.start = start; + net->destid_table.next = 0; + net->destid_table.max = + RIO_MAX_ROUTE_ENTRIES(port->sys_size); + spin_lock_init(&net->destid_table.lock); + } + } + if (net) { INIT_LIST_HEAD(&net->node); INIT_LIST_HEAD(&net->devices); + INIT_LIST_HEAD(&net->switches); INIT_LIST_HEAD(&net->mports); list_add_tail(&port->nnode, &net->mports); net->hport = port; - net->id = next_net++; + net->id = port->id; } return net; } /** * rio_update_route_tables- Updates route tables in switches - * @port: Master port associated with the RIO network + * @net: RIO network to run update on * * For each enumerated device, ensure that each switch in a system * has correct routing entries. Add routes for devices that where * unknown dirung the first enumeration pass through the switch. */ -static void rio_update_route_tables(struct rio_mport *port) +static void rio_update_route_tables(struct rio_net *net) { struct rio_dev *rdev, *swrdev; struct rio_switch *rswitch; u8 sport; u16 destid; - list_for_each_entry(rdev, &rio_devices, global_list) { + list_for_each_entry(rdev, &net->devices, net_list) { destid = rdev->destid; - list_for_each_entry(rswitch, &rio_switches, node) { + list_for_each_entry(rswitch, &net->switches, node) { if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) continue; @@ -1166,12 +1290,16 @@ int __devinit rio_enum_mport(struct rio_mport *mport) /* If master port has an active link, allocate net and enum peers */ if (rio_mport_is_active(mport)) { - if (!(net = rio_alloc_net(mport))) { + net = rio_alloc_net(mport, 1, 0); + if (!net) { printk(KERN_ERR "RIO: failed to allocate new net\n"); rc = -ENOMEM; goto out; } + /* reserve mport destID in new net */ + rio_destid_reserve(net, mport->host_deviceid); + /* Enable Input Output Port (transmitter reviever) */ rio_enable_rx_tx_port(mport, 1, 0, 0, 0); @@ -1179,17 +1307,21 @@ int __devinit rio_enum_mport(struct rio_mport *mport) rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, next_comptag++); + next_destid = rio_destid_alloc(net); + if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { /* A higher priority host won enumeration, bail. */ printk(KERN_INFO "RIO: master port %d device has lost enumeration to a remote host\n", mport->id); - rio_clear_locks(mport); + rio_clear_locks(net); rc = -EBUSY; goto out; } - rio_update_route_tables(mport); - rio_clear_locks(mport); + /* free the last allocated destID (unused) */ + rio_destid_free(net, next_destid); + rio_update_route_tables(net); + rio_clear_locks(net); rio_pw_enable(mport, 1); } else { printk(KERN_INFO "RIO: master port %d link inactive\n", @@ -1203,47 +1335,34 @@ int __devinit rio_enum_mport(struct rio_mport *mport) /** * rio_build_route_tables- Generate route tables from switch route entries + * @net: RIO network to run route tables scan on * * For each switch device, generate a route table by copying existing * route entries from the switch. */ -static void rio_build_route_tables(void) +static void rio_build_route_tables(struct rio_net *net) { + struct rio_switch *rswitch; struct rio_dev *rdev; int i; u8 sport; - list_for_each_entry(rdev, &rio_devices, global_list) - if (rio_is_switch(rdev)) { - rio_lock_device(rdev->net->hport, rdev->destid, - rdev->hopcount, 1000); - for (i = 0; - i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); - i++) { - if (rio_route_get_entry(rdev, - RIO_GLOBAL_TABLE, i, &sport, 0) < 0) - continue; - rdev->rswitch->route_table[i] = sport; - } + list_for_each_entry(rswitch, &net->switches, node) { + rdev = sw_to_rio_dev(rswitch); - rio_unlock_device(rdev->net->hport, - rdev->destid, - rdev->hopcount); + rio_lock_device(net->hport, rdev->destid, + rdev->hopcount, 1000); + for (i = 0; + i < RIO_MAX_ROUTE_ENTRIES(net->hport->sys_size); + i++) { + if (rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, + i, &sport, 0) < 0) + continue; + rswitch->route_table[i] = sport; } -} -/** - * rio_enum_timeout- Signal that enumeration timed out - * @data: Address of timeout flag. - * - * When the enumeration complete timer expires, set a flag that - * signals to the discovery process that enumeration did not - * complete in a sane amount of time. - */ -static void rio_enum_timeout(unsigned long data) -{ - /* Enumeration timed out, set flag */ - *(int *)data = 1; + rio_unlock_device(net->hport, rdev->destid, rdev->hopcount); + } } /** @@ -1259,34 +1378,33 @@ static void rio_enum_timeout(unsigned long data) int __devinit rio_disc_mport(struct rio_mport *mport) { struct rio_net *net = NULL; - int enum_timeout_flag = 0; + unsigned long to_end; printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id, mport->name); /* If master port has an active link, allocate net and discover peers */ if (rio_mport_is_active(mport)) { - if (!(net = rio_alloc_net(mport))) { - printk(KERN_ERR "RIO: Failed to allocate new net\n"); - goto bail; - } + pr_debug("RIO: wait for enumeration to complete...\n"); - pr_debug("RIO: wait for enumeration complete..."); - - rio_enum_timer.expires = - jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; - rio_enum_timer.data = (unsigned long)&enum_timeout_flag; - add_timer(&rio_enum_timer); - while (!rio_enum_complete(mport)) { - mdelay(1); - if (enum_timeout_flag) { - del_timer_sync(&rio_enum_timer); - goto timeout; - } + to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; + while (time_before(jiffies, to_end)) { + if (rio_enum_complete(mport)) + goto enum_done; + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); } - del_timer_sync(&rio_enum_timer); - pr_debug("done\n"); + pr_debug("RIO: discovery timeout on mport %d %s\n", + mport->id, mport->name); + goto bail; +enum_done: + pr_debug("RIO: ... enumeration done\n"); + + net = rio_alloc_net(mport, 0, 0); + if (!net) { + printk(KERN_ERR "RIO: Failed to allocate new net\n"); + goto bail; + } /* Read DestID assigned by enumerator */ rio_local_read_config_32(mport, RIO_DID_CSR, @@ -1302,13 +1420,10 @@ int __devinit rio_disc_mport(struct rio_mport *mport) goto bail; } - rio_build_route_tables(); + rio_build_route_tables(net); } return 0; - - timeout: - pr_debug("timeout\n"); - bail: +bail: return -EBUSY; } diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index c40665a4fa33..d4bd69013c50 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -33,6 +33,7 @@ static LIST_HEAD(rio_mports); static unsigned char next_portid; +static DEFINE_SPINLOCK(rio_mmap_lock); /** * rio_local_get_device_id - Get the base/extended device id for a port @@ -398,6 +399,49 @@ int rio_release_inb_pwrite(struct rio_dev *rdev) EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); /** + * rio_map_inb_region -- Map inbound memory region. + * @mport: Master port. + * @lstart: physical address of memory region to be mapped + * @rbase: RIO base address assigned to this window + * @size: Size of the memory region + * @rflags: Flags for mapping. + * + * Return: 0 -- Success. + * + * This function will create the mapping from RIO space to local memory. + */ +int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, + u64 rbase, u32 size, u32 rflags) +{ + int rc = 0; + unsigned long flags; + + if (!mport->ops->map_inb) + return -1; + spin_lock_irqsave(&rio_mmap_lock, flags); + rc = mport->ops->map_inb(mport, local, rbase, size, rflags); + spin_unlock_irqrestore(&rio_mmap_lock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(rio_map_inb_region); + +/** + * rio_unmap_inb_region -- Unmap the inbound memory region + * @mport: Master port + * @lstart: physical address of memory region to be unmapped + */ +void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart) +{ + unsigned long flags; + if (!mport->ops->unmap_inb) + return; + spin_lock_irqsave(&rio_mmap_lock, flags); + mport->ops->unmap_inb(mport, lstart); + spin_unlock_irqrestore(&rio_mmap_lock, flags); +} +EXPORT_SYMBOL_GPL(rio_unmap_inb_region); + +/** * rio_mport_get_physefb - Helper function that returns register offset * for Physical Layer Extended Features Block. * @port: Master port to issue transaction @@ -1216,15 +1260,62 @@ static int __devinit rio_init(void) return 0; } +static struct workqueue_struct *rio_wq; + +struct rio_disc_work { + struct work_struct work; + struct rio_mport *mport; +}; + +static void __devinit disc_work_handler(struct work_struct *_work) +{ + struct rio_disc_work *work; + + work = container_of(_work, struct rio_disc_work, work); + pr_debug("RIO: discovery work for mport %d %s\n", + work->mport->id, work->mport->name); + rio_disc_mport(work->mport); + + kfree(work); +} + int __devinit rio_init_mports(void) { struct rio_mport *port; + struct rio_disc_work *work; + int no_disc = 0; list_for_each_entry(port, &rio_mports, node) { if (port->host_deviceid >= 0) rio_enum_mport(port); - else - rio_disc_mport(port); + else if (!no_disc) { + if (!rio_wq) { + rio_wq = alloc_workqueue("riodisc", 0, 0); + if (!rio_wq) { + pr_err("RIO: unable allocate rio_wq\n"); + no_disc = 1; + continue; + } + } + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) { + pr_err("RIO: no memory for work struct\n"); + no_disc = 1; + continue; + } + + work->mport = port; + INIT_WORK(&work->work, disc_work_handler); + queue_work(rio_wq, &work->work); + } + } + + if (rio_wq) { + pr_debug("RIO: flush discovery workqueue\n"); + flush_workqueue(rio_wq); + pr_debug("RIO: flush discovery workqueue finished\n"); + destroy_workqueue(rio_wq); } rio_init(); diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index c3482b954cb7..1c5ab0172ea2 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -12,6 +12,8 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/i2c.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> @@ -23,6 +25,7 @@ struct pm8607_regulator_info { struct pm860x_chip *chip; struct regulator_dev *regulator; struct i2c_client *i2c; + struct i2c_client *i2c_8606; unsigned int *vol_table; unsigned int *vol_suspend; @@ -242,6 +245,35 @@ static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) return ret; } +static int pm8606_preg_enable(struct regulator_dev *rdev) +{ + struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); + + return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, + 1 << rdev->desc->enable_mask, 0); +} + +static int pm8606_preg_disable(struct regulator_dev *rdev) +{ + struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); + + return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, + 1 << rdev->desc->enable_mask, + 1 << rdev->desc->enable_mask); +} + +static int pm8606_preg_is_enabled(struct regulator_dev *rdev) +{ + struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg); + if (ret < 0) + return ret; + + return !((unsigned char)ret & (1 << rdev->desc->enable_mask)); +} + static struct regulator_ops pm8607_regulator_ops = { .list_voltage = pm8607_list_voltage, .set_voltage_sel = pm8607_set_voltage_sel, @@ -251,6 +283,25 @@ static struct regulator_ops pm8607_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, }; +static struct regulator_ops pm8606_preg_ops = { + .enable = pm8606_preg_enable, + .disable = pm8606_preg_disable, + .is_enabled = pm8606_preg_is_enabled, +}; + +#define PM8606_PREG(ereg, ebit) \ +{ \ + .desc = { \ + .name = "PREG", \ + .ops = &pm8606_preg_ops, \ + .type = REGULATOR_CURRENT, \ + .id = PM8606_ID_PREG, \ + .owner = THIS_MODULE, \ + .enable_reg = PM8606_##ereg, \ + .enable_mask = (ebit), \ + }, \ +} + #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ { \ .desc = { \ @@ -311,6 +362,38 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = { PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), }; +static struct pm8607_regulator_info pm8606_regulator_info[] = { + PM8606_PREG(PREREGULATORB, 5), +}; + +#ifdef CONFIG_OF +static int pm8607_regulator_dt_init(struct platform_device *pdev, + struct pm8607_regulator_info *info, + struct regulator_config *config) +{ + struct device_node *nproot, *np; + nproot = pdev->dev.parent->of_node; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "regulators"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find regulators node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, info->desc.name)) { + config->init_data = + of_get_regulator_init_data(&pdev->dev, np); + config->of_node = np; + break; + } + } + return 0; +} +#else +#define pm8607_regulator_dt_init(x, y, z) (-1) +#endif + static int __devinit pm8607_regulator_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -320,22 +403,28 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) struct resource *res; int i; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { - info = &pm8607_regulator_info[i]; - if (info->desc.id == res->start) - break; - } - if (i == ARRAY_SIZE(pm8607_regulator_info)) { - dev_err(&pdev->dev, "Failed to find regulator %llu\n", - (unsigned long long)res->start); - return -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (res) { + /* There're resources in 88PM8607 regulator driver */ + for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { + info = &pm8607_regulator_info[i]; + if (info->desc.vsel_reg == res->start) + break; + } + if (i == ARRAY_SIZE(pm8607_regulator_info)) { + dev_err(&pdev->dev, "Failed to find regulator %llu\n", + (unsigned long long)res->start); + return -EINVAL; + } + } else { + /* There's no resource in 88PM8606 PREG regulator driver */ + info = &pm8606_regulator_info[0]; + /* i is used to check regulator ID */ + i = -1; } info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : + chip->client; info->chip = chip; /* check DVC ramp slope double */ @@ -343,15 +432,17 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) info->slope_double = 1; config.dev = &pdev->dev; - config.init_data = pdata; config.driver_data = info; + if (pm8607_regulator_dt_init(pdev, info, &config)) + if (pdata) + config.init_data = pdata; + if (chip->id == CHIP_PM8607) config.regmap = chip->regmap; else config.regmap = chip->regmap_companion; - /* replace driver_data with info */ info->regulator = regulator_register(&info->desc, &config); if (IS_ERR(info->regulator)) { dev_err(&pdev->dev, "failed to register regulator %s\n", @@ -372,6 +463,18 @@ static int __devexit pm8607_regulator_remove(struct platform_device *pdev) return 0; } +static struct platform_device_id pm8607_regulator_driver_ids[] = { + { + .name = "88pm860x-regulator", + .driver_data = 0, + }, { + .name = "88pm860x-preg", + .driver_data = 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids); + static struct platform_driver pm8607_regulator_driver = { .driver = { .name = "88pm860x-regulator", @@ -379,6 +482,7 @@ static struct platform_driver pm8607_regulator_driver = { }, .probe = pm8607_regulator_probe, .remove = __devexit_p(pm8607_regulator_remove), + .id_table = pm8607_regulator_driver_ids, }; static int __init pm8607_regulator_init(void) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e98a5e7827df..67d47b59a66d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -122,7 +122,7 @@ config REGULATOR_FAN53555 config REGULATOR_ANATOP tristate "Freescale i.MX on-chip ANATOP LDO regulators" - depends on MFD_ANATOP + depends on MFD_SYSCON help Say y here to support Freescale i.MX on-chip ANATOP LDOs regulators. It is recommended that this option be diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 65ad2b36ce36..df4ad8927f0c 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> +#include <linux/mfd/ab3100.h> #include <linux/mfd/abx500.h> /* LDO registers and some handy masking definitions for AB3100 */ diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index ce0fe72a428e..1af97686f444 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -21,19 +21,20 @@ #include <linux/slab.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/mfd/syscon.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/regmap.h> #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> struct anatop_regulator { const char *name; u32 control_reg; - struct anatop *mfd; + struct regmap *anatop; int vol_bit_shift; int vol_bit_width; int min_bit_val; @@ -43,7 +44,8 @@ struct anatop_regulator { struct regulator_init_data *initdata; }; -static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector) +static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, + unsigned selector) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); u32 val, mask; @@ -56,12 +58,13 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector) mask = ((1 << anatop_reg->vol_bit_width) - 1) << anatop_reg->vol_bit_shift; val <<= anatop_reg->vol_bit_shift; - anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask); + regmap_update_bits(anatop_reg->anatop, anatop_reg->control_reg, + mask, val); return 0; } -static int anatop_get_voltage_sel(struct regulator_dev *reg) +static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); u32 val, mask; @@ -69,7 +72,7 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg) if (!anatop_reg->control_reg) return -ENOTSUPP; - val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg); + regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val); mask = ((1 << anatop_reg->vol_bit_width) - 1) << anatop_reg->vol_bit_shift; val = (val & mask) >> anatop_reg->vol_bit_shift; @@ -78,8 +81,8 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg) } static struct regulator_ops anatop_rops = { - .set_voltage_sel = anatop_set_voltage_sel, - .get_voltage_sel = anatop_get_voltage_sel, + .set_voltage_sel = anatop_regmap_set_voltage_sel, + .get_voltage_sel = anatop_regmap_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; @@ -88,11 +91,11 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + struct device_node *anatop_np; 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); struct regulator_config config = { }; int ret = 0; @@ -109,7 +112,15 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) rdesc->ops = &anatop_rops; rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; - sreg->mfd = anatopmfd; + + anatop_np = of_get_parent(np); + if (!anatop_np) + return -ENODEV; + sreg->anatop = syscon_node_to_regmap(anatop_np); + of_node_put(anatop_np); + if (IS_ERR(sreg->anatop)) + return PTR_ERR(sreg->anatop); + ret = of_property_read_u32(np, "anatop-reg-offset", &sreg->control_reg); if (ret) { diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 43dc97ec3932..9bb0be37495f 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -214,37 +214,36 @@ static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_LDO(20, 750, 3900, 50), }; -static struct max8925_regulator_info * __devinit find_regulator_info(int id) -{ - struct max8925_regulator_info *ri; - int i; - - for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { - ri = &max8925_regulator_info[i]; - if (ri->desc.id == id) - return ri; - } - return NULL; -} - static int __devinit max8925_regulator_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *pdata = chip->dev->platform_data; + struct regulator_init_data *pdata = pdev->dev.platform_data; struct regulator_config config = { }; struct max8925_regulator_info *ri; + struct resource *res; struct regulator_dev *rdev; + int i; - ri = find_regulator_info(pdev->id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (!res) { + dev_err(&pdev->dev, "No REG resource!\n"); + return -EINVAL; + } + for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { + ri = &max8925_regulator_info[i]; + if (ri->vol_reg == res->start) + break; + } + if (i == ARRAY_SIZE(max8925_regulator_info)) { + dev_err(&pdev->dev, "Failed to find regulator %llu\n", + (unsigned long long)res->start); return -EINVAL; } ri->i2c = chip->i2c; ri->chip = chip; config.dev = &pdev->dev; - config.init_data = pdata->regulator[pdev->id]; + config.init_data = pdata; config.driver_data = ri; rdev = regulator_register(&ri->desc, &config); diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 2ba7502fa3b2..07aee694ba92 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -22,6 +22,9 @@ #include <linux/slab.h> #include <linux/regmap.h> #include <linux/mfd/palmas.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/regulator/of_regulator.h> struct regs_info { char *name; @@ -568,10 +571,103 @@ static int palmas_ldo_init(struct palmas *palmas, int id, return 0; } +static struct of_regulator_match palmas_matches[] = { + { .name = "smps12", }, + { .name = "smps123", }, + { .name = "smps3", }, + { .name = "smps45", }, + { .name = "smps457", }, + { .name = "smps6", }, + { .name = "smps7", }, + { .name = "smps8", }, + { .name = "smps9", }, + { .name = "smps10", }, + { .name = "ldo1", }, + { .name = "ldo2", }, + { .name = "ldo3", }, + { .name = "ldo4", }, + { .name = "ldo5", }, + { .name = "ldo6", }, + { .name = "ldo7", }, + { .name = "ldo8", }, + { .name = "ldo9", }, + { .name = "ldoln", }, + { .name = "ldousb", }, +}; + +static void __devinit palmas_dt_to_pdata(struct device *dev, + struct device_node *node, + struct palmas_pmic_platform_data *pdata) +{ + struct device_node *regulators; + u32 prop; + int idx, ret; + + regulators = of_find_node_by_name(node, "regulators"); + if (!regulators) { + dev_info(dev, "regulator node not found\n"); + return; + } + + ret = of_regulator_match(dev, regulators, palmas_matches, + PALMAS_NUM_REGS); + if (ret < 0) { + dev_err(dev, "Error parsing regulator init data: %d\n", ret); + return; + } + + for (idx = 0; idx < PALMAS_NUM_REGS; idx++) { + if (!palmas_matches[idx].init_data || + !palmas_matches[idx].of_node) + continue; + + pdata->reg_data[idx] = palmas_matches[idx].init_data; + + pdata->reg_init[idx] = devm_kzalloc(dev, + sizeof(struct palmas_reg_init), GFP_KERNEL); + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,warm_reset", &prop); + if (!ret) + pdata->reg_init[idx]->warm_reset = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,roof_floor", &prop); + if (!ret) + pdata->reg_init[idx]->roof_floor = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,mode_sleep", &prop); + if (!ret) + pdata->reg_init[idx]->mode_sleep = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,warm_reset", &prop); + if (!ret) + pdata->reg_init[idx]->warm_reset = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,tstep", &prop); + if (!ret) + pdata->reg_init[idx]->tstep = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,vsel", &prop); + if (!ret) + pdata->reg_init[idx]->vsel = prop; + } + + ret = of_property_read_u32(node, "ti,ldo6_vibrator", &prop); + if (!ret) + pdata->ldo6_vibrator = prop; +} + + static __devinit int palmas_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; struct regulator_dev *rdev; struct regulator_config config = { }; struct palmas_pmic *pmic; @@ -579,10 +675,14 @@ static __devinit int palmas_probe(struct platform_device *pdev) int id = 0, ret; unsigned int addr, reg; - if (!pdata) - return -EINVAL; - if (!pdata->reg_data) - return -EINVAL; + if (node && !pdata) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + + if (!pdata) + return -ENOMEM; + + palmas_dt_to_pdata(&pdev->dev, node, pdata); + } pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) @@ -661,7 +761,7 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->desc[id].owner = THIS_MODULE; /* Initialise sleep/init values from platform data */ - if (pdata && pdata->reg_init) { + if (pdata) { reg_init = pdata->reg_init[id]; if (reg_init) { ret = palmas_smps_init(palmas, id, reg_init); @@ -685,11 +785,13 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->range[id] = 1; } - if (pdata && pdata->reg_data) + if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; + config.of_node = palmas_matches[id].of_node; + rdev = regulator_register(&pmic->desc[id], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, @@ -726,11 +828,13 @@ static __devinit int palmas_probe(struct platform_device *pdev) palmas_regs_info[id].ctrl_addr); pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; - if (pdata && pdata->reg_data) + if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; + config.of_node = palmas_matches[id].of_node; + rdev = regulator_register(&pmic->desc[id], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, @@ -744,7 +848,7 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->rdev[id] = rdev; /* Initialise sleep/init values from platform data */ - if (pdata->reg_init) { + if (pdata) { reg_init = pdata->reg_init[id]; if (reg_init) { ret = palmas_ldo_init(palmas, id, reg_init); @@ -774,9 +878,15 @@ static int __devexit palmas_remove(struct platform_device *pdev) return 0; } +static struct of_device_id __devinitdata of_palmas_match_tbl[] = { + { .compatible = "ti,palmas-pmic", }, + { /* end */ } +}; + static struct platform_driver palmas_driver = { .driver = { .name = "palmas-pmic", + .of_match_table = of_palmas_match_tbl, .owner = THIS_MODULE, }, .probe = palmas_probe, @@ -799,3 +909,4 @@ MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); MODULE_DESCRIPTION("Palmas voltage regulator driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:palmas-pmic"); +MODULE_DEVICE_TABLE(of, of_palmas_match_tbl); diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 90cbcc683704..782c228a19bd 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -475,9 +475,9 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) dcdc->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -650,9 +650,9 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) dcdc->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -794,9 +794,9 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) dcdc->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 0d207c297714..2646a1902b33 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -172,9 +172,9 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) isink->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9af512672be1..c2dc03993dc7 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -273,9 +273,9 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -530,9 +530,9 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) ldo->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -687,9 +687,9 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) ldo->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index f8d818abf98c..96ce101b9067 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -4,11 +4,14 @@ menu "Remoteproc drivers (EXPERIMENTAL)" config REMOTEPROC tristate depends on EXPERIMENTAL + depends on HAS_DMA select FW_CONFIG + select VIRTIO config OMAP_REMOTEPROC tristate "OMAP remoteproc support" depends on EXPERIMENTAL + depends on HAS_DMA depends on ARCH_OMAP4 depends on OMAP_IOMMU select REMOTEPROC @@ -27,4 +30,15 @@ config OMAP_REMOTEPROC It's safe to say n here if you're not interested in multimedia offloading or just want a bare minimum kernel. +config STE_MODEM_RPROC + tristate "STE-Modem remoteproc support" + depends on EXPERIMENTAL + depends on HAS_DMA + select REMOTEPROC + default n + help + Say y or m here to support STE-Modem shared memory driver. + This can be either built-in or a loadable module. + If unsure say N. + endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 934ce6e2c66b..391b65181c05 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -8,3 +8,4 @@ remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_virtio.o remoteproc-y += remoteproc_elf_loader.o obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o +obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c index b54504ee61f1..32c289c2ba13 100644 --- a/drivers/remoteproc/omap_remoteproc.c +++ b/drivers/remoteproc/omap_remoteproc.c @@ -116,6 +116,9 @@ static int omap_rproc_start(struct rproc *rproc) struct omap_rproc_pdata *pdata = pdev->dev.platform_data; int ret; + if (pdata->set_bootaddr) + pdata->set_bootaddr(rproc->bootaddr); + oproc->nb.notifier_call = omap_rproc_mbox_callback; /* every omap rproc is assigned a mailbox instance for messaging */ diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index d5c2dbfc7443..dd3bfaf1ad40 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -50,6 +50,18 @@ typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); /* Unique indices for remoteproc devices */ static DEFINE_IDA(rproc_dev_index); +static const char * const rproc_crash_names[] = { + [RPROC_MMUFAULT] = "mmufault", +}; + +/* translate rproc_crash_type to string */ +static const char *rproc_crash_to_string(enum rproc_crash_type type) +{ + if (type < ARRAY_SIZE(rproc_crash_names)) + return rproc_crash_names[type]; + return "unkown"; +} + /* * This is the IOMMU fault handler we register with the IOMMU API * (when relevant; not all remote processors access memory through @@ -57,18 +69,19 @@ static DEFINE_IDA(rproc_dev_index); * * IOMMU core will invoke this handler whenever the remote processor * will try to access an unmapped device address. - * - * Currently this is mostly a stub, but it will be later used to trigger - * the recovery of the remote processor. */ static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *token) { + struct rproc *rproc = token; + dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags); + rproc_report_crash(rproc, RPROC_MMUFAULT); + /* * Let the iommu core know we're not really handling this fault; - * we just plan to use this as a recovery trigger. + * we just used it as a recovery trigger. */ return -ENOSYS; } @@ -215,8 +228,11 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i) return ret; } - dev_dbg(dev, "vring%d: va %p dma %x size %x idr %d\n", i, va, - dma, size, notifyid); + /* Store largest notifyid */ + rproc->max_notifyid = max(rproc->max_notifyid, notifyid); + + dev_dbg(dev, "vring%d: va %p dma %llx size %x idr %d\n", i, va, + (unsigned long long)dma, size, notifyid); rvring->va = va; rvring->dma = dma; @@ -256,13 +272,25 @@ rproc_parse_vring(struct rproc_vdev *rvdev, struct fw_rsc_vdev *rsc, int i) return 0; } +static int rproc_max_notifyid(int id, void *p, void *data) +{ + int *maxid = data; + *maxid = max(*maxid, id); + return 0; +} + void rproc_free_vring(struct rproc_vring *rvring) { int size = PAGE_ALIGN(vring_size(rvring->len, rvring->align)); struct rproc *rproc = rvring->rvdev->rproc; + int maxid = 0; dma_free_coherent(rproc->dev.parent, size, rvring->va, rvring->dma); idr_remove(&rproc->notifyids, rvring->notifyid); + + /* Find the largest remaining notifyid */ + idr_for_each(&rproc->notifyids, rproc_max_notifyid, &maxid); + rproc->max_notifyid = maxid; } /** @@ -545,17 +573,10 @@ static int rproc_handle_carveout(struct rproc *rproc, dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n", rsc->da, rsc->pa, rsc->len, rsc->flags); - mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); - if (!mapping) { - dev_err(dev, "kzalloc mapping failed\n"); - return -ENOMEM; - } - carveout = kzalloc(sizeof(*carveout), GFP_KERNEL); if (!carveout) { dev_err(dev, "kzalloc carveout failed\n"); - ret = -ENOMEM; - goto free_mapping; + return -ENOMEM; } va = dma_alloc_coherent(dev->parent, rsc->len, &dma, GFP_KERNEL); @@ -565,7 +586,8 @@ static int rproc_handle_carveout(struct rproc *rproc, goto free_carv; } - dev_dbg(dev, "carveout va %p, dma %x, len 0x%x\n", va, dma, rsc->len); + dev_dbg(dev, "carveout va %p, dma %llx, len 0x%x\n", va, + (unsigned long long)dma, rsc->len); /* * Ok, this is non-standard. @@ -585,11 +607,18 @@ static int rproc_handle_carveout(struct rproc *rproc, * physical address in this case. */ if (rproc->domain) { + mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); + if (!mapping) { + dev_err(dev, "kzalloc mapping failed\n"); + ret = -ENOMEM; + goto dma_free; + } + ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len, rsc->flags); if (ret) { dev_err(dev, "iommu_map failed: %d\n", ret); - goto dma_free; + goto free_mapping; } /* @@ -603,7 +632,8 @@ static int rproc_handle_carveout(struct rproc *rproc, mapping->len = rsc->len; list_add_tail(&mapping->node, &rproc->mappings); - dev_dbg(dev, "carveout mapped 0x%x to 0x%x\n", rsc->da, dma); + dev_dbg(dev, "carveout mapped 0x%x to 0x%llx\n", + rsc->da, (unsigned long long)dma); } /* @@ -634,12 +664,12 @@ static int rproc_handle_carveout(struct rproc *rproc, return 0; +free_mapping: + kfree(mapping); dma_free: dma_free_coherent(dev->parent, rsc->len, va, dma); free_carv: kfree(carveout); -free_mapping: - kfree(mapping); return ret; } @@ -871,6 +901,91 @@ out: complete_all(&rproc->firmware_loading_complete); } +static int rproc_add_virtio_devices(struct rproc *rproc) +{ + int ret; + + /* rproc_del() calls must wait until async loader completes */ + init_completion(&rproc->firmware_loading_complete); + + /* + * We must retrieve early virtio configuration info from + * the firmware (e.g. whether to register a virtio device, + * what virtio features does it support, ...). + * + * We're initiating an asynchronous firmware loading, so we can + * be built-in kernel code, without hanging the boot process. + */ + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + rproc->firmware, &rproc->dev, GFP_KERNEL, + rproc, rproc_fw_config_virtio); + if (ret < 0) { + dev_err(&rproc->dev, "request_firmware_nowait err: %d\n", ret); + complete_all(&rproc->firmware_loading_complete); + } + + return ret; +} + +/** + * rproc_trigger_recovery() - recover a remoteproc + * @rproc: the remote processor + * + * The recovery is done by reseting all the virtio devices, that way all the + * rpmsg drivers will be reseted along with the remote processor making the + * remoteproc functional again. + * + * This function can sleep, so it cannot be called from atomic context. + */ +int rproc_trigger_recovery(struct rproc *rproc) +{ + struct rproc_vdev *rvdev, *rvtmp; + + dev_err(&rproc->dev, "recovering %s\n", rproc->name); + + init_completion(&rproc->crash_comp); + + /* clean up remote vdev entries */ + list_for_each_entry_safe(rvdev, rvtmp, &rproc->rvdevs, node) + rproc_remove_virtio_dev(rvdev); + + /* wait until there is no more rproc users */ + wait_for_completion(&rproc->crash_comp); + + return rproc_add_virtio_devices(rproc); +} + +/** + * rproc_crash_handler_work() - handle a crash + * + * This function needs to handle everything related to a crash, like cpu + * registers and stack dump, information to help to debug the fatal error, etc. + */ +static void rproc_crash_handler_work(struct work_struct *work) +{ + struct rproc *rproc = container_of(work, struct rproc, crash_handler); + struct device *dev = &rproc->dev; + + dev_dbg(dev, "enter %s\n", __func__); + + mutex_lock(&rproc->lock); + + if (rproc->state == RPROC_CRASHED || rproc->state == RPROC_OFFLINE) { + /* handle only the first crash detected */ + mutex_unlock(&rproc->lock); + return; + } + + rproc->state = RPROC_CRASHED; + dev_err(dev, "handling crash #%u in %s\n", ++rproc->crash_cnt, + rproc->name); + + mutex_unlock(&rproc->lock); + + if (!rproc->recovery_disabled) + rproc_trigger_recovery(rproc); +} + /** * rproc_boot() - boot a remote processor * @rproc: handle of a remote processor @@ -992,6 +1107,10 @@ void rproc_shutdown(struct rproc *rproc) rproc_disable_iommu(rproc); + /* if in crash state, unlock crash handler */ + if (rproc->state == RPROC_CRASHED) + complete_all(&rproc->crash_comp); + rproc->state = RPROC_OFFLINE; dev_info(dev, "stopped remote processor %s\n", rproc->name); @@ -1026,7 +1145,7 @@ EXPORT_SYMBOL(rproc_shutdown); int rproc_add(struct rproc *rproc) { struct device *dev = &rproc->dev; - int ret = 0; + int ret; ret = device_add(dev); if (ret < 0) @@ -1040,26 +1159,7 @@ int rproc_add(struct rproc *rproc) /* create debugfs entries */ rproc_create_debug_dir(rproc); - /* rproc_del() calls must wait until async loader completes */ - init_completion(&rproc->firmware_loading_complete); - - /* - * We must retrieve early virtio configuration info from - * the firmware (e.g. whether to register a virtio device, - * what virtio features does it support, ...). - * - * We're initiating an asynchronous firmware loading, so we can - * be built-in kernel code, without hanging the boot process. - */ - ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, - rproc->firmware, dev, GFP_KERNEL, - rproc, rproc_fw_config_virtio); - if (ret < 0) { - dev_err(dev, "request_firmware_nowait failed: %d\n", ret); - complete_all(&rproc->firmware_loading_complete); - } - - return ret; + return rproc_add_virtio_devices(rproc); } EXPORT_SYMBOL(rproc_add); @@ -1165,6 +1265,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, INIT_LIST_HEAD(&rproc->traces); INIT_LIST_HEAD(&rproc->rvdevs); + INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work); + init_completion(&rproc->crash_comp); + rproc->state = RPROC_OFFLINE; return rproc; @@ -1221,6 +1324,32 @@ int rproc_del(struct rproc *rproc) } EXPORT_SYMBOL(rproc_del); +/** + * rproc_report_crash() - rproc crash reporter function + * @rproc: remote processor + * @type: crash type + * + * This function must be called every time a crash is detected by the low-level + * drivers implementing a specific remoteproc. This should not be called from a + * non-remoteproc driver. + * + * This function can be called from atomic/interrupt context. + */ +void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type) +{ + if (!rproc) { + pr_err("NULL rproc pointer\n"); + return; + } + + dev_err(&rproc->dev, "crash detected in %s: type %s\n", + rproc->name, rproc_crash_to_string(type)); + + /* create a new task to handle the error */ + schedule_work(&rproc->crash_handler); +} +EXPORT_SYMBOL(rproc_report_crash); + static int __init remoteproc_init(void) { rproc_init_debugfs(); diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 03833850f214..157a57309601 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c @@ -28,6 +28,9 @@ #include <linux/debugfs.h> #include <linux/remoteproc.h> #include <linux/device.h> +#include <linux/uaccess.h> + +#include "remoteproc_internal.h" /* remoteproc debugfs parent dir */ static struct dentry *rproc_dbg; @@ -79,7 +82,7 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state; - i = snprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state], + i = scnprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state], rproc->state); return simple_read_from_buffer(userbuf, count, ppos, buf, i); @@ -100,7 +103,7 @@ static ssize_t rproc_name_read(struct file *filp, char __user *userbuf, char buf[100]; int i; - i = snprintf(buf, sizeof(buf), "%.98s\n", rproc->name); + i = scnprintf(buf, sizeof(buf), "%.98s\n", rproc->name); return simple_read_from_buffer(userbuf, count, ppos, buf, i); } @@ -111,6 +114,82 @@ static const struct file_operations rproc_name_ops = { .llseek = generic_file_llseek, }; +/* expose recovery flag via debugfs */ +static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; + + return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); +} + +/* + * By writing to the 'recovery' debugfs entry, we control the behavior of the + * recovery mechanism dynamically. The default value of this entry is "enabled". + * + * The 'recovery' debugfs entry supports these commands: + * + * enabled: When enabled, the remote processor will be automatically + * recovered whenever it crashes. Moreover, if the remote + * processor crashes while recovery is disabled, it will + * be automatically recovered too as soon as recovery is enabled. + * + * disabled: When disabled, a remote processor will remain in a crashed + * state if it crashes. This is useful for debugging purposes; + * without it, debugging a crash is substantially harder. + * + * recover: This function will trigger an immediate recovery if the + * remote processor is in a crashed state, without changing + * or checking the recovery state (enabled/disabled). + * This is useful during debugging sessions, when one expects + * additional crashes to happen after enabling recovery. In this + * case, enabling recovery will make it hard to debug subsequent + * crashes, so it's recommended to keep recovery disabled, and + * instead use the "recover" command as needed. + */ +static ssize_t +rproc_recovery_write(struct file *filp, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rproc *rproc = filp->private_data; + char buf[10]; + int ret; + + if (count > sizeof(buf)) + return count; + + ret = copy_from_user(buf, user_buf, count); + if (ret) + return -EFAULT; + + /* remove end of line */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + if (!strncmp(buf, "enabled", count)) { + rproc->recovery_disabled = false; + /* if rproc has crashed, trigger recovery */ + if (rproc->state == RPROC_CRASHED) + rproc_trigger_recovery(rproc); + } else if (!strncmp(buf, "disabled", count)) { + rproc->recovery_disabled = true; + } else if (!strncmp(buf, "recover", count)) { + /* if rproc has crashed, trigger recovery */ + if (rproc->state == RPROC_CRASHED) + rproc_trigger_recovery(rproc); + } + + return count; +} + +static const struct file_operations rproc_recovery_ops = { + .read = rproc_recovery_read, + .write = rproc_recovery_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + void rproc_remove_trace_file(struct dentry *tfile) { debugfs_remove(tfile); @@ -154,6 +233,8 @@ void rproc_create_debug_dir(struct rproc *rproc) rproc, &rproc_name_ops); debugfs_create_file("state", 0400, rproc->dbg_dir, rproc, &rproc_state_ops); + debugfs_create_file("recovery", 0400, rproc->dbg_dir, + rproc, &rproc_recovery_ops); } void __init rproc_init_debugfs(void) diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h index a690ebe7aa51..7bb66482d061 100644 --- a/drivers/remoteproc/remoteproc_internal.h +++ b/drivers/remoteproc/remoteproc_internal.h @@ -63,6 +63,7 @@ void rproc_free_vring(struct rproc_vring *rvring); int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); void *rproc_da_to_va(struct rproc *rproc, u64 da, int len); +int rproc_trigger_recovery(struct rproc *rproc); static inline int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw) diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c new file mode 100644 index 000000000000..a7743c069339 --- /dev/null +++ b/drivers/remoteproc/ste_modem_rproc.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) ST-Ericsson AB 2012 + * Author: Sjur Brændeland <sjur.brandeland@stericsson.com> + * License terms: GNU General Public License (GPL), version 2 + */ + +#include <linux/module.h> +#include <linux/dma-mapping.h> +#include <linux/remoteproc.h> +#include <linux/ste_modem_shm.h> +#include "remoteproc_internal.h" + +#define SPROC_FW_SIZE (50 * 4096) +#define SPROC_MAX_TOC_ENTRIES 32 +#define SPROC_MAX_NOTIFY_ID 14 +#define SPROC_RESOURCE_NAME "rsc-table" +#define SPROC_MODEM_NAME "ste-modem" +#define SPROC_MODEM_FIRMWARE SPROC_MODEM_NAME "-fw.bin" + +#define sproc_dbg(sproc, fmt, ...) \ + dev_dbg(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__) +#define sproc_err(sproc, fmt, ...) \ + dev_err(&sproc->mdev->pdev.dev, fmt, ##__VA_ARGS__) + +/* STE-modem control structure */ +struct sproc { + struct rproc *rproc; + struct ste_modem_device *mdev; + int error; + void *fw_addr; + size_t fw_size; + dma_addr_t fw_dma_addr; +}; + +/* STE-Modem firmware entry */ +struct ste_toc_entry { + __le32 start; + __le32 size; + __le32 flags; + __le32 entry_point; + __le32 load_addr; + char name[12]; +}; + +/* + * The Table Of Content is located at the start of the firmware image and + * at offset zero in the shared memory region. The resource table typically + * contains the initial boot image (boot strap) and other information elements + * such as remoteproc resource table. Each entry is identified by a unique + * name. + */ +struct ste_toc { + struct ste_toc_entry table[SPROC_MAX_TOC_ENTRIES]; +}; + +/* Loads the firmware to shared memory. */ +static int sproc_load_segments(struct rproc *rproc, const struct firmware *fw) +{ + struct sproc *sproc = rproc->priv; + + memcpy(sproc->fw_addr, fw->data, fw->size); + + return 0; +} + +/* Find the entry for resource table in the Table of Content */ +static struct ste_toc_entry *sproc_find_rsc_entry(const struct firmware *fw) +{ + int i; + struct ste_toc *toc; + + if (!fw) + return NULL; + + toc = (void *)fw->data; + + /* Search the table for the resource table */ + for (i = 0; i < SPROC_MAX_TOC_ENTRIES && + toc->table[i].start != 0xffffffff; i++) { + + if (!strncmp(toc->table[i].name, SPROC_RESOURCE_NAME, + sizeof(toc->table[i].name))) { + if (toc->table[i].start > fw->size) + return NULL; + return &toc->table[i]; + } + } + + return NULL; +} + +/* Find the resource table inside the remote processor's firmware. */ +static struct resource_table * +sproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw, + int *tablesz) +{ + struct sproc *sproc = rproc->priv; + struct resource_table *table; + struct ste_toc_entry *entry; + + entry = sproc_find_rsc_entry(fw); + if (!entry) { + sproc_err(sproc, "resource table not found in fw\n"); + return NULL; + } + + table = (void *)(fw->data + entry->start); + + /* sanity check size and offset of resource table */ + if (entry->start > SPROC_FW_SIZE || + entry->size > SPROC_FW_SIZE || + fw->size > SPROC_FW_SIZE || + entry->start + entry->size > fw->size || + sizeof(struct resource_table) > entry->size) { + sproc_err(sproc, "bad size of fw or resource table\n"); + return NULL; + } + + /* we don't support any version beyond the first */ + if (table->ver != 1) { + sproc_err(sproc, "unsupported fw ver: %d\n", table->ver); + return NULL; + } + + /* make sure reserved bytes are zeroes */ + if (table->reserved[0] || table->reserved[1]) { + sproc_err(sproc, "non zero reserved bytes\n"); + return NULL; + } + + /* make sure the offsets array isn't truncated */ + if (table->num > SPROC_MAX_TOC_ENTRIES || + table->num * sizeof(table->offset[0]) + + sizeof(struct resource_table) > entry->size) { + sproc_err(sproc, "resource table incomplete\n"); + return NULL; + } + + /* If the fw size has grown, release the previous fw allocation */ + if (SPROC_FW_SIZE < fw->size) { + sproc_err(sproc, "Insufficient space for fw (%d < %zd)\n", + SPROC_FW_SIZE, fw->size); + return NULL; + } + + sproc->fw_size = fw->size; + *tablesz = entry->size; + + return table; +} + +/* STE modem firmware handler operations */ +const struct rproc_fw_ops sproc_fw_ops = { + .load = sproc_load_segments, + .find_rsc_table = sproc_find_rsc_table, +}; + +/* Kick the modem with specified notification id */ +static void sproc_kick(struct rproc *rproc, int vqid) +{ + struct sproc *sproc = rproc->priv; + + sproc_dbg(sproc, "kick vqid:%d\n", vqid); + + /* + * We need different notification IDs for RX and TX so add + * an offset on TX notification IDs. + */ + sproc->mdev->ops.kick(sproc->mdev, vqid + SPROC_MAX_NOTIFY_ID); +} + +/* Received a kick from a modem, kick the virtqueue */ +static void sproc_kick_callback(struct ste_modem_device *mdev, int vqid) +{ + struct sproc *sproc = mdev->drv_data; + + if (rproc_vq_interrupt(sproc->rproc, vqid) == IRQ_NONE) + sproc_dbg(sproc, "no message was found in vqid %d\n", vqid); +} + +struct ste_modem_dev_cb sproc_dev_cb = { + .kick = sproc_kick_callback, +}; + +/* Start the STE modem */ +static int sproc_start(struct rproc *rproc) +{ + struct sproc *sproc = rproc->priv; + int i, err; + + sproc_dbg(sproc, "start ste-modem\n"); + + /* Sanity test the max_notifyid */ + if (rproc->max_notifyid > SPROC_MAX_NOTIFY_ID) { + sproc_err(sproc, "Notification IDs too high:%d\n", + rproc->max_notifyid); + return -EINVAL; + } + + /* Subscribe to notifications */ + for (i = 0; i < rproc->max_notifyid; i++) { + err = sproc->mdev->ops.kick_subscribe(sproc->mdev, i); + if (err) { + sproc_err(sproc, + "subscription of kicks failed:%d\n", err); + return err; + } + } + + /* Request modem start-up*/ + return sproc->mdev->ops.power(sproc->mdev, true); +} + +/* Stop the STE modem */ +static int sproc_stop(struct rproc *rproc) +{ + struct sproc *sproc = rproc->priv; + sproc_dbg(sproc, "stop ste-modem\n"); + + return sproc->mdev->ops.power(sproc->mdev, false); +} + +static struct rproc_ops sproc_ops = { + .start = sproc_start, + .stop = sproc_stop, + .kick = sproc_kick, +}; + +/* STE modem device is unregistered */ +static int sproc_drv_remove(struct platform_device *pdev) +{ + struct ste_modem_device *mdev = + container_of(pdev, struct ste_modem_device, pdev); + struct sproc *sproc = mdev->drv_data; + + sproc_dbg(sproc, "remove ste-modem\n"); + + /* Reset device callback functions */ + sproc->mdev->ops.setup(sproc->mdev, NULL); + + /* Unregister as remoteproc device */ + rproc_del(sproc->rproc); + rproc_put(sproc->rproc); + + mdev->drv_data = NULL; + + return 0; +} + +/* Handle probe of a modem device */ +static int sproc_probe(struct platform_device *pdev) +{ + struct ste_modem_device *mdev = + container_of(pdev, struct ste_modem_device, pdev); + struct sproc *sproc; + struct rproc *rproc; + int err; + + dev_dbg(&mdev->pdev.dev, "probe ste-modem\n"); + + if (!mdev->ops.setup || !mdev->ops.kick || !mdev->ops.kick_subscribe || + !mdev->ops.power) { + dev_err(&mdev->pdev.dev, "invalid mdev ops\n"); + return -EINVAL; + } + + rproc = rproc_alloc(&mdev->pdev.dev, mdev->pdev.name, &sproc_ops, + SPROC_MODEM_FIRMWARE, sizeof(*sproc)); + if (!rproc) + return -ENOMEM; + + sproc = rproc->priv; + sproc->mdev = mdev; + sproc->rproc = rproc; + mdev->drv_data = sproc; + + /* Provide callback functions to modem device */ + sproc->mdev->ops.setup(sproc->mdev, &sproc_dev_cb); + + /* Set the STE-modem specific firmware handler */ + rproc->fw_ops = &sproc_fw_ops; + + /* + * STE-modem requires the firmware to be located + * at the start of the shared memory region. So we need to + * reserve space for firmware at the start. + */ + sproc->fw_addr = dma_alloc_coherent(rproc->dev.parent, SPROC_FW_SIZE, + &sproc->fw_dma_addr, + GFP_KERNEL); + if (!sproc->fw_addr) { + sproc_err(sproc, "Cannot allocate memory for fw\n"); + err = -ENOMEM; + goto free_rproc; + } + + /* Register as a remoteproc device */ + err = rproc_add(rproc); + if (err) + goto free_rproc; + + return 0; + +free_rproc: + /* Reset device data upon error */ + mdev->drv_data = NULL; + rproc_put(rproc); + return err; +} + +static struct platform_driver sproc_driver = { + .driver = { + .name = SPROC_MODEM_NAME, + .owner = THIS_MODULE, + }, + .probe = sproc_probe, + .remove = sproc_drv_remove, +}; + +module_platform_driver(sproc_driver); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("STE Modem driver using the Remote Processor Framework"); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index fabc99a75c65..e069f176a82d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -19,7 +19,6 @@ if RTC_CLASS config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" - depends on RTC_CLASS = y default y help If you say yes here, the system time (wall clock) will be set using @@ -51,7 +50,6 @@ config RTC_HCTOSYS_DEVICE config RTC_DEBUG bool "RTC debug support" - depends on RTC_CLASS = y help Say yes here to enable debugging support in the RTC framework and individual RTC drivers. @@ -61,7 +59,6 @@ comment "RTC interfaces" config RTC_INTF_SYSFS boolean "/sys/class/rtc/rtcN (sysfs)" depends on SYSFS - default RTC_CLASS help Say yes here if you want to use your RTCs using sysfs interfaces, /sys/class/rtc/rtc0 through /sys/.../rtcN. @@ -69,19 +66,19 @@ config RTC_INTF_SYSFS If unsure, say Y. config RTC_INTF_PROC - boolean "/proc/driver/rtc (procfs for rtc0)" + boolean "/proc/driver/rtc (procfs for rtcN)" depends on PROC_FS - default RTC_CLASS help - Say yes here if you want to use your first RTC through the proc - interface, /proc/driver/rtc. Other RTCs will not be available - through that API. + Say yes here if you want to use your system clock RTC through + the proc interface, /proc/driver/rtc. + Other RTCs will not be available through that API. + If there is no RTC for the system clock, then the first RTC(rtc0) + is used by default. If unsure, say Y. config RTC_INTF_DEV boolean "/dev/rtcN (character devices)" - default RTC_CLASS help Say yes here if you want to use your RTCs using the /dev interfaces, which "udev" sets up as /dev/rtc0 through @@ -127,7 +124,7 @@ if I2C config RTC_DRV_88PM860X tristate "Marvell 88PM860x" - depends on RTC_CLASS && I2C && MFD_88PM860X + depends on I2C && MFD_88PM860X help If you say yes here you get support for RTC function in Marvell 88PM860x chips. @@ -137,7 +134,7 @@ config RTC_DRV_88PM860X config RTC_DRV_88PM80X tristate "Marvell 88PM80x" - depends on RTC_CLASS && I2C && MFD_88PM800 + depends on I2C && MFD_88PM800 help If you say yes here you get support for RTC function in Marvell 88PM80x chips. @@ -165,7 +162,7 @@ config RTC_DRV_DS1307 config RTC_DRV_DS1374 tristate "Dallas/Maxim DS1374" - depends on RTC_CLASS && I2C + depends on I2C help If you say yes here you get support for Dallas Semiconductor DS1374 real-time clock chips. If an interrupt is associated @@ -185,7 +182,7 @@ config RTC_DRV_DS1672 config RTC_DRV_DS3232 tristate "Dallas/Maxim DS3232" - depends on RTC_CLASS && I2C + depends on I2C help If you say yes here you get support for Dallas Semiconductor DS3232 real-time clock chips. If an interrupt is associated @@ -203,6 +200,16 @@ config RTC_DRV_MAX6900 This driver can also be built as a module. If so, the module will be called rtc-max6900. +config RTC_DRV_MAX8907 + tristate "Maxim MAX8907" + depends on MFD_MAX8907 + help + If you say yes here you will get support for the + RTC of Maxim MAX8907 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8907. + config RTC_DRV_MAX8925 tristate "Maxim MAX8925" depends on MFD_MAX8925 @@ -325,7 +332,7 @@ config RTC_DRV_TWL92330 config RTC_DRV_TWL4030 tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" - depends on RTC_CLASS && TWL4030_CORE + depends on TWL4030_CORE help If you say yes here you get support for the RTC on the TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms. @@ -333,6 +340,26 @@ config RTC_DRV_TWL4030 This driver can also be built as a module. If so, the module will be called rtc-twl. +config RTC_DRV_TPS65910 + tristate "TI TPS65910 RTC driver" + depends on RTC_CLASS && MFD_TPS65910 + help + If you say yes here you get support for the RTC on the + TPS65910 chips. + + This driver can also be built as a module. If so, the module + will be called rtc-tps65910. + +config RTC_DRV_RC5T583 + tristate "RICOH 5T583 RTC driver" + depends on MFD_RC5T583 + help + If you say yes here you get support for the RTC on the + RICOH 5T583 chips. + + This driver can also be built as a module. If so, the module + will be called rtc-rc5t583. + config RTC_DRV_S35390A tristate "Seiko Instruments S-35390A" select BITREVERSE @@ -538,7 +565,6 @@ config RTC_DRV_DS1302 config RTC_DRV_DS1511 tristate "Dallas DS1511" - depends on RTC_CLASS help If you say yes here you get support for the Dallas DS1511 timekeeping/watchdog chip. @@ -583,7 +609,6 @@ config RTC_DRV_EFI config RTC_DRV_STK17TA8 tristate "Simtek STK17TA8" - depends on RTC_CLASS help If you say yes here you get support for the Simtek STK17TA8 timekeeping chip. @@ -658,6 +683,15 @@ config RTC_DRV_V3020 This driver can also be built as a module. If so, the module will be called rtc-v3020. +config RTC_DRV_DS2404 + tristate "Dallas DS2404" + help + If you say yes here you get support for the + Dallas DS2404 RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-ds2404. + config RTC_DRV_WM831X tristate "Wolfson Microelectronics WM831x RTC" depends on MFD_WM831X @@ -704,6 +738,7 @@ config RTC_DRV_AB3100 config RTC_DRV_AB8500 tristate "ST-Ericsson AB8500 RTC" depends on AB8500_CORE + select RTC_INTF_DEV select RTC_INTF_DEV_UIE_EMUL help Select this to enable the ST-Ericsson AB8500 power management IC RTC @@ -711,7 +746,7 @@ config RTC_DRV_AB8500 config RTC_DRV_NUC900 tristate "NUC910/NUC920 RTC driver" - depends on RTC_CLASS && ARCH_W90X900 + depends on ARCH_W90X900 help If you say yes here you get support for the RTC subsystem of the NUC910/NUC920 used in embedded systems. @@ -731,7 +766,6 @@ config RTC_DRV_DAVINCI config RTC_DRV_IMXDI tristate "Freescale IMX DryIce Real Time Clock" depends on SOC_IMX25 - depends on RTC_CLASS help Support for Freescale IMX DryIce RTC @@ -791,7 +825,7 @@ config RTC_DRV_SA1100 config RTC_DRV_SH tristate "SuperH On-Chip RTC" - depends on RTC_CLASS && SUPERH && HAVE_CLK + depends on SUPERH && HAVE_CLK help Say Y here to enable support for the on-chip RTC found in most SuperH processors. @@ -1023,7 +1057,6 @@ config RTC_DRV_MPC5121 config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 SoC" - depends on RTC_CLASS depends on MACH_JZ4740 help If you say yes here you get support for the Ingenic JZ4740 SoC RTC @@ -1053,7 +1086,7 @@ config RTC_DRV_PM8XXX config RTC_DRV_TEGRA tristate "NVIDIA Tegra Internal RTC driver" - depends on RTC_CLASS && ARCH_TEGRA + depends on ARCH_TEGRA help If you say yes here you get support for the Tegra 200 series internal RTC module. @@ -1090,7 +1123,6 @@ config RTC_DRV_LOONGSON1 config RTC_DRV_MXC tristate "Freescale MXC Real Time Clock" depends on ARCH_MXC - depends on RTC_CLASS help If you say yes here you get support for the Freescale MXC RTC module. @@ -1098,4 +1130,15 @@ config RTC_DRV_MXC This driver can also be built as a module, if so, the module will be called "rtc-mxc". +config RTC_DRV_SNVS + tristate "Freescale SNVS RTC support" + depends on HAS_IOMEM + depends on OF + help + If you say yes here you get support for the Freescale SNVS + Low Power (LP) RTC module. + + This driver can also be built as a module, if so, the module + will be called "rtc-snvs". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 0d5b2b66f90d..56297f0fd388 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o +obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o @@ -64,6 +65,7 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o +obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o @@ -85,6 +87,7 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o +obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o @@ -96,6 +99,7 @@ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o +obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o @@ -105,6 +109,7 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o +obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index dc4c2748bbc3..f8a0aab218cb 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -31,8 +31,12 @@ static void rtc_device_release(struct device *dev) kfree(rtc); } -#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) +#ifdef CONFIG_RTC_HCTOSYS_DEVICE +/* Result of the last RTC to system clock attempt. */ +int rtc_hctosys_ret = -ENODEV; +#endif +#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) /* * On suspend(), measure the delta between one RTC and the * system's wall clock; restore it on resume(). @@ -84,6 +88,7 @@ static int rtc_resume(struct device *dev) struct timespec new_system, new_rtc; struct timespec sleep_time; + rtc_hctosys_ret = -ENODEV; if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) return 0; @@ -117,6 +122,7 @@ static int rtc_resume(struct device *dev) if (sleep_time.tv_sec >= 0) timekeeping_inject_sleeptime(&sleep_time); + rtc_hctosys_ret = 0; return 0; } @@ -238,6 +244,7 @@ void rtc_device_unregister(struct rtc_device *rtc) rtc_proc_del_device(rtc); device_unregister(&rtc->dev); rtc->ops = NULL; + ida_simple_remove(&rtc_ida, rtc->id); mutex_unlock(&rtc->ops_lock); put_device(&rtc->dev); } diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c index bc90b091f195..4aa60d74004e 100644 --- a/drivers/rtc/hctosys.c +++ b/drivers/rtc/hctosys.c @@ -22,8 +22,6 @@ * the best guess is to add 0.5s. */ -int rtc_hctosys_ret = -ENODEV; - static int __init rtc_hctosys(void) { int err = -ENODEV; @@ -56,7 +54,7 @@ static int __init rtc_hctosys(void) rtc_tm_to_time(&tm, &tv.tv_sec); - do_settimeofday(&tv); + err = do_settimeofday(&tv); dev_info(rtc->dev.parent, "setting system clock to " diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index feddefc42109..de9e854b326a 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/mutex.h> @@ -284,6 +285,28 @@ out: } #endif +#ifdef CONFIG_OF +static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev, + struct pm860x_rtc_info *info) +{ + struct device_node *np = pdev->dev.parent->of_node; + int ret; + if (!np) + return -ENODEV; + np = of_find_node_by_name(np, "rtc"); + if (!np) { + dev_err(&pdev->dev, "failed to find rtc node\n"); + return -ENODEV; + } + ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc); + if (ret) + info->vrtc = 0; + return 0; +} +#else +#define pm860x_rtc_dt_init(x, y) (-1) +#endif + static int __devinit pm860x_rtc_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -294,8 +317,6 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) int ret; pdata = pdev->dev.platform_data; - if (pdata == NULL) - dev_warn(&pdev->dev, "No platform data!\n"); info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); if (!info) @@ -345,9 +366,11 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) } } rtc_tm_to_time(&tm, &ticks); - if (pdata && pdata->sync) { - pdata->sync(ticks); - info->sync = pdata->sync; + if (pm860x_rtc_dt_init(pdev, info)) { + if (pdata && pdata->sync) { + pdata->sync(ticks); + info->sync = pdata->sync; + } } info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, @@ -366,10 +389,12 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) #ifdef VRTC_CALIBRATION /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ - if (pdata && pdata->vrtc) - info->vrtc = pdata->vrtc & 0x3; - else - info->vrtc = 1; + if (pm860x_rtc_dt_init(pdev, info)) { + if (pdata && pdata->vrtc) + info->vrtc = pdata->vrtc & 0x3; + else + info->vrtc = 1; + } pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); /* calibrate VRTC */ diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 1dd61f402b04..2dfe7a2fb998 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -473,18 +473,7 @@ static struct platform_driver at91_rtc_driver = { }, }; -static int __init at91_rtc_init(void) -{ - return platform_driver_register(&at91_rtc_driver); -} -module_init(at91_rtc_init); - -static void __exit at91_rtc_exit(void) -{ - platform_driver_unregister(&at91_rtc_driver); -} -module_exit(at91_rtc_exit); - +module_platform_driver(at91_rtc_driver); MODULE_AUTHOR("Michel Benoit"); MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x"); diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 76b2156d3c62..c8115b83e5ab 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -276,8 +276,7 @@ static void coh901331_shutdown(struct platform_device *pdev) clk_enable(rtap->clk); writel(0, rtap->virtbase + COH901331_IRQ_MASK); - clk_disable(rtap->clk); - clk_unprepare(rtap->clk); + clk_disable_unprepare(rtap->clk); } static struct platform_driver coh901331_driver = { diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 7fa67d0df172..45d65c0b3a85 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -37,8 +37,17 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) unsigned char buf[4]; struct i2c_msg msgs[] = { - {client->addr, 0, 1, &addr}, /* setup read ptr */ - {client->addr, I2C_M_RD, 4, buf}, /* read date */ + {/* setup read ptr */ + .addr = client->addr, + .len = 1, + .buf = &addr + }, + {/* read date */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 4, + .buf = buf + }, }; /* read date registers */ @@ -99,8 +108,17 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status) unsigned char addr = DS1672_REG_CONTROL; struct i2c_msg msgs[] = { - {client->addr, 0, 1, &addr}, /* setup read ptr */ - {client->addr, I2C_M_RD, 1, status}, /* read control */ + {/* setup read ptr */ + .addr = client->addr, + .len = 1, + .buf = &addr + }, + {/* read control */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = status + }, }; /* read control register */ diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c new file mode 100644 index 000000000000..5ea9df7c8c31 --- /dev/null +++ b/drivers/rtc/rtc-ds2404.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org> + * + * 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/platform_device.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/rtc.h> +#include <linux/types.h> +#include <linux/bcd.h> +#include <linux/rtc-ds2404.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +#include <linux/io.h> + +#define DS2404_STATUS_REG 0x200 +#define DS2404_CONTROL_REG 0x201 +#define DS2404_RTC_REG 0x202 + +#define DS2404_WRITE_SCRATCHPAD_CMD 0x0f +#define DS2404_READ_SCRATCHPAD_CMD 0xaa +#define DS2404_COPY_SCRATCHPAD_CMD 0x55 +#define DS2404_READ_MEMORY_CMD 0xf0 + +struct ds2404; + +struct ds2404_chip_ops { + int (*map_io)(struct ds2404 *chip, struct platform_device *pdev, + struct ds2404_platform_data *pdata); + void (*unmap_io)(struct ds2404 *chip); +}; + +#define DS2404_RST 0 +#define DS2404_CLK 1 +#define DS2404_DQ 2 + +struct ds2404_gpio { + const char *name; + unsigned int gpio; +}; + +struct ds2404 { + struct ds2404_gpio *gpio; + struct ds2404_chip_ops *ops; + struct rtc_device *rtc; +}; + +static struct ds2404_gpio ds2404_gpio[] = { + { "RTC RST", 0 }, + { "RTC CLK", 0 }, + { "RTC DQ", 0 }, +}; + +static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev, + struct ds2404_platform_data *pdata) +{ + int i, err; + + ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst; + ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk; + ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq; + + for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) { + err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name); + if (err) { + printk(KERN_ERR "error mapping gpio %s: %d\n", + ds2404_gpio[i].name, err); + goto err_request; + } + if (i != DS2404_DQ) + gpio_direction_output(ds2404_gpio[i].gpio, 1); + } + + chip->gpio = ds2404_gpio; + return 0; + +err_request: + while (--i >= 0) + gpio_free(ds2404_gpio[i].gpio); + return err; +} + +static void ds2404_gpio_unmap(struct ds2404 *chip) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) + gpio_free(ds2404_gpio[i].gpio); +} + +static struct ds2404_chip_ops ds2404_gpio_ops = { + .map_io = ds2404_gpio_map, + .unmap_io = ds2404_gpio_unmap, +}; + +static void ds2404_reset(struct device *dev) +{ + gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0); + udelay(1000); + gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1); + gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0); + udelay(10); +} + +static void ds2404_write_byte(struct device *dev, u8 byte) +{ + int i; + + gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1); + for (i = 0; i < 8; i++) { + gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i)); + udelay(10); + gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); + udelay(10); + gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + udelay(10); + } +} + +static u8 ds2404_read_byte(struct device *dev) +{ + int i; + u8 ret = 0; + + gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); + + for (i = 0; i < 8; i++) { + gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0); + udelay(10); + if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) + ret |= 1 << i; + gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1); + udelay(10); + } + return ret; +} + +static void ds2404_read_memory(struct device *dev, u16 offset, + int length, u8 *out) +{ + ds2404_reset(dev); + ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD); + ds2404_write_byte(dev, offset & 0xff); + ds2404_write_byte(dev, (offset >> 8) & 0xff); + while (length--) + *out++ = ds2404_read_byte(dev); +} + +static void ds2404_write_memory(struct device *dev, u16 offset, + int length, u8 *out) +{ + int i; + u8 ta01, ta02, es; + + ds2404_reset(dev); + ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD); + ds2404_write_byte(dev, offset & 0xff); + ds2404_write_byte(dev, (offset >> 8) & 0xff); + + for (i = 0; i < length; i++) + ds2404_write_byte(dev, out[i]); + + ds2404_reset(dev); + ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD); + + ta01 = ds2404_read_byte(dev); + ta02 = ds2404_read_byte(dev); + es = ds2404_read_byte(dev); + + for (i = 0; i < length; i++) { + if (out[i] != ds2404_read_byte(dev)) { + printk(KERN_ERR "read invalid data\n"); + return; + } + } + + ds2404_reset(dev); + ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD); + ds2404_write_byte(dev, ta01); + ds2404_write_byte(dev, ta02); + ds2404_write_byte(dev, es); + + gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio); + while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio)) + ; +} + +static void ds2404_enable_osc(struct device *dev) +{ + u8 in[1] = { 0x10 }; /* enable oscillator */ + ds2404_write_memory(dev, 0x201, 1, in); +} + +static int ds2404_read_time(struct device *dev, struct rtc_time *dt) +{ + unsigned long time = 0; + + ds2404_read_memory(dev, 0x203, 4, (u8 *)&time); + time = le32_to_cpu(time); + + rtc_time_to_tm(time, dt); + return rtc_valid_tm(dt); +} + +static int ds2404_set_mmss(struct device *dev, unsigned long secs) +{ + u32 time = cpu_to_le32(secs); + ds2404_write_memory(dev, 0x203, 4, (u8 *)&time); + return 0; +} + +static const struct rtc_class_ops ds2404_rtc_ops = { + .read_time = ds2404_read_time, + .set_mmss = ds2404_set_mmss, +}; + +static int rtc_probe(struct platform_device *pdev) +{ + struct ds2404_platform_data *pdata = pdev->dev.platform_data; + struct ds2404 *chip; + int retval = -EBUSY; + + chip = kzalloc(sizeof(struct ds2404), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->ops = &ds2404_gpio_ops; + + retval = chip->ops->map_io(chip, pdev, pdata); + if (retval) + goto err_chip; + + dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n", + chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio, + chip->gpio[DS2404_DQ].gpio); + + platform_set_drvdata(pdev, chip); + + chip->rtc = rtc_device_register("ds2404", + &pdev->dev, &ds2404_rtc_ops, THIS_MODULE); + if (IS_ERR(chip->rtc)) { + retval = PTR_ERR(chip->rtc); + goto err_io; + } + + ds2404_enable_osc(&pdev->dev); + return 0; + +err_io: + chip->ops->unmap_io(chip); +err_chip: + kfree(chip); + return retval; +} + +static int rtc_remove(struct platform_device *dev) +{ + struct ds2404 *chip = platform_get_drvdata(dev); + struct rtc_device *rtc = chip->rtc; + + if (rtc) + rtc_device_unregister(rtc); + + chip->ops->unmap_io(chip); + kfree(chip); + + return 0; +} + +static struct platform_driver rtc_device_driver = { + .probe = rtc_probe, + .remove = rtc_remove, + .driver = { + .name = "ds2404", + .owner = THIS_MODULE, + }, +}; + +static __init int ds2404_init(void) +{ + return platform_driver_register(&rtc_device_driver); +} + +static __exit void ds2404_exit(void) +{ + platform_driver_unregister(&rtc_device_driver); +} + +module_init(ds2404_init); +module_exit(ds2404_exit); + +MODULE_DESCRIPTION("DS2404 RTC"); +MODULE_AUTHOR("Sven Schnelle"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ds2404"); diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c index 0104ea7ebe50..f6c24ce35d36 100644 --- a/drivers/rtc/rtc-em3027.c +++ b/drivers/rtc/rtc-em3027.c @@ -49,8 +49,17 @@ static int em3027_get_time(struct device *dev, struct rtc_time *tm) unsigned char buf[7]; struct i2c_msg msgs[] = { - {client->addr, 0, 1, &addr}, /* setup read addr */ - {client->addr, I2C_M_RD, 7, buf}, /* read time/date */ + {/* setup read addr */ + .addr = client->addr, + .len = 1, + .buf = &addr + }, + {/* read time/date */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 7, + .buf = buf + }, }; /* read time/date registers */ @@ -76,7 +85,9 @@ static int em3027_set_time(struct device *dev, struct rtc_time *tm) unsigned char buf[8]; struct i2c_msg msg = { - client->addr, 0, 8, buf, /* write time/date */ + .addr = client->addr, + .len = 8, + .buf = buf, /* write time/date */ }; buf[0] = EM3027_REG_WATCH_SEC; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index dd2aeee6c66a..26c81f233606 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -68,9 +68,17 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], { u8 reg_addr[1] = { reg }; struct i2c_msg msgs[2] = { - {client->addr, 0, sizeof(reg_addr), reg_addr} - , - {client->addr, I2C_M_RD, len, buf} + { + .addr = client->addr, + .len = sizeof(reg_addr), + .buf = reg_addr + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf + } }; int ret; @@ -90,7 +98,11 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], { u8 i2c_buf[ISL1208_REG_USR2 + 2]; struct i2c_msg msgs[1] = { - {client->addr, 0, len + 1, i2c_buf} + { + .addr = client->addr, + .len = len + 1, + .buf = i2c_buf + } }; int ret; @@ -697,6 +709,7 @@ isl1208_remove(struct i2c_client *client) static const struct i2c_device_id isl1208_id[] = { { "isl1208", 0 }, + { "isl1218", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, isl1208_id); diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 05ab227eeff7..1224182d3eab 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -42,7 +42,7 @@ struct jz4740_rtc { struct rtc_device *rtc; - unsigned int irq; + int irq; spinlock_t lock; }; diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 4e0f84af99a7..b885bcd08908 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -213,163 +213,14 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) return m41t80_set_datetime(to_i2c_client(dev), tm); } -static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct i2c_client *client = to_i2c_client(dev); - int rc; - - rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); - if (rc < 0) - goto err; - - if (enabled) - rc |= M41T80_ALMON_AFE; - else - rc &= ~M41T80_ALMON_AFE; - - if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0) - goto err; - - return 0; -err: - return -EIO; -} - -static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct i2c_client *client = to_i2c_client(dev); - u8 wbuf[1 + M41T80_ALARM_REG_SIZE]; - u8 *buf = &wbuf[1]; - u8 *reg = buf - M41T80_REG_ALARM_MON; - u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; - struct i2c_msg msgs_in[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = dt_addr, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = M41T80_ALARM_REG_SIZE, - .buf = buf, - }, - }; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1 + M41T80_ALARM_REG_SIZE, - .buf = wbuf, - }, - }; - - if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { - dev_err(&client->dev, "read error\n"); - return -EIO; - } - reg[M41T80_REG_ALARM_MON] &= ~(0x1f | M41T80_ALMON_AFE); - reg[M41T80_REG_ALARM_DAY] = 0; - reg[M41T80_REG_ALARM_HOUR] &= ~(0x3f | 0x80); - reg[M41T80_REG_ALARM_MIN] = 0; - reg[M41T80_REG_ALARM_SEC] = 0; - - wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */ - reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ? - bin2bcd(t->time.tm_sec) : 0x80; - reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ? - bin2bcd(t->time.tm_min) : 0x80; - reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ? - bin2bcd(t->time.tm_hour) : 0x80; - reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ? - bin2bcd(t->time.tm_mday) : 0x80; - if (t->time.tm_mon >= 0) - reg[M41T80_REG_ALARM_MON] |= bin2bcd(t->time.tm_mon + 1); - else - reg[M41T80_REG_ALARM_DAY] |= 0x40; - - if (i2c_transfer(client->adapter, msgs, 1) != 1) { - dev_err(&client->dev, "write error\n"); - return -EIO; - } - - if (t->enabled) { - reg[M41T80_REG_ALARM_MON] |= M41T80_ALMON_AFE; - if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, - reg[M41T80_REG_ALARM_MON]) < 0) { - dev_err(&client->dev, "write error\n"); - return -EIO; - } - } - return 0; -} - -static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) -{ - struct i2c_client *client = to_i2c_client(dev); - u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */ - u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; - u8 *reg = buf - M41T80_REG_ALARM_MON; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = dt_addr, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = M41T80_ALARM_REG_SIZE + 1, - .buf = buf, - }, - }; - - if (i2c_transfer(client->adapter, msgs, 2) < 0) { - dev_err(&client->dev, "read error\n"); - return -EIO; - } - t->time.tm_sec = -1; - t->time.tm_min = -1; - t->time.tm_hour = -1; - t->time.tm_mday = -1; - t->time.tm_mon = -1; - if (!(reg[M41T80_REG_ALARM_SEC] & 0x80)) - t->time.tm_sec = bcd2bin(reg[M41T80_REG_ALARM_SEC] & 0x7f); - if (!(reg[M41T80_REG_ALARM_MIN] & 0x80)) - t->time.tm_min = bcd2bin(reg[M41T80_REG_ALARM_MIN] & 0x7f); - if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80)) - t->time.tm_hour = bcd2bin(reg[M41T80_REG_ALARM_HOUR] & 0x3f); - if (!(reg[M41T80_REG_ALARM_DAY] & 0x80)) - t->time.tm_mday = bcd2bin(reg[M41T80_REG_ALARM_DAY] & 0x3f); - if (!(reg[M41T80_REG_ALARM_DAY] & 0x40)) - t->time.tm_mon = bcd2bin(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1; - t->time.tm_year = -1; - t->time.tm_wday = -1; - t->time.tm_yday = -1; - t->time.tm_isdst = -1; - t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE); - t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF); - return 0; -} - +/* + * XXX - m41t80 alarm functionality is reported broken. + * until it is fixed, don't register alarm functions. + */ static struct rtc_class_ops m41t80_rtc_ops = { .read_time = m41t80_rtc_read_time, .set_time = m41t80_rtc_set_time, - /* - * XXX - m41t80 alarm functionality is reported broken. - * until it is fixed, don't register alarm functions. - * - .read_alarm = m41t80_rtc_read_alarm, - .set_alarm = m41t80_rtc_set_alarm, - */ .proc = m41t80_rtc_proc, - /* - * See above comment on broken alarm - * - .alarm_irq_enable = m41t80_rtc_alarm_irq_enable, - */ }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c new file mode 100644 index 000000000000..e094ffa434f8 --- /dev/null +++ b/drivers/rtc/rtc-max8907.c @@ -0,0 +1,244 @@ +/* + * RTC driver for Maxim MAX8907 + * + * Copyright (c) 2011-2012, NVIDIA Corporation. + * + * Based on drivers/rtc/rtc-max8925.c, + * Copyright (C) 2009-2010 Marvell International Ltd. + * + * 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/bcd.h> +#include <linux/i2c.h> +#include <linux/mfd/max8907.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/slab.h> + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_DATE, + RTC_MONTH, + RTC_YEAR1, + RTC_YEAR2, +}; + +#define TIME_NUM 8 +#define ALARM_1SEC (1 << 7) +#define HOUR_12 (1 << 7) +#define HOUR_AM_PM (1 << 5) +#define ALARM0_IRQ (1 << 3) +#define ALARM1_IRQ (1 << 2) +#define ALARM0_STATUS (1 << 2) +#define ALARM1_STATUS (1 << 1) + +struct max8907_rtc { + struct max8907 *max8907; + struct regmap *regmap; + struct rtc_device *rtc_dev; + int irq; +}; + +static irqreturn_t max8907_irq_handler(int irq, void *data) +{ + struct max8907_rtc *rtc = data; + + regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); + + rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static void regs_to_tm(u8 *regs, struct rtc_time *tm) +{ + tm->tm_year = bcd2bin(regs[RTC_YEAR2]) * 100 + + bcd2bin(regs[RTC_YEAR1]) - 1900; + tm->tm_mon = bcd2bin(regs[RTC_MONTH] & 0x1f) - 1; + tm->tm_mday = bcd2bin(regs[RTC_DATE] & 0x3f); + tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07) - 1; + if (regs[RTC_HOUR] & HOUR_12) { + tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x01f); + if (tm->tm_hour == 12) + tm->tm_hour = 0; + if (regs[RTC_HOUR] & HOUR_AM_PM) + tm->tm_hour += 12; + } else { + tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x03f); + } + tm->tm_min = bcd2bin(regs[RTC_MIN] & 0x7f); + tm->tm_sec = bcd2bin(regs[RTC_SEC] & 0x7f); +} + +static void tm_to_regs(struct rtc_time *tm, u8 *regs) +{ + u8 high, low; + + high = (tm->tm_year + 1900) / 100; + low = tm->tm_year % 100; + regs[RTC_YEAR2] = bin2bcd(high); + regs[RTC_YEAR1] = bin2bcd(low); + regs[RTC_MONTH] = bin2bcd(tm->tm_mon + 1); + regs[RTC_DATE] = bin2bcd(tm->tm_mday); + regs[RTC_WEEKDAY] = tm->tm_wday + 1; + regs[RTC_HOUR] = bin2bcd(tm->tm_hour); + regs[RTC_MIN] = bin2bcd(tm->tm_min); + regs[RTC_SEC] = bin2bcd(tm->tm_sec); +} + +static int max8907_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8907_rtc *rtc = dev_get_drvdata(dev); + u8 regs[TIME_NUM]; + int ret; + + ret = regmap_bulk_read(rtc->regmap, MAX8907_REG_RTC_SEC, regs, + TIME_NUM); + if (ret < 0) + return ret; + + regs_to_tm(regs, tm); + + return 0; +} + +static int max8907_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8907_rtc *rtc = dev_get_drvdata(dev); + u8 regs[TIME_NUM]; + + tm_to_regs(tm, regs); + + return regmap_bulk_write(rtc->regmap, MAX8907_REG_RTC_SEC, regs, + TIME_NUM); +} + +static int max8907_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8907_rtc *rtc = dev_get_drvdata(dev); + u8 regs[TIME_NUM]; + unsigned int val; + int ret; + + ret = regmap_bulk_read(rtc->regmap, MAX8907_REG_ALARM0_SEC, regs, + TIME_NUM); + if (ret < 0) + return ret; + + regs_to_tm(regs, &alrm->time); + + ret = regmap_read(rtc->regmap, MAX8907_REG_ALARM0_CNTL, &val); + if (ret < 0) + return ret; + + alrm->enabled = !!(val & 0x7f); + + return 0; +} + +static int max8907_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8907_rtc *rtc = dev_get_drvdata(dev); + u8 regs[TIME_NUM]; + int ret; + + tm_to_regs(&alrm->time, regs); + + /* Disable alarm while we update the target time */ + ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); + if (ret < 0) + return ret; + + ret = regmap_bulk_write(rtc->regmap, MAX8907_REG_ALARM0_SEC, regs, + TIME_NUM); + if (ret < 0) + return ret; + + if (alrm->enabled) + ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, + 0x7f, 0x7f); + + return ret; +} + +static const struct rtc_class_ops max8907_rtc_ops = { + .read_time = max8907_rtc_read_time, + .set_time = max8907_rtc_set_time, + .read_alarm = max8907_rtc_read_alarm, + .set_alarm = max8907_rtc_set_alarm, +}; + +static int __devinit max8907_rtc_probe(struct platform_device *pdev) +{ + struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent); + struct max8907_rtc *rtc; + int ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + platform_set_drvdata(pdev, rtc); + + rtc->max8907 = max8907; + rtc->regmap = max8907->regmap_rtc; + + rtc->rtc_dev = rtc_device_register("max8907-rtc", &pdev->dev, + &max8907_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc_dev)) { + ret = PTR_ERR(rtc->rtc_dev); + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + return ret; + } + + rtc->irq = regmap_irq_get_virq(max8907->irqc_rtc, + MAX8907_IRQ_RTC_ALARM0); + if (rtc->irq < 0) { + ret = rtc->irq; + goto err_unregister; + } + + ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler, + IRQF_ONESHOT, "max8907-alarm0", rtc); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n", + rtc->irq, ret); + goto err_unregister; + } + + return 0; + +err_unregister: + rtc_device_unregister(rtc->rtc_dev); + return ret; +} + +static int __devexit max8907_rtc_remove(struct platform_device *pdev) +{ + struct max8907_rtc *rtc = platform_get_drvdata(pdev); + + free_irq(rtc->irq, rtc); + rtc_device_unregister(rtc->rtc_dev); + + return 0; +} + +static struct platform_driver max8907_rtc_driver = { + .driver = { + .name = "max8907-rtc", + .owner = THIS_MODULE, + }, + .probe = max8907_rtc_probe, + .remove = __devexit_p(max8907_rtc_remove), +}; +module_platform_driver(max8907_rtc_driver); + +MODULE_DESCRIPTION("Maxim MAX8907 RTC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index e3e50d69baf8..cd0106293a49 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -343,7 +343,7 @@ static struct rtc_class_ops mxc_rtc_ops = { .alarm_irq_enable = mxc_rtc_alarm_irq_enable, }; -static int __init mxc_rtc_probe(struct platform_device *pdev) +static int __devinit mxc_rtc_probe(struct platform_device *pdev) { struct resource *res; struct rtc_device *rtc; @@ -367,14 +367,14 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - pdata->clk = clk_get(&pdev->dev, "rtc"); + pdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pdata->clk)) { dev_err(&pdev->dev, "unable to get clock!\n"); ret = PTR_ERR(pdata->clk); goto exit_free_pdata; } - clk_enable(pdata->clk); + clk_prepare_enable(pdata->clk); rate = clk_get_rate(pdata->clk); if (rate == 32768) @@ -426,22 +426,20 @@ static int __init mxc_rtc_probe(struct platform_device *pdev) exit_clr_drvdata: platform_set_drvdata(pdev, NULL); exit_put_clk: - clk_disable(pdata->clk); - clk_put(pdata->clk); + clk_disable_unprepare(pdata->clk); exit_free_pdata: return ret; } -static int __exit mxc_rtc_remove(struct platform_device *pdev) +static int __devexit mxc_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); rtc_device_unregister(pdata->rtc); - clk_disable(pdata->clk); - clk_put(pdata->clk); + clk_disable_unprepare(pdata->clk); platform_set_drvdata(pdev, NULL); return 0; @@ -482,21 +480,11 @@ static struct platform_driver mxc_rtc_driver = { #endif .owner = THIS_MODULE, }, - .remove = __exit_p(mxc_rtc_remove), + .probe = mxc_rtc_probe, + .remove = __devexit_p(mxc_rtc_remove), }; -static int __init mxc_rtc_init(void) -{ - return platform_driver_probe(&mxc_rtc_driver, mxc_rtc_probe); -} - -static void __exit mxc_rtc_exit(void) -{ - platform_driver_unregister(&mxc_rtc_driver); -} - -module_init(mxc_rtc_init); -module_exit(mxc_rtc_exit); +module_platform_driver(mxc_rtc_driver) MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); MODULE_DESCRIPTION("RTC driver for Freescale MXC"); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index c2fe426a6ef2..98e3a2b681e6 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -78,8 +78,17 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm) unsigned char buf[13] = { PCF8563_REG_ST1 }; struct i2c_msg msgs[] = { - { client->addr, 0, 1, buf }, /* setup read ptr */ - { client->addr, I2C_M_RD, 13, buf }, /* read status + date */ + {/* setup read ptr */ + .addr = client->addr, + .len = 1, + .buf = buf + }, + {/* read status + date */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 13, + .buf = buf + }, }; /* read registers */ diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 0a59fda5c09d..e96236ac2e78 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -18,6 +18,26 @@ #include "rtc-core.h" +#define NAME_SIZE 10 + +#if defined(CONFIG_RTC_HCTOSYS_DEVICE) +static bool is_rtc_hctosys(struct rtc_device *rtc) +{ + int size; + char name[NAME_SIZE]; + + size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); + if (size > NAME_SIZE) + return false; + + return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); +} +#else +static bool is_rtc_hctosys(struct rtc_device *rtc) +{ + return (rtc->id == 0); +} +#endif static int rtc_proc_show(struct seq_file *seq, void *offset) { @@ -117,12 +137,12 @@ static const struct file_operations rtc_proc_fops = { void rtc_proc_add_device(struct rtc_device *rtc) { - if (rtc->id == 0) + if (is_rtc_hctosys(rtc)) proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); } void rtc_proc_del_device(struct rtc_device *rtc) { - if (rtc->id == 0) + if (is_rtc_hctosys(rtc)) remove_proc_entry("driver/rtc", NULL); } diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c new file mode 100644 index 000000000000..cdb140c29c56 --- /dev/null +++ b/drivers/rtc/rtc-rc5t583.c @@ -0,0 +1,331 @@ +/* + * rtc-rc5t583.c -- RICOH RC5T583 Real Time Clock + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Author: Venu Byravarasu <vbyravarasu@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/mfd/rc5t583.h> + +struct rc5t583_rtc { + struct rtc_device *rtc; + /* To store the list of enabled interrupts, during system suspend */ + u32 irqen; +}; + +/* Total number of RTC registers needed to set time*/ +#define NUM_TIME_REGS (RC5T583_RTC_YEAR - RC5T583_RTC_SEC + 1) + +/* Total number of RTC registers needed to set Y-Alarm*/ +#define NUM_YAL_REGS (RC5T583_RTC_AY_YEAR - RC5T583_RTC_AY_MIN + 1) + +/* Set Y-Alarm interrupt */ +#define SET_YAL BIT(5) + +/* Get Y-Alarm interrupt status*/ +#define GET_YAL_STATUS BIT(3) + +static int rc5t583_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + u8 val; + + /* Set Y-Alarm, based on 'enabled' */ + val = enabled ? SET_YAL : 0; + + return regmap_update_bits(rc5t583->regmap, RC5T583_RTC_CTL1, SET_YAL, + val); +} + +/* + * Gets current rc5t583 RTC time and date parameters. + * + * The RTC's time/alarm representation is not what gmtime(3) requires + * Linux to use: + * + * - Months are 1..12 vs Linux 0-11 + * - Years are 0..99 vs Linux 1900..N (we assume 21st century) + */ +static int rc5t583_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + u8 rtc_data[NUM_TIME_REGS]; + int ret; + + ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "RTC read time failed with err:%d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_wday = bcd2bin(rtc_data[3]); + tm->tm_mday = bcd2bin(rtc_data[4]); + tm->tm_mon = bcd2bin(rtc_data[5]) - 1; + tm->tm_year = bcd2bin(rtc_data[6]) + 100; + + return ret; +} + +static int rc5t583_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + unsigned char rtc_data[NUM_TIME_REGS]; + int ret; + + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_wday); + rtc_data[4] = bin2bcd(tm->tm_mday); + rtc_data[5] = bin2bcd(tm->tm_mon + 1); + rtc_data[6] = bin2bcd(tm->tm_year - 100); + + ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_SEC, rtc_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "RTC set time failed with error %d\n", ret); + return ret; + } + + return ret; +} + +static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + unsigned char alarm_data[NUM_YAL_REGS]; + u32 interrupt_enable; + int ret; + + ret = regmap_bulk_read(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data, + NUM_YAL_REGS); + if (ret < 0) { + dev_err(dev, "rtc_read_alarm error %d\n", ret); + return ret; + } + + alm->time.tm_min = bcd2bin(alarm_data[0]); + alm->time.tm_hour = bcd2bin(alarm_data[1]); + alm->time.tm_mday = bcd2bin(alarm_data[2]); + alm->time.tm_mon = bcd2bin(alarm_data[3]) - 1; + alm->time.tm_year = bcd2bin(alarm_data[4]) + 100; + + ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1, &interrupt_enable); + if (ret < 0) + return ret; + + /* check if YALE is set */ + if (interrupt_enable & SET_YAL) + alm->enabled = 1; + + return ret; +} + +static int rc5t583_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + unsigned char alarm_data[NUM_YAL_REGS]; + int ret; + + ret = rc5t583_rtc_alarm_irq_enable(dev, 0); + if (ret) + return ret; + + alarm_data[0] = bin2bcd(alm->time.tm_min); + alarm_data[1] = bin2bcd(alm->time.tm_hour); + alarm_data[2] = bin2bcd(alm->time.tm_mday); + alarm_data[3] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[4] = bin2bcd(alm->time.tm_year - 100); + + ret = regmap_bulk_write(rc5t583->regmap, RC5T583_RTC_AY_MIN, alarm_data, + NUM_YAL_REGS); + if (ret) { + dev_err(dev, "rtc_set_alarm error %d\n", ret); + return ret; + } + + if (alm->enabled) + ret = rc5t583_rtc_alarm_irq_enable(dev, 1); + + return ret; +} + +static irqreturn_t rc5t583_rtc_interrupt(int irq, void *rtc) +{ + struct device *dev = rtc; + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev); + unsigned long events = 0; + int ret; + u32 rtc_reg; + + ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL2, &rtc_reg); + if (ret < 0) + return IRQ_NONE; + + if (rtc_reg & GET_YAL_STATUS) { + events = RTC_IRQF | RTC_AF; + /* clear pending Y-alarm interrupt bit */ + rtc_reg &= ~GET_YAL_STATUS; + } + + ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, rtc_reg); + if (ret) + return IRQ_NONE; + + /* Notify RTC core on event */ + rtc_update_irq(rc5t583_rtc->rtc, 1, events); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops rc5t583_rtc_ops = { + .read_time = rc5t583_rtc_read_time, + .set_time = rc5t583_rtc_set_time, + .read_alarm = rc5t583_rtc_read_alarm, + .set_alarm = rc5t583_rtc_set_alarm, + .alarm_irq_enable = rc5t583_rtc_alarm_irq_enable, +}; + +static int __devinit rc5t583_rtc_probe(struct platform_device *pdev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); + struct rc5t583_rtc *ricoh_rtc; + struct rc5t583_platform_data *pmic_plat_data; + int ret; + int irq; + + ricoh_rtc = devm_kzalloc(&pdev->dev, sizeof(struct rc5t583_rtc), + GFP_KERNEL); + if (!ricoh_rtc) + return -ENOMEM; + + platform_set_drvdata(pdev, ricoh_rtc); + + /* Clear pending interrupts */ + ret = regmap_write(rc5t583->regmap, RC5T583_RTC_CTL2, 0); + if (ret < 0) + return ret; + + /* clear RTC Adjust register */ + ret = regmap_write(rc5t583->regmap, RC5T583_RTC_ADJ, 0); + if (ret < 0) { + dev_err(&pdev->dev, "unable to program rtc_adjust reg\n"); + return -EBUSY; + } + + pmic_plat_data = dev_get_platdata(rc5t583->dev); + irq = pmic_plat_data->irq_base; + if (irq <= 0) { + dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n", + irq); + return ret; + } + + irq += RC5T583_IRQ_YALE; + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + rc5t583_rtc_interrupt, IRQF_TRIGGER_LOW, + "rtc-rc5t583", &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "IRQ is not free.\n"); + return ret; + } + device_init_wakeup(&pdev->dev, 1); + + ricoh_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &rc5t583_rtc_ops, THIS_MODULE); + if (IS_ERR(ricoh_rtc->rtc)) { + ret = PTR_ERR(ricoh_rtc->rtc); + dev_err(&pdev->dev, "RTC device register: err %d\n", ret); + return ret; + } + + return 0; +} + +/* + * Disable rc5t583 RTC interrupts. + * Sets status flag to free. + */ +static int __devexit rc5t583_rtc_remove(struct platform_device *pdev) +{ + struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev); + + rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0); + + rtc_device_unregister(rc5t583_rtc->rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int rc5t583_rtc_suspend(struct device *dev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev); + int ret; + + /* Store current list of enabled interrupts*/ + ret = regmap_read(rc5t583->regmap, RC5T583_RTC_CTL1, + &rc5t583_rtc->irqen); + return ret; +} + +static int rc5t583_rtc_resume(struct device *dev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent); + struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(dev); + + /* Restore list of enabled interrupts before suspend */ + return regmap_write(rc5t583->regmap, RC5T583_RTC_CTL1, + rc5t583_rtc->irqen); +} + +static const struct dev_pm_ops rc5t583_rtc_pm_ops = { + .suspend = rc5t583_rtc_suspend, + .resume = rc5t583_rtc_resume, +}; + +#define DEV_PM_OPS (&rc5t583_rtc_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +static struct platform_driver rc5t583_rtc_driver = { + .probe = rc5t583_rtc_probe, + .remove = __devexit_p(rc5t583_rtc_remove), + .driver = { + .owner = THIS_MODULE, + .name = "rtc-rc5t583", + .pm = DEV_PM_OPS, + }, +}; + +module_platform_driver(rc5t583_rtc_driver); +MODULE_ALIAS("platform:rtc-rc5t583"); +MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index fb4842c3544e..76f565ae384d 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -104,7 +104,12 @@ static int rs5c_get_regs(struct rs5c372 *rs5c) { struct i2c_client *client = rs5c->client; struct i2c_msg msgs[] = { - { client->addr, I2C_M_RD, sizeof rs5c->buf, rs5c->buf }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = sizeof(rs5c->buf), + .buf = rs5c->buf + }, }; /* This implements the third reading method from the datasheet, using diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index c9562ceedef3..8a092325188d 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -19,6 +19,8 @@ #define S35390A_CMD_STATUS1 0 #define S35390A_CMD_STATUS2 1 #define S35390A_CMD_TIME1 2 +#define S35390A_CMD_TIME2 3 +#define S35390A_CMD_INT2_REG1 5 #define S35390A_BYTE_YEAR 0 #define S35390A_BYTE_MONTH 1 @@ -28,12 +30,23 @@ #define S35390A_BYTE_MINS 5 #define S35390A_BYTE_SECS 6 +#define S35390A_ALRM_BYTE_WDAY 0 +#define S35390A_ALRM_BYTE_HOURS 1 +#define S35390A_ALRM_BYTE_MINS 2 + #define S35390A_FLAG_POC 0x01 #define S35390A_FLAG_BLD 0x02 #define S35390A_FLAG_24H 0x40 #define S35390A_FLAG_RESET 0x80 #define S35390A_FLAG_TEST 0x01 +#define S35390A_INT2_MODE_MASK 0xF0 + +#define S35390A_INT2_MODE_NOINTR 0x00 +#define S35390A_INT2_MODE_FREQ 0x10 +#define S35390A_INT2_MODE_ALARM 0x40 +#define S35390A_INT2_MODE_PMIN_EDG 0x20 + static const struct i2c_device_id s35390a_id[] = { { "s35390a", 0 }, { } @@ -50,7 +63,11 @@ static int s35390a_set_reg(struct s35390a *s35390a, int reg, char *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { - { client->addr, 0, len, buf }, + { + .addr = client->addr, + .len = len, + .buf = buf + }, }; if ((i2c_transfer(client->adapter, msg, 1)) != 1) @@ -63,7 +80,12 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len) { struct i2c_client *client = s35390a->client[reg]; struct i2c_msg msg[] = { - { client->addr, I2C_M_RD, len, buf }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf + }, }; if ((i2c_transfer(client->adapter, msg, 1)) != 1) @@ -184,6 +206,104 @@ static int s35390a_get_datetime(struct i2c_client *client, struct rtc_time *tm) return rtc_valid_tm(tm); } +static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm) +{ + struct s35390a *s35390a = i2c_get_clientdata(client); + char buf[3], sts = 0; + int err, i; + + dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d mday=%d, "\ + "mon=%d, year=%d, wday=%d\n", __func__, alm->time.tm_sec, + alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday, + alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday); + + /* disable interrupt */ + err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); + if (err < 0) + return err; + + /* clear pending interrupt, if any */ + err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts)); + if (err < 0) + return err; + + if (alm->enabled) + sts = S35390A_INT2_MODE_ALARM; + else + sts = S35390A_INT2_MODE_NOINTR; + + /* This chip expects the bits of each byte to be in reverse order */ + sts = bitrev8(sts); + + /* set interupt mode*/ + err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); + if (err < 0) + return err; + + if (alm->time.tm_wday != -1) + buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80; + + buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a, + alm->time.tm_hour) | 0x80; + buf[S35390A_ALRM_BYTE_MINS] = bin2bcd(alm->time.tm_min) | 0x80; + + if (alm->time.tm_hour >= 12) + buf[S35390A_ALRM_BYTE_HOURS] |= 0x40; + + for (i = 0; i < 3; ++i) + buf[i] = bitrev8(buf[i]); + + err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf, + sizeof(buf)); + + return err; +} + +static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm) +{ + struct s35390a *s35390a = i2c_get_clientdata(client); + char buf[3], sts; + int i, err; + + err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts)); + if (err < 0) + return err; + + if (bitrev8(sts) != S35390A_INT2_MODE_ALARM) + return -EINVAL; + + err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf)); + if (err < 0) + return err; + + /* This chip returns the bits of each byte in reverse order */ + for (i = 0; i < 3; ++i) { + buf[i] = bitrev8(buf[i]); + buf[i] &= ~0x80; + } + + alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]); + alm->time.tm_hour = s35390a_reg2hr(s35390a, + buf[S35390A_ALRM_BYTE_HOURS]); + alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]); + + dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n", + __func__, alm->time.tm_min, alm->time.tm_hour, + alm->time.tm_wday); + + return 0; +} + +static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + return s35390a_read_alarm(to_i2c_client(dev), alm); +} + +static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + return s35390a_set_alarm(to_i2c_client(dev), alm); +} + static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm) { return s35390a_get_datetime(to_i2c_client(dev), tm); @@ -197,6 +317,9 @@ static int s35390a_rtc_set_time(struct device *dev, struct rtc_time *tm) static const struct rtc_class_ops s35390a_rtc_ops = { .read_time = s35390a_rtc_read_time, .set_time = s35390a_rtc_set_time, + .set_alarm = s35390a_rtc_set_alarm, + .read_alarm = s35390a_rtc_read_alarm, + }; static struct i2c_driver s35390a_driver; @@ -261,6 +384,8 @@ static int s35390a_probe(struct i2c_client *client, if (s35390a_get_datetime(client, &tm) < 0) dev_warn(&client->dev, "clock needs to be set\n"); + device_set_wakeup_capable(&client->dev, 1); + s35390a->rtc = rtc_device_register(s35390a_driver.driver.name, &client->dev, &s35390a_rtc_ops, THIS_MODULE); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index bfbd92c8d1c9..77823d21d314 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -476,13 +476,13 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_tickno = platform_get_irq(pdev, 1); if (s3c_rtc_tickno < 0) { dev_err(&pdev->dev, "no irq for rtc tick\n"); - return -ENOENT; + return s3c_rtc_tickno; } s3c_rtc_alarmno = platform_get_irq(pdev, 0); if (s3c_rtc_alarmno < 0) { dev_err(&pdev->dev, "no irq for alarm\n"); - return -ENOENT; + return s3c_rtc_alarmno; } pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c new file mode 100644 index 000000000000..3c0da333f465 --- /dev/null +++ b/drivers/rtc/rtc-snvs.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +/* These register offsets are relative to LP (Low Power) range */ +#define SNVS_LPCR 0x04 +#define SNVS_LPSR 0x18 +#define SNVS_LPSRTCMR 0x1c +#define SNVS_LPSRTCLR 0x20 +#define SNVS_LPTAR 0x24 +#define SNVS_LPPGDR 0x30 + +#define SNVS_LPCR_SRTC_ENV (1 << 0) +#define SNVS_LPCR_LPTA_EN (1 << 1) +#define SNVS_LPCR_LPWUI_EN (1 << 3) +#define SNVS_LPSR_LPTA (1 << 0) + +#define SNVS_LPPGDR_INIT 0x41736166 +#define CNTR_TO_SECS_SH 15 + +struct snvs_rtc_data { + struct rtc_device *rtc; + void __iomem *ioaddr; + int irq; + spinlock_t lock; +}; + +static u32 rtc_read_lp_counter(void __iomem *ioaddr) +{ + u64 read1, read2; + + do { + read1 = readl(ioaddr + SNVS_LPSRTCMR); + read1 <<= 32; + read1 |= readl(ioaddr + SNVS_LPSRTCLR); + + read2 = readl(ioaddr + SNVS_LPSRTCMR); + read2 <<= 32; + read2 |= readl(ioaddr + SNVS_LPSRTCLR); + } while (read1 != read2); + + /* Convert 47-bit counter to 32-bit raw second count */ + return (u32) (read1 >> CNTR_TO_SECS_SH); +} + +static void rtc_write_sync_lp(void __iomem *ioaddr) +{ + u32 count1, count2, count3; + int i; + + /* Wait for 3 CKIL cycles */ + for (i = 0; i < 3; i++) { + do { + count1 = readl(ioaddr + SNVS_LPSRTCLR); + count2 = readl(ioaddr + SNVS_LPSRTCLR); + } while (count1 != count2); + + /* Now wait until counter value changes */ + do { + do { + count2 = readl(ioaddr + SNVS_LPSRTCLR); + count3 = readl(ioaddr + SNVS_LPSRTCLR); + } while (count2 != count3); + } while (count3 == count1); + } +} + +static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) +{ + unsigned long flags; + int timeout = 1000; + u32 lpcr; + + spin_lock_irqsave(&data->lock, flags); + + lpcr = readl(data->ioaddr + SNVS_LPCR); + if (enable) + lpcr |= SNVS_LPCR_SRTC_ENV; + else + lpcr &= ~SNVS_LPCR_SRTC_ENV; + writel(lpcr, data->ioaddr + SNVS_LPCR); + + spin_unlock_irqrestore(&data->lock, flags); + + while (--timeout) { + lpcr = readl(data->ioaddr + SNVS_LPCR); + + if (enable) { + if (lpcr & SNVS_LPCR_SRTC_ENV) + break; + } else { + if (!(lpcr & SNVS_LPCR_SRTC_ENV)) + break; + } + } + + if (!timeout) + return -ETIMEDOUT; + + return 0; +} + +static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + unsigned long time = rtc_read_lp_counter(data->ioaddr); + + rtc_time_to_tm(time, tm); + + return 0; +} + +static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + unsigned long time; + + rtc_tm_to_time(tm, &time); + + /* Disable RTC first */ + snvs_rtc_enable(data, false); + + /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ + writel(time << CNTR_TO_SECS_SH, data->ioaddr + SNVS_LPSRTCLR); + writel(time >> (32 - CNTR_TO_SECS_SH), data->ioaddr + SNVS_LPSRTCMR); + + /* Enable RTC again */ + snvs_rtc_enable(data, true); + + return 0; +} + +static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + u32 lptar, lpsr; + + lptar = readl(data->ioaddr + SNVS_LPTAR); + rtc_time_to_tm(lptar, &alrm->time); + + lpsr = readl(data->ioaddr + SNVS_LPSR); + alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; + + return 0; +} + +static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + u32 lpcr; + unsigned long flags; + + spin_lock_irqsave(&data->lock, flags); + + lpcr = readl(data->ioaddr + SNVS_LPCR); + if (enable) + lpcr |= (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN); + else + lpcr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN); + writel(lpcr, data->ioaddr + SNVS_LPCR); + + spin_unlock_irqrestore(&data->lock, flags); + + rtc_write_sync_lp(data->ioaddr); + + return 0; +} + +static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + struct rtc_time *alrm_tm = &alrm->time; + unsigned long time; + unsigned long flags; + u32 lpcr; + + rtc_tm_to_time(alrm_tm, &time); + + spin_lock_irqsave(&data->lock, flags); + + /* Have to clear LPTA_EN before programming new alarm time in LPTAR */ + lpcr = readl(data->ioaddr + SNVS_LPCR); + lpcr &= ~SNVS_LPCR_LPTA_EN; + writel(lpcr, data->ioaddr + SNVS_LPCR); + + spin_unlock_irqrestore(&data->lock, flags); + + writel(time, data->ioaddr + SNVS_LPTAR); + + /* Clear alarm interrupt status bit */ + writel(SNVS_LPSR_LPTA, data->ioaddr + SNVS_LPSR); + + return snvs_rtc_alarm_irq_enable(dev, alrm->enabled); +} + +static const struct rtc_class_ops snvs_rtc_ops = { + .read_time = snvs_rtc_read_time, + .set_time = snvs_rtc_set_time, + .read_alarm = snvs_rtc_read_alarm, + .set_alarm = snvs_rtc_set_alarm, + .alarm_irq_enable = snvs_rtc_alarm_irq_enable, +}; + +static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) +{ + struct device *dev = dev_id; + struct snvs_rtc_data *data = dev_get_drvdata(dev); + u32 lpsr; + u32 events = 0; + + lpsr = readl(data->ioaddr + SNVS_LPSR); + + if (lpsr & SNVS_LPSR_LPTA) { + events |= (RTC_AF | RTC_IRQF); + + /* RTC alarm should be one-shot */ + snvs_rtc_alarm_irq_enable(dev, 0); + + rtc_update_irq(data->rtc, 1, events); + } + + /* clear interrupt status */ + writel(lpsr, data->ioaddr + SNVS_LPSR); + + return events ? IRQ_HANDLED : IRQ_NONE; +} + +static int __devinit snvs_rtc_probe(struct platform_device *pdev) +{ + struct snvs_rtc_data *data; + struct resource *res; + int ret; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->ioaddr = devm_request_and_ioremap(&pdev->dev, res); + if (!data->ioaddr) + return -EADDRNOTAVAIL; + + data->irq = platform_get_irq(pdev, 0); + if (data->irq < 0) + return data->irq; + + platform_set_drvdata(pdev, data); + + spin_lock_init(&data->lock); + + /* Initialize glitch detect */ + writel(SNVS_LPPGDR_INIT, data->ioaddr + SNVS_LPPGDR); + + /* Clear interrupt status */ + writel(0xffffffff, data->ioaddr + SNVS_LPSR); + + /* Enable RTC */ + snvs_rtc_enable(data, true); + + device_init_wakeup(&pdev->dev, true); + + ret = devm_request_irq(&pdev->dev, data->irq, snvs_rtc_irq_handler, + IRQF_SHARED, "rtc alarm", &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to request irq %d: %d\n", + data->irq, ret); + return ret; + } + + data->rtc = rtc_device_register(pdev->name, &pdev->dev, + &snvs_rtc_ops, THIS_MODULE); + if (IS_ERR(data->rtc)) { + ret = PTR_ERR(data->rtc); + dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); + return ret; + } + + return 0; +} + +static int __devexit snvs_rtc_remove(struct platform_device *pdev) +{ + struct snvs_rtc_data *data = platform_get_drvdata(pdev); + + rtc_device_unregister(data->rtc); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int snvs_rtc_suspend(struct device *dev) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(data->irq); + + return 0; +} + +static int snvs_rtc_resume(struct device *dev) +{ + struct snvs_rtc_data *data = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(data->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume); + +static const struct of_device_id __devinitconst snvs_dt_ids[] = { + { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, snvs_dt_ids); + +static struct platform_driver snvs_rtc_driver = { + .driver = { + .name = "snvs_rtc", + .owner = THIS_MODULE, + .pm = &snvs_rtc_pm_ops, + .of_match_table = snvs_dt_ids, + }, + .probe = snvs_rtc_probe, + .remove = __devexit_p(snvs_rtc_remove), +}; +module_platform_driver(snvs_rtc_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Freescale SNVS RTC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index e2785479113c..bb507d23f6ce 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -235,7 +235,7 @@ static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm) static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct spear_rtc_config *config = dev_get_drvdata(dev); - unsigned int time, date, err = 0; + unsigned int time, date; if (tm2bcd(tm) < 0) return -EINVAL; @@ -247,11 +247,8 @@ static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm) (tm->tm_year << YEAR_SHIFT); writel(time, config->ioaddr + TIME_REG); writel(date, config->ioaddr + DATE_REG); - err = is_write_complete(config); - if (err < 0) - return err; - return 0; + return is_write_complete(config); } /* @@ -295,7 +292,8 @@ static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { struct spear_rtc_config *config = dev_get_drvdata(dev); - unsigned int time, date, err = 0; + unsigned int time, date; + int err; if (tm2bcd(&alm->time) < 0) return -EINVAL; @@ -357,7 +355,7 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev) { struct resource *res; struct spear_rtc_config *config; - unsigned int status = 0; + int status = 0; int irq; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 380083ca572f..b70e2bb63645 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -102,6 +102,12 @@ rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, return n; } +/** + * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time + * + * Returns 1 if the system clock was set by this RTC at the last + * boot or resume event. + */ static ssize_t rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c new file mode 100644 index 000000000000..7a82337e4dee --- /dev/null +++ b/drivers/rtc/rtc-tps65910.c @@ -0,0 +1,349 @@ +/* + * rtc-tps65910.c -- TPS65910 Real Time Clock interface + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Author: Venu Byravarasu <vbyravarasu@nvidia.com> + * + * Based on original TI driver rtc-twl.c + * Copyright (C) 2007 MontaVista Software, Inc + * Author: Alexandre Rusev <source@mvista.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/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/mfd/tps65910.h> + +struct tps65910_rtc { + struct rtc_device *rtc; + /* To store the list of enabled interrupts */ + u32 irqstat; +}; + +/* Total number of RTC registers needed to set time*/ +#define NUM_TIME_REGS (TPS65910_YEARS - TPS65910_SECONDS + 1) + +static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) +{ + struct tps65910 *tps = dev_get_drvdata(dev->parent); + u8 val = 0; + + if (enabled) + val = TPS65910_RTC_INTERRUPTS_IT_ALARM; + + return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, val); +} + +/* + * Gets current tps65910 RTC time and date parameters. + * + * The RTC's time/alarm representation is not what gmtime(3) requires + * Linux to use: + * + * - Months are 1..12 vs Linux 0-11 + * - Years are 0..99 vs Linux 1900..N (we assume 21st century) + */ +static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[NUM_TIME_REGS]; + struct tps65910 *tps = dev_get_drvdata(dev->parent); + int ret; + + /* Copy RTC counting registers to static registers or latches */ + ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL, + TPS65910_RTC_CTRL_GET_TIME, TPS65910_RTC_CTRL_GET_TIME); + if (ret < 0) { + dev_err(dev, "RTC CTRL reg update failed with err:%d\n", ret); + return ret; + } + + ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, rtc_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "reading from RTC failed with err:%d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_mday = bcd2bin(rtc_data[3]); + tm->tm_mon = bcd2bin(rtc_data[4]) - 1; + tm->tm_year = bcd2bin(rtc_data[5]) + 100; + + return ret; +} + +static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[NUM_TIME_REGS]; + struct tps65910 *tps = dev_get_drvdata(dev->parent); + int ret; + + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); + + /* Stop RTC while updating the RTC time registers */ + ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL, + TPS65910_RTC_CTRL_STOP_RTC, 0); + if (ret < 0) { + dev_err(dev, "RTC stop failed with err:%d\n", ret); + return ret; + } + + /* update all the time registers in one shot */ + ret = regmap_bulk_write(tps->regmap, TPS65910_SECONDS, rtc_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "rtc_set_time error %d\n", ret); + return ret; + } + + /* Start back RTC */ + ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL, + TPS65910_RTC_CTRL_STOP_RTC, 1); + if (ret < 0) + dev_err(dev, "RTC start failed with err:%d\n", ret); + + return ret; +} + +/* + * Gets current tps65910 RTC alarm time. + */ +static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[NUM_TIME_REGS]; + u32 int_val; + struct tps65910 *tps = dev_get_drvdata(dev->parent); + int ret; + + ret = regmap_bulk_read(tps->regmap, TPS65910_SECONDS, alarm_data, + NUM_TIME_REGS); + if (ret < 0) { + dev_err(dev, "rtc_read_alarm error %d\n", ret); + return ret; + } + + alm->time.tm_sec = bcd2bin(alarm_data[0]); + alm->time.tm_min = bcd2bin(alarm_data[1]); + alm->time.tm_hour = bcd2bin(alarm_data[2]); + alm->time.tm_mday = bcd2bin(alarm_data[3]); + alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1; + alm->time.tm_year = bcd2bin(alarm_data[5]) + 100; + + ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &int_val); + if (ret < 0) + return ret; + + if (int_val & TPS65910_RTC_INTERRUPTS_IT_ALARM) + alm->enabled = 1; + + return ret; +} + +static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[NUM_TIME_REGS]; + struct tps65910 *tps = dev_get_drvdata(dev->parent); + int ret; + + ret = tps65910_rtc_alarm_irq_enable(dev, 0); + if (ret) + return ret; + + alarm_data[0] = bin2bcd(alm->time.tm_sec); + alarm_data[1] = bin2bcd(alm->time.tm_min); + alarm_data[2] = bin2bcd(alm->time.tm_hour); + alarm_data[3] = bin2bcd(alm->time.tm_mday); + alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[5] = bin2bcd(alm->time.tm_year - 100); + + /* update all the alarm registers in one shot */ + ret = regmap_bulk_write(tps->regmap, TPS65910_ALARM_SECONDS, + alarm_data, NUM_TIME_REGS); + if (ret) { + dev_err(dev, "rtc_set_alarm error %d\n", ret); + return ret; + } + + if (alm->enabled) + ret = tps65910_rtc_alarm_irq_enable(dev, 1); + + return ret; +} + +static irqreturn_t tps65910_rtc_interrupt(int irq, void *rtc) +{ + struct device *dev = rtc; + unsigned long events = 0; + struct tps65910 *tps = dev_get_drvdata(dev->parent); + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); + int ret; + u32 rtc_reg; + + ret = regmap_read(tps->regmap, TPS65910_RTC_STATUS, &rtc_reg); + if (ret) + return IRQ_NONE; + + if (rtc_reg & TPS65910_RTC_STATUS_ALARM) + events = RTC_IRQF | RTC_AF; + + ret = regmap_write(tps->regmap, TPS65910_RTC_STATUS, rtc_reg); + if (ret) + return IRQ_NONE; + + /* Notify RTC core on event */ + rtc_update_irq(tps_rtc->rtc, 1, events); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops tps65910_rtc_ops = { + .read_time = tps65910_rtc_read_time, + .set_time = tps65910_rtc_set_time, + .read_alarm = tps65910_rtc_read_alarm, + .set_alarm = tps65910_rtc_set_alarm, + .alarm_irq_enable = tps65910_rtc_alarm_irq_enable, +}; + +static int __devinit tps65910_rtc_probe(struct platform_device *pdev) +{ + struct tps65910 *tps65910 = NULL; + struct tps65910_rtc *tps_rtc = NULL; + int ret; + int irq; + u32 rtc_reg; + + tps65910 = dev_get_drvdata(pdev->dev.parent); + + tps_rtc = devm_kzalloc(&pdev->dev, sizeof(struct tps65910_rtc), + GFP_KERNEL); + if (!tps_rtc) + return -ENOMEM; + + /* Clear pending interrupts */ + ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg); + if (ret < 0) + return ret; + + ret = regmap_write(tps65910->regmap, TPS65910_RTC_STATUS, rtc_reg); + if (ret < 0) + return ret; + + dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n"); + rtc_reg = TPS65910_RTC_CTRL_STOP_RTC; + ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg); + if (ret < 0) + return ret; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n", + irq); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, + "rtc-tps65910", &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "IRQ is not free.\n"); + return ret; + } + device_init_wakeup(&pdev->dev, 1); + + tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, + &tps65910_rtc_ops, THIS_MODULE); + if (IS_ERR(tps_rtc->rtc)) { + ret = PTR_ERR(tps_rtc->rtc); + dev_err(&pdev->dev, "RTC device register: err %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, tps_rtc); + + return 0; +} + +/* + * Disable tps65910 RTC interrupts. + * Sets status flag to free. + */ +static int __devexit tps65910_rtc_remove(struct platform_device *pdev) +{ + /* leave rtc running, but disable irqs */ + struct rtc_device *rtc = platform_get_drvdata(pdev); + + tps65910_rtc_alarm_irq_enable(&rtc->dev, 0); + + rtc_device_unregister(rtc); + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int tps65910_rtc_suspend(struct device *dev) +{ + struct tps65910 *tps = dev_get_drvdata(dev->parent); + u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; + int ret; + + /* Store current list of enabled interrupts*/ + ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, + &tps->rtc->irqstat); + if (ret < 0) + return ret; + + /* Enable RTC ALARM interrupt only */ + return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm); +} + +static int tps65910_rtc_resume(struct device *dev) +{ + struct tps65910 *tps = dev_get_drvdata(dev->parent); + + /* Restore list of enabled interrupts before suspend */ + return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, + tps->rtc->irqstat); +} + +static const struct dev_pm_ops tps65910_rtc_pm_ops = { + .suspend = tps65910_rtc_suspend, + .resume = tps65910_rtc_resume, +}; + +#define DEV_PM_OPS (&tps65910_rtc_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +static struct platform_driver tps65910_rtc_driver = { + .probe = tps65910_rtc_probe, + .remove = __devexit_p(tps65910_rtc_remove), + .driver = { + .owner = THIS_MODULE, + .name = "tps65910-rtc", + .pm = DEV_PM_OPS, + }, +}; + +module_platform_driver(tps65910_rtc_driver); +MODULE_ALIAS("platform:rtc-tps65910"); +MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 403b3d41d101..f36e59c6bc01 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -97,8 +97,17 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm, int i; struct i2c_msg msgs[] = { - { client->addr, 0, 2, dt_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 8, buf }, /* read date */ + {/* setup read ptr */ + .addr = client->addr, + .len = 2, + .buf = dt_addr + }, + {/* read date */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 8, + .buf = buf + }, }; /* read date registers */ @@ -142,8 +151,17 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) static unsigned char sr_addr[2] = { 0, X1205_REG_SR }; struct i2c_msg msgs[] = { - { client->addr, 0, 2, sr_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, sr }, /* read status */ + { /* setup read ptr */ + .addr = client->addr, + .len = 2, + .buf = sr_addr + }, + { /* read status */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = sr + }, }; /* read status register */ @@ -279,8 +297,17 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim) static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR }; struct i2c_msg msgs[] = { - { client->addr, 0, 2, dtr_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, &dtr }, /* read dtr */ + { /* setup read ptr */ + .addr = client->addr, + .len = 2, + .buf = dtr_addr + }, + { /* read dtr */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &dtr + }, }; /* read dtr register */ @@ -311,8 +338,17 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim) static unsigned char atr_addr[2] = { 0, X1205_REG_ATR }; struct i2c_msg msgs[] = { - { client->addr, 0, 2, atr_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, &atr }, /* read atr */ + {/* setup read ptr */ + .addr = client->addr, + .len = 2, + .buf = atr_addr + }, + {/* read atr */ + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &atr + }, }; /* read atr register */ @@ -381,8 +417,17 @@ static int x1205_validate_client(struct i2c_client *client) unsigned char addr[2] = { 0, probe_zero_pattern[i] }; struct i2c_msg msgs[2] = { - { client->addr, 0, 2, addr }, - { client->addr, I2C_M_RD, 1, &buf }, + { + .addr = client->addr, + .len = 2, + .buf = addr + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &buf + }, }; if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { @@ -409,8 +454,17 @@ static int x1205_validate_client(struct i2c_client *client) unsigned char addr[2] = { 0, probe_limits_pattern[i].reg }; struct i2c_msg msgs[2] = { - { client->addr, 0, 2, addr }, - { client->addr, I2C_M_RD, 1, ® }, + { + .addr = client->addr, + .len = 2, + .buf = addr + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = ® + }, }; if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) { @@ -444,8 +498,18 @@ static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static unsigned char int_addr[2] = { 0, X1205_REG_INT }; struct i2c_client *client = to_i2c_client(dev); struct i2c_msg msgs[] = { - { client->addr, 0, 2, int_addr }, /* setup read ptr */ - { client->addr, I2C_M_RD, 1, &intreg }, /* read INT register */ + { /* setup read ptr */ + .addr = client->addr, + .len = 2, + .buf = int_addr + }, + {/* read INT register */ + + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &intreg + }, }; /* read interrupt register and status register */ diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 7199534cd07d..cb7f1582a6d1 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -93,7 +93,7 @@ static DECLARE_PCI_DEVICE_TABLE(aac_pci_tbl) = { #elif defined(__devinitconst) static const struct pci_device_id aac_pci_tbl[] __devinitconst = { #else -static const struct pci_device_id aac_pci_tbl[] __devinitdata = { +static const struct pci_device_id aac_pci_tbl[] __devinitconst = { #endif { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */ { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */ diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index ff80552ead84..1c4120c3db41 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -1012,7 +1012,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = { .lldd_ata_set_dmamode = asd_set_dmamode, }; -static const struct pci_device_id aic94xx_pci_table[] __devinitdata = { +static const struct pci_device_id aic94xx_pci_table[] __devinitconst = { {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1}, {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1}, diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 68ce08552f69..a540162ac59c 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1173,7 +1173,16 @@ wait_io1: outw(val, tmport); outb(2, 0x80); TCM_SYNC: - udelay(0x800); + /* + * The funny division into multiple delays is to accomodate + * arches like ARM where udelay() multiplies its argument by + * a large number to initialize a loop counter. To avoid + * overflow, the maximum supported udelay is 2000 microseconds. + * + * XXX it would be more polite to find a way to use msleep() + */ + mdelay(2); + udelay(48); if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */ outw(0, tmport--); outb(0, tmport); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e3f29f61cbc3..fe6029f4df16 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6373,14 +6373,14 @@ static struct ata_port_info sata_port_info = { #ifdef CONFIG_PPC_PSERIES static const u16 ipr_blocked_processors[] = { - PV_NORTHSTAR, - PV_PULSAR, - PV_POWER4, - PV_ICESTAR, - PV_SSTAR, - PV_POWER4p, - PV_630, - PV_630p + PVR_NORTHSTAR, + PVR_PULSAR, + PVR_POWER4, + PVR_ICESTAR, + PVR_SSTAR, + PVR_POWER4p, + PVR_630, + PVR_630p }; /** @@ -6400,7 +6400,7 @@ static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++) { - if (__is_processor(ipr_blocked_processors[i])) + if (pvr_version_is(ipr_blocked_processors[i])) return 1; } } diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 67789b8345d2..efd81bb25e01 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -78,7 +78,7 @@ again: else if (unlikely(err)) return err; - *id = *id & MAX_ID_MASK; + *id = *id & MAX_IDR_MASK; return 0; } diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 4a652999380f..a5dec1ca1b82 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -245,6 +245,20 @@ static void hvc_port_destruct(struct tty_port *port) kfree(hp); } +static void hvc_check_console(int index) +{ + /* Already enabled, bail out */ + if (hvc_console.flags & CON_ENABLED) + return; + + /* If this index is what the user requested, then register + * now (setup won't fail at this point). It's ok to just + * call register again if previously .setup failed. + */ + if (index == hvc_console.index) + register_console(&hvc_console); +} + /* * hvc_instantiate() is an early console discovery method which locates * consoles * prior to the vio subsystem discovering them. Hotplugged @@ -275,12 +289,8 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) if (last_hvc < index) last_hvc = index; - /* if this index is what the user requested, then register - * now (setup won't fail at this point). It's ok to just - * call register again if previously .setup failed. - */ - if (index == hvc_console.index) - register_console(&hvc_console); + /* check if we need to re-register the kernel console */ + hvc_check_console(index); return 0; } @@ -877,10 +887,15 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, i = ++last_hvc; hp->index = i; + cons_ops[i] = ops; + vtermnos[i] = vtermno; list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); + /* check if we need to re-register the kernel console */ + hvc_check_console(i); + return hp; } EXPORT_SYMBOL_GPL(hvc_alloc); @@ -893,8 +908,12 @@ int hvc_remove(struct hvc_struct *hp) tty = tty_port_tty_get(&hp->port); spin_lock_irqsave(&hp->lock, flags); - if (hp->index < MAX_NR_HVC_CONSOLES) + if (hp->index < MAX_NR_HVC_CONSOLES) { + console_lock(); vtermnos[hp->index] = -1; + cons_ops[hp->index] = NULL; + console_unlock(); + } /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index ee307799271a..070c0ee68642 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -230,6 +230,69 @@ static const struct hv_ops hvterm_hvsi_ops = { .tiocmset = hvterm_hvsi_tiocmset, }; +static void udbg_hvc_putc(char c) +{ + int count = -1; + + if (!hvterm_privs[0]) + return; + + if (c == '\n') + udbg_hvc_putc('\r'); + + do { + switch(hvterm_privs[0]->proto) { + case HV_PROTOCOL_RAW: + count = hvterm_raw_put_chars(0, &c, 1); + break; + case HV_PROTOCOL_HVSI: + count = hvterm_hvsi_put_chars(0, &c, 1); + break; + } + } while(count == 0); +} + +static int udbg_hvc_getc_poll(void) +{ + int rc = 0; + char c; + + if (!hvterm_privs[0]) + return -1; + + switch(hvterm_privs[0]->proto) { + case HV_PROTOCOL_RAW: + rc = hvterm_raw_get_chars(0, &c, 1); + break; + case HV_PROTOCOL_HVSI: + rc = hvterm_hvsi_get_chars(0, &c, 1); + break; + } + if (!rc) + return -1; + return c; +} + +static int udbg_hvc_getc(void) +{ + int ch; + + if (!hvterm_privs[0]) + return -1; + + for (;;) { + ch = udbg_hvc_getc_poll(); + if (ch == -1) { + /* This shouldn't be needed...but... */ + volatile unsigned long delay; + for (delay=0; delay < 2000000; delay++) + ; + } else { + return ch; + } + } +} + static int __devinit hvc_vio_probe(struct vio_dev *vdev, const struct vio_device_id *id) { @@ -289,6 +352,13 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev, return PTR_ERR(hp); dev_set_drvdata(&vdev->dev, hp); + /* register udbg if it's not there already for console 0 */ + if (hp->index == 0 && !udbg_putc) { + udbg_putc = udbg_hvc_putc; + udbg_getc = udbg_hvc_getc; + udbg_getc_poll = udbg_hvc_getc_poll; + } + return 0; } @@ -331,59 +401,6 @@ static void __exit hvc_vio_exit(void) } module_exit(hvc_vio_exit); -static void udbg_hvc_putc(char c) -{ - int count = -1; - - if (c == '\n') - udbg_hvc_putc('\r'); - - do { - switch(hvterm_priv0.proto) { - case HV_PROTOCOL_RAW: - count = hvterm_raw_put_chars(0, &c, 1); - break; - case HV_PROTOCOL_HVSI: - count = hvterm_hvsi_put_chars(0, &c, 1); - break; - } - } while(count == 0); -} - -static int udbg_hvc_getc_poll(void) -{ - int rc = 0; - char c; - - switch(hvterm_priv0.proto) { - case HV_PROTOCOL_RAW: - rc = hvterm_raw_get_chars(0, &c, 1); - break; - case HV_PROTOCOL_HVSI: - rc = hvterm_hvsi_get_chars(0, &c, 1); - break; - } - if (!rc) - return -1; - return c; -} - -static int udbg_hvc_getc(void) -{ - int ch; - for (;;) { - ch = udbg_hvc_getc_poll(); - if (ch == -1) { - /* This shouldn't be needed...but... */ - volatile unsigned long delay; - for (delay=0; delay < 2000000; delay++) - ; - } else { - return ch; - } - } -} - void __init hvc_vio_init_early(void) { struct device_node *stdout_node; diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 747442d2c0f6..0fefa84ed9ae 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -149,7 +149,7 @@ enum { }; /* Must match above enum */ -static const char *r128_family[] __devinitdata = { +static char * const r128_family[] __devinitconst = { "AGP", "PCI", "PRO AGP", diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index f49181c73113..b7ec34c57f46 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/fb.h> @@ -31,57 +32,26 @@ struct pm860x_backlight_data { int port; int pwm; int iset; + int reg_duty_cycle; + int reg_always_on; + int reg_current; }; -static inline int wled_a(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 2; - return ret; -} - -static inline int wled_b(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - return ret; -} - -/* WLED2 & WLED3 share the same IDC */ -static inline int wled_idc(int port) -{ - int ret; - - switch (port) { - case PM8606_BACKLIGHT1: - case PM8606_BACKLIGHT2: - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - break; - case PM8606_BACKLIGHT3: - default: - ret = ((port - PM8606_BACKLIGHT2) << 1) + 3; - break; - } - return ret; -} - static int backlight_power_set(struct pm860x_chip *chip, int port, int on) { int ret = -EINVAL; switch (port) { - case PM8606_BACKLIGHT1: + case 0: ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) : pm8606_osc_disable(chip, WLED1_DUTY); break; - case PM8606_BACKLIGHT2: + case 1: ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) : pm8606_osc_disable(chip, WLED2_DUTY); break; - case PM8606_BACKLIGHT3: + case 2: ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) : pm8606_osc_disable(chip, WLED3_DUTY); break; @@ -104,13 +74,13 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) if (brightness) backlight_power_set(chip, data->port, 1); - ret = pm860x_reg_write(data->i2c, wled_a(data->port), value); + ret = pm860x_reg_write(data->i2c, data->reg_duty_cycle, value); if (ret < 0) goto out; if ((data->current_brightness == 0) && brightness) { if (data->iset) { - ret = pm860x_set_bits(data->i2c, wled_idc(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_current, CURRENT_BITMASK, data->iset); if (ret < 0) goto out; @@ -123,17 +93,17 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) } if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } } else { if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } else { /* clear WLED_ON bit since it's not 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, 0); } } @@ -174,7 +144,7 @@ static int pm860x_backlight_get_brightness(struct backlight_device *bl) struct pm860x_chip *chip = data->chip; int ret; - ret = pm860x_reg_read(data->i2c, wled_a(data->port)); + ret = pm860x_reg_read(data->i2c, data->reg_duty_cycle); if (ret < 0) goto out; data->current_brightness = ret; @@ -190,45 +160,85 @@ static const struct backlight_ops pm860x_backlight_ops = { .get_brightness = pm860x_backlight_get_brightness, }; +#ifdef CONFIG_OF +static int pm860x_backlight_dt_init(struct platform_device *pdev, + struct pm860x_backlight_data *data, + char *name) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "backlights"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find backlights node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_WLED_CURRENT(iset); + of_property_read_u32(np, "marvell,88pm860x-pwm", + &data->pwm); + break; + } + } + return 0; +} +#else +#define pm860x_backlight_dt_init(x, y, z) (-1) +#endif + static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_backlight_pdata *pdata = NULL; + struct pm860x_backlight_pdata *pdata = pdev->dev.platform_data; struct pm860x_backlight_data *data; struct backlight_device *bl; struct resource *res; struct backlight_properties props; char name[MFD_NAME_SIZE]; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MFD_NAME_SIZE); + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "duty cycle"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for duty cycle\n"); + ret = -ENXIO; + goto out; + } + data->reg_duty_cycle = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "always on"); + if (!res) { + dev_err(&pdev->dev, "No REG resorce for always on\n"); + ret = -ENXIO; + goto out; + } + data->reg_always_on = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "current"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for current\n"); + ret = -ENXIO; + goto out; + } + data->reg_current = res->start; + + memset(name, 0, MFD_NAME_SIZE); + sprintf(name, "backlight-%d", pdev->id); + data->port = pdev->id; data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; - data->pwm = pdata->pwm; - data->iset = pdata->iset; - data->port = pdata->flags; - if (data->port < 0) { - dev_err(&pdev->dev, "wrong platform data is assigned"); - return -EINVAL; + if (pm860x_backlight_dt_init(pdev, data, name)) { + if (pdata) { + data->pwm = pdata->pwm; + data->iset = pdata->iset; + } } memset(&props, 0, sizeof(struct backlight_properties)); @@ -247,12 +257,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev) /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index cf282763a8dc..c101697a4ba7 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -229,13 +229,6 @@ config BACKLIGHT_HP700 If you have an HP Jornada 700 series, say Y to include backlight control driver. -config BACKLIGHT_PROGEAR - tristate "Frontpath ProGear Backlight Driver" - depends on PCI && X86 - help - If you have a Frontpath ProGear say Y to enable the - backlight driver. - config BACKLIGHT_CARILLO_RANCH tristate "Intel Carillo Ranch Backlight Driver" depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 @@ -352,6 +345,22 @@ config BACKLIGHT_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the backlight driver. +config BACKLIGHT_LM3630 + tristate "Backlight Driver for LM3630" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select REGMAP_I2C + help + This supports TI LM3630 Backlight Driver + +config BACKLIGHT_LM3639 + tristate "Backlight Driver for LM3639" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select REGMAP_I2C + select NEW_LEDS + select LEDS_CLASS + help + This supports TI LM3639 Backlight + 1.5A Flash LED Driver + config BACKLIGHT_LP855X tristate "Backlight driver for TI LP855X" depends on BACKLIGHT_CLASS_DEVICE && I2C @@ -373,6 +382,13 @@ config BACKLIGHT_PANDORA If you have a Pandora console, say Y to enable the backlight driver. +config BACKLIGHT_TPS65217 + tristate "TPS65217 Backlight" + depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 + help + If you have a Texas Instruments TPS65217 say Y to enable the + backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index a2ac9cfbaf6b..e7ce7291635d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -23,10 +23,11 @@ obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o +obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o +obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o -obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o @@ -43,3 +44,4 @@ obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o +obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index b628d68f5162..ac196181fe45 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -72,7 +72,7 @@ static int da9052_adjust_wled_brightness(struct da9052_bl *wleds) if (ret < 0) return ret; - msleep(10); + usleep_range(10000, 11000); if (wleds->brightness) { ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg], @@ -129,7 +129,6 @@ static int da9052_backlight_probe(struct platform_device *pdev) &da9052_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "Failed to register backlight\n"); - devm_kfree(&pdev->dev, wleds); return PTR_ERR(bl); } @@ -149,7 +148,6 @@ static int da9052_backlight_remove(struct platform_device *pdev) wleds->state = DA9052_WLEDS_OFF; da9052_adjust_wled_brightness(wleds); backlight_device_unregister(bl); - devm_kfree(&pdev->dev, wleds); return 0; } diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index 72dd5556a35b..6c5ed6b242cc 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -34,9 +34,9 @@ static void kb3886_bl_set_intensity(int intensity) mutex_lock(&bl_mutex); intensity = intensity&0xff; outb(KB3886_ADC_DAC_PWM, KB3886_PARENT); - msleep(10); + usleep_range(10000, 11000); outb(KB3886_PWM0_WRITE, KB3886_IO); - msleep(10); + usleep_range(10000, 11000); outb(intensity, KB3886_IO); mutex_unlock(&bl_mutex); } diff --git a/drivers/video/backlight/lm3630_bl.c b/drivers/video/backlight/lm3630_bl.c new file mode 100644 index 000000000000..dc191441796f --- /dev/null +++ b/drivers/video/backlight/lm3630_bl.c @@ -0,0 +1,475 @@ +/* +* Simple driver for Texas Instruments LM3630 Backlight driver chip +* Copyright (C) 2012 Texas Instruments +* +* 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/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/platform_data/lm3630_bl.h> + +#define REG_CTRL 0x00 +#define REG_CONFIG 0x01 +#define REG_BRT_A 0x03 +#define REG_BRT_B 0x04 +#define REG_INT_STATUS 0x09 +#define REG_INT_EN 0x0A +#define REG_FAULT 0x0B +#define REG_PWM_OUTLOW 0x12 +#define REG_PWM_OUTHIGH 0x13 +#define REG_MAX 0x1F + +#define INT_DEBOUNCE_MSEC 10 + +enum lm3630_leds { + BLED_ALL = 0, + BLED_1, + BLED_2 +}; + +static const char *bled_name[] = { + [BLED_ALL] = "lm3630_bled", /*Bank1 controls all string */ + [BLED_1] = "lm3630_bled1", /*Bank1 controls bled1 */ + [BLED_2] = "lm3630_bled2", /*Bank1 or 2 controls bled2 */ +}; + +struct lm3630_chip_data { + struct device *dev; + struct delayed_work work; + int irq; + struct workqueue_struct *irqthread; + struct lm3630_platform_data *pdata; + struct backlight_device *bled1; + struct backlight_device *bled2; + struct regmap *regmap; +}; + +/* initialize chip */ +static int __devinit lm3630_chip_init(struct lm3630_chip_data *pchip) +{ + int ret; + unsigned int reg_val; + struct lm3630_platform_data *pdata = pchip->pdata; + + /*pwm control */ + reg_val = ((pdata->pwm_active & 0x01) << 2) | (pdata->pwm_ctrl & 0x03); + ret = regmap_update_bits(pchip->regmap, REG_CONFIG, 0x07, reg_val); + if (ret < 0) + goto out; + + /* bank control */ + reg_val = ((pdata->bank_b_ctrl & 0x01) << 1) | + (pdata->bank_a_ctrl & 0x07); + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x07, reg_val); + if (ret < 0) + goto out; + + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + + /* set initial brightness */ + if (pdata->bank_a_ctrl != BANK_A_CTRL_DISABLE) { + ret = regmap_write(pchip->regmap, + REG_BRT_A, pdata->init_brt_led1); + if (ret < 0) + goto out; + } + + if (pdata->bank_b_ctrl != BANK_B_CTRL_DISABLE) { + ret = regmap_write(pchip->regmap, + REG_BRT_B, pdata->init_brt_led2); + if (ret < 0) + goto out; + } + return ret; + +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return ret; +} + +/* interrupt handling */ +static void lm3630_delayed_func(struct work_struct *work) +{ + int ret; + unsigned int reg_val; + struct lm3630_chip_data *pchip; + + pchip = container_of(work, struct lm3630_chip_data, work.work); + + ret = regmap_read(pchip->regmap, REG_INT_STATUS, ®_val); + if (ret < 0) { + dev_err(pchip->dev, + "i2c failed to access REG_INT_STATUS Register\n"); + return; + } + + dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", reg_val); +} + +static irqreturn_t lm3630_isr_func(int irq, void *chip) +{ + int ret; + struct lm3630_chip_data *pchip = chip; + unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); + + queue_delayed_work(pchip->irqthread, &pchip->work, delay); + + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + + return IRQ_HANDLED; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return IRQ_HANDLED; +} + +static int lm3630_intr_config(struct lm3630_chip_data *pchip) +{ + INIT_DELAYED_WORK(&pchip->work, lm3630_delayed_func); + pchip->irqthread = create_singlethread_workqueue("lm3630-irqthd"); + if (!pchip->irqthread) { + dev_err(pchip->dev, "create irq thread fail...\n"); + return -1; + } + if (request_threaded_irq + (pchip->irq, NULL, lm3630_isr_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630_irq", pchip)) { + dev_err(pchip->dev, "request threaded irq fail..\n"); + return -1; + } + return 0; +} + +static bool +set_intensity(struct backlight_device *bl, struct lm3630_chip_data *pchip) +{ + if (!pchip->pdata->pwm_set_intensity) + return false; + pchip->pdata->pwm_set_intensity(bl->props.brightness - 1, + pchip->pdata->pwm_period); + return true; +} + +/* update and get brightness */ +static int lm3630_bank_a_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + /* brightness 0 means disable */ + if (!bl->props.brightness) { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x04, 0x00); + if (ret < 0) + goto out; + return bl->props.brightness; + } + + /* pwm control */ + if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) { + if (!set_intensity(bl, pchip)) + dev_err(pchip->dev, "No pwm control func. in plat-data\n"); + } else { + + /* i2c control */ + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_write(pchip->regmap, + REG_BRT_A, bl->props.brightness - 1); + if (ret < 0) + goto out; + } + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); + return bl->props.brightness; +} + +static int lm3630_bank_a_get_brightness(struct backlight_device *bl) +{ + unsigned int reg_val; + int brightness, ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) { + ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, ®_val); + if (ret < 0) + goto out; + brightness = reg_val & 0x01; + ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, ®_val); + if (ret < 0) + goto out; + brightness = ((brightness << 8) | reg_val) + 1; + } else { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_read(pchip->regmap, REG_BRT_A, ®_val); + if (ret < 0) + goto out; + brightness = reg_val + 1; + } + bl->props.brightness = brightness; + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +} + +static const struct backlight_ops lm3630_bank_a_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630_bank_a_update_status, + .get_brightness = lm3630_bank_a_get_brightness, +}; + +static int lm3630_bank_b_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) { + if (!set_intensity(bl, pchip)) + dev_err(pchip->dev, + "no pwm control func. in plat-data\n"); + } else { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_write(pchip->regmap, + REG_BRT_B, bl->props.brightness - 1); + } + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static int lm3630_bank_b_get_brightness(struct backlight_device *bl) +{ + unsigned int reg_val; + int brightness, ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) { + ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, ®_val); + if (ret < 0) + goto out; + brightness = reg_val & 0x01; + ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, ®_val); + if (ret < 0) + goto out; + brightness = ((brightness << 8) | reg_val) + 1; + } else { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_read(pchip->regmap, REG_BRT_B, ®_val); + if (ret < 0) + goto out; + brightness = reg_val + 1; + } + bl->props.brightness = brightness; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static const struct backlight_ops lm3630_bank_b_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630_bank_b_update_status, + .get_brightness = lm3630_bank_b_get_brightness, +}; + +static int lm3630_backlight_register(struct lm3630_chip_data *pchip, + enum lm3630_leds ledno) +{ + const char *name = bled_name[ledno]; + struct backlight_properties props; + struct lm3630_platform_data *pdata = pchip->pdata; + + props.type = BACKLIGHT_RAW; + switch (ledno) { + case BLED_1: + case BLED_ALL: + props.brightness = pdata->init_brt_led1; + props.max_brightness = pdata->max_brt_led1; + pchip->bled1 = + backlight_device_register(name, pchip->dev, pchip, + &lm3630_bank_a_ops, &props); + if (IS_ERR(pchip->bled1)) + return -EIO; + break; + case BLED_2: + props.brightness = pdata->init_brt_led2; + props.max_brightness = pdata->max_brt_led2; + pchip->bled2 = + backlight_device_register(name, pchip->dev, pchip, + &lm3630_bank_b_ops, &props); + if (IS_ERR(pchip->bled2)) + return -EIO; + break; + } + return 0; +} + +static void lm3630_backlight_unregister(struct lm3630_chip_data *pchip) +{ + if (pchip->bled1) + backlight_device_unregister(pchip->bled1); + if (pchip->bled2) + backlight_device_unregister(pchip->bled2); +} + +static const struct regmap_config lm3630_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int __devinit lm3630_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3630_platform_data *pdata = client->dev.platform_data; + struct lm3630_chip_data *pchip; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "fail : i2c functionality check...\n"); + return -EOPNOTSUPP; + } + + if (pdata == NULL) { + dev_err(&client->dev, "fail : no platform data.\n"); + return -ENODATA; + } + + pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630_chip_data), + GFP_KERNEL); + if (!pchip) + return -ENOMEM; + pchip->pdata = pdata; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3630_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate register map: %d\n", + ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + /* chip initialize */ + ret = lm3630_chip_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail : init chip\n"); + goto err_chip_init; + } + + switch (pdata->bank_a_ctrl) { + case BANK_A_CTRL_ALL: + ret = lm3630_backlight_register(pchip, BLED_ALL); + pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE; + break; + case BANK_A_CTRL_LED1: + ret = lm3630_backlight_register(pchip, BLED_1); + break; + case BANK_A_CTRL_LED2: + ret = lm3630_backlight_register(pchip, BLED_2); + pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE; + break; + default: + break; + } + + if (ret < 0) + goto err_bl_reg; + + if (pdata->bank_b_ctrl && pchip->bled2 == NULL) { + ret = lm3630_backlight_register(pchip, BLED_2); + if (ret < 0) + goto err_bl_reg; + } + + /* interrupt enable : irq 0 is not allowed for lm3630 */ + pchip->irq = client->irq; + if (pchip->irq) + lm3630_intr_config(pchip); + + dev_info(&client->dev, "LM3630 backlight register OK.\n"); + return 0; + +err_bl_reg: + dev_err(&client->dev, "fail : backlight register.\n"); + lm3630_backlight_unregister(pchip); +err_chip_init: + return ret; +} + +static int __devexit lm3630_remove(struct i2c_client *client) +{ + int ret; + struct lm3630_chip_data *pchip = i2c_get_clientdata(client); + + ret = regmap_write(pchip->regmap, REG_BRT_A, 0); + if (ret < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + ret = regmap_write(pchip->regmap, REG_BRT_B, 0); + if (ret < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + lm3630_backlight_unregister(pchip); + if (pchip->irq) { + free_irq(pchip->irq, pchip); + flush_workqueue(pchip->irqthread); + destroy_workqueue(pchip->irqthread); + } + return 0; +} + +static const struct i2c_device_id lm3630_id[] = { + {LM3630_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3630_id); + +static struct i2c_driver lm3630_i2c_driver = { + .driver = { + .name = LM3630_NAME, + }, + .probe = lm3630_probe, + .remove = __devexit_p(lm3630_remove), + .id_table = lm3630_id, +}; + +module_i2c_driver(lm3630_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630"); +MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c new file mode 100644 index 000000000000..c6915c6c3cd1 --- /dev/null +++ b/drivers/video/backlight/lm3639_bl.c @@ -0,0 +1,437 @@ +/* +* Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip +* Copyright (C) 2012 Texas Instruments +* +* 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/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/platform_data/lm3639_bl.h> + +#define REG_DEV_ID 0x00 +#define REG_CHECKSUM 0x01 +#define REG_BL_CONF_1 0x02 +#define REG_BL_CONF_2 0x03 +#define REG_BL_CONF_3 0x04 +#define REG_BL_CONF_4 0x05 +#define REG_FL_CONF_1 0x06 +#define REG_FL_CONF_2 0x07 +#define REG_FL_CONF_3 0x08 +#define REG_IO_CTRL 0x09 +#define REG_ENABLE 0x0A +#define REG_FLAG 0x0B +#define REG_MAX REG_FLAG + +struct lm3639_chip_data { + struct device *dev; + struct lm3639_platform_data *pdata; + + struct backlight_device *bled; + struct led_classdev cdev_flash; + struct led_classdev cdev_torch; + struct regmap *regmap; + + unsigned int bled_mode; + unsigned int bled_map; + unsigned int last_flag; +}; + +/* initialize chip */ +static int __devinit lm3639_chip_init(struct lm3639_chip_data *pchip) +{ + int ret; + unsigned int reg_val; + struct lm3639_platform_data *pdata = pchip->pdata; + + /* input pins config. */ + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08, + pdata->pin_pwm); + if (ret < 0) + goto out; + + reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx; + ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val); + if (ret < 0) + goto out; + + /* init brightness */ + ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led); + if (ret < 0) + goto out; + + ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led); + if (ret < 0) + goto out; + + /* output pins config. */ + if (!pdata->init_brt_led) + reg_val = pdata->fled_pins | pdata->bled_pins; + else + reg_val = pdata->fled_pins | pdata->bled_pins | 0x01; + + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); + if (ret < 0) + goto out; + + return ret; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return ret; +} + +/* update and get brightness */ +static int lm3639_bled_update_status(struct backlight_device *bl) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip = bl_get_data(bl); + struct lm3639_platform_data *pdata = pchip->pdata; + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* pwm control */ + if (pdata->pin_pwm) { + if (pdata->pwm_set_intensity) + pdata->pwm_set_intensity(bl->props.brightness, + pdata->max_brt_led); + else + dev_err(pchip->dev, + "No pwm control func. in plat-data\n"); + return bl->props.brightness; + } + + /* i2c control and set brigtness */ + ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness); + if (ret < 0) + goto out; + ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness); + if (ret < 0) + goto out; + + if (!bl->props.brightness) + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00); + else + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01); + if (ret < 0) + goto out; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access registers\n"); + return bl->props.brightness; +} + +static int lm3639_bled_get_brightness(struct backlight_device *bl) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip = bl_get_data(bl); + struct lm3639_platform_data *pdata = pchip->pdata; + + if (pdata->pin_pwm) { + if (pdata->pwm_get_intensity) + bl->props.brightness = pdata->pwm_get_intensity(); + else + dev_err(pchip->dev, + "No pwm control func. in plat-data\n"); + return bl->props.brightness; + } + + ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val); + if (ret < 0) + goto out; + if (reg_val & 0x10) + ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val); + else + ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val); + if (ret < 0) + goto out; + bl->props.brightness = reg_val; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static const struct backlight_ops lm3639_bled_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3639_bled_update_status, + .get_brightness = lm3639_bled_get_brightness, +}; + +/* backlight mapping mode */ +static ssize_t lm3639_bled_mode_store(struct device *dev, + struct device_attribute *devAttr, + const char *buf, size_t size) +{ + ssize_t ret; + struct lm3639_chip_data *pchip = dev_get_drvdata(dev); + unsigned int state; + + ret = kstrtouint(buf, 10, &state); + if (ret) + goto out_input; + + if (!state) + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, + 0x00); + else + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, + 0x10); + + if (ret < 0) + goto out; + + return size; + +out: + dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__); + return size; + +out_input: + dev_err(pchip->dev, "%s:input conversion fail\n", __func__); + return size; + +} + +static DEVICE_ATTR(bled_mode, 0666, NULL, lm3639_bled_mode_store); + +/* torch */ +static void lm3639_torch_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip; + + pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch); + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* brightness 0 means off state */ + if (!brightness) { + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); + if (ret < 0) + goto out; + return; + } + + ret = regmap_update_bits(pchip->regmap, + REG_FL_CONF_1, 0x70, (brightness - 1) << 4); + if (ret < 0) + goto out; + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02); + if (ret < 0) + goto out; + + return; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return; +} + +/* flash */ +static void lm3639_flash_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip; + + pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash); + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* torch off before flash control */ + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); + if (ret < 0) + goto out; + + /* brightness 0 means off state */ + if (!brightness) + return; + + ret = regmap_update_bits(pchip->regmap, + REG_FL_CONF_1, 0x0F, brightness - 1); + if (ret < 0) + goto out; + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06); + if (ret < 0) + goto out; + + return; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return; +} + +static const struct regmap_config lm3639_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int __devinit lm3639_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct lm3639_chip_data *pchip; + struct lm3639_platform_data *pdata = client->dev.platform_data; + struct backlight_properties props; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c functionality check fail.\n"); + return -EOPNOTSUPP; + } + + if (pdata == NULL) { + dev_err(&client->dev, "Needs Platform Data.\n"); + return -ENODATA; + } + + pchip = devm_kzalloc(&client->dev, + sizeof(struct lm3639_chip_data), GFP_KERNEL); + if (!pchip) + return -ENOMEM; + + pchip->pdata = pdata; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate register map: %d\n", + ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + /* chip initialize */ + ret = lm3639_chip_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail : chip init\n"); + goto err_out; + } + + /* backlight */ + props.type = BACKLIGHT_RAW; + props.brightness = pdata->init_brt_led; + props.max_brightness = pdata->max_brt_led; + pchip->bled = + backlight_device_register("lm3639_bled", pchip->dev, pchip, + &lm3639_bled_ops, &props); + if (IS_ERR(pchip->bled)) { + dev_err(&client->dev, "fail : backlight register\n"); + ret = -EIO; + goto err_out; + } + + ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); + if (ret < 0) { + dev_err(&client->dev, "failed : add sysfs entries\n"); + ret = -EIO; + goto err_bled_mode; + } + + /* flash */ + pchip->cdev_flash.name = "lm3639_flash"; + pchip->cdev_flash.max_brightness = 16; + pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set; + ret = led_classdev_register((struct device *) + &client->dev, &pchip->cdev_flash); + if (ret < 0) { + dev_err(&client->dev, "fail : flash register\n"); + ret = -EIO; + goto err_flash; + } + + /* torch */ + pchip->cdev_torch.name = "lm3639_torch"; + pchip->cdev_torch.max_brightness = 8; + pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set; + ret = led_classdev_register((struct device *) + &client->dev, &pchip->cdev_torch); + if (ret < 0) { + dev_err(&client->dev, "fail : torch register\n"); + ret = -EIO; + goto err_torch; + } + + return 0; + +err_torch: + led_classdev_unregister(&pchip->cdev_flash); +err_flash: + device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); +err_bled_mode: + backlight_device_unregister(pchip->bled); +err_out: + return ret; +} + +static int __devexit lm3639_remove(struct i2c_client *client) +{ + struct lm3639_chip_data *pchip = i2c_get_clientdata(client); + + regmap_write(pchip->regmap, REG_ENABLE, 0x00); + + if (&pchip->cdev_torch) + led_classdev_unregister(&pchip->cdev_torch); + if (&pchip->cdev_flash) + led_classdev_unregister(&pchip->cdev_flash); + if (pchip->bled) { + device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); + backlight_device_unregister(pchip->bled); + } + return 0; +} + +static const struct i2c_device_id lm3639_id[] = { + {LM3639_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3639_id); +static struct i2c_driver lm3639_i2c_driver = { + .driver = { + .name = LM3639_NAME, + }, + .probe = lm3639_probe, + .remove = __devexit_p(lm3639_remove), + .id_table = lm3639_id, +}; + +module_i2c_driver(lm3639_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); +MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index 6c0f1ac0d32a..4066a5bbd826 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -75,7 +75,7 @@ static int ltv350qv_power_on(struct ltv350qv *lcd) /* Power On Reset Display off State */ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000)) goto err; - msleep(15); + usleep_range(15000, 16000); /* Power Setting Function 1 */ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE)) @@ -153,7 +153,7 @@ err_settings: err_power2: err_power1: ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); - msleep(1); + usleep_range(1000, 1100); err: ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); return -EIO; @@ -175,7 +175,7 @@ static int ltv350qv_power_off(struct ltv350qv *lcd) ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); /* Wait at least 1 ms */ - msleep(1); + usleep_range(1000, 1100); /* Power down setting 2 */ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index e833ac72e063..f72ba54f364e 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -27,7 +27,9 @@ struct max8925_backlight_data { struct max8925_chip *chip; - int current_brightness; + int current_brightness; + int reg_mode_cntl; + int reg_cntl; }; static int max8925_backlight_set(struct backlight_device *bl, int brightness) @@ -42,16 +44,16 @@ static int max8925_backlight_set(struct backlight_device *bl, int brightness) else value = brightness; - ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value); + ret = max8925_reg_write(chip->i2c, data->reg_cntl, value); if (ret < 0) goto out; if (!data->current_brightness && brightness) /* enable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1); else if (!brightness) /* disable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0); if (ret < 0) goto out; dev_dbg(chip->dev, "set brightness %d\n", value); @@ -85,7 +87,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl) struct max8925_chip *chip = data->chip; int ret; - ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL); + ret = max8925_reg_read(chip->i2c, data->reg_cntl); if (ret < 0) return -EINVAL; data->current_brightness = ret; @@ -102,69 +104,70 @@ static const struct backlight_ops max8925_backlight_ops = { static int __devinit max8925_backlight_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *max8925_pdata; - struct max8925_backlight_pdata *pdata = NULL; + struct max8925_backlight_pdata *pdata = pdev->dev.platform_data; struct max8925_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; struct resource *res; - char name[MAX8925_NAME_SIZE]; unsigned char value; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - if (pdev->dev.parent->platform_data) { - max8925_pdata = pdev->dev.parent->platform_data; - pdata = max8925_pdata->backlight; - } - - if (!pdata) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MAX8925_NAME_SIZE); + + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (!res) { + dev_err(&pdev->dev, "No REG resource for mode control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_mode_cntl = res->start; + res = platform_get_resource(pdev, IORESOURCE_REG, 1); + if (!res) { + dev_err(&pdev->dev, "No REG resource for control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_cntl = res->start; + data->chip = chip; data->current_brightness = 0; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register(name, &pdev->dev, data, + bl = backlight_device_register("max8925-backlight", &pdev->dev, data, &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - return PTR_ERR(bl); + ret = PTR_ERR(bl); + goto out; } bl->props.brightness = MAX_BRIGHTNESS; platform_set_drvdata(pdev, bl); value = 0; - if (pdata->lxw_scl) - value |= (1 << 7); - if (pdata->lxw_freq) - value |= (LWX_FREQ(pdata->lxw_freq) << 4); - if (pdata->dual_string) - value |= (1 << 1); - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value); + if (pdata) { + if (pdata->lxw_scl) + value |= (1 << 7); + if (pdata->lxw_freq) + value |= (LWX_FREQ(pdata->lxw_freq) << 4); + if (pdata->dual_string) + value |= (1 << 1); + } + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index b6672340d6c7..ca4f5d70fe10 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -16,6 +16,7 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/lcd.h> +#include <linux/of.h> #include <linux/slab.h> #include <video/platform_lcd.h> @@ -145,6 +146,14 @@ static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend, platform_lcd_resume); #endif +#ifdef CONFIG_OF +static const struct of_device_id platform_lcd_of_match[] = { + { .compatible = "platform-lcd" }, + {}, +}; +MODULE_DEVICE_TABLE(of, platform_lcd_of_match); +#endif + static struct platform_driver platform_lcd_driver = { .driver = { .name = "platform-lcd", @@ -152,6 +161,7 @@ static struct platform_driver platform_lcd_driver = { #ifdef CONFIG_PM .pm = &platform_lcd_pm_ops, #endif + .of_match_table = of_match_ptr(platform_lcd_of_match), }, .probe = platform_lcd_probe, .remove = __devexit_p(platform_lcd_remove), diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c deleted file mode 100644 index 69b35f02929e..000000000000 --- a/drivers/video/backlight/progear_bl.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Backlight Driver for Frontpath ProGear HX1050+ - * - * Copyright (c) 2006 Marcin Juszkiewicz - * - * Based on Progear LCD driver by M Schacht - * <mschacht at alumni dot washington dot edu> - * - * Based on Sharp's Corgi Backlight Driver - * Based on Backlight Driver for HP Jornada 680 - * - * 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. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/fb.h> -#include <linux/backlight.h> -#include <linux/pci.h> - -#define PMU_LPCR 0xB0 -#define SB_MPS1 0x61 -#define HW_LEVEL_MAX 0x77 -#define HW_LEVEL_MIN 0x4f - -static struct pci_dev *pmu_dev = NULL; -static struct pci_dev *sb_dev = NULL; - -static int progearbl_set_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (bd->props.power != FB_BLANK_UNBLANK) - intensity = 0; - if (bd->props.fb_blank != FB_BLANK_UNBLANK) - intensity = 0; - - pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN); - - return 0; -} - -static int progearbl_get_intensity(struct backlight_device *bd) -{ - u8 intensity; - pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity); - - return intensity - HW_LEVEL_MIN; -} - -static const struct backlight_ops progearbl_ops = { - .get_brightness = progearbl_get_intensity, - .update_status = progearbl_set_intensity, -}; - -static int progearbl_probe(struct platform_device *pdev) -{ - struct backlight_properties props; - u8 temp; - struct backlight_device *progear_backlight_device; - int ret; - - pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL); - if (!pmu_dev) { - pr_err("ALI M7101 PMU not found.\n"); - return -ENODEV; - } - - sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - if (!sb_dev) { - pr_err("ALI 1533 SB not found.\n"); - ret = -ENODEV; - goto put_pmu; - } - - /* Set SB_MPS1 to enable brightness control. */ - pci_read_config_byte(sb_dev, SB_MPS1, &temp); - pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20); - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progear_backlight_device = backlight_device_register("progear-bl", - &pdev->dev, NULL, - &progearbl_ops, - &props); - if (IS_ERR(progear_backlight_device)) { - ret = PTR_ERR(progear_backlight_device); - goto put_sb; - } - - platform_set_drvdata(pdev, progear_backlight_device); - - progear_backlight_device->props.power = FB_BLANK_UNBLANK; - progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progearbl_set_intensity(progear_backlight_device); - - return 0; -put_sb: - pci_dev_put(sb_dev); -put_pmu: - pci_dev_put(pmu_dev); - return ret; -} - -static int progearbl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - backlight_device_unregister(bd); - - return 0; -} - -static struct platform_driver progearbl_driver = { - .probe = progearbl_probe, - .remove = progearbl_remove, - .driver = { - .name = "progear-bl", - }, -}; - -static struct platform_device *progearbl_device; - -static int __init progearbl_init(void) -{ - int ret = platform_driver_register(&progearbl_driver); - - if (ret) - return ret; - progearbl_device = platform_device_register_simple("progear-bl", -1, - NULL, 0); - if (IS_ERR(progearbl_device)) { - platform_driver_unregister(&progearbl_driver); - return PTR_ERR(progearbl_device); - } - - return 0; -} - -static void __exit progearbl_exit(void) -{ - pci_dev_put(pmu_dev); - pci_dev_put(sb_dev); - - platform_device_unregister(progearbl_device); - platform_driver_unregister(&progearbl_driver); -} - -module_init(progearbl_init); -module_exit(progearbl_exit); - -MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>"); -MODULE_DESCRIPTION("ProGear Backlight Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c new file mode 100644 index 000000000000..70881633b45a --- /dev/null +++ b/drivers/video/backlight/tps65217_bl.c @@ -0,0 +1,342 @@ +/* + * tps65217_bl.c + * + * TPS65217 backlight driver + * + * Copyright (C) 2012 Matthias Kaehlcke + * Author: Matthias Kaehlcke <matthias@kaehlcke.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 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/backlight.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/mfd/tps65217.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct tps65217_bl { + struct tps65217 *tps; + struct device *dev; + struct backlight_device *bl; + bool is_enabled; +}; + +static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to enable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = true; + + dev_dbg(tps65217_bl->dev, "backlight enabled\n"); + + return 0; +} + +static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to disable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = false; + + dev_dbg(tps65217_bl->dev, "backlight disabled\n"); + + return 0; +} + +static int tps65217_bl_update_status(struct backlight_device *bl) +{ + struct tps65217_bl *tps65217_bl = bl_get_data(bl); + int rc; + int brightness = bl->props.brightness; + + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + if ((bl->props.power != FB_BLANK_UNBLANK) || + (bl->props.fb_blank != FB_BLANK_UNBLANK)) + /* framebuffer in low power mode or blanking active */ + brightness = 0; + + if (brightness > 0) { + rc = tps65217_reg_write(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL2, + brightness - 1, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to set brightness level: %d\n", rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness); + + if (!tps65217_bl->is_enabled) + rc = tps65217_bl_enable(tps65217_bl); + } else { + rc = tps65217_bl_disable(tps65217_bl); + } + + return rc; +} + +static int tps65217_bl_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static const struct backlight_ops tps65217_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = tps65217_bl_update_status, + .get_brightness = tps65217_bl_get_brightness +}; + +static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl, + struct tps65217_bl_pdata *pdata) +{ + int rc; + + rc = tps65217_bl_disable(tps65217_bl); + if (rc) + return rc; + + switch (pdata->isel) { + case TPS65217_BL_ISET1: + /* select ISET_1 current level */ + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET1 current level: %d)\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n"); + + break; + + case TPS65217_BL_ISET2: + /* select ISET2 current level */ + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET2 current level: %d\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n"); + + break; + + default: + dev_err(tps65217_bl->dev, + "invalid value for current level: %d\n", pdata->isel); + return -EINVAL; + } + + /* set PWM frequency */ + rc = tps65217_set_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_FDIM_MASK, + pdata->fdim, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select PWM dimming frequency: %d\n", + rc); + return rc; + } + + return 0; +} + +#ifdef CONFIG_OF +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct device_node *node = of_node_get(tps->dev->of_node); + struct tps65217_bl_pdata *pdata, *err; + u32 val; + + node = of_find_node_by_name(node, "backlight"); + if (!node) + return ERR_PTR(-ENODEV); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "failed to allocate platform data\n"); + err = ERR_PTR(-ENOMEM); + goto err; + } + + pdata->isel = TPS65217_BL_ISET1; + if (!of_property_read_u32(node, "isel", &val)) { + if (val < TPS65217_BL_ISET1 || + val > TPS65217_BL_ISET2) { + dev_err(&pdev->dev, + "invalid 'isel' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + + pdata->isel = val; + } + + pdata->fdim = TPS65217_BL_FDIM_200HZ; + if (!of_property_read_u32(node, "fdim", &val)) { + switch (val) { + case 100: + pdata->fdim = TPS65217_BL_FDIM_100HZ; + break; + + case 200: + pdata->fdim = TPS65217_BL_FDIM_200HZ; + break; + + case 500: + pdata->fdim = TPS65217_BL_FDIM_500HZ; + break; + + case 1000: + pdata->fdim = TPS65217_BL_FDIM_1000HZ; + break; + + default: + dev_err(&pdev->dev, + "invalid 'fdim' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + } + + of_node_put(node); + + return pdata; + +err: + of_node_put(node); + + return err; +} +#else +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +#endif + +static int tps65217_bl_probe(struct platform_device *pdev) +{ + int rc; + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct tps65217_bl *tps65217_bl; + struct tps65217_bl_pdata *pdata; + struct backlight_properties bl_props; + + if (tps->dev->of_node) { + pdata = tps65217_bl_parse_dt(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } else { + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + pdata = pdev->dev.platform_data; + } + + tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), + GFP_KERNEL); + if (tps65217_bl == NULL) { + dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n"); + return -ENOMEM; + } + + tps65217_bl->tps = tps; + tps65217_bl->dev = &pdev->dev; + tps65217_bl->is_enabled = false; + + rc = tps65217_bl_hw_init(tps65217_bl, pdata); + if (rc) + return rc; + + memset(&bl_props, 0, sizeof(struct backlight_properties)); + bl_props.type = BACKLIGHT_RAW; + bl_props.max_brightness = 100; + + tps65217_bl->bl = backlight_device_register(pdev->name, + tps65217_bl->dev, tps65217_bl, + &tps65217_bl_ops, &bl_props); + if (IS_ERR(tps65217_bl->bl)) { + dev_err(tps65217_bl->dev, + "registration of backlight device failed: %d\n", rc); + return PTR_ERR(tps65217_bl->bl); + } + + tps65217_bl->bl->props.brightness = 0; + platform_set_drvdata(pdev, tps65217_bl); + + return 0; +} + +static int tps65217_bl_remove(struct platform_device *pdev) +{ + struct tps65217_bl *tps65217_bl = platform_get_drvdata(pdev); + + backlight_device_unregister(tps65217_bl->bl); + + return 0; +} + +static struct platform_driver tps65217_bl_driver = { + .probe = tps65217_bl_probe, + .remove = tps65217_bl_remove, + .driver = { + .owner = THIS_MODULE, + .name = "tps65217-bl", + }, +}; + +module_platform_driver(tps65217_bl_driver); + +MODULE_DESCRIPTION("TPS65217 Backlight driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Matthias Kaehlcke <matthias@kaehlcke.net>"); diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 5a5d0928df33..265c5ed59ade 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c @@ -29,7 +29,7 @@ static int crt_option = 1; static char panel_option[32] = ""; /* Modes relevant to the GX1 (taken from modedb.c) */ -static const struct fb_videomode __devinitdata gx1_modedb[] = { +static const struct fb_videomode __devinitconst gx1_modedb[] = { /* 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index 0fad23f810a3..0e9afa41d163 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -156,7 +156,7 @@ struct gxt4500_par { static char *mode_option; /* default mode: 1280x1024 @ 60 Hz, 8 bpp */ -static const struct fb_videomode defaultmode __devinitdata = { +static const struct fb_videomode defaultmode __devinitconst = { .refresh = 60, .xres = 1280, .yres = 1024, @@ -581,7 +581,7 @@ static int gxt4500_blank(int blank, struct fb_info *info) return 0; } -static const struct fb_fix_screeninfo gxt4500_fix __devinitdata = { +static const struct fb_fix_screeninfo gxt4500_fix __devinitconst = { .id = "IBM GXT4500P", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index b83f36190cae..5c067816a81d 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -97,7 +97,7 @@ static int i810fb_blank (int blank_mode, struct fb_info *info); static void i810fb_release_resource (struct fb_info *info, struct i810fb_par *par); /* PCI */ -static const char *i810_pci_list[] __devinitdata = { +static const char * const i810_pci_list[] __devinitconst = { "Intel(R) 810 Framebuffer Device" , "Intel(R) 810-DC100 Framebuffer Device" , "Intel(R) 810E Framebuffer Device" , diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c index de366937c933..3c63fc24bb1f 100644 --- a/drivers/video/jz4740_fb.c +++ b/drivers/video/jz4740_fb.c @@ -136,7 +136,7 @@ struct jzfb { uint32_t pseudo_palette[16]; }; -static const struct fb_fix_screeninfo jzfb_fix __devinitdata = { +static const struct fb_fix_screeninfo jzfb_fix __devinitconst = { .id = "JZ4740 FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 213fbbcf613b..4e292f29bf5d 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -31,7 +31,6 @@ #include <linux/fb.h> #include <linux/init.h> -#include <asm/abs_addr.h> #include <asm/cell-regs.h> #include <asm/lv1call.h> #include <asm/ps3av.h> @@ -1141,7 +1140,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) */ fb_start = ps3fb_videomemory.address + GPU_FB_START; info->screen_base = (char __force __iomem *)fb_start; - info->fix.smem_start = virt_to_abs(fb_start); + info->fix.smem_start = __pa(fb_start); info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START; info->pseudo_palette = par->pseudo_palette; diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index ceed39f26011..545d387de411 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -37,6 +37,7 @@ * document number TBD : DH89xxCC * document number TBD : Panther Point * document number TBD : Lynx Point + * document number TBD : Lynx Point-LP */ /* diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index a4a3cab2f459..0e8637035457 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,11 +1,19 @@ -obj-y += grant-table.o features.o events.o manage.o balloon.o +ifneq ($(CONFIG_ARM),y) +obj-y += manage.o balloon.o +obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o +endif +obj-y += grant-table.o features.o events.o obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_features.o := $(nostackp) +dom0-$(CONFIG_PCI) += pci.o +dom0-$(CONFIG_USB_SUPPORT) += dbgp.o +dom0-$(CONFIG_ACPI) += acpi.o +dom0-$(CONFIG_X86) += pcpu.o +obj-$(CONFIG_XEN_DOM0) += $(dom0-y) obj-$(CONFIG_BLOCK) += biomerge.o -obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o obj-$(CONFIG_XEN_SELFBALLOONING) += xen-selfballoon.o @@ -17,8 +25,6 @@ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o obj-$(CONFIG_XEN_PVHVM) += platform-pci.o obj-$(CONFIG_XEN_TMEM) += tmem.o obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o -obj-$(CONFIG_XEN_DOM0) += pcpu.o -obj-$(CONFIG_XEN_DOM0) += pci.o dbgp.o acpi.o obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o diff --git a/drivers/xen/events.c b/drivers/xen/events.c index c60d1629c916..59e10a1286d5 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -31,14 +31,16 @@ #include <linux/irqnr.h> #include <linux/pci.h> +#ifdef CONFIG_X86 #include <asm/desc.h> #include <asm/ptrace.h> #include <asm/irq.h> #include <asm/idle.h> #include <asm/io_apic.h> -#include <asm/sync_bitops.h> #include <asm/xen/page.h> #include <asm/xen/pci.h> +#endif +#include <asm/sync_bitops.h> #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> @@ -50,6 +52,9 @@ #include <xen/interface/event_channel.h> #include <xen/interface/hvm/hvm_op.h> #include <xen/interface/hvm/params.h> +#include <xen/interface/physdev.h> +#include <xen/interface/sched.h> +#include <asm/hw_irq.h> /* * This lock protects updates to the following mapping and reference-count @@ -1386,7 +1391,9 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); +#ifdef CONFIG_X86 exit_idle(); +#endif irq_enter(); __xen_evtchn_do_upcall(); @@ -1797,7 +1804,7 @@ void xen_callback_vector(void) {} void __init xen_init_IRQ(void) { - int i, rc; + int i; evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), GFP_KERNEL); @@ -1813,6 +1820,7 @@ void __init xen_init_IRQ(void) pirq_needs_eoi = pirq_needs_eoi_flag; +#ifdef CONFIG_X86 if (xen_hvm_domain()) { xen_callback_vector(); native_init_IRQ(); @@ -1820,6 +1828,7 @@ void __init xen_init_IRQ(void) * __acpi_register_gsi can point at the right function */ pci_xen_hvm_init(); } else { + int rc; struct physdev_pirq_eoi_gmfn eoi_gmfn; irq_ctx_init(smp_processor_id()); @@ -1835,4 +1844,5 @@ void __init xen_init_IRQ(void) } else pirq_needs_eoi = pirq_check_eoi_map; } +#endif } diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 022574202749..0efd1524b977 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -164,3 +164,11 @@ config BINFMT_MISC You may say M here for module support and later load the module when you have use for it; the module is called binfmt_misc. If you don't know what to answer at this point, say Y. + +config COREDUMP + bool "Enable core dump support" if EXPERT + default y + help + This option enables support for performing core dumps. You almost + certainly want to say Y here. Not necessary on systems that never + need debugging or only ever run flawless code. diff --git a/fs/Makefile b/fs/Makefile index 8938f8250320..1d7af79288a0 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o drop_caches.o splice.o sync.o utimes.o \ - stack.o fs_struct.o statfs.o coredump.o + stack.o fs_struct.o statfs.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o @@ -48,6 +48,7 @@ obj-$(CONFIG_FS_MBCACHE) += mbcache.o obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o obj-$(CONFIG_NFS_COMMON) += nfs_common/ obj-$(CONFIG_GENERIC_ACL) += generic_acl.o +obj-$(CONFIG_COREDUMP) += coredump.o obj-$(CONFIG_FHANDLE) += fhandle.o diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index d146e181d10d..0e7a6f81ae36 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -32,31 +32,8 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout_library(struct file*); -static int aout_core_dump(struct coredump_params *cprm); - -static struct linux_binfmt aout_format = { - .module = THIS_MODULE, - .load_binary = load_aout_binary, - .load_shlib = load_aout_library, - .core_dump = aout_core_dump, - .min_coredump = PAGE_SIZE -}; - -#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) - -static int set_brk(unsigned long start, unsigned long end) -{ - start = PAGE_ALIGN(start); - end = PAGE_ALIGN(end); - if (end > start) { - unsigned long addr; - addr = vm_brk(start, end - start); - if (BAD_ADDR(addr)) - return addr; - } - return 0; -} +#ifdef CONFIG_COREDUMP /* * Routine writes a core dump image in the current directory. * Currently only a stub-function. @@ -66,7 +43,6 @@ static int set_brk(unsigned long start, unsigned long end) * field, which also makes sure the core-dumps won't be recursive if the * dumping of the process results in another error.. */ - static int aout_core_dump(struct coredump_params *cprm) { struct file *file = cprm->file; @@ -89,7 +65,7 @@ static int aout_core_dump(struct coredump_params *cprm) current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); dump.u_ar0 = offsetof(struct user, regs); - dump.signal = cprm->signr; + dump.signal = cprm->siginfo->si_signo; aout_dump_thread(cprm->regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen @@ -135,6 +111,32 @@ end_coredump: set_fs(fs); return has_dumped; } +#else +#define aout_core_dump NULL +#endif + +static struct linux_binfmt aout_format = { + .module = THIS_MODULE, + .load_binary = load_aout_binary, + .load_shlib = load_aout_library, + .core_dump = aout_core_dump, + .min_coredump = PAGE_SIZE +}; + +#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) + +static int set_brk(unsigned long start, unsigned long end) +{ + start = PAGE_ALIGN(start); + end = PAGE_ALIGN(end); + if (end > start) { + unsigned long addr; + addr = vm_brk(start, end - start); + if (BAD_ADDR(addr)) + return addr; + } + return 0; +} /* * create_aout_tables() parses the env- and arg-strings in new user diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0225fddf49b7..28a64e769527 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -27,6 +27,7 @@ #include <linux/compiler.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/vmalloc.h> #include <linux/security.h> #include <linux/random.h> #include <linux/elf.h> @@ -37,6 +38,13 @@ #include <asm/page.h> #include <asm/exec.h> +#ifndef user_long_t +#define user_long_t long +#endif +#ifndef user_siginfo_t +#define user_siginfo_t siginfo_t +#endif + static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(struct file *); static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, @@ -881,7 +889,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) } if (elf_interpreter) { - unsigned long uninitialized_var(interp_map_addr); + unsigned long interp_map_addr = 0; elf_entry = load_elf_interp(&loc->interp_elf_ex, interpreter, @@ -1372,6 +1380,103 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); } +static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, + siginfo_t *siginfo) +{ + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo); + set_fs(old_fs); + fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); +} + +#define MAX_FILE_NOTE_SIZE (4*1024*1024) +/* + * Format of NT_FILE note: + * + * long count -- how many files are mapped + * long page_size -- units for file_ofs + * array of [COUNT] elements of + * long start + * long end + * long file_ofs + * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... + */ +static void fill_files_note(struct memelfnote *note) +{ + struct vm_area_struct *vma; + unsigned count, size, names_ofs, remaining, n; + user_long_t *data; + user_long_t *start_end_ofs; + char *name_base, *name_curpos; + + /* *Estimated* file count and total data size needed */ + count = current->mm->map_count; + size = count * 64; + + names_ofs = (2 + 3 * count) * sizeof(data[0]); + alloc: + if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ + goto err; + size = round_up(size, PAGE_SIZE); + data = vmalloc(size); + if (!data) + goto err; + + start_end_ofs = data + 2; + name_base = name_curpos = ((char *)data) + names_ofs; + remaining = size - names_ofs; + count = 0; + for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + struct file *file; + const char *filename; + + file = vma->vm_file; + if (!file) + continue; + filename = d_path(&file->f_path, name_curpos, remaining); + if (IS_ERR(filename)) { + if (PTR_ERR(filename) == -ENAMETOOLONG) { + vfree(data); + size = size * 5 / 4; + goto alloc; + } + continue; + } + + /* d_path() fills at the end, move name down */ + /* n = strlen(filename) + 1: */ + n = (name_curpos + remaining) - filename; + remaining = filename - name_curpos; + memmove(name_curpos, filename, n); + name_curpos += n; + + *start_end_ofs++ = vma->vm_start; + *start_end_ofs++ = vma->vm_end; + *start_end_ofs++ = vma->vm_pgoff; + count++; + } + + /* Now we know exact count of files, can store it */ + data[0] = count; + data[1] = PAGE_SIZE; + /* + * Count usually is less than current->mm->map_count, + * we need to move filenames down. + */ + n = current->mm->map_count - count; + if (n != 0) { + unsigned shift_bytes = n * 3 * sizeof(data[0]); + memmove(name_base - shift_bytes, name_base, + name_curpos - name_base); + name_curpos -= shift_bytes; + } + + size = name_curpos - (char *)data; + fill_note(note, "CORE", NT_FILE, size, data); + err: ; +} + #ifdef CORE_DUMP_USE_REGSET #include <linux/regset.h> @@ -1385,7 +1490,10 @@ struct elf_thread_core_info { struct elf_note_info { struct elf_thread_core_info *thread; struct memelfnote psinfo; + struct memelfnote signote; struct memelfnote auxv; + struct memelfnote files; + user_siginfo_t csigdata; size_t size; int thread_notes; }; @@ -1480,7 +1588,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - long signr, struct pt_regs *regs) + siginfo_t *siginfo, struct pt_regs *regs) { struct task_struct *dump_task = current; const struct user_regset_view *view = task_user_regset_view(dump_task); @@ -1550,7 +1658,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, * Now fill in each thread's information. */ for (t = info->thread; t != NULL; t = t->next) - if (!fill_thread_core_info(t, view, signr, &info->size)) + if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) return 0; /* @@ -1559,9 +1667,15 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); info->size += notesize(&info->psinfo); + fill_siginfo_note(&info->signote, &info->csigdata, siginfo); + info->size += notesize(&info->signote); + fill_auxv_note(&info->auxv, current->mm); info->size += notesize(&info->auxv); + fill_files_note(&info->files); + info->size += notesize(&info->files); + return 1; } @@ -1588,8 +1702,12 @@ static int write_note_info(struct elf_note_info *info, if (first && !writenote(&info->psinfo, file, foffset)) return 0; + if (first && !writenote(&info->signote, file, foffset)) + return 0; if (first && !writenote(&info->auxv, file, foffset)) return 0; + if (first && !writenote(&info->files, file, foffset)) + return 0; for (i = 1; i < info->thread_notes; ++i) if (t->notes[i].data && @@ -1616,6 +1734,7 @@ static void free_note_info(struct elf_note_info *info) kfree(t); } kfree(info->psinfo.data); + vfree(info->files.data); } #else @@ -1681,6 +1800,7 @@ struct elf_note_info { #ifdef ELF_CORE_COPY_XFPREGS elf_fpxregset_t *xfpu; #endif + user_siginfo_t csigdata; int thread_status_size; int numnote; }; @@ -1690,8 +1810,8 @@ static int elf_note_info_init(struct elf_note_info *info) memset(info, 0, sizeof(*info)); INIT_LIST_HEAD(&info->thread_list); - /* Allocate space for six ELF notes */ - info->notes = kmalloc(6 * sizeof(struct memelfnote), GFP_KERNEL); + /* Allocate space for ELF notes */ + info->notes = kmalloc(8 * sizeof(struct memelfnote), GFP_KERNEL); if (!info->notes) return 0; info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); @@ -1713,14 +1833,14 @@ static int elf_note_info_init(struct elf_note_info *info) static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_note_info *info, - long signr, struct pt_regs *regs) + siginfo_t *siginfo, struct pt_regs *regs) { struct list_head *t; if (!elf_note_info_init(info)) return 0; - if (signr) { + if (siginfo->si_signo) { struct core_thread *ct; struct elf_thread_status *ets; @@ -1738,13 +1858,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, int sz; ets = list_entry(t, struct elf_thread_status, list); - sz = elf_dump_thread_status(signr, ets); + sz = elf_dump_thread_status(siginfo->si_signo, ets); info->thread_status_size += sz; } } /* now collect the dump for the current */ memset(info->prstatus, 0, sizeof(*info->prstatus)); - fill_prstatus(info->prstatus, current, signr); + fill_prstatus(info->prstatus, current, siginfo->si_signo); elf_core_copy_regs(&info->prstatus->pr_reg, regs); /* Set up header */ @@ -1761,9 +1881,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, fill_note(info->notes + 1, "CORE", NT_PRPSINFO, sizeof(*info->psinfo), info->psinfo); - info->numnote = 2; + fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); + fill_auxv_note(info->notes + 3, current->mm); + fill_files_note(info->notes + 4); - fill_auxv_note(&info->notes[info->numnote++], current->mm); + info->numnote = 5; /* Try to dump the FPU. */ info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, @@ -1825,6 +1947,9 @@ static void free_note_info(struct elf_note_info *info) kfree(list_entry(tmp, struct elf_thread_status, list)); } + /* Free data allocated by fill_files_note(): */ + vfree(info->notes[4].data); + kfree(info->prstatus); kfree(info->psinfo); kfree(info->notes); @@ -1951,7 +2076,7 @@ static int elf_core_dump(struct coredump_params *cprm) * Collect all the non-memory information about the process for the * notes. This also sets up the file header. */ - if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs)) + if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs)) goto cleanup; has_dumped = 1; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 3d77cf81ba3c..08d812b32282 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1642,7 +1642,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto cleanup; #endif - if (cprm->signr) { + if (cprm->siginfo->si_signo) { struct core_thread *ct; struct elf_thread_status *tmp; @@ -1661,13 +1661,13 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) int sz; tmp = list_entry(t, struct elf_thread_status, list); - sz = elf_dump_thread_status(cprm->signr, tmp); + sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); thread_status_size += sz; } } /* now collect the dump for the current */ - fill_prstatus(prstatus, current, cprm->signr); + fill_prstatus(prstatus, current, cprm->siginfo->si_signo); elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); segs = current->mm->map_count; diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 178cb70acc26..e280352b28f9 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -107,7 +107,7 @@ static struct linux_binfmt flat_format = { static int flat_core_dump(struct coredump_params *cprm) { printk("Process %s:%d received signr %d and should have core dumped\n", - current->comm, current->pid, (int) cprm->signr); + current->comm, current->pid, (int) cprm->siginfo->si_signo); return(1); } diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c index 112e45a17e99..a81147e2e4ef 100644 --- a/fs/compat_binfmt_elf.c +++ b/fs/compat_binfmt_elf.c @@ -38,6 +38,13 @@ #define elf_addr_t Elf32_Addr /* + * Some data types as stored in coredump. + */ +#define user_long_t compat_long_t +#define user_siginfo_t compat_siginfo_t +#define copy_siginfo_to_user copy_siginfo_to_user32 + +/* * The machine-dependent core note format types are defined in elfcore-compat.h, * which requires asm/elf.h to define compat_elf_gregset_t et al. */ diff --git a/fs/coredump.c b/fs/coredump.c index f045bbad6822..fd37facac8dc 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -14,6 +14,7 @@ #include <linux/key.h> #include <linux/personality.h> #include <linux/binfmts.h> +#include <linux/coredump.h> #include <linux/utsname.h> #include <linux/pid_namespace.h> #include <linux/module.h> @@ -39,6 +40,7 @@ #include <trace/events/task.h> #include "internal.h" +#include "coredump.h" #include <trace/events/sched.h> @@ -147,7 +149,7 @@ put_exe_file: * name into corename, which must have space for at least * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. */ -static int format_corename(struct core_name *cn, long signr) +static int format_corename(struct core_name *cn, struct coredump_params *cprm) { const struct cred *cred = current_cred(); const char *pat_ptr = core_pattern; @@ -192,9 +194,13 @@ static int format_corename(struct core_name *cn, long signr) case 'g': err = cn_printf(cn, "%d", cred->gid); break; + case 'd': + err = cn_printf(cn, "%d", + __get_dumpable(cprm->mm_flags)); + break; /* signal that caused the coredump */ case 's': - err = cn_printf(cn, "%ld", signr); + err = cn_printf(cn, "%ld", cprm->siginfo->si_signo); break; /* UNIX time of coredump */ case 't': { @@ -451,7 +457,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) return 0; } -void do_coredump(long signr, int exit_code, struct pt_regs *regs) +void do_coredump(siginfo_t *siginfo, struct pt_regs *regs) { struct core_state core_state; struct core_name cn; @@ -466,7 +472,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) bool need_nonrelative = false; static atomic_t core_dump_count = ATOMIC_INIT(0); struct coredump_params cprm = { - .signr = signr, + .siginfo = siginfo, .regs = regs, .limit = rlimit(RLIMIT_CORE), /* @@ -477,7 +483,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) .mm_flags = mm->flags, }; - audit_core_dumps(signr); + audit_core_dumps(siginfo->si_signo); binfmt = mm->binfmt; if (!binfmt || !binfmt->core_dump) @@ -501,7 +507,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) need_nonrelative = true; } - retval = coredump_wait(exit_code, &core_state); + retval = coredump_wait(siginfo->si_signo, &core_state); if (retval < 0) goto fail_creds; @@ -513,7 +519,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) */ clear_thread_flag(TIF_SIGPENDING); - ispipe = format_corename(&cn, signr); + ispipe = format_corename(&cn, &cprm); if (ispipe) { int dump_count; diff --git a/fs/coredump.h b/fs/coredump.h new file mode 100644 index 000000000000..e39ff072110d --- /dev/null +++ b/fs/coredump.h @@ -0,0 +1,6 @@ +#ifndef _FS_COREDUMP_H +#define _FS_COREDUMP_H + +extern int __get_dumpable(unsigned long mm_flags); + +#endif diff --git a/fs/eventpoll.c b/fs/eventpoll.c index cd96649bfe62..da72250ddc1c 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -346,7 +346,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p) /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ static inline int ep_op_has_event(int op) { - return op != EPOLL_CTL_DEL; + return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD; } /* Initialize the poll safe wake up structure */ @@ -676,6 +676,34 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) return 0; } +/* + * Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item + * had no event flags set, indicating that another thread may be currently + * handling that item's events (in the case that EPOLLONESHOT was being + * used). Otherwise a zero result indicates that the item has been disabled + * from receiving events. A disabled item may be re-enabled via + * EPOLL_CTL_MOD. Must be called with "mtx" held. + */ +static int ep_disable(struct eventpoll *ep, struct epitem *epi) +{ + int result = 0; + unsigned long flags; + + spin_lock_irqsave(&ep->lock, flags); + if (epi->event.events & ~EP_PRIVATE_BITS) { + if (ep_is_linked(&epi->rdllink)) + list_del_init(&epi->rdllink); + /* Ensure ep_poll_callback will not add epi back onto ready + list: */ + epi->event.events &= EP_PRIVATE_BITS; + } + else + result = -EBUSY; + spin_unlock_irqrestore(&ep->lock, flags); + + return result; +} + static void ep_free(struct eventpoll *ep) { struct rb_node *rbp; @@ -1020,8 +1048,6 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) rb_insert_color(&epi->rbn, &ep->rbr); } - - #define PATH_ARR_SIZE 5 /* * These are the number paths of length 1 to 5, that we are allowing to emanate @@ -1787,6 +1813,12 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, } else error = -ENOENT; break; + case EPOLL_CTL_DISABLE: + if (epi) + error = ep_disable(ep, epi); + else + error = -ENOENT; + break; } mutex_unlock(&ep->mtx); diff --git a/fs/exec.c b/fs/exec.c index 48fb26ef8a1b..9824473a7ec1 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -63,6 +63,7 @@ #include <trace/events/task.h> #include "internal.h" +#include "coredump.h" #include <trace/events/sched.h> @@ -1096,7 +1097,7 @@ void setup_new_exec(struct linux_binprm * bprm) current->sas_ss_sp = current->sas_ss_size = 0; if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) - set_dumpable(current->mm, 1); + set_dumpable(current->mm, SUID_DUMPABLE_ENABLED); else set_dumpable(current->mm, suid_dumpable); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index bd29894c8fbc..17ae5c83d234 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -980,7 +980,7 @@ static int parse_options (char *options, struct super_block *sb, * Initialize args struct so we know whether arg was * found; some options take optional arguments. */ - args[0].to = args[0].from = 0; + args[0].to = args[0].from = NULL; token = match_token(p, tokens, args); switch (token) { case Opt_bsd_df: @@ -1484,10 +1484,12 @@ static void ext3_orphan_cleanup (struct super_block * sb, } if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) { - if (es->s_last_orphan) + /* don't clear list on RO mount w/ errors */ + if (es->s_last_orphan && !(s_flags & MS_RDONLY)) { jbd_debug(1, "Errors on filesystem, " "clearing orphan list.\n"); - es->s_last_orphan = 0; + es->s_last_orphan = 0; + } jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); return; } diff --git a/fs/fat/Makefile b/fs/fat/Makefile index e06190322c1c..964b634f6667 100644 --- a/fs/fat/Makefile +++ b/fs/fat/Makefile @@ -6,6 +6,6 @@ obj-$(CONFIG_FAT_FS) += fat.o obj-$(CONFIG_VFAT_FS) += vfat.o obj-$(CONFIG_MSDOS_FS) += msdos.o -fat-y := cache.o dir.o fatent.o file.o inode.o misc.o +fat-y := cache.o dir.o fatent.o file.o inode.o misc.o nfs.o vfat-y := namei_vfat.o msdos-y := namei_msdos.o diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 1cc7038e273d..91ad9e1c9441 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -190,7 +190,8 @@ static void __fat_cache_inval_inode(struct inode *inode) struct fat_cache *cache; while (!list_empty(&i->cache_lru)) { - cache = list_entry(i->cache_lru.next, struct fat_cache, cache_list); + cache = list_entry(i->cache_lru.next, + struct fat_cache, cache_list); list_del_init(&cache->cache_list); i->nr_caches--; fat_cache_free(cache); @@ -261,9 +262,10 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) if (nr < 0) goto out; else if (nr == FAT_ENT_FREE) { - fat_fs_error_ratelimit(sb, "%s: invalid cluster chain" - " (i_pos %lld)", __func__, - MSDOS_I(inode)->i_pos); + fat_fs_error_ratelimit(sb, + "%s: invalid cluster chain (i_pos %lld)", + __func__, + MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } else if (nr == FAT_ENT_EOF) { diff --git a/fs/fat/dir.c b/fs/fat/dir.c index dc49ed2cbffa..bca6d0a1255e 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -18,7 +18,7 @@ #include <linux/time.h> #include <linux/buffer_head.h> #include <linux/compat.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/kernel.h> #include "fat.h" @@ -123,7 +123,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, { /* Fast stuff first */ if (*bh && *de && - (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) { + (*de - (struct msdos_dir_entry *)(*bh)->b_data) < + MSDOS_SB(dir->i_sb)->dir_per_block - 1) { *pos += sizeof(struct msdos_dir_entry); (*de)++; return 0; @@ -155,7 +156,8 @@ static int uni16_to_x8(struct super_block *sb, unsigned char *ascii, while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { ec = *ip++; - if ((charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { + charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE); + if (charlen > 0) { op += charlen; len -= charlen; } else { @@ -172,12 +174,12 @@ static int uni16_to_x8(struct super_block *sb, unsigned char *ascii, } if (unlikely(*ip)) { - fat_msg(sb, KERN_WARNING, "filename was truncated while " - "converting."); + fat_msg(sb, KERN_WARNING, + "filename was truncated while converting."); } *op = 0; - return (op - ascii); + return op - ascii; } static inline int fat_uni_to_x8(struct super_block *sb, const wchar_t *uni, @@ -205,7 +207,8 @@ fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) } static inline int -fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) +fat_short2lower_uni(struct nls_table *t, unsigned char *c, + int clen, wchar_t *uni) { int charlen; wchar_t wc; @@ -220,7 +223,8 @@ fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *un if (!nc) nc = *c; - if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) { + charlen = t->char2uni(&nc, 1, uni); + if (charlen < 0) { *uni = 0x003f; /* a question mark */ charlen = 1; } @@ -537,7 +541,6 @@ end_of_dir: return err; } - EXPORT_SYMBOL_GPL(fat_search_long); struct fat_ioctl_filldir_callback { @@ -574,7 +577,8 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, /* Fake . and .. for the root directory. */ if (inode->i_ino == MSDOS_ROOT_INO) { while (cpos < 2) { - if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0) + if (filldir(dirent, "..", cpos+1, cpos, + MSDOS_ROOT_INO, DT_DIR) < 0) goto out; cpos++; filp->f_pos++; @@ -872,25 +876,26 @@ static int fat_get_short_entry(struct inode *dir, loff_t *pos, } /* - * The ".." entry can not provide the "struct fat_slot_info" informations - * for inode. So, this function provide the some informations only. + * The ".." entry can not provide the "struct fat_slot_info" information + * for inode, nor a usable i_pos. So, this function provides some information + * only. + * + * Since this function walks through the on-disk inodes within a directory, + * callers are responsible for taking any locks necessary to prevent the + * directory from changing. */ int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, - struct msdos_dir_entry **de, loff_t *i_pos) + struct msdos_dir_entry **de) { - loff_t offset; + loff_t offset = 0; - offset = 0; - *bh = NULL; + *de = NULL; while (fat_get_short_entry(dir, &offset, bh, de) >= 0) { - if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) { - *i_pos = fat_make_i_pos(dir->i_sb, *bh, *de); + if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) return 0; - } } return -ENOENT; } - EXPORT_SYMBOL_GPL(fat_get_dotdot_entry); /* See if directory is empty */ @@ -913,7 +918,6 @@ int fat_dir_empty(struct inode *dir) brelse(bh); return result; } - EXPORT_SYMBOL_GPL(fat_dir_empty); /* @@ -959,7 +963,6 @@ int fat_scan(struct inode *dir, const unsigned char *name, } return -ENOENT; } - EXPORT_SYMBOL_GPL(fat_scan); static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) @@ -1047,7 +1050,6 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) return 0; } - EXPORT_SYMBOL_GPL(fat_remove_entries); static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, @@ -1141,10 +1143,8 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) de[0].ctime_cs = de[1].ctime_cs = 0; de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; } - de[0].start = cpu_to_le16(cluster); - de[0].starthi = cpu_to_le16(cluster >> 16); - de[1].start = cpu_to_le16(MSDOS_I(dir)->i_logstart); - de[1].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16); + fat_set_start(&de[0], cluster); + fat_set_start(&de[1], MSDOS_I(dir)->i_logstart); de[0].size = de[1].size = 0; memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); set_buffer_uptodate(bhs[0]); @@ -1161,7 +1161,6 @@ error_free: error: return err; } - EXPORT_SYMBOL_GPL(fat_alloc_new_dir); static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, @@ -1377,5 +1376,4 @@ error_remove: __fat_remove_entries(dir, pos, free_slots); return err; } - EXPORT_SYMBOL_GPL(fat_add_entries); diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 7d8e0dcac5d5..ca7e8f8bad7c 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -5,6 +5,7 @@ #include <linux/string.h> #include <linux/nls.h> #include <linux/fs.h> +#include <linux/hash.h> #include <linux/mutex.h> #include <linux/ratelimit.h> #include <linux/msdos_fs.h> @@ -27,26 +28,27 @@ struct fat_mount_options { kgid_t fs_gid; unsigned short fs_fmask; unsigned short fs_dmask; - unsigned short codepage; /* Codepage for shortname conversions */ - char *iocharset; /* Charset used for filename input/display */ - unsigned short shortname; /* flags for shortname display/create rule */ - unsigned char name_check; /* r = relaxed, n = normal, s = strict */ - unsigned char errors; /* On error: continue, panic, remount-ro */ + unsigned short codepage; /* Codepage for shortname conversions */ + char *iocharset; /* Charset used for filename input/display */ + unsigned short shortname; /* flags for shortname display/create rule */ + unsigned char name_check; /* r = relaxed, n = normal, s = strict */ + unsigned char errors; /* On error: continue, panic, remount-ro */ unsigned short allow_utime;/* permission for setting the [am]time */ - unsigned quiet:1, /* set = fake successful chmods and chowns */ - showexec:1, /* set = only set x bit for com/exe/bat */ - sys_immutable:1, /* set = system files are immutable */ - dotsOK:1, /* set = hidden and system files are named '.filename' */ - isvfat:1, /* 0=no vfat long filename support, 1=vfat support */ - utf8:1, /* Use of UTF-8 character set (Default) */ - unicode_xlate:1, /* create escape sequences for unhandled Unicode */ - numtail:1, /* Does first alias have a numeric '~1' type tail? */ - flush:1, /* write things quickly */ - nocase:1, /* Does this need case conversion? 0=need case conversion*/ - usefree:1, /* Use free_clusters for FAT32 */ - tz_utc:1, /* Filesystem timestamps are in UTC */ - rodir:1, /* allow ATTR_RO for directory */ - discard:1; /* Issue discard requests on deletions */ + unsigned quiet:1, /* set = fake successful chmods and chowns */ + showexec:1, /* set = only set x bit for com/exe/bat */ + sys_immutable:1, /* set = system files are immutable */ + dotsOK:1, /* set = hidden and system files are named '.filename' */ + isvfat:1, /* 0=no vfat long filename support, 1=vfat support */ + utf8:1, /* Use of UTF-8 character set (Default) */ + unicode_xlate:1, /* create escape sequences for unhandled Unicode */ + numtail:1, /* Does first alias have a numeric '~1' type tail? */ + flush:1, /* write things quickly */ + nocase:1, /* Does this need case conversion? 0=need case conversion*/ + usefree:1, /* Use free_clusters for FAT32 */ + tz_utc:1, /* Filesystem timestamps are in UTC */ + rodir:1, /* allow ATTR_RO for directory */ + discard:1, /* Issue discard requests on deletions */ + nfs:1; /* Do extra work needed for NFS export */ }; #define FAT_HASH_BITS 8 @@ -56,28 +58,28 @@ struct fat_mount_options { * MS-DOS file system in-core superblock data */ struct msdos_sb_info { - unsigned short sec_per_clus; /* sectors/cluster */ - unsigned short cluster_bits; /* log2(cluster_size) */ - unsigned int cluster_size; /* cluster size */ - unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */ + unsigned short sec_per_clus; /* sectors/cluster */ + unsigned short cluster_bits; /* log2(cluster_size) */ + unsigned int cluster_size; /* cluster size */ + unsigned char fats, fat_bits; /* number of FATs, FAT bits (12 or 16) */ unsigned short fat_start; - unsigned long fat_length; /* FAT start & length (sec.) */ + unsigned long fat_length; /* FAT start & length (sec.) */ unsigned long dir_start; - unsigned short dir_entries; /* root dir start & entries */ - unsigned long data_start; /* first data sector */ - unsigned long max_cluster; /* maximum cluster number */ - unsigned long root_cluster; /* first cluster of the root directory */ - unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ + unsigned short dir_entries; /* root dir start & entries */ + unsigned long data_start; /* first data sector */ + unsigned long max_cluster; /* maximum cluster number */ + unsigned long root_cluster; /* first cluster of the root directory */ + unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ struct mutex fat_lock; - unsigned int prev_free; /* previously allocated cluster number */ - unsigned int free_clusters; /* -1 if undefined */ + unsigned int prev_free; /* previously allocated cluster number */ + unsigned int free_clusters; /* -1 if undefined */ unsigned int free_clus_valid; /* is free_clusters valid? */ struct fat_mount_options options; - struct nls_table *nls_disk; /* Codepage used on disk */ - struct nls_table *nls_io; /* Charset used for input and display */ - const void *dir_ops; /* Opaque; default directory operations */ - int dir_per_block; /* dir entries per block */ - int dir_per_block_bits; /* log2(dir_per_block) */ + struct nls_table *nls_disk; /* Codepage used on disk */ + struct nls_table *nls_io; /* Charset used for input and display */ + const void *dir_ops; /* Opaque; default directory operations */ + int dir_per_block; /* dir entries per block */ + int dir_per_block_bits; /* log2(dir_per_block) */ int fatent_shift; struct fatent_operations *fatent_ops; @@ -88,6 +90,9 @@ struct msdos_sb_info { spinlock_t inode_hash_lock; struct hlist_head inode_hashtable[FAT_HASH_SIZE]; + + spinlock_t dir_hash_lock; + struct hlist_head dir_hashtable[FAT_HASH_SIZE]; }; #define FAT_CACHE_VALID 0 /* special case for valid cache */ @@ -110,6 +115,7 @@ struct msdos_inode_info { int i_attrs; /* unused attribute bits */ loff_t i_pos; /* on-disk position of directory entry or 0 */ struct hlist_node i_fat_hash; /* hash by i_location */ + struct hlist_node i_dir_hash; /* hash by i_logstart */ struct rw_semaphore truncate_lock; /* protect bmap against truncate */ struct inode vfs_inode; }; @@ -262,7 +268,7 @@ extern int fat_subdirs(struct inode *dir); extern int fat_scan(struct inode *dir, const unsigned char *name, struct fat_slot_info *sinfo); extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, - struct msdos_dir_entry **de, loff_t *i_pos); + struct msdos_dir_entry **de); extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts); extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots, struct fat_slot_info *sinfo); @@ -322,7 +328,7 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); extern const struct file_operations fat_file_operations; extern const struct inode_operations fat_file_inode_operations; -extern int fat_setattr(struct dentry * dentry, struct iattr * attr); +extern int fat_setattr(struct dentry *dentry, struct iattr *attr); extern void fat_truncate_blocks(struct inode *inode, loff_t offset); extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); @@ -340,7 +346,12 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, void (*setup)(struct super_block *)); extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, - struct inode *i2); + struct inode *i2); +static inline unsigned long fat_dir_hash(int logstart) +{ + return hash_32(logstart, FAT_HASH_BITS); +} + /* fat/misc.c */ extern __printf(3, 4) __cold void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...); @@ -366,6 +377,14 @@ extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); int fat_cache_init(void); void fat_cache_destroy(void); +/* fat/nfs.c */ +struct fid; +extern struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type); +extern struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type); +extern struct dentry *fat_get_parent(struct dentry *child_dir); + /* helper for printk */ typedef unsigned long long llu; diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 31f08ab62c56..260705c58062 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -186,9 +186,6 @@ static void fat16_ent_put(struct fat_entry *fatent, int new) static void fat32_ent_put(struct fat_entry *fatent, int new) { - if (new == FAT_ENT_EOF) - new = EOF_FAT32; - WARN_ON(new & 0xf0000000); new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; *fatent->u.ent32_p = cpu_to_le32(new); @@ -203,15 +200,18 @@ static int fat12_ent_next(struct fat_entry *fatent) fatent->entry++; if (fatent->nr_bhs == 1) { - WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2))); - WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); + WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + + (bhs[0]->b_size - 2))); + WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + + (bhs[0]->b_size - 1))); if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { ent12_p[0] = nextp - 1; ent12_p[1] = nextp; return 1; } } else { - WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); + WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + + (bhs[0]->b_size - 1))); WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data); ent12_p[0] = nextp - 1; ent12_p[1] = nextp; @@ -631,7 +631,6 @@ error: return err; } - EXPORT_SYMBOL_GPL(fat_free_clusters); /* 128kb is the whole sectors for FAT12 and FAT16 */ diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 4e5a6ac54ebd..76f60c642c06 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -281,15 +281,42 @@ static inline unsigned long fat_hash(loff_t i_pos) return hash_32(i_pos, FAT_HASH_BITS); } +static void dir_hash_init(struct super_block *sb) +{ + struct msdos_sb_info *sbi = MSDOS_SB(sb); + int i; + + spin_lock_init(&sbi->dir_hash_lock); + for (i = 0; i < FAT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&sbi->dir_hashtable[i]); +} + void fat_attach(struct inode *inode, loff_t i_pos) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); - spin_lock(&sbi->inode_hash_lock); - MSDOS_I(inode)->i_pos = i_pos; - hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); - spin_unlock(&sbi->inode_hash_lock); + if (inode->i_ino != MSDOS_ROOT_INO) { + struct hlist_head *head = sbi->inode_hashtable + + fat_hash(i_pos); + + spin_lock(&sbi->inode_hash_lock); + MSDOS_I(inode)->i_pos = i_pos; + hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); + spin_unlock(&sbi->inode_hash_lock); + } + + /* If NFS support is enabled, cache the mapping of start cluster + * to directory inode. This is used during reconnection of + * dentries to the filesystem root. + */ + if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { + struct hlist_head *d_head = sbi->dir_hashtable; + d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart); + + spin_lock(&sbi->dir_hash_lock); + hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head); + spin_unlock(&sbi->dir_hash_lock); + } } EXPORT_SYMBOL_GPL(fat_attach); @@ -300,6 +327,12 @@ void fat_detach(struct inode *inode) MSDOS_I(inode)->i_pos = 0; hlist_del_init(&MSDOS_I(inode)->i_fat_hash); spin_unlock(&sbi->inode_hash_lock); + + if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { + spin_lock(&sbi->dir_hash_lock); + hlist_del_init(&MSDOS_I(inode)->i_dir_hash); + spin_unlock(&sbi->dir_hash_lock); + } } EXPORT_SYMBOL_GPL(fat_detach); @@ -504,6 +537,7 @@ static void init_once(void *foo) ei->cache_valid_id = FAT_CACHE_VALID + 1; INIT_LIST_HEAD(&ei->cache_lru); INIT_HLIST_NODE(&ei->i_fat_hash); + INIT_HLIST_NODE(&ei->i_dir_hash); inode_init_once(&ei->vfs_inode); } @@ -668,125 +702,9 @@ static const struct super_operations fat_sops = { .show_options = fat_show_options, }; -/* - * a FAT file handle with fhtype 3 is - * 0/ i_ino - for fast, reliable lookup if still in the cache - * 1/ i_generation - to see if i_ino is still valid - * bit 0 == 0 iff directory - * 2/ i_pos(8-39) - if ino has changed, but still in cache - * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos - * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc - * - * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum - * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits - * of i_logstart is used to store the directory entry offset. - */ - -static struct dentry *fat_fh_to_dentry(struct super_block *sb, - struct fid *fid, int fh_len, int fh_type) -{ - struct inode *inode = NULL; - u32 *fh = fid->raw; - - if (fh_len < 5 || fh_type != 3) - return NULL; - - inode = ilookup(sb, fh[0]); - if (!inode || inode->i_generation != fh[1]) { - if (inode) - iput(inode); - inode = NULL; - } - if (!inode) { - loff_t i_pos; - int i_logstart = fh[3] & 0x0fffffff; - - i_pos = (loff_t)fh[2] << 8; - i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); - - /* try 2 - see if i_pos is in F-d-c - * require i_logstart to be the same - * Will fail if you truncate and then re-write - */ - - inode = fat_iget(sb, i_pos); - if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { - iput(inode); - inode = NULL; - } - } - - /* - * For now, do nothing if the inode is not found. - * - * What we could do is: - * - * - follow the file starting at fh[4], and record the ".." entry, - * and the name of the fh[2] entry. - * - then follow the ".." file finding the next step up. - * - * This way we build a path to the root of the tree. If this works, we - * lookup the path and so get this inode into the cache. Finally try - * the fat_iget lookup again. If that fails, then we are totally out - * of luck. But all that is for another day - */ - return d_obtain_alias(inode); -} - -static int -fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent) -{ - int len = *lenp; - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - loff_t i_pos; - - if (len < 5) { - *lenp = 5; - return 255; /* no room */ - } - - i_pos = fat_i_pos_read(sbi, inode); - *lenp = 5; - fh[0] = inode->i_ino; - fh[1] = inode->i_generation; - fh[2] = i_pos >> 8; - fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart; - fh[4] = (i_pos & 0x0f) << 28; - if (parent) - fh[4] |= MSDOS_I(parent)->i_logstart; - return 3; -} - -static struct dentry *fat_get_parent(struct dentry *child) -{ - struct super_block *sb = child->d_sb; - struct buffer_head *bh; - struct msdos_dir_entry *de; - loff_t i_pos; - struct dentry *parent; - struct inode *inode; - int err; - - lock_super(sb); - - err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); - if (err) { - parent = ERR_PTR(err); - goto out; - } - inode = fat_build_inode(sb, de, i_pos); - brelse(bh); - - parent = d_obtain_alias(inode); -out: - unlock_super(sb); - - return parent; -} - static const struct export_operations fat_export_ops = { - .encode_fh = fat_encode_fh, .fh_to_dentry = fat_fh_to_dentry, + .fh_to_parent = fat_fh_to_parent, .get_parent = fat_get_parent, }; @@ -836,6 +754,8 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",usefree"); if (opts->quiet) seq_puts(m, ",quiet"); + if (opts->nfs) + seq_puts(m, ",nfs"); if (opts->showexec) seq_puts(m, ",showexec"); if (opts->sys_immutable) @@ -880,7 +800,7 @@ enum { Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, - Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, + Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_err, }; static const match_table_t fat_tokens = { @@ -909,6 +829,7 @@ static const match_table_t fat_tokens = { {Opt_err_panic, "errors=panic"}, {Opt_err_ro, "errors=remount-ro"}, {Opt_discard, "discard"}, + {Opt_nfs, "nfs"}, {Opt_obsolete, "conv=binary"}, {Opt_obsolete, "conv=text"}, {Opt_obsolete, "conv=auto"}, @@ -989,6 +910,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, opts->numtail = 1; opts->usefree = opts->nocase = 0; opts->tz_utc = 0; + opts->nfs = 0; opts->errors = FAT_ERRORS_RO; *debug = 0; @@ -1153,6 +1075,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, case Opt_discard: opts->discard = 1; break; + case Opt_nfs: + opts->nfs = 1; + break; /* obsolete mount options */ case Opt_obsolete: @@ -1443,6 +1368,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, /* set up enough so that it can read an inode */ fat_hash_init(sb); + dir_hash_init(sb); fat_ent_access_init(sb); /* @@ -1497,6 +1423,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, } error = -ENOMEM; insert_inode_hash(root_inode); + fat_attach(root_inode, 0); sb->s_root = d_make_root(root_inode); if (!sb->s_root) { fat_msg(sb, KERN_ERR, "get root inode failed"); @@ -1536,18 +1463,14 @@ static int writeback_inode(struct inode *inode) { int ret; - struct address_space *mapping = inode->i_mapping; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_NONE, - .nr_to_write = 0, - }; - /* if we used WB_SYNC_ALL, sync_inode waits for the io for the - * inode to finish. So WB_SYNC_NONE is sent down to sync_inode + + /* if we used wait=1, sync_inode_metadata waits for the io for the + * inode to finish. So wait=0 is sent down to sync_inode_metadata * and filemap_fdatawrite is used for the data blocks */ - ret = sync_inode(inode, &wbc); + ret = sync_inode_metadata(inode, 0); if (!ret) - ret = filemap_fdatawrite(mapping); + ret = filemap_fdatawrite(inode->i_mapping); return ret; } diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index b0e12bf9f4a1..c1055e778fff 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -407,7 +407,7 @@ out: static int msdos_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; - struct super_block *sb= inode->i_sb; + struct super_block *sb = inode->i_sb; struct fat_slot_info sinfo; int err; @@ -440,7 +440,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, struct inode *old_inode, *new_inode; struct fat_slot_info old_sinfo, sinfo; struct timespec ts; - loff_t dotdot_i_pos, new_i_pos; + loff_t new_i_pos; int err, old_attrs, is_dir, update_dotdot, corrupt = 0; old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; @@ -456,8 +456,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, is_dir = S_ISDIR(old_inode->i_mode); update_dotdot = (is_dir && old_dir != new_dir); if (update_dotdot) { - if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de, - &dotdot_i_pos) < 0) { + if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) { err = -EIO; goto out; } diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 6a6d8c0715a1..e535dd75b986 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -914,7 +914,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *old_inode, *new_inode; struct fat_slot_info old_sinfo, sinfo; struct timespec ts; - loff_t dotdot_i_pos, new_i_pos; + loff_t new_i_pos; int err, is_dir, update_dotdot, corrupt = 0; struct super_block *sb = old_dir->i_sb; @@ -929,8 +929,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, is_dir = S_ISDIR(old_inode->i_mode); update_dotdot = (is_dir && old_dir != new_dir); if (update_dotdot) { - if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de, - &dotdot_i_pos) < 0) { + if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) { err = -EIO; goto out; } diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c new file mode 100644 index 000000000000..ef4b5faba87b --- /dev/null +++ b/fs/fat/nfs.c @@ -0,0 +1,101 @@ +/* fs/fat/nfs.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/exportfs.h> +#include "fat.h" + +/** + * Look up a directory inode given its starting cluster. + */ +static struct inode *fat_dget(struct super_block *sb, int i_logstart) +{ + struct msdos_sb_info *sbi = MSDOS_SB(sb); + struct hlist_head *head; + struct hlist_node *_p; + struct msdos_inode_info *i; + struct inode *inode = NULL; + + head = sbi->dir_hashtable + fat_dir_hash(i_logstart); + spin_lock(&sbi->dir_hash_lock); + hlist_for_each_entry(i, _p, head, i_dir_hash) { + BUG_ON(i->vfs_inode.i_sb != sb); + if (i->i_logstart != i_logstart) + continue; + inode = igrab(&i->vfs_inode); + if (inode) + break; + } + spin_unlock(&sbi->dir_hash_lock); + return inode; +} + +static struct inode *fat_nfs_get_inode(struct super_block *sb, + u64 ino, u32 generation) +{ + struct inode *inode; + + if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO)) + return NULL; + + inode = ilookup(sb, ino); + if (inode && generation && (inode->i_generation != generation)) { + iput(inode); + inode = NULL; + } + + return inode; +} + +/** + * Map a NFS file handle to a corresponding dentry. + * The dentry may or may not be connected to the filesystem root. + */ +struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, + fat_nfs_get_inode); +} + +/* + * Find the parent for a file specified by NFS handle. + * This requires that the handle contain the i_ino of the parent. + */ +struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, + fat_nfs_get_inode); +} + +/* + * Find the parent for a directory that is not currently connected to + * the filesystem root. + * + * On entry, the caller holds child_dir->d_inode->i_mutex. + */ +struct dentry *fat_get_parent(struct dentry *child_dir) +{ + struct super_block *sb = child_dir->d_sb; + struct buffer_head *bh = NULL; + struct msdos_dir_entry *de; + struct inode *parent_inode = NULL; + + if (!fat_get_dotdot_entry(child_dir->d_inode, &bh, &de)) { + int parent_logstart = fat_get_start(MSDOS_SB(sb), de); + parent_inode = fat_dget(sb, parent_logstart); + } + brelse(bh); + + return d_obtain_alias(parent_inode); +} diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c index 4bae4a4a60b1..2d5b254ad9e2 100644 --- a/fs/hpfs/anode.c +++ b/fs/hpfs/anode.c @@ -102,7 +102,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi return -1; } if (hpfs_alloc_if_possible(s, se = le32_to_cpu(btree->u.external[n].disk_secno) + le32_to_cpu(btree->u.external[n].length))) { - btree->u.external[n].length = cpu_to_le32(le32_to_cpu(btree->u.external[n].length) + 1); + le32_add_cpu(&btree->u.external[n].length, 1); mark_buffer_dirty(bh); brelse(bh); return se; @@ -153,7 +153,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi btree = &anode->btree; } btree->n_free_nodes--; n = btree->n_used_nodes++; - btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 12); + le16_add_cpu(&btree->first_free, 12); btree->u.external[n].disk_secno = cpu_to_le32(se); btree->u.external[n].file_secno = cpu_to_le32(fs); btree->u.external[n].length = cpu_to_le32(1); @@ -174,7 +174,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi } if (btree->n_free_nodes) { btree->n_free_nodes--; n = btree->n_used_nodes++; - btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 8); + le16_add_cpu(&btree->first_free, 8); btree->u.internal[n].file_secno = cpu_to_le32(-1); btree->u.internal[n].down = cpu_to_le32(na); btree->u.internal[n-1].file_secno = cpu_to_le32(fs); diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index 3228c524ebe5..4364b2a02c5d 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c @@ -145,10 +145,10 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno } } if (ptr) { - d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + 4); + le32_add_cpu(&d->first_free, 4); if (le32_to_cpu(d->first_free) > 2048) { hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self)); - d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - 4); + le32_add_cpu(&d->first_free, -4); return; } de->length = cpu_to_le16(36); @@ -184,7 +184,7 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, de->not_8x3 = hpfs_is_name_long(name, namelen); de->namelen = namelen; memcpy(de->name, name, namelen); - d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + d_size); + le32_add_cpu(&d->first_free, d_size); return de; } @@ -314,7 +314,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); de = de_next_de(de); memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); - nd->first_free = cpu_to_le32(le32_to_cpu(nd->first_free) - ((char *)de - (char *)nd - 20)); + le32_add_cpu(&nd->first_free, -((char *)de - (char *)nd - 20)); memcpy(d, nd, le32_to_cpu(nd->first_free)); for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); fix_up_ptrs(i->i_sb, ad); @@ -474,8 +474,8 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) hpfs_brelse4(&qbh); return 0; } - dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); - de->length = cpu_to_le16(le16_to_cpu(de->length) - 4); + le32_add_cpu(&dnode->first_free, -4); + le16_add_cpu(&de->length, -4); de->down = 0; hpfs_mark_4buffers_dirty(&qbh); dno = up; @@ -570,8 +570,8 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); if (!down) { de->down = 0; - de->length = cpu_to_le16(le16_to_cpu(de->length) - 4); - dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); + le16_add_cpu(&de->length, -4); + le32_add_cpu(&dnode->first_free, -4); memmove(de_next_de(de), (char *)de_next_de(de) + 4, (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); } else { @@ -647,14 +647,14 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); printk("HPFS: warning: goin'on\n"); } - del->length = cpu_to_le16(le16_to_cpu(del->length) + 4); + le16_add_cpu(&del->length, 4); del->down = 1; - d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) + 4); + le32_add_cpu(&d1->first_free, 4); } if (dlp && !down) { - del->length = cpu_to_le16(le16_to_cpu(del->length) - 4); + le16_add_cpu(&del->length, -4); del->down = 0; - d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4); + le32_add_cpu(&d1->first_free, -4); } else if (down) *(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); } else goto endm; @@ -668,9 +668,9 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length)); hpfs_delete_de(i->i_sb, dnode, de_prev); if (!de_prev->down) { - de_prev->length = cpu_to_le16(le16_to_cpu(de_prev->length) + 4); + le16_add_cpu(&de_prev->length, 4); de_prev->down = 1; - dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4); + le32_add_cpu(&dnode->first_free, 4); } *(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); hpfs_mark_4buffers_dirty(&qbh); diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 52c15c776029..86b39b167c23 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -86,7 +86,12 @@ nope: static void release_data_buffer(struct buffer_head *bh) { if (buffer_freed(bh)) { + WARN_ON_ONCE(buffer_dirty(bh)); clear_buffer_freed(bh); + clear_buffer_mapped(bh); + clear_buffer_new(bh); + clear_buffer_req(bh); + bh->b_bdev = NULL; release_buffer_page(bh); } else put_bh(bh); @@ -866,17 +871,35 @@ restart_loop: * there's no point in keeping a checkpoint record for * it. */ - /* A buffer which has been freed while still being - * journaled by a previous transaction may end up still - * being dirty here, but we want to avoid writing back - * that buffer in the future after the "add to orphan" - * operation been committed, That's not only a performance - * gain, it also stops aliasing problems if the buffer is - * left behind for writeback and gets reallocated for another - * use in a different page. */ - if (buffer_freed(bh) && !jh->b_next_transaction) { - clear_buffer_freed(bh); - clear_buffer_jbddirty(bh); + /* + * A buffer which has been freed while still being journaled by + * a previous transaction. + */ + if (buffer_freed(bh)) { + /* + * If the running transaction is the one containing + * "add to orphan" operation (b_next_transaction != + * NULL), we have to wait for that transaction to + * commit before we can really get rid of the buffer. + * So just clear b_modified to not confuse transaction + * credit accounting and refile the buffer to + * BJ_Forget of the running transaction. If the just + * committed transaction contains "add to orphan" + * operation, we can completely invalidate the buffer + * now. We are rather throughout in that since the + * buffer may be still accessible when blocksize < + * pagesize and it is attached to the last partial + * page. + */ + jh->b_modified = 0; + if (!jh->b_next_transaction) { + clear_buffer_freed(bh); + clear_buffer_jbddirty(bh); + clear_buffer_mapped(bh); + clear_buffer_new(bh); + clear_buffer_req(bh); + bh->b_bdev = NULL; + } } if (buffer_jbddirty(bh)) { diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index febc10db5ced..78b7f84241d4 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1843,15 +1843,16 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) * We're outside-transaction here. Either or both of j_running_transaction * and j_committing_transaction may be NULL. */ -static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) +static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, + int partial_page) { transaction_t *transaction; struct journal_head *jh; int may_free = 1; - int ret; BUFFER_TRACE(bh, "entry"); +retry: /* * It is safe to proceed here without the j_list_lock because the * buffers cannot be stolen by try_to_free_buffers as long as we are @@ -1879,10 +1880,18 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * clear the buffer dirty bit at latest at the moment when the * transaction marking the buffer as freed in the filesystem * structures is committed because from that moment on the - * buffer can be reallocated and used by a different page. + * block can be reallocated and used by a different page. * Since the block hasn't been freed yet but the inode has * already been added to orphan list, it is safe for us to add * the buffer to BJ_Forget list of the newest transaction. + * + * Also we have to clear buffer_mapped flag of a truncated buffer + * because the buffer_head may be attached to the page straddling + * i_size (can happen only when blocksize < pagesize) and thus the + * buffer_head can be reused when the file is extended again. So we end + * up keeping around invalidated buffers attached to transactions' + * BJ_Forget list just to stop checkpointing code from cleaning up + * the transaction this buffer was modified in. */ transaction = jh->b_transaction; if (transaction == NULL) { @@ -1909,13 +1918,9 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * committed, the buffer won't be needed any * longer. */ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); - ret = __dispose_buffer(jh, + may_free = __dispose_buffer(jh, journal->j_running_transaction); - journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); - return ret; + goto zap_buffer; } else { /* There is no currently-running transaction. So the * orphan record which we wrote for this file must have @@ -1923,13 +1928,9 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * the committing transaction, if it exists. */ if (journal->j_committing_transaction) { JBUFFER_TRACE(jh, "give to committing trans"); - ret = __dispose_buffer(jh, + may_free = __dispose_buffer(jh, journal->j_committing_transaction); - journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); - return ret; + goto zap_buffer; } else { /* The orphan record's transaction has * committed. We can cleanse this buffer */ @@ -1950,10 +1951,24 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) } /* * The buffer is committing, we simply cannot touch - * it. So we just set j_next_transaction to the - * running transaction (if there is one) and mark - * buffer as freed so that commit code knows it should - * clear dirty bits when it is done with the buffer. + * it. If the page is straddling i_size we have to wait + * for commit and try again. + */ + if (partial_page) { + tid_t tid = journal->j_committing_transaction->t_tid; + + journal_put_journal_head(jh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + goto retry; + } + /* + * OK, buffer won't be reachable after truncate. We just set + * j_next_transaction to the running transaction (if there is + * one) and mark buffer as freed so that commit code knows it + * should clear dirty bits when it is done with the buffer. */ set_buffer_freed(bh); if (journal->j_running_transaction && buffer_jbddirty(bh)) @@ -1976,6 +1991,14 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) } zap_buffer: + /* + * This is tricky. Although the buffer is truncated, it may be reused + * if blocksize < pagesize and it is attached to the page straddling + * EOF. Since the buffer might have been added to BJ_Forget list of the + * running transaction, journal_get_write_access() won't clear + * b_modified and credit accounting gets confused. So clear b_modified + * here. */ + jh->b_modified = 0; journal_put_journal_head(jh); zap_buffer_no_jh: spin_unlock(&journal->j_list_lock); @@ -2024,7 +2047,8 @@ void journal_invalidatepage(journal_t *journal, if (offset <= curr_off) { /* This block is wholly outside the truncation point */ lock_buffer(bh); - may_free &= journal_unmap_buffer(journal, bh); + may_free &= journal_unmap_buffer(journal, bh, + offset > 0); unlock_buffer(bh); } curr_off = next_off; diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 2c6d95257a4d..77e3cb2962b4 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -146,8 +146,7 @@ static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe, be64_to_cpu(entry->e_blocks); if (omfs_allocate_block(inode->i_sb, new_block)) { - entry->e_blocks = - cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1); + be64_add_cpu(&entry->e_blocks, 1); terminator->e_blocks = ~(cpu_to_be64( be64_to_cpu(~terminator->e_blocks) + 1)); goto out; @@ -177,7 +176,7 @@ static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe, be64_to_cpu(~terminator->e_blocks) + (u64) new_count)); /* write in new entry */ - oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count)); + be32_add_cpu(&oe->e_extent_count, 1); out: *ret_block = new_block; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index b3647fe6a608..0d80cef4cfb9 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -427,7 +427,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { pde_get(de); spin_unlock(&proc_subdir_lock); - error = -EINVAL; + error = -ENOMEM; inode = proc_get_inode(dir->i_sb, de); goto out_unlock; } @@ -605,7 +605,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, unsigned int len; /* make sure name is valid */ - if (!name || !strlen(name)) goto out; + if (!name || !strlen(name)) + goto out; if (xlate_proc_name(name, parent, &fn) != 0) goto out; @@ -616,20 +617,18 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, len = strlen(fn); - ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); - if (!ent) goto out; + ent = kzalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); + if (!ent) + goto out; - memset(ent, 0, sizeof(struct proc_dir_entry)); memcpy(ent->name, fn, len + 1); ent->namelen = len; ent->mode = mode; ent->nlink = nlink; atomic_set(&ent->count, 1); - ent->pde_users = 0; spin_lock_init(&ent->pde_unload_lock); - ent->pde_unload_completion = NULL; INIT_LIST_HEAD(&ent->pde_openers); - out: +out: return ent; } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 7ac817b64a71..3b22bbdee9ec 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -450,7 +450,6 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) return NULL; if (inode->i_state & I_NEW) { inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - PROC_I(inode)->fd = 0; PROC_I(inode)->pde = de; if (de->mode) { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 67925a7bd8cb..cceaab07ad54 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -103,7 +103,7 @@ static inline int task_dumpable(struct task_struct *task) if (mm) dumpable = get_dumpable(mm); task_unlock(task); - if(dumpable == 1) + if (dumpable == SUID_DUMPABLE_ENABLED) return 1; return 0; } diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index eb7cc91b7258..dcd56f84db7e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -266,8 +266,7 @@ void sysctl_head_put(struct ctl_table_header *head) static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) { - if (!head) - BUG(); + BUG_ON(!head); spin_lock(&sysctl_lock); if (!use_table(head)) head = ERR_PTR(-ENOENT); diff --git a/fs/proc/root.c b/fs/proc/root.c index 9a2d9fd7cadd..9889a92d2e01 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -61,7 +61,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) if (!*p) continue; - args[0].to = args[0].from = 0; + args[0].to = args[0].from = NULL; token = match_token(p, tokens, args); switch (token) { case Opt_gid: diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index d319963aeb11..c196369fe408 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -896,7 +896,7 @@ static int create_privroot(struct dentry *dentry) { return 0; } #endif /* Actual operations that are exported to VFS-land */ -const struct xattr_handler *reiserfs_xattr_handlers[] = { +static const struct xattr_handler *reiserfs_xattr_handlers[] = { #ifdef CONFIG_REISERFS_FS_XATTR &reiserfs_xattr_user_handler, &reiserfs_xattr_trusted_handler, diff --git a/fs/super.c b/fs/super.c index 5fdf7ff32c4e..a3bc935069d9 100644 --- a/fs/super.c +++ b/fs/super.c @@ -865,7 +865,7 @@ int get_anon_bdev(dev_t *p) else if (error) return -EAGAIN; - if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { + if ((dev & MAX_IDR_MASK) == (1 << MINORBITS)) { spin_lock(&unnamed_dev_lock); ida_remove(&unnamed_dev_ida, dev); if (unnamed_dev_start > dev) diff --git a/fs/udf/file.c b/fs/udf/file.c index d1c6093fd3d3..77b5953eaac8 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -118,11 +118,20 @@ static int udf_adinicb_write_end(struct file *file, return simple_write_end(file, mapping, pos, len, copied, page, fsdata); } +static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + /* Fallback to buffered I/O. */ + return 0; +} + const struct address_space_operations udf_adinicb_aops = { .readpage = udf_adinicb_readpage, .writepage = udf_adinicb_writepage, .write_begin = udf_adinicb_write_begin, .write_end = udf_adinicb_write_end, + .direct_IO = udf_adinicb_direct_IO, }; static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 287ef9f587b7..df88b957ccf0 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -95,11 +95,33 @@ void udf_evict_inode(struct inode *inode) } } +static void udf_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + struct udf_inode_info *iinfo = UDF_I(inode); + loff_t isize = inode->i_size; + + if (to > isize) { + truncate_pagecache(inode, to, isize); + if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + down_write(&iinfo->i_data_sem); + udf_truncate_extents(inode); + up_write(&iinfo->i_data_sem); + } + } +} + static int udf_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, udf_get_block, wbc); } +static int udf_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + return mpage_writepages(mapping, wbc, udf_get_block); +} + static int udf_readpage(struct file *file, struct page *page) { return mpage_readpage(page, udf_get_block); @@ -118,21 +140,24 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, int ret; ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block); - if (unlikely(ret)) { - struct inode *inode = mapping->host; - struct udf_inode_info *iinfo = UDF_I(inode); - loff_t isize = inode->i_size; - - if (pos + len > isize) { - truncate_pagecache(inode, pos + len, isize); - if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { - down_write(&iinfo->i_data_sem); - udf_truncate_extents(inode); - up_write(&iinfo->i_data_sem); - } - } - } + if (unlikely(ret)) + udf_write_failed(mapping, pos + len); + return ret; +} +static ssize_t udf_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + + ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, + udf_get_block); + if (unlikely(ret < 0 && (rw & WRITE))) + udf_write_failed(mapping, offset + iov_length(iov, nr_segs)); return ret; } @@ -145,8 +170,10 @@ const struct address_space_operations udf_aops = { .readpage = udf_readpage, .readpages = udf_readpages, .writepage = udf_writepage, - .write_begin = udf_write_begin, - .write_end = generic_write_end, + .writepages = udf_writepages, + .write_begin = udf_write_begin, + .write_end = generic_write_end, + .direct_IO = udf_direct_IO, .bmap = udf_bmap, }; diff --git a/include/asm-generic/bitops/le.h b/include/asm-generic/bitops/le.h index f95c663a6a41..61731543c00e 100644 --- a/include/asm-generic/bitops/le.h +++ b/include/asm-generic/bitops/le.h @@ -54,6 +54,16 @@ static inline int test_bit_le(int nr, const void *addr) return test_bit(nr ^ BITOP_LE_SWIZZLE, addr); } +static inline void set_bit_le(int nr, void *addr) +{ + set_bit(nr ^ BITOP_LE_SWIZZLE, addr); +} + +static inline void clear_bit_le(int nr, void *addr) +{ + clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); +} + static inline void __set_bit_le(int nr, void *addr) { __set_bit(nr ^ BITOP_LE_SWIZZLE, addr); diff --git a/include/crypto/cast5.h b/include/crypto/cast5.h new file mode 100644 index 000000000000..586183a0406e --- /dev/null +++ b/include/crypto/cast5.h @@ -0,0 +1,27 @@ +#ifndef _CRYPTO_CAST5_H +#define _CRYPTO_CAST5_H + +#include <linux/types.h> +#include <linux/crypto.h> + +#define CAST5_BLOCK_SIZE 8 +#define CAST5_MIN_KEY_SIZE 5 +#define CAST5_MAX_KEY_SIZE 16 + +struct cast5_ctx { + u32 Km[16]; + u8 Kr[16]; + int rr; /* rr ? rounds = 12 : rounds = 16; (rfc 2144) */ +}; + +int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); + +void __cast5_encrypt(struct cast5_ctx *ctx, u8 *dst, const u8 *src); +void __cast5_decrypt(struct cast5_ctx *ctx, u8 *dst, const u8 *src); + +extern const u32 cast5_s1[256]; +extern const u32 cast5_s2[256]; +extern const u32 cast5_s3[256]; +extern const u32 cast5_s4[256]; + +#endif diff --git a/include/crypto/cast6.h b/include/crypto/cast6.h new file mode 100644 index 000000000000..157af6f342c8 --- /dev/null +++ b/include/crypto/cast6.h @@ -0,0 +1,28 @@ +#ifndef _CRYPTO_CAST6_H +#define _CRYPTO_CAST6_H + +#include <linux/types.h> +#include <linux/crypto.h> + +#define CAST6_BLOCK_SIZE 16 +#define CAST6_MIN_KEY_SIZE 16 +#define CAST6_MAX_KEY_SIZE 32 + +struct cast6_ctx { + u32 Km[12][4]; + u8 Kr[12][4]; +}; + +int __cast6_setkey(struct cast6_ctx *ctx, const u8 *key, + unsigned int keylen, u32 *flags); +int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); + +void __cast6_encrypt(struct cast6_ctx *ctx, u8 *dst, const u8 *src); +void __cast6_decrypt(struct cast6_ctx *ctx, u8 *dst, const u8 *src); + +extern const u32 cast6_s1[256]; +extern const u32 cast6_s2[256]; +extern const u32 cast6_s3[256]; +extern const u32 cast6_s4[256]; + +#endif diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 5bfad8c80595..821eae8cbd8c 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -83,6 +83,8 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask); int crypto_register_shash(struct shash_alg *alg); int crypto_unregister_shash(struct shash_alg *alg); +int crypto_register_shashes(struct shash_alg *algs, int count); +int crypto_unregister_shashes(struct shash_alg *algs, int count); int shash_register_instance(struct crypto_template *tmpl, struct shash_instance *inst); void shash_free_instance(struct crypto_instance *inst); diff --git a/include/linux/audit.h b/include/linux/audit.h index e7c836d961ea..2c83e5f7edb1 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -527,9 +527,18 @@ static inline void audit_ptrace(struct task_struct *t) extern unsigned int audit_serial(void); extern int auditsc_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial); -extern int audit_set_loginuid(kuid_t loginuid); -#define audit_get_loginuid(t) ((t)->loginuid) -#define audit_get_sessionid(t) ((t)->sessionid) +extern int audit_set_loginuid(kuid_t loginuid); + +static inline kuid_t audit_get_loginuid(struct task_struct *tsk) +{ + return tsk->loginuid; +} + +static inline int audit_get_sessionid(struct task_struct *tsk) +{ + return tsk->sessionid; +} + extern void audit_log_task_context(struct audit_buffer *ab); extern void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk); extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); @@ -626,38 +635,101 @@ static inline void audit_mmap_fd(int fd, int flags) extern int audit_n_rules; extern int audit_signals; #else /* CONFIG_AUDITSYSCALL */ -#define audit_alloc(t) ({ 0; }) -#define audit_free(t) do { ; } while (0) -#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0) -#define audit_syscall_exit(r) do { ; } while (0) -#define audit_dummy_context() 1 -#define audit_getname(n) do { ; } while (0) -#define audit_putname(n) do { ; } while (0) -#define __audit_inode(n,d) do { ; } while (0) -#define __audit_inode_child(i,p) do { ; } while (0) -#define audit_inode(n,d) do { (void)(d); } while (0) -#define audit_inode_child(i,p) do { ; } while (0) -#define audit_core_dumps(i) do { ; } while (0) -#define audit_seccomp(i,s,c) do { ; } while (0) -#define auditsc_get_stamp(c,t,s) (0) -#define audit_get_loginuid(t) (INVALID_UID) -#define audit_get_sessionid(t) (-1) -#define audit_log_task_context(b) do { ; } while (0) -#define audit_log_task_info(b, t) do { ; } while (0) -#define audit_ipc_obj(i) ((void)0) -#define audit_ipc_set_perm(q,u,g,m) ((void)0) -#define audit_bprm(p) ({ 0; }) -#define audit_socketcall(n,a) ((void)0) -#define audit_fd_pair(n,a) ((void)0) -#define audit_sockaddr(len, addr) ({ 0; }) -#define audit_mq_open(o,m,a) ((void)0) -#define audit_mq_sendrecv(d,l,p,t) ((void)0) -#define audit_mq_notify(d,n) ((void)0) -#define audit_mq_getsetattr(d,s) ((void)0) -#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; }) -#define audit_log_capset(pid, ncr, ocr) ((void)0) -#define audit_mmap_fd(fd, flags) ((void)0) -#define audit_ptrace(t) ((void)0) +static inline int audit_alloc(struct task_struct *task) +{ + return 0; +} +static inline void audit_free(struct task_struct *task) +{ } +static inline void audit_syscall_entry(int arch, int major, unsigned long a0, + unsigned long a1, unsigned long a2, + unsigned long a3) +{ } +static inline void audit_syscall_exit(void *pt_regs) +{ } +static inline int audit_dummy_context(void) +{ + return 1; +} +static inline void audit_getname(const char *name) +{ } +static inline void audit_putname(const char *name) +{ } +static inline void __audit_inode(const char *name, const struct dentry *dentry) +{ } +static inline void __audit_inode_child(const struct dentry *dentry, + const struct inode *parent) +{ } +static inline void audit_inode(const char *name, const struct dentry *dentry) +{ } +static inline void audit_inode_child(const struct dentry *dentry, + const struct inode *parent) +{ } +static inline void audit_core_dumps(long signr) +{ } +static inline void __audit_seccomp(unsigned long syscall, long signr, int code) +{ } +static inline void audit_seccomp(unsigned long syscall, long signr, int code) +{ } +static inline int auditsc_get_stamp(struct audit_context *ctx, + struct timespec *t, unsigned int *serial) +{ + return 0; +} +static inline kuid_t audit_get_loginuid(struct task_struct *tsk) +{ + return INVALID_UID; +} +static inline int audit_get_sessionid(struct task_struct *tsk) +{ + return -1; +} +static inline void audit_log_task_context(struct audit_buffer *ab) +{ } +static inline void audit_log_task_info(struct audit_buffer *ab, + struct task_struct *tsk) +{ } +static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) +{ } +static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, + gid_t gid, umode_t mode) +{ } +static inline int audit_bprm(struct linux_binprm *bprm) +{ + return 0; +} +static inline void audit_socketcall(int nargs, unsigned long *args) +{ } +static inline void audit_fd_pair(int fd1, int fd2) +{ } +static inline int audit_sockaddr(int len, void *addr) +{ + return 0; +} +static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr) +{ } +static inline void audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, + unsigned int msg_prio, + const struct timespec *abs_timeout) +{ } +static inline void audit_mq_notify(mqd_t mqdes, + const struct sigevent *notification) +{ } +static inline void audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) +{ } +static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, + const struct cred *new, + const struct cred *old) +{ + return 0; +} +static inline void audit_log_capset(pid_t pid, const struct cred *new, + const struct cred *old) +{ } +static inline void audit_mmap_fd(int fd, int flags) +{ } +static inline void audit_ptrace(struct task_struct *t) +{ } #define audit_n_rules 0 #define audit_signals 0 #endif /* CONFIG_AUDITSYSCALL */ @@ -681,7 +753,6 @@ extern void audit_log_n_hex(struct audit_buffer *ab, extern void audit_log_n_string(struct audit_buffer *ab, const char *buf, size_t n); -#define audit_log_string(a,b) audit_log_n_string(a, b, strlen(b)); extern void audit_log_n_untrustedstring(struct audit_buffer *ab, const char *string, size_t n); @@ -698,7 +769,8 @@ extern void audit_log_lost(const char *message); #ifdef CONFIG_SECURITY extern void audit_log_secctx(struct audit_buffer *ab, u32 secid); #else -#define audit_log_secctx(b,s) do { ; } while (0) +static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid) +{ } #endif extern int audit_update_lsm_rules(void); @@ -710,22 +782,50 @@ extern int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz, kuid_t loginuid, u32 sessionid, u32 sid); extern int audit_enabled; -#else -#define audit_log(c,g,t,f,...) do { ; } while (0) -#define audit_log_start(c,g,t) ({ NULL; }) -#define audit_log_vformat(b,f,a) do { ; } while (0) -#define audit_log_format(b,f,...) do { ; } while (0) -#define audit_log_end(b) do { ; } while (0) -#define audit_log_n_hex(a,b,l) do { ; } while (0) -#define audit_log_n_string(a,c,l) do { ; } while (0) -#define audit_log_string(a,c) do { ; } while (0) -#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0) -#define audit_log_untrustedstring(a,s) do { ; } while (0) -#define audit_log_d_path(b, p, d) do { ; } while (0) -#define audit_log_key(b, k) do { ; } while (0) -#define audit_log_link_denied(o, l) do { ; } while (0) -#define audit_log_secctx(b,s) do { ; } while (0) +#else /* CONFIG_AUDIT */ +static inline __printf(4, 5) +void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, + const char *fmt, ...) +{ } +static inline struct audit_buffer *audit_log_start(struct audit_context *ctx, + gfp_t gfp_mask, int type) +{ + return NULL; +} +static inline __printf(2, 3) +void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) +{ } +static inline void audit_log_end(struct audit_buffer *ab) +{ } +static inline void audit_log_n_hex(struct audit_buffer *ab, + const unsigned char *buf, size_t len) +{ } +static inline void audit_log_n_string(struct audit_buffer *ab, + const char *buf, size_t n) +{ } +static inline void audit_log_n_untrustedstring(struct audit_buffer *ab, + const char *string, size_t n) +{ } +static inline void audit_log_untrustedstring(struct audit_buffer *ab, + const char *string) +{ } +static inline void audit_log_d_path(struct audit_buffer *ab, + const char *prefix, + const struct path *path) +{ } +static inline void audit_log_key(struct audit_buffer *ab, char *key) +{ } +static inline void audit_log_link_denied(const char *string, + const struct path *link) +{ } +static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid) +{ } #define audit_enabled 0 -#endif +#endif /* CONFIG_AUDIT */ +static inline void audit_log_string(struct audit_buffer *ab, const char *buf) +{ + audit_log_n_string(ab, buf, strlen(buf)); +} + #endif #endif diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 366422bc1633..37935c2d2e8f 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -72,7 +72,7 @@ struct linux_binprm { /* Function parameter for binfmt->coredump */ struct coredump_params { - long signr; + siginfo_t *siginfo; struct pt_regs *regs; struct file *file; unsigned long limit; @@ -132,7 +132,6 @@ extern int copy_strings_kernel(int argc, const char *const *argv, struct linux_binprm *bprm); extern int prepare_bprm_creds(struct linux_binprm *bprm); extern void install_exec_creds(struct linux_binprm *bprm); -extern void do_coredump(long signr, int exit_code, struct pt_regs *regs); extern void set_binfmt(struct linux_binfmt *new); extern void free_bprm(struct linux_binprm *); diff --git a/include/linux/compat.h b/include/linux/compat.h index fd4e29956d1c..3f53d002c7c5 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -160,11 +160,6 @@ struct compat_ustat { char f_fpack[6]; }; -typedef union compat_sigval { - compat_int_t sival_int; - compat_uptr_t sival_ptr; -} compat_sigval_t; - #define COMPAT_SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) typedef struct compat_sigevent { diff --git a/include/linux/coredump.h b/include/linux/coredump.h index ba4b85a6d9b8..1775eb8acc03 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -11,5 +11,10 @@ */ extern int dump_write(struct file *file, const void *addr, int nr); extern int dump_seek(struct file *file, loff_t off); +#ifdef CONFIG_COREDUMP +extern void do_coredump(siginfo_t *siginfo, struct pt_regs *regs); +#else +static inline void do_coredump(siginfo_t *siginfo, struct pt_regs *regs) {} +#endif #endif /* _LINUX_COREDUMP_H */ diff --git a/include/linux/elf.h b/include/linux/elf.h index 0a05051a8924..59ef40650e1e 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -372,6 +372,12 @@ typedef struct elf64_shdr { #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 #define NT_AUXV 6 +/* + * Note to userspace developers: size of NT_SIGINFO note may increase + * in the future to accomodate more fields, don't assume it is fixed! + */ +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 #define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index f4bb378ccf6a..41085d0f3955 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -25,6 +25,7 @@ #define EPOLL_CTL_ADD 1 #define EPOLL_CTL_DEL 2 #define EPOLL_CTL_MOD 3 +#define EPOLL_CTL_DISABLE 4 /* * Request the handling of system wakeup events so as to prevent system suspends diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 5e98eeb2af3b..dd7c569aacad 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -29,6 +29,20 @@ #ifndef __GENALLOC_H__ #define __GENALLOC_H__ +/** + * Allocation callback function type definition + * @map: Pointer to bitmap + * @size: The bitmap size in bits + * @start: The bitnumber to start searching at + * @nr: The number of zeroed bits we're looking for + * @data: optional additional data used by @genpool_algo_t + */ +typedef unsigned long (*genpool_algo_t)(unsigned long *map, + unsigned long size, + unsigned long start, + unsigned int nr, + void *data); + /* * General purpose special memory pool descriptor. */ @@ -36,6 +50,9 @@ struct gen_pool { spinlock_t lock; struct list_head chunks; /* list of chunks in this pool */ int min_alloc_order; /* minimum allocation order */ + + genpool_algo_t algo; /* allocation function */ + void *data; }; /* @@ -78,4 +95,14 @@ extern void gen_pool_for_each_chunk(struct gen_pool *, void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *); extern size_t gen_pool_avail(struct gen_pool *); extern size_t gen_pool_size(struct gen_pool *); + +extern void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo, + void *data); + +extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size, + unsigned long start, unsigned int nr, void *data); + +extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size, + unsigned long start, unsigned int nr, void *data); + #endif /* __GENALLOC_H__ */ diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index a12a38107c1a..1faa58f9b85e 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -188,6 +188,7 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes); int twl_get_type(void); int twl_get_version(void); +int twl_get_hfclk_rate(void); int twl6030_interrupt_unmask(u8 bit_mask, u8 offset); int twl6030_interrupt_mask(u8 bit_mask, u8 offset); diff --git a/include/linux/idr.h b/include/linux/idr.h index 255491cf522e..87259a44c251 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -38,15 +38,15 @@ #define IDR_SIZE (1 << IDR_BITS) #define IDR_MASK ((1 << IDR_BITS)-1) -#define MAX_ID_SHIFT (sizeof(int)*8 - 1) -#define MAX_ID_BIT (1U << MAX_ID_SHIFT) -#define MAX_ID_MASK (MAX_ID_BIT - 1) +#define MAX_IDR_SHIFT (sizeof(int)*8 - 1) +#define MAX_IDR_BIT (1U << MAX_IDR_SHIFT) +#define MAX_IDR_MASK (MAX_IDR_BIT - 1) /* Leave the possibility of an incomplete final layer */ -#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS +#define MAX_IDR_LEVEL ((MAX_IDR_SHIFT + IDR_BITS - 1) / IDR_BITS) /* Number of id_layer structs to leave in free list */ -#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL +#define MAX_IDR_FREE (MAX_IDR_LEVEL * 2) struct idr_layer { unsigned long bitmap; /* A zero bit means "space here" */ diff --git a/include/linux/init.h b/include/linux/init.h index 5e664f671615..e59041e21df3 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -43,11 +43,22 @@ discard it in modules) */ #define __init __section(.init.text) __cold notrace #define __initdata __section(.init.data) -#define __initconst __section(.init.rodata) +#define __initconst __constsection(.init.rodata) #define __exitdata __section(.exit.data) #define __exit_call __used __section(.exitcall.exit) /* + * Some architecture have tool chains which do not handle rodata attributes + * correctly. For those disable special sections for const, so that other + * architectures can annotate correctly. + */ +#ifdef CONFIG_BROKEN_RODATA +#define __constsection(x) +#else +#define __constsection(x) __section(x) +#endif + +/* * modpost check for section mismatches during the kernel build. * A section mismatch happens when there are references from a * code or data section to an init section (both code or data). @@ -66,7 +77,7 @@ */ #define __ref __section(.ref.text) noinline #define __refdata __section(.ref.data) -#define __refconst __section(.ref.rodata) +#define __refconst __constsection(.ref.rodata) /* compatibility defines */ #define __init_refok __ref @@ -85,26 +96,26 @@ /* Used for HOTPLUG */ #define __devinit __section(.devinit.text) __cold notrace #define __devinitdata __section(.devinit.data) -#define __devinitconst __section(.devinit.rodata) +#define __devinitconst __constsection(.devinit.rodata) #define __devexit __section(.devexit.text) __exitused __cold notrace #define __devexitdata __section(.devexit.data) -#define __devexitconst __section(.devexit.rodata) +#define __devexitconst __constsection(.devexit.rodata) /* Used for HOTPLUG_CPU */ #define __cpuinit __section(.cpuinit.text) __cold notrace #define __cpuinitdata __section(.cpuinit.data) -#define __cpuinitconst __section(.cpuinit.rodata) +#define __cpuinitconst __constsection(.cpuinit.rodata) #define __cpuexit __section(.cpuexit.text) __exitused __cold notrace #define __cpuexitdata __section(.cpuexit.data) -#define __cpuexitconst __section(.cpuexit.rodata) +#define __cpuexitconst __constsection(.cpuexit.rodata) /* Used for MEMORY_HOTPLUG */ #define __meminit __section(.meminit.text) __cold notrace #define __meminitdata __section(.meminit.data) -#define __meminitconst __section(.meminit.rodata) +#define __meminitconst __constsection(.meminit.rodata) #define __memexit __section(.memexit.text) __exitused __cold notrace #define __memexitdata __section(.memexit.data) -#define __memexitconst __section(.memexit.rodata) +#define __memexitconst __constsection(.memexit.rodata) /* For assembly routines */ #define __HEAD .section ".head.text","ax" diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 589e0e75efae..85ac9b9b72a2 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -29,8 +29,9 @@ struct resource { #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ #define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ -#define IORESOURCE_IO 0x00000100 +#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */ #define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_REG 0x00000300 /* Register offsets */ #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 #define IORESOURCE_BUS 0x00001000 diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 2ce09aa7d3b3..0a6d6ba44c85 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -101,9 +101,13 @@ struct kvm_userspace_memory_region { __u64 userspace_addr; /* start of the userspace allocated memory */ }; -/* for kvm_memory_region::flags */ -#define KVM_MEM_LOG_DIRTY_PAGES 1UL -#define KVM_MEMSLOT_INVALID (1UL << 1) +/* + * The bit 0 ~ bit 15 of kvm_memory_region::flags are visible for userspace, + * other bits are reserved for kvm internal use which are defined in + * include/linux/kvm_host.h. + */ +#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) +#define KVM_MEM_READONLY (1UL << 1) /* for KVM_IRQ_LINE */ struct kvm_irq_level { @@ -618,6 +622,10 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_GET_SMMU_INFO 78 #define KVM_CAP_S390_COW 79 #define KVM_CAP_PPC_ALLOC_HTAB 80 +#ifdef __KVM_HAVE_READONLY_MEM +#define KVM_CAP_READONLY_MEM 81 +#endif +#define KVM_CAP_IRQFD_RESAMPLE 82 #ifdef KVM_CAP_IRQ_ROUTING @@ -683,12 +691,21 @@ struct kvm_xen_hvm_config { #endif #define KVM_IRQFD_FLAG_DEASSIGN (1 << 0) +/* + * Available with KVM_CAP_IRQFD_RESAMPLE + * + * KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies + * the irqfd to operate in resampling mode for level triggered interrupt + * emlation. See Documentation/virtual/kvm/api.txt. + */ +#define KVM_IRQFD_FLAG_RESAMPLE (1 << 1) struct kvm_irqfd { __u32 fd; __u32 gsi; __u32 flags; - __u8 pad[20]; + __u32 resamplefd; + __u8 pad[16]; }; struct kvm_clock_data { diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 8a59e0abe5fa..93bfc9f9815c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/rcupdate.h> #include <linux/ratelimit.h> +#include <linux/err.h> #include <asm/signal.h> #include <linux/kvm.h> @@ -35,6 +36,13 @@ #endif /* + * The bit 16 ~ bit 31 of kvm_memory_region::flags are internally used + * in kvm, other bits are visible for userspace which are defined in + * include/linux/kvm_h. + */ +#define KVM_MEMSLOT_INVALID (1UL << 16) + +/* * If we support unaligned MMIO, at most one fragment will be split into two: */ #ifdef KVM_UNALIGNED_MMIO @@ -49,6 +57,47 @@ (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS) /* + * For the normal pfn, the highest 12 bits should be zero, + * so we can mask these bits to indicate the error. + */ +#define KVM_PFN_ERR_MASK (0xfffULL << 52) + +#define KVM_PFN_ERR_FAULT (KVM_PFN_ERR_MASK) +#define KVM_PFN_ERR_HWPOISON (KVM_PFN_ERR_MASK + 1) +#define KVM_PFN_ERR_BAD (KVM_PFN_ERR_MASK + 2) +#define KVM_PFN_ERR_RO_FAULT (KVM_PFN_ERR_MASK + 3) + +static inline bool is_error_pfn(pfn_t pfn) +{ + return !!(pfn & KVM_PFN_ERR_MASK); +} + +static inline bool is_noslot_pfn(pfn_t pfn) +{ + return pfn == KVM_PFN_ERR_BAD; +} + +static inline bool is_invalid_pfn(pfn_t pfn) +{ + return !is_noslot_pfn(pfn) && is_error_pfn(pfn); +} + +#define KVM_HVA_ERR_BAD (PAGE_OFFSET) +#define KVM_HVA_ERR_RO_BAD (PAGE_OFFSET + PAGE_SIZE) + +static inline bool kvm_is_error_hva(unsigned long addr) +{ + return addr >= PAGE_OFFSET; +} + +#define KVM_ERR_PTR_BAD_PAGE (ERR_PTR(-ENOENT)) + +static inline bool is_error_page(struct page *page) +{ + return IS_ERR(page); +} + +/* * vcpu->requests bit members */ #define KVM_REQ_TLB_FLUSH 0 @@ -70,7 +119,8 @@ #define KVM_REQ_PMU 16 #define KVM_REQ_PMI 17 -#define KVM_USERSPACE_IRQ_SOURCE_ID 0 +#define KVM_USERSPACE_IRQ_SOURCE_ID 0 +#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 struct kvm; struct kvm_vcpu; @@ -183,6 +233,18 @@ struct kvm_vcpu { } async_pf; #endif +#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT + /* + * Cpu relax intercept or pause loop exit optimization + * in_spin_loop: set when a vcpu does a pause loop exit + * or cpu relax intercepted. + * dy_eligible: indicates whether vcpu is eligible for directed yield. + */ + struct { + bool in_spin_loop; + bool dy_eligible; + } spin_loop; +#endif struct kvm_vcpu_arch arch; }; @@ -201,7 +263,6 @@ struct kvm_memory_slot { gfn_t base_gfn; unsigned long npages; unsigned long flags; - unsigned long *rmap; unsigned long *dirty_bitmap; struct kvm_arch_memory_slot arch; unsigned long userspace_addr; @@ -283,6 +344,8 @@ struct kvm { struct { spinlock_t lock; struct list_head items; + struct list_head resampler_list; + struct mutex resampler_lock; } irqfds; struct list_head ioeventfds; #endif @@ -348,7 +411,7 @@ static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i) int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id); void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); -void vcpu_load(struct kvm_vcpu *vcpu); +int __must_check vcpu_load(struct kvm_vcpu *vcpu); void vcpu_put(struct kvm_vcpu *vcpu); int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, @@ -378,23 +441,6 @@ id_to_memslot(struct kvm_memslots *slots, int id) return slot; } -#define HPA_MSB ((sizeof(hpa_t) * 8) - 1) -#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) -static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } - -extern struct page *bad_page; -extern struct page *fault_page; - -extern pfn_t bad_pfn; -extern pfn_t fault_pfn; - -int is_error_page(struct page *page); -int is_error_pfn(pfn_t pfn); -int is_hwpoison_pfn(pfn_t pfn); -int is_fault_pfn(pfn_t pfn); -int is_noslot_pfn(pfn_t pfn); -int is_invalid_pfn(pfn_t pfn); -int kvm_is_error_hva(unsigned long addr); int kvm_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, int user_alloc); @@ -415,28 +461,33 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, int user_alloc); bool kvm_largepages_enabled(void); void kvm_disable_largepages(void); -void kvm_arch_flush_shadow(struct kvm *kvm); +/* flush all memory translations */ +void kvm_arch_flush_shadow_all(struct kvm *kvm); +/* flush memory translations pointing to 'slot' */ +void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot); int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, int nr_pages); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); +unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn); void kvm_release_page_clean(struct page *page); void kvm_release_page_dirty(struct page *page); void kvm_set_page_dirty(struct page *page); void kvm_set_page_accessed(struct page *page); -pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr); pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn); pfn_t gfn_to_pfn_async(struct kvm *kvm, gfn_t gfn, bool *async, bool write_fault, bool *writable); pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn); pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, bool *writable); -pfn_t gfn_to_pfn_memslot(struct kvm *kvm, - struct kvm_memory_slot *slot, gfn_t gfn); -void kvm_release_pfn_dirty(pfn_t); +pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn); +pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn); + +void kvm_release_pfn_dirty(pfn_t pfn); void kvm_release_pfn_clean(pfn_t pfn); void kvm_set_pfn_dirty(pfn_t pfn); void kvm_set_pfn_accessed(pfn_t pfn); @@ -494,6 +545,7 @@ int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, struct kvm_userspace_memory_region *mem, int user_alloc); +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level); long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); @@ -573,7 +625,7 @@ void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); void kvm_vcpu_kick(struct kvm_vcpu *vcpu); -int kvm_is_mmio_pfn(pfn_t pfn); +bool kvm_is_mmio_pfn(pfn_t pfn); struct kvm_irq_ack_notifier { struct hlist_node link; @@ -728,6 +780,12 @@ __gfn_to_memslot(struct kvm_memslots *slots, gfn_t gfn) return search_memslots(slots, gfn); } +static inline unsigned long +__gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE; +} + static inline int memslot_id(struct kvm *kvm, gfn_t gfn) { return gfn_to_memslot(kvm, gfn)->id; @@ -740,10 +798,12 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level) (base_gfn >> KVM_HPAGE_GFN_SHIFT(level)); } -static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, - gfn_t gfn) +static inline gfn_t +hva_to_gfn_memslot(unsigned long hva, struct kvm_memory_slot *slot) { - return slot->userspace_addr + (gfn - slot->base_gfn) * PAGE_SIZE; + gfn_t gfn_offset = (hva - slot->userspace_addr) >> PAGE_SHIFT; + + return slot->base_gfn + gfn_offset; } static inline gpa_t gfn_to_gpa(gfn_t gfn) @@ -899,5 +959,32 @@ static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu) } } +#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT + +static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val) +{ + vcpu->spin_loop.in_spin_loop = val; +} +static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val) +{ + vcpu->spin_loop.dy_eligible = val; +} + +#else /* !CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ + +static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val) +{ +} + +static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val) +{ +} + +static inline bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu) +{ + return true; +} + +#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */ #endif diff --git a/include/linux/libfdt.h b/include/linux/libfdt.h index a0c3bf6c9edb..4c0306c69b4e 100644 --- a/include/linux/libfdt.h +++ b/include/linux/libfdt.h @@ -2,7 +2,7 @@ #define _INCLUDE_LIBFDT_H_ #include <linux/libfdt_env.h> -#include <> -#include <> +#include "../../scripts/dtc/libfdt/fdt.h" +#include "../../scripts/dtc/libfdt/libfdt.h" #endif /* _INCLUDE_LIBFDT_H_ */ diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index 7b24943779fa..ef3e6b701179 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -34,22 +34,6 @@ enum { PM8606_ID_MAX, }; -enum { - PM8606_BACKLIGHT1 = 0, - PM8606_BACKLIGHT2, - PM8606_BACKLIGHT3, -}; - -enum { - PM8606_LED1_RED = 0, - PM8606_LED1_GREEN, - PM8606_LED1_BLUE, - PM8606_LED2_RED, - PM8606_LED2_GREEN, - PM8606_LED2_BLUE, - PM8607_LED_VIBRATOR, -}; - /* 8606 Registers */ #define PM8606_DCM_BOOST (0x00) @@ -322,7 +306,7 @@ struct pm860x_chip { struct regmap *regmap_companion; int buck3_double; /* DVC ramp slope double */ - unsigned short companion_addr; + int companion_addr; unsigned short osc_vote; int id; int irq_mode; @@ -340,16 +324,12 @@ enum { }; struct pm860x_backlight_pdata { - int id; int pwm; int iset; - unsigned long flags; }; struct pm860x_led_pdata { - int id; int iset; - unsigned long flags; }; struct pm860x_rtc_pdata { @@ -379,15 +359,29 @@ struct pm860x_platform_data { struct pm860x_rtc_pdata *rtc; struct pm860x_touch_pdata *touch; struct pm860x_power_pdata *power; - struct regulator_init_data *regulator; - - unsigned short companion_addr; /* I2C address of companion chip */ + struct regulator_init_data *buck1; + struct regulator_init_data *buck2; + struct regulator_init_data *buck3; + struct regulator_init_data *ldo1; + struct regulator_init_data *ldo2; + struct regulator_init_data *ldo3; + struct regulator_init_data *ldo4; + struct regulator_init_data *ldo5; + struct regulator_init_data *ldo6; + struct regulator_init_data *ldo7; + struct regulator_init_data *ldo8; + struct regulator_init_data *ldo9; + struct regulator_init_data *ldo10; + struct regulator_init_data *ldo12; + struct regulator_init_data *ldo_vibrator; + struct regulator_init_data *ldo14; + + int companion_addr; /* I2C address of companion chip */ int i2c_port; /* Controlled by GI2C or PI2C */ int irq_mode; /* Clear interrupt by read/write(0/1) */ int irq_base; /* IRQ base number of 88pm860x */ int num_leds; int num_backlights; - int num_regulators; }; extern int pm8606_osc_enable(struct pm860x_chip *, unsigned short); @@ -408,8 +402,4 @@ extern int pm860x_page_bulk_write(struct i2c_client *, int, int, extern int pm860x_page_set_bits(struct i2c_client *, int, unsigned char, unsigned char); -extern int pm860x_device_init(struct pm860x_chip *chip, - struct pm860x_platform_data *pdata) __devinit ; -extern void pm860x_device_exit(struct pm860x_chip *chip) __devexit ; - #endif /* __LINUX_MFD_88PM860X_H */ diff --git a/include/linux/mfd/ab3100.h b/include/linux/mfd/ab3100.h new file mode 100644 index 000000000000..afd3080bde24 --- /dev/null +++ b/include/linux/mfd/ab3100.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007-2009 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * AB3100 core access functions + * Author: Linus Walleij <linus.walleij@stericsson.com> + * + */ + +#include <linux/regulator/machine.h> + +struct device; + +#ifndef MFD_AB3100_H +#define MFD_AB3100_H + + +#define AB3100_P1A 0xc0 +#define AB3100_P1B 0xc1 +#define AB3100_P1C 0xc2 +#define AB3100_P1D 0xc3 +#define AB3100_P1E 0xc4 +#define AB3100_P1F 0xc5 +#define AB3100_P1G 0xc6 +#define AB3100_R2A 0xc7 +#define AB3100_R2B 0xc8 + +/* + * AB3100, EVENTA1, A2 and A3 event register flags + * these are catenated into a single 32-bit flag in the code + * for event notification broadcasts. + */ +#define AB3100_EVENTA1_ONSWA (0x01<<16) +#define AB3100_EVENTA1_ONSWB (0x02<<16) +#define AB3100_EVENTA1_ONSWC (0x04<<16) +#define AB3100_EVENTA1_DCIO (0x08<<16) +#define AB3100_EVENTA1_OVER_TEMP (0x10<<16) +#define AB3100_EVENTA1_SIM_OFF (0x20<<16) +#define AB3100_EVENTA1_VBUS (0x40<<16) +#define AB3100_EVENTA1_VSET_USB (0x80<<16) + +#define AB3100_EVENTA2_READY_TX (0x01<<8) +#define AB3100_EVENTA2_READY_RX (0x02<<8) +#define AB3100_EVENTA2_OVERRUN_ERROR (0x04<<8) +#define AB3100_EVENTA2_FRAMING_ERROR (0x08<<8) +#define AB3100_EVENTA2_CHARG_OVERCURRENT (0x10<<8) +#define AB3100_EVENTA2_MIDR (0x20<<8) +#define AB3100_EVENTA2_BATTERY_REM (0x40<<8) +#define AB3100_EVENTA2_ALARM (0x80<<8) + +#define AB3100_EVENTA3_ADC_TRIG5 (0x01) +#define AB3100_EVENTA3_ADC_TRIG4 (0x02) +#define AB3100_EVENTA3_ADC_TRIG3 (0x04) +#define AB3100_EVENTA3_ADC_TRIG2 (0x08) +#define AB3100_EVENTA3_ADC_TRIGVBAT (0x10) +#define AB3100_EVENTA3_ADC_TRIGVTX (0x20) +#define AB3100_EVENTA3_ADC_TRIG1 (0x40) +#define AB3100_EVENTA3_ADC_TRIG0 (0x80) + +/* AB3100, STR register flags */ +#define AB3100_STR_ONSWA (0x01) +#define AB3100_STR_ONSWB (0x02) +#define AB3100_STR_ONSWC (0x04) +#define AB3100_STR_DCIO (0x08) +#define AB3100_STR_BOOT_MODE (0x10) +#define AB3100_STR_SIM_OFF (0x20) +#define AB3100_STR_BATT_REMOVAL (0x40) +#define AB3100_STR_VBUS (0x80) + +/* + * AB3100 contains 8 regulators, one external regulator controller + * and a buck converter, further the LDO E and buck converter can + * have separate settings if they are in sleep mode, this is + * modeled as a separate regulator. + */ +#define AB3100_NUM_REGULATORS 10 + +/** + * struct ab3100 + * @access_mutex: lock out concurrent accesses to the AB3100 registers + * @dev: pointer to the containing device + * @i2c_client: I2C client for this chip + * @testreg_client: secondary client for test registers + * @chip_name: name of this chip variant + * @chip_id: 8 bit chip ID for this chip variant + * @event_subscribers: event subscribers are listed here + * @startup_events: a copy of the first reading of the event registers + * @startup_events_read: whether the first events have been read + * + * This struct is PRIVATE and devices using it should NOT + * access ANY fields. It is used as a token for calling the + * AB3100 functions. + */ +struct ab3100 { + struct mutex access_mutex; + struct device *dev; + struct i2c_client *i2c_client; + struct i2c_client *testreg_client; + char chip_name[32]; + u8 chip_id; + struct blocking_notifier_head event_subscribers; + u8 startup_events[3]; + bool startup_events_read; +}; + +/** + * struct ab3100_platform_data + * Data supplied to initialize board connections to the AB3100 + * @reg_constraints: regulator constraints for target board + * the order of these constraints are: LDO A, C, D, E, + * F, G, H, K, EXT and BUCK. + * @reg_initvals: initial values for the regulator registers + * plus two sleep settings for LDO E and the BUCK converter. + * exactly AB3100_NUM_REGULATORS+2 values must be sent in. + * Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK, + * BUCK sleep, LDO D. (LDO D need to be initialized last.) + * @external_voltage: voltage level of the external regulator. + */ +struct ab3100_platform_data { + struct regulator_init_data reg_constraints[AB3100_NUM_REGULATORS]; + u8 reg_initvals[AB3100_NUM_REGULATORS+2]; + int external_voltage; +}; + +int ab3100_event_register(struct ab3100 *ab3100, + struct notifier_block *nb); +int ab3100_event_unregister(struct ab3100 *ab3100, + struct notifier_block *nb); + +#endif /* MFD_AB3100_H */ diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 1318ca622633..5d5298d56026 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -1,12 +1,9 @@ /* * Copyright (C) 2007-2009 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 - * AB3100 core access functions - * Author: Linus Walleij <linus.walleij@stericsson.com> * * ABX500 core access functions. - * The abx500 interface is used for the Analog Baseband chip - * ab3100 and ab8500. + * The abx500 interface is used for the Analog Baseband chips. * * Author: Mattias Wallin <mattias.wallin@stericsson.com> * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> @@ -21,118 +18,6 @@ struct device; #ifndef MFD_ABX500_H #define MFD_ABX500_H -#define AB3100_P1A 0xc0 -#define AB3100_P1B 0xc1 -#define AB3100_P1C 0xc2 -#define AB3100_P1D 0xc3 -#define AB3100_P1E 0xc4 -#define AB3100_P1F 0xc5 -#define AB3100_P1G 0xc6 -#define AB3100_R2A 0xc7 -#define AB3100_R2B 0xc8 - -/* - * AB3100, EVENTA1, A2 and A3 event register flags - * these are catenated into a single 32-bit flag in the code - * for event notification broadcasts. - */ -#define AB3100_EVENTA1_ONSWA (0x01<<16) -#define AB3100_EVENTA1_ONSWB (0x02<<16) -#define AB3100_EVENTA1_ONSWC (0x04<<16) -#define AB3100_EVENTA1_DCIO (0x08<<16) -#define AB3100_EVENTA1_OVER_TEMP (0x10<<16) -#define AB3100_EVENTA1_SIM_OFF (0x20<<16) -#define AB3100_EVENTA1_VBUS (0x40<<16) -#define AB3100_EVENTA1_VSET_USB (0x80<<16) - -#define AB3100_EVENTA2_READY_TX (0x01<<8) -#define AB3100_EVENTA2_READY_RX (0x02<<8) -#define AB3100_EVENTA2_OVERRUN_ERROR (0x04<<8) -#define AB3100_EVENTA2_FRAMING_ERROR (0x08<<8) -#define AB3100_EVENTA2_CHARG_OVERCURRENT (0x10<<8) -#define AB3100_EVENTA2_MIDR (0x20<<8) -#define AB3100_EVENTA2_BATTERY_REM (0x40<<8) -#define AB3100_EVENTA2_ALARM (0x80<<8) - -#define AB3100_EVENTA3_ADC_TRIG5 (0x01) -#define AB3100_EVENTA3_ADC_TRIG4 (0x02) -#define AB3100_EVENTA3_ADC_TRIG3 (0x04) -#define AB3100_EVENTA3_ADC_TRIG2 (0x08) -#define AB3100_EVENTA3_ADC_TRIGVBAT (0x10) -#define AB3100_EVENTA3_ADC_TRIGVTX (0x20) -#define AB3100_EVENTA3_ADC_TRIG1 (0x40) -#define AB3100_EVENTA3_ADC_TRIG0 (0x80) - -/* AB3100, STR register flags */ -#define AB3100_STR_ONSWA (0x01) -#define AB3100_STR_ONSWB (0x02) -#define AB3100_STR_ONSWC (0x04) -#define AB3100_STR_DCIO (0x08) -#define AB3100_STR_BOOT_MODE (0x10) -#define AB3100_STR_SIM_OFF (0x20) -#define AB3100_STR_BATT_REMOVAL (0x40) -#define AB3100_STR_VBUS (0x80) - -/* - * AB3100 contains 8 regulators, one external regulator controller - * and a buck converter, further the LDO E and buck converter can - * have separate settings if they are in sleep mode, this is - * modeled as a separate regulator. - */ -#define AB3100_NUM_REGULATORS 10 - -/** - * struct ab3100 - * @access_mutex: lock out concurrent accesses to the AB3100 registers - * @dev: pointer to the containing device - * @i2c_client: I2C client for this chip - * @testreg_client: secondary client for test registers - * @chip_name: name of this chip variant - * @chip_id: 8 bit chip ID for this chip variant - * @event_subscribers: event subscribers are listed here - * @startup_events: a copy of the first reading of the event registers - * @startup_events_read: whether the first events have been read - * - * This struct is PRIVATE and devices using it should NOT - * access ANY fields. It is used as a token for calling the - * AB3100 functions. - */ -struct ab3100 { - struct mutex access_mutex; - struct device *dev; - struct i2c_client *i2c_client; - struct i2c_client *testreg_client; - char chip_name[32]; - u8 chip_id; - struct blocking_notifier_head event_subscribers; - u8 startup_events[3]; - bool startup_events_read; -}; - -/** - * struct ab3100_platform_data - * Data supplied to initialize board connections to the AB3100 - * @reg_constraints: regulator constraints for target board - * the order of these constraints are: LDO A, C, D, E, - * F, G, H, K, EXT and BUCK. - * @reg_initvals: initial values for the regulator registers - * plus two sleep settings for LDO E and the BUCK converter. - * exactly AB3100_NUM_REGULATORS+2 values must be sent in. - * Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK, - * BUCK sleep, LDO D. (LDO D need to be initialized last.) - * @external_voltage: voltage level of the external regulator. - */ -struct ab3100_platform_data { - struct regulator_init_data reg_constraints[AB3100_NUM_REGULATORS]; - u8 reg_initvals[AB3100_NUM_REGULATORS+2]; - int external_voltage; -}; - -int ab3100_event_register(struct ab3100 *ab3100, - struct notifier_block *nb); -int ab3100_event_unregister(struct ab3100 *ab3100, - struct notifier_block *nb); - /** * struct abx500_init_setting * Initial value of the registers for driver to use during setup. diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 3764cb6759e3..1491044efa10 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -341,6 +341,4 @@ static inline int is_ab8500_2p0(struct ab8500 *ab) return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0)); } -int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq); - #endif /* MFD_AB8500_H */ diff --git a/include/linux/mfd/anatop.h b/include/linux/mfd/anatop.h deleted file mode 100644 index 7f92acf03d9e..000000000000 --- a/include/linux/mfd/anatop.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * anatop.h - Anatop MFD driver - * - * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org> - * Copyright (C) 2012 Linaro - * - * 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 - */ - -#ifndef __LINUX_MFD_ANATOP_H -#define __LINUX_MFD_ANATOP_H - -#include <linux/spinlock.h> - -/** - * anatop - MFD data - * @ioreg: ioremap register - * @reglock: spinlock for register read/write - */ -struct anatop { - void *ioreg; - spinlock_t reglock; -}; - -extern u32 anatop_read_reg(struct anatop *, u32); -extern void anatop_write_reg(struct anatop *, u32, u32, u32); - -#endif /* __LINUX_MFD_ANATOP_H */ diff --git a/include/linux/mfd/da9055/core.h b/include/linux/mfd/da9055/core.h new file mode 100644 index 000000000000..c96ad682c59e --- /dev/null +++ b/include/linux/mfd/da9055/core.h @@ -0,0 +1,94 @@ +/* + * da9055 declarations for DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.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. + * + */ + +#ifndef __DA9055_CORE_H +#define __DA9055_CORE_H + +#include <linux/interrupt.h> +#include <linux/regmap.h> + +/* + * PMIC IRQ + */ +#define DA9055_IRQ_ALARM 0x01 +#define DA9055_IRQ_TICK 0x02 +#define DA9055_IRQ_NONKEY 0x00 +#define DA9055_IRQ_REGULATOR 0x0B +#define DA9055_IRQ_HWMON 0x03 + +struct da9055_pdata; + +struct da9055 { + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; + struct device *dev; + struct i2c_client *i2c_client; + + int irq_base; + int chip_irq; +}; + +/* Device I/O */ +static inline int da9055_reg_read(struct da9055 *da9055, unsigned char reg) +{ + int val, ret; + + ret = regmap_read(da9055->regmap, reg, &val); + if (ret < 0) + return ret; + + return val; +} + +static inline int da9055_reg_write(struct da9055 *da9055, unsigned char reg, + unsigned char val) +{ + return regmap_write(da9055->regmap, reg, val); +} + +static inline int da9055_group_read(struct da9055 *da9055, unsigned char reg, + unsigned reg_cnt, unsigned char *val) +{ + return regmap_bulk_read(da9055->regmap, reg, val, reg_cnt); +} + +static inline int da9055_group_write(struct da9055 *da9055, unsigned char reg, + unsigned reg_cnt, unsigned char *val) +{ + return regmap_raw_write(da9055->regmap, reg, val, reg_cnt); +} + +static inline int da9055_reg_update(struct da9055 *da9055, unsigned char reg, + unsigned char bit_mask, + unsigned char reg_val) +{ + return regmap_update_bits(da9055->regmap, reg, bit_mask, reg_val); +} + +/* Generic Device API */ +int da9055_device_init(struct da9055 *da9055); +void da9055_device_exit(struct da9055 *da9055); + +extern struct regmap_config da9055_regmap_config; + +#endif /* __DA9055_CORE_H */ diff --git a/include/linux/mfd/da9055/pdata.h b/include/linux/mfd/da9055/pdata.h new file mode 100644 index 000000000000..147293b4471d --- /dev/null +++ b/include/linux/mfd/da9055/pdata.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2012 Dialog Semiconductor Ltd. + * + * 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. + * + */ +#ifndef __DA9055_PDATA_H +#define __DA9055_PDATA_H + +#define DA9055_MAX_REGULATORS 8 + +struct da9055; + +enum gpio_select { + NO_GPIO = 0, + GPIO_1, + GPIO_2 +}; + +struct da9055_pdata { + int (*init) (struct da9055 *da9055); + int irq_base; + int gpio_base; + + struct regulator_init_data *regulators[DA9055_MAX_REGULATORS]; + bool reset_enable; /* Enable RTC in RESET Mode */ + enum gpio_select *gpio_rsel; /* Select regulator set thru GPIO 1/2 */ + enum gpio_select *gpio_ren; /* Enable regulator thru GPIO 1/2 */ +}; +#endif /* __DA9055_PDATA_H */ diff --git a/include/linux/mfd/da9055/reg.h b/include/linux/mfd/da9055/reg.h new file mode 100644 index 000000000000..df237ee54803 --- /dev/null +++ b/include/linux/mfd/da9055/reg.h @@ -0,0 +1,699 @@ +/* + * DA9055 declarations for DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.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. + * + */ + +#ifndef __DA9055_REG_H +#define __DA9055_REG_H + +/* + * PMIC registers + */ + /* PAGE0 */ +#define DA9055_REG_PAGE_CON 0x00 + +/* System Control and Event Registers */ +#define DA9055_REG_STATUS_A 0x01 +#define DA9055_REG_STATUS_B 0x02 +#define DA9055_REG_FAULT_LOG 0x03 +#define DA9055_REG_EVENT_A 0x04 +#define DA9055_REG_EVENT_B 0x05 +#define DA9055_REG_EVENT_C 0x06 +#define DA9055_REG_IRQ_MASK_A 0x07 +#define DA9055_REG_IRQ_MASK_B 0x08 +#define DA9055_REG_IRQ_MASK_C 0x09 +#define DA9055_REG_CONTROL_A 0x0A +#define DA9055_REG_CONTROL_B 0x0B +#define DA9055_REG_CONTROL_C 0x0C +#define DA9055_REG_CONTROL_D 0x0D +#define DA9055_REG_CONTROL_E 0x0E +#define DA9055_REG_PD_DIS 0x0F + +/* GPIO Control Registers */ +#define DA9055_REG_GPIO0_1 0x10 +#define DA9055_REG_GPIO2 0x11 +#define DA9055_REG_GPIO_MODE0_2 0x12 + +/* Regulator Control Registers */ +#define DA9055_REG_BCORE_CONT 0x13 +#define DA9055_REG_BMEM_CONT 0x14 +#define DA9055_REG_LDO1_CONT 0x15 +#define DA9055_REG_LDO2_CONT 0x16 +#define DA9055_REG_LDO3_CONT 0x17 +#define DA9055_REG_LDO4_CONT 0x18 +#define DA9055_REG_LDO5_CONT 0x19 +#define DA9055_REG_LDO6_CONT 0x1A + +/* GP-ADC Control Registers */ +#define DA9055_REG_ADC_MAN 0x1B +#define DA9055_REG_ADC_CONT 0x1C +#define DA9055_REG_VSYS_MON 0x1D +#define DA9055_REG_ADC_RES_L 0x1E +#define DA9055_REG_ADC_RES_H 0x1F +#define DA9055_REG_VSYS_RES 0x20 +#define DA9055_REG_ADCIN1_RES 0x21 +#define DA9055_REG_ADCIN2_RES 0x22 +#define DA9055_REG_ADCIN3_RES 0x23 + +/* Sequencer Control Registers */ +#define DA9055_REG_EN_32K 0x35 + +/* Regulator Setting Registers */ +#define DA9055_REG_BUCK_LIM 0x37 +#define DA9055_REG_BCORE_MODE 0x38 +#define DA9055_REG_VBCORE_A 0x39 +#define DA9055_REG_VBMEM_A 0x3A +#define DA9055_REG_VLDO1_A 0x3B +#define DA9055_REG_VLDO2_A 0x3C +#define DA9055_REG_VLDO3_A 0x3D +#define DA9055_REG_VLDO4_A 0x3E +#define DA9055_REG_VLDO5_A 0x3F +#define DA9055_REG_VLDO6_A 0x40 +#define DA9055_REG_VBCORE_B 0x41 +#define DA9055_REG_VBMEM_B 0x42 +#define DA9055_REG_VLDO1_B 0x43 +#define DA9055_REG_VLDO2_B 0x44 +#define DA9055_REG_VLDO3_B 0x45 +#define DA9055_REG_VLDO4_B 0x46 +#define DA9055_REG_VLDO5_B 0x47 +#define DA9055_REG_VLDO6_B 0x48 + +/* GP-ADC Threshold Registers */ +#define DA9055_REG_AUTO1_HIGH 0x49 +#define DA9055_REG_AUTO1_LOW 0x4A +#define DA9055_REG_AUTO2_HIGH 0x4B +#define DA9055_REG_AUTO2_LOW 0x4C +#define DA9055_REG_AUTO3_HIGH 0x4D +#define DA9055_REG_AUTO3_LOW 0x4E + +/* OTP */ +#define DA9055_REG_OPT_COUNT 0x50 +#define DA9055_REG_OPT_ADDR 0x51 +#define DA9055_REG_OPT_DATA 0x52 + +/* RTC Calendar and Alarm Registers */ +#define DA9055_REG_COUNT_S 0x53 +#define DA9055_REG_COUNT_MI 0x54 +#define DA9055_REG_COUNT_H 0x55 +#define DA9055_REG_COUNT_D 0x56 +#define DA9055_REG_COUNT_MO 0x57 +#define DA9055_REG_COUNT_Y 0x58 +#define DA9055_REG_ALARM_MI 0x59 +#define DA9055_REG_ALARM_H 0x5A +#define DA9055_REG_ALARM_D 0x5B +#define DA9055_REG_ALARM_MO 0x5C +#define DA9055_REG_ALARM_Y 0x5D +#define DA9055_REG_SECOND_A 0x5E +#define DA9055_REG_SECOND_B 0x5F +#define DA9055_REG_SECOND_C 0x60 +#define DA9055_REG_SECOND_D 0x61 + +/* Customer Trim and Configuration */ +#define DA9055_REG_T_OFFSET 0x63 +#define DA9055_REG_INTERFACE 0x64 +#define DA9055_REG_CONFIG_A 0x65 +#define DA9055_REG_CONFIG_B 0x66 +#define DA9055_REG_CONFIG_C 0x67 +#define DA9055_REG_CONFIG_D 0x68 +#define DA9055_REG_CONFIG_E 0x69 +#define DA9055_REG_TRIM_CLDR 0x6F + +/* General Purpose Registers */ +#define DA9055_REG_GP_ID_0 0x70 +#define DA9055_REG_GP_ID_1 0x71 +#define DA9055_REG_GP_ID_2 0x72 +#define DA9055_REG_GP_ID_3 0x73 +#define DA9055_REG_GP_ID_4 0x74 +#define DA9055_REG_GP_ID_5 0x75 +#define DA9055_REG_GP_ID_6 0x76 +#define DA9055_REG_GP_ID_7 0x77 +#define DA9055_REG_GP_ID_8 0x78 +#define DA9055_REG_GP_ID_9 0x79 +#define DA9055_REG_GP_ID_10 0x7A +#define DA9055_REG_GP_ID_11 0x7B +#define DA9055_REG_GP_ID_12 0x7C +#define DA9055_REG_GP_ID_13 0x7D +#define DA9055_REG_GP_ID_14 0x7E +#define DA9055_REG_GP_ID_15 0x7F +#define DA9055_REG_GP_ID_16 0x80 +#define DA9055_REG_GP_ID_17 0x81 +#define DA9055_REG_GP_ID_18 0x82 +#define DA9055_REG_GP_ID_19 0x83 + +#define DA9055_MAX_REGISTER_CNT DA9055_REG_GP_ID_19 + +/* + * PMIC registers bits + */ + +/* DA9055_REG_PAGE_CON (addr=0x00) */ +#define DA9055_PAGE_WRITE_MODE (0<<6) +#define DA9055_REPEAT_WRITE_MODE (1<<6) + +/* DA9055_REG_STATUS_A (addr=0x01) */ +#define DA9055_NOKEY_STS 0x01 +#define DA9055_WAKE_STS 0x02 +#define DA9055_DVC_BUSY_STS 0x04 +#define DA9055_COMP1V2_STS 0x08 +#define DA9055_NJIG_STS 0x10 +#define DA9055_LDO5_LIM_STS 0x20 +#define DA9055_LDO6_LIM_STS 0x40 + +/* DA9055_REG_STATUS_B (addr=0x02) */ +#define DA9055_GPI0_STS 0x01 +#define DA9055_GPI1_STS 0x02 +#define DA9055_GPI2_STS 0x04 + +/* DA9055_REG_FAULT_LOG (addr=0x03) */ +#define DA9055_TWD_ERROR_FLG 0x01 +#define DA9055_POR_FLG 0x02 +#define DA9055_VDD_FAULT_FLG 0x04 +#define DA9055_VDD_START_FLG 0x08 +#define DA9055_TEMP_CRIT_FLG 0x10 +#define DA9055_KEY_RESET_FLG 0x20 +#define DA9055_WAIT_SHUT_FLG 0x80 + +/* DA9055_REG_EVENT_A (addr=0x04) */ +#define DA9055_NOKEY_EINT 0x01 +#define DA9055_ALARM_EINT 0x02 +#define DA9055_TICK_EINT 0x04 +#define DA9055_ADC_RDY_EINT 0x08 +#define DA9055_SEQ_RDY_EINT 0x10 +#define DA9055_EVENTS_B_EINT 0x20 +#define DA9055_EVENTS_C_EINT 0x40 + +/* DA9055_REG_EVENT_B (addr=0x05) */ +#define DA9055_E_WAKE_EINT 0x01 +#define DA9055_E_TEMP_EINT 0x02 +#define DA9055_E_COMP1V2_EINT 0x04 +#define DA9055_E_LDO_LIM_EINT 0x08 +#define DA9055_E_NJIG_EINT 0x20 +#define DA9055_E_VDD_MON_EINT 0x40 +#define DA9055_E_VDD_WARN_EINT 0x80 + +/* DA9055_REG_EVENT_C (addr=0x06) */ +#define DA9055_E_GPI0_EINT 0x01 +#define DA9055_E_GPI1_EINT 0x02 +#define DA9055_E_GPI2_EINT 0x04 + +/* DA9055_REG_IRQ_MASK_A (addr=0x07) */ +#define DA9055_M_NONKEY_EINT 0x01 +#define DA9055_M_ALARM_EINT 0x02 +#define DA9055_M_TICK_EINT 0x04 +#define DA9055_M_ADC_RDY_EINT 0x08 +#define DA9055_M_SEQ_RDY_EINT 0x10 + +/* DA9055_REG_IRQ_MASK_B (addr=0x08) */ +#define DA9055_M_WAKE_EINT 0x01 +#define DA9055_M_TEMP_EINT 0x02 +#define DA9055_M_COMP_1V2_EINT 0x04 +#define DA9055_M_LDO_LIM_EINT 0x08 +#define DA9055_M_NJIG_EINT 0x20 +#define DA9055_M_VDD_MON_EINT 0x40 +#define DA9055_M_VDD_WARN_EINT 0x80 + +/* DA9055_REG_IRQ_MASK_C (addr=0x09) */ +#define DA9055_M_GPI0_EINT 0x01 +#define DA9055_M_GPI1_EINT 0x02 +#define DA9055_M_GPI2_EINT 0x04 + +/* DA9055_REG_CONTROL_A (addr=0xA) */ +#define DA9055_DEBOUNCING_SHIFT 0x00 +#define DA9055_DEBOUNCING_MASK 0x07 +#define DA9055_NRES_MODE_SHIFT 0x03 +#define DA9055_NRES_MODE_MASK 0x08 +#define DA9055_SLEW_RATE_SHIFT 0x04 +#define DA9055_SLEW_RATE_MASK 0x30 +#define DA9055_NOKEY_LOCK_SHIFT 0x06 +#define DA9055_NOKEY_LOCK_MASK 0x40 + +/* DA9055_REG_CONTROL_B (addr=0xB) */ +#define DA9055_RTC_MODE_PD 0x01 +#define DA9055_RTC_MODE_SD_SHIFT 0x01 +#define DA9055_RTC_MODE_SD 0x02 +#define DA9055_RTC_EN 0x04 +#define DA9055_ECO_MODE_SHIFT 0x03 +#define DA9055_ECO_MODE_MASK 0x08 +#define DA9055_TWDSCALE_SHIFT 4 +#define DA9055_TWDSCALE_MASK 0x70 +#define DA9055_V_LOCK_SHIFT 0x07 +#define DA9055_V_LOCK_MASK 0x80 + +/* DA9055_REG_CONTROL_C (addr=0xC) */ +#define DA9055_SYSTEM_EN_SHIFT 0x00 +#define DA9055_SYSTEM_EN_MASK 0x01 +#define DA9055_POWERN_EN_SHIFT 0x01 +#define DA9055_POWERN_EN_MASK 0x02 +#define DA9055_POWER1_EN_SHIFT 0x02 +#define DA9055_POWER1_EN_MASK 0x04 + +/* DA9055_REG_CONTROL_D (addr=0xD) */ +#define DA9055_STANDBY_SHIFT 0x02 +#define DA9055_STANDBY_MASK 0x08 +#define DA9055_AUTO_BOOT_SHIFT 0x03 +#define DA9055_AUTO_BOOT_MASK 0x04 + +/* DA9055_REG_CONTROL_E (addr=0xE) */ +#define DA9055_WATCHDOG_SHIFT 0x00 +#define DA9055_WATCHDOG_MASK 0x01 +#define DA9055_SHUTDOWN_SHIFT 0x01 +#define DA9055_SHUTDOWN_MASK 0x02 +#define DA9055_WAKE_UP_SHIFT 0x02 +#define DA9055_WAKE_UP_MASK 0x04 + +/* DA9055_REG_GPIO (addr=0x10/0x11) */ +#define DA9055_GPIO0_PIN_SHIFT 0x00 +#define DA9055_GPIO0_PIN_MASK 0x03 +#define DA9055_GPIO0_TYPE_SHIFT 0x02 +#define DA9055_GPIO0_TYPE_MASK 0x04 +#define DA9055_GPIO0_WEN_SHIFT 0x03 +#define DA9055_GPIO0_WEN_MASK 0x08 +#define DA9055_GPIO1_PIN_SHIFT 0x04 +#define DA9055_GPIO1_PIN_MASK 0x30 +#define DA9055_GPIO1_TYPE_SHIFT 0x06 +#define DA9055_GPIO1_TYPE_MASK 0x40 +#define DA9055_GPIO1_WEN_SHIFT 0x07 +#define DA9055_GPIO1_WEN_MASK 0x80 +#define DA9055_GPIO2_PIN_SHIFT 0x00 +#define DA9055_GPIO2_PIN_MASK 0x30 +#define DA9055_GPIO2_TYPE_SHIFT 0x02 +#define DA9055_GPIO2_TYPE_MASK 0x04 +#define DA9055_GPIO2_WEN_SHIFT 0x03 +#define DA9055_GPIO2_WEN_MASK 0x08 + +/* DA9055_REG_GPIO_MODE (addr=0x12) */ +#define DA9055_GPIO0_MODE_SHIFT 0x00 +#define DA9055_GPIO0_MODE_MASK 0x01 +#define DA9055_GPIO1_MODE_SHIFT 0x01 +#define DA9055_GPIO1_MODE_MASK 0x02 +#define DA9055_GPIO2_MODE_SHIFT 0x02 +#define DA9055_GPIO2_MODE_MASK 0x04 + +/* DA9055_REG_BCORE_CONT (addr=0x13) */ +#define DA9055_BCORE_EN_SHIFT 0x00 +#define DA9055_BCORE_EN_MASK 0x01 +#define DA9055_BCORE_GPI_SHIFT 0x01 +#define DA9055_BCORE_GPI_MASK 0x02 +#define DA9055_BCORE_PD_DIS_SHIFT 0x03 +#define DA9055_BCORE_PD_DIS_MASK 0x04 +#define DA9055_VBCORE_SEL_SHIFT 0x04 +#define DA9055_SEL_REG_A 0x0 +#define DA9055_SEL_REG_B 0x10 +#define DA9055_VBCORE_SEL_MASK 0x10 +#define DA9055_V_GPI_MASK 0x60 +#define DA9055_V_GPI_SHIFT 0x05 +#define DA9055_E_GPI_MASK 0x06 +#define DA9055_E_GPI_SHIFT 0x01 +#define DA9055_VBCORE_GPI_SHIFT 0x05 +#define DA9055_VBCORE_GPI_MASK 0x60 +#define DA9055_BCORE_CONF_SHIFT 0x07 +#define DA9055_BCORE_CONF_MASK 0x80 + +/* DA9055_REG_BMEM_CONT (addr=0x14) */ +#define DA9055_BMEM_EN_SHIFT 0x00 +#define DA9055_BMEM_EN_MASK 0x01 +#define DA9055_BMEM_GPI_SHIFT 0x01 +#define DA9055_BMEM_GPI_MASK 0x06 +#define DA9055_BMEM_PD_DIS_SHIFT 0x03 +#define DA9055_BMEM_PD_DIS_MASK 0x08 +#define DA9055_VBMEM_SEL_SHIT 0x04 +#define DA9055_VBMEM_SEL_VBMEM_A (0<<4) +#define DA9055_VBMEM_SEL_VBMEM_B (1<<4) +#define DA9055_VBMEM_SEL_MASK 0x10 +#define DA9055_VBMEM_GPI_SHIFT 0x05 +#define DA9055_VBMEM_GPI_MASK 0x60 +#define DA9055_BMEM_CONF_SHIFT 0x07 +#define DA9055_BMEM_CONF_MASK 0x80 + +/* DA9055_REG_LDO_CONT (addr=0x15-0x1A) */ +#define DA9055_LDO_EN_SHIFT 0x00 +#define DA9055_LDO_EN_MASK 0x01 +#define DA9055_LDO_GPI_SHIFT 0x01 +#define DA9055_LDO_GPI_MASK 0x06 +#define DA9055_LDO_PD_DIS_SHIFT 0x03 +#define DA9055_LDO_PD_DIS_MASK 0x08 +#define DA9055_VLDO_SEL_SHIFT 0x04 +#define DA9055_VLDO_SEL_MASK 0x10 +#define DA9055_VLDO_SEL_VLDO_A 0x00 +#define DA9055_VLDO_SEL_VLDO_B 0x01 +#define DA9055_VLDO_GPI_SHIFT 0x05 +#define DA9055_VLDO_GPI_MASK 0x60 +#define DA9055_LDO_CONF_SHIFT 0x07 +#define DA9055_LDO_CONF_MASK 0x80 +#define DA9055_REGUALTOR_SET_A 0x00 +#define DA9055_REGUALTOR_SET_B 0x10 + +/* DA9055_REG_ADC_MAN (addr=0x1B) */ +#define DA9055_ADC_MUX_SHIFT 0 +#define DA9055_ADC_MUX_MASK 0xF +#define DA9055_ADC_MUX_VSYS 0x0 +#define DA9055_ADC_MUX_ADCIN1 0x01 +#define DA9055_ADC_MUX_ADCIN2 0x02 +#define DA9055_ADC_MUX_ADCIN3 0x03 +#define DA9055_ADC_MUX_T_SENSE 0x04 +#define DA9055_ADC_MAN_SHIFT 0x04 +#define DA9055_ADC_MAN_CONV 0x10 +#define DA9055_ADC_LSB_MASK 0X03 +#define DA9055_ADC_MODE_MASK 0x20 +#define DA9055_ADC_MODE_SHIFT 5 +#define DA9055_ADC_MODE_1MS (1<<5) +#define DA9055_COMP1V2_EN_SHIFT 7 + +/* DA9055_REG_ADC_CONT (addr=0x1C) */ +#define DA9055_ADC_AUTO_VSYS_EN_SHIFT 0 +#define DA9055_ADC_AUTO_AD1_EN_SHIFT 1 +#define DA9055_ADC_AUTO_AD2_EN_SHIFT 2 +#define DA9055_ADC_AUTO_AD3_EN_SHIFT 3 +#define DA9055_ADC_ISRC_EN_SHIFT 4 +#define DA9055_ADC_ADCIN1_DEB_SHIFT 5 +#define DA9055_ADC_ADCIN2_DEB_SHIFT 6 +#define DA9055_ADC_ADCIN3_DEB_SHIFT 7 +#define DA9055_AD1_ISRC_MASK 0x10 +#define DA9055_AD1_ISRC_SHIFT 4 + +/* DA9055_REG_VSYS_MON (addr=0x1D) */ +#define DA9055_VSYS_VAL_SHIFT 0 +#define DA9055_VSYS_VAL_MASK 0xFF +#define DA9055_VSYS_VAL_BASE 0x00 +#define DA9055_VSYS_VAL_MAX DA9055_VSYS_VAL_MASK +#define DA9055_VSYS_VOLT_BASE 2500 +#define DA9055_VSYS_VOLT_INC 10 +#define DA9055_VSYS_STEPS 255 +#define DA9055_VSYS_VOLT_MIN 2500 + +/* DA9044_REG_XXX_RES (addr=0x20-0x23) */ +#define DA9055_ADC_VAL_SHIFT 0 +#define DA9055_ADC_VAL_MASK 0xFF +#define DA9055_ADC_VAL_BASE 0x00 +#define DA9055_ADC_VAL_MAX DA9055_ADC_VAL_MASK +#define DA9055_ADC_VOLT_BASE 0 +#define DA9055_ADC_VSYS_VOLT_BASE 2500 +#define DA9055_ADC_VOLT_INC 10 +#define DA9055_ADC_VSYS_VOLT_INC 12 +#define DA9055_ADC_STEPS 255 + +/* DA9055_REG_EN_32K (addr=0x35)*/ +#define DA9055_STARTUP_TIME_MASK 0x07 +#define DA9055_STARTUP_TIME_0S 0x0 +#define DA9055_STARTUP_TIME_0_52S 0x1 +#define DA9055_STARTUP_TIME_1S 0x2 +#define DA9055_CRYSTAL_EN 0x08 +#define DA9055_DELAY_MODE_EN 0x10 +#define DA9055_OUT_CLCK_GATED 0x20 +#define DA9055_RTC_CLOCK_GATED 0x40 +#define DA9055_EN_32KOUT_BUF 0x80 + +/* DA9055_REG_RESET (addr=0x36) */ +/* Timer up to 31.744 ms */ +#define DA9055_RESET_TIMER_VAL_SHIFT 0 +#define DA9055_RESET_LOW_VAL_MASK 0x3F +#define DA9055_RESET_LOW_VAL_BASE 0 +#define DA9055_RESET_LOW_VAL_MAX DA9055_RESET_LOW_VAL_MASK +#define DA9055_RESET_US_LOW_BASE 1024 /* min val in units of us */ +#define DA9055_RESET_US_LOW_INC 1024 /* inc val in units of us */ +#define DA9055_RESET_US_LOW_STEP 30 + +/* Timer up to 1048.576ms */ +#define DA9055_RESET_HIGH_VAL_MASK 0x3F +#define DA9055_RESET_HIGH_VAL_BASE 0 +#define DA9055_RESET_HIGH_VAL_MAX DA9055_RESET_HIGH_VAL_MASK +#define DA9055_RESET_US_HIGH_BASE 32768 /* min val in units of us */ +#define DA9055_RESET_US_HIGH_INC 32768 /* inv val in units of us */ +#define DA9055_RESET_US_HIGH_STEP 31 + +/* DA9055_REG_BUCK_ILIM (addr=0x37)*/ +#define DA9055_BMEM_ILIM_SHIFT 0 +#define DA9055_ILIM_MASK 0x3 +#define DA9055_ILIM_500MA 0x0 +#define DA9055_ILIM_600MA 0x1 +#define DA9055_ILIM_700MA 0x2 +#define DA9055_ILIM_800MA 0x3 +#define DA9055_BCORE_ILIM_SHIFT 2 + +/* DA9055_REG_BCORE_MODE (addr=0x38) */ +#define DA9055_BMEM_MODE_SHIFT 0 +#define DA9055_MODE_MASK 0x3 +#define DA9055_MODE_AB 0x0 +#define DA9055_MODE_SLEEP 0x1 +#define DA9055_MODE_SYNCHRO 0x2 +#define DA9055_MODE_AUTO 0x3 +#define DA9055_BCORE_MODE_SHIFT 2 + +/* DA9055_REG_VBCORE_A/B (addr=0x39/0x41)*/ +#define DA9055_VBCORE_VAL_SHIFT 0 +#define DA9055_VBCORE_VAL_MASK 0x3F +#define DA9055_VBCORE_VAL_BASE 0x09 +#define DA9055_VBCORE_VAL_MAX DA9055_VBCORE_VAL_MASK +#define DA9055_VBCORE_VOLT_BASE 750 +#define DA9055_VBCORE_VOLT_INC 25 +#define DA9055_VBCORE_STEPS 53 +#define DA9055_VBCORE_VOLT_MIN DA9055_VBCORE_VOLT_BASE +#define DA9055_BCORE_SL_SYNCHRO (0<<7) +#define DA9055_BCORE_SL_SLEEP (1<<7) + +/* DA9055_REG_VBMEM_A/B (addr=0x3A/0x42)*/ +#define DA9055_VBMEM_VAL_SHIFT 0 +#define DA9055_VBMEM_VAL_MASK 0x3F +#define DA9055_VBMEM_VAL_BASE 0x00 +#define DA9055_VBMEM_VAL_MAX DA9055_VBMEM_VAL_MASK +#define DA9055_VBMEM_VOLT_BASE 925 +#define DA9055_VBMEM_VOLT_INC 25 +#define DA9055_VBMEM_STEPS 63 +#define DA9055_VBMEM_VOLT_MIN DA9055_VBMEM_VOLT_BASE +#define DA9055_BCMEM_SL_SYNCHRO (0<<7) +#define DA9055_BCMEM_SL_SLEEP (1<<7) + + +/* DA9055_REG_VLDO (addr=0x3B-0x40/0x43-0x48)*/ +#define DA9055_VLDO_VAL_SHIFT 0 +#define DA9055_VLDO_VAL_MASK 0x3F +#define DA9055_VLDO6_VAL_MASK 0x7F +#define DA9055_VLDO_VAL_BASE 0x02 +#define DA9055_VLDO2_VAL_BASE 0x03 +#define DA9055_VLDO6_VAL_BASE 0x00 +#define DA9055_VLDO_VAL_MAX DA9055_VLDO_VAL_MASK +#define DA9055_VLDO6_VAL_MAX DA9055_VLDO6_VAL_MASK +#define DA9055_VLDO_VOLT_BASE 900 +#define DA9055_VLDO_VOLT_INC 50 +#define DA9055_VLDO6_VOLT_INC 20 +#define DA9055_VLDO_STEPS 48 +#define DA9055_VLDO5_STEPS 37 +#define DA9055_VLDO6_STEPS 120 +#define DA9055_VLDO_VOLT_MIN DA9055_VLDO_VOLT_BASE +#define DA9055_LDO_MODE_SHIFT 7 +#define DA9055_LDO_SL_NORMAL 0 +#define DA9055_LDO_SL_SLEEP 1 + +/* DA9055_REG_OTP_CONT (addr=0x50) */ +#define DA9055_OTP_TIM_NORMAL (0<<0) +#define DA9055_OTP_TIM_MARGINAL (1<<0) +#define DA9055_OTP_GP_RD_SHIFT 1 +#define DA9055_OTP_APPS_RD_SHIFT 2 +#define DA9055_PC_DONE_SHIFT 3 +#define DA9055_OTP_GP_LOCK_SHIFT 4 +#define DA9055_OTP_APPS_LOCK_SHIFT 5 +#define DA9055_OTP_CONF_LOCK_SHIFT 6 +#define DA9055_OTP_WRITE_DIS_SHIFT 7 + +/* DA9055_REG_COUNT_S (addr=0x53) */ +#define DA9055_RTC_SEC 0x3F +#define DA9055_RTC_MONITOR_EN 0x40 +#define DA9055_RTC_READ 0x80 + +/* DA9055_REG_COUNT_MI (addr=0x54) */ +#define DA9055_RTC_MIN 0x3F + +/* DA9055_REG_COUNT_H (addr=0x55) */ +#define DA9055_RTC_HOUR 0x1F + +/* DA9055_REG_COUNT_D (addr=0x56) */ +#define DA9055_RTC_DAY 0x1F + +/* DA9055_REG_COUNT_MO (addr=0x57) */ +#define DA9055_RTC_MONTH 0x0F + +/* DA9055_REG_COUNT_Y (addr=0x58) */ +#define DA9055_RTC_YEAR 0x3F +#define DA9055_RTC_YEAR_BASE 2000 + +/* DA9055_REG_ALARM_MI (addr=0x59) */ +#define DA9055_RTC_ALM_MIN 0x3F +#define DA9055_ALARM_STATUS_SHIFT 6 +#define DA9055_ALARM_STATUS_MASK 0x3 +#define DA9055_ALARM_STATUS_NO_ALARM 0x0 +#define DA9055_ALARM_STATUS_TICK 0x1 +#define DA9055_ALARM_STATUS_TIMER_ALARM 0x2 +#define DA9055_ALARM_STATUS_BOTH 0x3 + +/* DA9055_REG_ALARM_H (addr=0x5A) */ +#define DA9055_RTC_ALM_HOUR 0x1F + +/* DA9055_REG_ALARM_D (addr=0x5B) */ +#define DA9055_RTC_ALM_DAY 0x1F + +/* DA9055_REG_ALARM_MO (addr=0x5C) */ +#define DA9055_RTC_ALM_MONTH 0x0F +#define DA9055_RTC_TICK_WAKE_MASK 0x20 +#define DA9055_RTC_TICK_WAKE_SHIFT 5 +#define DA9055_RTC_TICK_TYPE 0x10 +#define DA9055_RTC_TICK_TYPE_SHIFT 0x4 +#define DA9055_RTC_TICK_SEC 0x0 +#define DA9055_RTC_TICK_MIN 0x1 +#define DA9055_ALARAM_TICK_WAKE 0x20 + +/* DA9055_REG_ALARM_Y (addr=0x5D) */ +#define DA9055_RTC_TICK_EN 0x80 +#define DA9055_RTC_ALM_EN 0x40 +#define DA9055_RTC_TICK_ALM_MASK 0xC0 +#define DA9055_RTC_ALM_YEAR 0x3F + +/* DA9055_REG_TRIM_CLDR (addr=0x62) */ +#define DA9055_TRIM_32K_SHIFT 0 +#define DA9055_TRIM_32K_MASK 0x7F +#define DA9055_TRIM_DECREMENT (1<<7) +#define DA9055_TRIM_INCREMENT (0<<7) +#define DA9055_TRIM_VAL_BASE 0x0 +#define DA9055_TRIM_PPM_BASE 0x0 /* min val in units of 0.1PPM */ +#define DA9055_TRIM_PPM_INC 19 /* min inc in units of 0.1PPM */ +#define DA9055_TRIM_STEPS 127 + +/* DA9055_REG_CONFIG_A (addr=0x65) */ +#define DA9055_PM_I_V_VDDCORE (0<<0) +#define DA9055_PM_I_V_VDD_IO (1<<0) +#define DA9055_VDD_FAULT_TYPE_ACT_LOW (0<<1) +#define DA9055_VDD_FAULT_TYPE_ACT_HIGH (1<<1) +#define DA9055_PM_O_TYPE_PUSH_PULL (0<<2) +#define DA9055_PM_O_TYPE_OPEN_DRAIN (1<<2) +#define DA9055_IRQ_TYPE_ACT_LOW (0<<3) +#define DA9055_IRQ_TYPE_ACT_HIGH (1<<3) +#define DA9055_NIRQ_MODE_IMM (0<<4) +#define DA9055_NIRQ_MODE_ACTIVE (1<<4) +#define DA9055_GPI_V_VDDCORE (0<<5) +#define DA9055_GPI_V_VDD_IO (1<<5) +#define DA9055_PM_IF_V_VDDCORE (0<<6) +#define DA9055_PM_IF_V_VDD_IO (1<<6) + +/* DA9055_REG_CONFIG_B (addr=0x66) */ +#define DA9055_VDD_FAULT_VAL_SHIFT 0 +#define DA9055_VDD_FAULT_VAL_MASK 0xF +#define DA9055_VDD_FAULT_VAL_BASE 0x0 +#define DA9055_VDD_FAULT_VAL_MAX DA9055_VDD_FAULT_VAL_MASK +#define DA9055_VDD_FAULT_VOLT_BASE 2500 +#define DA9055_VDD_FAULT_VOLT_INC 50 +#define DA9055_VDD_FAULT_STEPS 15 + +#define DA9055_VDD_HYST_VAL_SHIFT 4 +#define DA9055_VDD_HYST_VAL_MASK 0x7 +#define DA9055_VDD_HYST_VAL_BASE 0x0 +#define DA9055_VDD_HYST_VAL_MAX DA9055_VDD_HYST_VAL_MASK +#define DA9055_VDD_HYST_VOLT_BASE 100 +#define DA9055_VDD_HYST_VOLT_INC 50 +#define DA9055_VDD_HYST_STEPS 7 +#define DA9055_VDD_HYST_VOLT_MIN DA9055_VDD_HYST_VOLT_BASE + +#define DA9055_VDD_FAULT_EN_SHIFT 7 + +/* DA9055_REG_CONFIG_C (addr=0x67) */ +#define DA9055_BCORE_CLK_INV_SHIFT 0 +#define DA9055_BMEM_CLK_INV_SHIFT 1 +#define DA9055_NFAULT_CONF_SHIFT 2 +#define DA9055_LDO_SD_SHIFT 4 +#define DA9055_LDO5_BYP_SHIFT 6 +#define DA9055_LDO6_BYP_SHIFT 7 + +/* DA9055_REG_CONFIG_D (addr=0x68) */ +#define DA9055_NONKEY_PIN_SHIFT 0 +#define DA9055_NONKEY_PIN_MASK 0x3 +#define DA9055_NONKEY_PIN_PORT_MODE 0x0 +#define DA9055_NONKEY_PIN_KEY_MODE 0x1 +#define DA9055_NONKEY_PIN_MULTI_FUNC 0x2 +#define DA9055_NONKEY_PIN_DEDICT 0x3 +#define DA9055_NONKEY_SD_SHIFT 2 +#define DA9055_KEY_DELAY_SHIFT 3 +#define DA9055_KEY_DELAY_MASK 0x3 +#define DA9055_KEY_DELAY_4S 0x0 +#define DA9055_KEY_DELAY_6S 0x1 +#define DA9055_KEY_DELAY_8S 0x2 +#define DA9055_KEY_DELAY_10S 0x3 + +/* DA9055_REG_CONFIG_E (addr=0x69) */ +#define DA9055_GPIO_PUPD_PULL_UP 0x0 +#define DA9055_GPIO_PUPD_OPEN_DRAIN 0x1 +#define DA9055_GPIO0_PUPD_SHIFT 0 +#define DA9055_GPIO1_PUPD_SHIFT 1 +#define DA9055_GPIO2_PUPD_SHIFT 2 +#define DA9055_UVOV_DELAY_SHIFT 4 +#define DA9055_UVOV_DELAY_MASK 0x3 +#define DA9055_RESET_DURATION_SHIFT 6 +#define DA9055_RESET_DURATION_MASK 0x3 +#define DA9055_RESET_DURATION_0MS 0x0 +#define DA9055_RESET_DURATION_100MS 0x1 +#define DA9055_RESET_DURATION_500MS 0x2 +#define DA9055_RESET_DURATION_1000MS 0x3 + +/* DA9055_REG_MON_REG_1 (addr=0x6A) */ +#define DA9055_MON_THRES_SHIFT 0 +#define DA9055_MON_THRES_MASK 0x3 +#define DA9055_MON_RES_SHIFT 2 +#define DA9055_MON_DEB_SHIFT 3 +#define DA9055_MON_MODE_SHIFT 4 +#define DA9055_MON_MODE_MASK 0x3 +#define DA9055_START_MAX_SHIFT 6 +#define DA9055_START_MAX_MASK 0x3 + +/* DA9055_REG_MON_REG_2 (addr=0x6B) */ +#define DA9055_LDO1_MON_EN_SHIFT 0 +#define DA9055_LDO2_MON_EN_SHIFT 1 +#define DA9055_LDO3_MON_EN_SHIFT 2 +#define DA9055_LDO4_MON_EN_SHIFT 3 +#define DA9055_LDO5_MON_EN_SHIFT 4 +#define DA9055_LDO6_MON_EN_SHIFT 5 +#define DA9055_BCORE_MON_EN_SHIFT 6 +#define DA9055_BMEM_MON_EN_SHIFT 7 + +/* DA9055_REG_CONFIG_F (addr=0x6C) */ +#define DA9055_LDO1_DEF_SHIFT 0 +#define DA9055_LDO2_DEF_SHIFT 1 +#define DA9055_LDO3_DEF_SHIFT 2 +#define DA9055_LDO4_DEF_SHIFT 3 +#define DA9055_LDO5_DEF_SHIFT 4 +#define DA9055_LDO6_DEF_SHIFT 5 +#define DA9055_BCORE_DEF_SHIFT 6 +#define DA9055_BMEM_DEF_SHIFT 7 + +/* DA9055_REG_MON_REG_4 (addr=0x6D) */ +#define DA9055_MON_A8_IDX_SHIFT 0 +#define DA9055_MON_A89_IDX_MASK 0x3 +#define DA9055_MON_A89_IDX_NONE 0x0 +#define DA9055_MON_A89_IDX_BUCKCORE 0x1 +#define DA9055_MON_A89_IDX_LDO3 0x2 +#define DA9055_MON_A9_IDX_SHIFT 5 + +/* DA9055_REG_MON_REG_5 (addr=0x6E) */ +#define DA9055_MON_A10_IDX_SHIFT 0 +#define DA9055_MON_A10_IDX_MASK 0x3 +#define DA9055_MON_A10_IDX_NONE 0x0 +#define DA9055_MON_A10_IDX_LDO1 0x1 +#define DA9055_MON_A10_IDX_LDO2 0x2 +#define DA9055_MON_A10_IDX_LDO5 0x3 +#define DA9055_MON_A10_IDX_LDO6 0x4 + +#endif /* __DA9055_REG_H */ diff --git a/include/linux/mfd/lp8788-isink.h b/include/linux/mfd/lp8788-isink.h new file mode 100644 index 000000000000..f38262d21ff1 --- /dev/null +++ b/include/linux/mfd/lp8788-isink.h @@ -0,0 +1,52 @@ +/* + * TI LP8788 MFD - common definitions for current sinks + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * 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. + * + */ + +#ifndef __ISINK_LP8788_H__ +#define __ISINK_LP8788_H__ + +/* register address */ +#define LP8788_ISINK_CTRL 0x99 +#define LP8788_ISINK12_IOUT 0x9A +#define LP8788_ISINK3_IOUT 0x9B +#define LP8788_ISINK1_PWM 0x9C +#define LP8788_ISINK2_PWM 0x9D +#define LP8788_ISINK3_PWM 0x9E + +/* mask bits */ +#define LP8788_ISINK1_IOUT_M 0x0F /* Addr 9Ah */ +#define LP8788_ISINK2_IOUT_M 0xF0 +#define LP8788_ISINK3_IOUT_M 0x0F /* Addr 9Bh */ + +/* 6 bits used for PWM code : Addr 9C ~ 9Eh */ +#define LP8788_ISINK_MAX_PWM 63 +#define LP8788_ISINK_SCALE_OFFSET 3 + +static const u8 lp8788_iout_addr[] = { + LP8788_ISINK12_IOUT, + LP8788_ISINK12_IOUT, + LP8788_ISINK3_IOUT, +}; + +static const u8 lp8788_iout_mask[] = { + LP8788_ISINK1_IOUT_M, + LP8788_ISINK2_IOUT_M, + LP8788_ISINK3_IOUT_M, +}; + +static const u8 lp8788_pwm_addr[] = { + LP8788_ISINK1_PWM, + LP8788_ISINK2_PWM, + LP8788_ISINK3_PWM, +}; + +#endif diff --git a/include/linux/mfd/lp8788.h b/include/linux/mfd/lp8788.h new file mode 100644 index 000000000000..cec364bdccfa --- /dev/null +++ b/include/linux/mfd/lp8788.h @@ -0,0 +1,364 @@ +/* + * TI LP8788 MFD Device + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * 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. + * + */ + +#ifndef __MFD_LP8788_H__ +#define __MFD_LP8788_H__ + +#include <linux/gpio.h> +#include <linux/irqdomain.h> +#include <linux/regmap.h> + +#define LP8788_DEV_BUCK "lp8788-buck" +#define LP8788_DEV_DLDO "lp8788-dldo" +#define LP8788_DEV_ALDO "lp8788-aldo" +#define LP8788_DEV_CHARGER "lp8788-charger" +#define LP8788_DEV_RTC "lp8788-rtc" +#define LP8788_DEV_BACKLIGHT "lp8788-backlight" +#define LP8788_DEV_VIBRATOR "lp8788-vibrator" +#define LP8788_DEV_KEYLED "lp8788-keyled" +#define LP8788_DEV_ADC "lp8788-adc" + +#define LP8788_NUM_BUCKS 4 +#define LP8788_NUM_DLDOS 12 +#define LP8788_NUM_ALDOS 10 +#define LP8788_NUM_BUCK2_DVS 2 + +#define LP8788_CHG_IRQ "CHG_IRQ" +#define LP8788_PRSW_IRQ "PRSW_IRQ" +#define LP8788_BATT_IRQ "BATT_IRQ" +#define LP8788_ALM_IRQ "ALARM_IRQ" + +enum lp8788_int_id { + /* interrup register 1 : Addr 00h */ + LP8788_INT_TSDL, + LP8788_INT_TSDH, + LP8788_INT_UVLO, + LP8788_INT_FLAGMON, + LP8788_INT_PWRON_TIME, + LP8788_INT_PWRON, + LP8788_INT_COMP1, + LP8788_INT_COMP2, + + /* interrupt register 2 : Addr 01h */ + LP8788_INT_CHG_INPUT_STATE, + LP8788_INT_CHG_STATE, + LP8788_INT_EOC, + LP8788_INT_CHG_RESTART, + LP8788_INT_RESTART_TIMEOUT, + LP8788_INT_FULLCHG_TIMEOUT, + LP8788_INT_PRECHG_TIMEOUT, + + /* interrupt register 3 : Addr 02h */ + LP8788_INT_RTC_ALARM1 = 17, + LP8788_INT_RTC_ALARM2, + LP8788_INT_ENTER_SYS_SUPPORT, + LP8788_INT_EXIT_SYS_SUPPORT, + LP8788_INT_BATT_LOW, + LP8788_INT_NO_BATT, + + LP8788_INT_MAX = 24, +}; + +enum lp8788_dvs_sel { + DVS_SEL_V0, + DVS_SEL_V1, + DVS_SEL_V2, + DVS_SEL_V3, +}; + +enum lp8788_ext_ldo_en_id { + EN_ALDO1, + EN_ALDO234, + EN_ALDO5, + EN_ALDO7, + EN_DLDO7, + EN_DLDO911, + EN_LDOS_MAX, +}; + +enum lp8788_charger_event { + NO_CHARGER, + CHARGER_DETECTED, +}; + +enum lp8788_bl_ctrl_mode { + LP8788_BL_REGISTER_ONLY, + LP8788_BL_COMB_PWM_BASED, /* PWM + I2C, changed by PWM input */ + LP8788_BL_COMB_REGISTER_BASED, /* PWM + I2C, changed by I2C */ +}; + +enum lp8788_bl_dim_mode { + LP8788_DIM_EXPONENTIAL, + LP8788_DIM_LINEAR, +}; + +enum lp8788_bl_full_scale_current { + LP8788_FULLSCALE_5000uA, + LP8788_FULLSCALE_8500uA, + LP8788_FULLSCALE_1200uA, + LP8788_FULLSCALE_1550uA, + LP8788_FULLSCALE_1900uA, + LP8788_FULLSCALE_2250uA, + LP8788_FULLSCALE_2600uA, + LP8788_FULLSCALE_2950uA, +}; + +enum lp8788_bl_ramp_step { + LP8788_RAMP_8us, + LP8788_RAMP_1024us, + LP8788_RAMP_2048us, + LP8788_RAMP_4096us, + LP8788_RAMP_8192us, + LP8788_RAMP_16384us, + LP8788_RAMP_32768us, + LP8788_RAMP_65538us, +}; + +enum lp8788_bl_pwm_polarity { + LP8788_PWM_ACTIVE_HIGH, + LP8788_PWM_ACTIVE_LOW, +}; + +enum lp8788_isink_scale { + LP8788_ISINK_SCALE_100mA, + LP8788_ISINK_SCALE_120mA, +}; + +enum lp8788_isink_number { + LP8788_ISINK_1, + LP8788_ISINK_2, + LP8788_ISINK_3, +}; + +enum lp8788_alarm_sel { + LP8788_ALARM_1, + LP8788_ALARM_2, + LP8788_ALARM_MAX, +}; + +enum lp8788_adc_id { + LPADC_VBATT_5P5, + LPADC_VIN_CHG, + LPADC_IBATT, + LPADC_IC_TEMP, + LPADC_VBATT_6P0, + LPADC_VBATT_5P0, + LPADC_ADC1, + LPADC_ADC2, + LPADC_VDD, + LPADC_VCOIN, + LPADC_VDD_LDO, + LPADC_ADC3, + LPADC_ADC4, + LPADC_MAX, +}; + +struct lp8788; + +/* + * lp8788_buck1_dvs + * @gpio : gpio pin number for dvs control + * @vsel : dvs selector for buck v1 register + */ +struct lp8788_buck1_dvs { + int gpio; + enum lp8788_dvs_sel vsel; +}; + +/* + * lp8788_buck2_dvs + * @gpio : two gpio pin numbers are used for dvs + * @vsel : dvs selector for buck v2 register + */ +struct lp8788_buck2_dvs { + int gpio[LP8788_NUM_BUCK2_DVS]; + enum lp8788_dvs_sel vsel; +}; + +/* + * struct lp8788_ldo_enable_pin + * + * Basically, all LDOs are enabled through the I2C commands. + * But ALDO 1 ~ 5, 7, DLDO 7, 9, 11 can be enabled by external gpio pins. + * + * @gpio : gpio number which is used for enabling ldos + * @init_state : initial gpio state (ex. GPIOF_OUT_INIT_LOW) + */ +struct lp8788_ldo_enable_pin { + int gpio; + int init_state; +}; + +/* + * struct lp8788_chg_param + * @addr : charging control register address (range : 0x11 ~ 0x1C) + * @val : charging parameter value + */ +struct lp8788_chg_param { + u8 addr; + u8 val; +}; + +/* + * struct lp8788_charger_platform_data + * @vbatt_adc : adc selection id for battery voltage + * @batt_temp_adc : adc selection id for battery temperature + * @max_vbatt_mv : used for calculating battery capacity + * @chg_params : initial charging parameters + * @num_chg_params : numbers of charging parameters + * @charger_event : the charger event can be reported to the platform side + */ +struct lp8788_charger_platform_data { + enum lp8788_adc_id vbatt_adc; + enum lp8788_adc_id batt_temp_adc; + unsigned int max_vbatt_mv; + struct lp8788_chg_param *chg_params; + int num_chg_params; + void (*charger_event) (struct lp8788 *lp, + enum lp8788_charger_event event); +}; + +/* + * struct lp8788_bl_pwm_data + * @pwm_set_intensity : set duty of pwm + * @pwm_get_intensity : get current duty of pwm + */ +struct lp8788_bl_pwm_data { + void (*pwm_set_intensity) (int brightness, int max_brightness); + int (*pwm_get_intensity) (int max_brightness); +}; + +/* + * struct lp8788_backlight_platform_data + * @name : backlight driver name. (default: "lcd-backlight") + * @initial_brightness : initial value of backlight brightness + * @bl_mode : brightness control by pwm or lp8788 register + * @dim_mode : dimming mode selection + * @full_scale : full scale current setting + * @rise_time : brightness ramp up step time + * @fall_time : brightness ramp down step time + * @pwm_pol : pwm polarity setting when bl_mode is pwm based + * @pwm_data : platform specific pwm generation functions + * only valid when bl_mode is pwm based + */ +struct lp8788_backlight_platform_data { + char *name; + int initial_brightness; + enum lp8788_bl_ctrl_mode bl_mode; + enum lp8788_bl_dim_mode dim_mode; + enum lp8788_bl_full_scale_current full_scale; + enum lp8788_bl_ramp_step rise_time; + enum lp8788_bl_ramp_step fall_time; + enum lp8788_bl_pwm_polarity pwm_pol; + struct lp8788_bl_pwm_data pwm_data; +}; + +/* + * struct lp8788_led_platform_data + * @name : led driver name. (default: "keyboard-backlight") + * @scale : current scale + * @num : current sink number + * @iout_code : current output value (Addr 9Ah ~ 9Bh) + */ +struct lp8788_led_platform_data { + char *name; + enum lp8788_isink_scale scale; + enum lp8788_isink_number num; + int iout_code; +}; + +/* + * struct lp8788_vib_platform_data + * @name : vibrator driver name + * @scale : current scale + * @num : current sink number + * @iout_code : current output value (Addr 9Ah ~ 9Bh) + * @pwm_code : PWM code value (Addr 9Ch ~ 9Eh) + */ +struct lp8788_vib_platform_data { + char *name; + enum lp8788_isink_scale scale; + enum lp8788_isink_number num; + int iout_code; + int pwm_code; +}; + +/* + * struct lp8788_platform_data + * @init_func : used for initializing registers + * before mfd driver is registered + * @buck_data : regulator initial data for buck + * @dldo_data : regulator initial data for digital ldo + * @aldo_data : regulator initial data for analog ldo + * @buck1_dvs : gpio configurations for buck1 dvs + * @buck2_dvs : gpio configurations for buck2 dvs + * @ldo_pin : gpio configurations for enabling LDOs + * @chg_pdata : platform data for charger driver + * @alarm_sel : rtc alarm selection (1 or 2) + * @bl_pdata : configurable data for backlight driver + * @led_pdata : configurable data for led driver + * @vib_pdata : configurable data for vibrator driver + * @adc_pdata : iio map data for adc driver + */ +struct lp8788_platform_data { + /* general system information */ + int (*init_func) (struct lp8788 *lp); + + /* regulators */ + struct regulator_init_data *buck_data[LP8788_NUM_BUCKS]; + struct regulator_init_data *dldo_data[LP8788_NUM_DLDOS]; + struct regulator_init_data *aldo_data[LP8788_NUM_ALDOS]; + struct lp8788_buck1_dvs *buck1_dvs; + struct lp8788_buck2_dvs *buck2_dvs; + struct lp8788_ldo_enable_pin *ldo_pin[EN_LDOS_MAX]; + + /* charger */ + struct lp8788_charger_platform_data *chg_pdata; + + /* rtc alarm */ + enum lp8788_alarm_sel alarm_sel; + + /* backlight */ + struct lp8788_backlight_platform_data *bl_pdata; + + /* current sinks */ + struct lp8788_led_platform_data *led_pdata; + struct lp8788_vib_platform_data *vib_pdata; + + /* adc iio map data */ + struct iio_map *adc_pdata; +}; + +/* + * struct lp8788 + * @dev : parent device pointer + * @regmap : used for i2c communcation on accessing registers + * @irqdm : interrupt domain for handling nested interrupt + * @irq : pin number of IRQ_N + * @pdata : lp8788 platform specific data + */ +struct lp8788 { + struct device *dev; + struct regmap *regmap; + struct irq_domain *irqdm; + int irq; + struct lp8788_platform_data *pdata; +}; + +int lp8788_irq_init(struct lp8788 *lp, int chip_irq); +void lp8788_irq_exit(struct lp8788 *lp); +int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data); +int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count); +int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data); +int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data); +#endif diff --git a/include/linux/mfd/lpc_ich.h b/include/linux/mfd/lpc_ich.h index fec5256c3f5d..3e1df644c407 100644 --- a/include/linux/mfd/lpc_ich.h +++ b/include/linux/mfd/lpc_ich.h @@ -43,6 +43,7 @@ struct lpc_ich_info { char name[32]; unsigned int iTCO_version; unsigned int gpio_version; + u8 use_gpio; }; #endif diff --git a/include/linux/mfd/max8907.h b/include/linux/mfd/max8907.h new file mode 100644 index 000000000000..b06f7a6a1e80 --- /dev/null +++ b/include/linux/mfd/max8907.h @@ -0,0 +1,252 @@ +/* + * Functions to access MAX8907 power management chip. + * + * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com> + * Copyright (C) 2012, NVIDIA CORPORATION. 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 version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MFD_MAX8907_H +#define __LINUX_MFD_MAX8907_H + +#include <linux/mutex.h> +#include <linux/pm.h> + +#define MAX8907_GEN_I2C_ADDR (0x78 >> 1) +#define MAX8907_ADC_I2C_ADDR (0x8e >> 1) +#define MAX8907_RTC_I2C_ADDR (0xd0 >> 1) + +/* MAX8907 register map */ +#define MAX8907_REG_SYSENSEL 0x00 +#define MAX8907_REG_ON_OFF_IRQ1 0x01 +#define MAX8907_REG_ON_OFF_IRQ1_MASK 0x02 +#define MAX8907_REG_ON_OFF_STAT 0x03 +#define MAX8907_REG_SDCTL1 0x04 +#define MAX8907_REG_SDSEQCNT1 0x05 +#define MAX8907_REG_SDV1 0x06 +#define MAX8907_REG_SDCTL2 0x07 +#define MAX8907_REG_SDSEQCNT2 0x08 +#define MAX8907_REG_SDV2 0x09 +#define MAX8907_REG_SDCTL3 0x0A +#define MAX8907_REG_SDSEQCNT3 0x0B +#define MAX8907_REG_SDV3 0x0C +#define MAX8907_REG_ON_OFF_IRQ2 0x0D +#define MAX8907_REG_ON_OFF_IRQ2_MASK 0x0E +#define MAX8907_REG_RESET_CNFG 0x0F +#define MAX8907_REG_LDOCTL16 0x10 +#define MAX8907_REG_LDOSEQCNT16 0x11 +#define MAX8907_REG_LDO16VOUT 0x12 +#define MAX8907_REG_SDBYSEQCNT 0x13 +#define MAX8907_REG_LDOCTL17 0x14 +#define MAX8907_REG_LDOSEQCNT17 0x15 +#define MAX8907_REG_LDO17VOUT 0x16 +#define MAX8907_REG_LDOCTL1 0x18 +#define MAX8907_REG_LDOSEQCNT1 0x19 +#define MAX8907_REG_LDO1VOUT 0x1A +#define MAX8907_REG_LDOCTL2 0x1C +#define MAX8907_REG_LDOSEQCNT2 0x1D +#define MAX8907_REG_LDO2VOUT 0x1E +#define MAX8907_REG_LDOCTL3 0x20 +#define MAX8907_REG_LDOSEQCNT3 0x21 +#define MAX8907_REG_LDO3VOUT 0x22 +#define MAX8907_REG_LDOCTL4 0x24 +#define MAX8907_REG_LDOSEQCNT4 0x25 +#define MAX8907_REG_LDO4VOUT 0x26 +#define MAX8907_REG_LDOCTL5 0x28 +#define MAX8907_REG_LDOSEQCNT5 0x29 +#define MAX8907_REG_LDO5VOUT 0x2A +#define MAX8907_REG_LDOCTL6 0x2C +#define MAX8907_REG_LDOSEQCNT6 0x2D +#define MAX8907_REG_LDO6VOUT 0x2E +#define MAX8907_REG_LDOCTL7 0x30 +#define MAX8907_REG_LDOSEQCNT7 0x31 +#define MAX8907_REG_LDO7VOUT 0x32 +#define MAX8907_REG_LDOCTL8 0x34 +#define MAX8907_REG_LDOSEQCNT8 0x35 +#define MAX8907_REG_LDO8VOUT 0x36 +#define MAX8907_REG_LDOCTL9 0x38 +#define MAX8907_REG_LDOSEQCNT9 0x39 +#define MAX8907_REG_LDO9VOUT 0x3A +#define MAX8907_REG_LDOCTL10 0x3C +#define MAX8907_REG_LDOSEQCNT10 0x3D +#define MAX8907_REG_LDO10VOUT 0x3E +#define MAX8907_REG_LDOCTL11 0x40 +#define MAX8907_REG_LDOSEQCNT11 0x41 +#define MAX8907_REG_LDO11VOUT 0x42 +#define MAX8907_REG_LDOCTL12 0x44 +#define MAX8907_REG_LDOSEQCNT12 0x45 +#define MAX8907_REG_LDO12VOUT 0x46 +#define MAX8907_REG_LDOCTL13 0x48 +#define MAX8907_REG_LDOSEQCNT13 0x49 +#define MAX8907_REG_LDO13VOUT 0x4A +#define MAX8907_REG_LDOCTL14 0x4C +#define MAX8907_REG_LDOSEQCNT14 0x4D +#define MAX8907_REG_LDO14VOUT 0x4E +#define MAX8907_REG_LDOCTL15 0x50 +#define MAX8907_REG_LDOSEQCNT15 0x51 +#define MAX8907_REG_LDO15VOUT 0x52 +#define MAX8907_REG_OUT5VEN 0x54 +#define MAX8907_REG_OUT5VSEQ 0x55 +#define MAX8907_REG_OUT33VEN 0x58 +#define MAX8907_REG_OUT33VSEQ 0x59 +#define MAX8907_REG_LDOCTL19 0x5C +#define MAX8907_REG_LDOSEQCNT19 0x5D +#define MAX8907_REG_LDO19VOUT 0x5E +#define MAX8907_REG_LBCNFG 0x60 +#define MAX8907_REG_SEQ1CNFG 0x64 +#define MAX8907_REG_SEQ2CNFG 0x65 +#define MAX8907_REG_SEQ3CNFG 0x66 +#define MAX8907_REG_SEQ4CNFG 0x67 +#define MAX8907_REG_SEQ5CNFG 0x68 +#define MAX8907_REG_SEQ6CNFG 0x69 +#define MAX8907_REG_SEQ7CNFG 0x6A +#define MAX8907_REG_LDOCTL18 0x72 +#define MAX8907_REG_LDOSEQCNT18 0x73 +#define MAX8907_REG_LDO18VOUT 0x74 +#define MAX8907_REG_BBAT_CNFG 0x78 +#define MAX8907_REG_CHG_CNTL1 0x7C +#define MAX8907_REG_CHG_CNTL2 0x7D +#define MAX8907_REG_CHG_IRQ1 0x7E +#define MAX8907_REG_CHG_IRQ2 0x7F +#define MAX8907_REG_CHG_IRQ1_MASK 0x80 +#define MAX8907_REG_CHG_IRQ2_MASK 0x81 +#define MAX8907_REG_CHG_STAT 0x82 +#define MAX8907_REG_WLED_MODE_CNTL 0x84 +#define MAX8907_REG_ILED_CNTL 0x84 +#define MAX8907_REG_II1RR 0x8E +#define MAX8907_REG_II2RR 0x8F +#define MAX8907_REG_LDOCTL20 0x9C +#define MAX8907_REG_LDOSEQCNT20 0x9D +#define MAX8907_REG_LDO20VOUT 0x9E + +/* RTC register map */ +#define MAX8907_REG_RTC_SEC 0x00 +#define MAX8907_REG_RTC_MIN 0x01 +#define MAX8907_REG_RTC_HOURS 0x02 +#define MAX8907_REG_RTC_WEEKDAY 0x03 +#define MAX8907_REG_RTC_DATE 0x04 +#define MAX8907_REG_RTC_MONTH 0x05 +#define MAX8907_REG_RTC_YEAR1 0x06 +#define MAX8907_REG_RTC_YEAR2 0x07 +#define MAX8907_REG_ALARM0_SEC 0x08 +#define MAX8907_REG_ALARM0_MIN 0x09 +#define MAX8907_REG_ALARM0_HOURS 0x0A +#define MAX8907_REG_ALARM0_WEEKDAY 0x0B +#define MAX8907_REG_ALARM0_DATE 0x0C +#define MAX8907_REG_ALARM0_MONTH 0x0D +#define MAX8907_REG_ALARM0_YEAR1 0x0E +#define MAX8907_REG_ALARM0_YEAR2 0x0F +#define MAX8907_REG_ALARM1_SEC 0x10 +#define MAX8907_REG_ALARM1_MIN 0x11 +#define MAX8907_REG_ALARM1_HOURS 0x12 +#define MAX8907_REG_ALARM1_WEEKDAY 0x13 +#define MAX8907_REG_ALARM1_DATE 0x14 +#define MAX8907_REG_ALARM1_MONTH 0x15 +#define MAX8907_REG_ALARM1_YEAR1 0x16 +#define MAX8907_REG_ALARM1_YEAR2 0x17 +#define MAX8907_REG_ALARM0_CNTL 0x18 +#define MAX8907_REG_ALARM1_CNTL 0x19 +#define MAX8907_REG_RTC_STATUS 0x1A +#define MAX8907_REG_RTC_CNTL 0x1B +#define MAX8907_REG_RTC_IRQ 0x1C +#define MAX8907_REG_RTC_IRQ_MASK 0x1D +#define MAX8907_REG_MPL_CNTL 0x1E + +/* ADC and Touch Screen Controller register map */ +#define MAX8907_CTL 0 +#define MAX8907_SEQCNT 1 +#define MAX8907_VOUT 2 + +/* mask bit fields */ +#define MAX8907_MASK_LDO_SEQ 0x1C +#define MAX8907_MASK_LDO_EN 0x01 +#define MAX8907_MASK_VBBATTCV 0x03 +#define MAX8907_MASK_OUT5V_VINEN 0x10 +#define MAX8907_MASK_OUT5V_ENSRC 0x0E +#define MAX8907_MASK_OUT5V_EN 0x01 +#define MAX8907_MASK_POWER_OFF 0x40 + +/* Regulator IDs */ +#define MAX8907_MBATT 0 +#define MAX8907_SD1 1 +#define MAX8907_SD2 2 +#define MAX8907_SD3 3 +#define MAX8907_LDO1 4 +#define MAX8907_LDO2 5 +#define MAX8907_LDO3 6 +#define MAX8907_LDO4 7 +#define MAX8907_LDO5 8 +#define MAX8907_LDO6 9 +#define MAX8907_LDO7 10 +#define MAX8907_LDO8 11 +#define MAX8907_LDO9 12 +#define MAX8907_LDO10 13 +#define MAX8907_LDO11 14 +#define MAX8907_LDO12 15 +#define MAX8907_LDO13 16 +#define MAX8907_LDO14 17 +#define MAX8907_LDO15 18 +#define MAX8907_LDO16 19 +#define MAX8907_LDO17 20 +#define MAX8907_LDO18 21 +#define MAX8907_LDO19 22 +#define MAX8907_LDO20 23 +#define MAX8907_OUT5V 24 +#define MAX8907_OUT33V 25 +#define MAX8907_BBAT 26 +#define MAX8907_SDBY 27 +#define MAX8907_VRTC 28 +#define MAX8907_NUM_REGULATORS (MAX8907_VRTC + 1) + +/* IRQ definitions */ +enum { + MAX8907_IRQ_VCHG_DC_OVP = 0, + MAX8907_IRQ_VCHG_DC_F, + MAX8907_IRQ_VCHG_DC_R, + MAX8907_IRQ_VCHG_THM_OK_R, + MAX8907_IRQ_VCHG_THM_OK_F, + MAX8907_IRQ_VCHG_MBATTLOW_F, + MAX8907_IRQ_VCHG_MBATTLOW_R, + MAX8907_IRQ_VCHG_RST, + MAX8907_IRQ_VCHG_DONE, + MAX8907_IRQ_VCHG_TOPOFF, + MAX8907_IRQ_VCHG_TMR_FAULT, + + MAX8907_IRQ_GPM_RSTIN = 0, + MAX8907_IRQ_GPM_MPL, + MAX8907_IRQ_GPM_SW_3SEC, + MAX8907_IRQ_GPM_EXTON_F, + MAX8907_IRQ_GPM_EXTON_R, + MAX8907_IRQ_GPM_SW_1SEC, + MAX8907_IRQ_GPM_SW_F, + MAX8907_IRQ_GPM_SW_R, + MAX8907_IRQ_GPM_SYSCKEN_F, + MAX8907_IRQ_GPM_SYSCKEN_R, + + MAX8907_IRQ_RTC_ALARM1 = 0, + MAX8907_IRQ_RTC_ALARM0, +}; + +struct max8907_platform_data { + struct regulator_init_data *init_data[MAX8907_NUM_REGULATORS]; + bool pm_off; +}; + +struct regmap_irq_chips_data; + +struct max8907 { + struct device *dev; + struct mutex irq_lock; + struct i2c_client *i2c_gen; + struct i2c_client *i2c_rtc; + struct regmap *regmap_gen; + struct regmap *regmap_rtc; + struct regmap_irq_chip_data *irqc_chg; + struct regmap_irq_chip_data *irqc_on_off; + struct regmap_irq_chip_data *irqc_rtc; +}; + +#endif diff --git a/include/linux/mfd/max8925.h b/include/linux/mfd/max8925.h index 15b2392a56fb..74d8e2969630 100644 --- a/include/linux/mfd/max8925.h +++ b/include/linux/mfd/max8925.h @@ -158,8 +158,6 @@ enum { #define TSC_IRQ_MASK (0x03) #define RTC_IRQ_MASK (0x0c) -#define MAX8925_MAX_REGULATOR (23) - #define MAX8925_NAME_SIZE (32) /* IRQ definitions */ @@ -236,7 +234,29 @@ struct max8925_platform_data { struct max8925_backlight_pdata *backlight; struct max8925_touch_pdata *touch; struct max8925_power_pdata *power; - struct regulator_init_data *regulator[MAX8925_MAX_REGULATOR]; + struct regulator_init_data *sd1; + struct regulator_init_data *sd2; + struct regulator_init_data *sd3; + struct regulator_init_data *ldo1; + struct regulator_init_data *ldo2; + struct regulator_init_data *ldo3; + struct regulator_init_data *ldo4; + struct regulator_init_data *ldo5; + struct regulator_init_data *ldo6; + struct regulator_init_data *ldo7; + struct regulator_init_data *ldo8; + struct regulator_init_data *ldo9; + struct regulator_init_data *ldo10; + struct regulator_init_data *ldo11; + struct regulator_init_data *ldo12; + struct regulator_init_data *ldo13; + struct regulator_init_data *ldo14; + struct regulator_init_data *ldo15; + struct regulator_init_data *ldo16; + struct regulator_init_data *ldo17; + struct regulator_init_data *ldo18; + struct regulator_init_data *ldo19; + struct regulator_init_data *ldo20; int irq_base; int tsc_irq; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 9cbc642d40ad..29f6616e12f0 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -23,6 +23,9 @@ #define PALMAS_NUM_CLIENTS 3 struct palmas_pmic; +struct palmas_gpadc; +struct palmas_resource; +struct palmas_usb; struct palmas { struct device *dev; @@ -41,6 +44,9 @@ struct palmas { /* Child Devices */ struct palmas_pmic *pmic; + struct palmas_gpadc *gpadc; + struct palmas_resource *resource; + struct palmas_usb *usb; /* GPIO MUXing */ u8 gpio_muxed; @@ -48,6 +54,23 @@ struct palmas { u8 pwm_muxed; }; +struct palmas_gpadc_platform_data { + /* Channel 3 current source is only enabled during conversion */ + int ch3_current; + + /* Channel 0 current source can be used for battery detection. + * If used for battery detection this will cause a permanent current + * consumption depending on current level set here. + */ + int ch0_current; + + /* default BAT_REMOVAL_DAT setting on device probe */ + int bat_removal; + + /* Sets the START_POLARITY bit in the RT_CTRL register */ + int start_polarity; +}; + struct palmas_reg_init { /* warm_rest controls the voltage levels after a warm reset * @@ -107,21 +130,94 @@ struct palmas_reg_init { }; +enum palmas_regulators { + /* SMPS regulators */ + PALMAS_REG_SMPS12, + PALMAS_REG_SMPS123, + PALMAS_REG_SMPS3, + PALMAS_REG_SMPS45, + PALMAS_REG_SMPS457, + PALMAS_REG_SMPS6, + PALMAS_REG_SMPS7, + PALMAS_REG_SMPS8, + PALMAS_REG_SMPS9, + PALMAS_REG_SMPS10, + /* LDO regulators */ + PALMAS_REG_LDO1, + PALMAS_REG_LDO2, + PALMAS_REG_LDO3, + PALMAS_REG_LDO4, + PALMAS_REG_LDO5, + PALMAS_REG_LDO6, + PALMAS_REG_LDO7, + PALMAS_REG_LDO8, + PALMAS_REG_LDO9, + PALMAS_REG_LDOLN, + PALMAS_REG_LDOUSB, + /* Total number of regulators */ + PALMAS_NUM_REGS, +}; + struct palmas_pmic_platform_data { /* An array of pointers to regulator init data indexed by regulator * ID */ - struct regulator_init_data **reg_data; + struct regulator_init_data *reg_data[PALMAS_NUM_REGS]; /* An array of pointers to structures containing sleep mode and DVS * configuration for regulators indexed by ID */ - struct palmas_reg_init **reg_init; + struct palmas_reg_init *reg_init[PALMAS_NUM_REGS]; /* use LDO6 for vibrator control */ int ldo6_vibrator; +}; +struct palmas_usb_platform_data { + /* Set this if platform wishes its own vbus control */ + int no_control_vbus; + /* Do we enable the wakeup comparator on probe */ + int wakeup; +}; + +struct palmas_resource_platform_data { + int regen1_mode_sleep; + int regen2_mode_sleep; + int sysen1_mode_sleep; + int sysen2_mode_sleep; + + /* bitfield to be loaded to NSLEEP_RES_ASSIGN */ + u8 nsleep_res; + /* bitfield to be loaded to NSLEEP_SMPS_ASSIGN */ + u8 nsleep_smps; + /* bitfield to be loaded to NSLEEP_LDO_ASSIGN1 */ + u8 nsleep_ldo1; + /* bitfield to be loaded to NSLEEP_LDO_ASSIGN2 */ + u8 nsleep_ldo2; + + /* bitfield to be loaded to ENABLE1_RES_ASSIGN */ + u8 enable1_res; + /* bitfield to be loaded to ENABLE1_SMPS_ASSIGN */ + u8 enable1_smps; + /* bitfield to be loaded to ENABLE1_LDO_ASSIGN1 */ + u8 enable1_ldo1; + /* bitfield to be loaded to ENABLE1_LDO_ASSIGN2 */ + u8 enable1_ldo2; + + /* bitfield to be loaded to ENABLE2_RES_ASSIGN */ + u8 enable2_res; + /* bitfield to be loaded to ENABLE2_SMPS_ASSIGN */ + u8 enable2_smps; + /* bitfield to be loaded to ENABLE2_LDO_ASSIGN1 */ + u8 enable2_ldo1; + /* bitfield to be loaded to ENABLE2_LDO_ASSIGN2 */ + u8 enable2_ldo2; +}; + +struct palmas_clk_platform_data { + int clk32kg_mode_sleep; + int clk32kgaudio_mode_sleep; }; struct palmas_platform_data { @@ -138,8 +234,49 @@ struct palmas_platform_data { u8 pad1, pad2; struct palmas_pmic_platform_data *pmic_pdata; + struct palmas_gpadc_platform_data *gpadc_pdata; + struct palmas_usb_platform_data *usb_pdata; + struct palmas_resource_platform_data *resource_pdata; + struct palmas_clk_platform_data *clk_pdata; +}; + +struct palmas_gpadc_calibration { + s32 gain; + s32 gain_error; + s32 offset_error; }; +struct palmas_gpadc { + struct device *dev; + struct palmas *palmas; + + int ch3_current; + int ch0_current; + + int gpadc_force; + + int bat_removal; + + struct mutex reading_lock; + struct completion irq_complete; + + int eoc_sw_irq; + + struct palmas_gpadc_calibration *palmas_cal_tbl; + + int conv0_channel; + int conv1_channel; + int rt_channel; +}; + +struct palmas_gpadc_result { + s32 raw_code; + s32 corrected_code; + s32 result; +}; + +#define PALMAS_MAX_CHANNELS 16 + /* Define the palmas IRQ numbers */ enum palmas_irqs { /* INT1 registers */ @@ -182,34 +319,6 @@ enum palmas_irqs { PALMAS_NUM_IRQ, }; -enum palmas_regulators { - /* SMPS regulators */ - PALMAS_REG_SMPS12, - PALMAS_REG_SMPS123, - PALMAS_REG_SMPS3, - PALMAS_REG_SMPS45, - PALMAS_REG_SMPS457, - PALMAS_REG_SMPS6, - PALMAS_REG_SMPS7, - PALMAS_REG_SMPS8, - PALMAS_REG_SMPS9, - PALMAS_REG_SMPS10, - /* LDO regulators */ - PALMAS_REG_LDO1, - PALMAS_REG_LDO2, - PALMAS_REG_LDO3, - PALMAS_REG_LDO4, - PALMAS_REG_LDO5, - PALMAS_REG_LDO6, - PALMAS_REG_LDO7, - PALMAS_REG_LDO8, - PALMAS_REG_LDO9, - PALMAS_REG_LDOLN, - PALMAS_REG_LDOUSB, - /* Total number of regulators */ - PALMAS_NUM_REGS, -}; - struct palmas_pmic { struct palmas *palmas; struct device *dev; @@ -223,6 +332,69 @@ struct palmas_pmic { int range[PALMAS_REG_SMPS10]; }; +struct palmas_resource { + struct palmas *palmas; + struct device *dev; +}; + +struct palmas_usb { + struct palmas *palmas; + struct device *dev; + + /* for vbus reporting with irqs disabled */ + spinlock_t lock; + + struct regulator *vbus_reg; + + /* used to set vbus, in atomic path */ + struct work_struct set_vbus_work; + + int irq1; + int irq2; + int irq3; + int irq4; + + int vbus_enable; + + u8 linkstat; +}; + +#define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator) + +enum usb_irq_events { + /* Wakeup events from INT3 */ + PALMAS_USB_ID_WAKEPUP, + PALMAS_USB_VBUS_WAKEUP, + + /* ID_OTG_EVENTS */ + PALMAS_USB_ID_GND, + N_PALMAS_USB_ID_GND, + PALMAS_USB_ID_C, + N_PALMAS_USB_ID_C, + PALMAS_USB_ID_B, + N_PALMAS_USB_ID_B, + PALMAS_USB_ID_A, + N_PALMAS_USB_ID_A, + PALMAS_USB_ID_FLOAT, + N_PALMAS_USB_ID_FLOAT, + + /* VBUS_OTG_EVENTS */ + PALMAS_USB_VB_SESS_END, + N_PALMAS_USB_VB_SESS_END, + PALMAS_USB_VB_SESS_VLD, + N_PALMAS_USB_VB_SESS_VLD, + PALMAS_USB_VA_SESS_VLD, + N_PALMAS_USB_VA_SESS_VLD, + PALMAS_USB_VA_VBUS_VLD, + N_PALMAS_USB_VA_VBUS_VLD, + PALMAS_USB_VADP_SNS, + N_PALMAS_USB_VADP_SNS, + PALMAS_USB_VADP_PRB, + N_PALMAS_USB_VADP_PRB, + PALMAS_USB_VOTG_SESS_VLD, + N_PALMAS_USB_VOTG_SESS_VLD, +}; + /* defines so we can store the mux settings */ #define PALMAS_GPIO_0_MUXED (1 << 0) #define PALMAS_GPIO_1_MUXED (1 << 1) diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h index 3661c59aa1e9..36c242e52ef1 100644 --- a/include/linux/mfd/rc5t583.h +++ b/include/linux/mfd/rc5t583.h @@ -146,6 +146,28 @@ #define RC5T583_GPIO_MON_IOIN 0xAB #define RC5T583_GPIO_GPOFUNC 0xAC +/* RTC registers */ +#define RC5T583_RTC_SEC 0xE0 +#define RC5T583_RTC_MIN 0xE1 +#define RC5T583_RTC_HOUR 0xE2 +#define RC5T583_RTC_WDAY 0xE3 +#define RC5T583_RTC_DAY 0xE4 +#define RC5T583_RTC_MONTH 0xE5 +#define RC5T583_RTC_YEAR 0xE6 +#define RC5T583_RTC_ADJ 0xE7 +#define RC5T583_RTC_AW_MIN 0xE8 +#define RC5T583_RTC_AW_HOUR 0xE9 +#define RC5T583_RTC_AW_WEEK 0xEA +#define RC5T583_RTC_AD_MIN 0xEB +#define RC5T583_RTC_AD_HOUR 0xEC +#define RC5T583_RTC_CTL1 0xED +#define RC5T583_RTC_CTL2 0xEE +#define RC5T583_RTC_AY_MIN 0xF0 +#define RC5T583_RTC_AY_HOUR 0xF1 +#define RC5T583_RTC_AY_DAY 0xF2 +#define RC5T583_RTC_AY_MONTH 0xF3 +#define RC5T583_RTC_AY_YEAR 0xF4 + /* RICOH_RC5T583 IRQ definitions */ enum { RC5T583_IRQ_ONKEY, diff --git a/include/linux/mfd/smsc.h b/include/linux/mfd/smsc.h new file mode 100644 index 000000000000..9747b29f356f --- /dev/null +++ b/include/linux/mfd/smsc.h @@ -0,0 +1,109 @@ +/* + * SMSC ECE1099 + * + * Copyright 2012 Texas Instruments Inc. + * + * Author: Sourav Poddar <sourav.poddar@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; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __LINUX_MFD_SMSC_H +#define __LINUX_MFD_SMSC_H + +#include <linux/regmap.h> + +#define SMSC_ID_ECE1099 1 +#define SMSC_NUM_CLIENTS 2 + +#define SMSC_BASE_ADDR 0x38 +#define OMAP_GPIO_SMSC_IRQ 151 + +#define SMSC_MAXGPIO 32 +#define SMSC_BANK(offs) ((offs) >> 3) +#define SMSC_BIT(offs) (1u << ((offs) & 0x7)) + +struct smsc { + struct device *dev; + struct i2c_client *i2c_clients[SMSC_NUM_CLIENTS]; + struct regmap *regmap; + int clk; + /* Stored chip id */ + int id; +}; + +struct smsc_gpio; +struct smsc_keypad; + +static inline int smsc_read(struct device *child, unsigned int reg, + unsigned int *dest) +{ + struct smsc *smsc = dev_get_drvdata(child->parent); + + return regmap_read(smsc->regmap, reg, dest); +} + +static inline int smsc_write(struct device *child, unsigned int reg, + unsigned int value) +{ + struct smsc *smsc = dev_get_drvdata(child->parent); + + return regmap_write(smsc->regmap, reg, value); +} + +/* Registers for SMSC */ +#define SMSC_RESET 0xF5 +#define SMSC_GRP_INT 0xF9 +#define SMSC_CLK_CTRL 0xFA +#define SMSC_WKUP_CTRL 0xFB +#define SMSC_DEV_ID 0xFC +#define SMSC_DEV_REV 0xFD +#define SMSC_VEN_ID_L 0xFE +#define SMSC_VEN_ID_H 0xFF + +/* CLK VALUE */ +#define SMSC_CLK_VALUE 0x13 + +/* Registers for function GPIO INPUT */ +#define SMSC_GPIO_DATA_IN_START 0x00 + +/* Registers for function GPIO OUPUT */ +#define SMSC_GPIO_DATA_OUT_START 0x05 + +/* Definitions for SMSC GPIO CONFIGURATION REGISTER*/ +#define SMSC_GPIO_INPUT_LOW 0x01 +#define SMSC_GPIO_INPUT_RISING 0x09 +#define SMSC_GPIO_INPUT_FALLING 0x11 +#define SMSC_GPIO_INPUT_BOTH_EDGE 0x19 +#define SMSC_GPIO_OUTPUT_PP 0x21 +#define SMSC_GPIO_OUTPUT_OP 0x31 + +#define GRP_INT_STAT 0xf9 +#define SMSC_GPI_INT 0x0f +#define SMSC_CFG_START 0x0A + +/* Registers for SMSC GPIO INTERRUPT STATUS REGISTER*/ +#define SMSC_GPIO_INT_STAT_START 0x32 + +/* Registers for SMSC GPIO INTERRUPT MASK REGISTER*/ +#define SMSC_GPIO_INT_MASK_START 0x37 + +/* Registers for SMSC function KEYPAD*/ +#define SMSC_KP_OUT 0x40 +#define SMSC_KP_IN 0x41 +#define SMSC_KP_INT_STAT 0x42 +#define SMSC_KP_INT_MASK 0x43 + +/* Definitions for keypad */ +#define SMSC_KP_KSO 0x70 +#define SMSC_KP_KSI 0x51 +#define SMSC_KSO_ALL_LOW 0x20 +#define SMSC_KP_SET_LOW_PWR 0x0B +#define SMSC_KP_SET_HIGH 0xFF +#define SMSC_KSO_EVAL 0x00 + +#endif /* __LINUX_MFD_SMSC_H */ diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h new file mode 100644 index 000000000000..6aeb6b8da64d --- /dev/null +++ b/include/linux/mfd/syscon.h @@ -0,0 +1,23 @@ +/* + * System Control Driver + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng <dong.aisheng@linaro.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. + */ + +#ifndef __LINUX_MFD_SYSCON_H__ +#define __LINUX_MFD_SYSCON_H__ + +extern struct regmap *syscon_node_to_regmap(struct device_node *np); +extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); +extern struct regmap *syscon_regmap_lookup_by_phandle( + struct device_node *np, + const char *property); +#endif /* __LINUX_MFD_SYSCON_H__ */ diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h new file mode 100644 index 000000000000..dab34a1deb2c --- /dev/null +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * 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. + */ + +#ifndef __LINUX_IMX6Q_IOMUXC_GPR_H +#define __LINUX_IMX6Q_IOMUXC_GPR_H + +#include <linux/bitops.h> + +#define IOMUXC_GPR0 0x00 +#define IOMUXC_GPR1 0x04 +#define IOMUXC_GPR2 0x08 +#define IOMUXC_GPR3 0x0c +#define IOMUXC_GPR4 0x10 +#define IOMUXC_GPR5 0x14 +#define IOMUXC_GPR6 0x18 +#define IOMUXC_GPR7 0x1c +#define IOMUXC_GPR8 0x20 +#define IOMUXC_GPR9 0x24 +#define IOMUXC_GPR10 0x28 +#define IOMUXC_GPR11 0x2c +#define IOMUXC_GPR12 0x30 +#define IOMUXC_GPR13 0x34 + +#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_MASK (0x3 << 30) +#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_AUDMUX_RXCLK_P7_MUXED (0x0 << 30) +#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_AUDMUX_RXCLK_P7 (0x1 << 30) +#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_SSI3_SSI_SRCK (0x2 << 30) +#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_SSI3_RX_BIT_CLK (0x3 << 30) +#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_MASK (0x3 << 28) +#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_IND_SCKR_MUXED (0x0 << 28) +#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_IND_SCKR (0x1 << 28) +#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_DO_SCKR (0x2 << 28) +#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_MASK (0x3 << 26) +#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_AUDMUX_TXCLK_P7_MUXED (0x0 << 26) +#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_AUDMUX_TXCLK_P7 (0x1 << 26) +#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_SSI3_SSI_STCK (0x2 << 26) +#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_SSI3_TX_BIT_CLK (0x3 << 26) +#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_MASK (0x3 << 24) +#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_AUDMUX_RXCLK_P7_MUXED (0x3 << 24) +#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_AUDMUX_RXCLK_P7 (0x3 << 24) +#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_SSI3_SSI_SRCK (0x3 << 24) +#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_SSI3_RX_BIT_CLK (0x3 << 24) +#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_MASK (0x3 << 22) +#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_AUDMUX_TXCLK_P2_MUXED (0x0 << 22) +#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_AUDMUX_TXCLK_P2 (0x1 << 22) +#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_SSI2_SSI_STCK (0x2 << 22) +#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_SSI2_TX_BIT_CLK (0x3 << 22) +#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_MASK (0x3 << 20) +#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_AUDMUX_RXCLK_P2_MUXED (0x0 << 20) +#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_AUDMUX_RXCLK_P2 (0x1 << 20) +#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_SSI2_SSI_SRCK (0x2 << 20) +#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_SSI2_RX_BIT_CLK (0x3 << 20) +#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_MASK (0x3 << 18) +#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_AUDMUX_TXCLK_P1_MUXED (0x0 << 18) +#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_AUDMUX_TXCLK_P1 (0x1 << 18) +#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_SSI1_SSI_STCK (0x2 << 18) +#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_SSI1_SSI_TX_BIT_CLK (0x3 << 18) +#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_MASK (0x3 << 16) +#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_AUDMUX_RXCLK_P1_MUXED (0x0 << 16) +#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_AUDMUX_RXCLK_P1 (0x1 << 16) +#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_SSI1_SSI_SRCK (0x2 << 16) +#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_SSI1_SSI_RX_BIT_CLK (0x3 << 16) +#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_MASK (0x3 << 14) +#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK1 (0x0 << 14) +#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK2 (0x1 << 14) +#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK3 (0x2 << 14) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_MASK BIT(7) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_SPDIF 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_IOMUX BIT(7) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_MASK BIT(6) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_ESAI 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_I2C3 BIT(6) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_MASK BIT(5) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_ECSPI4 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_EPIT2 BIT(5) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_MASK BIT(4) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_ECSPI4 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_I2C1 BIT(4) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_MASK BIT(3) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_ECSPI2 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_I2C1 BIT(3) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_MASK BIT(2) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_ECSPI1 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_I2C2 BIT(2) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_MASK BIT(1) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_ECSPI1 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_I2C3 BIT(1) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_MASK BIT(0) +#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IPU1 0x0 +#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IOMUX BIT(0) + +#define IMX6Q_GPR1_PCIE_REQ_MASK (0x3 << 30) +#define IMX6Q_GPR1_PCIE_EXIT_L1 BIT(28) +#define IMX6Q_GPR1_PCIE_RDY_L23 BIT(27) +#define IMX6Q_GPR1_PCIE_ENTER_L1 BIT(26) +#define IMX6Q_GPR1_MIPI_COLOR_SW BIT(25) +#define IMX6Q_GPR1_DPI_OFF BIT(24) +#define IMX6Q_GPR1_EXC_MON_MASK BIT(22) +#define IMX6Q_GPR1_EXC_MON_OKAY 0x0 +#define IMX6Q_GPR1_EXC_MON_SLVE BIT(22) +#define IMX6Q_GPR1_MIPI_IPU2_SEL_MASK BIT(21) +#define IMX6Q_GPR1_MIPI_IPU2_SEL_GASKET 0x0 +#define IMX6Q_GPR1_MIPI_IPU2_SEL_IOMUX BIT(21) +#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK BIT(20) +#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET 0x0 +#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX BIT(20) +#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK BIT(19) +#define IMX6Q_GPR1_MIPI_IPU2_MUX_GASKET 0x0 +#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX BIT(19) +#define IMX6Q_GPR1_PCIE_TEST_PD BIT(18) +#define IMX6Q_GPR1_IPU_VPU_MUX_MASK BIT(17) +#define IMX6Q_GPR1_IPU_VPU_MUX_IPU1 0x0 +#define IMX6Q_GPR1_IPU_VPU_MUX_IPU2 BIT(17) +#define IMX6Q_GPR1_PCIE_REF_CLK_EN BIT(16) +#define IMX6Q_GPR1_USB_EXP_MODE BIT(15) +#define IMX6Q_GPR1_PCIE_INT BIT(14) +#define IMX6Q_GPR1_USB_OTG_ID_SEL_MASK BIT(13) +#define IMX6Q_GPR1_USB_OTG_ID_SEL_ENET_RX_ER 0x0 +#define IMX6Q_GPR1_USB_OTG_ID_SEL_GPIO_1 BIT(13) +#define IMX6Q_GPR1_GINT BIT(12) +#define IMX6Q_GPR1_ADDRS3_MASK (0x3 << 10) +#define IMX6Q_GPR1_ADDRS3_32MB (0x0 << 10) +#define IMX6Q_GPR1_ADDRS3_64MB (0x1 << 10) +#define IMX6Q_GPR1_ADDRS3_128MB (0x2 << 10) +#define IMX6Q_GPR1_ACT_CS3 BIT(9) +#define IMX6Q_GPR1_ADDRS2_MASK (0x3 << 7) +#define IMX6Q_GPR1_ACT_CS2 BIT(6) +#define IMX6Q_GPR1_ADDRS1_MASK (0x3 << 4) +#define IMX6Q_GPR1_ACT_CS1 BIT(3) +#define IMX6Q_GPR1_ADDRS0_MASK (0x3 << 1) +#define IMX6Q_GPR1_ACT_CS0 BIT(0) + +#define IMX6Q_GPR2_COUNTER_RESET_VAL_MASK (0x3 << 20) +#define IMX6Q_GPR2_COUNTER_RESET_VAL_5 (0x0 << 20) +#define IMX6Q_GPR2_COUNTER_RESET_VAL_3 (0x1 << 20) +#define IMX6Q_GPR2_COUNTER_RESET_VAL_4 (0x2 << 20) +#define IMX6Q_GPR2_COUNTER_RESET_VAL_6 (0x3 << 20) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_MASK (0x7 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_0 (0x0 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_1 (0x1 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_2 (0x2 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_3 (0x3 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_4 (0x4 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_5 (0x5 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_6 (0x6 << 16) +#define IMX6Q_GPR2_LVDS_CLK_SHIFT_7 (0x7 << 16) +#define IMX6Q_GPR2_BGREF_RRMODE_MASK BIT(15) +#define IMX6Q_GPR2_BGREF_RRMODE_EXT_RESISTOR 0x0 +#define IMX6Q_GPR2_BGREF_RRMODE_INT_RESISTOR BIT(15) +#define IMX6Q_GPR2_DI1_VS_POLARITY_MASK BIT(10) +#define IMX6Q_GPR2_DI1_VS_POLARITY_ACTIVE_H 0x0 +#define IMX6Q_GPR2_DI1_VS_POLARITY_ACTIVE_L BIT(10) +#define IMX6Q_GPR2_DI0_VS_POLARITY_MASK BIT(9) +#define IMX6Q_GPR2_DI0_VS_POLARITY_ACTIVE_H 0x0 +#define IMX6Q_GPR2_DI0_VS_POLARITY_ACTIVE_L BIT(9) +#define IMX6Q_GPR2_BIT_MAPPING_CH1_MASK BIT(8) +#define IMX6Q_GPR2_BIT_MAPPING_CH1_SPWG 0x0 +#define IMX6Q_GPR2_BIT_MAPPING_CH1_JEIDA BIT(8) +#define IMX6Q_GPR2_DATA_WIDTH_CH1_MASK BIT(7) +#define IMX6Q_GPR2_DATA_WIDTH_CH1_18BIT 0x0 +#define IMX6Q_GPR2_DATA_WIDTH_CH1_24BIT BIT(7) +#define IMX6Q_GPR2_BIT_MAPPING_CH0_MASK BIT(6) +#define IMX6Q_GPR2_BIT_MAPPING_CH0_SPWG 0x0 +#define IMX6Q_GPR2_BIT_MAPPING_CH0_JEIDA BIT(6) +#define IMX6Q_GPR2_DATA_WIDTH_CH0_MASK BIT(5) +#define IMX6Q_GPR2_DATA_WIDTH_CH0_18BIT 0x0 +#define IMX6Q_GPR2_DATA_WIDTH_CH0_24BIT BIT(5) +#define IMX6Q_GPR2_SPLIT_MODE_EN BIT(4) +#define IMX6Q_GPR2_CH1_MODE_MASK (0x3 << 2) +#define IMX6Q_GPR2_CH1_MODE_DISABLE (0x0 << 2) +#define IMX6Q_GPR2_CH1_MODE_EN_ROUTE_DI0 (0x1 << 2) +#define IMX6Q_GPR2_CH1_MODE_EN_ROUTE_DI1 (0x3 << 2) +#define IMX6Q_GPR2_CH0_MODE_MASK (0x3 << 0) +#define IMX6Q_GPR2_CH0_MODE_DISABLE (0x0 << 0) +#define IMX6Q_GPR2_CH0_MODE_EN_ROUTE_DI0 (0x1 << 0) +#define IMX6Q_GPR2_CH0_MODE_EN_ROUTE_DI1 (0x3 << 0) + +#define IMX6Q_GPR3_GPU_DBG_MASK (0x3 << 29) +#define IMX6Q_GPR3_GPU_DBG_GPU3D (0x0 << 29) +#define IMX6Q_GPR3_GPU_DBG_GPU2D (0x1 << 29) +#define IMX6Q_GPR3_GPU_DBG_OPENVG (0x2 << 29) +#define IMX6Q_GPR3_BCH_WR_CACHE_CTL BIT(28) +#define IMX6Q_GPR3_BCH_RD_CACHE_CTL BIT(27) +#define IMX6Q_GPR3_USDHCX_WR_CACHE_CTL BIT(26) +#define IMX6Q_GPR3_USDHCX_RD_CACHE_CTL BIT(25) +#define IMX6Q_GPR3_OCRAM_CTL_MASK (0xf << 21) +#define IMX6Q_GPR3_OCRAM_STATUS_MASK (0xf << 17) +#define IMX6Q_GPR3_CORE3_DBG_ACK_EN BIT(16) +#define IMX6Q_GPR3_CORE2_DBG_ACK_EN BIT(15) +#define IMX6Q_GPR3_CORE1_DBG_ACK_EN BIT(14) +#define IMX6Q_GPR3_CORE0_DBG_ACK_EN BIT(13) +#define IMX6Q_GPR3_TZASC2_BOOT_LOCK BIT(12) +#define IMX6Q_GPR3_TZASC1_BOOT_LOCK BIT(11) +#define IMX6Q_GPR3_IPU_DIAG_MASK BIT(10) +#define IMX6Q_GPR3_LVDS1_MUX_CTL_MASK (0x3 << 8) +#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI0 (0x0 << 8) +#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI1 (0x1 << 8) +#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI0 (0x2 << 8) +#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI1 (0x3 << 8) +#define IMX6Q_GPR3_LVDS0_MUX_CTL_MASK (0x3 << 6) +#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI0 (0x0 << 6) +#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6) +#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0 (0x2 << 6) +#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1 (0x3 << 6) +#define IMX6Q_GPR3_MIPI_MUX_CTL_MASK (0x3 << 4) +#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0 (0x0 << 4) +#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4) +#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI0 (0x2 << 4) +#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI1 (0x3 << 4) +#define IMX6Q_GPR3_HDMI_MUX_CTL_MASK (0x3 << 2) +#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI0 (0x0 << 2) +#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI1 (0x1 << 2) +#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU2_DI0 (0x2 << 2) +#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU2_DI1 (0x3 << 2) + +#define IMX6Q_GPR4_VDOA_WR_CACHE_SEL BIT(31) +#define IMX6Q_GPR4_VDOA_RD_CACHE_SEL BIT(30) +#define IMX6Q_GPR4_VDOA_WR_CACHE_VAL BIT(29) +#define IMX6Q_GPR4_VDOA_RD_CACHE_VAL BIT(28) +#define IMX6Q_GPR4_PCIE_WR_CACHE_SEL BIT(27) +#define IMX6Q_GPR4_PCIE_RD_CACHE_SEL BIT(26) +#define IMX6Q_GPR4_PCIE_WR_CACHE_VAL BIT(25) +#define IMX6Q_GPR4_PCIE_RD_CACHE_VAL BIT(24) +#define IMX6Q_GPR4_SDMA_STOP_ACK BIT(19) +#define IMX6Q_GPR4_CAN2_STOP_ACK BIT(18) +#define IMX6Q_GPR4_CAN1_STOP_ACK BIT(17) +#define IMX6Q_GPR4_ENET_STOP_ACK BIT(16) +#define IMX6Q_GPR4_SOC_VERSION_MASK (0xff << 8) +#define IMX6Q_GPR4_SOC_VERSION_OFF 0x8 +#define IMX6Q_GPR4_VPU_WR_CACHE_SEL BIT(7) +#define IMX6Q_GPR4_VPU_RD_CACHE_SEL BIT(6) +#define IMX6Q_GPR4_VPU_P_WR_CACHE_VAL BIT(3) +#define IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK BIT(2) +#define IMX6Q_GPR4_IPU_WR_CACHE_CTL BIT(1) +#define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0) + +#define IMX6Q_GPR5_L2_CLK_STOP BIT(8) + +#define IMX6Q_GPR9_TZASC2_BYP BIT(1) +#define IMX6Q_GPR9_TZASC1_BYP BIT(0) + +#define IMX6Q_GPR10_LOCK_DBG_EN BIT(29) +#define IMX6Q_GPR10_LOCK_DBG_CLK_EN BIT(28) +#define IMX6Q_GPR10_LOCK_SEC_ERR_RESP BIT(27) +#define IMX6Q_GPR10_LOCK_OCRAM_TZ_ADDR (0x3f << 21) +#define IMX6Q_GPR10_LOCK_OCRAM_TZ_EN BIT(20) +#define IMX6Q_GPR10_LOCK_DCIC2_MUX_MASK (0x3 << 18) +#define IMX6Q_GPR10_LOCK_DCIC1_MUX_MASK (0x3 << 16) +#define IMX6Q_GPR10_DBG_EN BIT(13) +#define IMX6Q_GPR10_DBG_CLK_EN BIT(12) +#define IMX6Q_GPR10_SEC_ERR_RESP_MASK BIT(11) +#define IMX6Q_GPR10_SEC_ERR_RESP_OKEY 0x0 +#define IMX6Q_GPR10_SEC_ERR_RESP_SLVE BIT(11) +#define IMX6Q_GPR10_OCRAM_TZ_ADDR_MASK (0x3f << 5) +#define IMX6Q_GPR10_OCRAM_TZ_EN_MASK BIT(4) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_MASK (0x3 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI0 (0x0 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1 (0x1 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI0 (0x2 << 2) +#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI1 (0x3 << 2) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_MASK (0x3 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0 (0x0 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI1 (0x1 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI0 (0x2 << 0) +#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI1 (0x3 << 0) + +#define IMX6Q_GPR12_ARMP_IPG_CLK_EN BIT(27) +#define IMX6Q_GPR12_ARMP_AHB_CLK_EN BIT(26) +#define IMX6Q_GPR12_ARMP_ATB_CLK_EN BIT(25) +#define IMX6Q_GPR12_ARMP_APB_CLK_EN BIT(24) +#define IMX6Q_GPR12_PCIE_CTL_2 BIT(10) + +#define IMX6Q_GPR13_SDMA_STOP_REQ BIT(30) +#define IMX6Q_GPR13_CAN2_STOP_REQ BIT(29) +#define IMX6Q_GPR13_CAN1_STOP_REQ BIT(28) +#define IMX6Q_GPR13_ENET_STOP_REQ BIT(27) +#define IMX6Q_GPR13_SATA_PHY_8_MASK (0x7 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_0_5_DB (0x0 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_1_0_DB (0x1 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_1_5_DB (0x2 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_2_0_DB (0x3 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_2_5_DB (0x4 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_3_0_DB (0x5 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_3_5_DB (0x6 << 24) +#define IMX6Q_GPR13_SATA_PHY_8_4_0_DB (0x7 << 24) +#define IMX6Q_GPR13_SATA_PHY_7_MASK (0x1f << 19) +#define IMX6Q_GPR13_SATA_PHY_7_SATA1I (0x10 << 19) +#define IMX6Q_GPR13_SATA_PHY_7_SATA1M (0x10 << 19) +#define IMX6Q_GPR13_SATA_PHY_7_SATA1X (0x1a << 19) +#define IMX6Q_GPR13_SATA_PHY_7_SATA2I (0x12 << 19) +#define IMX6Q_GPR13_SATA_PHY_7_SATA2M (0x12 << 19) +#define IMX6Q_GPR13_SATA_PHY_7_SATA2X (0x1a << 19) +#define IMX6Q_GPR13_SATA_PHY_6_MASK (0x7 << 16) +#define IMX6Q_GPR13_SATA_SPEED_MASK BIT(15) +#define IMX6Q_GPR13_SATA_SPEED_1P5G 0x0 +#define IMX6Q_GPR13_SATA_SPEED_3P0G BIT(15) +#define IMX6Q_GPR13_SATA_PHY_5 BIT(14) +#define IMX6Q_GPR13_SATA_PHY_4_MASK (0x7 << 11) +#define IMX6Q_GPR13_SATA_PHY_4_16_16 (0x0 << 11) +#define IMX6Q_GPR13_SATA_PHY_4_14_16 (0x1 << 11) +#define IMX6Q_GPR13_SATA_PHY_4_12_16 (0x2 << 11) +#define IMX6Q_GPR13_SATA_PHY_4_10_16 (0x3 << 11) +#define IMX6Q_GPR13_SATA_PHY_4_9_16 (0x4 << 11) +#define IMX6Q_GPR13_SATA_PHY_4_8_16 (0x5 << 11) +#define IMX6Q_GPR13_SATA_PHY_3_MASK (0xf << 7) +#define IMX6Q_GPR13_SATA_PHY_3_OFF 0x7 +#define IMX6Q_GPR13_SATA_PHY_2_MASK (0x1f << 2) +#define IMX6Q_GPR13_SATA_PHY_2_OFF 0x2 +#define IMX6Q_GPR13_SATA_PHY_1_MASK (0x3 << 0) +#define IMX6Q_GPR13_SATA_PHY_1_FAST (0x0 << 0) +#define IMX6Q_GPR13_SATA_PHY_1_MED (0x1 << 0) +#define IMX6Q_GPR13_SATA_PHY_1_SLOW (0x2 << 0) + +#endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */ diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h index 3acb3a8e3af5..6b8e1ff4672b 100644 --- a/include/linux/mfd/tc3589x.h +++ b/include/linux/mfd/tc3589x.h @@ -117,6 +117,7 @@ struct tc3589x { struct mutex lock; struct device *dev; struct i2c_client *i2c; + struct irq_domain *domain; int irq_base; int num_gpio; diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index 7cd83d826ed8..290762f93930 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -213,6 +213,23 @@ enum tps65217_regulator_id { /* Number of total regulators available */ #define TPS65217_NUM_REGULATOR (TPS65217_NUM_DCDC + TPS65217_NUM_LDO) +enum tps65217_bl_isel { + TPS65217_BL_ISET1 = 1, + TPS65217_BL_ISET2, +}; + +enum tps65217_bl_fdim { + TPS65217_BL_FDIM_100HZ, + TPS65217_BL_FDIM_200HZ, + TPS65217_BL_FDIM_500HZ, + TPS65217_BL_FDIM_1000HZ, +}; + +struct tps65217_bl_pdata { + enum tps65217_bl_isel isel; + enum tps65217_bl_fdim fdim; +}; + /** * struct tps65217_board - packages regulator init data * @tps65217_regulator_data: regulator initialization values @@ -222,6 +239,7 @@ enum tps65217_regulator_id { struct tps65217_board { struct regulator_init_data *tps65217_init_data[TPS65217_NUM_REGULATOR]; struct device_node *of_node[TPS65217_NUM_REGULATOR]; + struct tps65217_bl_pdata *bl_pdata; }; /** diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h index 94514710a03f..2dd123194958 100644 --- a/include/linux/mfd/tps6586x.h +++ b/include/linux/mfd/tps6586x.h @@ -78,6 +78,7 @@ struct tps6586x_platform_data { int gpio_base; int irq_base; + bool pm_off; }; /* diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index 9bf8767818b4..02e894f3ff45 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -132,6 +132,16 @@ * */ +/* RTC_CTRL_REG bitfields */ +#define TPS65910_RTC_CTRL_STOP_RTC 0x01 /*0=stop, 1=run */ +#define TPS65910_RTC_CTRL_GET_TIME 0x40 + +/* RTC_STATUS_REG bitfields */ +#define TPS65910_RTC_STATUS_ALARM 0x40 + +/* RTC_INTERRUPTS_REG bitfields */ +#define TPS65910_RTC_INTERRUPTS_EVERY 0x03 +#define TPS65910_RTC_INTERRUPTS_IT_ALARM 0x08 /*Register BCK1 (0x80) register.RegisterDescription */ #define BCK1_BCKUP_MASK 0xFF @@ -366,6 +376,8 @@ /*Register DEVCTRL (0x80) register.RegisterDescription */ +#define DEVCTRL_PWR_OFF_MASK 0x80 +#define DEVCTRL_PWR_OFF_SHIFT 7 #define DEVCTRL_RTC_PWDN_MASK 0x40 #define DEVCTRL_RTC_PWDN_SHIFT 6 #define DEVCTRL_CK32K_CTRL_MASK 0x20 @@ -809,6 +821,7 @@ struct tps65910_board { int vmbch2_threshold; bool en_ck32k_xtal; bool en_dev_slp; + bool pm_off; struct tps65910_sleep_keepon_data *slp_keepon; bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO]; unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS]; diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index ba43d4806b83..a8eff4ad9be5 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -143,7 +143,7 @@ #define TWL6040_GPO1 0x01 #define TWL6040_GPO2 0x02 -#define TWL6040_GPO3 0x03 +#define TWL6040_GPO3 0x04 /* ACCCTL (0x2D) fields */ @@ -158,7 +158,7 @@ #define TWL6040_VIBROCDET 0x20 #define TWL6040_TSHUTDET 0x40 -#define TWL6040_CELLS 2 +#define TWL6040_CELLS 3 #define TWL6040_REV_ES1_0 0x00 #define TWL6040_REV_ES1_1 0x01 /* Rev ES1.1 and ES1.2 */ @@ -176,6 +176,8 @@ #define TWL6040_SYSCLK_SEL_LPPLL 0 #define TWL6040_SYSCLK_SEL_HPPLL 1 +#define TWL6040_GPO_MAX 3 + struct twl6040_codec_data { u16 hs_left_step; u16 hs_right_step; @@ -192,11 +194,16 @@ struct twl6040_vibra_data { int vddvibr_uV; /* VDDVIBR volt, set 0 for fixed reg */ }; +struct twl6040_gpo_data { + int gpio_base; +}; + struct twl6040_platform_data { int audpwron_gpio; /* audio power-on gpio */ struct twl6040_codec_data *codec; struct twl6040_vibra_data *vibra; + struct twl6040_gpo_data *gpo; }; struct regmap; diff --git a/include/linux/nbd.h b/include/linux/nbd.h index d146ca10c0f5..5c86e2b33e2d 100644 --- a/include/linux/nbd.h +++ b/include/linux/nbd.h @@ -27,13 +27,22 @@ #define NBD_SET_SIZE_BLOCKS _IO( 0xab, 7 ) #define NBD_DISCONNECT _IO( 0xab, 8 ) #define NBD_SET_TIMEOUT _IO( 0xab, 9 ) +#define NBD_SET_FLAGS _IO( 0xab, 10) enum { NBD_CMD_READ = 0, NBD_CMD_WRITE = 1, - NBD_CMD_DISC = 2 + NBD_CMD_DISC = 2, + /* there is a gap here to match userspace */ + NBD_CMD_TRIM = 4 }; +/* values for flags field */ +#define NBD_FLAG_HAS_FLAGS (1 << 0) /* nbd-server supports flags */ +#define NBD_FLAG_READ_ONLY (1 << 1) /* device is read-only */ +/* there is a gap here to match userspace */ +#define NBD_FLAG_SEND_TRIM (1 << 5) /* send trim/discard */ + #define nbd_cmd(req) ((req)->cmd[0]) /* userspace doesn't need the nbd_device structure */ @@ -42,10 +51,6 @@ enum { #include <linux/wait.h> #include <linux/mutex.h> -/* values for flags field */ -#define NBD_READ_ONLY 0x0001 -#define NBD_WRITE_NOCHK 0x0002 - struct request; struct nbd_device { diff --git a/include/linux/nx842.h b/include/linux/nx842.h new file mode 100644 index 000000000000..a4d324c6406a --- /dev/null +++ b/include/linux/nx842.h @@ -0,0 +1,11 @@ +#ifndef __NX842_H__ +#define __NX842_H__ + +int nx842_get_workmem_size(void); +int nx842_get_workmem_size_aligned(void); +int nx842_compress(const unsigned char *in, unsigned int in_len, + unsigned char *out, unsigned int *out_len, void *wrkmem); +int nx842_decompress(const unsigned char *in, unsigned int in_len, + unsigned char *out, unsigned int *out_len, void *wrkmem); + +#endif diff --git a/include/linux/of.h b/include/linux/of.h index f594c528842f..72843b72a2b2 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -317,6 +317,12 @@ static inline const char* of_node_full_name(struct device_node *np) return "<no-node>"; } +static inline struct device_node *of_find_node_by_name(struct device_node *from, + const char *name) +{ + return NULL; +} + static inline bool of_have_populated_dt(void) { return false; diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 2b9f82c037c9..cc88172c7d9a 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -107,7 +107,7 @@ enum pcpu_fc { PCPU_FC_NR, }; -extern const char *pcpu_fc_names[PCPU_FC_NR]; +extern const char * const pcpu_fc_names[PCPU_FC_NR]; extern enum pcpu_fc pcpu_chosen_fc; diff --git a/include/linux/platform_data/lm3630_bl.h b/include/linux/platform_data/lm3630_bl.h new file mode 100644 index 000000000000..9176dd3f2d63 --- /dev/null +++ b/include/linux/platform_data/lm3630_bl.h @@ -0,0 +1,57 @@ +/* +* Simple driver for Texas Instruments LM3630 LED Flash driver chip +* Copyright (C) 2012 Texas Instruments +* +* 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. +* +*/ + +#ifndef __LINUX_LM3630_H +#define __LINUX_LM3630_H + +#define LM3630_NAME "lm3630_bl" + +enum lm3630_pwm_ctrl { + PWM_CTRL_DISABLE = 0, + PWM_CTRL_BANK_A, + PWM_CTRL_BANK_B, + PWM_CTRL_BANK_ALL, +}; + +enum lm3630_pwm_active { + PWM_ACTIVE_HIGH = 0, + PWM_ACTIVE_LOW, +}; + +enum lm3630_bank_a_ctrl { + BANK_A_CTRL_DISABLE = 0x0, + BANK_A_CTRL_LED1 = 0x4, + BANK_A_CTRL_LED2 = 0x1, + BANK_A_CTRL_ALL = 0x5, +}; + +enum lm3630_bank_b_ctrl { + BANK_B_CTRL_DISABLE = 0, + BANK_B_CTRL_LED2, +}; + +struct lm3630_platform_data { + + /* maximum brightness */ + int max_brt_led1; + int max_brt_led2; + + /* initial on brightness */ + int init_brt_led1; + int init_brt_led2; + enum lm3630_pwm_ctrl pwm_ctrl; + enum lm3630_pwm_active pwm_active; + enum lm3630_bank_a_ctrl bank_a_ctrl; + enum lm3630_bank_b_ctrl bank_b_ctrl; + unsigned int pwm_period; + void (*pwm_set_intensity) (int brightness, int max_brightness); +}; + +#endif /* __LINUX_LM3630_H */ diff --git a/include/linux/platform_data/lm3639_bl.h b/include/linux/platform_data/lm3639_bl.h new file mode 100644 index 000000000000..5234cd5ed166 --- /dev/null +++ b/include/linux/platform_data/lm3639_bl.h @@ -0,0 +1,69 @@ +/* +* Simple driver for Texas Instruments LM3630 LED Flash driver chip +* Copyright (C) 2012 Texas Instruments +* +* 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. +* +*/ + +#ifndef __LINUX_LM3639_H +#define __LINUX_LM3639_H + +#define LM3639_NAME "lm3639_bl" + +enum lm3639_pwm { + LM3639_PWM_DISABLE = 0x00, + LM3639_PWM_EN_ACTLOW = 0x48, + LM3639_PWM_EN_ACTHIGH = 0x40, +}; + +enum lm3639_strobe { + LM3639_STROBE_DISABLE = 0x00, + LM3639_STROBE_EN_ACTLOW = 0x10, + LM3639_STROBE_EN_ACTHIGH = 0x30, +}; + +enum lm3639_txpin { + LM3639_TXPIN_DISABLE = 0x00, + LM3639_TXPIN_EN_ACTLOW = 0x04, + LM3639_TXPIN_EN_ACTHIGH = 0x0C, +}; + +enum lm3639_fleds { + LM3639_FLED_DIASBLE_ALL = 0x00, + LM3639_FLED_EN_1 = 0x40, + LM3639_FLED_EN_2 = 0x20, + LM3639_FLED_EN_ALL = 0x60, +}; + +enum lm3639_bleds { + LM3639_BLED_DIASBLE_ALL = 0x00, + LM3639_BLED_EN_1 = 0x10, + LM3639_BLED_EN_2 = 0x08, + LM3639_BLED_EN_ALL = 0x18, +}; +enum lm3639_bled_mode { + LM3639_BLED_MODE_EXPONETIAL = 0x00, + LM3639_BLED_MODE_LINEAR = 0x10, +}; + +struct lm3639_platform_data { + unsigned int max_brt_led; + unsigned int init_brt_led; + + /* input pins */ + enum lm3639_pwm pin_pwm; + enum lm3639_strobe pin_strobe; + enum lm3639_txpin pin_tx; + + /* output pins */ + enum lm3639_fleds fled_pins; + enum lm3639_bleds bled_pins; + enum lm3639_bled_mode bled_mode; + + void (*pwm_set_intensity) (int brightness, int max_brightness); + int (*pwm_get_intensity) (void); +}; +#endif /* __LINUX_LM3639_H */ diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h index cc76f1f18f18..761f31752367 100644 --- a/include/linux/platform_data/lp855x.h +++ b/include/linux/platform_data/lp855x.h @@ -46,6 +46,8 @@ #define LP8556_I2C_CONFIG ((ENABLE_BL << BL_CTL_SHFT) | \ (LP8556_I2C_ONLY << BRT_MODE_SHFT)) #define LP8556_COMB2_CONFIG (LP8556_COMBINED2 << BRT_MODE_SHFT) +#define LP8556_FAST_CONFIG BIT(7) /* use it if EPROMs should be maintained + when exiting the low power mode */ enum lp855x_chip_id { LP8550, diff --git a/include/linux/platform_data/remoteproc-omap.h b/include/linux/platform_data/remoteproc-omap.h index b10eac89e2e9..3c1c6444ec4b 100644 --- a/include/linux/platform_data/remoteproc-omap.h +++ b/include/linux/platform_data/remoteproc-omap.h @@ -30,6 +30,7 @@ struct platform_device; * @ops: start/stop rproc handlers * @device_enable: omap-specific handler for enabling a device * @device_shutdown: omap-specific handler for shutting down a device + * @set_bootaddr: omap-specific handler for setting the rproc boot address */ struct omap_rproc_pdata { const char *name; @@ -40,6 +41,7 @@ struct omap_rproc_pdata { const struct rproc_ops *ops; int (*device_enable) (struct platform_device *pdev); int (*device_shutdown) (struct platform_device *pdev); + void(*set_bootaddr)(u32); }; #if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE) diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 131b53957b9f..faf33324c78f 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -361,6 +361,19 @@ enum rproc_state { }; /** + * enum rproc_crash_type - remote processor crash types + * @RPROC_MMUFAULT: iommu fault + * + * Each element of the enum is used as an array index. So that, the value of + * the elements should be always something sane. + * + * Feel free to add more types when needed. + */ +enum rproc_crash_type { + RPROC_MMUFAULT, +}; + +/** * struct rproc - represents a physical remote processor device * @node: klist node of this rproc object * @domain: iommu domain @@ -383,6 +396,11 @@ enum rproc_state { * @rvdevs: list of remote virtio devices * @notifyids: idr for dynamically assigning rproc-wide unique notify ids * @index: index of this rproc device + * @crash_handler: workqueue for handling a crash + * @crash_cnt: crash counter + * @crash_comp: completion used to sync crash handler and the rproc reload + * @recovery_disabled: flag that state if recovery was disabled + * @max_notifyid: largest allocated notify id. */ struct rproc { struct klist_node node; @@ -406,6 +424,11 @@ struct rproc { struct list_head rvdevs; struct idr notifyids; int index; + struct work_struct crash_handler; + unsigned crash_cnt; + struct completion crash_comp; + bool recovery_disabled; + int max_notifyid; }; /* we currently support only two vrings per rvdev */ @@ -460,6 +483,7 @@ int rproc_del(struct rproc *rproc); int rproc_boot(struct rproc *rproc); void rproc_shutdown(struct rproc *rproc); +void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) { diff --git a/include/linux/rio.h b/include/linux/rio.h index a90ebadd9da0..d2dff22cf681 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -30,6 +30,7 @@ #define RIO_MAX_MPORTS 8 #define RIO_MAX_MPORT_RESOURCES 16 #define RIO_MAX_DEV_RESOURCES 16 +#define RIO_MAX_MPORT_NAME 40 #define RIO_GLOBAL_TABLE 0xff /* Indicates access of a switch's global routing table if it @@ -235,6 +236,7 @@ enum rio_phy_type { * @phys_efptr: RIO port extended features pointer * @name: Port name string * @priv: Master port private data + * @dma: DMA device associated with mport */ struct rio_mport { struct list_head dbells; /* list of doorbell events */ @@ -255,13 +257,21 @@ struct rio_mport { */ enum rio_phy_type phy_type; /* RapidIO phy type */ u32 phys_efptr; - unsigned char name[40]; + unsigned char name[RIO_MAX_MPORT_NAME]; void *priv; /* Master port private data */ #ifdef CONFIG_RAPIDIO_DMA_ENGINE struct dma_device dma; #endif }; +struct rio_id_table { + u16 start; /* logical minimal id */ + u16 next; /* hint for find */ + u32 max; /* max number of IDs in table */ + spinlock_t lock; + unsigned long *table; +}; + /** * struct rio_net - RIO network info * @node: Node in global list of RIO networks @@ -273,9 +283,11 @@ struct rio_mport { struct rio_net { struct list_head node; /* node in list of networks */ struct list_head devices; /* list of devices in this net */ + struct list_head switches; /* list of switches in this net */ struct list_head mports; /* list of ports accessing net */ struct rio_mport *hport; /* primary port for accessing net */ unsigned char id; /* RIO network ID */ + struct rio_id_table destid_table; /* destID allocation table */ }; /* Definitions used by switch sysfs initialization callback */ @@ -299,6 +311,8 @@ struct rio_net { * @add_outb_message: Callback to add a message to an outbound mailbox queue. * @add_inb_buffer: Callback to add a buffer to an inbound mailbox queue. * @get_inb_message: Callback to get a message from an inbound mailbox queue. + * @map_inb: Callback to map RapidIO address region into local memory space. + * @unmap_inb: Callback to unmap RapidIO address region mapped with map_inb(). */ struct rio_ops { int (*lcread) (struct rio_mport *mport, int index, u32 offset, int len, @@ -321,6 +335,9 @@ struct rio_ops { int mbox, void *buffer, size_t len); int (*add_inb_buffer)(struct rio_mport *mport, int mbox, void *buf); void *(*get_inb_message)(struct rio_mport *mport, int mbox); + int (*map_inb)(struct rio_mport *mport, dma_addr_t lstart, + u64 rstart, u32 size, u32 flags); + void (*unmap_inb)(struct rio_mport *mport, dma_addr_t lstart); }; #define RIO_RESOURCE_MEM 0x00000100 @@ -403,7 +420,7 @@ union rio_pw_msg { #ifdef CONFIG_RAPIDIO_DMA_ENGINE -/** +/* * enum rio_write_type - RIO write transaction types used in DMA transfers * * Note: RapidIO specification defines write (NWRITE) and diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h index 31ad146be316..b75c05920ab5 100644 --- a/include/linux/rio_drv.h +++ b/include/linux/rio_drv.h @@ -365,6 +365,11 @@ void rio_release_regions(struct rio_dev *); int rio_request_region(struct rio_dev *, int, char *); void rio_release_region(struct rio_dev *, int); +/* Memory mapping functions */ +extern int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, + u64 rbase, u32 size, u32 rflags); +extern void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart); + /* Port-Write management */ extern int rio_request_inb_pwrite(struct rio_dev *, int (*)(struct rio_dev *, union rio_pw_msg*, int)); diff --git a/include/linux/rtc-ds2404.h b/include/linux/rtc-ds2404.h new file mode 100644 index 000000000000..22c53825528f --- /dev/null +++ b/include/linux/rtc-ds2404.h @@ -0,0 +1,20 @@ +/* + * ds2404.h - platform data structure for the DS2404 RTC. + * + * 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. + * + * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org> + */ + +#ifndef __LINUX_DS2404_H +#define __LINUX_DS2404_H + +struct ds2404_platform_data { + + unsigned int gpio_rst; + unsigned int gpio_clk; + unsigned int gpio_dq; +}; +#endif diff --git a/include/linux/rtc.h b/include/linux/rtc.h index f071b3922c67..20ec4d3bed73 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -276,7 +276,7 @@ static inline bool is_leap_year(unsigned int year) return (!(year % 4) && (year % 100)) || !(year % 400); } -#ifdef CONFIG_RTC_HCTOSYS +#ifdef CONFIG_RTC_HCTOSYS_DEVICE extern int rtc_hctosys_ret; #else #define rtc_hctosys_ret -ENODEV diff --git a/include/linux/sched.h b/include/linux/sched.h index 9d51e260bde0..9c5612f0374b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -405,7 +405,6 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm) {} extern void set_dumpable(struct mm_struct *mm, int value); extern int get_dumpable(struct mm_struct *mm); -extern int __get_dumpable(unsigned long mm_flags); /* get/set_dumpable() values */ #define SUID_DUMPABLE_DISABLED 0 diff --git a/include/linux/slab.h b/include/linux/slab.h index 0dd2dfa7beca..83d1a1454b7e 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -321,7 +321,8 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep, * request comes from. */ #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \ - (defined(CONFIG_SLAB) && defined(CONFIG_TRACING)) + (defined(CONFIG_SLAB) && defined(CONFIG_TRACING)) || \ + (defined(CONFIG_SLOB) && defined(CONFIG_TRACING)) extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); #define kmalloc_track_caller(size, flags) \ __kmalloc_track_caller(size, flags, _RET_IP_) @@ -340,7 +341,8 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); * allocation request comes from. */ #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \ - (defined(CONFIG_SLAB) && defined(CONFIG_TRACING)) + (defined(CONFIG_SLAB) && defined(CONFIG_TRACING)) || \ + (defined(CONFIG_SLOB) && defined(CONFIG_TRACING)) extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long); #define kmalloc_node_track_caller(size, flags, node) \ __kmalloc_node_track_caller(size, flags, node, \ diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h index 0c634fa376c9..cc290f0bdb34 100644 --- a/include/linux/slab_def.h +++ b/include/linux/slab_def.h @@ -45,7 +45,6 @@ struct kmem_cache { unsigned int colour_off; /* colour offset */ struct kmem_cache *slabp_cache; unsigned int slab_size; - unsigned int dflags; /* dynamic flags */ /* constructor func */ void (*ctor)(void *obj); @@ -112,19 +111,13 @@ void *kmem_cache_alloc(struct kmem_cache *, gfp_t); void *__kmalloc(size_t size, gfp_t flags); #ifdef CONFIG_TRACING -extern void *kmem_cache_alloc_trace(size_t size, - struct kmem_cache *cachep, gfp_t flags); -extern size_t slab_buffer_size(struct kmem_cache *cachep); +extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t); #else static __always_inline void * -kmem_cache_alloc_trace(size_t size, struct kmem_cache *cachep, gfp_t flags) +kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size) { return kmem_cache_alloc(cachep, flags); } -static inline size_t slab_buffer_size(struct kmem_cache *cachep) -{ - return 0; -} #endif static __always_inline void *kmalloc(size_t size, gfp_t flags) @@ -154,7 +147,7 @@ found: #endif cachep = malloc_sizes[i].cs_cachep; - ret = kmem_cache_alloc_trace(size, cachep, flags); + ret = kmem_cache_alloc_trace(cachep, flags, size); return ret; } @@ -166,16 +159,16 @@ extern void *__kmalloc_node(size_t size, gfp_t flags, int node); extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); #ifdef CONFIG_TRACING -extern void *kmem_cache_alloc_node_trace(size_t size, - struct kmem_cache *cachep, +extern void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep, gfp_t flags, - int nodeid); + int nodeid, + size_t size); #else static __always_inline void * -kmem_cache_alloc_node_trace(size_t size, - struct kmem_cache *cachep, +kmem_cache_alloc_node_trace(struct kmem_cache *cachep, gfp_t flags, - int nodeid) + int nodeid, + size_t size) { return kmem_cache_alloc_node(cachep, flags, nodeid); } @@ -207,7 +200,7 @@ found: #endif cachep = malloc_sizes[i].cs_cachep; - return kmem_cache_alloc_node_trace(size, cachep, flags, node); + return kmem_cache_alloc_node_trace(cachep, flags, node, size); } return __kmalloc_node(size, flags, node); } diff --git a/include/linux/slob_def.h b/include/linux/slob_def.h index 0ec00b39d006..f28e14a12e3f 100644 --- a/include/linux/slob_def.h +++ b/include/linux/slob_def.h @@ -1,12 +1,14 @@ #ifndef __LINUX_SLOB_DEF_H #define __LINUX_SLOB_DEF_H +#include <linux/numa.h> + void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); static __always_inline void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) { - return kmem_cache_alloc_node(cachep, flags, -1); + return kmem_cache_alloc_node(cachep, flags, NUMA_NO_NODE); } void *__kmalloc_node(size_t size, gfp_t flags, int node); @@ -26,7 +28,7 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) */ static __always_inline void *kmalloc(size_t size, gfp_t flags) { - return __kmalloc_node(size, flags, -1); + return __kmalloc_node(size, flags, NUMA_NO_NODE); } static __always_inline void *__kmalloc(size_t size, gfp_t flags) diff --git a/include/linux/ste_modem_shm.h b/include/linux/ste_modem_shm.h new file mode 100644 index 000000000000..8444a4eff1bb --- /dev/null +++ b/include/linux/ste_modem_shm.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) ST-Ericsson AB 2012 + * Author: Sjur Brendeland / sjur.brandeland@stericsson.com + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __INC_MODEM_DEV_H +#define __INC_MODEM_DEV_H +#include <linux/types.h> +#include <linux/platform_device.h> + +struct ste_modem_device; + +/** + * struct ste_modem_dev_cb - Callbacks for modem initiated events. + * @kick: Called when the modem kicks the host. + * + * This structure contains callbacks for actions triggered by the modem. + */ +struct ste_modem_dev_cb { + void (*kick)(struct ste_modem_device *mdev, int notify_id); +}; + +/** + * struct ste_modem_dev_ops - Functions to control modem and modem interface. + * + * @power: Main power switch, used for cold-start or complete power off. + * @kick: Kick the modem. + * @kick_subscribe: Subscribe for notifications from the modem. + * @setup: Provide callback functions to modem device. + * + * This structure contains functions used by the ste remoteproc driver + * to manage the modem. + */ +struct ste_modem_dev_ops { + int (*power)(struct ste_modem_device *mdev, bool on); + int (*kick)(struct ste_modem_device *mdev, int notify_id); + int (*kick_subscribe)(struct ste_modem_device *mdev, int notify_id); + int (*setup)(struct ste_modem_device *mdev, + struct ste_modem_dev_cb *cfg); +}; + +/** + * struct ste_modem_device - represent the STE modem device + * @pdev: Reference to platform device + * @ops: Operations used to manage the modem. + * @drv_data: Driver private data. + */ +struct ste_modem_device { + struct platform_device pdev; + struct ste_modem_dev_ops ops; + void *drv_data; +}; + +#endif /*INC_MODEM_DEV_H*/ diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 926142ed8d7a..9497be1ad4c0 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -102,6 +102,7 @@ struct fib_info { unsigned char fib_dead; unsigned char fib_protocol; unsigned char fib_scope; + unsigned char fib_type; __be32 fib_prefsrc; u32 fib_priority; u32 *fib_metrics; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 4faf6612ecac..95e646641184 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -257,10 +257,12 @@ static inline struct net *read_pnet(struct net * const *pnet) #define __net_init #define __net_exit #define __net_initdata +#define __net_initconst #else #define __net_init __init #define __net_exit __exit_refok #define __net_initdata __initdata +#define __net_initconst __initconst #endif struct pernet_operations { diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 0fef00f5d3ce..64158aa1bb5f 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1068,7 +1068,7 @@ void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_teardown(struct sctp_outq *); void sctp_outq_free(struct sctp_outq*); int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk); -int sctp_outq_sack(struct sctp_outq *, struct sctp_sackhdr *); +int sctp_outq_sack(struct sctp_outq *, struct sctp_chunk *); int sctp_outq_is_empty(const struct sctp_outq *); void sctp_outq_restart(struct sctp_outq *); diff --git a/include/xen/events.h b/include/xen/events.h index 04399b28e821..c6bfe01acf6b 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -109,4 +109,6 @@ int xen_irq_from_gsi(unsigned gsi); /* Determine whether to ignore this IRQ if it is passed to a guest. */ int xen_test_irq_shared(int irq); +/* initialize Xen IRQ subsystem */ +void xen_init_IRQ(void); #endif /* _XEN_EVENTS_H */ diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h index b6ca39a069d8..131a6ccdba25 100644 --- a/include/xen/interface/features.h +++ b/include/xen/interface/features.h @@ -50,6 +50,9 @@ /* x86: pirq can be used by HVM guests */ #define XENFEAT_hvm_pirqs 10 +/* operation as Dom0 is supported */ +#define XENFEAT_dom0 11 + #define XENFEAT_NR_SUBMAPS 1 #endif /* __XEN_PUBLIC_FEATURES_H__ */ diff --git a/include/xen/interface/io/protocols.h b/include/xen/interface/io/protocols.h index 01fc8ae5f0b0..0eafaf254fff 100644 --- a/include/xen/interface/io/protocols.h +++ b/include/xen/interface/io/protocols.h @@ -5,6 +5,7 @@ #define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi" #define XEN_IO_PROTO_ABI_IA64 "ia64-abi" #define XEN_IO_PROTO_ABI_POWERPC64 "powerpc64-abi" +#define XEN_IO_PROTO_ABI_ARM "arm-abi" #if defined(__i386__) # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32 @@ -14,6 +15,8 @@ # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64 #elif defined(__powerpc64__) # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64 +#elif defined(__arm__) +# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_ARM #else # error arch fixup needed here #endif diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h index d8e33a93ea4d..b66d04ce6957 100644 --- a/include/xen/interface/memory.h +++ b/include/xen/interface/memory.h @@ -34,7 +34,7 @@ struct xen_memory_reservation { GUEST_HANDLE(xen_pfn_t) extent_start; /* Number of extents, and size/alignment of each (2^extent_order pages). */ - unsigned long nr_extents; + xen_ulong_t nr_extents; unsigned int extent_order; /* @@ -92,7 +92,7 @@ struct xen_memory_exchange { * command will be non-zero. * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER! */ - unsigned long nr_exchanged; + xen_ulong_t nr_exchanged; }; DEFINE_GUEST_HANDLE_STRUCT(xen_memory_exchange); @@ -148,8 +148,8 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mfn_list); */ #define XENMEM_machphys_mapping 12 struct xen_machphys_mapping { - unsigned long v_start, v_end; /* Start and end virtual addresses. */ - unsigned long max_mfn; /* Maximum MFN that can be looked up. */ + xen_ulong_t v_start, v_end; /* Start and end virtual addresses. */ + xen_ulong_t max_mfn; /* Maximum MFN that can be looked up. */ }; DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t); @@ -172,7 +172,7 @@ struct xen_add_to_physmap { unsigned int space; /* Index into source mapping space. */ - unsigned long idx; + xen_ulong_t idx; /* GPFN where the source mapping page should appear. */ xen_pfn_t gpfn; @@ -189,7 +189,7 @@ struct xen_translate_gpfn_list { domid_t domid; /* Length of list. */ - unsigned long nr_gpfns; + xen_ulong_t nr_gpfns; /* List of GPFNs to translate. */ GUEST_HANDLE(ulong) gpfn_list; diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index bfa1d50fe15b..1844d31f4552 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h @@ -56,7 +56,7 @@ struct physdev_eoi { #define PHYSDEVOP_pirq_eoi_gmfn_v2 28 struct physdev_pirq_eoi_gmfn { /* IN */ - unsigned long gmfn; + xen_ulong_t gmfn; }; /* diff --git a/include/xen/interface/version.h b/include/xen/interface/version.h index 5f5e551cf546..7ff6498679a3 100644 --- a/include/xen/interface/version.h +++ b/include/xen/interface/version.h @@ -45,7 +45,7 @@ struct xen_changeset_info { #define XENVER_platform_parameters 5 struct xen_platform_parameters { - unsigned long virt_start; + xen_ulong_t virt_start; }; #define XENVER_get_features 6 diff --git a/include/xen/xen.h b/include/xen/xen.h index a16402418d31..a74d4362c4f8 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -23,8 +23,8 @@ extern enum xen_domain_type xen_domain_type; #include <xen/interface/xen.h> #include <asm/xen/hypervisor.h> -#define xen_initial_domain() (xen_pv_domain() && \ - xen_start_info->flags & SIF_INITDOMAIN) +#define xen_initial_domain() (xen_domain() && \ + xen_start_info && xen_start_info->flags & SIF_INITDOMAIN) #else /* !CONFIG_XEN_DOM0 */ #define xen_initial_domain() (0) #endif /* CONFIG_XEN_DOM0 */ diff --git a/init/Kconfig b/init/Kconfig index cb003a3c9122..ed6334dd5e71 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1199,6 +1199,7 @@ config BUG Just say Y. config ELF_CORE + depends on COREDUMP default y bool "Enable ELF core dumps" if EXPERT help @@ -1581,4 +1582,10 @@ config PADATA depends on SMP bool +# Can be selected by architectures with broken toolchains +# that get confused by correct const<->read_only section +# mappings +config BROKEN_RODATA + bool + source "kernel/Kconfig.locks" diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 43049192b5ec..60f48fa0fd0d 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -118,6 +118,7 @@ void jump_label_rate_limit(struct static_key_deferred *key, key->timeout = rl; INIT_DELAYED_WORK(&key->work, jump_label_update_timeout); } +EXPORT_SYMBOL_GPL(jump_label_rate_limit); static int addr_conflict(struct jump_entry *entry, void *start, void *end) { diff --git a/kernel/kexec.c b/kernel/kexec.c index 0668d58d6413..5e4bd7864c5d 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -21,7 +21,6 @@ #include <linux/hardirq.h> #include <linux/elf.h> #include <linux/elfcore.h> -#include <generated/utsrelease.h> #include <linux/utsname.h> #include <linux/numa.h> #include <linux/suspend.h> diff --git a/kernel/resource.c b/kernel/resource.c index 34d45886ee84..73f35d4b30b9 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -763,6 +763,7 @@ static void __init __reserve_region_with_split(struct resource *root, struct resource *parent = root; struct resource *conflict; struct resource *res = kzalloc(sizeof(*res), GFP_ATOMIC); + struct resource *next_res = NULL; if (!res) return; @@ -772,21 +773,46 @@ static void __init __reserve_region_with_split(struct resource *root, res->end = end; res->flags = IORESOURCE_BUSY; - conflict = __request_resource(parent, res); - if (!conflict) - return; + while (1) { - /* failed, split and try again */ - kfree(res); + conflict = __request_resource(parent, res); + if (!conflict) { + if (!next_res) + break; + res = next_res; + next_res = NULL; + continue; + } - /* conflict covered whole area */ - if (conflict->start <= start && conflict->end >= end) - return; + /* conflict covered whole area */ + if (conflict->start <= res->start && + conflict->end >= res->end) { + kfree(res); + WARN_ON(next_res); + break; + } + + /* failed, split and try again */ + if (conflict->start > res->start) { + end = res->end; + res->end = conflict->start - 1; + if (conflict->end < end) { + next_res = kzalloc(sizeof(*next_res), + GFP_ATOMIC); + if (!next_res) { + kfree(res); + break; + } + next_res->name = name; + next_res->start = conflict->end + 1; + next_res->end = end; + next_res->flags = IORESOURCE_BUSY; + } + } else { + res->start = conflict->end + 1; + } + } - if (conflict->start > start) - __reserve_region_with_split(root, start, conflict->start-1, name); - if (conflict->end < end) - __reserve_region_with_split(root, conflict->end+1, end, name); } void __init reserve_region_with_split(struct resource *root, diff --git a/kernel/signal.c b/kernel/signal.c index 2c681f11b7d2..0af8868525d6 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -17,6 +17,7 @@ #include <linux/fs.h> #include <linux/tty.h> #include <linux/binfmts.h> +#include <linux/coredump.h> #include <linux/security.h> #include <linux/syscalls.h> #include <linux/ptrace.h> @@ -2359,7 +2360,7 @@ relock: * first and our do_group_exit call below will use * that value and ignore the one we pass it. */ - do_coredump(info->si_signo, info->si_signo, regs); + do_coredump(info, regs); } /* diff --git a/kernel/sys.c b/kernel/sys.c index f9492284e5d2..c5cb5b99cb81 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -368,6 +368,7 @@ EXPORT_SYMBOL(unregister_reboot_notifier); void kernel_restart(char *cmd) { kernel_restart_prepare(cmd); + disable_nonboot_cpus(); if (!cmd) printk(KERN_EMERG "Restarting system.\n"); else @@ -2204,7 +2205,7 @@ static int __orderly_poweroff(void) return -ENOMEM; } - ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_NO_WAIT, + ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_WAIT_EXEC, NULL, argv_cleanup, NULL); if (ret == -ENOMEM) argv_free(argv); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 84c76a34e41c..c2a2f8084bad 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -97,10 +97,12 @@ extern int sysctl_overcommit_memory; extern int sysctl_overcommit_ratio; extern int max_threads; -extern int core_uses_pid; extern int suid_dumpable; +#ifdef CONFIG_COREDUMP +extern int core_uses_pid; extern char core_pattern[]; extern unsigned int core_pipe_limit; +#endif extern int pid_max; extern int min_free_kbytes; extern int pid_max_min, pid_max_max; @@ -177,8 +179,10 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +#ifdef CONFIG_COREDUMP static int proc_dostring_coredump(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +#endif #ifdef CONFIG_MAGIC_SYSRQ /* Note: sysrq code uses it's own private copy */ @@ -404,6 +408,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, +#ifdef CONFIG_COREDUMP { .procname = "core_uses_pid", .data = &core_uses_pid, @@ -425,6 +430,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, +#endif #ifdef CONFIG_PROC_SYSCTL { .procname = "tainted", @@ -2036,12 +2042,14 @@ int proc_dointvec_minmax(struct ctl_table *table, int write, static void validate_coredump_safety(void) { +#ifdef CONFIG_COREDUMP if (suid_dumpable == SUID_DUMPABLE_SAFE && core_pattern[0] != '/' && core_pattern[0] != '|') { printk(KERN_WARNING "Unsafe core_pattern used with "\ "suid_dumpable=2. Pipe handler or fully qualified "\ "core dump path required.\n"); } +#endif } static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, @@ -2053,6 +2061,7 @@ static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, return error; } +#ifdef CONFIG_COREDUMP static int proc_dostring_coredump(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2061,6 +2070,7 @@ static int proc_dostring_coredump(struct ctl_table *table, int write, validate_coredump_safety(); return error; } +#endif static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int write, void __user *buffer, diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 610f0838d555..145bb4d3bd4d 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -445,6 +445,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) na = nla_reserve(rep_skb, CGROUPSTATS_TYPE_CGROUP_STATS, sizeof(struct cgroupstats)); if (na == NULL) { + nlmsg_free(rep_skb); rc = -EMSGSIZE; goto err; } diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 35c4565ee8fa..7fba3a98967f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -196,12 +196,13 @@ config LOCKUP_DETECTOR thresholds can be controlled through the sysctl watchdog_thresh. config HARDLOCKUP_DETECTOR - def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI && \ - !HAVE_NMI_WATCHDOG + def_bool y + depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG + depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI config BOOTPARAM_HARDLOCKUP_PANIC bool "Panic (Reboot) On Hard Lockups" - depends on LOCKUP_DETECTOR + depends on HARDLOCKUP_DETECTOR help Say Y here to enable the kernel to panic on "hard lockups", which are bugs that cause the kernel to loop in kernel @@ -212,7 +213,7 @@ config BOOTPARAM_HARDLOCKUP_PANIC config BOOTPARAM_HARDLOCKUP_PANIC_VALUE int - depends on LOCKUP_DETECTOR + depends on HARDLOCKUP_DETECTOR range 0 1 default 0 if !BOOTPARAM_HARDLOCKUP_PANIC default 1 if BOOTPARAM_HARDLOCKUP_PANIC diff --git a/lib/crc32.c b/lib/crc32.c index 61774b8db4de..072fbd8234d5 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -188,11 +188,13 @@ u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) #else u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) { - return crc32_le_generic(crc, p, len, crc32table_le, CRCPOLY_LE); + return crc32_le_generic(crc, p, len, + (const u32 (*)[256])crc32table_le, CRCPOLY_LE); } u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) { - return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE); + return crc32_le_generic(crc, p, len, + (const u32 (*)[256])crc32ctable_le, CRC32C_POLY_LE); } #endif EXPORT_SYMBOL(crc32_le); @@ -253,7 +255,8 @@ u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) #else u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) { - return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE); + return crc32_be_generic(crc, p, len, + (const u32 (*)[256])crc32table_be, CRCPOLY_BE); } #endif EXPORT_SYMBOL(crc32_be); diff --git a/lib/decompress.c b/lib/decompress.c index 3d766b7f60ab..31a804277282 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/string.h> +#include <linux/init.h> #ifndef CONFIG_DECOMPRESS_GZIP # define gunzip NULL @@ -31,11 +32,13 @@ # define unlzo NULL #endif -static const struct compress_format { +struct compress_format { unsigned char magic[2]; const char *name; decompress_fn decompressor; -} compressed_formats[] = { +}; + +static const struct compress_format compressed_formats[] __initdata = { { {037, 0213}, "gzip", gunzip }, { {037, 0236}, "gzip", gunzip }, { {0x42, 0x5a}, "bzip2", bunzip2 }, @@ -45,7 +48,7 @@ static const struct compress_format { { {0, 0}, NULL, NULL } }; -decompress_fn decompress_method(const unsigned char *inbuf, int len, +decompress_fn __init decompress_method(const unsigned char *inbuf, int len, const char **name) { const struct compress_format *cf; diff --git a/lib/gcd.c b/lib/gcd.c index cce4f3cd14b3..3657f129d7b8 100644 --- a/lib/gcd.c +++ b/lib/gcd.c @@ -9,6 +9,9 @@ unsigned long gcd(unsigned long a, unsigned long b) if (a < b) swap(a, b); + + if (!b) + return a; while ((r = a % b) != 0) { a = b; b = r; diff --git a/lib/gen_crc32table.c b/lib/gen_crc32table.c index 8f8d5439e2d9..71fcfcd96410 100644 --- a/lib/gen_crc32table.c +++ b/lib/gen_crc32table.c @@ -109,7 +109,7 @@ int main(int argc, char** argv) if (CRC_LE_BITS > 1) { crc32init_le(); - printf("static const u32 __cacheline_aligned " + printf("static u32 __cacheline_aligned " "crc32table_le[%d][%d] = {", LE_TABLE_ROWS, LE_TABLE_SIZE); output_table(crc32table_le, LE_TABLE_ROWS, @@ -119,7 +119,7 @@ int main(int argc, char** argv) if (CRC_BE_BITS > 1) { crc32init_be(); - printf("static const u32 __cacheline_aligned " + printf("static u32 __cacheline_aligned " "crc32table_be[%d][%d] = {", BE_TABLE_ROWS, BE_TABLE_SIZE); output_table(crc32table_be, LE_TABLE_ROWS, @@ -128,7 +128,7 @@ int main(int argc, char** argv) } if (CRC_LE_BITS > 1) { crc32cinit_le(); - printf("static const u32 __cacheline_aligned " + printf("static u32 __cacheline_aligned " "crc32ctable_le[%d][%d] = {", LE_TABLE_ROWS, LE_TABLE_SIZE); output_table(crc32ctable_le, LE_TABLE_ROWS, diff --git a/lib/genalloc.c b/lib/genalloc.c index 6bc04aab6ec7..ca208a92628c 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -152,6 +152,8 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid) spin_lock_init(&pool->lock); INIT_LIST_HEAD(&pool->chunks); pool->min_alloc_order = min_alloc_order; + pool->algo = gen_pool_first_fit; + pool->data = NULL; } return pool; } @@ -255,8 +257,9 @@ EXPORT_SYMBOL(gen_pool_destroy); * @size: number of bytes to allocate from the pool * * Allocate the requested number of bytes from the specified pool. - * Uses a first-fit algorithm. Can not be used in NMI handler on - * architectures without NMI-safe cmpxchg implementation. + * Uses the pool allocation function (with first-fit algorithm by default). + * Can not be used in NMI handler on architectures without + * NMI-safe cmpxchg implementation. */ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) { @@ -280,8 +283,8 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) end_bit = (chunk->end_addr - chunk->start_addr) >> order; retry: - start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit, - start_bit, nbits, 0); + start_bit = pool->algo(chunk->bits, end_bit, start_bit, nbits, + pool->data); if (start_bit >= end_bit) continue; remain = bitmap_set_ll(chunk->bits, start_bit, nbits); @@ -400,3 +403,80 @@ size_t gen_pool_size(struct gen_pool *pool) return size; } EXPORT_SYMBOL_GPL(gen_pool_size); + +/** + * gen_pool_set_algo - set the allocation algorithm + * @pool: pool to change allocation algorithm + * @algo: custom algorithm function + * @data: additional data used by @algo + * + * Call @algo for each memory allocation in the pool. + * If @algo is NULL use gen_pool_first_fit as default + * memory allocation function. + */ +void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo, void *data) +{ + rcu_read_lock(); + + pool->algo = algo; + if (!pool->algo) + pool->algo = gen_pool_first_fit; + + pool->data = data; + + rcu_read_unlock(); +} +EXPORT_SYMBOL(gen_pool_set_algo); + +/** + * gen_pool_first_fit - find the first available region + * of memory matching the size requirement (no alignment constraint) + * @map: The address to base the search on + * @size: The bitmap size in bits + * @start: The bitnumber to start searching at + * @nr: The number of zeroed bits we're looking for + * @data: additional data - unused + */ +unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size, + unsigned long start, unsigned int nr, void *data) +{ + return bitmap_find_next_zero_area(map, size, start, nr, 0); +} +EXPORT_SYMBOL(gen_pool_first_fit); + +/** + * gen_pool_best_fit - find the best fitting region of memory + * macthing the size requirement (no alignment constraint) + * @map: The address to base the search on + * @size: The bitmap size in bits + * @start: The bitnumber to start searching at + * @nr: The number of zeroed bits we're looking for + * @data: additional data - unused + * + * Iterate over the bitmap to find the smallest free region + * which we can allocate the memory. + */ +unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size, + unsigned long start, unsigned int nr, void *data) +{ + unsigned long start_bit = size; + unsigned long len = size + 1; + unsigned long index; + + index = bitmap_find_next_zero_area(map, size, start, nr, 0); + + while (index < size) { + int next_bit = find_next_bit(map, size, index + nr); + if ((next_bit - index) < len) { + len = next_bit - index; + start_bit = index; + if (len == nr) + return start_bit; + } + index = bitmap_find_next_zero_area(map, size, + next_bit + 1, nr, 0); + } + + return start_bit; +} +EXPORT_SYMBOL(gen_pool_best_fit); diff --git a/lib/idr.c b/lib/idr.c index 4046e29c0a99..648239079dd2 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -20,7 +20,7 @@ * that id to this code and it returns your pointer. * You can release ids at any time. When all ids are released, most of - * the memory is returned (we keep IDR_FREE_MAX) in a local pool so we + * the memory is returned (we keep MAX_IDR_FREE) in a local pool so we * don't need to go to the memory "store" during an id allocate, just * so you don't need to be too concerned about locking and conflicts * with the slab allocator. @@ -122,7 +122,7 @@ static void idr_mark_full(struct idr_layer **pa, int id) */ int idr_pre_get(struct idr *idp, gfp_t gfp_mask) { - while (idp->id_free_cnt < IDR_FREE_MAX) { + while (idp->id_free_cnt < MAX_IDR_FREE) { struct idr_layer *new; new = kmem_cache_zalloc(idr_layer_cache, gfp_mask); if (new == NULL) @@ -179,7 +179,7 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa) sh = IDR_BITS*l; id = ((id >> sh) ^ n ^ m) << sh; } - if ((id >= MAX_ID_BIT) || (id < 0)) + if ((id >= MAX_IDR_BIT) || (id < 0)) return IDR_NOMORE_SPACE; if (l == 0) break; @@ -223,7 +223,7 @@ build_up: * Add a new layer to the top of the tree if the requested * id is larger than the currently allocated space. */ - while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) { + while ((layers < (MAX_IDR_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) { layers++; if (!p->count) { /* special case: if the tree is currently empty, @@ -265,7 +265,7 @@ build_up: static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id) { - struct idr_layer *pa[MAX_LEVEL]; + struct idr_layer *pa[MAX_IDR_LEVEL]; int id; id = idr_get_empty_slot(idp, starting_id, pa); @@ -357,7 +357,7 @@ static void idr_remove_warning(int id) static void sub_remove(struct idr *idp, int shift, int id) { struct idr_layer *p = idp->top; - struct idr_layer **pa[MAX_LEVEL]; + struct idr_layer **pa[MAX_IDR_LEVEL]; struct idr_layer ***paa = &pa[0]; struct idr_layer *to_free; int n; @@ -402,7 +402,7 @@ void idr_remove(struct idr *idp, int id) struct idr_layer *to_free; /* Mask off upper bits we don't use for the search. */ - id &= MAX_ID_MASK; + id &= MAX_IDR_MASK; sub_remove(idp, (idp->layers - 1) * IDR_BITS, id); if (idp->top && idp->top->count == 1 && (idp->layers > 1) && @@ -420,7 +420,7 @@ void idr_remove(struct idr *idp, int id) to_free->bitmap = to_free->count = 0; free_layer(to_free); } - while (idp->id_free_cnt >= IDR_FREE_MAX) { + while (idp->id_free_cnt >= MAX_IDR_FREE) { p = get_from_free_list(idp); /* * Note: we don't call the rcu callback here, since the only @@ -451,7 +451,7 @@ void idr_remove_all(struct idr *idp) int n, id, max; int bt_mask; struct idr_layer *p; - struct idr_layer *pa[MAX_LEVEL]; + struct idr_layer *pa[MAX_IDR_LEVEL]; struct idr_layer **paa = &pa[0]; n = idp->layers * IDR_BITS; @@ -517,7 +517,7 @@ void *idr_find(struct idr *idp, int id) n = (p->layer+1) * IDR_BITS; /* Mask off upper bits we don't use for the search. */ - id &= MAX_ID_MASK; + id &= MAX_IDR_MASK; if (id >= (1 << n)) return NULL; @@ -555,7 +555,7 @@ int idr_for_each(struct idr *idp, { int n, id, max, error = 0; struct idr_layer *p; - struct idr_layer *pa[MAX_LEVEL]; + struct idr_layer *pa[MAX_IDR_LEVEL]; struct idr_layer **paa = &pa[0]; n = idp->layers * IDR_BITS; @@ -601,7 +601,7 @@ EXPORT_SYMBOL(idr_for_each); */ void *idr_get_next(struct idr *idp, int *nextidp) { - struct idr_layer *p, *pa[MAX_LEVEL]; + struct idr_layer *p, *pa[MAX_IDR_LEVEL]; struct idr_layer **paa = &pa[0]; int id = *nextidp; int n, max; @@ -659,7 +659,7 @@ void *idr_replace(struct idr *idp, void *ptr, int id) n = (p->layer+1) * IDR_BITS; - id &= MAX_ID_MASK; + id &= MAX_IDR_MASK; if (id >= (1 << n)) return ERR_PTR(-EINVAL); @@ -780,7 +780,7 @@ EXPORT_SYMBOL(ida_pre_get); */ int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) { - struct idr_layer *pa[MAX_LEVEL]; + struct idr_layer *pa[MAX_IDR_LEVEL]; struct ida_bitmap *bitmap; unsigned long flags; int idr_id = starting_id / IDA_BITMAP_BITS; @@ -793,7 +793,7 @@ int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) if (t < 0) return _idr_rc_to_errno(t); - if (t * IDA_BITMAP_BITS >= MAX_ID_BIT) + if (t * IDA_BITMAP_BITS >= MAX_IDR_BIT) return -ENOSPC; if (t != idr_id) @@ -827,7 +827,7 @@ int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) } id = idr_id * IDA_BITMAP_BITS + t; - if (id >= MAX_ID_BIT) + if (id >= MAX_IDR_BIT) return -ENOSPC; __set_bit(t, bitmap->bitmap); diff --git a/lib/parser.c b/lib/parser.c index c43410084838..52cfa69f73df 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -122,13 +122,14 @@ int match_token(char *s, const match_table_t table, substring_t args[]) * * Description: Given a &substring_t and a base, attempts to parse the substring * as a number in that base. On success, sets @result to the integer represented - * by the string and returns 0. Returns either -ENOMEM or -EINVAL on failure. + * by the string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure. */ static int match_number(substring_t *s, int *result, int base) { char *endp; char *buf; int ret; + long val; size_t len = s->to - s->from; buf = kmalloc(len + 1, GFP_KERNEL); @@ -136,10 +137,15 @@ static int match_number(substring_t *s, int *result, int base) return -ENOMEM; memcpy(buf, s->from, len); buf[len] = '\0'; - *result = simple_strtol(buf, &endp, base); + ret = 0; + val = simple_strtol(buf, &endp, base); if (endp == buf) ret = -EINVAL; + else if (val < (long)INT_MIN || val > (long)INT_MAX) + ret = -ERANGE; + else + *result = (int) val; kfree(buf); return ret; } diff --git a/lib/plist.c b/lib/plist.c index 6ab0e521c48b..1ebc95f7a46f 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -175,7 +175,7 @@ static int __init plist_test(void) int nr_expect = 0, i, loop; unsigned int r = local_clock(); - printk(KERN_INFO "start plist test\n"); + pr_debug("start plist test\n"); plist_head_init(&test_head); for (i = 0; i < ARRAY_SIZE(test_node); i++) plist_node_init(test_node + i, 0); @@ -203,7 +203,7 @@ static int __init plist_test(void) plist_test_check(nr_expect); } - printk(KERN_INFO "end plist test\n"); + pr_debug("end plist test\n"); return 0; } diff --git a/lib/scatterlist.c b/lib/scatterlist.c index fadae774a20c..e76d85cf3175 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -404,14 +404,13 @@ EXPORT_SYMBOL(sg_miter_start); * @miter: sg mapping iter to proceed * * Description: - * Proceeds @miter@ to the next mapping. @miter@ should have been - * started using sg_miter_start(). On successful return, - * @miter@->page, @miter@->addr and @miter@->length point to the - * current mapping. + * Proceeds @miter to the next mapping. @miter should have been started + * using sg_miter_start(). On successful return, @miter->page, + * @miter->addr and @miter->length point to the current mapping. * * Context: - * IRQ disabled if SG_MITER_ATOMIC. IRQ must stay disabled till - * @miter@ is stopped. May sleep if !SG_MITER_ATOMIC. + * Preemption disabled if SG_MITER_ATOMIC. Preemption must stay disabled + * till @miter is stopped. May sleep if !SG_MITER_ATOMIC. * * Returns: * true if @miter contains the next mapping. false if end of sg @@ -465,7 +464,8 @@ EXPORT_SYMBOL(sg_miter_next); * resources (kmap) need to be released during iteration. * * Context: - * IRQ disabled if the SG_MITER_ATOMIC is set. Don't care otherwise. + * Preemption disabled if the SG_MITER_ATOMIC is set. Don't care + * otherwise. */ void sg_miter_stop(struct sg_mapping_iter *miter) { @@ -479,7 +479,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter) flush_kernel_dcache_page(miter->page); if (miter->__flags & SG_MITER_ATOMIC) { - WARN_ON(!irqs_disabled()); + WARN_ON_ONCE(preemptible()); kunmap_atomic(miter->addr); } else kunmap(miter->page); diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c index eb10578ae055..0374a596cffa 100644 --- a/lib/spinlock_debug.c +++ b/lib/spinlock_debug.c @@ -107,23 +107,27 @@ static void __spin_lock_debug(raw_spinlock_t *lock) { u64 i; u64 loops = loops_per_jiffy * HZ; - int print_once = 1; - for (;;) { - for (i = 0; i < loops; i++) { - if (arch_spin_trylock(&lock->raw_lock)) - return; - __delay(1); - } - /* lockup suspected: */ - if (print_once) { - print_once = 0; - spin_dump(lock, "lockup suspected"); + for (i = 0; i < loops; i++) { + if (arch_spin_trylock(&lock->raw_lock)) + return; + __delay(1); + } + /* lockup suspected: */ + spin_dump(lock, "lockup suspected"); #ifdef CONFIG_SMP - trigger_all_cpu_backtrace(); + trigger_all_cpu_backtrace(); #endif - } - } + + /* + * The trylock above was causing a livelock. Give the lower level arch + * specific lock code a chance to acquire the lock. We have already + * printed a warning/backtrace at this point. The non-debug arch + * specific code might actually succeed in acquiring the lock. If it is + * not successful, the end-result is the same - there is no forward + * progress. + */ + arch_spin_lock(&lock->raw_lock); } void do_raw_spin_lock(raw_spinlock_t *lock) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0e337541f005..39c99fea7c03 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -174,35 +174,25 @@ char *put_dec_trunc8(char *buf, unsigned r) unsigned q; /* Copy of previous function's body with added early returns */ - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 2 */ - if (q == 0) - return buf; - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 3 */ - if (r == 0) - return buf; - q = (r * (uint64_t)0x1999999a) >> 32; - *buf++ = (r - 10 * q) + '0'; /* 4 */ - if (q == 0) - return buf; - r = (q * (uint64_t)0x1999999a) >> 32; - *buf++ = (q - 10 * r) + '0'; /* 5 */ - if (r == 0) - return buf; - q = (r * 0x199a) >> 16; - *buf++ = (r - 10 * q) + '0'; /* 6 */ + while (r >= 10000) { + q = r + '0'; + r = (r * (uint64_t)0x1999999a) >> 32; + *buf++ = q - 10*r; + } + + q = (r * 0x199a) >> 16; /* r <= 9999 */ + *buf++ = (r - 10 * q) + '0'; if (q == 0) return buf; - r = (q * 0xcd) >> 11; - *buf++ = (q - 10 * r) + '0'; /* 7 */ + r = (q * 0xcd) >> 11; /* q <= 999 */ + *buf++ = (q - 10 * r) + '0'; if (r == 0) return buf; - q = (r * 0xcd) >> 11; - *buf++ = (r - 10 * q) + '0'; /* 8 */ + q = (r * 0xcd) >> 11; /* r <= 99 */ + *buf++ = (r - 10 * q) + '0'; if (q == 0) return buf; - *buf++ = q + '0'; /* 9 */ + *buf++ = q + '0'; /* q <= 9 */ return buf; } @@ -243,18 +233,34 @@ char *put_dec(char *buf, unsigned long long n) /* Second algorithm: valid only for 64-bit long longs */ +/* See comment in put_dec_full9 for choice of constants */ static noinline_for_stack -char *put_dec_full4(char *buf, unsigned q) +void put_dec_full4(char *buf, unsigned q) { unsigned r; - r = (q * 0xcccd) >> 19; - *buf++ = (q - 10 * r) + '0'; - q = (r * 0x199a) >> 16; - *buf++ = (r - 10 * q) + '0'; + r = (q * 0xccd) >> 15; + buf[0] = (q - 10 * r) + '0'; + q = (r * 0xcd) >> 11; + buf[1] = (r - 10 * q) + '0'; r = (q * 0xcd) >> 11; - *buf++ = (q - 10 * r) + '0'; - *buf++ = r + '0'; - return buf; + buf[2] = (q - 10 * r) + '0'; + buf[3] = r + '0'; +} + +/* + * Call put_dec_full4 on x % 10000, return x / 10000. + * The approximation x/10000 == (x * 0x346DC5D7) >> 43 + * holds for all x < 1,128,869,999. The largest value this + * helper will ever be asked to convert is 1,125,520,955. + * (d1 in the put_dec code, assuming n is all-ones). + */ +static +unsigned put_dec_helper4(char *buf, unsigned x) +{ + uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; + + put_dec_full4(buf, x - q * 10000); + return q; } /* Based on code by Douglas W. Jones found at @@ -276,28 +282,19 @@ char *put_dec(char *buf, unsigned long long n) d3 = (h >> 16); /* implicit "& 0xffff" */ q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); + q = put_dec_helper4(buf, q); + + q += 7671 * d3 + 9496 * d2 + 6 * d1; + q = put_dec_helper4(buf+4, q); + + q += 4749 * d3 + 42 * d2; + q = put_dec_helper4(buf+8, q); - buf = put_dec_full4(buf, q % 10000); - q = q / 10000; - - d1 = q + 7671 * d3 + 9496 * d2 + 6 * d1; - buf = put_dec_full4(buf, d1 % 10000); - q = d1 / 10000; - - d2 = q + 4749 * d3 + 42 * d2; - buf = put_dec_full4(buf, d2 % 10000); - q = d2 / 10000; - - d3 = q + 281 * d3; - if (!d3) - goto done; - buf = put_dec_full4(buf, d3 % 10000); - q = d3 / 10000; - if (!q) - goto done; - buf = put_dec_full4(buf, q); - done: - while (buf[-1] == '0') + q += 281 * d3; + buf += 12; + if (q) + buf = put_dec_trunc8(buf, q); + else while (buf[-1] == '0') --buf; return buf; @@ -990,7 +987,7 @@ int kptr_restrict __read_mostly; * - 'm' For a 6-byte MAC address, it prints the hex address without colons * - 'MF' For a 6-byte MAC FDDI address, it prints the address * with a dash-separated hex notation - * - '[mM]R For a 6-byte MAC address, Reverse order (Bluetooth) + * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth) * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) * IPv6 uses colon separated network-order 16 bit hex with leading 0's @@ -1341,7 +1338,10 @@ qualifier: * %pR output the address range in a struct resource with decoded flags * %pr output the address range in a struct resource with raw flags * %pM output a 6-byte MAC address with colons + * %pMR output a 6-byte MAC address with colons in reversed order + * %pMF output a 6-byte MAC address with dashes * %pm output a 6-byte MAC address without colons + * %pmR output a 6-byte MAC address without colons in reversed order * %pI4 print an IPv4 address without leading zeros * %pi4 print an IPv4 address with leading zeros * %pI6 print an IPv6 address with colons @@ -2017,7 +2017,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args) s16 field_width; bool is_sign; - while (*fmt && *str) { + while (*fmt) { /* skip any white space in format */ /* white space in format matchs any amount of * white space, including none, in the input. @@ -2042,6 +2042,8 @@ int vsscanf(const char *buf, const char *fmt, va_list args) * advance both strings to next white space */ if (*fmt == '*') { + if (!*str) + break; while (!isspace(*fmt) && *fmt != '%' && *fmt) fmt++; while (!isspace(*str) && *str) @@ -2070,7 +2072,17 @@ int vsscanf(const char *buf, const char *fmt, va_list args) } } - if (!*fmt || !*str) + if (!*fmt) + break; + + if (*fmt == 'n') { + /* return number of characters read so far */ + *va_arg(args, int *) = str - buf; + ++fmt; + continue; + } + + if (!*str) break; base = 10; @@ -2103,13 +2115,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args) num++; } continue; - case 'n': - /* return number of characters read so far */ - { - int *i = (int *)va_arg(args, int*); - *i = str - buf; - } - continue; case 'o': base = 8; break; @@ -2210,16 +2215,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args) str = next; } - /* - * Now we've come all the way through so either the input string or the - * format ended. In the former case, there can be a %n at the current - * position in the format that needs to be filled. - */ - if (*fmt == '%' && *(fmt + 1) == 'n') { - int *p = (int *)va_arg(args, int *); - *p = str - buf; - } - return num; } EXPORT_SYMBOL(vsscanf); diff --git a/mm/percpu.c b/mm/percpu.c index bb4be7435ce3..ddc5efb9c5bb 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1370,7 +1370,7 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, #ifdef CONFIG_SMP -const char *pcpu_fc_names[PCPU_FC_NR] __initdata = { +const char * const pcpu_fc_names[PCPU_FC_NR] __initconst = { [PCPU_FC_AUTO] = "auto", [PCPU_FC_EMBED] = "embed", [PCPU_FC_PAGE] = "page", diff --git a/mm/slab.c b/mm/slab.c index 11339110271e..33d3363658df 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -498,14 +498,6 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp) #endif -#ifdef CONFIG_TRACING -size_t slab_buffer_size(struct kmem_cache *cachep) -{ - return cachep->size; -} -EXPORT_SYMBOL(slab_buffer_size); -#endif - /* * Do not go above this order unless 0 objects fit into the slab or * overridden on the command line. @@ -515,13 +507,6 @@ EXPORT_SYMBOL(slab_buffer_size); static int slab_max_order = SLAB_MAX_ORDER_LO; static bool slab_max_order_set __initdata; -static inline struct kmem_cache *page_get_cache(struct page *page) -{ - page = compound_head(page); - BUG_ON(!PageSlab(page)); - return page->slab_cache; -} - static inline struct kmem_cache *virt_to_cache(const void *obj) { struct page *page = virt_to_head_page(obj); @@ -585,9 +570,9 @@ static struct arraycache_init initarray_generic = { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; /* internal cache of cache description objs */ -static struct kmem_list3 *cache_cache_nodelists[MAX_NUMNODES]; -static struct kmem_cache cache_cache = { - .nodelists = cache_cache_nodelists, +static struct kmem_list3 *kmem_cache_nodelists[MAX_NUMNODES]; +static struct kmem_cache kmem_cache_boot = { + .nodelists = kmem_cache_nodelists, .batchcount = 1, .limit = BOOT_CPUCACHE_ENTRIES, .shared = 1, @@ -810,6 +795,7 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size, *left_over = slab_size - nr_objs*buffer_size - mgmt_size; } +#if DEBUG #define slab_error(cachep, msg) __slab_error(__func__, cachep, msg) static void __slab_error(const char *function, struct kmem_cache *cachep, @@ -818,7 +804,9 @@ static void __slab_error(const char *function, struct kmem_cache *cachep, printk(KERN_ERR "slab error in %s(): cache `%s': %s\n", function, cachep->name, msg); dump_stack(); + add_taint(TAINT_BAD_PAGE); } +#endif /* * By default on NUMA we use alien caches to stage the freeing of @@ -1601,15 +1589,17 @@ void __init kmem_cache_init(void) int order; int node; + kmem_cache = &kmem_cache_boot; + if (num_possible_nodes() == 1) use_alien_caches = 0; for (i = 0; i < NUM_INIT_LISTS; i++) { kmem_list3_init(&initkmem_list3[i]); if (i < MAX_NUMNODES) - cache_cache.nodelists[i] = NULL; + kmem_cache->nodelists[i] = NULL; } - set_up_list3s(&cache_cache, CACHE_CACHE); + set_up_list3s(kmem_cache, CACHE_CACHE); /* * Fragmentation resistance on low memory - only use bigger @@ -1621,9 +1611,9 @@ void __init kmem_cache_init(void) /* Bootstrap is tricky, because several objects are allocated * from caches that do not exist yet: - * 1) initialize the cache_cache cache: it contains the struct - * kmem_cache structures of all caches, except cache_cache itself: - * cache_cache is statically allocated. + * 1) initialize the kmem_cache cache: it contains the struct + * kmem_cache structures of all caches, except kmem_cache itself: + * kmem_cache is statically allocated. * Initially an __init data area is used for the head array and the * kmem_list3 structures, it's replaced with a kmalloc allocated * array at the end of the bootstrap. @@ -1632,43 +1622,43 @@ void __init kmem_cache_init(void) * An __init data area is used for the head array. * 3) Create the remaining kmalloc caches, with minimally sized * head arrays. - * 4) Replace the __init data head arrays for cache_cache and the first + * 4) Replace the __init data head arrays for kmem_cache and the first * kmalloc cache with kmalloc allocated arrays. - * 5) Replace the __init data for kmem_list3 for cache_cache and + * 5) Replace the __init data for kmem_list3 for kmem_cache and * the other cache's with kmalloc allocated memory. * 6) Resize the head arrays of the kmalloc caches to their final sizes. */ node = numa_mem_id(); - /* 1) create the cache_cache */ + /* 1) create the kmem_cache */ INIT_LIST_HEAD(&slab_caches); - list_add(&cache_cache.list, &slab_caches); - cache_cache.colour_off = cache_line_size(); - cache_cache.array[smp_processor_id()] = &initarray_cache.cache; - cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node]; + list_add(&kmem_cache->list, &slab_caches); + kmem_cache->colour_off = cache_line_size(); + kmem_cache->array[smp_processor_id()] = &initarray_cache.cache; + kmem_cache->nodelists[node] = &initkmem_list3[CACHE_CACHE + node]; /* * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids */ - cache_cache.size = offsetof(struct kmem_cache, array[nr_cpu_ids]) + + kmem_cache->size = offsetof(struct kmem_cache, array[nr_cpu_ids]) + nr_node_ids * sizeof(struct kmem_list3 *); - cache_cache.object_size = cache_cache.size; - cache_cache.size = ALIGN(cache_cache.size, + kmem_cache->object_size = kmem_cache->size; + kmem_cache->size = ALIGN(kmem_cache->object_size, cache_line_size()); - cache_cache.reciprocal_buffer_size = - reciprocal_value(cache_cache.size); + kmem_cache->reciprocal_buffer_size = + reciprocal_value(kmem_cache->size); for (order = 0; order < MAX_ORDER; order++) { - cache_estimate(order, cache_cache.size, - cache_line_size(), 0, &left_over, &cache_cache.num); - if (cache_cache.num) + cache_estimate(order, kmem_cache->size, + cache_line_size(), 0, &left_over, &kmem_cache->num); + if (kmem_cache->num) break; } - BUG_ON(!cache_cache.num); - cache_cache.gfporder = order; - cache_cache.colour = left_over / cache_cache.colour_off; - cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) + + BUG_ON(!kmem_cache->num); + kmem_cache->gfporder = order; + kmem_cache->colour = left_over / kmem_cache->colour_off; + kmem_cache->slab_size = ALIGN(kmem_cache->num * sizeof(kmem_bufctl_t) + sizeof(struct slab), cache_line_size()); /* 2+3) create the kmalloc caches */ @@ -1681,19 +1671,22 @@ void __init kmem_cache_init(void) * bug. */ - sizes[INDEX_AC].cs_cachep = __kmem_cache_create(names[INDEX_AC].name, - sizes[INDEX_AC].cs_size, - ARCH_KMALLOC_MINALIGN, - ARCH_KMALLOC_FLAGS|SLAB_PANIC, - NULL); + sizes[INDEX_AC].cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); + sizes[INDEX_AC].cs_cachep->name = names[INDEX_AC].name; + sizes[INDEX_AC].cs_cachep->size = sizes[INDEX_AC].cs_size; + sizes[INDEX_AC].cs_cachep->object_size = sizes[INDEX_AC].cs_size; + sizes[INDEX_AC].cs_cachep->align = ARCH_KMALLOC_MINALIGN; + __kmem_cache_create(sizes[INDEX_AC].cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC); + list_add(&sizes[INDEX_AC].cs_cachep->list, &slab_caches); if (INDEX_AC != INDEX_L3) { - sizes[INDEX_L3].cs_cachep = - __kmem_cache_create(names[INDEX_L3].name, - sizes[INDEX_L3].cs_size, - ARCH_KMALLOC_MINALIGN, - ARCH_KMALLOC_FLAGS|SLAB_PANIC, - NULL); + sizes[INDEX_L3].cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); + sizes[INDEX_L3].cs_cachep->name = names[INDEX_L3].name; + sizes[INDEX_L3].cs_cachep->size = sizes[INDEX_L3].cs_size; + sizes[INDEX_L3].cs_cachep->object_size = sizes[INDEX_L3].cs_size; + sizes[INDEX_L3].cs_cachep->align = ARCH_KMALLOC_MINALIGN; + __kmem_cache_create(sizes[INDEX_L3].cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC); + list_add(&sizes[INDEX_L3].cs_cachep->list, &slab_caches); } slab_early_init = 0; @@ -1707,20 +1700,23 @@ void __init kmem_cache_init(void) * allow tighter packing of the smaller caches. */ if (!sizes->cs_cachep) { - sizes->cs_cachep = __kmem_cache_create(names->name, - sizes->cs_size, - ARCH_KMALLOC_MINALIGN, - ARCH_KMALLOC_FLAGS|SLAB_PANIC, - NULL); + sizes->cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); + sizes->cs_cachep->name = names->name; + sizes->cs_cachep->size = sizes->cs_size; + sizes->cs_cachep->object_size = sizes->cs_size; + sizes->cs_cachep->align = ARCH_KMALLOC_MINALIGN; + __kmem_cache_create(sizes->cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC); + list_add(&sizes->cs_cachep->list, &slab_caches); } #ifdef CONFIG_ZONE_DMA - sizes->cs_dmacachep = __kmem_cache_create( - names->name_dma, - sizes->cs_size, - ARCH_KMALLOC_MINALIGN, - ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| - SLAB_PANIC, - NULL); + sizes->cs_dmacachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); + sizes->cs_dmacachep->name = names->name_dma; + sizes->cs_dmacachep->size = sizes->cs_size; + sizes->cs_dmacachep->object_size = sizes->cs_size; + sizes->cs_dmacachep->align = ARCH_KMALLOC_MINALIGN; + __kmem_cache_create(sizes->cs_dmacachep, + ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| SLAB_PANIC); + list_add(&sizes->cs_dmacachep->list, &slab_caches); #endif sizes++; names++; @@ -1731,15 +1727,15 @@ void __init kmem_cache_init(void) ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT); - BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache); - memcpy(ptr, cpu_cache_get(&cache_cache), + BUG_ON(cpu_cache_get(kmem_cache) != &initarray_cache.cache); + memcpy(ptr, cpu_cache_get(kmem_cache), sizeof(struct arraycache_init)); /* * Do not assume that spinlocks can be initialized via memcpy: */ spin_lock_init(&ptr->lock); - cache_cache.array[smp_processor_id()] = ptr; + kmem_cache->array[smp_processor_id()] = ptr; ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT); @@ -1760,7 +1756,7 @@ void __init kmem_cache_init(void) int nid; for_each_online_node(nid) { - init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid); + init_list(kmem_cache, &initkmem_list3[CACHE_CACHE + nid], nid); init_list(malloc_sizes[INDEX_AC].cs_cachep, &initkmem_list3[SIZE_AC + nid], nid); @@ -1781,9 +1777,6 @@ void __init kmem_cache_init_late(void) slab_state = UP; - /* Annotate slab for lockdep -- annotate the malloc caches */ - init_lock_keys(); - /* 6) resize the head arrays to their final sizes */ mutex_lock(&slab_mutex); list_for_each_entry(cachep, &slab_caches, list) @@ -1791,6 +1784,9 @@ void __init kmem_cache_init_late(void) BUG(); mutex_unlock(&slab_mutex); + /* Annotate slab for lockdep -- annotate the malloc caches */ + init_lock_keys(); + /* Done! */ slab_state = FULL; @@ -2209,27 +2205,6 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp) } } -static void __kmem_cache_destroy(struct kmem_cache *cachep) -{ - int i; - struct kmem_list3 *l3; - - for_each_online_cpu(i) - kfree(cachep->array[i]); - - /* NUMA: free the list3 structures */ - for_each_online_node(i) { - l3 = cachep->nodelists[i]; - if (l3) { - kfree(l3->shared); - free_alien_cache(l3->alien); - kfree(l3); - } - } - kmem_cache_free(&cache_cache, cachep); -} - - /** * calculate_slab_order - calculate size (page order) of slabs * @cachep: pointer to the cache that is being created @@ -2366,9 +2341,6 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) * Cannot be called within a int, but can be interrupted. * The @ctor is run when new pages are allocated by the cache. * - * @name must be valid until the cache is destroyed. This implies that - * the module calling this has to destroy the cache before getting unloaded. - * * The flags are * * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5) @@ -2381,13 +2353,13 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp) * cacheline. This can be beneficial if you're counting cycles as closely * as davem. */ -struct kmem_cache * -__kmem_cache_create (const char *name, size_t size, size_t align, - unsigned long flags, void (*ctor)(void *)) +int +__kmem_cache_create (struct kmem_cache *cachep, unsigned long flags) { size_t left_over, slab_size, ralign; - struct kmem_cache *cachep = NULL; gfp_t gfp; + int err; + size_t size = cachep->size; #if DEBUG #if FORCED_DEBUG @@ -2459,8 +2431,8 @@ __kmem_cache_create (const char *name, size_t size, size_t align, ralign = ARCH_SLAB_MINALIGN; } /* 3) caller mandated alignment */ - if (ralign < align) { - ralign = align; + if (ralign < cachep->align) { + ralign = cachep->align; } /* disable debug if necessary */ if (ralign > __alignof__(unsigned long long)) @@ -2468,21 +2440,14 @@ __kmem_cache_create (const char *name, size_t size, size_t align, /* * 4) Store it. */ - align = ralign; + cachep->align = ralign; if (slab_is_available()) gfp = GFP_KERNEL; else gfp = GFP_NOWAIT; - /* Get cache's description obj. */ - cachep = kmem_cache_zalloc(&cache_cache, gfp); - if (!cachep) - return NULL; - cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids]; - cachep->object_size = size; - cachep->align = align; #if DEBUG /* @@ -2506,8 +2471,9 @@ __kmem_cache_create (const char *name, size_t size, size_t align, } #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) if (size >= malloc_sizes[INDEX_L3 + 1].cs_size - && cachep->object_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) { - cachep->obj_offset += PAGE_SIZE - ALIGN(size, align); + && cachep->object_size > cache_line_size() + && ALIGN(size, cachep->align) < PAGE_SIZE) { + cachep->obj_offset += PAGE_SIZE - ALIGN(size, cachep->align); size = PAGE_SIZE; } #endif @@ -2527,18 +2493,15 @@ __kmem_cache_create (const char *name, size_t size, size_t align, */ flags |= CFLGS_OFF_SLAB; - size = ALIGN(size, align); + size = ALIGN(size, cachep->align); - left_over = calculate_slab_order(cachep, size, align, flags); + left_over = calculate_slab_order(cachep, size, cachep->align, flags); + + if (!cachep->num) + return -E2BIG; - if (!cachep->num) { - printk(KERN_ERR - "kmem_cache_create: couldn't create cache %s.\n", name); - kmem_cache_free(&cache_cache, cachep); - return NULL; - } slab_size = ALIGN(cachep->num * sizeof(kmem_bufctl_t) - + sizeof(struct slab), align); + + sizeof(struct slab), cachep->align); /* * If the slab has been placed off-slab, and we have enough space then @@ -2566,8 +2529,8 @@ __kmem_cache_create (const char *name, size_t size, size_t align, cachep->colour_off = cache_line_size(); /* Offset must be a multiple of the alignment. */ - if (cachep->colour_off < align) - cachep->colour_off = align; + if (cachep->colour_off < cachep->align) + cachep->colour_off = cachep->align; cachep->colour = left_over / cachep->colour_off; cachep->slab_size = slab_size; cachep->flags = flags; @@ -2588,12 +2551,11 @@ __kmem_cache_create (const char *name, size_t size, size_t align, */ BUG_ON(ZERO_OR_NULL_PTR(cachep->slabp_cache)); } - cachep->ctor = ctor; - cachep->name = name; - if (setup_cpu_cache(cachep, gfp)) { - __kmem_cache_destroy(cachep); - return NULL; + err = setup_cpu_cache(cachep, gfp); + if (err) { + __kmem_cache_shutdown(cachep); + return err; } if (flags & SLAB_DEBUG_OBJECTS) { @@ -2606,9 +2568,7 @@ __kmem_cache_create (const char *name, size_t size, size_t align, slab_set_debugobj_lock_classes(cachep); } - /* cache setup completed, link it into the list */ - list_add(&cachep->list, &slab_caches); - return cachep; + return 0; } #if DEBUG @@ -2767,49 +2727,29 @@ int kmem_cache_shrink(struct kmem_cache *cachep) } EXPORT_SYMBOL(kmem_cache_shrink); -/** - * kmem_cache_destroy - delete a cache - * @cachep: the cache to destroy - * - * Remove a &struct kmem_cache object from the slab cache. - * - * It is expected this function will be called by a module when it is - * unloaded. This will remove the cache completely, and avoid a duplicate - * cache being allocated each time a module is loaded and unloaded, if the - * module doesn't have persistent in-kernel storage across loads and unloads. - * - * The cache must be empty before calling this function. - * - * The caller must guarantee that no one will allocate memory from the cache - * during the kmem_cache_destroy(). - */ -void kmem_cache_destroy(struct kmem_cache *cachep) +int __kmem_cache_shutdown(struct kmem_cache *cachep) { - BUG_ON(!cachep || in_interrupt()); + int i; + struct kmem_list3 *l3; + int rc = __cache_shrink(cachep); - /* Find the cache in the chain of caches. */ - get_online_cpus(); - mutex_lock(&slab_mutex); - /* - * the chain is never empty, cache_cache is never destroyed - */ - list_del(&cachep->list); - if (__cache_shrink(cachep)) { - slab_error(cachep, "Can't free all objects"); - list_add(&cachep->list, &slab_caches); - mutex_unlock(&slab_mutex); - put_online_cpus(); - return; - } + if (rc) + return rc; - if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU)) - rcu_barrier(); + for_each_online_cpu(i) + kfree(cachep->array[i]); - __kmem_cache_destroy(cachep); - mutex_unlock(&slab_mutex); - put_online_cpus(); + /* NUMA: free the list3 structures */ + for_each_online_node(i) { + l3 = cachep->nodelists[i]; + if (l3) { + kfree(l3->shared); + free_alien_cache(l3->alien); + kfree(l3); + } + } + return 0; } -EXPORT_SYMBOL(kmem_cache_destroy); /* * Get the memory for a slab management obj. @@ -3098,7 +3038,7 @@ static inline void verify_redzone_free(struct kmem_cache *cache, void *obj) } static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp, - void *caller) + unsigned long caller) { struct page *page; unsigned int objnr; @@ -3118,7 +3058,7 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp, *dbg_redzone2(cachep, objp) = RED_INACTIVE; } if (cachep->flags & SLAB_STORE_USER) - *dbg_userword(cachep, objp) = caller; + *dbg_userword(cachep, objp) = (void *)caller; objnr = obj_to_index(cachep, slabp, objp); @@ -3131,7 +3071,7 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp, if (cachep->flags & SLAB_POISON) { #ifdef CONFIG_DEBUG_PAGEALLOC if ((cachep->size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) { - store_stackinfo(cachep, objp, (unsigned long)caller); + store_stackinfo(cachep, objp, caller); kernel_map_pages(virt_to_page(objp), cachep->size / PAGE_SIZE, 0); } else { @@ -3285,7 +3225,7 @@ static inline void cache_alloc_debugcheck_before(struct kmem_cache *cachep, #if DEBUG static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep, - gfp_t flags, void *objp, void *caller) + gfp_t flags, void *objp, unsigned long caller) { if (!objp) return objp; @@ -3302,7 +3242,7 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep, poison_obj(cachep, objp, POISON_INUSE); } if (cachep->flags & SLAB_STORE_USER) - *dbg_userword(cachep, objp) = caller; + *dbg_userword(cachep, objp) = (void *)caller; if (cachep->flags & SLAB_RED_ZONE) { if (*dbg_redzone1(cachep, objp) != RED_INACTIVE || @@ -3343,7 +3283,7 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep, static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags) { - if (cachep == &cache_cache) + if (cachep == kmem_cache) return false; return should_failslab(cachep->object_size, flags, cachep->flags); @@ -3576,8 +3516,8 @@ done: * Fallback to other node is possible if __GFP_THISNODE is not set. */ static __always_inline void * -__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, - void *caller) +slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, + unsigned long caller) { unsigned long save_flags; void *ptr; @@ -3663,7 +3603,7 @@ __do_cache_alloc(struct kmem_cache *cachep, gfp_t flags) #endif /* CONFIG_NUMA */ static __always_inline void * -__cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller) +slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller) { unsigned long save_flags; void *objp; @@ -3799,7 +3739,7 @@ free_done: * be in this state _before_ it is released. Called with disabled ints. */ static inline void __cache_free(struct kmem_cache *cachep, void *objp, - void *caller) + unsigned long caller) { struct array_cache *ac = cpu_cache_get(cachep); @@ -3839,7 +3779,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp, */ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) { - void *ret = __cache_alloc(cachep, flags, __builtin_return_address(0)); + void *ret = slab_alloc(cachep, flags, _RET_IP_); trace_kmem_cache_alloc(_RET_IP_, ret, cachep->object_size, cachep->size, flags); @@ -3850,14 +3790,14 @@ EXPORT_SYMBOL(kmem_cache_alloc); #ifdef CONFIG_TRACING void * -kmem_cache_alloc_trace(size_t size, struct kmem_cache *cachep, gfp_t flags) +kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size) { void *ret; - ret = __cache_alloc(cachep, flags, __builtin_return_address(0)); + ret = slab_alloc(cachep, flags, _RET_IP_); trace_kmalloc(_RET_IP_, ret, - size, slab_buffer_size(cachep), flags); + size, cachep->size, flags); return ret; } EXPORT_SYMBOL(kmem_cache_alloc_trace); @@ -3866,8 +3806,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_trace); #ifdef CONFIG_NUMA void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) { - void *ret = __cache_alloc_node(cachep, flags, nodeid, - __builtin_return_address(0)); + void *ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_); trace_kmem_cache_alloc_node(_RET_IP_, ret, cachep->object_size, cachep->size, @@ -3878,17 +3817,17 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) EXPORT_SYMBOL(kmem_cache_alloc_node); #ifdef CONFIG_TRACING -void *kmem_cache_alloc_node_trace(size_t size, - struct kmem_cache *cachep, +void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep, gfp_t flags, - int nodeid) + int nodeid, + size_t size) { void *ret; - ret = __cache_alloc_node(cachep, flags, nodeid, - __builtin_return_address(0)); + ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_); + trace_kmalloc_node(_RET_IP_, ret, - size, slab_buffer_size(cachep), + size, cachep->size, flags, nodeid); return ret; } @@ -3896,34 +3835,33 @@ EXPORT_SYMBOL(kmem_cache_alloc_node_trace); #endif static __always_inline void * -__do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller) +__do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller) { struct kmem_cache *cachep; cachep = kmem_find_general_cachep(size, flags); if (unlikely(ZERO_OR_NULL_PTR(cachep))) return cachep; - return kmem_cache_alloc_node_trace(size, cachep, flags, node); + return kmem_cache_alloc_node_trace(cachep, flags, node, size); } #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING) void *__kmalloc_node(size_t size, gfp_t flags, int node) { - return __do_kmalloc_node(size, flags, node, - __builtin_return_address(0)); + return __do_kmalloc_node(size, flags, node, _RET_IP_); } EXPORT_SYMBOL(__kmalloc_node); void *__kmalloc_node_track_caller(size_t size, gfp_t flags, int node, unsigned long caller) { - return __do_kmalloc_node(size, flags, node, (void *)caller); + return __do_kmalloc_node(size, flags, node, caller); } EXPORT_SYMBOL(__kmalloc_node_track_caller); #else void *__kmalloc_node(size_t size, gfp_t flags, int node) { - return __do_kmalloc_node(size, flags, node, NULL); + return __do_kmalloc_node(size, flags, node, 0); } EXPORT_SYMBOL(__kmalloc_node); #endif /* CONFIG_DEBUG_SLAB || CONFIG_TRACING */ @@ -3936,7 +3874,7 @@ EXPORT_SYMBOL(__kmalloc_node); * @caller: function caller for debug tracking of the caller */ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, - void *caller) + unsigned long caller) { struct kmem_cache *cachep; void *ret; @@ -3949,9 +3887,9 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, cachep = __find_general_cachep(size, flags); if (unlikely(ZERO_OR_NULL_PTR(cachep))) return cachep; - ret = __cache_alloc(cachep, flags, caller); + ret = slab_alloc(cachep, flags, caller); - trace_kmalloc((unsigned long) caller, ret, + trace_kmalloc(caller, ret, size, cachep->size, flags); return ret; @@ -3961,20 +3899,20 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING) void *__kmalloc(size_t size, gfp_t flags) { - return __do_kmalloc(size, flags, __builtin_return_address(0)); + return __do_kmalloc(size, flags, _RET_IP_); } EXPORT_SYMBOL(__kmalloc); void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller) { - return __do_kmalloc(size, flags, (void *)caller); + return __do_kmalloc(size, flags, caller); } EXPORT_SYMBOL(__kmalloc_track_caller); #else void *__kmalloc(size_t size, gfp_t flags) { - return __do_kmalloc(size, flags, NULL); + return __do_kmalloc(size, flags, 0); } EXPORT_SYMBOL(__kmalloc); #endif @@ -3995,7 +3933,7 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp) debug_check_no_locks_freed(objp, cachep->object_size); if (!(cachep->flags & SLAB_DEBUG_OBJECTS)) debug_check_no_obj_freed(objp, cachep->object_size); - __cache_free(cachep, objp, __builtin_return_address(0)); + __cache_free(cachep, objp, _RET_IP_); local_irq_restore(flags); trace_kmem_cache_free(_RET_IP_, objp); @@ -4026,7 +3964,7 @@ void kfree(const void *objp) debug_check_no_locks_freed(objp, c->object_size); debug_check_no_obj_freed(objp, c->object_size); - __cache_free(c, (void *)objp, __builtin_return_address(0)); + __cache_free(c, (void *)objp, _RET_IP_); local_irq_restore(flags); } EXPORT_SYMBOL(kfree); diff --git a/mm/slab.h b/mm/slab.h index db7848caaa25..7deeb449a301 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -25,9 +25,26 @@ extern enum slab_state slab_state; /* The slab cache mutex protects the management structures during changes */ extern struct mutex slab_mutex; + +/* The list of all slab caches on the system */ extern struct list_head slab_caches; -struct kmem_cache *__kmem_cache_create(const char *name, size_t size, +/* The slab cache that manages slab cache information */ +extern struct kmem_cache *kmem_cache; + +/* Functions provided by the slab allocators */ +extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags); + +#ifdef CONFIG_SLUB +struct kmem_cache *__kmem_cache_alias(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *)); +#else +static inline struct kmem_cache *__kmem_cache_alias(const char *name, size_t size, + size_t align, unsigned long flags, void (*ctor)(void *)) +{ return NULL; } +#endif + + +int __kmem_cache_shutdown(struct kmem_cache *); #endif diff --git a/mm/slab_common.c b/mm/slab_common.c index aa3ca5bb01b5..9c217255ac49 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -22,6 +22,53 @@ enum slab_state slab_state; LIST_HEAD(slab_caches); DEFINE_MUTEX(slab_mutex); +struct kmem_cache *kmem_cache; + +#ifdef CONFIG_DEBUG_VM +static int kmem_cache_sanity_check(const char *name, size_t size) +{ + struct kmem_cache *s = NULL; + + if (!name || in_interrupt() || size < sizeof(void *) || + size > KMALLOC_MAX_SIZE) { + pr_err("kmem_cache_create(%s) integrity check failed\n", name); + return -EINVAL; + } + + list_for_each_entry(s, &slab_caches, list) { + char tmp; + int res; + + /* + * This happens when the module gets unloaded and doesn't + * destroy its slab cache and no-one else reuses the vmalloc + * area of the module. Print a warning. + */ + res = probe_kernel_address(s->name, tmp); + if (res) { + pr_err("Slab cache with size %d has lost its name\n", + s->object_size); + continue; + } + + if (!strcmp(s->name, name)) { + pr_err("%s (%s): Cache name already exists.\n", + __func__, name); + dump_stack(); + s = NULL; + return -EINVAL; + } + } + + WARN_ON(strchr(name, ' ')); /* It confuses parsers */ + return 0; +} +#else +static inline int kmem_cache_sanity_check(const char *name, size_t size) +{ + return 0; +} +#endif /* * kmem_cache_create - Create a cache. @@ -52,68 +99,92 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align unsigned long flags, void (*ctor)(void *)) { struct kmem_cache *s = NULL; - -#ifdef CONFIG_DEBUG_VM - if (!name || in_interrupt() || size < sizeof(void *) || - size > KMALLOC_MAX_SIZE) { - printk(KERN_ERR "kmem_cache_create(%s) integrity check" - " failed\n", name); - goto out; - } -#endif + int err = 0; get_online_cpus(); mutex_lock(&slab_mutex); -#ifdef CONFIG_DEBUG_VM - list_for_each_entry(s, &slab_caches, list) { - char tmp; - int res; + if (!kmem_cache_sanity_check(name, size) == 0) + goto out_locked; - /* - * This happens when the module gets unloaded and doesn't - * destroy its slab cache and no-one else reuses the vmalloc - * area of the module. Print a warning. - */ - res = probe_kernel_address(s->name, tmp); - if (res) { - printk(KERN_ERR - "Slab cache with size %d has lost its name\n", - s->object_size); - continue; - } - if (!strcmp(s->name, name)) { - printk(KERN_ERR "kmem_cache_create(%s): Cache name" - " already exists.\n", - name); - dump_stack(); - s = NULL; - goto oops; + s = __kmem_cache_alias(name, size, align, flags, ctor); + if (s) + goto out_locked; + + s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL); + if (s) { + s->object_size = s->size = size; + s->align = align; + s->ctor = ctor; + s->name = kstrdup(name, GFP_KERNEL); + if (!s->name) { + kmem_cache_free(kmem_cache, s); + err = -ENOMEM; + goto out_locked; } - } - WARN_ON(strchr(name, ' ')); /* It confuses parsers */ -#endif + err = __kmem_cache_create(s, flags); + if (!err) { - s = __kmem_cache_create(name, size, align, flags, ctor); + s->refcount = 1; + list_add(&s->list, &slab_caches); -#ifdef CONFIG_DEBUG_VM -oops: -#endif + } else { + kfree(s->name); + kmem_cache_free(kmem_cache, s); + } + } else + err = -ENOMEM; + +out_locked: mutex_unlock(&slab_mutex); put_online_cpus(); -#ifdef CONFIG_DEBUG_VM -out: -#endif - if (!s && (flags & SLAB_PANIC)) - panic("kmem_cache_create: Failed to create slab '%s'\n", name); + if (err) { + + if (flags & SLAB_PANIC) + panic("kmem_cache_create: Failed to create slab '%s'. Error %d\n", + name, err); + else { + printk(KERN_WARNING "kmem_cache_create(%s) failed with error %d", + name, err); + dump_stack(); + } + + return NULL; + } return s; } EXPORT_SYMBOL(kmem_cache_create); +void kmem_cache_destroy(struct kmem_cache *s) +{ + get_online_cpus(); + mutex_lock(&slab_mutex); + s->refcount--; + if (!s->refcount) { + list_del(&s->list); + + if (!__kmem_cache_shutdown(s)) { + if (s->flags & SLAB_DESTROY_BY_RCU) + rcu_barrier(); + + kfree(s->name); + kmem_cache_free(kmem_cache, s); + } else { + list_add(&s->list, &slab_caches); + printk(KERN_ERR "kmem_cache_destroy %s: Slab cache still has objects\n", + s->name); + dump_stack(); + } + } + mutex_unlock(&slab_mutex); + put_online_cpus(); +} +EXPORT_SYMBOL(kmem_cache_destroy); + int slab_is_available(void) { return slab_state >= UP; diff --git a/mm/slob.c b/mm/slob.c index 45d4ca79933a..a08e4681fd0d 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -194,7 +194,7 @@ static void *slob_new_pages(gfp_t gfp, int order, int node) void *page; #ifdef CONFIG_NUMA - if (node != -1) + if (node != NUMA_NO_NODE) page = alloc_pages_exact_node(node, gfp, order); else #endif @@ -290,7 +290,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node) * If there's a node specification, search for a partial * page with a matching node id in the freelist. */ - if (node != -1 && page_to_nid(sp) != node) + if (node != NUMA_NO_NODE && page_to_nid(sp) != node) continue; #endif /* Enough room on this page? */ @@ -425,7 +425,8 @@ out: * End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend. */ -void *__kmalloc_node(size_t size, gfp_t gfp, int node) +static __always_inline void * +__do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller) { unsigned int *m; int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); @@ -446,7 +447,7 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node) *m = size; ret = (void *)m + align; - trace_kmalloc_node(_RET_IP_, ret, + trace_kmalloc_node(caller, ret, size, size + align, gfp, node); } else { unsigned int order = get_order(size); @@ -460,15 +461,35 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node) page->private = size; } - trace_kmalloc_node(_RET_IP_, ret, + trace_kmalloc_node(caller, ret, size, PAGE_SIZE << order, gfp, node); } kmemleak_alloc(ret, size, 1, gfp); return ret; } + +void *__kmalloc_node(size_t size, gfp_t gfp, int node) +{ + return __do_kmalloc_node(size, gfp, node, _RET_IP_); +} EXPORT_SYMBOL(__kmalloc_node); +#ifdef CONFIG_TRACING +void *__kmalloc_track_caller(size_t size, gfp_t gfp, unsigned long caller) +{ + return __do_kmalloc_node(size, gfp, NUMA_NO_NODE, caller); +} + +#ifdef CONFIG_NUMA +void *__kmalloc_node_track_caller(size_t size, gfp_t gfp, + int node, unsigned long caller) +{ + return __do_kmalloc_node(size, gfp, node, caller); +} +#endif +#endif + void kfree(const void *block) { struct page *sp; @@ -508,44 +529,24 @@ size_t ksize(const void *block) } EXPORT_SYMBOL(ksize); -struct kmem_cache *__kmem_cache_create(const char *name, size_t size, - size_t align, unsigned long flags, void (*ctor)(void *)) +int __kmem_cache_create(struct kmem_cache *c, unsigned long flags) { - struct kmem_cache *c; - - c = slob_alloc(sizeof(struct kmem_cache), - GFP_KERNEL, ARCH_KMALLOC_MINALIGN, -1); + size_t align = c->size; - if (c) { - c->name = name; - c->size = size; - if (flags & SLAB_DESTROY_BY_RCU) { - /* leave room for rcu footer at the end of object */ - c->size += sizeof(struct slob_rcu); - } - c->flags = flags; - c->ctor = ctor; - /* ignore alignment unless it's forced */ - c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; - if (c->align < ARCH_SLAB_MINALIGN) - c->align = ARCH_SLAB_MINALIGN; - if (c->align < align) - c->align = align; - - kmemleak_alloc(c, sizeof(struct kmem_cache), 1, GFP_KERNEL); - c->refcount = 1; + if (flags & SLAB_DESTROY_BY_RCU) { + /* leave room for rcu footer at the end of object */ + c->size += sizeof(struct slob_rcu); } - return c; -} + c->flags = flags; + /* ignore alignment unless it's forced */ + c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0; + if (c->align < ARCH_SLAB_MINALIGN) + c->align = ARCH_SLAB_MINALIGN; + if (c->align < align) + c->align = align; -void kmem_cache_destroy(struct kmem_cache *c) -{ - kmemleak_free(c); - if (c->flags & SLAB_DESTROY_BY_RCU) - rcu_barrier(); - slob_free(c, sizeof(struct kmem_cache)); + return 0; } -EXPORT_SYMBOL(kmem_cache_destroy); void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node) { @@ -613,14 +614,28 @@ unsigned int kmem_cache_size(struct kmem_cache *c) } EXPORT_SYMBOL(kmem_cache_size); +int __kmem_cache_shutdown(struct kmem_cache *c) +{ + /* No way to check for remaining objects */ + return 0; +} + int kmem_cache_shrink(struct kmem_cache *d) { return 0; } EXPORT_SYMBOL(kmem_cache_shrink); +struct kmem_cache kmem_cache_boot = { + .name = "kmem_cache", + .size = sizeof(struct kmem_cache), + .flags = SLAB_PANIC, + .align = ARCH_KMALLOC_MINALIGN, +}; + void __init kmem_cache_init(void) { + kmem_cache = &kmem_cache_boot; slab_state = UP; } diff --git a/mm/slub.c b/mm/slub.c index 2fdd96f9e998..a0d698467f70 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -210,11 +210,7 @@ static void sysfs_slab_remove(struct kmem_cache *); static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; } static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p) { return 0; } -static inline void sysfs_slab_remove(struct kmem_cache *s) -{ - kfree(s->name); - kfree(s); -} +static inline void sysfs_slab_remove(struct kmem_cache *s) { } #endif @@ -568,6 +564,8 @@ static void slab_bug(struct kmem_cache *s, char *fmt, ...) printk(KERN_ERR "BUG %s (%s): %s\n", s->name, print_tainted(), buf); printk(KERN_ERR "----------------------------------------" "-------------------------------------\n\n"); + + add_taint(TAINT_BAD_PAGE); } static void slab_fix(struct kmem_cache *s, char *fmt, ...) @@ -624,7 +622,7 @@ static void object_err(struct kmem_cache *s, struct page *page, print_trailer(s, page, object); } -static void slab_err(struct kmem_cache *s, struct page *page, char *fmt, ...) +static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...) { va_list args; char buf[100]; @@ -1069,13 +1067,13 @@ bad: return 0; } -static noinline int free_debug_processing(struct kmem_cache *s, - struct page *page, void *object, unsigned long addr) +static noinline struct kmem_cache_node *free_debug_processing( + struct kmem_cache *s, struct page *page, void *object, + unsigned long addr, unsigned long *flags) { - unsigned long flags; - int rc = 0; + struct kmem_cache_node *n = get_node(s, page_to_nid(page)); - local_irq_save(flags); + spin_lock_irqsave(&n->list_lock, *flags); slab_lock(page); if (!check_slab(s, page)) @@ -1113,15 +1111,19 @@ static noinline int free_debug_processing(struct kmem_cache *s, set_track(s, object, TRACK_FREE, addr); trace(s, page, object, 0); init_object(s, object, SLUB_RED_INACTIVE); - rc = 1; out: slab_unlock(page); - local_irq_restore(flags); - return rc; + /* + * Keep node_lock to preserve integrity + * until the object is actually freed + */ + return n; fail: + slab_unlock(page); + spin_unlock_irqrestore(&n->list_lock, *flags); slab_fix(s, "Object at 0x%p not freed", object); - goto out; + return NULL; } static int __init setup_slub_debug(char *str) @@ -1214,8 +1216,9 @@ static inline void setup_object_debug(struct kmem_cache *s, static inline int alloc_debug_processing(struct kmem_cache *s, struct page *page, void *object, unsigned long addr) { return 0; } -static inline int free_debug_processing(struct kmem_cache *s, - struct page *page, void *object, unsigned long addr) { return 0; } +static inline struct kmem_cache_node *free_debug_processing( + struct kmem_cache *s, struct page *page, void *object, + unsigned long addr, unsigned long *flags) { return NULL; } static inline int slab_pad_check(struct kmem_cache *s, struct page *page) { return 1; } @@ -1714,7 +1717,7 @@ static inline void note_cmpxchg_failure(const char *n, stat(s, CMPXCHG_DOUBLE_CPU_FAIL); } -void init_kmem_cache_cpus(struct kmem_cache *s) +static void init_kmem_cache_cpus(struct kmem_cache *s) { int cpu; @@ -1939,7 +1942,7 @@ static void unfreeze_partials(struct kmem_cache *s) * If we did not find a slot then simply move all the partials to the * per node partial list. */ -int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) +static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) { struct page *oldpage; int pages; @@ -1962,6 +1965,7 @@ int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) local_irq_save(flags); unfreeze_partials(s); local_irq_restore(flags); + oldpage = NULL; pobjects = 0; pages = 0; stat(s, CPU_PARTIAL_DRAIN); @@ -2310,7 +2314,7 @@ new_slab: * * Otherwise we can simply pick the next object from the lockless free list. */ -static __always_inline void *slab_alloc(struct kmem_cache *s, +static __always_inline void *slab_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node, unsigned long addr) { void **object; @@ -2380,9 +2384,15 @@ redo: return object; } +static __always_inline void *slab_alloc(struct kmem_cache *s, + gfp_t gfpflags, unsigned long addr) +{ + return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr); +} + void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) { - void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_); + void *ret = slab_alloc(s, gfpflags, _RET_IP_); trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags); @@ -2393,7 +2403,7 @@ EXPORT_SYMBOL(kmem_cache_alloc); #ifdef CONFIG_TRACING void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size) { - void *ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, _RET_IP_); + void *ret = slab_alloc(s, gfpflags, _RET_IP_); trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags); return ret; } @@ -2411,7 +2421,7 @@ EXPORT_SYMBOL(kmalloc_order_trace); #ifdef CONFIG_NUMA void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) { - void *ret = slab_alloc(s, gfpflags, node, _RET_IP_); + void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_); trace_kmem_cache_alloc_node(_RET_IP_, ret, s->object_size, s->size, gfpflags, node); @@ -2425,7 +2435,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s, gfp_t gfpflags, int node, size_t size) { - void *ret = slab_alloc(s, gfpflags, node, _RET_IP_); + void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_); trace_kmalloc_node(_RET_IP_, ret, size, s->size, gfpflags, node); @@ -2457,7 +2467,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page, stat(s, FREE_SLOWPATH); - if (kmem_cache_debug(s) && !free_debug_processing(s, page, x, addr)) + if (kmem_cache_debug(s) && + !(n = free_debug_processing(s, page, x, addr, &flags))) return; do { @@ -2612,6 +2623,13 @@ void kmem_cache_free(struct kmem_cache *s, void *x) page = virt_to_head_page(x); + if (kmem_cache_debug(s) && page->slab != s) { + pr_err("kmem_cache_free: Wrong slab cache. %s but object" + " is from %s\n", page->slab->name, s->name); + WARN_ON_ONCE(1); + return; + } + slab_free(s, page, x, _RET_IP_); trace_kmem_cache_free(_RET_IP_, x); @@ -3026,17 +3044,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) } -static int kmem_cache_open(struct kmem_cache *s, - const char *name, size_t size, - size_t align, unsigned long flags, - void (*ctor)(void *)) +static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) { - memset(s, 0, kmem_size); - s->name = name; - s->ctor = ctor; - s->object_size = size; - s->align = align; - s->flags = kmem_cache_flags(size, flags, name, ctor); + s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor); s->reserved = 0; if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU)) @@ -3098,7 +3108,6 @@ static int kmem_cache_open(struct kmem_cache *s, else s->cpu_partial = 30; - s->refcount = 1; #ifdef CONFIG_NUMA s->remote_node_defrag_ratio = 1000; #endif @@ -3106,16 +3115,16 @@ static int kmem_cache_open(struct kmem_cache *s, goto error; if (alloc_kmem_cache_cpus(s)) - return 1; + return 0; free_kmem_cache_nodes(s); error: if (flags & SLAB_PANIC) panic("Cannot create slab %s size=%lu realsize=%u " "order=%u offset=%u flags=%lx\n", - s->name, (unsigned long)size, s->size, oo_order(s->oo), + s->name, (unsigned long)s->size, s->size, oo_order(s->oo), s->offset, flags); - return 0; + return -EINVAL; } /* @@ -3137,7 +3146,7 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page, sizeof(long), GFP_ATOMIC); if (!map) return; - slab_err(s, page, "%s", text); + slab_err(s, page, text, s->name); slab_lock(page); get_map(s, page, map); @@ -3169,7 +3178,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n) discard_slab(s, page); } else { list_slab_objects(s, page, - "Objects remaining on kmem_cache_close()"); + "Objects remaining in %s on kmem_cache_close()"); } } } @@ -3182,7 +3191,6 @@ static inline int kmem_cache_close(struct kmem_cache *s) int node; flush_all(s); - free_percpu(s->cpu_slab); /* Attempt to free all objects */ for_each_node_state(node, N_NORMAL_MEMORY) { struct kmem_cache_node *n = get_node(s, node); @@ -3191,33 +3199,20 @@ static inline int kmem_cache_close(struct kmem_cache *s) if (n->nr_partial || slabs_node(s, node)) return 1; } + free_percpu(s->cpu_slab); free_kmem_cache_nodes(s); return 0; } -/* - * Close a cache and release the kmem_cache structure - * (must be used for caches created using kmem_cache_create) - */ -void kmem_cache_destroy(struct kmem_cache *s) +int __kmem_cache_shutdown(struct kmem_cache *s) { - mutex_lock(&slab_mutex); - s->refcount--; - if (!s->refcount) { - list_del(&s->list); - mutex_unlock(&slab_mutex); - if (kmem_cache_close(s)) { - printk(KERN_ERR "SLUB %s: %s called for cache that " - "still has objects.\n", s->name, __func__); - dump_stack(); - } - if (s->flags & SLAB_DESTROY_BY_RCU) - rcu_barrier(); + int rc = kmem_cache_close(s); + + if (!rc) sysfs_slab_remove(s); - } else - mutex_unlock(&slab_mutex); + + return rc; } -EXPORT_SYMBOL(kmem_cache_destroy); /******************************************************************** * Kmalloc subsystem @@ -3226,8 +3221,6 @@ EXPORT_SYMBOL(kmem_cache_destroy); struct kmem_cache *kmalloc_caches[SLUB_PAGE_SHIFT]; EXPORT_SYMBOL(kmalloc_caches); -static struct kmem_cache *kmem_cache; - #ifdef CONFIG_ZONE_DMA static struct kmem_cache *kmalloc_dma_caches[SLUB_PAGE_SHIFT]; #endif @@ -3273,14 +3266,17 @@ static struct kmem_cache *__init create_kmalloc_cache(const char *name, { struct kmem_cache *s; - s = kmem_cache_alloc(kmem_cache, GFP_NOWAIT); + s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); + + s->name = name; + s->size = s->object_size = size; + s->align = ARCH_KMALLOC_MINALIGN; /* * This function is called with IRQs disabled during early-boot on * single CPU so there's no need to take slab_mutex here. */ - if (!kmem_cache_open(s, name, size, ARCH_KMALLOC_MINALIGN, - flags, NULL)) + if (kmem_cache_open(s, flags)) goto panic; list_add(&s->list, &slab_caches); @@ -3362,7 +3358,7 @@ void *__kmalloc(size_t size, gfp_t flags) if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc(s, flags, NUMA_NO_NODE, _RET_IP_); + ret = slab_alloc(s, flags, _RET_IP_); trace_kmalloc(_RET_IP_, ret, size, s->size, flags); @@ -3405,7 +3401,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc(s, flags, node, _RET_IP_); + ret = slab_alloc_node(s, flags, node, _RET_IP_); trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node); @@ -3482,7 +3478,7 @@ void kfree(const void *x) if (unlikely(!PageSlab(page))) { BUG_ON(!PageCompound(page)); kmemleak_free(x); - put_page(page); + __free_pages(page, compound_order(page)); return; } slab_free(page->slab, page, object, _RET_IP_); @@ -3719,12 +3715,12 @@ void __init kmem_cache_init(void) slub_max_order = 0; kmem_size = offsetof(struct kmem_cache, node) + - nr_node_ids * sizeof(struct kmem_cache_node *); + nr_node_ids * sizeof(struct kmem_cache_node *); /* Allocate two kmem_caches from the page allocator */ kmalloc_size = ALIGN(kmem_size, cache_line_size()); order = get_order(2 * kmalloc_size); - kmem_cache = (void *)__get_free_pages(GFP_NOWAIT, order); + kmem_cache = (void *)__get_free_pages(GFP_NOWAIT | __GFP_ZERO, order); /* * Must first have the slab cache available for the allocations of the @@ -3733,9 +3729,10 @@ void __init kmem_cache_init(void) */ kmem_cache_node = (void *)kmem_cache + kmalloc_size; - kmem_cache_open(kmem_cache_node, "kmem_cache_node", - sizeof(struct kmem_cache_node), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); + kmem_cache_node->name = "kmem_cache_node"; + kmem_cache_node->size = kmem_cache_node->object_size = + sizeof(struct kmem_cache_node); + kmem_cache_open(kmem_cache_node, SLAB_HWCACHE_ALIGN | SLAB_PANIC); hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI); @@ -3743,8 +3740,10 @@ void __init kmem_cache_init(void) slab_state = PARTIAL; temp_kmem_cache = kmem_cache; - kmem_cache_open(kmem_cache, "kmem_cache", kmem_size, - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); + kmem_cache->name = "kmem_cache"; + kmem_cache->size = kmem_cache->object_size = kmem_size; + kmem_cache_open(kmem_cache, SLAB_HWCACHE_ALIGN | SLAB_PANIC); + kmem_cache = kmem_cache_alloc(kmem_cache, GFP_NOWAIT); memcpy(kmem_cache, temp_kmem_cache, kmem_size); @@ -3933,11 +3932,10 @@ static struct kmem_cache *find_mergeable(size_t size, return NULL; } -struct kmem_cache *__kmem_cache_create(const char *name, size_t size, +struct kmem_cache *__kmem_cache_alias(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *)) { struct kmem_cache *s; - char *n; s = find_mergeable(size, align, flags, name, ctor); if (s) { @@ -3951,36 +3949,29 @@ struct kmem_cache *__kmem_cache_create(const char *name, size_t size, if (sysfs_slab_alias(s, name)) { s->refcount--; - return NULL; + s = NULL; } - return s; } - n = kstrdup(name, GFP_KERNEL); - if (!n) - return NULL; + return s; +} - s = kmalloc(kmem_size, GFP_KERNEL); - if (s) { - if (kmem_cache_open(s, n, - size, align, flags, ctor)) { - int r; +int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) +{ + int err; - list_add(&s->list, &slab_caches); - mutex_unlock(&slab_mutex); - r = sysfs_slab_add(s); - mutex_lock(&slab_mutex); + err = kmem_cache_open(s, flags); + if (err) + return err; - if (!r) - return s; + mutex_unlock(&slab_mutex); + err = sysfs_slab_add(s); + mutex_lock(&slab_mutex); - list_del(&s->list); - kmem_cache_close(s); - } - kfree(s); - } - kfree(n); - return NULL; + if (err) + kmem_cache_close(s); + + return err; } #ifdef CONFIG_SMP @@ -4033,7 +4024,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller) if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc(s, gfpflags, NUMA_NO_NODE, caller); + ret = slab_alloc(s, gfpflags, caller); /* Honor the call site pointer we received. */ trace_kmalloc(caller, ret, size, s->size, gfpflags); @@ -4063,7 +4054,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc(s, gfpflags, node, caller); + ret = slab_alloc_node(s, gfpflags, node, caller); /* Honor the call site pointer we received. */ trace_kmalloc_node(caller, ret, size, s->size, gfpflags, node); @@ -5210,14 +5201,6 @@ static ssize_t slab_attr_store(struct kobject *kobj, return err; } -static void kmem_cache_release(struct kobject *kobj) -{ - struct kmem_cache *s = to_slab(kobj); - - kfree(s->name); - kfree(s); -} - static const struct sysfs_ops slab_sysfs_ops = { .show = slab_attr_show, .store = slab_attr_store, @@ -5225,7 +5208,6 @@ static const struct sysfs_ops slab_sysfs_ops = { static struct kobj_type slab_ktype = { .sysfs_ops = &slab_sysfs_ops, - .release = kmem_cache_release }; static int uevent_filter(struct kset *kset, struct kobject *kobj) diff --git a/mm/util.c b/mm/util.c index 8c7265afa29f..dc3036cdcc6a 100644 --- a/mm/util.c +++ b/mm/util.c @@ -105,6 +105,25 @@ void *memdup_user(const void __user *src, size_t len) } EXPORT_SYMBOL(memdup_user); +static __always_inline void *__do_krealloc(const void *p, size_t new_size, + gfp_t flags) +{ + void *ret; + size_t ks = 0; + + if (p) + ks = ksize(p); + + if (ks >= new_size) + return (void *)p; + + ret = kmalloc_track_caller(new_size, flags); + if (ret && p) + memcpy(ret, p, ks); + + return ret; +} + /** * __krealloc - like krealloc() but don't free @p. * @p: object to reallocate memory for. @@ -117,23 +136,11 @@ EXPORT_SYMBOL(memdup_user); */ void *__krealloc(const void *p, size_t new_size, gfp_t flags) { - void *ret; - size_t ks = 0; - if (unlikely(!new_size)) return ZERO_SIZE_PTR; - if (p) - ks = ksize(p); + return __do_krealloc(p, new_size, flags); - if (ks >= new_size) - return (void *)p; - - ret = kmalloc_track_caller(new_size, flags); - if (ret && p) - memcpy(ret, p, ks); - - return ret; } EXPORT_SYMBOL(__krealloc); @@ -157,7 +164,7 @@ void *krealloc(const void *p, size_t new_size, gfp_t flags) return ZERO_SIZE_PTR; } - ret = __krealloc(p, new_size, flags); + ret = __do_krealloc(p, new_size, flags); if (ret && p != ret) kfree(p); diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index b258da88f675..add69d0fd99d 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -105,7 +105,6 @@ static struct sk_buff *vlan_reorder_header(struct sk_buff *skb) return NULL; memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); skb->mac_header += VLAN_HLEN; - skb_reset_mac_len(skb); return skb; } @@ -139,6 +138,8 @@ struct sk_buff *vlan_untag(struct sk_buff *skb) skb_reset_network_header(skb); skb_reset_transport_header(skb); + skb_reset_mac_len(skb); + return skb; err_free: diff --git a/net/can/af_can.c b/net/can/af_can.c index 821022a7214f..ddac1ee2ed20 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -63,7 +63,7 @@ #include "af_can.h" -static __initdata const char banner[] = KERN_INFO +static __initconst const char banner[] = KERN_INFO "can: controller area network core (" CAN_VERSION_STRING ")\n"; MODULE_DESCRIPTION("Controller Area Network PF_CAN core"); diff --git a/net/can/bcm.c b/net/can/bcm.c index 151b7730c12c..6f747582718e 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -77,7 +77,7 @@ (CAN_SFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG)) #define CAN_BCM_VERSION CAN_VERSION -static __initdata const char banner[] = KERN_INFO +static __initconst const char banner[] = KERN_INFO "can: broadcast manager protocol (rev " CAN_BCM_VERSION " t)\n"; MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); diff --git a/net/can/gw.c b/net/can/gw.c index 127879c55fb6..1f5c9785a262 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -58,7 +58,7 @@ #include <net/sock.h> #define CAN_GW_VERSION "20101209" -static __initdata const char banner[] = +static __initconst const char banner[] = KERN_INFO "can: netlink gateway (rev " CAN_GW_VERSION ")\n"; MODULE_DESCRIPTION("PF_CAN netlink gateway"); diff --git a/net/can/raw.c b/net/can/raw.c index 3e9c89356a93..5b0e3e330d97 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -55,7 +55,7 @@ #include <net/net_namespace.h> #define CAN_RAW_VERSION CAN_VERSION -static __initdata const char banner[] = +static __initconst const char banner[] = KERN_INFO "can: raw protocol (rev " CAN_RAW_VERSION ")\n"; MODULE_DESCRIPTION("PF_CAN raw protocol"); diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index e65f2c856e06..faf7cc3483fe 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -220,7 +220,7 @@ static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops) dn_rt_cache_flush(-1); } -static const struct fib_rules_ops __net_initdata dn_fib_rules_ops_template = { +static const struct fib_rules_ops __net_initconst dn_fib_rules_ops_template = { .family = AF_DECnet, .rule_size = sizeof(struct dn_fib_rule), .addr_size = sizeof(u16), diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 274309d3aded..26aa65d1fce4 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -262,7 +262,7 @@ static void fib4_rule_flush_cache(struct fib_rules_ops *ops) rt_cache_flush(ops->fro_net); } -static const struct fib_rules_ops __net_initdata fib4_rules_ops_template = { +static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = { .family = AF_INET, .rule_size = sizeof(struct fib4_rule), .addr_size = sizeof(u32), diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 3509065e409a..267753060ffc 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -314,6 +314,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi) nfi->fib_scope == fi->fib_scope && nfi->fib_prefsrc == fi->fib_prefsrc && nfi->fib_priority == fi->fib_priority && + nfi->fib_type == fi->fib_type && memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(u32) * RTAX_MAX) == 0 && ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && @@ -833,6 +834,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) fi->fib_flags = cfg->fc_flags; fi->fib_priority = cfg->fc_priority; fi->fib_prefsrc = cfg->fc_prefsrc; + fi->fib_type = cfg->fc_type; fi->fib_nhs = nhs; change_nexthops(fi) { diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 1daa95c2a0ba..6168c4dc58b1 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -221,7 +221,7 @@ static int ipmr_rule_fill(struct fib_rule *rule, struct sk_buff *skb, return 0; } -static const struct fib_rules_ops __net_initdata ipmr_rules_ops_template = { +static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = { .family = RTNL_FAMILY_IPMR, .rule_size = sizeof(struct ipmr_rule), .addr_size = sizeof(u32), diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 480e68422efb..d7c56f8a5b4e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1769,14 +1769,6 @@ static void sit_route_add(struct net_device *dev) } #endif -static void addrconf_add_lroute(struct net_device *dev) -{ - struct in6_addr addr; - - ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - addrconf_prefix_route(&addr, 64, dev, 0, 0); -} - static struct inet6_dev *addrconf_add_dev(struct net_device *dev) { struct inet6_dev *idev; @@ -1794,8 +1786,6 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) if (!(dev->flags & IFF_LOOPBACK)) addrconf_add_mroute(dev); - /* Add link local route */ - addrconf_add_lroute(dev); return idev; } @@ -2474,10 +2464,9 @@ static void addrconf_sit_config(struct net_device *dev) sit_add_v4_addrs(idev); - if (dev->flags&IFF_POINTOPOINT) { + if (dev->flags&IFF_POINTOPOINT) addrconf_add_mroute(dev); - addrconf_add_lroute(dev); - } else + else sit_route_add(dev); } #endif diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 4be23da32b89..ff76eecfd622 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -79,7 +79,7 @@ struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL -static const __net_initdata struct ip6addrlbl_init_table +static const __net_initconst struct ip6addrlbl_init_table { const struct in6_addr *prefix; int prefixlen; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 0ff1cfd55bc4..d9fb9110f607 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -238,7 +238,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) + nla_total_size(16); /* src */ } -static const struct fib_rules_ops __net_initdata fib6_rules_ops_template = { +static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = { .family = AF_INET6, .rule_size = sizeof(struct fib6_rule), .addr_size = sizeof(struct in6_addr), diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 08ea3f0b6e55..f7c7c6319720 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -205,7 +205,7 @@ static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb, return 0; } -static const struct fib_rules_ops __net_initdata ip6mr_rules_ops_template = { +static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = { .family = RTNL_FAMILY_IP6MR, .rule_size = sizeof(struct ip6mr_rule), .addr_size = sizeof(struct in6_addr), diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d1ddbc6ddac5..7c7e963260e1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1593,17 +1593,18 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) struct fib6_table *table; struct net *net = dev_net(rt->dst.dev); - if (rt == net->ipv6.ip6_null_entry) - return -ENOENT; + if (rt == net->ipv6.ip6_null_entry) { + err = -ENOENT; + goto out; + } table = rt->rt6i_table; write_lock_bh(&table->tb6_lock); - err = fib6_del(rt, info); - dst_release(&rt->dst); - write_unlock_bh(&table->tb6_lock); +out: + dst_release(&rt->dst); return err; } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index bb738c9f9146..b833677d83d6 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -468,7 +468,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name) notify_t notify; if (self->tsap) { - IRDA_WARNING("%s: busy!\n", __func__); + IRDA_DEBUG(0, "%s: busy!\n", __func__); return -EBUSY; } diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 5c93f2952b08..1002e3396f72 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -440,7 +440,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) */ lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); if (lsap == NULL) { - IRDA_WARNING("%s: unable to allocate LSAP!!\n", __func__); + IRDA_DEBUG(0, "%s: unable to allocate LSAP!!\n", __func__); return NULL; } diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 40f056debf9a..63e4cdc92376 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -497,15 +497,11 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags); if (!addr || len < sizeof(struct sockaddr_nfc) || - addr->sa_family != AF_NFC) { - pr_err("Invalid socket\n"); + addr->sa_family != AF_NFC) return -EINVAL; - } - if (addr->service_name_len == 0 && addr->dsap == 0) { - pr_err("Missing service name or dsap\n"); + if (addr->service_name_len == 0 && addr->dsap == 0) return -EINVAL; - } pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx, addr->target_idx, addr->nfc_protocol); diff --git a/net/sctp/input.c b/net/sctp/input.c index 25dfe7380479..8bd3c279427e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -68,8 +68,8 @@ static int sctp_rcv_ootb(struct sk_buff *); static struct sctp_association *__sctp_rcv_lookup(struct net *net, struct sk_buff *skb, - const union sctp_addr *laddr, const union sctp_addr *paddr, + const union sctp_addr *laddr, struct sctp_transport **transportp); static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net, const union sctp_addr *laddr); diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index d16632e1503a..1b4a7f8ec3fd 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -63,6 +63,7 @@ static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn); static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, + union sctp_addr *saddr, struct sctp_sackhdr *sack, __u32 *highest_new_tsn); @@ -1139,9 +1140,10 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc, * Process the SACK against the outqueue. Mostly, this just frees * things off the transmitted queue. */ -int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) +int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) { struct sctp_association *asoc = q->asoc; + struct sctp_sackhdr *sack = chunk->subh.sack_hdr; struct sctp_transport *transport; struct sctp_chunk *tchunk = NULL; struct list_head *lchunk, *transport_list, *temp; @@ -1210,7 +1212,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) /* Run through the retransmit queue. Credit bytes received * and free those chunks that we can. */ - sctp_check_transmitted(q, &q->retransmit, NULL, sack, &highest_new_tsn); + sctp_check_transmitted(q, &q->retransmit, NULL, NULL, sack, &highest_new_tsn); /* Run through the transmitted queue. * Credit bytes received and free those chunks which we can. @@ -1219,7 +1221,8 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) */ list_for_each_entry(transport, transport_list, transports) { sctp_check_transmitted(q, &transport->transmitted, - transport, sack, &highest_new_tsn); + transport, &chunk->source, sack, + &highest_new_tsn); /* * SFR-CACC algorithm: * C) Let count_of_newacks be the number of @@ -1326,6 +1329,7 @@ int sctp_outq_is_empty(const struct sctp_outq *q) static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, + union sctp_addr *saddr, struct sctp_sackhdr *sack, __u32 *highest_new_tsn_in_sack) { @@ -1633,8 +1637,9 @@ static void sctp_check_transmitted(struct sctp_outq *q, /* Mark the destination transport address as * active if it is not so marked. */ - if ((transport->state == SCTP_INACTIVE) || - (transport->state == SCTP_UNCONFIRMED)) { + if ((transport->state == SCTP_INACTIVE || + transport->state == SCTP_UNCONFIRMED) && + sctp_cmp_addr_exact(&transport->ipaddr, saddr)) { sctp_assoc_control_transport( transport->asoc, transport, diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index bcfebb91559d..57f7de839b03 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -752,11 +752,11 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, /* Helper function to process the process SACK command. */ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, - struct sctp_sackhdr *sackh) + struct sctp_chunk *chunk) { int err = 0; - if (sctp_outq_sack(&asoc->outqueue, sackh)) { + if (sctp_outq_sack(&asoc->outqueue, chunk)) { struct net *net = sock_net(asoc->base.sk); /* There are no more TSNs awaiting SACK. */ diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 094813b6c3c3..b6adef8a1e93 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3179,7 +3179,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(struct net *net, return sctp_sf_violation_ctsn(net, ep, asoc, type, arg, commands); /* Return this SACK for further processing. */ - sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh)); + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_CHUNK(chunk)); /* Note: We do the rest of the work on the PROCESS_SACK * sideeffect. diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 09dc5b97e079..fd5f042dbff4 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -220,6 +220,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, sock_init_data(sock, sk); sk->sk_backlog_rcv = backlog_rcv; + sk->sk_rcvbuf = TIPC_FLOW_CONTROL_WIN * 2 * TIPC_MAX_USER_MSG_SIZE * 2; tipc_sk(sk)->p = tp_ptr; tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 6a3ee981931d..afa44595f348 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -209,7 +209,7 @@ endif # >$< substitution to preserve $ when reloading .cmd file # note: when using inline perl scripts [perl -e '...$$t=1;...'] # in $(cmd_xxx) double $$ your perl vars -make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) +make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ca05ba217f5f..21a9f5de0a21 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -421,7 +421,7 @@ sub top_of_kernel_tree { } } return 1; - } +} sub parse_email { my ($formatted_email) = @_; @@ -1386,6 +1386,8 @@ sub process { my $in_header_lines = 1; my $in_commit_log = 0; #Scanning lines before patch + my $non_utf8_charset = 0; + our @report = (); our $cnt_lines = 0; our $cnt_error = 0; @@ -1686,10 +1688,17 @@ sub process { $in_commit_log = 1; } -# Still not yet in a patch, check for any UTF-8 - if ($in_commit_log && $realfile =~ /^$/ && +# Check if there is UTF-8 in a commit log when a mail header has explicitly +# declined it, i.e defined some charset where it is missing. + if ($in_header_lines && + $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && + $1 !~ /utf-8/i) { + $non_utf8_charset = 1; + } + + if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && $rawline =~ /$NON_ASCII_UTF8/) { - CHK("UTF8_BEFORE_PATCH", + WARN("UTF8_BEFORE_PATCH", "8-bit UTF-8 used in possible commit log\n" . $herecurr); } @@ -1873,6 +1882,20 @@ sub process { "No space is necessary after a cast\n" . $hereprev); } + if ($realfile =~ m@^(drivers/net/|net/)@ && + $rawline =~ /^\+[ \t]*\/\*[ \t]*$/ && + $prevrawline =~ /^\+[ \t]*$/) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); + } + + if ($realfile =~ m@^(drivers/net/|net/)@ && + $rawline !~ m@^\+[ \t]*(\/\*|\*\/)@ && + $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments put the trailing */ on a separate line\n" . $herecurr); + } + # check for spaces at the beginning of a line. # Exceptions: # 1) within comments @@ -2390,8 +2413,10 @@ sub process { my $orig = $1; my $level = lc($orig); $level = "warn" if ($level eq "warning"); + my $level2 = $level; + $level2 = "dbg" if ($level eq "debug"); WARN("PREFER_PR_LEVEL", - "Prefer pr_$level(... to printk(KERN_$1, ...\n" . $herecurr); + "Prefer netdev_$level2(netdev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); } if ($line =~ /\bpr_warning\s*\(/) { @@ -2947,7 +2972,7 @@ sub process { my $exceptions = qr{ $Declare| module_param_named| - MODULE_PARAM_DESC| + MODULE_PARM_DESC| DECLARE_PER_CPU| DEFINE_PER_CPU| __typeof__\(| diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 8fd107a3fac4..01e8a8e22602 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -230,6 +230,7 @@ my $dohighlight = ""; my $verbose = 0; my $output_mode = "man"; +my $output_preformatted = 0; my $no_doc_sections = 0; my %highlights = %highlights_man; my $blankline = $blankline_man; @@ -280,9 +281,10 @@ my $doc_special = "\@\%\$\&"; my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start. my $doc_end = '\*/'; my $doc_com = '\s*\*\s*'; +my $doc_com_body = '\s*\* ?'; my $doc_decl = $doc_com . '(\w+)'; my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)'; -my $doc_content = $doc_com . '(.*)'; +my $doc_content = $doc_com_body . '(.*)'; my $doc_block = $doc_com . 'DOC:\s*(.*)?'; my %constants; @@ -459,8 +461,13 @@ sub output_highlight { # print STDERR "contents af:$contents\n"; foreach $line (split "\n", $contents) { + if (! $output_preformatted) { + $line =~ s/^\s*//; + } if ($line eq ""){ - print $lineprefix, local_unescape($blankline); + if (! $output_preformatted) { + print $lineprefix, local_unescape($blankline); + } } else { $line =~ s/\\\\\\/\&/g; if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { @@ -643,10 +650,12 @@ sub output_section_xml(%) { print "<title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<informalexample><programlisting>\n"; + $output_preformatted = 1; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; if ($section =~ m/EXAMPLE/i) { print "</programlisting></informalexample>\n"; } else { @@ -949,10 +958,12 @@ sub output_blockhead_xml(%) { } if ($section =~ m/EXAMPLE/i) { print "<example><para>\n"; + $output_preformatted = 1; } else { print "<para>\n"; } output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; if ($section =~ m/EXAMPLE/i) { print "</para></example>\n"; } else { @@ -1028,10 +1039,12 @@ sub output_function_gnome { print "<simplesect>\n <title>$section</title>\n"; if ($section =~ m/EXAMPLE/i) { print "<example><programlisting>\n"; + $output_preformatted = 1; } else { } print "<para>\n"; output_highlight($args{'sections'}{$section}); + $output_preformatted = 0; print "</para>\n"; if ($section =~ m/EXAMPLE/i) { print "</programlisting></example>\n"; @@ -2046,6 +2059,9 @@ sub process_file($) { $section_counter = 0; while (<IN>) { + while (s/\\\s*$//) { + $_ .= <IN>; + } if ($state == 0) { if (/$doc_start/o) { $state = 1; # next line is always the function name @@ -2073,7 +2089,7 @@ sub process_file($) { $descr= $1; $descr =~ s/^\s*//; $descr =~ s/\s*$//; - $descr =~ s/\s+/ /; + $descr =~ s/\s+/ /g; $declaration_purpose = xml_escape($descr); $in_purpose = 1; } else { @@ -2165,6 +2181,7 @@ sub process_file($) { # Continued declaration purpose chomp($declaration_purpose); $declaration_purpose .= " " . xml_escape($1); + $declaration_purpose =~ s/\s+/ /g; } else { $contents .= $1 . "\n"; } diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 4b877a92a7ea..44dfc415a379 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -26,12 +26,12 @@ static DEFINE_MUTEX(devcgroup_mutex); /* - * whitelist locking rules: + * exception list locking rules: * hold devcgroup_mutex for update/read. * hold rcu_read_lock() for read. */ -struct dev_whitelist_item { +struct dev_exception_item { u32 major, minor; short type; short access; @@ -41,7 +41,8 @@ struct dev_whitelist_item { struct dev_cgroup { struct cgroup_subsys_state css; - struct list_head whitelist; + struct list_head exceptions; + bool deny_all; }; static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s) @@ -74,12 +75,12 @@ static int devcgroup_can_attach(struct cgroup *new_cgrp, /* * called under devcgroup_mutex */ -static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig) +static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig) { - struct dev_whitelist_item *wh, *tmp, *new; + struct dev_exception_item *ex, *tmp, *new; - list_for_each_entry(wh, orig, list) { - new = kmemdup(wh, sizeof(*wh), GFP_KERNEL); + list_for_each_entry(ex, orig, list) { + new = kmemdup(ex, sizeof(*ex), GFP_KERNEL); if (!new) goto free_and_exit; list_add_tail(&new->list, dest); @@ -88,64 +89,60 @@ static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig) return 0; free_and_exit: - list_for_each_entry_safe(wh, tmp, dest, list) { - list_del(&wh->list); - kfree(wh); + list_for_each_entry_safe(ex, tmp, dest, list) { + list_del(&ex->list); + kfree(ex); } return -ENOMEM; } -/* Stupid prototype - don't bother combining existing entries */ /* * called under devcgroup_mutex */ -static int dev_whitelist_add(struct dev_cgroup *dev_cgroup, - struct dev_whitelist_item *wh) +static int dev_exception_add(struct dev_cgroup *dev_cgroup, + struct dev_exception_item *ex) { - struct dev_whitelist_item *whcopy, *walk; + struct dev_exception_item *excopy, *walk; - whcopy = kmemdup(wh, sizeof(*wh), GFP_KERNEL); - if (!whcopy) + excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL); + if (!excopy) return -ENOMEM; - list_for_each_entry(walk, &dev_cgroup->whitelist, list) { - if (walk->type != wh->type) + list_for_each_entry(walk, &dev_cgroup->exceptions, list) { + if (walk->type != ex->type) continue; - if (walk->major != wh->major) + if (walk->major != ex->major) continue; - if (walk->minor != wh->minor) + if (walk->minor != ex->minor) continue; - walk->access |= wh->access; - kfree(whcopy); - whcopy = NULL; + walk->access |= ex->access; + kfree(excopy); + excopy = NULL; } - if (whcopy != NULL) - list_add_tail_rcu(&whcopy->list, &dev_cgroup->whitelist); + if (excopy != NULL) + list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions); return 0; } /* * called under devcgroup_mutex */ -static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup, - struct dev_whitelist_item *wh) +static void dev_exception_rm(struct dev_cgroup *dev_cgroup, + struct dev_exception_item *ex) { - struct dev_whitelist_item *walk, *tmp; + struct dev_exception_item *walk, *tmp; - list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) { - if (walk->type == DEV_ALL) - goto remove; - if (walk->type != wh->type) + list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) { + if (walk->type != ex->type) continue; - if (walk->major != ~0 && walk->major != wh->major) + if (walk->major != ex->major) continue; - if (walk->minor != ~0 && walk->minor != wh->minor) + if (walk->minor != ex->minor) continue; -remove: - walk->access &= ~wh->access; + walk->access &= ~ex->access; if (!walk->access) { list_del_rcu(&walk->list); kfree_rcu(walk, rcu); @@ -153,6 +150,22 @@ remove: } } +/** + * dev_exception_clean - frees all entries of the exception list + * @dev_cgroup: dev_cgroup with the exception list to be cleaned + * + * called under devcgroup_mutex + */ +static void dev_exception_clean(struct dev_cgroup *dev_cgroup) +{ + struct dev_exception_item *ex, *tmp; + + list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) { + list_del(&ex->list); + kfree(ex); + } +} + /* * called from kernel/cgroup.c with cgroup_lock() held. */ @@ -165,25 +178,17 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup) dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL); if (!dev_cgroup) return ERR_PTR(-ENOMEM); - INIT_LIST_HEAD(&dev_cgroup->whitelist); + INIT_LIST_HEAD(&dev_cgroup->exceptions); parent_cgroup = cgroup->parent; - if (parent_cgroup == NULL) { - struct dev_whitelist_item *wh; - wh = kmalloc(sizeof(*wh), GFP_KERNEL); - if (!wh) { - kfree(dev_cgroup); - return ERR_PTR(-ENOMEM); - } - wh->minor = wh->major = ~0; - wh->type = DEV_ALL; - wh->access = ACC_MASK; - list_add(&wh->list, &dev_cgroup->whitelist); - } else { + if (parent_cgroup == NULL) + dev_cgroup->deny_all = false; + else { parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup); mutex_lock(&devcgroup_mutex); - ret = dev_whitelist_copy(&dev_cgroup->whitelist, - &parent_dev_cgroup->whitelist); + ret = dev_exceptions_copy(&dev_cgroup->exceptions, + &parent_dev_cgroup->exceptions); + dev_cgroup->deny_all = parent_dev_cgroup->deny_all; mutex_unlock(&devcgroup_mutex); if (ret) { kfree(dev_cgroup); @@ -197,13 +202,9 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup) static void devcgroup_destroy(struct cgroup *cgroup) { struct dev_cgroup *dev_cgroup; - struct dev_whitelist_item *wh, *tmp; dev_cgroup = cgroup_to_devcgroup(cgroup); - list_for_each_entry_safe(wh, tmp, &dev_cgroup->whitelist, list) { - list_del(&wh->list); - kfree(wh); - } + dev_exception_clean(dev_cgroup); kfree(dev_cgroup); } @@ -249,59 +250,87 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft, struct seq_file *m) { struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup); - struct dev_whitelist_item *wh; + struct dev_exception_item *ex; char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; rcu_read_lock(); - list_for_each_entry_rcu(wh, &devcgroup->whitelist, list) { - set_access(acc, wh->access); - set_majmin(maj, wh->major); - set_majmin(min, wh->minor); - seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type), + /* + * To preserve the compatibility: + * - Only show the "all devices" when the default policy is to allow + * - List the exceptions in case the default policy is to deny + * This way, the file remains as a "whitelist of devices" + */ + if (devcgroup->deny_all == false) { + set_access(acc, ACC_MASK); + set_majmin(maj, ~0); + set_majmin(min, ~0); + seq_printf(m, "%c %s:%s %s\n", type_to_char(DEV_ALL), maj, min, acc); + } else { + list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) { + set_access(acc, ex->access); + set_majmin(maj, ex->major); + set_majmin(min, ex->minor); + seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type), + maj, min, acc); + } } rcu_read_unlock(); return 0; } -/* - * may_access_whitelist: - * does the access granted to dev_cgroup c contain the access - * requested in whitelist item refwh. - * return 1 if yes, 0 if no. - * call with devcgroup_mutex held +/** + * may_access - verifies if a new exception is part of what is allowed + * by a dev cgroup based on the default policy + + * exceptions. This is used to make sure a child cgroup + * won't have more privileges than its parent or to + * verify if a certain access is allowed. + * @dev_cgroup: dev cgroup to be tested against + * @refex: new exception */ -static int may_access_whitelist(struct dev_cgroup *c, - struct dev_whitelist_item *refwh) +static int may_access(struct dev_cgroup *dev_cgroup, + struct dev_exception_item *refex) { - struct dev_whitelist_item *whitem; + struct dev_exception_item *ex; + bool match = false; - list_for_each_entry(whitem, &c->whitelist, list) { - if (whitem->type & DEV_ALL) - return 1; - if ((refwh->type & DEV_BLOCK) && !(whitem->type & DEV_BLOCK)) + list_for_each_entry(ex, &dev_cgroup->exceptions, list) { + if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) continue; - if ((refwh->type & DEV_CHAR) && !(whitem->type & DEV_CHAR)) + if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR)) continue; - if (whitem->major != ~0 && whitem->major != refwh->major) + if (ex->major != ~0 && ex->major != refex->major) continue; - if (whitem->minor != ~0 && whitem->minor != refwh->minor) + if (ex->minor != ~0 && ex->minor != refex->minor) continue; - if (refwh->access & (~whitem->access)) + if (refex->access & (~ex->access)) continue; - return 1; + match = true; + break; } + + /* + * In two cases we'll consider this new exception valid: + * - the dev cgroup has its default policy to allow + exception list: + * the new exception should *not* match any of the exceptions + * (!deny_all, !match) + * - the dev cgroup has its default policy to deny + exception list: + * the new exception *should* match the exceptions + * (deny_all, match) + */ + if (dev_cgroup->deny_all == match) + return 1; return 0; } /* * parent_has_perm: - * when adding a new allow rule to a device whitelist, the rule + * when adding a new allow rule to a device exception list, the rule * must be allowed in the parent device */ static int parent_has_perm(struct dev_cgroup *childcg, - struct dev_whitelist_item *wh) + struct dev_exception_item *ex) { struct cgroup *pcg = childcg->css.cgroup->parent; struct dev_cgroup *parent; @@ -309,17 +338,17 @@ static int parent_has_perm(struct dev_cgroup *childcg, if (!pcg) return 1; parent = cgroup_to_devcgroup(pcg); - return may_access_whitelist(parent, wh); + return may_access(parent, ex); } /* - * Modify the whitelist using allow/deny rules. + * Modify the exception list using allow/deny rules. * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD * so we can give a container CAP_MKNOD to let it create devices but not - * modify the whitelist. + * modify the exception list. * It seems likely we'll want to add a CAP_CONTAINER capability to allow * us to also grant CAP_SYS_ADMIN to containers without giving away the - * device whitelist controls, but for now we'll stick with CAP_SYS_ADMIN + * device exception list controls, but for now we'll stick with CAP_SYS_ADMIN * * Taking rules away is always allowed (given CAP_SYS_ADMIN). Granting * new access is only allowed if you're in the top-level cgroup, or your @@ -331,26 +360,36 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, const char *b; char *endp; int count; - struct dev_whitelist_item wh; + struct dev_exception_item ex; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - memset(&wh, 0, sizeof(wh)); + memset(&ex, 0, sizeof(ex)); b = buffer; switch (*b) { case 'a': - wh.type = DEV_ALL; - wh.access = ACC_MASK; - wh.major = ~0; - wh.minor = ~0; - goto handle; + switch (filetype) { + case DEVCG_ALLOW: + if (!parent_has_perm(devcgroup, &ex)) + return -EPERM; + dev_exception_clean(devcgroup); + devcgroup->deny_all = false; + break; + case DEVCG_DENY: + dev_exception_clean(devcgroup); + devcgroup->deny_all = true; + break; + default: + return -EINVAL; + } + return 0; case 'b': - wh.type = DEV_BLOCK; + ex.type = DEV_BLOCK; break; case 'c': - wh.type = DEV_CHAR; + ex.type = DEV_CHAR; break; default: return -EINVAL; @@ -360,10 +399,10 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, return -EINVAL; b++; if (*b == '*') { - wh.major = ~0; + ex.major = ~0; b++; } else if (isdigit(*b)) { - wh.major = simple_strtoul(b, &endp, 10); + ex.major = simple_strtoul(b, &endp, 10); b = endp; } else { return -EINVAL; @@ -374,10 +413,10 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, /* read minor */ if (*b == '*') { - wh.minor = ~0; + ex.minor = ~0; b++; } else if (isdigit(*b)) { - wh.minor = simple_strtoul(b, &endp, 10); + ex.minor = simple_strtoul(b, &endp, 10); b = endp; } else { return -EINVAL; @@ -387,13 +426,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, for (b++, count = 0; count < 3; count++, b++) { switch (*b) { case 'r': - wh.access |= ACC_READ; + ex.access |= ACC_READ; break; case 'w': - wh.access |= ACC_WRITE; + ex.access |= ACC_WRITE; break; case 'm': - wh.access |= ACC_MKNOD; + ex.access |= ACC_MKNOD; break; case '\n': case '\0': @@ -404,15 +443,31 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, } } -handle: switch (filetype) { case DEVCG_ALLOW: - if (!parent_has_perm(devcgroup, &wh)) + if (!parent_has_perm(devcgroup, &ex)) return -EPERM; - return dev_whitelist_add(devcgroup, &wh); + /* + * If the default policy is to allow by default, try to remove + * an matching exception instead. And be silent about it: we + * don't want to break compatibility + */ + if (devcgroup->deny_all == false) { + dev_exception_rm(devcgroup, &ex); + return 0; + } + return dev_exception_add(devcgroup, &ex); case DEVCG_DENY: - dev_whitelist_rm(devcgroup, &wh); - break; + /* + * If the default policy is to deny by default, try to remove + * an matching exception instead. And be silent about it: we + * don't want to break compatibility + */ + if (devcgroup->deny_all == true) { + dev_exception_rm(devcgroup, &ex); + return 0; + } + return dev_exception_add(devcgroup, &ex); default: return -EINVAL; } @@ -468,73 +523,71 @@ struct cgroup_subsys devices_subsys = { .broken_hierarchy = true, }; -int __devcgroup_inode_permission(struct inode *inode, int mask) +/** + * __devcgroup_check_permission - checks if an inode operation is permitted + * @dev_cgroup: the dev cgroup to be tested against + * @type: device type + * @major: device major number + * @minor: device minor number + * @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD + * + * returns 0 on success, -EPERM case the operation is not permitted + */ +static int __devcgroup_check_permission(struct dev_cgroup *dev_cgroup, + short type, u32 major, u32 minor, + short access) { - struct dev_cgroup *dev_cgroup; - struct dev_whitelist_item *wh; - - rcu_read_lock(); + struct dev_exception_item ex; + int rc; - dev_cgroup = task_devcgroup(current); + memset(&ex, 0, sizeof(ex)); + ex.type = type; + ex.major = major; + ex.minor = minor; + ex.access = access; - list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) { - if (wh->type & DEV_ALL) - goto found; - if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode)) - continue; - if ((wh->type & DEV_CHAR) && !S_ISCHR(inode->i_mode)) - continue; - if (wh->major != ~0 && wh->major != imajor(inode)) - continue; - if (wh->minor != ~0 && wh->minor != iminor(inode)) - continue; + rcu_read_lock(); + rc = may_access(dev_cgroup, &ex); + rcu_read_unlock(); - if ((mask & MAY_WRITE) && !(wh->access & ACC_WRITE)) - continue; - if ((mask & MAY_READ) && !(wh->access & ACC_READ)) - continue; -found: - rcu_read_unlock(); - return 0; - } + if (!rc) + return -EPERM; - rcu_read_unlock(); + return 0; +} - return -EPERM; +int __devcgroup_inode_permission(struct inode *inode, int mask) +{ + struct dev_cgroup *dev_cgroup = task_devcgroup(current); + short type, access = 0; + + if (S_ISBLK(inode->i_mode)) + type = DEV_BLOCK; + if (S_ISCHR(inode->i_mode)) + type = DEV_CHAR; + if (mask & MAY_WRITE) + access |= ACC_WRITE; + if (mask & MAY_READ) + access |= ACC_READ; + + return __devcgroup_check_permission(dev_cgroup, type, imajor(inode), + iminor(inode), access); } int devcgroup_inode_mknod(int mode, dev_t dev) { - struct dev_cgroup *dev_cgroup; - struct dev_whitelist_item *wh; + struct dev_cgroup *dev_cgroup = task_devcgroup(current); + short type; if (!S_ISBLK(mode) && !S_ISCHR(mode)) return 0; - rcu_read_lock(); - - dev_cgroup = task_devcgroup(current); - - list_for_each_entry_rcu(wh, &dev_cgroup->whitelist, list) { - if (wh->type & DEV_ALL) - goto found; - if ((wh->type & DEV_BLOCK) && !S_ISBLK(mode)) - continue; - if ((wh->type & DEV_CHAR) && !S_ISCHR(mode)) - continue; - if (wh->major != ~0 && wh->major != MAJOR(dev)) - continue; - if (wh->minor != ~0 && wh->minor != MINOR(dev)) - continue; - - if (!(wh->access & ACC_MKNOD)) - continue; -found: - rcu_read_unlock(); - return 0; - } + if (S_ISBLK(mode)) + type = DEV_BLOCK; + else + type = DEV_CHAR; - rcu_read_unlock(); + return __devcgroup_check_permission(dev_cgroup, type, MAJOR(dev), + MINOR(dev), ACC_MKNOD); - return -EPERM; } diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index f4817292ef45..aa62c0e44cb6 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1233,7 +1233,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static const __devinitdata struct reg_default wm5100_reva_patches[] = { +static const __devinitconst struct reg_default wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 85baf11e2acd..43480149119e 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -1,4 +1,4 @@ -TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug +TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll all: for TARGET in $(TARGETS); do \ diff --git a/tools/testing/selftests/epoll/Makefile b/tools/testing/selftests/epoll/Makefile new file mode 100644 index 000000000000..19806ed62f50 --- /dev/null +++ b/tools/testing/selftests/epoll/Makefile @@ -0,0 +1,11 @@ +# Makefile for epoll selftests + +all: test_epoll +%: %.c + gcc -pthread -g -o $@ $^ + +run_tests: all + ./test_epoll + +clean: + $(RM) test_epoll diff --git a/tools/testing/selftests/epoll/test_epoll.c b/tools/testing/selftests/epoll/test_epoll.c new file mode 100644 index 000000000000..e0fcff1e8331 --- /dev/null +++ b/tools/testing/selftests/epoll/test_epoll.c @@ -0,0 +1,344 @@ +/* + * tools/testing/selftests/epoll/test_epoll.c + * + * Copyright 2012 Adobe Systems Incorporated + * + * 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. + * + * Paton J. Lewis <palewis@adobe.com> + * + */ + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/epoll.h> +#include <sys/socket.h> + +/* + * A pointer to an epoll_item_private structure will be stored in the epoll + * item's event structure so that we can get access to the epoll_item_private + * data after calling epoll_wait: + */ +struct epoll_item_private { + int index; /* Position of this struct within the epoll_items array. */ + int fd; + uint32_t events; + pthread_mutex_t mutex; /* Guards the following variables... */ + int stop; + int status; /* Stores any error encountered while handling item. */ + /* The following variable allows us to test whether we have encountered + a problem while attempting to cancel and delete the associated + event. When the test program exits, 'deleted' should be exactly + one. If it is greater than one, then the failed test reflects a real + world situation where we would have tried to access the epoll item's + private data after deleting it: */ + int deleted; +}; + +struct epoll_item_private *epoll_items; + +/* + * Delete the specified item from the epoll set. In a real-world secneario this + * is where we would free the associated data structure, but in this testing + * environment we retain the structure so that we can test for double-deletion: + */ +void delete_item(int index) +{ + __sync_fetch_and_add(&epoll_items[index].deleted, 1); +} + +/* + * A pointer to a read_thread_data structure will be passed as the argument to + * each read thread: + */ +struct read_thread_data { + int stop; + int status; /* Indicates any error encountered by the read thread. */ + int epoll_set; +}; + +/* + * The function executed by the read threads: + */ +void *read_thread_function(void *function_data) +{ + struct read_thread_data *thread_data = + (struct read_thread_data *)function_data; + struct epoll_event event_data; + struct epoll_item_private *item_data; + char socket_data; + + /* Handle events until we encounter an error or this thread's 'stop' + condition is set: */ + while (1) { + int result = epoll_wait(thread_data->epoll_set, + &event_data, + 1, /* Number of desired events */ + 1000); /* Timeout in ms */ + if (result < 0) { + /* Breakpoints signal all threads. Ignore that while + debugging: */ + if (errno == EINTR) + continue; + thread_data->status = errno; + return 0; + } else if (thread_data->stop) + return 0; + else if (result == 0) /* Timeout */ + continue; + + /* We need the mutex here because checking for the stop + condition and re-enabling the epoll item need to be done + together as one atomic operation when EPOLL_CTL_DISABLE is + available: */ + item_data = (struct epoll_item_private *)event_data.data.ptr; + pthread_mutex_lock(&item_data->mutex); + + /* Remove the item from the epoll set if we want to stop + handling that event: */ + if (item_data->stop) + delete_item(item_data->index); + else { + /* Clear the data that was written to the other end of + our non-blocking socket: */ + do { + if (read(item_data->fd, &socket_data, 1) < 1) { + if ((errno == EAGAIN) || + (errno == EWOULDBLOCK)) + break; + else + goto error_unlock; + } + } while (item_data->events & EPOLLET); + + /* The item was one-shot, so re-enable it: */ + event_data.events = item_data->events; + if (epoll_ctl(thread_data->epoll_set, + EPOLL_CTL_MOD, + item_data->fd, + &event_data) < 0) + goto error_unlock; + } + + pthread_mutex_unlock(&item_data->mutex); + } + +error_unlock: + thread_data->status = item_data->status = errno; + pthread_mutex_unlock(&item_data->mutex); + return 0; +} + +/* + * A pointer to a write_thread_data structure will be passed as the argument to + * the write thread: + */ +struct write_thread_data { + int stop; + int status; /* Indicates any error encountered by the write thread. */ + int n_fds; + int *fds; +}; + +/* + * The function executed by the write thread. It writes a single byte to each + * socket in turn until the stop condition for this thread is set. If writing to + * a socket would block (i.e. errno was EAGAIN), we leave that socket alone for + * the moment and just move on to the next socket in the list. We don't care + * about the order in which we deliver events to the epoll set. In fact we don't + * care about the data we're writing to the pipes at all; we just want to + * trigger epoll events: + */ +void *write_thread_function(void *function_data) +{ + const char data = 'X'; + int index; + struct write_thread_data *thread_data = + (struct write_thread_data *)function_data; + while (!write_thread_data->stop) + for (index = 0; + !thread_data->stop && (index < thread_data->n_fds); + ++index) + if ((write(thread_data->fds[index], &data, 1) < 1) && + (errno != EAGAIN) && + (errno != EWOULDBLOCK)) { + write_thread_data->status = errno; + return; + } +} + +/* + * Arguments are currently ignored: + */ +int main(int argc, char **argv) +{ + const int n_read_threads = 100; + const int n_epoll_items = 500; + int index; + int epoll_set = epoll_create1(0); + struct write_thread_data write_thread_data = { + 0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int)) + }; + struct read_thread_data *read_thread_data = + malloc(n_read_threads * sizeof(struct read_thread_data)); + pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t)); + pthread_t write_thread; + + printf("-----------------\n"); + printf("Runing test_epoll\n"); + printf("-----------------\n"); + + epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private)); + + if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 || + read_thread_data == 0 || read_threads == 0) + goto error; + + if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { + printf("Error: please run this test on a multi-core system.\n"); + goto error; + } + + /* Create the socket pairs and epoll items: */ + for (index = 0; index < n_epoll_items; ++index) { + int socket_pair[2]; + struct epoll_event event_data; + if (socketpair(AF_UNIX, + SOCK_STREAM | SOCK_NONBLOCK, + 0, + socket_pair) < 0) + goto error; + write_thread_data.fds[index] = socket_pair[0]; + epoll_items[index].index = index; + epoll_items[index].fd = socket_pair[1]; + if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0) + goto error; + /* We always use EPOLLONESHOT because this test is currently + structured to demonstrate the need for EPOLL_CTL_DISABLE, + which only produces useful information in the EPOLLONESHOT + case (without EPOLLONESHOT, calling epoll_ctl with + EPOLL_CTL_DISABLE will never return EBUSY). If support for + testing events without EPOLLONESHOT is desired, it should + probably be implemented in a separate unit test. */ + epoll_items[index].events = EPOLLIN | EPOLLONESHOT; + if (index < n_epoll_items / 2) + epoll_items[index].events |= EPOLLET; + epoll_items[index].stop = 0; + epoll_items[index].status = 0; + epoll_items[index].deleted = 0; + event_data.events = epoll_items[index].events; + event_data.data.ptr = &epoll_items[index]; + if (epoll_ctl(epoll_set, + EPOLL_CTL_ADD, + epoll_items[index].fd, + &event_data) < 0) + goto error; + } + + /* Create and start the read threads: */ + for (index = 0; index < n_read_threads; ++index) { + read_thread_data[index].stop = 0; + read_thread_data[index].status = 0; + read_thread_data[index].epoll_set = epoll_set; + if (pthread_create(&read_threads[index], + NULL, + read_thread_function, + &read_thread_data[index]) != 0) + goto error; + } + + if (pthread_create(&write_thread, + NULL, + write_thread_function, + &write_thread_data) != 0) + goto error; + + /* Cancel all event pollers: */ +#ifdef EPOLL_CTL_DISABLE + for (index = 0; index < n_epoll_items; ++index) { + pthread_mutex_lock(&epoll_items[index].mutex); + ++epoll_items[index].stop; + if (epoll_ctl(epoll_set, + EPOLL_CTL_DISABLE, + epoll_items[index].fd, + NULL) == 0) + delete_item(index); + else if (errno != EBUSY) { + pthread_mutex_unlock(&epoll_items[index].mutex); + goto error; + } + /* EBUSY means events were being handled; allow the other thread + to delete the item. */ + pthread_mutex_unlock(&epoll_items[index].mutex); + } +#else + for (index = 0; index < n_epoll_items; ++index) { + pthread_mutex_lock(&epoll_items[index].mutex); + ++epoll_items[index].stop; + pthread_mutex_unlock(&epoll_items[index].mutex); + /* Wait in case a thread running read_thread_function is + currently executing code between epoll_wait and + pthread_mutex_lock with this item. Note that a longer delay + would make double-deletion less likely (at the expense of + performance), but there is no guarantee that any delay would + ever be sufficient. Note also that we delete all event + pollers at once for testing purposes, but in a real-world + environment we are likely to want to be able to cancel event + pollers at arbitrary times. Therefore we can't improve this + situation by just splitting this loop into two loops + (i.e. signal 'stop' for all items, sleep, and then delete all + items). We also can't fix the problem via EPOLL_CTL_DEL + because that command can't prevent the case where some other + thread is executing read_thread_function within the region + mentioned above: */ + usleep(1); + pthread_mutex_lock(&epoll_items[index].mutex); + if (!epoll_items[index].deleted) + delete_item(index); + pthread_mutex_unlock(&epoll_items[index].mutex); + } +#endif + + /* Shut down the read threads: */ + for (index = 0; index < n_read_threads; ++index) + __sync_fetch_and_add(&read_thread_data[index].stop, 1); + for (index = 0; index < n_read_threads; ++index) { + if (pthread_join(read_threads[index], NULL) != 0) + goto error; + if (read_thread_data[index].status) + goto error; + } + + /* Shut down the write thread: */ + __sync_fetch_and_add(&write_thread_data.stop, 1); + if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status) + goto error; + + /* Check for final error conditions: */ + for (index = 0; index < n_epoll_items; ++index) { + if (epoll_items[index].status != 0) + goto error; + if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0) + goto error; + } + for (index = 0; index < n_epoll_items; ++index) + if (epoll_items[index].deleted != 1) { + printf("Error: item data deleted %1d times.\n", + epoll_items[index].deleted); + goto error; + } + + printf("[PASS]\n"); + return 0; + + error: + printf("[FAIL]\n"); + return errno; +} diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 28694f4a9139..d01b24b72c61 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -21,3 +21,6 @@ config KVM_ASYNC_PF config HAVE_KVM_MSI bool + +config HAVE_KVM_CPU_RELAX_INTERCEPT + bool diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 74268b4c2ee1..ea475cd03511 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -111,8 +111,8 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) list_entry(vcpu->async_pf.done.next, typeof(*work), link); list_del(&work->link); - if (work->page) - put_page(work->page); + if (!is_error_page(work->page)) + kvm_release_page_clean(work->page); kmem_cache_free(async_pf_cache, work); } spin_unlock(&vcpu->async_pf.lock); @@ -138,8 +138,8 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu) list_del(&work->queue); vcpu->async_pf.queued--; - if (work->page) - put_page(work->page); + if (!is_error_page(work->page)) + kvm_release_page_clean(work->page); kmem_cache_free(async_pf_cache, work); } } @@ -203,8 +203,7 @@ int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu) if (!work) return -ENOMEM; - work->page = bad_page; - get_page(bad_page); + work->page = KVM_ERR_PTR_BAD_PAGE; INIT_LIST_HEAD(&work->queue); /* for list_del to work */ spin_lock(&vcpu->async_pf.lock); diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 67a35e90384c..9718e98d6d2a 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -43,6 +43,31 @@ * -------------------------------------------------------------------- */ +/* + * Resampling irqfds are a special variety of irqfds used to emulate + * level triggered interrupts. The interrupt is asserted on eventfd + * trigger. On acknowledgement through the irq ack notifier, the + * interrupt is de-asserted and userspace is notified through the + * resamplefd. All resamplers on the same gsi are de-asserted + * together, so we don't need to track the state of each individual + * user. We can also therefore share the same irq source ID. + */ +struct _irqfd_resampler { + struct kvm *kvm; + /* + * List of resampling struct _irqfd objects sharing this gsi. + * RCU list modified under kvm->irqfds.resampler_lock + */ + struct list_head list; + struct kvm_irq_ack_notifier notifier; + /* + * Entry in list of kvm->irqfd.resampler_list. Use for sharing + * resamplers among irqfds on the same gsi. + * Accessed and modified under kvm->irqfds.resampler_lock + */ + struct list_head link; +}; + struct _irqfd { /* Used for MSI fast-path */ struct kvm *kvm; @@ -52,6 +77,12 @@ struct _irqfd { /* Used for level IRQ fast-path */ int gsi; struct work_struct inject; + /* The resampler used by this irqfd (resampler-only) */ + struct _irqfd_resampler *resampler; + /* Eventfd notified on resample (resampler-only) */ + struct eventfd_ctx *resamplefd; + /* Entry in list of irqfds for a resampler (resampler-only) */ + struct list_head resampler_link; /* Used for setup/shutdown */ struct eventfd_ctx *eventfd; struct list_head list; @@ -67,8 +98,58 @@ irqfd_inject(struct work_struct *work) struct _irqfd *irqfd = container_of(work, struct _irqfd, inject); struct kvm *kvm = irqfd->kvm; - kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1); - kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0); + if (!irqfd->resampler) { + kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1); + kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0); + } else + kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, + irqfd->gsi, 1); +} + +/* + * Since resampler irqfds share an IRQ source ID, we de-assert once + * then notify all of the resampler irqfds using this GSI. We can't + * do multiple de-asserts or we risk racing with incoming re-asserts. + */ +static void +irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian) +{ + struct _irqfd_resampler *resampler; + struct _irqfd *irqfd; + + resampler = container_of(kian, struct _irqfd_resampler, notifier); + + kvm_set_irq(resampler->kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, + resampler->notifier.gsi, 0); + + rcu_read_lock(); + + list_for_each_entry_rcu(irqfd, &resampler->list, resampler_link) + eventfd_signal(irqfd->resamplefd, 1); + + rcu_read_unlock(); +} + +static void +irqfd_resampler_shutdown(struct _irqfd *irqfd) +{ + struct _irqfd_resampler *resampler = irqfd->resampler; + struct kvm *kvm = resampler->kvm; + + mutex_lock(&kvm->irqfds.resampler_lock); + + list_del_rcu(&irqfd->resampler_link); + synchronize_rcu(); + + if (list_empty(&resampler->list)) { + list_del(&resampler->link); + kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier); + kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, + resampler->notifier.gsi, 0); + kfree(resampler); + } + + mutex_unlock(&kvm->irqfds.resampler_lock); } /* @@ -92,6 +173,11 @@ irqfd_shutdown(struct work_struct *work) */ flush_work(&irqfd->inject); + if (irqfd->resampler) { + irqfd_resampler_shutdown(irqfd); + eventfd_ctx_put(irqfd->resamplefd); + } + /* * It is now safe to release the object's resources */ @@ -203,7 +289,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) struct kvm_irq_routing_table *irq_rt; struct _irqfd *irqfd, *tmp; struct file *file = NULL; - struct eventfd_ctx *eventfd = NULL; + struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL; int ret; unsigned int events; @@ -231,6 +317,54 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) irqfd->eventfd = eventfd; + if (args->flags & KVM_IRQFD_FLAG_RESAMPLE) { + struct _irqfd_resampler *resampler; + + resamplefd = eventfd_ctx_fdget(args->resamplefd); + if (IS_ERR(resamplefd)) { + ret = PTR_ERR(resamplefd); + goto fail; + } + + irqfd->resamplefd = resamplefd; + INIT_LIST_HEAD(&irqfd->resampler_link); + + mutex_lock(&kvm->irqfds.resampler_lock); + + list_for_each_entry(resampler, + &kvm->irqfds.resampler_list, list) { + if (resampler->notifier.gsi == irqfd->gsi) { + irqfd->resampler = resampler; + break; + } + } + + if (!irqfd->resampler) { + resampler = kzalloc(sizeof(*resampler), GFP_KERNEL); + if (!resampler) { + ret = -ENOMEM; + mutex_unlock(&kvm->irqfds.resampler_lock); + goto fail; + } + + resampler->kvm = kvm; + INIT_LIST_HEAD(&resampler->list); + resampler->notifier.gsi = irqfd->gsi; + resampler->notifier.irq_acked = irqfd_resampler_ack; + INIT_LIST_HEAD(&resampler->link); + + list_add(&resampler->link, &kvm->irqfds.resampler_list); + kvm_register_irq_ack_notifier(kvm, + &resampler->notifier); + irqfd->resampler = resampler; + } + + list_add_rcu(&irqfd->resampler_link, &irqfd->resampler->list); + synchronize_rcu(); + + mutex_unlock(&kvm->irqfds.resampler_lock); + } + /* * Install our own custom wake-up handling so we are notified via * a callback whenever someone signals the underlying eventfd @@ -276,6 +410,12 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) return 0; fail: + if (irqfd->resampler) + irqfd_resampler_shutdown(irqfd); + + if (resamplefd && !IS_ERR(resamplefd)) + eventfd_ctx_put(resamplefd); + if (eventfd && !IS_ERR(eventfd)) eventfd_ctx_put(eventfd); @@ -291,6 +431,8 @@ kvm_eventfd_init(struct kvm *kvm) { spin_lock_init(&kvm->irqfds.lock); INIT_LIST_HEAD(&kvm->irqfds.items); + INIT_LIST_HEAD(&kvm->irqfds.resampler_list); + mutex_init(&kvm->irqfds.resampler_lock); INIT_LIST_HEAD(&kvm->ioeventfds); } @@ -340,7 +482,7 @@ kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args) int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args) { - if (args->flags & ~KVM_IRQFD_FLAG_DEASSIGN) + if (args->flags & ~(KVM_IRQFD_FLAG_DEASSIGN | KVM_IRQFD_FLAG_RESAMPLE)) return -EINVAL; if (args->flags & KVM_IRQFD_FLAG_DEASSIGN) diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index ef61d529a6c4..cfb7e4d52dc2 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -197,28 +197,29 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id, u32 old_irr; u32 mask = 1 << irq; union kvm_ioapic_redirect_entry entry; - int ret = 1; + int ret, irq_level; + + BUG_ON(irq < 0 || irq >= IOAPIC_NUM_PINS); spin_lock(&ioapic->lock); old_irr = ioapic->irr; - if (irq >= 0 && irq < IOAPIC_NUM_PINS) { - int irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq], - irq_source_id, level); - entry = ioapic->redirtbl[irq]; - irq_level ^= entry.fields.polarity; - if (!irq_level) - ioapic->irr &= ~mask; - else { - int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); - ioapic->irr |= mask; - if ((edge && old_irr != ioapic->irr) || - (!edge && !entry.fields.remote_irr)) - ret = ioapic_service(ioapic, irq); - else - ret = 0; /* report coalesced interrupt */ - } - trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); + irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq], + irq_source_id, level); + entry = ioapic->redirtbl[irq]; + irq_level ^= entry.fields.polarity; + if (!irq_level) { + ioapic->irr &= ~mask; + ret = 1; + } else { + int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); + ioapic->irr |= mask; + if ((edge && old_irr != ioapic->irr) || + (!edge && !entry.fields.remote_irr)) + ret = ioapic_service(ioapic, irq); + else + ret = 0; /* report coalesced interrupt */ } + trace_kvm_ioapic_set_irq(entry.bits, irq, ret == 0); spin_unlock(&ioapic->lock); return ret; diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index e9fff9830bf0..037cb6730e68 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -42,13 +42,13 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm); static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages); -static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot, - gfn_t gfn, unsigned long size) +static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, + unsigned long size) { gfn_t end_gfn; pfn_t pfn; - pfn = gfn_to_pfn_memslot(kvm, slot, gfn); + pfn = gfn_to_pfn_memslot(slot, gfn); end_gfn = gfn + (size >> PAGE_SHIFT); gfn += 1; @@ -56,7 +56,7 @@ static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot, return pfn; while (gfn < end_gfn) - gfn_to_pfn_memslot(kvm, slot, gfn++); + gfn_to_pfn_memslot(slot, gfn++); return pfn; } @@ -105,7 +105,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) * Pin all pages we are about to map in memory. This is * important because we unmap and unpin in 4kb steps later. */ - pfn = kvm_pin_pages(kvm, slot, gfn, page_size); + pfn = kvm_pin_pages(slot, gfn, page_size); if (is_error_pfn(pfn)) { gfn += 1; continue; @@ -300,6 +300,12 @@ static void kvm_iommu_put_pages(struct kvm *kvm, /* Get physical address */ phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); + + if (!phys) { + gfn++; + continue; + } + pfn = phys >> PAGE_SHIFT; /* Unmap address from IO address space */ diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 83402d74a767..2eb58af7ee99 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -68,8 +68,13 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, struct kvm_vcpu *vcpu, *lowest = NULL; if (irq->dest_mode == 0 && irq->dest_id == 0xff && - kvm_is_dm_lowest_prio(irq)) + kvm_is_dm_lowest_prio(irq)) { printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); + irq->delivery_mode = APIC_DM_FIXED; + } + + if (kvm_irq_delivery_to_apic_fast(kvm, src, irq, &r)) + return r; kvm_for_each_vcpu(i, vcpu, kvm) { if (!kvm_apic_present(vcpu)) @@ -223,6 +228,9 @@ int kvm_request_irq_source_id(struct kvm *kvm) } ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); +#ifdef CONFIG_X86 + ASSERT(irq_source_id != KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID); +#endif set_bit(irq_source_id, bitmap); unlock: mutex_unlock(&kvm->irq_lock); @@ -233,6 +241,9 @@ unlock: void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) { ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); +#ifdef CONFIG_X86 + ASSERT(irq_source_id != KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID); +#endif mutex_lock(&kvm->irq_lock); if (irq_source_id < 0 || @@ -321,11 +332,11 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt, switch (ue->u.irqchip.irqchip) { case KVM_IRQCHIP_PIC_MASTER: e->set = kvm_set_pic_irq; - max_pin = 16; + max_pin = PIC_NUM_PINS; break; case KVM_IRQCHIP_PIC_SLAVE: e->set = kvm_set_pic_irq; - max_pin = 16; + max_pin = PIC_NUM_PINS; delta = 8; break; case KVM_IRQCHIP_IOAPIC: diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d617f69131d7..e59bb63cb089 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -100,13 +100,7 @@ EXPORT_SYMBOL_GPL(kvm_rebooting); static bool largepages_enabled = true; -static struct page *hwpoison_page; -static pfn_t hwpoison_pfn; - -struct page *fault_page; -pfn_t fault_pfn; - -inline int kvm_is_mmio_pfn(pfn_t pfn) +bool kvm_is_mmio_pfn(pfn_t pfn) { if (pfn_valid(pfn)) { int reserved; @@ -137,11 +131,12 @@ inline int kvm_is_mmio_pfn(pfn_t pfn) /* * Switches to specified vcpu, until a matching vcpu_put() */ -void vcpu_load(struct kvm_vcpu *vcpu) +int vcpu_load(struct kvm_vcpu *vcpu) { int cpu; - mutex_lock(&vcpu->mutex); + if (mutex_lock_killable(&vcpu->mutex)) + return -EINTR; if (unlikely(vcpu->pid != current->pids[PIDTYPE_PID].pid)) { /* The thread running this VCPU changed. */ struct pid *oldpid = vcpu->pid; @@ -154,6 +149,7 @@ void vcpu_load(struct kvm_vcpu *vcpu) preempt_notifier_register(&vcpu->preempt_notifier); kvm_arch_vcpu_load(vcpu, cpu); put_cpu(); + return 0; } void vcpu_put(struct kvm_vcpu *vcpu) @@ -236,6 +232,9 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) } vcpu->run = page_address(page); + kvm_vcpu_set_in_spin_loop(vcpu, false); + kvm_vcpu_set_dy_eligible(vcpu, false); + r = kvm_arch_vcpu_init(vcpu); if (r < 0) goto fail_free_run; @@ -332,8 +331,7 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, * count is also read inside the mmu_lock critical section. */ kvm->mmu_notifier_count++; - for (; start < end; start += PAGE_SIZE) - need_tlb_flush |= kvm_unmap_hva(kvm, start); + need_tlb_flush = kvm_unmap_hva_range(kvm, start, end); need_tlb_flush |= kvm->tlbs_dirty; /* we've to flush the tlb before the pages can be freed */ if (need_tlb_flush) @@ -412,7 +410,7 @@ static void kvm_mmu_notifier_release(struct mmu_notifier *mn, int idx; idx = srcu_read_lock(&kvm->srcu); - kvm_arch_flush_shadow(kvm); + kvm_arch_flush_shadow_all(kvm); srcu_read_unlock(&kvm->srcu, idx); } @@ -551,16 +549,12 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot) static void kvm_free_physmem_slot(struct kvm_memory_slot *free, struct kvm_memory_slot *dont) { - if (!dont || free->rmap != dont->rmap) - vfree(free->rmap); - if (!dont || free->dirty_bitmap != dont->dirty_bitmap) kvm_destroy_dirty_bitmap(free); kvm_arch_free_memslot(free, dont); free->npages = 0; - free->rmap = NULL; } void kvm_free_physmem(struct kvm *kvm) @@ -590,7 +584,7 @@ static void kvm_destroy_vm(struct kvm *kvm) #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm); #else - kvm_arch_flush_shadow(kvm); + kvm_arch_flush_shadow_all(kvm); #endif kvm_arch_destroy_vm(kvm); kvm_free_physmem(kvm); @@ -686,6 +680,20 @@ void update_memslots(struct kvm_memslots *slots, struct kvm_memory_slot *new) slots->generation++; } +static int check_memory_region_flags(struct kvm_userspace_memory_region *mem) +{ + u32 valid_flags = KVM_MEM_LOG_DIRTY_PAGES; + +#ifdef KVM_CAP_READONLY_MEM + valid_flags |= KVM_MEM_READONLY; +#endif + + if (mem->flags & ~valid_flags) + return -EINVAL; + + return 0; +} + /* * Allocate some memory and give it an address in the guest physical address * space. @@ -706,6 +714,10 @@ int __kvm_set_memory_region(struct kvm *kvm, struct kvm_memory_slot old, new; struct kvm_memslots *slots, *old_memslots; + r = check_memory_region_flags(mem); + if (r) + goto out; + r = -EINVAL; /* General sanity checks */ if (mem->memory_size & (PAGE_SIZE - 1)) @@ -769,11 +781,7 @@ int __kvm_set_memory_region(struct kvm *kvm, if (npages && !old.npages) { new.user_alloc = user_alloc; new.userspace_addr = mem->userspace_addr; -#ifndef CONFIG_S390 - new.rmap = vzalloc(npages * sizeof(*new.rmap)); - if (!new.rmap) - goto out_free; -#endif /* not defined CONFIG_S390 */ + if (kvm_arch_create_memslot(&new, npages)) goto out_free; } @@ -785,7 +793,7 @@ int __kvm_set_memory_region(struct kvm *kvm, /* destroy any largepage mappings for dirty tracking */ } - if (!npages) { + if (!npages || base_gfn != old.base_gfn) { struct kvm_memory_slot *slot; r = -ENOMEM; @@ -801,14 +809,14 @@ int __kvm_set_memory_region(struct kvm *kvm, old_memslots = kvm->memslots; rcu_assign_pointer(kvm->memslots, slots); synchronize_srcu_expedited(&kvm->srcu); - /* From this point no new shadow pages pointing to a deleted - * memslot will be created. + /* From this point no new shadow pages pointing to a deleted, + * or moved, memslot will be created. * * validation of sp->gfn happens in: * - gfn_to_hva (kvm_read_guest, gfn_to_pfn) * - kvm_is_visible_gfn (mmu_check_roots) */ - kvm_arch_flush_shadow(kvm); + kvm_arch_flush_shadow_memslot(kvm, slot); kfree(old_memslots); } @@ -832,7 +840,6 @@ int __kvm_set_memory_region(struct kvm *kvm, /* actual memory is freed via old in kvm_free_physmem_slot below */ if (!npages) { - new.rmap = NULL; new.dirty_bitmap = NULL; memset(&new.arch, 0, sizeof(new.arch)); } @@ -844,13 +851,6 @@ int __kvm_set_memory_region(struct kvm *kvm, kvm_arch_commit_memory_region(kvm, mem, old, user_alloc); - /* - * If the new memory slot is created, we need to clear all - * mmio sptes. - */ - if (npages && old.base_gfn != mem->guest_phys_addr >> PAGE_SHIFT) - kvm_arch_flush_shadow(kvm); - kvm_free_physmem_slot(&old, &new); kfree(old_memslots); @@ -932,53 +932,6 @@ void kvm_disable_largepages(void) } EXPORT_SYMBOL_GPL(kvm_disable_largepages); -int is_error_page(struct page *page) -{ - return page == bad_page || page == hwpoison_page || page == fault_page; -} -EXPORT_SYMBOL_GPL(is_error_page); - -int is_error_pfn(pfn_t pfn) -{ - return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn; -} -EXPORT_SYMBOL_GPL(is_error_pfn); - -int is_hwpoison_pfn(pfn_t pfn) -{ - return pfn == hwpoison_pfn; -} -EXPORT_SYMBOL_GPL(is_hwpoison_pfn); - -int is_fault_pfn(pfn_t pfn) -{ - return pfn == fault_pfn; -} -EXPORT_SYMBOL_GPL(is_fault_pfn); - -int is_noslot_pfn(pfn_t pfn) -{ - return pfn == bad_pfn; -} -EXPORT_SYMBOL_GPL(is_noslot_pfn); - -int is_invalid_pfn(pfn_t pfn) -{ - return pfn == hwpoison_pfn || pfn == fault_pfn; -} -EXPORT_SYMBOL_GPL(is_invalid_pfn); - -static inline unsigned long bad_hva(void) -{ - return PAGE_OFFSET; -} - -int kvm_is_error_hva(unsigned long addr) -{ - return addr == bad_hva(); -} -EXPORT_SYMBOL_GPL(kvm_is_error_hva); - struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) { return __gfn_to_memslot(kvm_memslots(kvm), gfn); @@ -1021,28 +974,62 @@ out: return size; } -static unsigned long gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, - gfn_t *nr_pages) +static bool memslot_is_readonly(struct kvm_memory_slot *slot) +{ + return slot->flags & KVM_MEM_READONLY; +} + +static unsigned long __gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, + gfn_t *nr_pages, bool write) { if (!slot || slot->flags & KVM_MEMSLOT_INVALID) - return bad_hva(); + return KVM_HVA_ERR_BAD; + + if (memslot_is_readonly(slot) && write) + return KVM_HVA_ERR_RO_BAD; if (nr_pages) *nr_pages = slot->npages - (gfn - slot->base_gfn); - return gfn_to_hva_memslot(slot, gfn); + return __gfn_to_hva_memslot(slot, gfn); } +static unsigned long gfn_to_hva_many(struct kvm_memory_slot *slot, gfn_t gfn, + gfn_t *nr_pages) +{ + return __gfn_to_hva_many(slot, gfn, nr_pages, true); +} + +unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, + gfn_t gfn) +{ + return gfn_to_hva_many(slot, gfn, NULL); +} +EXPORT_SYMBOL_GPL(gfn_to_hva_memslot); + unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) { return gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL); } EXPORT_SYMBOL_GPL(gfn_to_hva); -static pfn_t get_fault_pfn(void) +/* + * The hva returned by this function is only allowed to be read. + * It should pair with kvm_read_hva() or kvm_read_hva_atomic(). + */ +static unsigned long gfn_to_hva_read(struct kvm *kvm, gfn_t gfn) +{ + return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false); +} + +static int kvm_read_hva(void *data, void __user *hva, int len) { - get_page(fault_page); - return fault_pfn; + return __copy_from_user(data, hva, len); +} + +static int kvm_read_hva_atomic(void *data, void __user *hva, int len) +{ + return __copy_from_user_inatomic(data, hva, len); } int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm, @@ -1065,108 +1052,186 @@ static inline int check_user_page_hwpoison(unsigned long addr) return rc == -EHWPOISON; } -static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic, - bool *async, bool write_fault, bool *writable) +/* + * The atomic path to get the writable pfn which will be stored in @pfn, + * true indicates success, otherwise false is returned. + */ +static bool hva_to_pfn_fast(unsigned long addr, bool atomic, bool *async, + bool write_fault, bool *writable, pfn_t *pfn) { struct page *page[1]; - int npages = 0; - pfn_t pfn; + int npages; - /* we can do it either atomically or asynchronously, not both */ - BUG_ON(atomic && async); + if (!(async || atomic)) + return false; - BUG_ON(!write_fault && !writable); + /* + * Fast pin a writable pfn only if it is a write fault request + * or the caller allows to map a writable pfn for a read fault + * request. + */ + if (!(write_fault || writable)) + return false; - if (writable) - *writable = true; + npages = __get_user_pages_fast(addr, 1, 1, page); + if (npages == 1) { + *pfn = page_to_pfn(page[0]); - if (atomic || async) - npages = __get_user_pages_fast(addr, 1, 1, page); + if (writable) + *writable = true; + return true; + } - if (unlikely(npages != 1) && !atomic) { - might_sleep(); + return false; +} - if (writable) - *writable = write_fault; +/* + * The slow path to get the pfn of the specified host virtual address, + * 1 indicates success, -errno is returned if error is detected. + */ +static int hva_to_pfn_slow(unsigned long addr, bool *async, bool write_fault, + bool *writable, pfn_t *pfn) +{ + struct page *page[1]; + int npages = 0; - if (async) { - down_read(¤t->mm->mmap_sem); - npages = get_user_page_nowait(current, current->mm, - addr, write_fault, page); - up_read(¤t->mm->mmap_sem); - } else - npages = get_user_pages_fast(addr, 1, write_fault, - page); - - /* map read fault as writable if possible */ - if (unlikely(!write_fault) && npages == 1) { - struct page *wpage[1]; - - npages = __get_user_pages_fast(addr, 1, 1, wpage); - if (npages == 1) { - *writable = true; - put_page(page[0]); - page[0] = wpage[0]; - } - npages = 1; + might_sleep(); + + if (writable) + *writable = write_fault; + + if (async) { + down_read(¤t->mm->mmap_sem); + npages = get_user_page_nowait(current, current->mm, + addr, write_fault, page); + up_read(¤t->mm->mmap_sem); + } else + npages = get_user_pages_fast(addr, 1, write_fault, + page); + if (npages != 1) + return npages; + + /* map read fault as writable if possible */ + if (unlikely(!write_fault) && writable) { + struct page *wpage[1]; + + npages = __get_user_pages_fast(addr, 1, 1, wpage); + if (npages == 1) { + *writable = true; + put_page(page[0]); + page[0] = wpage[0]; } + + npages = 1; } + *pfn = page_to_pfn(page[0]); + return npages; +} - if (unlikely(npages != 1)) { - struct vm_area_struct *vma; +static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) +{ + if (unlikely(!(vma->vm_flags & VM_READ))) + return false; - if (atomic) - return get_fault_pfn(); + if (write_fault && (unlikely(!(vma->vm_flags & VM_WRITE)))) + return false; - down_read(¤t->mm->mmap_sem); - if (npages == -EHWPOISON || - (!async && check_user_page_hwpoison(addr))) { - up_read(¤t->mm->mmap_sem); - get_page(hwpoison_page); - return page_to_pfn(hwpoison_page); - } + return true; +} - vma = find_vma_intersection(current->mm, addr, addr+1); - - if (vma == NULL) - pfn = get_fault_pfn(); - else if ((vma->vm_flags & VM_PFNMAP)) { - pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + - vma->vm_pgoff; - BUG_ON(!kvm_is_mmio_pfn(pfn)); - } else { - if (async && (vma->vm_flags & VM_WRITE)) - *async = true; - pfn = get_fault_pfn(); - } - up_read(¤t->mm->mmap_sem); - } else - pfn = page_to_pfn(page[0]); +/* + * Pin guest page in memory and return its pfn. + * @addr: host virtual address which maps memory to the guest + * @atomic: whether this function can sleep + * @async: whether this function need to wait IO complete if the + * host page is not in the memory + * @write_fault: whether we should get a writable host page + * @writable: whether it allows to map a writable host page for !@write_fault + * + * The function will map a writable host page for these two cases: + * 1): @write_fault = true + * 2): @write_fault = false && @writable, @writable will tell the caller + * whether the mapping is writable. + */ +static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, + bool write_fault, bool *writable) +{ + struct vm_area_struct *vma; + pfn_t pfn = 0; + int npages; + + /* we can do it either atomically or asynchronously, not both */ + BUG_ON(atomic && async); + if (hva_to_pfn_fast(addr, atomic, async, write_fault, writable, &pfn)) + return pfn; + + if (atomic) + return KVM_PFN_ERR_FAULT; + + npages = hva_to_pfn_slow(addr, async, write_fault, writable, &pfn); + if (npages == 1) + return pfn; + + down_read(¤t->mm->mmap_sem); + if (npages == -EHWPOISON || + (!async && check_user_page_hwpoison(addr))) { + pfn = KVM_PFN_ERR_HWPOISON; + goto exit; + } + + vma = find_vma_intersection(current->mm, addr, addr + 1); + + if (vma == NULL) + pfn = KVM_PFN_ERR_FAULT; + else if ((vma->vm_flags & VM_PFNMAP)) { + pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + + vma->vm_pgoff; + BUG_ON(!kvm_is_mmio_pfn(pfn)); + } else { + if (async && vma_is_valid(vma, write_fault)) + *async = true; + pfn = KVM_PFN_ERR_FAULT; + } +exit: + up_read(¤t->mm->mmap_sem); return pfn; } -pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr) +static pfn_t +__gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn, bool atomic, + bool *async, bool write_fault, bool *writable) { - return hva_to_pfn(kvm, addr, true, NULL, true, NULL); + unsigned long addr = __gfn_to_hva_many(slot, gfn, NULL, write_fault); + + if (addr == KVM_HVA_ERR_RO_BAD) + return KVM_PFN_ERR_RO_FAULT; + + if (kvm_is_error_hva(addr)) + return KVM_PFN_ERR_BAD; + + /* Do not map writable pfn in the readonly memslot. */ + if (writable && memslot_is_readonly(slot)) { + *writable = false; + writable = NULL; + } + + return hva_to_pfn(addr, atomic, async, write_fault, + writable); } -EXPORT_SYMBOL_GPL(hva_to_pfn_atomic); static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic, bool *async, bool write_fault, bool *writable) { - unsigned long addr; + struct kvm_memory_slot *slot; if (async) *async = false; - addr = gfn_to_hva(kvm, gfn); - if (kvm_is_error_hva(addr)) { - get_page(bad_page); - return page_to_pfn(bad_page); - } + slot = gfn_to_memslot(kvm, gfn); - return hva_to_pfn(kvm, addr, atomic, async, write_fault, writable); + return __gfn_to_pfn_memslot(slot, gfn, atomic, async, write_fault, + writable); } pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn) @@ -1195,12 +1260,16 @@ pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, } EXPORT_SYMBOL_GPL(gfn_to_pfn_prot); -pfn_t gfn_to_pfn_memslot(struct kvm *kvm, - struct kvm_memory_slot *slot, gfn_t gfn) +pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn) +{ + return __gfn_to_pfn_memslot(slot, gfn, false, NULL, true, NULL); +} + +pfn_t gfn_to_pfn_memslot_atomic(struct kvm_memory_slot *slot, gfn_t gfn) { - unsigned long addr = gfn_to_hva_memslot(slot, gfn); - return hva_to_pfn(kvm, addr, false, NULL, true, NULL); + return __gfn_to_pfn_memslot(slot, gfn, true, NULL, true, NULL); } +EXPORT_SYMBOL_GPL(gfn_to_pfn_memslot_atomic); int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, int nr_pages) @@ -1219,30 +1288,42 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, } EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); +static struct page *kvm_pfn_to_page(pfn_t pfn) +{ + if (is_error_pfn(pfn)) + return KVM_ERR_PTR_BAD_PAGE; + + if (kvm_is_mmio_pfn(pfn)) { + WARN_ON(1); + return KVM_ERR_PTR_BAD_PAGE; + } + + return pfn_to_page(pfn); +} + struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { pfn_t pfn; pfn = gfn_to_pfn(kvm, gfn); - if (!kvm_is_mmio_pfn(pfn)) - return pfn_to_page(pfn); - - WARN_ON(kvm_is_mmio_pfn(pfn)); - get_page(bad_page); - return bad_page; + return kvm_pfn_to_page(pfn); } EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_page_clean(struct page *page) { + WARN_ON(is_error_page(page)); + kvm_release_pfn_clean(page_to_pfn(page)); } EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(pfn_t pfn) { + WARN_ON(is_error_pfn(pfn)); + if (!kvm_is_mmio_pfn(pfn)) put_page(pfn_to_page(pfn)); } @@ -1250,6 +1331,8 @@ EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); void kvm_release_page_dirty(struct page *page) { + WARN_ON(is_error_page(page)); + kvm_release_pfn_dirty(page_to_pfn(page)); } EXPORT_SYMBOL_GPL(kvm_release_page_dirty); @@ -1305,10 +1388,10 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, int r; unsigned long addr; - addr = gfn_to_hva(kvm, gfn); + addr = gfn_to_hva_read(kvm, gfn); if (kvm_is_error_hva(addr)) return -EFAULT; - r = __copy_from_user(data, (void __user *)addr + offset, len); + r = kvm_read_hva(data, (void __user *)addr + offset, len); if (r) return -EFAULT; return 0; @@ -1343,11 +1426,11 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, gfn_t gfn = gpa >> PAGE_SHIFT; int offset = offset_in_page(gpa); - addr = gfn_to_hva(kvm, gfn); + addr = gfn_to_hva_read(kvm, gfn); if (kvm_is_error_hva(addr)) return -EFAULT; pagefault_disable(); - r = __copy_from_user_inatomic(data, (void __user *)addr + offset, len); + r = kvm_read_hva_atomic(data, (void __user *)addr + offset, len); pagefault_enable(); if (r) return -EFAULT; @@ -1485,8 +1568,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm, struct kvm_memory_slot *memslot, if (memslot && memslot->dirty_bitmap) { unsigned long rel_gfn = gfn - memslot->base_gfn; - /* TODO: introduce set_bit_le() and use it */ - test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap); + set_bit_le(rel_gfn, memslot->dirty_bitmap); } } @@ -1580,6 +1662,43 @@ bool kvm_vcpu_yield_to(struct kvm_vcpu *target) } EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to); +#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT +/* + * Helper that checks whether a VCPU is eligible for directed yield. + * Most eligible candidate to yield is decided by following heuristics: + * + * (a) VCPU which has not done pl-exit or cpu relax intercepted recently + * (preempted lock holder), indicated by @in_spin_loop. + * Set at the beiginning and cleared at the end of interception/PLE handler. + * + * (b) VCPU which has done pl-exit/ cpu relax intercepted but did not get + * chance last time (mostly it has become eligible now since we have probably + * yielded to lockholder in last iteration. This is done by toggling + * @dy_eligible each time a VCPU checked for eligibility.) + * + * Yielding to a recently pl-exited/cpu relax intercepted VCPU before yielding + * to preempted lock-holder could result in wrong VCPU selection and CPU + * burning. Giving priority for a potential lock-holder increases lock + * progress. + * + * Since algorithm is based on heuristics, accessing another VCPU data without + * locking does not harm. It may result in trying to yield to same VCPU, fail + * and continue with next VCPU and so on. + */ +bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu) +{ + bool eligible; + + eligible = !vcpu->spin_loop.in_spin_loop || + (vcpu->spin_loop.in_spin_loop && + vcpu->spin_loop.dy_eligible); + + if (vcpu->spin_loop.in_spin_loop) + kvm_vcpu_set_dy_eligible(vcpu, !vcpu->spin_loop.dy_eligible); + + return eligible; +} +#endif void kvm_vcpu_on_spin(struct kvm_vcpu *me) { struct kvm *kvm = me->kvm; @@ -1589,6 +1708,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) int pass; int i; + kvm_vcpu_set_in_spin_loop(me, true); /* * We boost the priority of a VCPU that is runnable but not * currently running, because it got preempted by something @@ -1607,6 +1727,8 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) continue; if (waitqueue_active(&vcpu->wq)) continue; + if (!kvm_vcpu_eligible_for_directed_yield(vcpu)) + continue; if (kvm_vcpu_yield_to(vcpu)) { kvm->last_boosted_vcpu = i; yielded = 1; @@ -1614,6 +1736,10 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me) } } } + kvm_vcpu_set_in_spin_loop(me, false); + + /* Ensure vcpu is not eligible during next spinloop */ + kvm_vcpu_set_dy_eligible(me, false); } EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin); @@ -1766,7 +1892,9 @@ static long kvm_vcpu_ioctl(struct file *filp, #endif - vcpu_load(vcpu); + r = vcpu_load(vcpu); + if (r) + return r; switch (ioctl) { case KVM_RUN: r = -EINVAL; @@ -2094,6 +2222,29 @@ static long kvm_vm_ioctl(struct file *filp, break; } #endif +#ifdef __KVM_HAVE_IRQ_LINE + case KVM_IRQ_LINE_STATUS: + case KVM_IRQ_LINE: { + struct kvm_irq_level irq_event; + + r = -EFAULT; + if (copy_from_user(&irq_event, argp, sizeof irq_event)) + goto out; + + r = kvm_vm_ioctl_irq_line(kvm, &irq_event); + if (r) + goto out; + + r = -EFAULT; + if (ioctl == KVM_IRQ_LINE_STATUS) { + if (copy_to_user(argp, &irq_event, sizeof irq_event)) + goto out; + } + + r = 0; + break; + } +#endif default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); if (r == -ENOTTY) @@ -2698,9 +2849,6 @@ static struct syscore_ops kvm_syscore_ops = { .resume = kvm_resume, }; -struct page *bad_page; -pfn_t bad_pfn; - static inline struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) { @@ -2732,33 +2880,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, if (r) goto out_fail; - bad_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - - if (bad_page == NULL) { - r = -ENOMEM; - goto out; - } - - bad_pfn = page_to_pfn(bad_page); - - hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - - if (hwpoison_page == NULL) { - r = -ENOMEM; - goto out_free_0; - } - - hwpoison_pfn = page_to_pfn(hwpoison_page); - - fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - - if (fault_page == NULL) { - r = -ENOMEM; - goto out_free_0; - } - - fault_pfn = page_to_pfn(fault_page); - if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) { r = -ENOMEM; goto out_free_0; @@ -2833,12 +2954,6 @@ out_free_1: out_free_0a: free_cpumask_var(cpus_hardware_enabled); out_free_0: - if (fault_page) - __free_page(fault_page); - if (hwpoison_page) - __free_page(hwpoison_page); - __free_page(bad_page); -out: kvm_arch_exit(); out_fail: return r; @@ -2858,8 +2973,5 @@ void kvm_exit(void) kvm_arch_hardware_unsetup(); kvm_arch_exit(); free_cpumask_var(cpus_hardware_enabled); - __free_page(fault_page); - __free_page(hwpoison_page); - __free_page(bad_page); } EXPORT_SYMBOL_GPL(kvm_exit); |