ASoC: Fixes for v4.1

A few more fixes for v4.1, some driver fixes plus one core fix which
 fixes registration of DAI links when adding prefixes to CODECs to
 deuplicate in multi-CODEC systems.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJVVzfnAAoJECTWi3JdVIfQL5UH/RAByQl4QZC6/LeeUVVi13Ht
 PcdWa1rFZBeNkfhMnEGCwAOa1mwaiMU+di8SX3Fd3AOFvdqeVA6gInj1+2uGf/fH
 YdlTXRNs/LRFVVMVERvkNqumIvcY4sWiTWjjMXcQg8BLuO3nQCCm/Mic8ElBflEQ
 rvWdiTE/12IAhEqy6tQx7THSTrQ+bf5/Tbm6oe38C/3wwwjn7eCOXv/BX0MQR5Bu
 l3B3QoyHmbyrjZ7VLCc8UJhUG0Y3W/Najg7U7pcZN0LX4+60haAiI2aRDyeAgGky
 ivpzqzWxUctSHBpms7W8NsZjnzaePwAO9VYYslKFxY7eFjBERmjJg1QD1pIPG5o=
 =gl1c
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v4.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v4.1

A few more fixes for v4.1, some driver fixes plus one core fix which
fixes registration of DAI links when adding prefixes to CODECs to
deuplicate in multi-CODEC systems.
This commit is contained in:
Takashi Iwai 2015-05-18 08:23:37 +02:00
commit 5a6cc82171
431 changed files with 5149 additions and 2719 deletions

View File

@ -3709,6 +3709,13 @@ N: Dirk Verworner
D: Co-author of German book ``Linux-Kernel-Programmierung'' D: Co-author of German book ``Linux-Kernel-Programmierung''
D: Co-founder of Berlin Linux User Group D: Co-founder of Berlin Linux User Group
N: Andrew Victor
E: linux@maxim.org.za
W: http://maxim.org.za/at91_26.html
D: First maintainer of Atmel ARM-based SoC, aka AT91
D: Introduced support for at91rm9200, the first chip of AT91 family
S: South Africa
N: Riku Voipio N: Riku Voipio
E: riku.voipio@iki.fi E: riku.voipio@iki.fi
D: Author of PCA9532 LED and Fintek f75375s hwmon driver D: Author of PCA9532 LED and Fintek f75375s hwmon driver

View File

@ -505,7 +505,10 @@ at module load time (for a module) with:
The addresses are normal I2C addresses. The adapter is the string The addresses are normal I2C addresses. The adapter is the string
name of the adapter, as shown in /sys/class/i2c-adapter/i2c-<n>/name. name of the adapter, as shown in /sys/class/i2c-adapter/i2c-<n>/name.
It is *NOT* i2c-<n> itself. It is *NOT* i2c-<n> itself. Also, the comparison is done ignoring
spaces, so if the name is "This is an I2C chip" you can say
adapter_name=ThisisanI2cchip. This is because it's hard to pass in
spaces in kernel parameters.
The debug flags are bit flags for each BMC found, they are: The debug flags are bit flags for each BMC found, they are:
IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8 IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8

View File

@ -253,7 +253,7 @@ input driver:
GPIO support GPIO support
~~~~~~~~~~~~ ~~~~~~~~~~~~
ACPI 5 introduced two new resources to describe GPIO connections: GpioIo ACPI 5 introduced two new resources to describe GPIO connections: GpioIo
and GpioInt. These resources are used be used to pass GPIO numbers used by and GpioInt. These resources can be used to pass GPIO numbers used by
the device to the driver. ACPI 5.1 extended this with _DSD (Device the device to the driver. ACPI 5.1 extended this with _DSD (Device
Specific Data) which made it possible to name the GPIOs among other things. Specific Data) which made it possible to name the GPIOs among other things.

View File

@ -1,9 +1,9 @@
_DSD Device Properties Related to GPIO _DSD Device Properties Related to GPIO
-------------------------------------- --------------------------------------
With the release of ACPI 5.1 and the _DSD configuration objecte names With the release of ACPI 5.1, the _DSD configuration object finally
can finally be given to GPIOs (and other things as well) returned by allows names to be given to GPIOs (and other things as well) returned
_CRS. Previously, we were only able to use an integer index to find by _CRS. Previously, we were only able to use an integer index to find
the corresponding GPIO, which is pretty error prone (it depends on the corresponding GPIO, which is pretty error prone (it depends on
the _CRS output ordering, for example). the _CRS output ordering, for example).

View File

@ -6,6 +6,7 @@ provided by Arteris.
Required properties: Required properties:
- compatible : Should be "ti,omap3-l3-smx" for OMAP3 family - compatible : Should be "ti,omap3-l3-smx" for OMAP3 family
Should be "ti,omap4-l3-noc" for OMAP4 family Should be "ti,omap4-l3-noc" for OMAP4 family
Should be "ti,omap5-l3-noc" for OMAP5 family
Should be "ti,dra7-l3-noc" for DRA7 family Should be "ti,dra7-l3-noc" for DRA7 family
Should be "ti,am4372-l3-noc" for AM43 family Should be "ti,am4372-l3-noc" for AM43 family
- reg: Contains L3 register address range for each noc domain. - reg: Contains L3 register address range for each noc domain.

View File

@ -38,7 +38,7 @@ dma_apbx: dma-apbx@80024000 {
80 81 68 69 80 81 68 69
70 71 72 73 70 71 72 73
74 75 76 77>; 74 75 76 77>;
interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
"saif0", "saif1", "i2c0", "i2c1", "saif0", "saif1", "i2c0", "i2c1",
"auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
"auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";

View File

@ -0,0 +1,30 @@
Abracon ABX80X I2C ultra low power RTC/Alarm chip
The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801,
ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805
is the superset of ab180x.
Required properties:
- "compatible": should one of:
"abracon,abx80x"
"abracon,ab0801"
"abracon,ab0803"
"abracon,ab0804"
"abracon,ab0805"
"abracon,ab1801"
"abracon,ab1803"
"abracon,ab1804"
"abracon,ab1805"
Using "abracon,abx80x" will enable chip autodetection.
- "reg": I2C bus address of the device
Optional properties:
The abx804 and abx805 have a trickle charger that is able to charge the
connected battery or supercap. Both the following properties have to be defined
and valid to enable charging:
- "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
- "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
resistor, the other values are in ohm.

View File

@ -9,7 +9,9 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds
bugs. bugs.
KASan uses compile-time instrumentation for checking every memory access, KASan uses compile-time instrumentation for checking every memory access,
therefore you will need a certain version of GCC > 4.9.2 therefore you will need a gcc version of 4.9.2 or later. KASan could detect out
of bounds accesses to stack or global variables, but only if gcc 5.0 or later was
used to built the kernel.
Currently KASan is supported only for x86_64 architecture and requires that the Currently KASan is supported only for x86_64 architecture and requires that the
kernel be built with the SLUB allocator. kernel be built with the SLUB allocator.
@ -23,8 +25,8 @@ To enable KASAN configure kernel with:
and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
is compiler instrumentation types. The former produces smaller binary the is compiler instrumentation types. The former produces smaller binary the
latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version
latter. of 5.0 or later.
Currently KASAN works only with the SLUB memory allocator. Currently KASAN works only with the SLUB memory allocator.
For better bug detection and nicer report, enable CONFIG_STACKTRACE and put For better bug detection and nicer report, enable CONFIG_STACKTRACE and put

View File

@ -3787,6 +3787,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
READ_CAPACITY_16 command); READ_CAPACITY_16 command);
f = NO_REPORT_OPCODES (don't use report opcodes f = NO_REPORT_OPCODES (don't use report opcodes
command, uas only); command, uas only);
g = MAX_SECTORS_240 (don't transfer more than
240 sectors at a time, uas only);
h = CAPACITY_HEURISTICS (decrease the h = CAPACITY_HEURISTICS (decrease the
reported device capacity by one reported device capacity by one
sector if the number is odd); sector if the number is odd);

View File

@ -119,9 +119,9 @@ Most notably, in the x509.genkey file, the req_distinguished_name section
should be altered from the default: should be altered from the default:
[ req_distinguished_name ] [ req_distinguished_name ]
O = Magrathea #O = Unspecified company
CN = Glacier signing key CN = Build time autogenerated kernel key
emailAddress = slartibartfast@magrathea.h2g2 #emailAddress = unspecified.user@unspecified.company
The generated RSA key size can also be set with: The generated RSA key size can also be set with:

View File

@ -18,3 +18,12 @@ platform_labels - INTEGER
Possible values: 0 - 1048575 Possible values: 0 - 1048575
Default: 0 Default: 0
conf/<interface>/input - BOOL
Control whether packets can be input on this interface.
If disabled, packets will be discarded without further
processing.
0 - disabled (default)
not 0 - enabled

View File

@ -282,7 +282,7 @@ following is true:
- The current CPU's queue head counter >= the recorded tail counter - The current CPU's queue head counter >= the recorded tail counter
value in rps_dev_flow[i] value in rps_dev_flow[i]
- The current CPU is unset (equal to RPS_NO_CPU) - The current CPU is unset (>= nr_cpu_ids)
- The current CPU is offline - The current CPU is offline
After this check, the packet is sent to the (possibly updated) current After this check, the packet is sent to the (possibly updated) current

View File

@ -74,23 +74,22 @@ Causes of transaction aborts
Syscalls Syscalls
======== ========
Syscalls made from within an active transaction will not be performed and the Performing syscalls from within transaction is not recommended, and can lead
transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL to unpredictable results.
| TM_CAUSE_PERSISTENT.
Syscalls made from within a suspended transaction are performed as normal and Syscalls do not by design abort transactions, but beware: The kernel code will
the transaction is not explicitly doomed by the kernel. However, what the not be running in transactional state. The effect of syscalls will always
kernel does to perform the syscall may result in the transaction being doomed remain visible, but depending on the call they may abort your transaction as a
by the hardware. The syscall is performed in suspended mode so any side side-effect, read soon-to-be-aborted transactional data that should not remain
effects will be persistent, independent of transaction success or failure. No invisible, etc. If you constantly retry a transaction that constantly aborts
guarantees are provided by the kernel about which syscalls will affect itself by calling a syscall, you'll have a livelock & make no progress.
transaction success.
Care must be taken when relying on syscalls to abort during active transactions Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write()
if the calls are made via a library. Libraries may cache values (which may from, say, printf() should be OK as long as the kernel does not access any
give the appearance of success) or perform operations that cause transaction memory that was accessed transactionally.
failure before entering the kernel (which may produce different failure codes).
Examples are glibc's getpid() and lazy symbol resolution. Consider any syscalls that happen to work as debug-only -- not recommended for
production use. Best to queue them up till after the transaction is over.
Signals Signals
@ -177,7 +176,8 @@ kernel aborted a transaction:
TM_CAUSE_RESCHED Thread was rescheduled. TM_CAUSE_RESCHED Thread was rescheduled.
TM_CAUSE_TLBI Software TLB invalid. TM_CAUSE_TLBI Software TLB invalid.
TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap. TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap.
TM_CAUSE_SYSCALL Syscall from active transaction. TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort
transactions for consistency will use this.
TM_CAUSE_SIGNAL Signal delivered. TM_CAUSE_SIGNAL Signal delivered.
TM_CAUSE_MISC Currently unused. TM_CAUSE_MISC Currently unused.
TM_CAUSE_ALIGNMENT Alignment fault. TM_CAUSE_ALIGNMENT Alignment fault.

View File

@ -892,11 +892,10 @@ S: Maintained
F: arch/arm/mach-alpine/ F: arch/arm/mach-alpine/
ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
M: Andrew Victor <linux@maxim.org.za>
M: Nicolas Ferre <nicolas.ferre@atmel.com> M: Nicolas Ferre <nicolas.ferre@atmel.com>
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com> M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://maxim.org.za/at91_26.html
W: http://www.linux4sam.org W: http://www.linux4sam.org
S: Supported S: Supported
F: arch/arm/mach-at91/ F: arch/arm/mach-at91/
@ -990,6 +989,12 @@ F: drivers/clocksource/timer-prima2.c
F: drivers/clocksource/timer-atlas7.c F: drivers/clocksource/timer-atlas7.c
N: [^a-z]sirf N: [^a-z]sirf
ARM/CONEXANT DIGICOLOR MACHINE SUPPORT
M: Baruch Siach <baruch@tkos.co.il>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
N: digicolor
ARM/EBSA110 MACHINE SUPPORT ARM/EBSA110 MACHINE SUPPORT
M: Russell King <linux@arm.linux.org.uk> M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@ -1439,9 +1444,10 @@ ARM/SOCFPGA ARCHITECTURE
M: Dinh Nguyen <dinguyen@opensource.altera.com> M: Dinh Nguyen <dinguyen@opensource.altera.com>
S: Maintained S: Maintained
F: arch/arm/mach-socfpga/ F: arch/arm/mach-socfpga/
F: arch/arm/boot/dts/socfpga*
F: arch/arm/configs/socfpga_defconfig
W: http://www.rocketboards.org W: http://www.rocketboards.org
T: git://git.rocketboards.org/linux-socfpga.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
T: git://git.rocketboards.org/linux-socfpga-next.git
ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT
M: Dinh Nguyen <dinguyen@opensource.altera.com> M: Dinh Nguyen <dinguyen@opensource.altera.com>
@ -2116,8 +2122,9 @@ S: Supported
F: drivers/net/ethernet/broadcom/bnx2x/ F: drivers/net/ethernet/broadcom/bnx2x/
BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
M: Christian Daudt <bcm@fixthebug.org>
M: Florian Fainelli <f.fainelli@gmail.com> M: Florian Fainelli <f.fainelli@gmail.com>
M: Ray Jui <rjui@broadcom.com>
M: Scott Branden <sbranden@broadcom.com>
L: bcm-kernel-feedback-list@broadcom.com L: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/mach-bcm T: git git://github.com/broadcom/mach-bcm
S: Maintained S: Maintained
@ -2168,7 +2175,6 @@ S: Maintained
F: drivers/usb/gadget/udc/bcm63xx_udc.* F: drivers/usb/gadget/udc/bcm63xx_udc.*
BROADCOM BCM7XXX ARM ARCHITECTURE BROADCOM BCM7XXX ARM ARCHITECTURE
M: Marc Carino <marc.ceeeee@gmail.com>
M: Brian Norris <computersforpeace@gmail.com> M: Brian Norris <computersforpeace@gmail.com>
M: Gregory Fong <gregory.0xf0@gmail.com> M: Gregory Fong <gregory.0xf0@gmail.com>
M: Florian Fainelli <f.fainelli@gmail.com> M: Florian Fainelli <f.fainelli@gmail.com>
@ -3413,6 +3419,13 @@ F: drivers/gpu/drm/rcar-du/
F: drivers/gpu/drm/shmobile/ F: drivers/gpu/drm/shmobile/
F: include/linux/platform_data/shmob_drm.h F: include/linux/platform_data/shmob_drm.h
DRM DRIVERS FOR ROCKCHIP
M: Mark Yao <mark.yao@rock-chips.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
F: drivers/gpu/drm/rockchip/
F: Documentation/devicetree/bindings/video/rockchip*
DSBR100 USB FM RADIO DRIVER DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com> M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
@ -5035,17 +5048,19 @@ S: Orphan
F: drivers/video/fbdev/imsttfb.c F: drivers/video/fbdev/imsttfb.c
INFINIBAND SUBSYSTEM INFINIBAND SUBSYSTEM
M: Roland Dreier <roland@kernel.org> M: Doug Ledford <dledford@redhat.com>
M: Sean Hefty <sean.hefty@intel.com> M: Sean Hefty <sean.hefty@intel.com>
M: Hal Rosenstock <hal.rosenstock@gmail.com> M: Hal Rosenstock <hal.rosenstock@gmail.com>
L: linux-rdma@vger.kernel.org L: linux-rdma@vger.kernel.org
W: http://www.openfabrics.org/ W: http://www.openfabrics.org/
Q: http://patchwork.kernel.org/project/linux-rdma/list/ Q: http://patchwork.kernel.org/project/linux-rdma/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git T: git git://github.com/dledford/linux.git
S: Supported S: Supported
F: Documentation/infiniband/ F: Documentation/infiniband/
F: drivers/infiniband/ F: drivers/infiniband/
F: include/uapi/linux/if_infiniband.h F: include/uapi/linux/if_infiniband.h
F: include/uapi/rdma/
F: include/rdma/
INOTIFY INOTIFY
M: John McCutchan <john@johnmccutchan.com> M: John McCutchan <john@johnmccutchan.com>
@ -5798,6 +5813,7 @@ F: drivers/scsi/53c700*
LED SUBSYSTEM LED SUBSYSTEM
M: Bryan Wu <cooloney@gmail.com> M: Bryan Wu <cooloney@gmail.com>
M: Richard Purdie <rpurdie@rpsys.net> M: Richard Purdie <rpurdie@rpsys.net>
M: Jacek Anaszewski <j.anaszewski@samsung.com>
L: linux-leds@vger.kernel.org L: linux-leds@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git
S: Maintained S: Maintained
@ -10523,7 +10539,6 @@ F: include/linux/virtio_console.h
F: include/uapi/linux/virtio_console.h F: include/uapi/linux/virtio_console.h
VIRTIO CORE, NET AND BLOCK DRIVERS VIRTIO CORE, NET AND BLOCK DRIVERS
M: Rusty Russell <rusty@rustcorp.com.au>
M: "Michael S. Tsirkin" <mst@redhat.com> M: "Michael S. Tsirkin" <mst@redhat.com>
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
S: Maintained S: Maintained
@ -11031,6 +11046,7 @@ F: drivers/media/pci/zoran/
ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
M: Minchan Kim <minchan@kernel.org> M: Minchan Kim <minchan@kernel.org>
M: Nitin Gupta <ngupta@vflare.org> M: Nitin Gupta <ngupta@vflare.org>
R: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
F: drivers/block/zram/ F: drivers/block/zram/

View File

@ -1,7 +1,7 @@
VERSION = 4 VERSION = 4
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc1 EXTRAVERSION = -rc3
NAME = Hurr durr I'ma sheep NAME = Hurr durr I'ma sheep
# *DOCUMENTATION* # *DOCUMENTATION*

View File

@ -49,7 +49,7 @@
pinctrl-0 = <&matrix_keypad_pins>; pinctrl-0 = <&matrix_keypad_pins>;
debounce-delay-ms = <5>; debounce-delay-ms = <5>;
col-scan-delay-us = <1500>; col-scan-delay-us = <5>;
row-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH /* Bank5, pin5 */ row-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH /* Bank5, pin5 */
&gpio5 6 GPIO_ACTIVE_HIGH>; /* Bank5, pin6 */ &gpio5 6 GPIO_ACTIVE_HIGH>; /* Bank5, pin6 */
@ -473,7 +473,7 @@
interrupt-parent = <&gpio0>; interrupt-parent = <&gpio0>;
interrupts = <31 0>; interrupts = <31 0>;
wake-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <480>; touchscreen-size-x = <480>;
touchscreen-size-y = <272>; touchscreen-size-y = <272>;

View File

@ -18,6 +18,7 @@
aliases { aliases {
rtc0 = &mcp_rtc; rtc0 = &mcp_rtc;
rtc1 = &tps659038_rtc; rtc1 = &tps659038_rtc;
rtc2 = &rtc;
}; };
memory { memory {
@ -83,7 +84,7 @@
gpio_fan: gpio_fan { gpio_fan: gpio_fan {
/* Based on 5v 500mA AFB02505HHB */ /* Based on 5v 500mA AFB02505HHB */
compatible = "gpio-fan"; compatible = "gpio-fan";
gpios = <&tps659038_gpio 1 GPIO_ACTIVE_HIGH>; gpios = <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>;
gpio-fan,speed-map = <0 0>, gpio-fan,speed-map = <0 0>,
<13000 1>; <13000 1>;
#cooling-cells = <2>; #cooling-cells = <2>;
@ -130,8 +131,8 @@
uart3_pins_default: uart3_pins_default { uart3_pins_default: uart3_pins_default {
pinctrl-single,pins = < pinctrl-single,pins = <
0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd.rxd */ 0x3f8 (PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd.txd */ 0x3fc (PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
>; >;
}; };
@ -455,7 +456,7 @@
mcp_rtc: rtc@6f { mcp_rtc: rtc@6f {
compatible = "microchip,mcp7941x"; compatible = "microchip,mcp7941x";
reg = <0x6f>; reg = <0x6f>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */ interrupts = <GIC_SPI 2 IRQ_TYPE_EDGE_RISING>; /* IRQ_SYS_1N */
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&mcp79410_pins_default>; pinctrl-0 = <&mcp79410_pins_default>;
@ -478,7 +479,7 @@
&uart3 { &uart3 {
status = "okay"; status = "okay";
interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
<&dra7_pmx_core 0x248>; <&dra7_pmx_core 0x3f8>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&uart3_pins_default>; pinctrl-0 = <&uart3_pins_default>;

View File

@ -105,6 +105,10 @@
}; };
internal-regs { internal-regs {
rtc@10300 {
/* No crystal connected to the internal RTC */
status = "disabled";
};
serial@12000 { serial@12000 {
status = "okay"; status = "okay";
}; };

View File

@ -911,7 +911,7 @@
ti,clock-cycles = <16>; ti,clock-cycles = <16>;
reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>, reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>,
<0x4ae06014 0x4>, <0x4a003b20 0x8>, <0x4ae06014 0x4>, <0x4a003b20 0xc>,
<0x4ae0c158 0x4>; <0x4ae0c158 0x4>;
reg-names = "setup-address", "control-address", reg-names = "setup-address", "control-address",
"int-address", "efuse-address", "int-address", "efuse-address",
@ -944,7 +944,7 @@
ti,clock-cycles = <16>; ti,clock-cycles = <16>;
reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>, reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>,
<0x4ae06010 0x4>, <0x4a0025cc 0x8>, <0x4ae06010 0x4>, <0x4a0025cc 0xc>,
<0x4a002470 0x4>; <0x4a002470 0x4>;
reg-names = "setup-address", "control-address", reg-names = "setup-address", "control-address",
"int-address", "efuse-address", "int-address", "efuse-address",
@ -977,7 +977,7 @@
ti,clock-cycles = <16>; ti,clock-cycles = <16>;
reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>, reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>,
<0x4ae06010 0x4>, <0x4a0025e0 0x8>, <0x4ae06010 0x4>, <0x4a0025e0 0xc>,
<0x4a00246c 0x4>; <0x4a00246c 0x4>;
reg-names = "setup-address", "control-address", reg-names = "setup-address", "control-address",
"int-address", "efuse-address", "int-address", "efuse-address",
@ -1010,7 +1010,7 @@
ti,clock-cycles = <16>; ti,clock-cycles = <16>;
reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>, reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>,
<0x4ae06010 0x4>, <0x4a003b08 0x8>, <0x4ae06010 0x4>, <0x4a003b08 0xc>,
<0x4ae0c154 0x4>; <0x4ae0c154 0x4>;
reg-names = "setup-address", "control-address", reg-names = "setup-address", "control-address",
"int-address", "efuse-address", "int-address", "efuse-address",
@ -1203,7 +1203,7 @@
status = "disabled"; status = "disabled";
}; };
rtc@48838000 { rtc: rtc@48838000 {
compatible = "ti,am3352-rtc"; compatible = "ti,am3352-rtc";
reg = <0x48838000 0x100>; reg = <0x48838000 0x100>;
interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>, interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,

View File

@ -9,6 +9,7 @@
#include <dt-bindings/sound/samsung-i2s.h> #include <dt-bindings/sound/samsung-i2s.h>
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include <dt-bindings/clock/maxim,max77686.h>
#include "exynos4412.dtsi" #include "exynos4412.dtsi"
/ { / {
@ -105,6 +106,8 @@
rtc@10070000 { rtc@10070000 {
status = "okay"; status = "okay";
clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
clock-names = "rtc", "rtc_src";
}; };
g2d@10800000 { g2d@10800000 {

View File

@ -567,6 +567,7 @@
num-slots = <1>; num-slots = <1>;
broken-cd; broken-cd;
cap-sdio-irq; cap-sdio-irq;
keep-power-in-suspend;
card-detect-delay = <200>; card-detect-delay = <200>;
samsung,dw-mshc-ciu-div = <3>; samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <2 3>; samsung,dw-mshc-sdr-timing = <2 3>;

View File

@ -28,7 +28,7 @@ trips {
type = "active"; type = "active";
}; };
cpu-crit-0 { cpu-crit-0 {
temperature = <1200000>; /* millicelsius */ temperature = <120000>; /* millicelsius */
hysteresis = <0>; /* millicelsius */ hysteresis = <0>; /* millicelsius */
type = "critical"; type = "critical";
}; };

View File

@ -536,6 +536,7 @@
clock-names = "dp"; clock-names = "dp";
phys = <&dp_phy>; phys = <&dp_phy>;
phy-names = "dp"; phy-names = "dp";
power-domains = <&disp_pd>;
}; };
mipi_phy: video-phy@10040714 { mipi_phy: video-phy@10040714 {

View File

@ -18,7 +18,7 @@ trips {
type = "active"; type = "active";
}; };
cpu-crit-0 { cpu-crit-0 {
temperature = <1050000>; /* millicelsius */ temperature = <105000>; /* millicelsius */
hysteresis = <0>; /* millicelsius */ hysteresis = <0>; /* millicelsius */
type = "critical"; type = "critical";
}; };

View File

@ -12,6 +12,7 @@
*/ */
/dts-v1/; /dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include "imx23.dtsi" #include "imx23.dtsi"
/ { / {
@ -93,6 +94,7 @@
ahb@80080000 { ahb@80080000 {
usb0: usb@80080000 { usb0: usb@80080000 {
dr_mode = "host";
vbus-supply = <&reg_usb0_vbus>; vbus-supply = <&reg_usb0_vbus>;
status = "okay"; status = "okay";
}; };
@ -122,7 +124,7 @@
user { user {
label = "green"; label = "green";
gpios = <&gpio2 1 1>; gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
}; };
}; };
}; };

View File

@ -428,6 +428,7 @@
pwm4: pwm@53fc8000 { pwm4: pwm@53fc8000 {
compatible = "fsl,imx25-pwm", "fsl,imx27-pwm"; compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
#pwm-cells = <2>;
reg = <0x53fc8000 0x4000>; reg = <0x53fc8000 0x4000>;
clocks = <&clks 108>, <&clks 52>; clocks = <&clks 108>, <&clks 52>;
clock-names = "ipg", "per"; clock-names = "ipg", "per";

View File

@ -913,7 +913,7 @@
80 81 68 69 80 81 68 69
70 71 72 73 70 71 72 73
74 75 76 77>; 74 75 76 77>;
interrupt-names = "auart4-rx", "aurat4-tx", "spdif-tx", "empty", interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty",
"saif0", "saif1", "i2c0", "i2c1", "saif0", "saif1", "i2c0", "i2c1",
"auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
"auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";

View File

@ -31,6 +31,7 @@
regulator-min-microvolt = <5000000>; regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>; regulator-max-microvolt = <5000000>;
gpio = <&gpio4 15 0>; gpio = <&gpio4 15 0>;
enable-active-high;
}; };
reg_usb_h1_vbus: regulator@1 { reg_usb_h1_vbus: regulator@1 {
@ -40,6 +41,7 @@
regulator-min-microvolt = <5000000>; regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>; regulator-max-microvolt = <5000000>;
gpio = <&gpio1 0 0>; gpio = <&gpio1 0 0>;
enable-active-high;
}; };
}; };

View File

@ -185,7 +185,6 @@
&i2c3 { &i2c3 {
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>; pinctrl-0 = <&pinctrl_i2c3>;
pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
status = "okay"; status = "okay";
max7310_a: gpio@30 { max7310_a: gpio@30 {

View File

@ -498,6 +498,8 @@
DRVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>;
IOVDD-supply = <&vio>; IOVDD-supply = <&vio>;
DVDD-supply = <&vio>; DVDD-supply = <&vio>;
ai3x-micbias-vg = <1>;
}; };
tlv320aic3x_aux: tlv320aic3x@19 { tlv320aic3x_aux: tlv320aic3x@19 {
@ -509,6 +511,8 @@
DRVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>;
IOVDD-supply = <&vio>; IOVDD-supply = <&vio>;
DVDD-supply = <&vio>; DVDD-supply = <&vio>;
ai3x-micbias-vg = <2>;
}; };
tsl2563: tsl2563@29 { tsl2563: tsl2563@29 {

View File

@ -456,6 +456,7 @@
}; };
mmu_isp: mmu@480bd400 { mmu_isp: mmu@480bd400 {
#iommu-cells = <0>;
compatible = "ti,omap2-iommu"; compatible = "ti,omap2-iommu";
reg = <0x480bd400 0x80>; reg = <0x480bd400 0x80>;
interrupts = <24>; interrupts = <24>;
@ -464,6 +465,7 @@
}; };
mmu_iva: mmu@5d000000 { mmu_iva: mmu@5d000000 {
#iommu-cells = <0>;
compatible = "ti,omap2-iommu"; compatible = "ti,omap2-iommu";
reg = <0x5d000000 0x80>; reg = <0x5d000000 0x80>;
interrupts = <28>; interrupts = <28>;

View File

@ -128,7 +128,7 @@
* hierarchy. * hierarchy.
*/ */
ocp { ocp {
compatible = "ti,omap4-l3-noc", "simple-bus"; compatible = "ti,omap5-l3-noc", "simple-bus";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
ranges; ranges;

View File

@ -545,7 +545,7 @@
compatible = "adi,adv7511w"; compatible = "adi,adv7511w";
reg = <0x39>; reg = <0x39>;
interrupt-parent = <&gpio3>; interrupt-parent = <&gpio3>;
interrupts = <29 IRQ_TYPE_EDGE_FALLING>; interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
adi,input-depth = <8>; adi,input-depth = <8>;
adi,input-colorspace = "rgb"; adi,input-colorspace = "rgb";

View File

@ -1017,23 +1017,6 @@
status = "disabled"; status = "disabled";
}; };
vmmci: regulator-gpio {
compatible = "regulator-gpio";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2900000>;
regulator-name = "mmci-reg";
regulator-type = "voltage";
startup-delay-us = <100>;
enable-active-high;
states = <1800000 0x1
2900000 0x0>;
status = "disabled";
};
mcde@a0350000 { mcde@a0350000 {
compatible = "stericsson,mcde"; compatible = "stericsson,mcde";
reg = <0xa0350000 0x1000>, /* MCDE */ reg = <0xa0350000 0x1000>, /* MCDE */

View File

@ -111,6 +111,21 @@
pinctrl-1 = <&i2c3_sleep_mode>; pinctrl-1 = <&i2c3_sleep_mode>;
}; };
vmmci: regulator-gpio {
compatible = "regulator-gpio";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2900000>;
regulator-name = "mmci-reg";
regulator-type = "voltage";
startup-delay-us = <100>;
enable-active-high;
states = <1800000 0x1
2900000 0x0>;
};
// External Micro SD slot // External Micro SD slot
sdi0_per1@80126000 { sdi0_per1@80126000 {
arm,primecell-periphid = <0x10480180>; arm,primecell-periphid = <0x10480180>;

View File

@ -146,8 +146,21 @@
}; };
vmmci: regulator-gpio { vmmci: regulator-gpio {
compatible = "regulator-gpio";
gpios = <&gpio7 4 0x4>; gpios = <&gpio7 4 0x4>;
enable-gpio = <&gpio6 25 0x4>; enable-gpio = <&gpio6 25 0x4>;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2900000>;
regulator-name = "mmci-reg";
regulator-type = "voltage";
startup-delay-us = <100>;
enable-active-high;
states = <1800000 0x1
2900000 0x0>;
}; };
// External Micro SD slot // External Micro SD slot

View File

@ -39,11 +39,14 @@ CONFIG_ARCH_HIP04=y
CONFIG_ARCH_KEYSTONE=y CONFIG_ARCH_KEYSTONE=y
CONFIG_ARCH_MESON=y CONFIG_ARCH_MESON=y
CONFIG_ARCH_MXC=y CONFIG_ARCH_MXC=y
CONFIG_SOC_IMX50=y
CONFIG_SOC_IMX51=y CONFIG_SOC_IMX51=y
CONFIG_SOC_IMX53=y CONFIG_SOC_IMX53=y
CONFIG_SOC_IMX6Q=y CONFIG_SOC_IMX6Q=y
CONFIG_SOC_IMX6SL=y CONFIG_SOC_IMX6SL=y
CONFIG_SOC_IMX6SX=y
CONFIG_SOC_VF610=y CONFIG_SOC_VF610=y
CONFIG_SOC_LS1021A=y
CONFIG_ARCH_OMAP3=y CONFIG_ARCH_OMAP3=y
CONFIG_ARCH_OMAP4=y CONFIG_ARCH_OMAP4=y
CONFIG_SOC_OMAP5=y CONFIG_SOC_OMAP5=y

View File

@ -393,7 +393,7 @@ CONFIG_TI_EDMA=y
CONFIG_DMA_OMAP=y CONFIG_DMA_OMAP=y
# CONFIG_IOMMU_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXTCON=m CONFIG_EXTCON=m
CONFIG_EXTCON_GPIO=m CONFIG_EXTCON_USB_GPIO=m
CONFIG_EXTCON_PALMAS=m CONFIG_EXTCON_PALMAS=m
CONFIG_TI_EMIF=m CONFIG_TI_EMIF=m
CONFIG_PWM=y CONFIG_PWM=y

View File

@ -25,7 +25,7 @@ struct dma_iommu_mapping {
}; };
struct dma_iommu_mapping * struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size); arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size);
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping); void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);

View File

@ -110,5 +110,6 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
bool xen_arch_need_swiotlb(struct device *dev, bool xen_arch_need_swiotlb(struct device *dev,
unsigned long pfn, unsigned long pfn,
unsigned long mfn); unsigned long mfn);
unsigned long xen_get_swiotlb_free_pages(unsigned int order);
#endif /* _ASM_ARM_XEN_PAGE_H */ #endif /* _ASM_ARM_XEN_PAGE_H */

View File

@ -303,12 +303,17 @@ static int probe_current_pmu(struct arm_pmu *pmu)
static int of_pmu_irq_cfg(struct platform_device *pdev) static int of_pmu_irq_cfg(struct platform_device *pdev)
{ {
int i; int i, irq;
int *irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); int *irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
if (!irqs) if (!irqs)
return -ENOMEM; return -ENOMEM;
/* Don't bother with PPIs; they're already affine */
irq = platform_get_irq(pdev, 0);
if (irq >= 0 && irq_is_percpu(irq))
return 0;
for (i = 0; i < pdev->num_resources; ++i) { for (i = 0; i < pdev->num_resources; ++i) {
struct device_node *dn; struct device_node *dn;
int cpu; int cpu;
@ -317,7 +322,7 @@ static int of_pmu_irq_cfg(struct platform_device *pdev)
i); i);
if (!dn) { if (!dn) {
pr_warn("Failed to parse %s/interrupt-affinity[%d]\n", pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
of_node_full_name(dn), i); of_node_full_name(pdev->dev.of_node), i);
break; break;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang@pengutronix.de> * Copyright (C) 2010 Pengutronix, Wolfram Sang <kernel@pengutronix.de>
* *
* This program is free software; you can redistribute it and/or modify it under * 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 * the terms of the GNU General Public License version 2 as published by the

View File

@ -112,6 +112,7 @@
#define OMAP3430_VC_CMD_ONLP_SHIFT 16 #define OMAP3430_VC_CMD_ONLP_SHIFT 16
#define OMAP3430_VC_CMD_RET_SHIFT 8 #define OMAP3430_VC_CMD_RET_SHIFT 8
#define OMAP3430_VC_CMD_OFF_SHIFT 0 #define OMAP3430_VC_CMD_OFF_SHIFT 0
#define OMAP3430_SREN_MASK (1 << 4)
#define OMAP3430_HSEN_MASK (1 << 3) #define OMAP3430_HSEN_MASK (1 << 3)
#define OMAP3430_MCODE_MASK (0x7 << 0) #define OMAP3430_MCODE_MASK (0x7 << 0)
#define OMAP3430_VALID_MASK (1 << 24) #define OMAP3430_VALID_MASK (1 << 24)

View File

@ -35,6 +35,7 @@
#define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT 1 #define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT 1
#define OMAP4430_GLOBAL_WUEN_MASK (1 << 16) #define OMAP4430_GLOBAL_WUEN_MASK (1 << 16)
#define OMAP4430_HSMCODE_MASK (0x7 << 0) #define OMAP4430_HSMCODE_MASK (0x7 << 0)
#define OMAP4430_SRMODEEN_MASK (1 << 4)
#define OMAP4430_HSMODEEN_MASK (1 << 3) #define OMAP4430_HSMODEEN_MASK (1 << 3)
#define OMAP4430_HSSCLL_SHIFT 24 #define OMAP4430_HSSCLL_SHIFT 24
#define OMAP4430_ICEPICK_RST_SHIFT 9 #define OMAP4430_ICEPICK_RST_SHIFT 9

View File

@ -316,7 +316,8 @@ static void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm)
* idle. And we can also scale voltages to zero for off-idle. * idle. And we can also scale voltages to zero for off-idle.
* Note that no actual voltage scaling during off-idle will * Note that no actual voltage scaling during off-idle will
* happen unless the board specific twl4030 PMIC scripts are * happen unless the board specific twl4030 PMIC scripts are
* loaded. * loaded. See also omap_vc_i2c_init for comments regarding
* erratum i531.
*/ */
val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET);
if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) { if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) {
@ -704,9 +705,16 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
return; return;
} }
/*
* Note that for omap3 OMAP3430_SREN_MASK clears SREN to work around
* erratum i531 "Extra Power Consumed When Repeated Start Operation
* Mode Is Enabled on I2C Interface Dedicated for Smart Reflex (I2C4)".
* Otherwise I2C4 eventually leads into about 23mW extra power being
* consumed even during off idle using VMODE.
*/
i2c_high_speed = voltdm->pmic->i2c_high_speed; i2c_high_speed = voltdm->pmic->i2c_high_speed;
if (i2c_high_speed) if (i2c_high_speed)
voltdm->rmw(vc->common->i2c_cfg_hsen_mask, voltdm->rmw(vc->common->i2c_cfg_clear_mask,
vc->common->i2c_cfg_hsen_mask, vc->common->i2c_cfg_hsen_mask,
vc->common->i2c_cfg_reg); vc->common->i2c_cfg_reg);

View File

@ -34,6 +34,7 @@ struct voltagedomain;
* @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register
* @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register
* @i2c_cfg_reg: I2C configuration register offset * @i2c_cfg_reg: I2C configuration register offset
* @i2c_cfg_clear_mask: high-speed mode bit clear mask in I2C config register
* @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register
* @i2c_mcode_mask: MCODE field mask for I2C config register * @i2c_mcode_mask: MCODE field mask for I2C config register
* *
@ -52,6 +53,7 @@ struct omap_vc_common {
u8 cmd_ret_shift; u8 cmd_ret_shift;
u8 cmd_off_shift; u8 cmd_off_shift;
u8 i2c_cfg_reg; u8 i2c_cfg_reg;
u8 i2c_cfg_clear_mask;
u8 i2c_cfg_hsen_mask; u8 i2c_cfg_hsen_mask;
u8 i2c_mcode_mask; u8 i2c_mcode_mask;
}; };

View File

@ -40,6 +40,7 @@ static struct omap_vc_common omap3_vc_common = {
.cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT, .cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT,
.cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT, .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT,
.cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT, .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT,
.i2c_cfg_clear_mask = OMAP3430_SREN_MASK | OMAP3430_HSEN_MASK,
.i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK, .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK,
.i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET, .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET,
.i2c_mcode_mask = OMAP3430_MCODE_MASK, .i2c_mcode_mask = OMAP3430_MCODE_MASK,

View File

@ -42,6 +42,7 @@ static const struct omap_vc_common omap4_vc_common = {
.cmd_ret_shift = OMAP4430_RET_SHIFT, .cmd_ret_shift = OMAP4430_RET_SHIFT,
.cmd_off_shift = OMAP4430_OFF_SHIFT, .cmd_off_shift = OMAP4430_OFF_SHIFT,
.i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET, .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET,
.i2c_cfg_clear_mask = OMAP4430_SRMODEEN_MASK | OMAP4430_HSMODEEN_MASK,
.i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK, .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK,
.i2c_mcode_mask = OMAP4430_HSMCODE_MASK, .i2c_mcode_mask = OMAP4430_HSMCODE_MASK,
}; };

View File

@ -691,4 +691,13 @@ config SHARPSL_PM_MAX1111
config PXA310_ULPI config PXA310_ULPI
bool bool
config PXA_SYSTEMS_CPLDS
tristate "Motherboard cplds"
default ARCH_LUBBOCK || MACH_MAINSTONE
help
This driver supports the Lubbock and Mainstone multifunction chip
found on the pxa25x development platform system (Lubbock) and pxa27x
development platform system (Mainstone). This IO board supports the
interrupts handling, ethernet controller, flash chips, etc ...
endif endif

View File

@ -90,4 +90,5 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o
obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o
obj-$(CONFIG_MACH_ZIPIT2) += z2.o obj-$(CONFIG_MACH_ZIPIT2) += z2.o
obj-$(CONFIG_PXA_SYSTEMS_CPLDS) += pxa_cplds_irqs.o
obj-$(CONFIG_TOSA_BT) += tosa-bt.o obj-$(CONFIG_TOSA_BT) += tosa-bt.o

View File

@ -37,7 +37,9 @@
#define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100) #define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100)
/* Board specific IRQs */ /* Board specific IRQs */
#define LUBBOCK_IRQ(x) (IRQ_BOARD_START + (x)) #define LUBBOCK_NR_IRQS IRQ_BOARD_START
#define LUBBOCK_IRQ(x) (LUBBOCK_NR_IRQS + (x))
#define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0) #define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0)
#define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1) #define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1)
#define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) /* usb connect */ #define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) /* usb connect */
@ -47,8 +49,7 @@
#define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */ #define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */
#define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6) #define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6)
#define LUBBOCK_SA1111_IRQ_BASE (IRQ_BOARD_START + 16) #define LUBBOCK_SA1111_IRQ_BASE (LUBBOCK_NR_IRQS + 32)
#define LUBBOCK_NR_IRQS (IRQ_BOARD_START + 16 + 55)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set); extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);

View File

@ -120,7 +120,9 @@
#define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */ #define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */
/* board specific IRQs */ /* board specific IRQs */
#define MAINSTONE_IRQ(x) (IRQ_BOARD_START + (x)) #define MAINSTONE_NR_IRQS IRQ_BOARD_START
#define MAINSTONE_IRQ(x) (MAINSTONE_NR_IRQS + (x))
#define MAINSTONE_MMC_IRQ MAINSTONE_IRQ(0) #define MAINSTONE_MMC_IRQ MAINSTONE_IRQ(0)
#define MAINSTONE_USIM_IRQ MAINSTONE_IRQ(1) #define MAINSTONE_USIM_IRQ MAINSTONE_IRQ(1)
#define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2) #define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2)
@ -136,6 +138,4 @@
#define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14) #define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14)
#define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15) #define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15)
#define MAINSTONE_NR_IRQS (IRQ_BOARD_START + 16)
#endif #endif

View File

@ -12,6 +12,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
@ -123,84 +124,6 @@ void lubbock_set_misc_wr(unsigned int mask, unsigned int set)
} }
EXPORT_SYMBOL(lubbock_set_misc_wr); EXPORT_SYMBOL(lubbock_set_misc_wr);
static unsigned long lubbock_irq_enabled;
static void lubbock_mask_irq(struct irq_data *d)
{
int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
}
static void lubbock_unmask_irq(struct irq_data *d)
{
int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
}
static struct irq_chip lubbock_irq_chip = {
.name = "FPGA",
.irq_ack = lubbock_mask_irq,
.irq_mask = lubbock_mask_irq,
.irq_unmask = lubbock_unmask_irq,
};
static void lubbock_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
do {
/* clear our parent irq */
desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = LUBBOCK_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
}
pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
} while (pending);
}
static void __init lubbock_init_irq(void)
{
int irq;
pxa25x_init_irq();
/* setup extra lubbock irqs */
for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
irq_set_chip_and_handler(irq, &lubbock_irq_chip,
handle_level_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), lubbock_irq_handler);
irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING);
}
#ifdef CONFIG_PM
static void lubbock_irq_resume(void)
{
LUB_IRQ_MASK_EN = lubbock_irq_enabled;
}
static struct syscore_ops lubbock_irq_syscore_ops = {
.resume = lubbock_irq_resume,
};
static int __init lubbock_irq_device_init(void)
{
if (machine_is_lubbock()) {
register_syscore_ops(&lubbock_irq_syscore_ops);
return 0;
}
return -ENODEV;
}
device_initcall(lubbock_irq_device_init);
#endif
static int lubbock_udc_is_connected(void) static int lubbock_udc_is_connected(void)
{ {
return (LUB_MISC_RD & (1 << 9)) == 0; return (LUB_MISC_RD & (1 << 9)) == 0;
@ -383,11 +306,38 @@ static struct platform_device lubbock_flash_device[2] = {
}, },
}; };
static struct resource lubbock_cplds_resources[] = {
[0] = {
.start = LUBBOCK_FPGA_PHYS + 0xc0,
.end = LUBBOCK_FPGA_PHYS + 0xe0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = PXA_GPIO_TO_IRQ(0),
.end = PXA_GPIO_TO_IRQ(0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
},
[2] = {
.start = LUBBOCK_IRQ(0),
.end = LUBBOCK_IRQ(6),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device lubbock_cplds_device = {
.name = "pxa_cplds_irqs",
.id = -1,
.resource = &lubbock_cplds_resources[0],
.num_resources = 3,
};
static struct platform_device *devices[] __initdata = { static struct platform_device *devices[] __initdata = {
&sa1111_device, &sa1111_device,
&smc91x_device, &smc91x_device,
&lubbock_flash_device[0], &lubbock_flash_device[0],
&lubbock_flash_device[1], &lubbock_flash_device[1],
&lubbock_cplds_device,
}; };
static struct pxafb_mode_info sharp_lm8v31_mode = { static struct pxafb_mode_info sharp_lm8v31_mode = {
@ -648,7 +598,7 @@ MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
/* Maintainer: MontaVista Software Inc. */ /* Maintainer: MontaVista Software Inc. */
.map_io = lubbock_map_io, .map_io = lubbock_map_io,
.nr_irqs = LUBBOCK_NR_IRQS, .nr_irqs = LUBBOCK_NR_IRQS,
.init_irq = lubbock_init_irq, .init_irq = pxa25x_init_irq,
.handle_irq = pxa25x_handle_irq, .handle_irq = pxa25x_handle_irq,
.init_time = pxa_timer_init, .init_time = pxa_timer_init,
.init_machine = lubbock_init, .init_machine = lubbock_init,

View File

@ -13,6 +13,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
@ -122,92 +123,6 @@ static unsigned long mainstone_pin_config[] = {
GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
}; };
static unsigned long mainstone_irq_enabled;
static void mainstone_mask_irq(struct irq_data *d)
{
int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq));
}
static void mainstone_unmask_irq(struct irq_data *d)
{
int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
MST_INTSETCLR &= ~(1 << mainstone_irq);
MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq));
}
static struct irq_chip mainstone_irq_chip = {
.name = "FPGA",
.irq_ack = mainstone_mask_irq,
.irq_mask = mainstone_mask_irq,
.irq_unmask = mainstone_unmask_irq,
};
static void mainstone_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
do {
/* clear useless edge notification */
desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = MAINSTONE_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
}
pending = MST_INTSETCLR & mainstone_irq_enabled;
} while (pending);
}
static void __init mainstone_init_irq(void)
{
int irq;
pxa27x_init_irq();
/* setup extra Mainstone irqs */
for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) {
irq_set_chip_and_handler(irq, &mainstone_irq_chip,
handle_level_irq);
if (irq == MAINSTONE_IRQ(10) || irq == MAINSTONE_IRQ(14))
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE | IRQF_NOAUTOEN);
else
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
set_irq_flags(MAINSTONE_IRQ(8), 0);
set_irq_flags(MAINSTONE_IRQ(12), 0);
MST_INTMSKENA = 0;
MST_INTSETCLR = 0;
irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), mainstone_irq_handler);
irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING);
}
#ifdef CONFIG_PM
static void mainstone_irq_resume(void)
{
MST_INTMSKENA = mainstone_irq_enabled;
}
static struct syscore_ops mainstone_irq_syscore_ops = {
.resume = mainstone_irq_resume,
};
static int __init mainstone_irq_device_init(void)
{
if (machine_is_mainstone())
register_syscore_ops(&mainstone_irq_syscore_ops);
return 0;
}
device_initcall(mainstone_irq_device_init);
#endif
static struct resource smc91x_resources[] = { static struct resource smc91x_resources[] = {
[0] = { [0] = {
.start = (MST_ETH_PHYS + 0x300), .start = (MST_ETH_PHYS + 0x300),
@ -487,11 +402,37 @@ static struct platform_device mst_gpio_keys_device = {
}, },
}; };
static struct resource mst_cplds_resources[] = {
[0] = {
.start = MST_FPGA_PHYS + 0xc0,
.end = MST_FPGA_PHYS + 0xe0 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = PXA_GPIO_TO_IRQ(0),
.end = PXA_GPIO_TO_IRQ(0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
},
[2] = {
.start = MAINSTONE_IRQ(0),
.end = MAINSTONE_IRQ(15),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mst_cplds_device = {
.name = "pxa_cplds_irqs",
.id = -1,
.resource = &mst_cplds_resources[0],
.num_resources = 3,
};
static struct platform_device *platform_devices[] __initdata = { static struct platform_device *platform_devices[] __initdata = {
&smc91x_device, &smc91x_device,
&mst_flash_device[0], &mst_flash_device[0],
&mst_flash_device[1], &mst_flash_device[1],
&mst_gpio_keys_device, &mst_gpio_keys_device,
&mst_cplds_device,
}; };
static struct pxaohci_platform_data mainstone_ohci_platform_data = { static struct pxaohci_platform_data mainstone_ohci_platform_data = {
@ -718,7 +659,7 @@ MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
.atag_offset = 0x100, /* BLOB boot parameter setting */ .atag_offset = 0x100, /* BLOB boot parameter setting */
.map_io = mainstone_map_io, .map_io = mainstone_map_io,
.nr_irqs = MAINSTONE_NR_IRQS, .nr_irqs = MAINSTONE_NR_IRQS,
.init_irq = mainstone_init_irq, .init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq, .handle_irq = pxa27x_handle_irq,
.init_time = pxa_timer_init, .init_time = pxa_timer_init,
.init_machine = mainstone_init, .init_machine = mainstone_init,

View File

@ -0,0 +1,200 @@
/*
* Intel Reference Systems cplds
*
* Copyright (C) 2014 Robert Jarzmik
*
* 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.
*
* Cplds motherboard driver, supporting lubbock and mainstone SoC board.
*/
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#define FPGA_IRQ_MASK_EN 0x0
#define FPGA_IRQ_SET_CLR 0x10
#define CPLDS_NB_IRQ 32
struct cplds {
void __iomem *base;
int irq;
unsigned int irq_mask;
struct gpio_desc *gpio0;
struct irq_domain *irqdomain;
};
static irqreturn_t cplds_irq_handler(int in_irq, void *d)
{
struct cplds *fpga = d;
unsigned long pending;
unsigned int bit;
pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
for_each_set_bit(bit, &pending, CPLDS_NB_IRQ)
generic_handle_irq(irq_find_mapping(fpga->irqdomain, bit));
return IRQ_HANDLED;
}
static void cplds_irq_mask_ack(struct irq_data *d)
{
struct cplds *fpga = irq_data_get_irq_chip_data(d);
unsigned int cplds_irq = irqd_to_hwirq(d);
unsigned int set, bit = BIT(cplds_irq);
fpga->irq_mask &= ~bit;
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
set = readl(fpga->base + FPGA_IRQ_SET_CLR);
writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
}
static void cplds_irq_unmask(struct irq_data *d)
{
struct cplds *fpga = irq_data_get_irq_chip_data(d);
unsigned int cplds_irq = irqd_to_hwirq(d);
unsigned int bit = BIT(cplds_irq);
fpga->irq_mask |= bit;
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
}
static struct irq_chip cplds_irq_chip = {
.name = "pxa_cplds",
.irq_mask_ack = cplds_irq_mask_ack,
.irq_unmask = cplds_irq_unmask,
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
};
static int cplds_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
struct cplds *fpga = d->host_data;
irq_set_chip_and_handler(irq, &cplds_irq_chip, handle_level_irq);
irq_set_chip_data(irq, fpga);
return 0;
}
static const struct irq_domain_ops cplds_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
.map = cplds_irq_domain_map,
};
static int cplds_resume(struct platform_device *pdev)
{
struct cplds *fpga = platform_get_drvdata(pdev);
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
return 0;
}
static int cplds_probe(struct platform_device *pdev)
{
struct resource *res;
struct cplds *fpga;
int ret;
unsigned int base_irq = 0;
unsigned long irqflags = 0;
fpga = devm_kzalloc(&pdev->dev, sizeof(*fpga), GFP_KERNEL);
if (!fpga)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
fpga->irq = (unsigned int)res->start;
irqflags = res->flags;
}
if (!fpga->irq)
return -ENODEV;
base_irq = platform_get_irq(pdev, 1);
if (base_irq < 0)
base_irq = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fpga->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(fpga->base))
return PTR_ERR(fpga->base);
platform_set_drvdata(pdev, fpga);
writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
writel(0, fpga->base + FPGA_IRQ_SET_CLR);
ret = devm_request_irq(&pdev->dev, fpga->irq, cplds_irq_handler,
irqflags, dev_name(&pdev->dev), fpga);
if (ret == -ENOSYS)
return -EPROBE_DEFER;
if (ret) {
dev_err(&pdev->dev, "couldn't request main irq%d: %d\n",
fpga->irq, ret);
return ret;
}
irq_set_irq_wake(fpga->irq, 1);
fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
CPLDS_NB_IRQ,
&cplds_irq_domain_ops, fpga);
if (!fpga->irqdomain)
return -ENODEV;
if (base_irq) {
ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0,
CPLDS_NB_IRQ);
if (ret) {
dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n",
base_irq, base_irq + CPLDS_NB_IRQ);
return ret;
}
}
return 0;
}
static int cplds_remove(struct platform_device *pdev)
{
struct cplds *fpga = platform_get_drvdata(pdev);
irq_set_chip_and_handler(fpga->irq, NULL, NULL);
return 0;
}
static const struct of_device_id cplds_id_table[] = {
{ .compatible = "intel,lubbock-cplds-irqs", },
{ .compatible = "intel,mainstone-cplds-irqs", },
{ }
};
MODULE_DEVICE_TABLE(of, cplds_id_table);
static struct platform_driver cplds_driver = {
.driver = {
.name = "pxa_cplds_irqs",
.of_match_table = of_match_ptr(cplds_id_table),
},
.probe = cplds_probe,
.remove = cplds_remove,
.resume = cplds_resume,
};
module_platform_driver(cplds_driver);
MODULE_DESCRIPTION("PXA Cplds interrupts driver");
MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
MODULE_LICENSE("GPL");

View File

@ -44,9 +44,11 @@ static void __iomem *rk3288_bootram_base;
static phys_addr_t rk3288_bootram_phy; static phys_addr_t rk3288_bootram_phy;
static struct regmap *pmu_regmap; static struct regmap *pmu_regmap;
static struct regmap *grf_regmap;
static struct regmap *sgrf_regmap; static struct regmap *sgrf_regmap;
static u32 rk3288_pmu_pwr_mode_con; static u32 rk3288_pmu_pwr_mode_con;
static u32 rk3288_grf_soc_con0;
static u32 rk3288_sgrf_soc_con0; static u32 rk3288_sgrf_soc_con0;
static inline u32 rk3288_l2_config(void) static inline u32 rk3288_l2_config(void)
@ -70,11 +72,25 @@ static void rk3288_slp_mode_set(int level)
{ {
u32 mode_set, mode_set1; u32 mode_set, mode_set1;
regmap_read(grf_regmap, RK3288_GRF_SOC_CON0, &rk3288_grf_soc_con0);
regmap_read(sgrf_regmap, RK3288_SGRF_SOC_CON0, &rk3288_sgrf_soc_con0); regmap_read(sgrf_regmap, RK3288_SGRF_SOC_CON0, &rk3288_sgrf_soc_con0);
regmap_read(pmu_regmap, RK3288_PMU_PWRMODE_CON, regmap_read(pmu_regmap, RK3288_PMU_PWRMODE_CON,
&rk3288_pmu_pwr_mode_con); &rk3288_pmu_pwr_mode_con);
/*
* We need set this bit GRF_FORCE_JTAG here, for the debug module,
* otherwise, it may become inaccessible after resume.
* This creates a potential security issue, as the sdmmc pins may
* accept jtag data for a short time during resume if no card is
* inserted.
* But this is of course also true for the regular boot, before we
* turn of the jtag/sdmmc autodetect.
*/
regmap_write(grf_regmap, RK3288_GRF_SOC_CON0, GRF_FORCE_JTAG |
GRF_FORCE_JTAG_WRITE);
/* /*
* SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR * SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR
* PCLK_WDT_GATE - disable WDT during suspend. * PCLK_WDT_GATE - disable WDT during suspend.
@ -83,6 +99,13 @@ static void rk3288_slp_mode_set(int level)
SGRF_PCLK_WDT_GATE | SGRF_FAST_BOOT_EN SGRF_PCLK_WDT_GATE | SGRF_FAST_BOOT_EN
| SGRF_PCLK_WDT_GATE_WRITE | SGRF_FAST_BOOT_EN_WRITE); | SGRF_PCLK_WDT_GATE_WRITE | SGRF_FAST_BOOT_EN_WRITE);
/*
* The dapswjdp can not auto reset before resume, that cause it may
* access some illegal address during resume. Let's disable it before
* suspend, and the MASKROM will enable it back.
*/
regmap_write(sgrf_regmap, RK3288_SGRF_CPU_CON0, SGRF_DAPDEVICEEN_WRITE);
/* booting address of resuming system is from this register value */ /* booting address of resuming system is from this register value */
regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR, regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
rk3288_bootram_phy); rk3288_bootram_phy);
@ -128,6 +151,9 @@ static void rk3288_slp_mode_set_resume(void)
regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0, regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
rk3288_sgrf_soc_con0 | SGRF_PCLK_WDT_GATE_WRITE rk3288_sgrf_soc_con0 | SGRF_PCLK_WDT_GATE_WRITE
| SGRF_FAST_BOOT_EN_WRITE); | SGRF_FAST_BOOT_EN_WRITE);
regmap_write(grf_regmap, RK3288_GRF_SOC_CON0, rk3288_grf_soc_con0 |
GRF_FORCE_JTAG_WRITE);
} }
static int rockchip_lpmode_enter(unsigned long arg) static int rockchip_lpmode_enter(unsigned long arg)
@ -186,6 +212,13 @@ static int rk3288_suspend_init(struct device_node *np)
return PTR_ERR(pmu_regmap); return PTR_ERR(pmu_regmap);
} }
grf_regmap = syscon_regmap_lookup_by_compatible(
"rockchip,rk3288-grf");
if (IS_ERR(grf_regmap)) {
pr_err("%s: could not find grf regmap\n", __func__);
return PTR_ERR(pmu_regmap);
}
sram_np = of_find_compatible_node(NULL, NULL, sram_np = of_find_compatible_node(NULL, NULL,
"rockchip,rk3288-pmu-sram"); "rockchip,rk3288-pmu-sram");
if (!sram_np) { if (!sram_np) {

View File

@ -48,6 +48,10 @@ static inline void rockchip_suspend_init(void)
#define RK3288_PMU_WAKEUP_RST_CLR_CNT 0x44 #define RK3288_PMU_WAKEUP_RST_CLR_CNT 0x44
#define RK3288_PMU_PWRMODE_CON1 0x90 #define RK3288_PMU_PWRMODE_CON1 0x90
#define RK3288_GRF_SOC_CON0 0x244
#define GRF_FORCE_JTAG BIT(12)
#define GRF_FORCE_JTAG_WRITE BIT(28)
#define RK3288_SGRF_SOC_CON0 (0x0000) #define RK3288_SGRF_SOC_CON0 (0x0000)
#define RK3288_SGRF_FAST_BOOT_ADDR (0x0120) #define RK3288_SGRF_FAST_BOOT_ADDR (0x0120)
#define SGRF_PCLK_WDT_GATE BIT(6) #define SGRF_PCLK_WDT_GATE BIT(6)
@ -55,6 +59,10 @@ static inline void rockchip_suspend_init(void)
#define SGRF_FAST_BOOT_EN BIT(8) #define SGRF_FAST_BOOT_EN BIT(8)
#define SGRF_FAST_BOOT_EN_WRITE BIT(24) #define SGRF_FAST_BOOT_EN_WRITE BIT(24)
#define RK3288_SGRF_CPU_CON0 (0x40)
#define SGRF_DAPDEVICEEN BIT(0)
#define SGRF_DAPDEVICEEN_WRITE BIT(16)
#define RK3288_CRU_MODE_CON 0x50 #define RK3288_CRU_MODE_CON 0x50
#define RK3288_CRU_SEL0_CON 0x60 #define RK3288_CRU_SEL0_CON 0x60
#define RK3288_CRU_SEL1_CON 0x64 #define RK3288_CRU_SEL1_CON 0x64

View File

@ -30,11 +30,30 @@
#include "pm.h" #include "pm.h"
#define RK3288_GRF_SOC_CON0 0x244 #define RK3288_GRF_SOC_CON0 0x244
#define RK3288_TIMER6_7_PHYS 0xff810000
static void __init rockchip_timer_init(void) static void __init rockchip_timer_init(void)
{ {
if (of_machine_is_compatible("rockchip,rk3288")) { if (of_machine_is_compatible("rockchip,rk3288")) {
struct regmap *grf; struct regmap *grf;
void __iomem *reg_base;
/*
* Most/all uboot versions for rk3288 don't enable timer7
* which is needed for the architected timer to work.
* So make sure it is running during early boot.
*/
reg_base = ioremap(RK3288_TIMER6_7_PHYS, SZ_16K);
if (reg_base) {
writel(0, reg_base + 0x30);
writel(0xffffffff, reg_base + 0x20);
writel(0xffffffff, reg_base + 0x24);
writel(1, reg_base + 0x30);
dsb();
iounmap(reg_base);
} else {
pr_err("rockchip: could not map timer7 registers\n");
}
/* /*
* Disable auto jtag/sdmmc switching that causes issues * Disable auto jtag/sdmmc switching that causes issues

View File

@ -1878,7 +1878,7 @@ struct dma_map_ops iommu_coherent_ops = {
* arm_iommu_attach_device function. * arm_iommu_attach_device function.
*/ */
struct dma_iommu_mapping * struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size)
{ {
unsigned int bits = size >> PAGE_SHIFT; unsigned int bits = size >> PAGE_SHIFT;
unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long); unsigned int bitmap_size = BITS_TO_LONGS(bits) * sizeof(long);
@ -1886,6 +1886,10 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
int extensions = 1; int extensions = 1;
int err = -ENOMEM; int err = -ENOMEM;
/* currently only 32-bit DMA address space is supported */
if (size > DMA_BIT_MASK(32) + 1)
return ERR_PTR(-ERANGE);
if (!bitmap_size) if (!bitmap_size)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
@ -2057,13 +2061,6 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
if (!iommu) if (!iommu)
return false; return false;
/*
* currently arm_iommu_create_mapping() takes a max of size_t
* for size param. So check this limit for now.
*/
if (size > SIZE_MAX)
return false;
mapping = arm_iommu_create_mapping(dev->bus, dma_base, size); mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
if (IS_ERR(mapping)) { if (IS_ERR(mapping)) {
pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n", pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",

View File

@ -22,8 +22,6 @@
* *
* These are the low level assembler for performing cache and TLB * These are the low level assembler for performing cache and TLB
* functions on the arm1020. * functions on the arm1020.
*
* CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>

View File

@ -22,8 +22,6 @@
* *
* These are the low level assembler for performing cache and TLB * These are the low level assembler for performing cache and TLB
* functions on the arm1020e. * functions on the arm1020e.
*
* CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>

View File

@ -441,9 +441,6 @@ ENTRY(cpu_arm925_set_pte_ext)
.type __arm925_setup, #function .type __arm925_setup, #function
__arm925_setup: __arm925_setup:
mov r0, #0 mov r0, #0
#if defined(CONFIG_CPU_ICACHE_STREAMING_DISABLE)
orr r0,r0,#1 << 7
#endif
/* Transparent on, D-cache clean & flush mode. See NOTE2 above */ /* Transparent on, D-cache clean & flush mode. See NOTE2 above */
orr r0,r0,#1 << 1 @ transparent mode on orr r0,r0,#1 << 1 @ transparent mode on

View File

@ -602,7 +602,6 @@ __\name\()_proc_info:
PMD_SECT_AP_WRITE | \ PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ PMD_SECT_AP_READ
initfn __feroceon_setup, __\name\()_proc_info initfn __feroceon_setup, __\name\()_proc_info
.long __feroceon_setup
.long cpu_arch_name .long cpu_arch_name
.long cpu_elf_name .long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP

View File

@ -4,6 +4,7 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/memblock.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
@ -21,6 +22,20 @@
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <asm/xen/interface.h> #include <asm/xen/interface.h>
unsigned long xen_get_swiotlb_free_pages(unsigned int order)
{
struct memblock_region *reg;
gfp_t flags = __GFP_NOWARN;
for_each_memblock(memory, reg) {
if (reg->base < (phys_addr_t)0xffffffff) {
flags |= __GFP_DMA;
break;
}
}
return __get_free_pages(flags, order);
}
enum dma_cache_op { enum dma_cache_op {
DMA_UNMAP, DMA_UNMAP,
DMA_MAP, DMA_MAP,

View File

@ -31,6 +31,7 @@ config ARM64
select GENERIC_EARLY_IOREMAP select GENERIC_EARLY_IOREMAP
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL
select GENERIC_PCI_IOMAP select GENERIC_PCI_IOMAP
select GENERIC_SCHED_CLOCK select GENERIC_SCHED_CLOCK
select GENERIC_SMP_IDLE_THREAD select GENERIC_SMP_IDLE_THREAD

View File

@ -65,6 +65,14 @@ do { \
do { \ do { \
compiletime_assert_atomic_type(*p); \ compiletime_assert_atomic_type(*p); \
switch (sizeof(*p)) { \ switch (sizeof(*p)) { \
case 1: \
asm volatile ("stlrb %w1, %0" \
: "=Q" (*p) : "r" (v) : "memory"); \
break; \
case 2: \
asm volatile ("stlrh %w1, %0" \
: "=Q" (*p) : "r" (v) : "memory"); \
break; \
case 4: \ case 4: \
asm volatile ("stlr %w1, %0" \ asm volatile ("stlr %w1, %0" \
: "=Q" (*p) : "r" (v) : "memory"); \ : "=Q" (*p) : "r" (v) : "memory"); \
@ -81,6 +89,14 @@ do { \
typeof(*p) ___p1; \ typeof(*p) ___p1; \
compiletime_assert_atomic_type(*p); \ compiletime_assert_atomic_type(*p); \
switch (sizeof(*p)) { \ switch (sizeof(*p)) { \
case 1: \
asm volatile ("ldarb %w0, %1" \
: "=r" (___p1) : "Q" (*p) : "memory"); \
break; \
case 2: \
asm volatile ("ldarh %w0, %1" \
: "=r" (___p1) : "Q" (*p) : "memory"); \
break; \
case 4: \ case 4: \
asm volatile ("ldar %w0, %1" \ asm volatile ("ldar %w0, %1" \
: "=r" (___p1) : "Q" (*p) : "memory"); \ : "=r" (___p1) : "Q" (*p) : "memory"); \

View File

@ -1310,7 +1310,7 @@ static const struct of_device_id armpmu_of_device_ids[] = {
static int armpmu_device_probe(struct platform_device *pdev) static int armpmu_device_probe(struct platform_device *pdev)
{ {
int i, *irqs; int i, irq, *irqs;
if (!cpu_pmu) if (!cpu_pmu)
return -ENODEV; return -ENODEV;
@ -1319,6 +1319,11 @@ static int armpmu_device_probe(struct platform_device *pdev)
if (!irqs) if (!irqs)
return -ENOMEM; return -ENOMEM;
/* Don't bother with PPIs; they're already affine */
irq = platform_get_irq(pdev, 0);
if (irq >= 0 && irq_is_percpu(irq))
return 0;
for (i = 0; i < pdev->num_resources; ++i) { for (i = 0; i < pdev->num_resources; ++i) {
struct device_node *dn; struct device_node *dn;
int cpu; int cpu;
@ -1327,7 +1332,7 @@ static int armpmu_device_probe(struct platform_device *pdev)
i); i);
if (!dn) { if (!dn) {
pr_warn("Failed to parse %s/interrupt-affinity[%d]\n", pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
of_node_full_name(dn), i); of_node_full_name(pdev->dev.of_node), i);
break; break;
} }

View File

@ -67,8 +67,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags)
*ret_page = phys_to_page(phys); *ret_page = phys_to_page(phys);
ptr = (void *)val; ptr = (void *)val;
if (flags & __GFP_ZERO) memset(ptr, 0, size);
memset(ptr, 0, size);
} }
return ptr; return ptr;
@ -105,7 +104,6 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
struct page *page; struct page *page;
void *addr; void *addr;
size = PAGE_ALIGN(size);
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT, page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
get_order(size)); get_order(size));
if (!page) if (!page)
@ -113,8 +111,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
*dma_handle = phys_to_dma(dev, page_to_phys(page)); *dma_handle = phys_to_dma(dev, page_to_phys(page));
addr = page_address(page); addr = page_address(page);
if (flags & __GFP_ZERO) memset(addr, 0, size);
memset(addr, 0, size);
return addr; return addr;
} else { } else {
return swiotlb_alloc_coherent(dev, size, dma_handle, flags); return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
@ -195,6 +192,8 @@ static void __dma_free(struct device *dev, size_t size,
{ {
void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle)); void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
size = PAGE_ALIGN(size);
if (!is_device_dma_coherent(dev)) { if (!is_device_dma_coherent(dev)) {
if (__free_from_pool(vaddr, size)) if (__free_from_pool(vaddr, size))
return; return;

View File

@ -45,7 +45,7 @@ static volatile unsigned long flushcache_cpumask = 0;
/* /*
* For flush_tlb_others() * For flush_tlb_others()
*/ */
static volatile cpumask_t flush_cpumask; static cpumask_t flush_cpumask;
static struct mm_struct *flush_mm; static struct mm_struct *flush_mm;
static struct vm_area_struct *flush_vma; static struct vm_area_struct *flush_vma;
static volatile unsigned long flush_va; static volatile unsigned long flush_va;
@ -415,7 +415,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
*/ */
send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0); send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
while (!cpumask_empty((cpumask_t*)&flush_cpumask)) { while (!cpumask_empty(&flush_cpumask)) {
/* nothing. lockup detection does not belong here */ /* nothing. lockup detection does not belong here */
mb(); mb();
} }
@ -468,7 +468,7 @@ void smp_invalidate_interrupt(void)
__flush_tlb_page(va); __flush_tlb_page(va);
} }
} }
cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask); cpumask_clear_cpu(cpu_id, &flush_cpumask);
} }
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/

View File

@ -11,7 +11,7 @@
#define TM_CAUSE_RESCHED 0xde #define TM_CAUSE_RESCHED 0xde
#define TM_CAUSE_TLBI 0xdc #define TM_CAUSE_TLBI 0xdc
#define TM_CAUSE_FAC_UNAV 0xda #define TM_CAUSE_FAC_UNAV 0xda
#define TM_CAUSE_SYSCALL 0xd8 #define TM_CAUSE_SYSCALL 0xd8 /* future use */
#define TM_CAUSE_MISC 0xd6 /* future use */ #define TM_CAUSE_MISC 0xd6 /* future use */
#define TM_CAUSE_SIGNAL 0xd4 #define TM_CAUSE_SIGNAL 0xd4
#define TM_CAUSE_ALIGNMENT 0xd2 #define TM_CAUSE_ALIGNMENT 0xd2

View File

@ -749,21 +749,24 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
eeh_unfreeze_pe(pe, false); eeh_unfreeze_pe(pe, false);
eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev); eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev);
eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
break; break;
case pcie_hot_reset: case pcie_hot_reset:
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
eeh_ops->reset(pe, EEH_RESET_HOT); eeh_ops->reset(pe, EEH_RESET_HOT);
break; break;
case pcie_warm_reset: case pcie_warm_reset:
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
break; break;
default: default:
eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); eeh_pe_state_clear(pe, EEH_PE_ISOLATED | EEH_PE_CFG_BLOCKED);
return -EINVAL; return -EINVAL;
}; };
@ -1058,6 +1061,9 @@ void eeh_add_device_early(struct pci_dn *pdn)
if (!edev || !eeh_enabled()) if (!edev || !eeh_enabled())
return; return;
if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
return;
/* USB Bus children of PCI devices will not have BUID's */ /* USB Bus children of PCI devices will not have BUID's */
phb = edev->phb; phb = edev->phb;
if (NULL == phb || if (NULL == phb ||
@ -1112,6 +1118,9 @@ void eeh_add_device_late(struct pci_dev *dev)
return; return;
} }
if (eeh_has_flag(EEH_PROBE_MODE_DEV))
eeh_ops->probe(pdn, NULL);
/* /*
* The EEH cache might not be removed correctly because of * The EEH cache might not be removed correctly because of
* unbalanced kref to the device during unplug time, which * unbalanced kref to the device during unplug time, which

View File

@ -34,7 +34,6 @@
#include <asm/ftrace.h> #include <asm/ftrace.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/context_tracking.h> #include <asm/context_tracking.h>
#include <asm/tm.h>
/* /*
* System calls. * System calls.
@ -146,24 +145,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
andi. r11,r10,_TIF_SYSCALL_DOTRACE andi. r11,r10,_TIF_SYSCALL_DOTRACE
bne syscall_dotrace bne syscall_dotrace
.Lsyscall_dotrace_cont: .Lsyscall_dotrace_cont:
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
BEGIN_FTR_SECTION
b 1f
END_FTR_SECTION_IFCLR(CPU_FTR_TM)
extrdi. r11, r12, 1, (63-MSR_TS_T_LG) /* transaction active? */
beq+ 1f
/* Doom the transaction and don't perform the syscall: */
mfmsr r11
li r12, 1
rldimi r11, r12, MSR_TM_LG, 63-MSR_TM_LG
mtmsrd r11, 0
li r11, (TM_CAUSE_SYSCALL|TM_CAUSE_PERSISTENT)
TABORT(R11)
b .Lsyscall_exit
1:
#endif
cmpldi 0,r0,NR_syscalls cmpldi 0,r0,NR_syscalls
bge- syscall_enosys bge- syscall_enosys

View File

@ -501,9 +501,11 @@ BEGIN_FTR_SECTION
CHECK_HMI_INTERRUPT CHECK_HMI_INTERRUPT
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
ld r1,PACAR1(r13) ld r1,PACAR1(r13)
ld r6,_CCR(r1)
ld r4,_MSR(r1) ld r4,_MSR(r1)
ld r5,_NIP(r1) ld r5,_NIP(r1)
addi r1,r1,INT_FRAME_SIZE addi r1,r1,INT_FRAME_SIZE
mtcr r6
mtspr SPRN_SRR1,r4 mtspr SPRN_SRR1,r4
mtspr SPRN_SRR0,r5 mtspr SPRN_SRR0,r5
rfid rfid

View File

@ -12,6 +12,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/anon_inodes.h> #include <linux/anon_inodes.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/kvm_book3s.h> #include <asm/kvm_book3s.h>
@ -20,7 +21,6 @@
#include <asm/xics.h> #include <asm/xics.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/spinlock.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>

View File

@ -2693,7 +2693,6 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
hose->last_busno = 0xff; hose->last_busno = 0xff;
} }
hose->private_data = phb; hose->private_data = phb;
hose->controller_ops = pnv_pci_controller_ops;
phb->hub_id = hub_id; phb->hub_id = hub_id;
phb->opal_id = phb_id; phb->opal_id = phb_id;
phb->type = ioda_type; phb->type = ioda_type;
@ -2812,6 +2811,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
pnv_pci_controller_ops.enable_device_hook = pnv_pci_enable_device_hook; pnv_pci_controller_ops.enable_device_hook = pnv_pci_enable_device_hook;
pnv_pci_controller_ops.window_alignment = pnv_pci_window_alignment; pnv_pci_controller_ops.window_alignment = pnv_pci_window_alignment;
pnv_pci_controller_ops.reset_secondary_bus = pnv_pci_reset_secondary_bus; pnv_pci_controller_ops.reset_secondary_bus = pnv_pci_reset_secondary_bus;
hose->controller_ops = pnv_pci_controller_ops;
#ifdef CONFIG_PCI_IOV #ifdef CONFIG_PCI_IOV
ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources; ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;

View File

@ -412,6 +412,10 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
if (rc) if (rc)
return -EINVAL; return -EINVAL;
rc = dlpar_acquire_drc(drc_index);
if (rc)
return -EINVAL;
parent = of_find_node_by_path("/cpus"); parent = of_find_node_by_path("/cpus");
if (!parent) if (!parent)
return -ENODEV; return -ENODEV;
@ -422,12 +426,6 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
of_node_put(parent); of_node_put(parent);
rc = dlpar_acquire_drc(drc_index);
if (rc) {
dlpar_free_cc_nodes(dn);
return -EINVAL;
}
rc = dlpar_attach_node(dn); rc = dlpar_attach_node(dn);
if (rc) { if (rc) {
dlpar_release_drc(drc_index); dlpar_release_drc(drc_index);

View File

@ -115,7 +115,7 @@ config S390
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE select HAVE_ARCH_TRANSPARENT_HUGEPAGE
select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z9_109_FEATURES select HAVE_BPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
select HAVE_CMPXCHG_DOUBLE select HAVE_CMPXCHG_DOUBLE
select HAVE_CMPXCHG_LOCAL select HAVE_CMPXCHG_LOCAL
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK

View File

@ -3,9 +3,10 @@
* *
* Support for s390 cryptographic instructions. * Support for s390 cryptographic instructions.
* *
* Copyright IBM Corp. 2003, 2007 * Copyright IBM Corp. 2003, 2015
* Author(s): Thomas Spatzier * Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@de.ibm.com) * Jan Glauber (jan.glauber@de.ibm.com)
* Harald Freudenberger (freude@de.ibm.com)
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the Free
@ -28,15 +29,17 @@
#define CRYPT_S390_MSA 0x1 #define CRYPT_S390_MSA 0x1
#define CRYPT_S390_MSA3 0x2 #define CRYPT_S390_MSA3 0x2
#define CRYPT_S390_MSA4 0x4 #define CRYPT_S390_MSA4 0x4
#define CRYPT_S390_MSA5 0x8
/* s390 cryptographic operations */ /* s390 cryptographic operations */
enum crypt_s390_operations { enum crypt_s390_operations {
CRYPT_S390_KM = 0x0100, CRYPT_S390_KM = 0x0100,
CRYPT_S390_KMC = 0x0200, CRYPT_S390_KMC = 0x0200,
CRYPT_S390_KIMD = 0x0300, CRYPT_S390_KIMD = 0x0300,
CRYPT_S390_KLMD = 0x0400, CRYPT_S390_KLMD = 0x0400,
CRYPT_S390_KMAC = 0x0500, CRYPT_S390_KMAC = 0x0500,
CRYPT_S390_KMCTR = 0x0600 CRYPT_S390_KMCTR = 0x0600,
CRYPT_S390_PPNO = 0x0700
}; };
/* /*
@ -138,6 +141,16 @@ enum crypt_s390_kmac_func {
KMAC_TDEA_192 = CRYPT_S390_KMAC | 3 KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
}; };
/*
* function codes for PPNO (PERFORM PSEUDORANDOM NUMBER
* OPERATION) instruction
*/
enum crypt_s390_ppno_func {
PPNO_QUERY = CRYPT_S390_PPNO | 0,
PPNO_SHA512_DRNG_GEN = CRYPT_S390_PPNO | 3,
PPNO_SHA512_DRNG_SEED = CRYPT_S390_PPNO | 0x83
};
/** /**
* crypt_s390_km: * crypt_s390_km:
* @func: the function code passed to KM; see crypt_s390_km_func * @func: the function code passed to KM; see crypt_s390_km_func
@ -162,11 +175,11 @@ static inline int crypt_s390_km(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */ "0: .insn rre,0xb92e0000,%3,%1\n" /* KM opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
@ -198,11 +211,11 @@ static inline int crypt_s390_kmc(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */ "0: .insn rre,0xb92f0000,%3,%1\n" /* KMC opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
@ -233,11 +246,11 @@ static inline int crypt_s390_kimd(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */ "0: .insn rre,0xb93e0000,%1,%1\n" /* KIMD opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len) : "=d" (ret), "+a" (__src), "+d" (__src_len)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
@ -267,11 +280,11 @@ static inline int crypt_s390_klmd(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */ "0: .insn rre,0xb93f0000,%1,%1\n" /* KLMD opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len) : "=d" (ret), "+a" (__src), "+d" (__src_len)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
@ -302,11 +315,11 @@ static inline int crypt_s390_kmac(long func, void *param,
int ret; int ret;
asm volatile( asm volatile(
"0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */ "0: .insn rre,0xb91e0000,%1,%1\n" /* KLAC opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "=d" (ret), "+a" (__src), "+d" (__src_len) : "=d" (ret), "+a" (__src), "+d" (__src_len)
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
if (ret < 0) if (ret < 0)
@ -340,11 +353,11 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
int ret = -1; int ret = -1;
asm volatile( asm volatile(
"0: .insn rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */ "0: .insn rrf,0xb92d0000,%3,%1,%4,0\n" /* KMCTR opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest), : "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest),
"+a" (__ctr) "+a" (__ctr)
: "d" (__func), "a" (__param) : "cc", "memory"); : "d" (__func), "a" (__param) : "cc", "memory");
@ -353,6 +366,47 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
} }
/**
* crypt_s390_ppno:
* @func: the function code passed to PPNO; see crypt_s390_ppno_func
* @param: address of parameter block; see POP for details on each func
* @dest: address of destination memory area
* @dest_len: size of destination memory area in bytes
* @seed: address of seed data
* @seed_len: size of seed data in bytes
*
* Executes the PPNO (PERFORM PSEUDORANDOM NUMBER OPERATION)
* operation of the CPU.
*
* Returns -1 for failure, 0 for the query func, number of random
* bytes stored in dest buffer for generate function
*/
static inline int crypt_s390_ppno(long func, void *param,
u8 *dest, long dest_len,
const u8 *seed, long seed_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
register void *__param asm("1") = param; /* param block (240 bytes) */
register u8 *__dest asm("2") = dest; /* buf for recv random bytes */
register long __dest_len asm("3") = dest_len; /* requested random bytes */
register const u8 *__seed asm("4") = seed; /* buf with seed data */
register long __seed_len asm("5") = seed_len; /* bytes in seed buf */
int ret = -1;
asm volatile (
"0: .insn rre,0xb93c0000,%1,%5\n" /* PPNO opcode */
"1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n"
"2:\n"
EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (ret), "+a"(__dest), "+d"(__dest_len)
: "d"(__func), "a"(__param), "a"(__seed), "d"(__seed_len)
: "cc", "memory");
if (ret < 0)
return ret;
return (func & CRYPT_S390_FUNC_MASK) ? dest_len - __dest_len : 0;
}
/** /**
* crypt_s390_func_available: * crypt_s390_func_available:
* @func: the function code of the specific function; 0 if op in general * @func: the function code of the specific function; 0 if op in general
@ -373,6 +427,9 @@ static inline int crypt_s390_func_available(int func,
return 0; return 0;
if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77)) if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77))
return 0; return 0;
if (facility_mask & CRYPT_S390_MSA5 && !test_facility(57))
return 0;
switch (func & CRYPT_S390_OP_MASK) { switch (func & CRYPT_S390_OP_MASK) {
case CRYPT_S390_KM: case CRYPT_S390_KM:
ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
@ -390,8 +447,12 @@ static inline int crypt_s390_func_available(int func,
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
break; break;
case CRYPT_S390_KMCTR: case CRYPT_S390_KMCTR:
ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0, ret = crypt_s390_kmctr(KMCTR_QUERY, &status,
NULL); NULL, NULL, 0, NULL);
break;
case CRYPT_S390_PPNO:
ret = crypt_s390_ppno(PPNO_QUERY, &status,
NULL, 0, NULL, 0);
break; break;
default: default:
return 0; return 0;
@ -419,15 +480,14 @@ static inline int crypt_s390_pcc(long func, void *param)
int ret = -1; int ret = -1;
asm volatile( asm volatile(
"0: .insn rre,0xb92c0000,0,0 \n" /* PCC opcode */ "0: .insn rre,0xb92c0000,0,0\n" /* PCC opcode */
"1: brc 1,0b \n" /* handle partial completion */ "1: brc 1,0b\n" /* handle partial completion */
" la %0,0\n" " la %0,0\n"
"2:\n" "2:\n"
EX_TABLE(0b,2b) EX_TABLE(1b,2b) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
: "+d" (ret) : "+d" (ret)
: "d" (__func), "a" (__param) : "cc", "memory"); : "d" (__func), "a" (__param) : "cc", "memory");
return ret; return ret;
} }
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */ #endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */

View File

@ -1,106 +1,529 @@
/* /*
* Copyright IBM Corp. 2006, 2007 * Copyright IBM Corp. 2006, 2015
* Author(s): Jan Glauber <jan.glauber@de.ibm.com> * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
* Harald Freudenberger <freude@de.ibm.com>
* Driver for the s390 pseudo random number generator * Driver for the s390 pseudo random number generator
*/ */
#define KMSG_COMPONENT "prng"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fips.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/device.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/debug.h> #include <asm/debug.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/timex.h>
#include "crypt_s390.h" #include "crypt_s390.h"
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>"); MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("s390 PRNG interface"); MODULE_DESCRIPTION("s390 PRNG interface");
static int prng_chunk_size = 256;
module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH); #define PRNG_MODE_AUTO 0
#define PRNG_MODE_TDES 1
#define PRNG_MODE_SHA512 2
static unsigned int prng_mode = PRNG_MODE_AUTO;
module_param_named(mode, prng_mode, int, 0);
MODULE_PARM_DESC(prng_mode, "PRNG mode: 0 - auto, 1 - TDES, 2 - SHA512");
#define PRNG_CHUNKSIZE_TDES_MIN 8
#define PRNG_CHUNKSIZE_TDES_MAX (64*1024)
#define PRNG_CHUNKSIZE_SHA512_MIN 64
#define PRNG_CHUNKSIZE_SHA512_MAX (64*1024)
static unsigned int prng_chunk_size = 256;
module_param_named(chunksize, prng_chunk_size, int, 0);
MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes"); MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
static int prng_entropy_limit = 4096;
module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); #define PRNG_RESEED_LIMIT_TDES 4096
MODULE_PARM_DESC(prng_entropy_limit, #define PRNG_RESEED_LIMIT_TDES_LOWER 4096
"PRNG add entropy after that much bytes were produced"); #define PRNG_RESEED_LIMIT_SHA512 100000
#define PRNG_RESEED_LIMIT_SHA512_LOWER 10000
static unsigned int prng_reseed_limit;
module_param_named(reseed_limit, prng_reseed_limit, int, 0);
MODULE_PARM_DESC(prng_reseed_limit, "PRNG reseed limit");
/* /*
* Any one who considers arithmetical methods of producing random digits is, * Any one who considers arithmetical methods of producing random digits is,
* of course, in a state of sin. -- John von Neumann * of course, in a state of sin. -- John von Neumann
*/ */
struct s390_prng_data { static int prng_errorflag;
unsigned long count; /* how many bytes were produced */
char *buf; #define PRNG_GEN_ENTROPY_FAILED 1
#define PRNG_SELFTEST_FAILED 2
#define PRNG_INSTANTIATE_FAILED 3
#define PRNG_SEED_FAILED 4
#define PRNG_RESEED_FAILED 5
#define PRNG_GEN_FAILED 6
struct prng_ws_s {
u8 parm_block[32];
u32 reseed_counter;
u64 byte_counter;
}; };
static struct s390_prng_data *p; struct ppno_ws_s {
u32 res;
/* copied from libica, use a non-zero initial parameter block */ u32 reseed_counter;
static unsigned char parm_block[32] = { u64 stream_bytes;
0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4, u8 V[112];
0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0, u8 C[112];
}; };
static int prng_open(struct inode *inode, struct file *file) struct prng_data_s {
struct mutex mutex;
union {
struct prng_ws_s prngws;
struct ppno_ws_s ppnows;
};
u8 *buf;
u32 rest;
u8 *prev;
};
static struct prng_data_s *prng_data;
/* initial parameter block for tdes mode, copied from libica */
static const u8 initial_parm_block[32] __initconst = {
0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52,
0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4,
0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF,
0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0 };
/*** helper functions ***/
static int generate_entropy(u8 *ebuf, size_t nbytes)
{ {
return nonseekable_open(inode, file); int n, ret = 0;
u8 *pg, *h, hash[32];
pg = (u8 *) __get_free_page(GFP_KERNEL);
if (!pg) {
prng_errorflag = PRNG_GEN_ENTROPY_FAILED;
return -ENOMEM;
}
while (nbytes) {
/* fill page with urandom bytes */
get_random_bytes(pg, PAGE_SIZE);
/* exor page with stckf values */
for (n = 0; n < sizeof(PAGE_SIZE/sizeof(u64)); n++) {
u64 *p = ((u64 *)pg) + n;
*p ^= get_tod_clock_fast();
}
n = (nbytes < sizeof(hash)) ? nbytes : sizeof(hash);
if (n < sizeof(hash))
h = hash;
else
h = ebuf;
/* generate sha256 from this page */
if (crypt_s390_kimd(KIMD_SHA_256, h,
pg, PAGE_SIZE) != PAGE_SIZE) {
prng_errorflag = PRNG_GEN_ENTROPY_FAILED;
ret = -EIO;
goto out;
}
if (n < sizeof(hash))
memcpy(ebuf, hash, n);
ret += n;
ebuf += n;
nbytes -= n;
}
out:
free_page((unsigned long)pg);
return ret;
} }
static void prng_add_entropy(void)
/*** tdes functions ***/
static void prng_tdes_add_entropy(void)
{ {
__u64 entropy[4]; __u64 entropy[4];
unsigned int i; unsigned int i;
int ret; int ret;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy, ret = crypt_s390_kmc(KMC_PRNG, prng_data->prngws.parm_block,
(char *)entropy, sizeof(entropy)); (char *)entropy, (char *)entropy,
sizeof(entropy));
BUG_ON(ret < 0 || ret != sizeof(entropy)); BUG_ON(ret < 0 || ret != sizeof(entropy));
memcpy(parm_block, entropy, sizeof(entropy)); memcpy(prng_data->prngws.parm_block, entropy, sizeof(entropy));
} }
} }
static void prng_seed(int nbytes)
static void prng_tdes_seed(int nbytes)
{ {
char buf[16]; char buf[16];
int i = 0; int i = 0;
BUG_ON(nbytes > 16); BUG_ON(nbytes > sizeof(buf));
get_random_bytes(buf, nbytes); get_random_bytes(buf, nbytes);
/* Add the entropy */ /* Add the entropy */
while (nbytes >= 8) { while (nbytes >= 8) {
*((__u64 *)parm_block) ^= *((__u64 *)(buf+i)); *((__u64 *)prng_data->prngws.parm_block) ^= *((__u64 *)(buf+i));
prng_add_entropy(); prng_tdes_add_entropy();
i += 8; i += 8;
nbytes -= 8; nbytes -= 8;
} }
prng_add_entropy(); prng_tdes_add_entropy();
prng_data->prngws.reseed_counter = 0;
} }
static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
loff_t *ppos)
{
int chunk, n;
int ret = 0;
int tmp;
/* nbytes can be arbitrary length, we split it into chunks */ static int __init prng_tdes_instantiate(void)
{
int datalen;
pr_debug("prng runs in TDES mode with "
"chunksize=%d and reseed_limit=%u\n",
prng_chunk_size, prng_reseed_limit);
/* memory allocation, prng_data struct init, mutex init */
datalen = sizeof(struct prng_data_s) + prng_chunk_size;
prng_data = kzalloc(datalen, GFP_KERNEL);
if (!prng_data) {
prng_errorflag = PRNG_INSTANTIATE_FAILED;
return -ENOMEM;
}
mutex_init(&prng_data->mutex);
prng_data->buf = ((u8 *)prng_data) + sizeof(struct prng_data_s);
memcpy(prng_data->prngws.parm_block, initial_parm_block, 32);
/* initialize the PRNG, add 128 bits of entropy */
prng_tdes_seed(16);
return 0;
}
static void prng_tdes_deinstantiate(void)
{
pr_debug("The prng module stopped "
"after running in triple DES mode\n");
kzfree(prng_data);
}
/*** sha512 functions ***/
static int __init prng_sha512_selftest(void)
{
/* NIST DRBG testvector for Hash Drbg, Sha-512, Count #0 */
static const u8 seed[] __initconst = {
0x6b, 0x50, 0xa7, 0xd8, 0xf8, 0xa5, 0x5d, 0x7a,
0x3d, 0xf8, 0xbb, 0x40, 0xbc, 0xc3, 0xb7, 0x22,
0xd8, 0x70, 0x8d, 0xe6, 0x7f, 0xda, 0x01, 0x0b,
0x03, 0xc4, 0xc8, 0x4d, 0x72, 0x09, 0x6f, 0x8c,
0x3e, 0xc6, 0x49, 0xcc, 0x62, 0x56, 0xd9, 0xfa,
0x31, 0xdb, 0x7a, 0x29, 0x04, 0xaa, 0xf0, 0x25 };
static const u8 V0[] __initconst = {
0x00, 0xad, 0xe3, 0x6f, 0x9a, 0x01, 0xc7, 0x76,
0x61, 0x34, 0x35, 0xf5, 0x4e, 0x24, 0x74, 0x22,
0x21, 0x9a, 0x29, 0x89, 0xc7, 0x93, 0x2e, 0x60,
0x1e, 0xe8, 0x14, 0x24, 0x8d, 0xd5, 0x03, 0xf1,
0x65, 0x5d, 0x08, 0x22, 0x72, 0xd5, 0xad, 0x95,
0xe1, 0x23, 0x1e, 0x8a, 0xa7, 0x13, 0xd9, 0x2b,
0x5e, 0xbc, 0xbb, 0x80, 0xab, 0x8d, 0xe5, 0x79,
0xab, 0x5b, 0x47, 0x4e, 0xdd, 0xee, 0x6b, 0x03,
0x8f, 0x0f, 0x5c, 0x5e, 0xa9, 0x1a, 0x83, 0xdd,
0xd3, 0x88, 0xb2, 0x75, 0x4b, 0xce, 0x83, 0x36,
0x57, 0x4b, 0xf1, 0x5c, 0xca, 0x7e, 0x09, 0xc0,
0xd3, 0x89, 0xc6, 0xe0, 0xda, 0xc4, 0x81, 0x7e,
0x5b, 0xf9, 0xe1, 0x01, 0xc1, 0x92, 0x05, 0xea,
0xf5, 0x2f, 0xc6, 0xc6, 0xc7, 0x8f, 0xbc, 0xf4 };
static const u8 C0[] __initconst = {
0x00, 0xf4, 0xa3, 0xe5, 0xa0, 0x72, 0x63, 0x95,
0xc6, 0x4f, 0x48, 0xd0, 0x8b, 0x5b, 0x5f, 0x8e,
0x6b, 0x96, 0x1f, 0x16, 0xed, 0xbc, 0x66, 0x94,
0x45, 0x31, 0xd7, 0x47, 0x73, 0x22, 0xa5, 0x86,
0xce, 0xc0, 0x4c, 0xac, 0x63, 0xb8, 0x39, 0x50,
0xbf, 0xe6, 0x59, 0x6c, 0x38, 0x58, 0x99, 0x1f,
0x27, 0xa7, 0x9d, 0x71, 0x2a, 0xb3, 0x7b, 0xf9,
0xfb, 0x17, 0x86, 0xaa, 0x99, 0x81, 0xaa, 0x43,
0xe4, 0x37, 0xd3, 0x1e, 0x6e, 0xe5, 0xe6, 0xee,
0xc2, 0xed, 0x95, 0x4f, 0x53, 0x0e, 0x46, 0x8a,
0xcc, 0x45, 0xa5, 0xdb, 0x69, 0x0d, 0x81, 0xc9,
0x32, 0x92, 0xbc, 0x8f, 0x33, 0xe6, 0xf6, 0x09,
0x7c, 0x8e, 0x05, 0x19, 0x0d, 0xf1, 0xb6, 0xcc,
0xf3, 0x02, 0x21, 0x90, 0x25, 0xec, 0xed, 0x0e };
static const u8 random[] __initconst = {
0x95, 0xb7, 0xf1, 0x7e, 0x98, 0x02, 0xd3, 0x57,
0x73, 0x92, 0xc6, 0xa9, 0xc0, 0x80, 0x83, 0xb6,
0x7d, 0xd1, 0x29, 0x22, 0x65, 0xb5, 0xf4, 0x2d,
0x23, 0x7f, 0x1c, 0x55, 0xbb, 0x9b, 0x10, 0xbf,
0xcf, 0xd8, 0x2c, 0x77, 0xa3, 0x78, 0xb8, 0x26,
0x6a, 0x00, 0x99, 0x14, 0x3b, 0x3c, 0x2d, 0x64,
0x61, 0x1e, 0xee, 0xb6, 0x9a, 0xcd, 0xc0, 0x55,
0x95, 0x7c, 0x13, 0x9e, 0x8b, 0x19, 0x0c, 0x7a,
0x06, 0x95, 0x5f, 0x2c, 0x79, 0x7c, 0x27, 0x78,
0xde, 0x94, 0x03, 0x96, 0xa5, 0x01, 0xf4, 0x0e,
0x91, 0x39, 0x6a, 0xcf, 0x8d, 0x7e, 0x45, 0xeb,
0xdb, 0xb5, 0x3b, 0xbf, 0x8c, 0x97, 0x52, 0x30,
0xd2, 0xf0, 0xff, 0x91, 0x06, 0xc7, 0x61, 0x19,
0xae, 0x49, 0x8e, 0x7f, 0xbc, 0x03, 0xd9, 0x0f,
0x8e, 0x4c, 0x51, 0x62, 0x7a, 0xed, 0x5c, 0x8d,
0x42, 0x63, 0xd5, 0xd2, 0xb9, 0x78, 0x87, 0x3a,
0x0d, 0xe5, 0x96, 0xee, 0x6d, 0xc7, 0xf7, 0xc2,
0x9e, 0x37, 0xee, 0xe8, 0xb3, 0x4c, 0x90, 0xdd,
0x1c, 0xf6, 0xa9, 0xdd, 0xb2, 0x2b, 0x4c, 0xbd,
0x08, 0x6b, 0x14, 0xb3, 0x5d, 0xe9, 0x3d, 0xa2,
0xd5, 0xcb, 0x18, 0x06, 0x69, 0x8c, 0xbd, 0x7b,
0xbb, 0x67, 0xbf, 0xe3, 0xd3, 0x1f, 0xd2, 0xd1,
0xdb, 0xd2, 0xa1, 0xe0, 0x58, 0xa3, 0xeb, 0x99,
0xd7, 0xe5, 0x1f, 0x1a, 0x93, 0x8e, 0xed, 0x5e,
0x1c, 0x1d, 0xe2, 0x3a, 0x6b, 0x43, 0x45, 0xd3,
0x19, 0x14, 0x09, 0xf9, 0x2f, 0x39, 0xb3, 0x67,
0x0d, 0x8d, 0xbf, 0xb6, 0x35, 0xd8, 0xe6, 0xa3,
0x69, 0x32, 0xd8, 0x10, 0x33, 0xd1, 0x44, 0x8d,
0x63, 0xb4, 0x03, 0xdd, 0xf8, 0x8e, 0x12, 0x1b,
0x6e, 0x81, 0x9a, 0xc3, 0x81, 0x22, 0x6c, 0x13,
0x21, 0xe4, 0xb0, 0x86, 0x44, 0xf6, 0x72, 0x7c,
0x36, 0x8c, 0x5a, 0x9f, 0x7a, 0x4b, 0x3e, 0xe2 };
int ret = 0;
u8 buf[sizeof(random)];
struct ppno_ws_s ws;
memset(&ws, 0, sizeof(ws));
/* initial seed */
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_SEED,
&ws, NULL, 0,
seed, sizeof(seed));
if (ret < 0) {
pr_err("The prng self test seed operation for the "
"SHA-512 mode failed with rc=%d\n", ret);
prng_errorflag = PRNG_SELFTEST_FAILED;
return -EIO;
}
/* check working states V and C */
if (memcmp(ws.V, V0, sizeof(V0)) != 0
|| memcmp(ws.C, C0, sizeof(C0)) != 0) {
pr_err("The prng self test state test "
"for the SHA-512 mode failed\n");
prng_errorflag = PRNG_SELFTEST_FAILED;
return -EIO;
}
/* generate random bytes */
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
&ws, buf, sizeof(buf),
NULL, 0);
if (ret < 0) {
pr_err("The prng self test generate operation for "
"the SHA-512 mode failed with rc=%d\n", ret);
prng_errorflag = PRNG_SELFTEST_FAILED;
return -EIO;
}
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
&ws, buf, sizeof(buf),
NULL, 0);
if (ret < 0) {
pr_err("The prng self test generate operation for "
"the SHA-512 mode failed with rc=%d\n", ret);
prng_errorflag = PRNG_SELFTEST_FAILED;
return -EIO;
}
/* check against expected data */
if (memcmp(buf, random, sizeof(random)) != 0) {
pr_err("The prng self test data test "
"for the SHA-512 mode failed\n");
prng_errorflag = PRNG_SELFTEST_FAILED;
return -EIO;
}
return 0;
}
static int __init prng_sha512_instantiate(void)
{
int ret, datalen;
u8 seed[64];
pr_debug("prng runs in SHA-512 mode "
"with chunksize=%d and reseed_limit=%u\n",
prng_chunk_size, prng_reseed_limit);
/* memory allocation, prng_data struct init, mutex init */
datalen = sizeof(struct prng_data_s) + prng_chunk_size;
if (fips_enabled)
datalen += prng_chunk_size;
prng_data = kzalloc(datalen, GFP_KERNEL);
if (!prng_data) {
prng_errorflag = PRNG_INSTANTIATE_FAILED;
return -ENOMEM;
}
mutex_init(&prng_data->mutex);
prng_data->buf = ((u8 *)prng_data) + sizeof(struct prng_data_s);
/* selftest */
ret = prng_sha512_selftest();
if (ret)
goto outfree;
/* generate initial seed bytestring, first 48 bytes of entropy */
ret = generate_entropy(seed, 48);
if (ret != 48)
goto outfree;
/* followed by 16 bytes of unique nonce */
get_tod_clock_ext(seed + 48);
/* initial seed of the ppno drng */
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_SEED,
&prng_data->ppnows, NULL, 0,
seed, sizeof(seed));
if (ret < 0) {
prng_errorflag = PRNG_SEED_FAILED;
ret = -EIO;
goto outfree;
}
/* if fips mode is enabled, generate a first block of random
bytes for the FIPS 140-2 Conditional Self Test */
if (fips_enabled) {
prng_data->prev = prng_data->buf + prng_chunk_size;
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
&prng_data->ppnows,
prng_data->prev,
prng_chunk_size,
NULL, 0);
if (ret < 0 || ret != prng_chunk_size) {
prng_errorflag = PRNG_GEN_FAILED;
ret = -EIO;
goto outfree;
}
}
return 0;
outfree:
kfree(prng_data);
return ret;
}
static void prng_sha512_deinstantiate(void)
{
pr_debug("The prng module stopped after running in SHA-512 mode\n");
kzfree(prng_data);
}
static int prng_sha512_reseed(void)
{
int ret;
u8 seed[32];
/* generate 32 bytes of fresh entropy */
ret = generate_entropy(seed, sizeof(seed));
if (ret != sizeof(seed))
return ret;
/* do a reseed of the ppno drng with this bytestring */
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_SEED,
&prng_data->ppnows, NULL, 0,
seed, sizeof(seed));
if (ret) {
prng_errorflag = PRNG_RESEED_FAILED;
return -EIO;
}
return 0;
}
static int prng_sha512_generate(u8 *buf, size_t nbytes)
{
int ret;
/* reseed needed ? */
if (prng_data->ppnows.reseed_counter > prng_reseed_limit) {
ret = prng_sha512_reseed();
if (ret)
return ret;
}
/* PPNO generate */
ret = crypt_s390_ppno(PPNO_SHA512_DRNG_GEN,
&prng_data->ppnows, buf, nbytes,
NULL, 0);
if (ret < 0 || ret != nbytes) {
prng_errorflag = PRNG_GEN_FAILED;
return -EIO;
}
/* FIPS 140-2 Conditional Self Test */
if (fips_enabled) {
if (!memcmp(prng_data->prev, buf, nbytes)) {
prng_errorflag = PRNG_GEN_FAILED;
return -EILSEQ;
}
memcpy(prng_data->prev, buf, nbytes);
}
return ret;
}
/*** file io functions ***/
static int prng_open(struct inode *inode, struct file *file)
{
return nonseekable_open(inode, file);
}
static ssize_t prng_tdes_read(struct file *file, char __user *ubuf,
size_t nbytes, loff_t *ppos)
{
int chunk, n, tmp, ret = 0;
/* lock prng_data struct */
if (mutex_lock_interruptible(&prng_data->mutex))
return -ERESTARTSYS;
while (nbytes) { while (nbytes) {
/* same as in extract_entropy_user in random.c */
if (need_resched()) { if (need_resched()) {
if (signal_pending(current)) { if (signal_pending(current)) {
if (ret == 0) if (ret == 0)
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
break; break;
} }
/* give mutex free before calling schedule() */
mutex_unlock(&prng_data->mutex);
schedule(); schedule();
/* occopy mutex again */
if (mutex_lock_interruptible(&prng_data->mutex)) {
if (ret == 0)
ret = -ERESTARTSYS;
return ret;
}
} }
/* /*
@ -112,12 +535,11 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
/* PRNG only likes multiples of 8 bytes */ /* PRNG only likes multiples of 8 bytes */
n = (chunk + 7) & -8; n = (chunk + 7) & -8;
if (p->count > prng_entropy_limit) if (prng_data->prngws.reseed_counter > prng_reseed_limit)
prng_seed(8); prng_tdes_seed(8);
/* if the CPU supports PRNG stckf is present too */ /* if the CPU supports PRNG stckf is present too */
asm volatile(".insn s,0xb27c0000,%0" *((unsigned long long *)prng_data->buf) = get_tod_clock_fast();
: "=m" (*((unsigned long long *)p->buf)) : : "cc");
/* /*
* Beside the STCKF the input for the TDES-EDE is the output * Beside the STCKF the input for the TDES-EDE is the output
@ -132,34 +554,258 @@ static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
* Note: you can still get strict X9.17 conformity by setting * Note: you can still get strict X9.17 conformity by setting
* prng_chunk_size to 8 bytes. * prng_chunk_size to 8 bytes.
*/ */
tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n); tmp = crypt_s390_kmc(KMC_PRNG, prng_data->prngws.parm_block,
BUG_ON((tmp < 0) || (tmp != n)); prng_data->buf, prng_data->buf, n);
if (tmp < 0 || tmp != n) {
ret = -EIO;
break;
}
p->count += n; prng_data->prngws.byte_counter += n;
prng_data->prngws.reseed_counter += n;
if (copy_to_user(ubuf, p->buf, chunk)) if (copy_to_user(ubuf, prng_data->buf, chunk))
return -EFAULT; return -EFAULT;
nbytes -= chunk; nbytes -= chunk;
ret += chunk; ret += chunk;
ubuf += chunk; ubuf += chunk;
} }
/* unlock prng_data struct */
mutex_unlock(&prng_data->mutex);
return ret; return ret;
} }
static const struct file_operations prng_fops = {
static ssize_t prng_sha512_read(struct file *file, char __user *ubuf,
size_t nbytes, loff_t *ppos)
{
int n, ret = 0;
u8 *p;
/* if errorflag is set do nothing and return 'broken pipe' */
if (prng_errorflag)
return -EPIPE;
/* lock prng_data struct */
if (mutex_lock_interruptible(&prng_data->mutex))
return -ERESTARTSYS;
while (nbytes) {
if (need_resched()) {
if (signal_pending(current)) {
if (ret == 0)
ret = -ERESTARTSYS;
break;
}
/* give mutex free before calling schedule() */
mutex_unlock(&prng_data->mutex);
schedule();
/* occopy mutex again */
if (mutex_lock_interruptible(&prng_data->mutex)) {
if (ret == 0)
ret = -ERESTARTSYS;
return ret;
}
}
if (prng_data->rest) {
/* push left over random bytes from the previous read */
p = prng_data->buf + prng_chunk_size - prng_data->rest;
n = (nbytes < prng_data->rest) ?
nbytes : prng_data->rest;
prng_data->rest -= n;
} else {
/* generate one chunk of random bytes into read buf */
p = prng_data->buf;
n = prng_sha512_generate(p, prng_chunk_size);
if (n < 0) {
ret = n;
break;
}
if (nbytes < prng_chunk_size) {
n = nbytes;
prng_data->rest = prng_chunk_size - n;
} else {
n = prng_chunk_size;
prng_data->rest = 0;
}
}
if (copy_to_user(ubuf, p, n)) {
ret = -EFAULT;
break;
}
ubuf += n;
nbytes -= n;
ret += n;
}
/* unlock prng_data struct */
mutex_unlock(&prng_data->mutex);
return ret;
}
/*** sysfs stuff ***/
static const struct file_operations prng_sha512_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = &prng_open, .open = &prng_open,
.release = NULL, .release = NULL,
.read = &prng_read, .read = &prng_sha512_read,
.llseek = noop_llseek,
};
static const struct file_operations prng_tdes_fops = {
.owner = THIS_MODULE,
.open = &prng_open,
.release = NULL,
.read = &prng_tdes_read,
.llseek = noop_llseek, .llseek = noop_llseek,
}; };
static struct miscdevice prng_dev = { static struct miscdevice prng_sha512_dev = {
.name = "prandom", .name = "prandom",
.minor = MISC_DYNAMIC_MINOR, .minor = MISC_DYNAMIC_MINOR,
.fops = &prng_fops, .fops = &prng_sha512_fops,
}; };
static struct miscdevice prng_tdes_dev = {
.name = "prandom",
.minor = MISC_DYNAMIC_MINOR,
.fops = &prng_tdes_fops,
};
/* chunksize attribute (ro) */
static ssize_t prng_chunksize_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%u\n", prng_chunk_size);
}
static DEVICE_ATTR(chunksize, 0444, prng_chunksize_show, NULL);
/* counter attribute (ro) */
static ssize_t prng_counter_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u64 counter;
if (mutex_lock_interruptible(&prng_data->mutex))
return -ERESTARTSYS;
if (prng_mode == PRNG_MODE_SHA512)
counter = prng_data->ppnows.stream_bytes;
else
counter = prng_data->prngws.byte_counter;
mutex_unlock(&prng_data->mutex);
return snprintf(buf, PAGE_SIZE, "%llu\n", counter);
}
static DEVICE_ATTR(byte_counter, 0444, prng_counter_show, NULL);
/* errorflag attribute (ro) */
static ssize_t prng_errorflag_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", prng_errorflag);
}
static DEVICE_ATTR(errorflag, 0444, prng_errorflag_show, NULL);
/* mode attribute (ro) */
static ssize_t prng_mode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
if (prng_mode == PRNG_MODE_TDES)
return snprintf(buf, PAGE_SIZE, "TDES\n");
else
return snprintf(buf, PAGE_SIZE, "SHA512\n");
}
static DEVICE_ATTR(mode, 0444, prng_mode_show, NULL);
/* reseed attribute (w) */
static ssize_t prng_reseed_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
if (mutex_lock_interruptible(&prng_data->mutex))
return -ERESTARTSYS;
prng_sha512_reseed();
mutex_unlock(&prng_data->mutex);
return count;
}
static DEVICE_ATTR(reseed, 0200, NULL, prng_reseed_store);
/* reseed limit attribute (rw) */
static ssize_t prng_reseed_limit_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%u\n", prng_reseed_limit);
}
static ssize_t prng_reseed_limit_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned limit;
if (sscanf(buf, "%u\n", &limit) != 1)
return -EINVAL;
if (prng_mode == PRNG_MODE_SHA512) {
if (limit < PRNG_RESEED_LIMIT_SHA512_LOWER)
return -EINVAL;
} else {
if (limit < PRNG_RESEED_LIMIT_TDES_LOWER)
return -EINVAL;
}
prng_reseed_limit = limit;
return count;
}
static DEVICE_ATTR(reseed_limit, 0644,
prng_reseed_limit_show, prng_reseed_limit_store);
/* strength attribute (ro) */
static ssize_t prng_strength_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "256\n");
}
static DEVICE_ATTR(strength, 0444, prng_strength_show, NULL);
static struct attribute *prng_sha512_dev_attrs[] = {
&dev_attr_errorflag.attr,
&dev_attr_chunksize.attr,
&dev_attr_byte_counter.attr,
&dev_attr_mode.attr,
&dev_attr_reseed.attr,
&dev_attr_reseed_limit.attr,
&dev_attr_strength.attr,
NULL
};
static struct attribute *prng_tdes_dev_attrs[] = {
&dev_attr_chunksize.attr,
&dev_attr_byte_counter.attr,
&dev_attr_mode.attr,
NULL
};
static struct attribute_group prng_sha512_dev_attr_group = {
.attrs = prng_sha512_dev_attrs
};
static struct attribute_group prng_tdes_dev_attr_group = {
.attrs = prng_tdes_dev_attrs
};
/*** module init and exit ***/
static int __init prng_init(void) static int __init prng_init(void)
{ {
@ -169,43 +815,105 @@ static int __init prng_init(void)
if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA)) if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (prng_chunk_size < 8) /* choose prng mode */
return -EINVAL; if (prng_mode != PRNG_MODE_TDES) {
/* check for MSA5 support for PPNO operations */
p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL); if (!crypt_s390_func_available(PPNO_SHA512_DRNG_GEN,
if (!p) CRYPT_S390_MSA5)) {
return -ENOMEM; if (prng_mode == PRNG_MODE_SHA512) {
p->count = 0; pr_err("The prng module cannot "
"start in SHA-512 mode\n");
p->buf = kmalloc(prng_chunk_size, GFP_KERNEL); return -EOPNOTSUPP;
if (!p->buf) { }
ret = -ENOMEM; prng_mode = PRNG_MODE_TDES;
goto out_free; } else
prng_mode = PRNG_MODE_SHA512;
} }
/* initialize the PRNG, add 128 bits of entropy */ if (prng_mode == PRNG_MODE_SHA512) {
prng_seed(16);
ret = misc_register(&prng_dev); /* SHA512 mode */
if (ret)
goto out_buf;
return 0;
out_buf: if (prng_chunk_size < PRNG_CHUNKSIZE_SHA512_MIN
kfree(p->buf); || prng_chunk_size > PRNG_CHUNKSIZE_SHA512_MAX)
out_free: return -EINVAL;
kfree(p); prng_chunk_size = (prng_chunk_size + 0x3f) & ~0x3f;
if (prng_reseed_limit == 0)
prng_reseed_limit = PRNG_RESEED_LIMIT_SHA512;
else if (prng_reseed_limit < PRNG_RESEED_LIMIT_SHA512_LOWER)
return -EINVAL;
ret = prng_sha512_instantiate();
if (ret)
goto out;
ret = misc_register(&prng_sha512_dev);
if (ret) {
prng_sha512_deinstantiate();
goto out;
}
ret = sysfs_create_group(&prng_sha512_dev.this_device->kobj,
&prng_sha512_dev_attr_group);
if (ret) {
misc_deregister(&prng_sha512_dev);
prng_sha512_deinstantiate();
goto out;
}
} else {
/* TDES mode */
if (prng_chunk_size < PRNG_CHUNKSIZE_TDES_MIN
|| prng_chunk_size > PRNG_CHUNKSIZE_TDES_MAX)
return -EINVAL;
prng_chunk_size = (prng_chunk_size + 0x07) & ~0x07;
if (prng_reseed_limit == 0)
prng_reseed_limit = PRNG_RESEED_LIMIT_TDES;
else if (prng_reseed_limit < PRNG_RESEED_LIMIT_TDES_LOWER)
return -EINVAL;
ret = prng_tdes_instantiate();
if (ret)
goto out;
ret = misc_register(&prng_tdes_dev);
if (ret) {
prng_tdes_deinstantiate();
goto out;
}
ret = sysfs_create_group(&prng_tdes_dev.this_device->kobj,
&prng_tdes_dev_attr_group);
if (ret) {
misc_deregister(&prng_tdes_dev);
prng_tdes_deinstantiate();
goto out;
}
}
out:
return ret; return ret;
} }
static void __exit prng_exit(void) static void __exit prng_exit(void)
{ {
/* wipe me */ if (prng_mode == PRNG_MODE_SHA512) {
kzfree(p->buf); sysfs_remove_group(&prng_sha512_dev.this_device->kobj,
kfree(p); &prng_sha512_dev_attr_group);
misc_deregister(&prng_sha512_dev);
misc_deregister(&prng_dev); prng_sha512_deinstantiate();
} else {
sysfs_remove_group(&prng_tdes_dev.this_device->kobj,
&prng_tdes_dev_attr_group);
misc_deregister(&prng_tdes_dev);
prng_tdes_deinstantiate();
}
} }
module_init(prng_init); module_init(prng_init);
module_exit(prng_exit); module_exit(prng_exit);

View File

@ -26,6 +26,9 @@
/* Not more than 2GB */ /* Not more than 2GB */
#define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31)
/* Allocate control page with GFP_DMA */
#define KEXEC_CONTROL_MEMORY_GFP GFP_DMA
/* Maximum address we can use for the crash control pages */ /* Maximum address we can use for the crash control pages */
#define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL) #define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL)

View File

@ -14,7 +14,9 @@ typedef struct {
unsigned long asce_bits; unsigned long asce_bits;
unsigned long asce_limit; unsigned long asce_limit;
unsigned long vdso_base; unsigned long vdso_base;
/* The mmu context has extended page tables. */ /* The mmu context allocates 4K page tables. */
unsigned int alloc_pgste:1;
/* The mmu context uses extended page tables. */
unsigned int has_pgste:1; unsigned int has_pgste:1;
/* The mmu context uses storage keys. */ /* The mmu context uses storage keys. */
unsigned int use_skey:1; unsigned int use_skey:1;

View File

@ -20,8 +20,11 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.flush_mm = 0; mm->context.flush_mm = 0;
mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
mm->context.asce_bits |= _ASCE_TYPE_REGION3; mm->context.asce_bits |= _ASCE_TYPE_REGION3;
#ifdef CONFIG_PGSTE
mm->context.alloc_pgste = page_table_allocate_pgste;
mm->context.has_pgste = 0; mm->context.has_pgste = 0;
mm->context.use_skey = 0; mm->context.use_skey = 0;
#endif
mm->context.asce_limit = STACK_TOP_MAX; mm->context.asce_limit = STACK_TOP_MAX;
crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
return 0; return 0;

View File

@ -21,6 +21,7 @@ void crst_table_free(struct mm_struct *, unsigned long *);
unsigned long *page_table_alloc(struct mm_struct *); unsigned long *page_table_alloc(struct mm_struct *);
void page_table_free(struct mm_struct *, unsigned long *); void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long);
extern int page_table_allocate_pgste;
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq); unsigned long key, bool nq);

View File

@ -12,12 +12,9 @@
#define _ASM_S390_PGTABLE_H #define _ASM_S390_PGTABLE_H
/* /*
* The Linux memory management assumes a three-level page table setup. For * The Linux memory management assumes a three-level page table setup.
* s390 31 bit we "fold" the mid level into the top-level page table, so * For s390 64 bit we use up to four of the five levels the hardware
* that we physically have the same two-level page table as the s390 mmu * provides (region first tables are not used).
* expects in 31 bit mode. For s390 64 bit we use three of the five levels
* the hardware provides (region first and region second tables are not
* used).
* *
* The "pgd_xxx()" functions are trivial for a folded two-level * The "pgd_xxx()" functions are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded * setup: the pgd is never bad, and a pmd always exists (as it's folded
@ -101,8 +98,8 @@ extern unsigned long zero_page_mask;
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
/* /*
* The vmalloc and module area will always be on the topmost area of the kernel * The vmalloc and module area will always be on the topmost area of the
* mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc and modules. * kernel mapping. We reserve 128GB (64bit) for vmalloc and modules.
* On 64 bit kernels we have a 2GB area at the top of the vmalloc area where * On 64 bit kernels we have a 2GB area at the top of the vmalloc area where
* modules will reside. That makes sure that inter module branches always * modules will reside. That makes sure that inter module branches always
* happen without trampolines and in addition the placement within a 2GB frame * happen without trampolines and in addition the placement within a 2GB frame
@ -131,38 +128,6 @@ static inline int is_module_addr(void *addr)
} }
/* /*
* A 31 bit pagetable entry of S390 has following format:
* | PFRA | | OS |
* 0 0IP0
* 00000000001111111111222222222233
* 01234567890123456789012345678901
*
* I Page-Invalid Bit: Page is not available for address-translation
* P Page-Protection Bit: Store access not possible for page
*
* A 31 bit segmenttable entry of S390 has following format:
* | P-table origin | |PTL
* 0 IC
* 00000000001111111111222222222233
* 01234567890123456789012345678901
*
* I Segment-Invalid Bit: Segment is not available for address-translation
* C Common-Segment Bit: Segment is not private (PoP 3-30)
* PTL Page-Table-Length: Page-table length (PTL+1*16 entries -> up to 256)
*
* The 31 bit segmenttable origin of S390 has following format:
*
* |S-table origin | | STL |
* X **GPS
* 00000000001111111111222222222233
* 01234567890123456789012345678901
*
* X Space-Switch event:
* G Segment-Invalid Bit: *
* P Private-Space Bit: Segment is not private (PoP 3-30)
* S Storage-Alteration:
* STL Segment-Table-Length: Segment-table length (STL+1*16 entries -> up to 2048)
*
* A 64 bit pagetable entry of S390 has following format: * A 64 bit pagetable entry of S390 has following format:
* | PFRA |0IPC| OS | * | PFRA |0IPC| OS |
* 0000000000111111111122222222223333333333444444444455555555556666 * 0000000000111111111122222222223333333333444444444455555555556666
@ -220,7 +185,6 @@ static inline int is_module_addr(void *addr)
/* Software bits in the page table entry */ /* Software bits in the page table entry */
#define _PAGE_PRESENT 0x001 /* SW pte present bit */ #define _PAGE_PRESENT 0x001 /* SW pte present bit */
#define _PAGE_TYPE 0x002 /* SW pte type bit */
#define _PAGE_YOUNG 0x004 /* SW pte young bit */ #define _PAGE_YOUNG 0x004 /* SW pte young bit */
#define _PAGE_DIRTY 0x008 /* SW pte dirty bit */ #define _PAGE_DIRTY 0x008 /* SW pte dirty bit */
#define _PAGE_READ 0x010 /* SW pte read bit */ #define _PAGE_READ 0x010 /* SW pte read bit */
@ -240,31 +204,34 @@ static inline int is_module_addr(void *addr)
* table lock held. * table lock held.
* *
* The following table gives the different possible bit combinations for * The following table gives the different possible bit combinations for
* the pte hardware and software bits in the last 12 bits of a pte: * the pte hardware and software bits in the last 12 bits of a pte
* (. unassigned bit, x don't care, t swap type):
* *
* 842100000000 * 842100000000
* 000084210000 * 000084210000
* 000000008421 * 000000008421
* .IR...wrdytp * .IR.uswrdy.p
* empty .10...000000 * empty .10.00000000
* swap .10...xxxx10 * swap .11..ttttt.0
* file .11...xxxxx0 * prot-none, clean, old .11.xx0000.1
* prot-none, clean, old .11...000001 * prot-none, clean, young .11.xx0001.1
* prot-none, clean, young .11...000101 * prot-none, dirty, old .10.xx0010.1
* prot-none, dirty, old .10...001001 * prot-none, dirty, young .10.xx0011.1
* prot-none, dirty, young .10...001101 * read-only, clean, old .11.xx0100.1
* read-only, clean, old .11...010001 * read-only, clean, young .01.xx0101.1
* read-only, clean, young .01...010101 * read-only, dirty, old .11.xx0110.1
* read-only, dirty, old .11...011001 * read-only, dirty, young .01.xx0111.1
* read-only, dirty, young .01...011101 * read-write, clean, old .11.xx1100.1
* read-write, clean, old .11...110001 * read-write, clean, young .01.xx1101.1
* read-write, clean, young .01...110101 * read-write, dirty, old .10.xx1110.1
* read-write, dirty, old .10...111001 * read-write, dirty, young .00.xx1111.1
* read-write, dirty, young .00...111101 * HW-bits: R read-only, I invalid
* SW-bits: p present, y young, d dirty, r read, w write, s special,
* u unused, l large
* *
* pte_present is true for the bit pattern .xx...xxxxx1, (pte & 0x001) == 0x001 * pte_none is true for the bit pattern .10.00000000, pte == 0x400
* pte_none is true for the bit pattern .10...xxxx00, (pte & 0x603) == 0x400 * pte_swap is true for the bit pattern .11..ooooo.0, (pte & 0x201) == 0x200
* pte_swap is true for the bit pattern .10...xxxx10, (pte & 0x603) == 0x402 * pte_present is true for the bit pattern .xx.xxxxxx.1, (pte & 0x001) == 0x001
*/ */
/* Bits in the segment/region table address-space-control-element */ /* Bits in the segment/region table address-space-control-element */
@ -335,6 +302,8 @@ static inline int is_module_addr(void *addr)
* read-write, dirty, young 11..0...0...11 * read-write, dirty, young 11..0...0...11
* The segment table origin is used to distinguish empty (origin==0) from * The segment table origin is used to distinguish empty (origin==0) from
* read-write, old segment table entries (origin!=0) * read-write, old segment table entries (origin!=0)
* HW-bits: R read-only, I invalid
* SW-bits: y young, d dirty, r read, w write
*/ */
#define _SEGMENT_ENTRY_SPLIT_BIT 11 /* THP splitting bit number */ #define _SEGMENT_ENTRY_SPLIT_BIT 11 /* THP splitting bit number */
@ -423,6 +392,15 @@ static inline int mm_has_pgste(struct mm_struct *mm)
return 0; return 0;
} }
static inline int mm_alloc_pgste(struct mm_struct *mm)
{
#ifdef CONFIG_PGSTE
if (unlikely(mm->context.alloc_pgste))
return 1;
#endif
return 0;
}
/* /*
* In the case that a guest uses storage keys * In the case that a guest uses storage keys
* faults should no longer be backed by zero pages * faults should no longer be backed by zero pages
@ -582,10 +560,9 @@ static inline int pte_none(pte_t pte)
static inline int pte_swap(pte_t pte) static inline int pte_swap(pte_t pte)
{ {
/* Bit pattern: (pte & 0x603) == 0x402 */ /* Bit pattern: (pte & 0x201) == 0x200 */
return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT | return (pte_val(pte) & (_PAGE_PROTECT | _PAGE_PRESENT))
_PAGE_TYPE | _PAGE_PRESENT)) == _PAGE_PROTECT;
== (_PAGE_INVALID | _PAGE_TYPE);
} }
static inline int pte_special(pte_t pte) static inline int pte_special(pte_t pte)
@ -1586,51 +1563,51 @@ static inline int has_transparent_hugepage(void)
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
/* /*
* 31 bit swap entry format:
* A page-table entry has some bits we have to treat in a special way.
* Bits 0, 20 and bit 23 have to be zero, otherwise an specification
* exception will occur instead of a page translation exception. The
* specifiation exception has the bad habit not to store necessary
* information in the lowcore.
* Bits 21, 22, 30 and 31 are used to indicate the page type.
* A swap pte is indicated by bit pattern (pte & 0x603) == 0x402
* This leaves the bits 1-19 and bits 24-29 to store type and offset.
* We use the 5 bits from 25-29 for the type and the 20 bits from 1-19
* plus 24 for the offset.
* 0| offset |0110|o|type |00|
* 0 0000000001111111111 2222 2 22222 33
* 0 1234567890123456789 0123 4 56789 01
*
* 64 bit swap entry format: * 64 bit swap entry format:
* A page-table entry has some bits we have to treat in a special way. * A page-table entry has some bits we have to treat in a special way.
* Bits 52 and bit 55 have to be zero, otherwise an specification * Bits 52 and bit 55 have to be zero, otherwise an specification
* exception will occur instead of a page translation exception. The * exception will occur instead of a page translation exception. The
* specifiation exception has the bad habit not to store necessary * specifiation exception has the bad habit not to store necessary
* information in the lowcore. * information in the lowcore.
* Bits 53, 54, 62 and 63 are used to indicate the page type. * Bits 54 and 63 are used to indicate the page type.
* A swap pte is indicated by bit pattern (pte & 0x603) == 0x402 * A swap pte is indicated by bit pattern (pte & 0x201) == 0x200
* This leaves the bits 0-51 and bits 56-61 to store type and offset. * This leaves the bits 0-51 and bits 56-62 to store type and offset.
* We use the 5 bits from 57-61 for the type and the 53 bits from 0-51 * We use the 5 bits from 57-61 for the type and the 52 bits from 0-51
* plus 56 for the offset. * for the offset.
* | offset |0110|o|type |00| * | offset |01100|type |00|
* 0000000000111111111122222222223333333333444444444455 5555 5 55566 66 * |0000000000111111111122222222223333333333444444444455|55555|55566|66|
* 0123456789012345678901234567890123456789012345678901 2345 6 78901 23 * |0123456789012345678901234567890123456789012345678901|23456|78901|23|
*/ */
#define __SWP_OFFSET_MASK (~0UL >> 11) #define __SWP_OFFSET_MASK ((1UL << 52) - 1)
#define __SWP_OFFSET_SHIFT 12
#define __SWP_TYPE_MASK ((1UL << 5) - 1)
#define __SWP_TYPE_SHIFT 2
static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
{ {
pte_t pte; pte_t pte;
offset &= __SWP_OFFSET_MASK;
pte_val(pte) = _PAGE_INVALID | _PAGE_TYPE | ((type & 0x1f) << 2) | pte_val(pte) = _PAGE_INVALID | _PAGE_PROTECT;
((offset & 1UL) << 7) | ((offset & ~1UL) << 11); pte_val(pte) |= (offset & __SWP_OFFSET_MASK) << __SWP_OFFSET_SHIFT;
pte_val(pte) |= (type & __SWP_TYPE_MASK) << __SWP_TYPE_SHIFT;
return pte; return pte;
} }
#define __swp_type(entry) (((entry).val >> 2) & 0x1f) static inline unsigned long __swp_type(swp_entry_t entry)
#define __swp_offset(entry) (((entry).val >> 11) | (((entry).val >> 7) & 1)) {
#define __swp_entry(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) }) return (entry.val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK;
}
static inline unsigned long __swp_offset(swp_entry_t entry)
{
return (entry.val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK;
}
static inline swp_entry_t __swp_entry(unsigned long type, unsigned long offset)
{
return (swp_entry_t) { pte_val(mk_swap_pte(type, offset)) };
}
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val })

View File

@ -14,20 +14,23 @@ static inline pmd_t __pte_to_pmd(pte_t pte)
/* /*
* Convert encoding pte bits pmd bits * Convert encoding pte bits pmd bits
* .IR...wrdytp dy..R...I...wr * lIR.uswrdy.p dy..R...I...wr
* empty .10...000000 -> 00..0...1...00 * empty 010.000000.0 -> 00..0...1...00
* prot-none, clean, old .11...000001 -> 00..1...1...00 * prot-none, clean, old 111.000000.1 -> 00..1...1...00
* prot-none, clean, young .11...000101 -> 01..1...1...00 * prot-none, clean, young 111.000001.1 -> 01..1...1...00
* prot-none, dirty, old .10...001001 -> 10..1...1...00 * prot-none, dirty, old 111.000010.1 -> 10..1...1...00
* prot-none, dirty, young .10...001101 -> 11..1...1...00 * prot-none, dirty, young 111.000011.1 -> 11..1...1...00
* read-only, clean, old .11...010001 -> 00..1...1...01 * read-only, clean, old 111.000100.1 -> 00..1...1...01
* read-only, clean, young .01...010101 -> 01..1...0...01 * read-only, clean, young 101.000101.1 -> 01..1...0...01
* read-only, dirty, old .11...011001 -> 10..1...1...01 * read-only, dirty, old 111.000110.1 -> 10..1...1...01
* read-only, dirty, young .01...011101 -> 11..1...0...01 * read-only, dirty, young 101.000111.1 -> 11..1...0...01
* read-write, clean, old .11...110001 -> 00..0...1...11 * read-write, clean, old 111.001100.1 -> 00..1...1...11
* read-write, clean, young .01...110101 -> 01..0...0...11 * read-write, clean, young 101.001101.1 -> 01..1...0...11
* read-write, dirty, old .10...111001 -> 10..0...1...11 * read-write, dirty, old 110.001110.1 -> 10..0...1...11
* read-write, dirty, young .00...111101 -> 11..0...0...11 * read-write, dirty, young 100.001111.1 -> 11..0...0...11
* HW-bits: R read-only, I invalid
* SW-bits: p present, y young, d dirty, r read, w write, s special,
* u unused, l large
*/ */
if (pte_present(pte)) { if (pte_present(pte)) {
pmd_val(pmd) = pte_val(pte) & PAGE_MASK; pmd_val(pmd) = pte_val(pte) & PAGE_MASK;
@ -48,20 +51,23 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
/* /*
* Convert encoding pmd bits pte bits * Convert encoding pmd bits pte bits
* dy..R...I...wr .IR...wrdytp * dy..R...I...wr lIR.uswrdy.p
* empty 00..0...1...00 -> .10...001100 * empty 00..0...1...00 -> 010.000000.0
* prot-none, clean, old 00..0...1...00 -> .10...000001 * prot-none, clean, old 00..1...1...00 -> 111.000000.1
* prot-none, clean, young 01..0...1...00 -> .10...000101 * prot-none, clean, young 01..1...1...00 -> 111.000001.1
* prot-none, dirty, old 10..0...1...00 -> .10...001001 * prot-none, dirty, old 10..1...1...00 -> 111.000010.1
* prot-none, dirty, young 11..0...1...00 -> .10...001101 * prot-none, dirty, young 11..1...1...00 -> 111.000011.1
* read-only, clean, old 00..1...1...01 -> .11...010001 * read-only, clean, old 00..1...1...01 -> 111.000100.1
* read-only, clean, young 01..1...1...01 -> .11...010101 * read-only, clean, young 01..1...0...01 -> 101.000101.1
* read-only, dirty, old 10..1...1...01 -> .11...011001 * read-only, dirty, old 10..1...1...01 -> 111.000110.1
* read-only, dirty, young 11..1...1...01 -> .11...011101 * read-only, dirty, young 11..1...0...01 -> 101.000111.1
* read-write, clean, old 00..0...1...11 -> .10...110001 * read-write, clean, old 00..1...1...11 -> 111.001100.1
* read-write, clean, young 01..0...1...11 -> .10...110101 * read-write, clean, young 01..1...0...11 -> 101.001101.1
* read-write, dirty, old 10..0...1...11 -> .10...111001 * read-write, dirty, old 10..0...1...11 -> 110.001110.1
* read-write, dirty, young 11..0...1...11 -> .10...111101 * read-write, dirty, young 11..0...0...11 -> 100.001111.1
* HW-bits: R read-only, I invalid
* SW-bits: p present, y young, d dirty, r read, w write, s special,
* u unused, l large
*/ */
if (pmd_present(pmd)) { if (pmd_present(pmd)) {
pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE; pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE;
@ -70,8 +76,8 @@ static inline pte_t __pmd_to_pte(pmd_t pmd)
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4;
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5;
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT); pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT);
pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) >> 10;
pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10; pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) >> 10;
} else } else
pte_val(pte) = _PAGE_INVALID; pte_val(pte) = _PAGE_INVALID;
return pte; return pte;

View File

@ -18,6 +18,7 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/swapops.h> #include <linux/swapops.h>
#include <linux/sysctl.h>
#include <linux/ksm.h> #include <linux/ksm.h>
#include <linux/mman.h> #include <linux/mman.h>
@ -920,6 +921,40 @@ unsigned long get_guest_storage_key(struct mm_struct *mm, unsigned long addr)
} }
EXPORT_SYMBOL(get_guest_storage_key); EXPORT_SYMBOL(get_guest_storage_key);
static int page_table_allocate_pgste_min = 0;
static int page_table_allocate_pgste_max = 1;
int page_table_allocate_pgste = 0;
EXPORT_SYMBOL(page_table_allocate_pgste);
static struct ctl_table page_table_sysctl[] = {
{
.procname = "allocate_pgste",
.data = &page_table_allocate_pgste,
.maxlen = sizeof(int),
.mode = S_IRUGO | S_IWUSR,
.proc_handler = proc_dointvec,
.extra1 = &page_table_allocate_pgste_min,
.extra2 = &page_table_allocate_pgste_max,
},
{ }
};
static struct ctl_table page_table_sysctl_dir[] = {
{
.procname = "vm",
.maxlen = 0,
.mode = 0555,
.child = page_table_sysctl,
},
{ }
};
static int __init page_table_register_sysctl(void)
{
return register_sysctl_table(page_table_sysctl_dir) ? 0 : -ENOMEM;
}
__initcall(page_table_register_sysctl);
#else /* CONFIG_PGSTE */ #else /* CONFIG_PGSTE */
static inline int page_table_with_pgste(struct page *page) static inline int page_table_with_pgste(struct page *page)
@ -963,7 +998,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
struct page *uninitialized_var(page); struct page *uninitialized_var(page);
unsigned int mask, bit; unsigned int mask, bit;
if (mm_has_pgste(mm)) if (mm_alloc_pgste(mm))
return page_table_alloc_pgste(mm); return page_table_alloc_pgste(mm);
/* Allocate fragments of a 4K page as 1K/2K page table */ /* Allocate fragments of a 4K page as 1K/2K page table */
spin_lock_bh(&mm->context.list_lock); spin_lock_bh(&mm->context.list_lock);
@ -1165,116 +1200,25 @@ static inline void thp_split_mm(struct mm_struct *mm)
} }
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
struct mm_struct *mm, pud_t *pud,
unsigned long addr, unsigned long end)
{
unsigned long next, *table, *new;
struct page *page;
spinlock_t *ptl;
pmd_t *pmd;
pmd = pmd_offset(pud, addr);
do {
next = pmd_addr_end(addr, end);
again:
if (pmd_none_or_clear_bad(pmd))
continue;
table = (unsigned long *) pmd_deref(*pmd);
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
if (page_table_with_pgste(page))
continue;
/* Allocate new page table with pgstes */
new = page_table_alloc_pgste(mm);
if (!new)
return -ENOMEM;
ptl = pmd_lock(mm, pmd);
if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
/* Nuke pmd entry pointing to the "short" page table */
pmdp_flush_lazy(mm, addr, pmd);
pmd_clear(pmd);
/* Copy ptes from old table to new table */
memcpy(new, table, PAGE_SIZE/2);
clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
/* Establish new table */
pmd_populate(mm, pmd, (pte_t *) new);
/* Free old table with rcu, there might be a walker! */
page_table_free_rcu(tlb, table, addr);
new = NULL;
}
spin_unlock(ptl);
if (new) {
page_table_free_pgste(new);
goto again;
}
} while (pmd++, addr = next, addr != end);
return addr;
}
static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
struct mm_struct *mm, pgd_t *pgd,
unsigned long addr, unsigned long end)
{
unsigned long next;
pud_t *pud;
pud = pud_offset(pgd, addr);
do {
next = pud_addr_end(addr, end);
if (pud_none_or_clear_bad(pud))
continue;
next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
if (unlikely(IS_ERR_VALUE(next)))
return next;
} while (pud++, addr = next, addr != end);
return addr;
}
static unsigned long page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
unsigned long addr, unsigned long end)
{
unsigned long next;
pgd_t *pgd;
pgd = pgd_offset(mm, addr);
do {
next = pgd_addr_end(addr, end);
if (pgd_none_or_clear_bad(pgd))
continue;
next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
if (unlikely(IS_ERR_VALUE(next)))
return next;
} while (pgd++, addr = next, addr != end);
return 0;
}
/* /*
* switch on pgstes for its userspace process (for kvm) * switch on pgstes for its userspace process (for kvm)
*/ */
int s390_enable_sie(void) int s390_enable_sie(void)
{ {
struct task_struct *tsk = current; struct mm_struct *mm = current->mm;
struct mm_struct *mm = tsk->mm;
struct mmu_gather tlb;
/* Do we have pgstes? if yes, we are done */ /* Do we have pgstes? if yes, we are done */
if (mm_has_pgste(tsk->mm)) if (mm_has_pgste(mm))
return 0; return 0;
/* Fail if the page tables are 2K */
if (!mm_alloc_pgste(mm))
return -EINVAL;
down_write(&mm->mmap_sem); down_write(&mm->mmap_sem);
mm->context.has_pgste = 1;
/* split thp mappings and disable thp for future mappings */ /* split thp mappings and disable thp for future mappings */
thp_split_mm(mm); thp_split_mm(mm);
/* Reallocate the page tables with pgstes */
tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE);
if (!page_table_realloc(&tlb, mm, 0, TASK_SIZE))
mm->context.has_pgste = 1;
tlb_finish_mmu(&tlb, 0, TASK_SIZE);
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
return mm->context.has_pgste ? 0 : -ENOMEM; return 0;
} }
EXPORT_SYMBOL_GPL(s390_enable_sie); EXPORT_SYMBOL_GPL(s390_enable_sie);

View File

@ -774,7 +774,7 @@ static void __init zone_sizes_init(void)
* though, there'll be no lowmem, so we just alloc_bootmem * though, there'll be no lowmem, so we just alloc_bootmem
* the memmap. There will be no percpu memory either. * the memmap. There will be no percpu memory either.
*/ */
if (i != 0 && cpumask_test_cpu(i, &isolnodes)) { if (i != 0 && node_isset(i, isolnodes)) {
node_memmap_pfn[i] = node_memmap_pfn[i] =
alloc_bootmem_pfn(0, memmap_size, 0); alloc_bootmem_pfn(0, memmap_size, 0);
BUG_ON(node_percpu[i] != 0); BUG_ON(node_percpu[i] != 0);

View File

@ -1109,6 +1109,8 @@ struct boot_params *make_boot_params(struct efi_config *c)
if (!cmdline_ptr) if (!cmdline_ptr)
goto fail; goto fail;
hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
/* Fill in upper bits of command line address, NOP on 32 bit */
boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
hdr->ramdisk_image = 0; hdr->ramdisk_image = 0;
hdr->ramdisk_size = 0; hdr->ramdisk_size = 0;

View File

@ -50,7 +50,7 @@ extern const struct hypervisor_x86 *x86_hyper;
/* Recognized hypervisors */ /* Recognized hypervisors */
extern const struct hypervisor_x86 x86_hyper_vmware; extern const struct hypervisor_x86 x86_hyper_vmware;
extern const struct hypervisor_x86 x86_hyper_ms_hyperv; extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
extern const struct hypervisor_x86 x86_hyper_xen_hvm; extern const struct hypervisor_x86 x86_hyper_xen;
extern const struct hypervisor_x86 x86_hyper_kvm; extern const struct hypervisor_x86 x86_hyper_kvm;
extern void init_hypervisor(struct cpuinfo_x86 *c); extern void init_hypervisor(struct cpuinfo_x86 *c);

View File

@ -95,7 +95,6 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
struct pvclock_vsyscall_time_info { struct pvclock_vsyscall_time_info {
struct pvclock_vcpu_time_info pvti; struct pvclock_vcpu_time_info pvti;
u32 migrate_count;
} __attribute__((__aligned__(SMP_CACHE_BYTES))); } __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)

View File

@ -169,7 +169,7 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock)
struct __raw_tickets tmp = READ_ONCE(lock->tickets); struct __raw_tickets tmp = READ_ONCE(lock->tickets);
tmp.head &= ~TICKET_SLOWPATH_FLAG; tmp.head &= ~TICKET_SLOWPATH_FLAG;
return (tmp.tail - tmp.head) > TICKET_LOCK_INC; return (__ticket_t)(tmp.tail - tmp.head) > TICKET_LOCK_INC;
} }
#define arch_spin_is_contended arch_spin_is_contended #define arch_spin_is_contended arch_spin_is_contended

View File

@ -269,4 +269,9 @@ static inline bool xen_arch_need_swiotlb(struct device *dev,
return false; return false;
} }
static inline unsigned long xen_get_swiotlb_free_pages(unsigned int order)
{
return __get_free_pages(__GFP_NOWARN, order);
}
#endif /* _ASM_X86_XEN_PAGE_H */ #endif /* _ASM_X86_XEN_PAGE_H */

View File

@ -27,8 +27,8 @@
static const __initconst struct hypervisor_x86 * const hypervisors[] = static const __initconst struct hypervisor_x86 * const hypervisors[] =
{ {
#ifdef CONFIG_XEN_PVHVM #ifdef CONFIG_XEN
&x86_hyper_xen_hvm, &x86_hyper_xen,
#endif #endif
&x86_hyper_vmware, &x86_hyper_vmware,
&x86_hyper_ms_hyperv, &x86_hyper_ms_hyperv,

View File

@ -2533,34 +2533,6 @@ ssize_t intel_event_sysfs_show(char *page, u64 config)
return x86_event_sysfs_show(page, config, event); return x86_event_sysfs_show(page, config, event);
} }
static __initconst const struct x86_pmu core_pmu = {
.name = "core",
.handle_irq = x86_pmu_handle_irq,
.disable_all = x86_pmu_disable_all,
.enable_all = core_pmu_enable_all,
.enable = core_pmu_enable_event,
.disable = x86_pmu_disable_event,
.hw_config = x86_pmu_hw_config,
.schedule_events = x86_schedule_events,
.eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
.perfctr = MSR_ARCH_PERFMON_PERFCTR0,
.event_map = intel_pmu_event_map,
.max_events = ARRAY_SIZE(intel_perfmon_event_map),
.apic = 1,
/*
* Intel PMCs cannot be accessed sanely above 32 bit width,
* so we install an artificial 1<<31 period regardless of
* the generic event period:
*/
.max_period = (1ULL << 31) - 1,
.get_event_constraints = intel_get_event_constraints,
.put_event_constraints = intel_put_event_constraints,
.event_constraints = intel_core_event_constraints,
.guest_get_msrs = core_guest_get_msrs,
.format_attrs = intel_arch_formats_attr,
.events_sysfs_show = intel_event_sysfs_show,
};
struct intel_shared_regs *allocate_shared_regs(int cpu) struct intel_shared_regs *allocate_shared_regs(int cpu)
{ {
struct intel_shared_regs *regs; struct intel_shared_regs *regs;
@ -2743,6 +2715,44 @@ static struct attribute *intel_arch3_formats_attr[] = {
NULL, NULL,
}; };
static __initconst const struct x86_pmu core_pmu = {
.name = "core",
.handle_irq = x86_pmu_handle_irq,
.disable_all = x86_pmu_disable_all,
.enable_all = core_pmu_enable_all,
.enable = core_pmu_enable_event,
.disable = x86_pmu_disable_event,
.hw_config = x86_pmu_hw_config,
.schedule_events = x86_schedule_events,
.eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
.perfctr = MSR_ARCH_PERFMON_PERFCTR0,
.event_map = intel_pmu_event_map,
.max_events = ARRAY_SIZE(intel_perfmon_event_map),
.apic = 1,
/*
* Intel PMCs cannot be accessed sanely above 32-bit width,
* so we install an artificial 1<<31 period regardless of
* the generic event period:
*/
.max_period = (1ULL<<31) - 1,
.get_event_constraints = intel_get_event_constraints,
.put_event_constraints = intel_put_event_constraints,
.event_constraints = intel_core_event_constraints,
.guest_get_msrs = core_guest_get_msrs,
.format_attrs = intel_arch_formats_attr,
.events_sysfs_show = intel_event_sysfs_show,
/*
* Virtual (or funny metal) CPU can define x86_pmu.extra_regs
* together with PMU version 1 and thus be using core_pmu with
* shared_regs. We need following callbacks here to allocate
* it properly.
*/
.cpu_prepare = intel_pmu_cpu_prepare,
.cpu_starting = intel_pmu_cpu_starting,
.cpu_dying = intel_pmu_cpu_dying,
};
static __initconst const struct x86_pmu intel_pmu = { static __initconst const struct x86_pmu intel_pmu = {
.name = "Intel", .name = "Intel",
.handle_irq = intel_pmu_handle_irq, .handle_irq = intel_pmu_handle_irq,

View File

@ -1,6 +1,13 @@
/* Nehalem/SandBridge/Haswell uncore support */ /* Nehalem/SandBridge/Haswell uncore support */
#include "perf_event_intel_uncore.h" #include "perf_event_intel_uncore.h"
/* Uncore IMC PCI IDs */
#define PCI_DEVICE_ID_INTEL_SNB_IMC 0x0100
#define PCI_DEVICE_ID_INTEL_IVB_IMC 0x0154
#define PCI_DEVICE_ID_INTEL_IVB_E3_IMC 0x0150
#define PCI_DEVICE_ID_INTEL_HSW_IMC 0x0c00
#define PCI_DEVICE_ID_INTEL_HSW_U_IMC 0x0a04
/* SNB event control */ /* SNB event control */
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff #define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
#define SNB_UNC_CTL_UMASK_MASK 0x0000ff00 #define SNB_UNC_CTL_UMASK_MASK 0x0000ff00
@ -472,6 +479,10 @@ static const struct pci_device_id hsw_uncore_pci_ids[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC), PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0), .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
}, },
{ /* IMC */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_U_IMC),
.driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
},
{ /* end: all zeroes */ }, { /* end: all zeroes */ },
}; };
@ -502,6 +513,7 @@ static const struct imc_uncore_pci_dev desktop_imc_pci_ids[] = {
IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver), /* 3rd Gen Core processor */ IMC_DEV(IVB_IMC, &ivb_uncore_pci_driver), /* 3rd Gen Core processor */
IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */ IMC_DEV(IVB_E3_IMC, &ivb_uncore_pci_driver), /* Xeon E3-1200 v2/3rd Gen Core processor */
IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core Processor */ IMC_DEV(HSW_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core Processor */
IMC_DEV(HSW_U_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core ULT Mobile Processor */
{ /* end marker */ } { /* end marker */ }
}; };

View File

@ -57,7 +57,7 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = {
.io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 }, .io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 },
#endif #endif
}; };
EXPORT_PER_CPU_SYMBOL_GPL(cpu_tss); EXPORT_PER_CPU_SYMBOL(cpu_tss);
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
static DEFINE_PER_CPU(unsigned char, is_idle); static DEFINE_PER_CPU(unsigned char, is_idle);
@ -156,11 +156,13 @@ void flush_thread(void)
/* FPU state will be reallocated lazily at the first use. */ /* FPU state will be reallocated lazily at the first use. */
drop_fpu(tsk); drop_fpu(tsk);
free_thread_xstate(tsk); free_thread_xstate(tsk);
} else if (!used_math()) { } else {
/* kthread execs. TODO: cleanup this horror. */ if (!tsk_used_math(tsk)) {
if (WARN_ON(init_fpu(tsk))) /* kthread execs. TODO: cleanup this horror. */
force_sig(SIGKILL, tsk); if (WARN_ON(init_fpu(tsk)))
user_fpu_begin(); force_sig(SIGKILL, tsk);
user_fpu_begin();
}
restore_init_xstate(); restore_init_xstate();
} }
} }

View File

@ -141,46 +141,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
set_normalized_timespec(ts, now.tv_sec, now.tv_nsec); set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
} }
static struct pvclock_vsyscall_time_info *pvclock_vdso_info;
static struct pvclock_vsyscall_time_info *
pvclock_get_vsyscall_user_time_info(int cpu)
{
if (!pvclock_vdso_info) {
BUG();
return NULL;
}
return &pvclock_vdso_info[cpu];
}
struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu)
{
return &pvclock_get_vsyscall_user_time_info(cpu)->pvti;
}
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
static int pvclock_task_migrate(struct notifier_block *nb, unsigned long l,
void *v)
{
struct task_migration_notifier *mn = v;
struct pvclock_vsyscall_time_info *pvti;
pvti = pvclock_get_vsyscall_user_time_info(mn->from_cpu);
/* this is NULL when pvclock vsyscall is not initialized */
if (unlikely(pvti == NULL))
return NOTIFY_DONE;
pvti->migrate_count++;
return NOTIFY_DONE;
}
static struct notifier_block pvclock_migrate = {
.notifier_call = pvclock_task_migrate,
};
/* /*
* Initialize the generic pvclock vsyscall state. This will allocate * Initialize the generic pvclock vsyscall state. This will allocate
* a/some page(s) for the per-vcpu pvclock information, set up a * a/some page(s) for the per-vcpu pvclock information, set up a
@ -194,17 +155,12 @@ int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE); WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE);
pvclock_vdso_info = i;
for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) { for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
__set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx, __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
__pa(i) + (idx*PAGE_SIZE), __pa(i) + (idx*PAGE_SIZE),
PAGE_KERNEL_VVAR); PAGE_KERNEL_VVAR);
} }
register_task_migration_notifier(&pvclock_migrate);
return 0; return 0;
} }
#endif #endif

View File

@ -1669,12 +1669,28 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
&guest_hv_clock, sizeof(guest_hv_clock)))) &guest_hv_clock, sizeof(guest_hv_clock))))
return 0; return 0;
/* /* This VCPU is paused, but it's legal for a guest to read another
* The interface expects us to write an even number signaling that the * VCPU's kvmclock, so we really have to follow the specification where
* update is finished. Since the guest won't see the intermediate * it says that version is odd if data is being modified, and even after
* state, we just increase by 2 at the end. * it is consistent.
*
* Version field updates must be kept separate. This is because
* kvm_write_guest_cached might use a "rep movs" instruction, and
* writes within a string instruction are weakly ordered. So there
* are three writes overall.
*
* As a small optimization, only write the version field in the first
* and third write. The vcpu->pv_time cache is still valid, because the
* version field is the first in the struct.
*/ */
vcpu->hv_clock.version = guest_hv_clock.version + 2; BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0);
vcpu->hv_clock.version = guest_hv_clock.version + 1;
kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
&vcpu->hv_clock,
sizeof(vcpu->hv_clock.version));
smp_wmb();
/* retain PVCLOCK_GUEST_STOPPED if set in guest copy */ /* retain PVCLOCK_GUEST_STOPPED if set in guest copy */
pvclock_flags = (guest_hv_clock.flags & PVCLOCK_GUEST_STOPPED); pvclock_flags = (guest_hv_clock.flags & PVCLOCK_GUEST_STOPPED);
@ -1695,6 +1711,13 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
kvm_write_guest_cached(v->kvm, &vcpu->pv_time, kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
&vcpu->hv_clock, &vcpu->hv_clock,
sizeof(vcpu->hv_clock)); sizeof(vcpu->hv_clock));
smp_wmb();
vcpu->hv_clock.version++;
kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
&vcpu->hv_clock,
sizeof(vcpu->hv_clock.version));
return 0; return 0;
} }

View File

@ -351,18 +351,20 @@ int arch_ioremap_pmd_supported(void)
*/ */
void *xlate_dev_mem_ptr(phys_addr_t phys) void *xlate_dev_mem_ptr(phys_addr_t phys)
{ {
void *addr; unsigned long start = phys & PAGE_MASK;
unsigned long start = phys & PAGE_MASK; unsigned long offset = phys & ~PAGE_MASK;
unsigned long vaddr;
/* If page is RAM, we can use __va. Otherwise ioremap and unmap. */ /* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
if (page_is_ram(start >> PAGE_SHIFT)) if (page_is_ram(start >> PAGE_SHIFT))
return __va(phys); return __va(phys);
addr = (void __force *)ioremap_cache(start, PAGE_SIZE); vaddr = (unsigned long)ioremap_cache(start, PAGE_SIZE);
if (addr) /* Only add the offset on success and return NULL if the ioremap() failed: */
addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK)); if (vaddr)
vaddr += offset;
return addr; return (void *)vaddr;
} }
void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)

View File

@ -325,6 +325,26 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
kfree(info); kfree(info);
} }
/*
* An IO port or MMIO resource assigned to a PCI host bridge may be
* consumed by the host bridge itself or available to its child
* bus/devices. The ACPI specification defines a bit (Producer/Consumer)
* to tell whether the resource is consumed by the host bridge itself,
* but firmware hasn't used that bit consistently, so we can't rely on it.
*
* On x86 and IA64 platforms, all IO port and MMIO resources are assumed
* to be available to child bus/devices except one special case:
* IO port [0xCF8-0xCFF] is consumed by the host bridge itself
* to access PCI configuration space.
*
* So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF].
*/
static bool resource_is_pcicfg_ioport(struct resource *res)
{
return (res->flags & IORESOURCE_IO) &&
res->start == 0xCF8 && res->end == 0xCFF;
}
static void probe_pci_root_info(struct pci_root_info *info, static void probe_pci_root_info(struct pci_root_info *info,
struct acpi_device *device, struct acpi_device *device,
int busnum, int domain, int busnum, int domain,
@ -346,8 +366,8 @@ static void probe_pci_root_info(struct pci_root_info *info,
"no IO and memory resources present in _CRS\n"); "no IO and memory resources present in _CRS\n");
else else
resource_list_for_each_entry_safe(entry, tmp, list) { resource_list_for_each_entry_safe(entry, tmp, list) {
if ((entry->res->flags & IORESOURCE_WINDOW) == 0 || if ((entry->res->flags & IORESOURCE_DISABLED) ||
(entry->res->flags & IORESOURCE_DISABLED)) resource_is_pcicfg_ioport(entry->res))
resource_list_destroy_entry(entry); resource_list_destroy_entry(entry);
else else
entry->res->name = info->name; entry->res->name = info->name;

Some files were not shown because too many files have changed in this diff Show More