Merge branch 'for-linus' into for-next
Merge back the latest HD-audio stuff for further development.
This commit is contained in:
commit
984a854705
7
CREDITS
7
CREDITS
@ -3709,6 +3709,13 @@ N: Dirk Verworner
|
||||
D: Co-author of German book ``Linux-Kernel-Programmierung''
|
||||
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
|
||||
E: riku.voipio@iki.fi
|
||||
D: Author of PCA9532 LED and Fintek f75375s hwmon driver
|
||||
|
@ -505,7 +505,10 @@ at module load time (for a module) with:
|
||||
|
||||
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.
|
||||
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:
|
||||
IPMI messages: 1, driver state: 2, timing: 4, I2C probe: 8
|
||||
|
@ -253,7 +253,7 @@ input driver:
|
||||
GPIO support
|
||||
~~~~~~~~~~~~
|
||||
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
|
||||
Specific Data) which made it possible to name the GPIOs among other things.
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
_DSD Device Properties Related to GPIO
|
||||
--------------------------------------
|
||||
|
||||
With the release of ACPI 5.1 and the _DSD configuration objecte names
|
||||
can finally be given to GPIOs (and other things as well) returned by
|
||||
_CRS. Previously, we were only able to use an integer index to find
|
||||
With the release of ACPI 5.1, the _DSD configuration object finally
|
||||
allows names to be given to GPIOs (and other things as well) returned
|
||||
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 _CRS output ordering, for example).
|
||||
|
||||
|
@ -6,6 +6,7 @@ provided by Arteris.
|
||||
Required properties:
|
||||
- compatible : Should be "ti,omap3-l3-smx" for OMAP3 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,am4372-l3-noc" for AM43 family
|
||||
- reg: Contains L3 register address range for each noc domain.
|
||||
|
@ -38,7 +38,7 @@ dma_apbx: dma-apbx@80024000 {
|
||||
80 81 68 69
|
||||
70 71 72 73
|
||||
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",
|
||||
"auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
|
||||
"auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
|
||||
|
30
Documentation/devicetree/bindings/rtc/abracon,abx80x.txt
Normal file
30
Documentation/devicetree/bindings/rtc/abracon,abx80x.txt
Normal 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.
|
@ -9,7 +9,9 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds
|
||||
bugs.
|
||||
|
||||
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
|
||||
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
|
||||
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.
|
||||
latter is 1.1 - 2 times faster. Inline instrumentation requires a gcc version
|
||||
of 5.0 or later.
|
||||
|
||||
Currently KASAN works only with the SLUB memory allocator.
|
||||
For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
|
||||
|
@ -3787,6 +3787,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
READ_CAPACITY_16 command);
|
||||
f = NO_REPORT_OPCODES (don't use report opcodes
|
||||
command, uas only);
|
||||
g = MAX_SECTORS_240 (don't transfer more than
|
||||
240 sectors at a time, uas only);
|
||||
h = CAPACITY_HEURISTICS (decrease the
|
||||
reported device capacity by one
|
||||
sector if the number is odd);
|
||||
|
@ -119,9 +119,9 @@ Most notably, in the x509.genkey file, the req_distinguished_name section
|
||||
should be altered from the default:
|
||||
|
||||
[ req_distinguished_name ]
|
||||
O = Magrathea
|
||||
CN = Glacier signing key
|
||||
emailAddress = slartibartfast@magrathea.h2g2
|
||||
#O = Unspecified company
|
||||
CN = Build time autogenerated kernel key
|
||||
#emailAddress = unspecified.user@unspecified.company
|
||||
|
||||
The generated RSA key size can also be set with:
|
||||
|
||||
|
@ -18,3 +18,12 @@ platform_labels - INTEGER
|
||||
|
||||
Possible values: 0 - 1048575
|
||||
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
|
||||
|
@ -282,7 +282,7 @@ following is true:
|
||||
|
||||
- The current CPU's queue head counter >= the recorded tail counter
|
||||
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
|
||||
|
||||
After this check, the packet is sent to the (possibly updated) current
|
||||
|
@ -74,23 +74,22 @@ Causes of transaction aborts
|
||||
Syscalls
|
||||
========
|
||||
|
||||
Syscalls made from within an active transaction will not be performed and the
|
||||
transaction will be doomed by the kernel with the failure code TM_CAUSE_SYSCALL
|
||||
| TM_CAUSE_PERSISTENT.
|
||||
Performing syscalls from within transaction is not recommended, and can lead
|
||||
to unpredictable results.
|
||||
|
||||
Syscalls made from within a suspended transaction are performed as normal and
|
||||
the transaction is not explicitly doomed by the kernel. However, what the
|
||||
kernel does to perform the syscall may result in the transaction being doomed
|
||||
by the hardware. The syscall is performed in suspended mode so any side
|
||||
effects will be persistent, independent of transaction success or failure. No
|
||||
guarantees are provided by the kernel about which syscalls will affect
|
||||
transaction success.
|
||||
Syscalls do not by design abort transactions, but beware: The kernel code will
|
||||
not be running in transactional state. The effect of syscalls will always
|
||||
remain visible, but depending on the call they may abort your transaction as a
|
||||
side-effect, read soon-to-be-aborted transactional data that should not remain
|
||||
invisible, etc. If you constantly retry a transaction that constantly aborts
|
||||
itself by calling a syscall, you'll have a livelock & make no progress.
|
||||
|
||||
Care must be taken when relying on syscalls to abort during active transactions
|
||||
if the calls are made via a library. Libraries may cache values (which may
|
||||
give the appearance of success) or perform operations that cause transaction
|
||||
failure before entering the kernel (which may produce different failure codes).
|
||||
Examples are glibc's getpid() and lazy symbol resolution.
|
||||
Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write()
|
||||
from, say, printf() should be OK as long as the kernel does not access any
|
||||
memory that was accessed transactionally.
|
||||
|
||||
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
|
||||
@ -177,7 +176,8 @@ kernel aborted a transaction:
|
||||
TM_CAUSE_RESCHED Thread was rescheduled.
|
||||
TM_CAUSE_TLBI Software TLB invalid.
|
||||
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_MISC Currently unused.
|
||||
TM_CAUSE_ALIGNMENT Alignment fault.
|
||||
|
34
MAINTAINERS
34
MAINTAINERS
@ -892,11 +892,10 @@ S: Maintained
|
||||
F: arch/arm/mach-alpine/
|
||||
|
||||
ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
|
||||
M: Andrew Victor <linux@maxim.org.za>
|
||||
M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
W: http://maxim.org.za/at91_26.html
|
||||
W: http://www.linux4sam.org
|
||||
S: Supported
|
||||
F: arch/arm/mach-at91/
|
||||
@ -990,6 +989,12 @@ F: drivers/clocksource/timer-prima2.c
|
||||
F: drivers/clocksource/timer-atlas7.c
|
||||
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
|
||||
M: Russell King <linux@arm.linux.org.uk>
|
||||
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>
|
||||
S: Maintained
|
||||
F: arch/arm/mach-socfpga/
|
||||
F: arch/arm/boot/dts/socfpga*
|
||||
F: arch/arm/configs/socfpga_defconfig
|
||||
W: http://www.rocketboards.org
|
||||
T: git://git.rocketboards.org/linux-socfpga.git
|
||||
T: git://git.rocketboards.org/linux-socfpga-next.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
|
||||
|
||||
ARM/SOCFPGA CLOCK FRAMEWORK SUPPORT
|
||||
M: Dinh Nguyen <dinguyen@opensource.altera.com>
|
||||
@ -2116,8 +2122,9 @@ S: Supported
|
||||
F: drivers/net/ethernet/broadcom/bnx2x/
|
||||
|
||||
BROADCOM BCM281XX/BCM11XXX/BCM216XX ARM ARCHITECTURE
|
||||
M: Christian Daudt <bcm@fixthebug.org>
|
||||
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
|
||||
T: git git://github.com/broadcom/mach-bcm
|
||||
S: Maintained
|
||||
@ -2168,7 +2175,6 @@ S: Maintained
|
||||
F: drivers/usb/gadget/udc/bcm63xx_udc.*
|
||||
|
||||
BROADCOM BCM7XXX ARM ARCHITECTURE
|
||||
M: Marc Carino <marc.ceeeee@gmail.com>
|
||||
M: Brian Norris <computersforpeace@gmail.com>
|
||||
M: Gregory Fong <gregory.0xf0@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: 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
|
||||
M: Alexey Klimov <klimov.linux@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -5035,17 +5048,19 @@ S: Orphan
|
||||
F: drivers/video/fbdev/imsttfb.c
|
||||
|
||||
INFINIBAND SUBSYSTEM
|
||||
M: Roland Dreier <roland@kernel.org>
|
||||
M: Doug Ledford <dledford@redhat.com>
|
||||
M: Sean Hefty <sean.hefty@intel.com>
|
||||
M: Hal Rosenstock <hal.rosenstock@gmail.com>
|
||||
L: linux-rdma@vger.kernel.org
|
||||
W: http://www.openfabrics.org/
|
||||
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
|
||||
F: Documentation/infiniband/
|
||||
F: drivers/infiniband/
|
||||
F: include/uapi/linux/if_infiniband.h
|
||||
F: include/uapi/rdma/
|
||||
F: include/rdma/
|
||||
|
||||
INOTIFY
|
||||
M: John McCutchan <john@johnmccutchan.com>
|
||||
@ -5798,6 +5813,7 @@ F: drivers/scsi/53c700*
|
||||
LED SUBSYSTEM
|
||||
M: Bryan Wu <cooloney@gmail.com>
|
||||
M: Richard Purdie <rpurdie@rpsys.net>
|
||||
M: Jacek Anaszewski <j.anaszewski@samsung.com>
|
||||
L: linux-leds@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git
|
||||
S: Maintained
|
||||
@ -10523,7 +10539,6 @@ F: include/linux/virtio_console.h
|
||||
F: include/uapi/linux/virtio_console.h
|
||||
|
||||
VIRTIO CORE, NET AND BLOCK DRIVERS
|
||||
M: Rusty Russell <rusty@rustcorp.com.au>
|
||||
M: "Michael S. Tsirkin" <mst@redhat.com>
|
||||
L: virtualization@lists.linux-foundation.org
|
||||
S: Maintained
|
||||
@ -11031,6 +11046,7 @@ F: drivers/media/pci/zoran/
|
||||
ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
|
||||
M: Minchan Kim <minchan@kernel.org>
|
||||
M: Nitin Gupta <ngupta@vflare.org>
|
||||
R: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/block/zram/
|
||||
|
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc1
|
||||
EXTRAVERSION = -rc3
|
||||
NAME = Hurr durr I'ma sheep
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -49,7 +49,7 @@
|
||||
pinctrl-0 = <&matrix_keypad_pins>;
|
||||
|
||||
debounce-delay-ms = <5>;
|
||||
col-scan-delay-us = <1500>;
|
||||
col-scan-delay-us = <5>;
|
||||
|
||||
row-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH /* Bank5, pin5 */
|
||||
&gpio5 6 GPIO_ACTIVE_HIGH>; /* Bank5, pin6 */
|
||||
@ -473,7 +473,7 @@
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <31 0>;
|
||||
|
||||
wake-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
|
||||
|
||||
touchscreen-size-x = <480>;
|
||||
touchscreen-size-y = <272>;
|
||||
|
@ -18,6 +18,7 @@
|
||||
aliases {
|
||||
rtc0 = &mcp_rtc;
|
||||
rtc1 = &tps659038_rtc;
|
||||
rtc2 = &rtc;
|
||||
};
|
||||
|
||||
memory {
|
||||
@ -83,7 +84,7 @@
|
||||
gpio_fan: gpio_fan {
|
||||
/* Based on 5v 500mA AFB02505HHB */
|
||||
compatible = "gpio-fan";
|
||||
gpios = <&tps659038_gpio 1 GPIO_ACTIVE_HIGH>;
|
||||
gpios = <&tps659038_gpio 2 GPIO_ACTIVE_HIGH>;
|
||||
gpio-fan,speed-map = <0 0>,
|
||||
<13000 1>;
|
||||
#cooling-cells = <2>;
|
||||
@ -130,8 +131,8 @@
|
||||
|
||||
uart3_pins_default: uart3_pins_default {
|
||||
pinctrl-single,pins = <
|
||||
0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd.rxd */
|
||||
0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd.txd */
|
||||
0x3f8 (PIN_INPUT_SLEW | MUX_MODE2) /* uart2_ctsn.uart3_rxd */
|
||||
0x3fc (PIN_INPUT_SLEW | MUX_MODE1) /* uart2_rtsn.uart3_txd */
|
||||
>;
|
||||
};
|
||||
|
||||
@ -455,7 +456,7 @@
|
||||
mcp_rtc: rtc@6f {
|
||||
compatible = "microchip,mcp7941x";
|
||||
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-0 = <&mcp79410_pins_default>;
|
||||
@ -478,7 +479,7 @@
|
||||
&uart3 {
|
||||
status = "okay";
|
||||
interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<&dra7_pmx_core 0x248>;
|
||||
<&dra7_pmx_core 0x3f8>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart3_pins_default>;
|
||||
|
@ -105,6 +105,10 @@
|
||||
};
|
||||
|
||||
internal-regs {
|
||||
rtc@10300 {
|
||||
/* No crystal connected to the internal RTC */
|
||||
status = "disabled";
|
||||
};
|
||||
serial@12000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
@ -911,7 +911,7 @@
|
||||
ti,clock-cycles = <16>;
|
||||
|
||||
reg = <0x4ae07ddc 0x4>, <0x4ae07de0 0x4>,
|
||||
<0x4ae06014 0x4>, <0x4a003b20 0x8>,
|
||||
<0x4ae06014 0x4>, <0x4a003b20 0xc>,
|
||||
<0x4ae0c158 0x4>;
|
||||
reg-names = "setup-address", "control-address",
|
||||
"int-address", "efuse-address",
|
||||
@ -944,7 +944,7 @@
|
||||
ti,clock-cycles = <16>;
|
||||
|
||||
reg = <0x4ae07e34 0x4>, <0x4ae07e24 0x4>,
|
||||
<0x4ae06010 0x4>, <0x4a0025cc 0x8>,
|
||||
<0x4ae06010 0x4>, <0x4a0025cc 0xc>,
|
||||
<0x4a002470 0x4>;
|
||||
reg-names = "setup-address", "control-address",
|
||||
"int-address", "efuse-address",
|
||||
@ -977,7 +977,7 @@
|
||||
ti,clock-cycles = <16>;
|
||||
|
||||
reg = <0x4ae07e30 0x4>, <0x4ae07e20 0x4>,
|
||||
<0x4ae06010 0x4>, <0x4a0025e0 0x8>,
|
||||
<0x4ae06010 0x4>, <0x4a0025e0 0xc>,
|
||||
<0x4a00246c 0x4>;
|
||||
reg-names = "setup-address", "control-address",
|
||||
"int-address", "efuse-address",
|
||||
@ -1010,7 +1010,7 @@
|
||||
ti,clock-cycles = <16>;
|
||||
|
||||
reg = <0x4ae07de4 0x4>, <0x4ae07de8 0x4>,
|
||||
<0x4ae06010 0x4>, <0x4a003b08 0x8>,
|
||||
<0x4ae06010 0x4>, <0x4a003b08 0xc>,
|
||||
<0x4ae0c154 0x4>;
|
||||
reg-names = "setup-address", "control-address",
|
||||
"int-address", "efuse-address",
|
||||
@ -1203,7 +1203,7 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
rtc@48838000 {
|
||||
rtc: rtc@48838000 {
|
||||
compatible = "ti,am3352-rtc";
|
||||
reg = <0x48838000 0x100>;
|
||||
interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <dt-bindings/sound/samsung-i2s.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/clock/maxim,max77686.h>
|
||||
#include "exynos4412.dtsi"
|
||||
|
||||
/ {
|
||||
@ -105,6 +106,8 @@
|
||||
|
||||
rtc@10070000 {
|
||||
status = "okay";
|
||||
clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
|
||||
clock-names = "rtc", "rtc_src";
|
||||
};
|
||||
|
||||
g2d@10800000 {
|
||||
|
@ -567,6 +567,7 @@
|
||||
num-slots = <1>;
|
||||
broken-cd;
|
||||
cap-sdio-irq;
|
||||
keep-power-in-suspend;
|
||||
card-detect-delay = <200>;
|
||||
samsung,dw-mshc-ciu-div = <3>;
|
||||
samsung,dw-mshc-sdr-timing = <2 3>;
|
||||
|
@ -28,7 +28,7 @@ trips {
|
||||
type = "active";
|
||||
};
|
||||
cpu-crit-0 {
|
||||
temperature = <1200000>; /* millicelsius */
|
||||
temperature = <120000>; /* millicelsius */
|
||||
hysteresis = <0>; /* millicelsius */
|
||||
type = "critical";
|
||||
};
|
||||
|
@ -536,6 +536,7 @@
|
||||
clock-names = "dp";
|
||||
phys = <&dp_phy>;
|
||||
phy-names = "dp";
|
||||
power-domains = <&disp_pd>;
|
||||
};
|
||||
|
||||
mipi_phy: video-phy@10040714 {
|
||||
|
@ -18,7 +18,7 @@ trips {
|
||||
type = "active";
|
||||
};
|
||||
cpu-crit-0 {
|
||||
temperature = <1050000>; /* millicelsius */
|
||||
temperature = <105000>; /* millicelsius */
|
||||
hysteresis = <0>; /* millicelsius */
|
||||
type = "critical";
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include "imx23.dtsi"
|
||||
|
||||
/ {
|
||||
@ -93,6 +94,7 @@
|
||||
|
||||
ahb@80080000 {
|
||||
usb0: usb@80080000 {
|
||||
dr_mode = "host";
|
||||
vbus-supply = <®_usb0_vbus>;
|
||||
status = "okay";
|
||||
};
|
||||
@ -122,7 +124,7 @@
|
||||
|
||||
user {
|
||||
label = "green";
|
||||
gpios = <&gpio2 1 1>;
|
||||
gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -428,6 +428,7 @@
|
||||
|
||||
pwm4: pwm@53fc8000 {
|
||||
compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
|
||||
#pwm-cells = <2>;
|
||||
reg = <0x53fc8000 0x4000>;
|
||||
clocks = <&clks 108>, <&clks 52>;
|
||||
clock-names = "ipg", "per";
|
||||
|
@ -913,7 +913,7 @@
|
||||
80 81 68 69
|
||||
70 71 72 73
|
||||
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",
|
||||
"auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx",
|
||||
"auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx";
|
||||
|
@ -31,6 +31,7 @@
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&gpio4 15 0>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
reg_usb_h1_vbus: regulator@1 {
|
||||
@ -40,6 +41,7 @@
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&gpio1 0 0>;
|
||||
enable-active-high;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -185,7 +185,6 @@
|
||||
&i2c3 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_i2c3>;
|
||||
pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>;
|
||||
status = "okay";
|
||||
|
||||
max7310_a: gpio@30 {
|
||||
|
@ -498,6 +498,8 @@
|
||||
DRVDD-supply = <&vmmc2>;
|
||||
IOVDD-supply = <&vio>;
|
||||
DVDD-supply = <&vio>;
|
||||
|
||||
ai3x-micbias-vg = <1>;
|
||||
};
|
||||
|
||||
tlv320aic3x_aux: tlv320aic3x@19 {
|
||||
@ -509,6 +511,8 @@
|
||||
DRVDD-supply = <&vmmc2>;
|
||||
IOVDD-supply = <&vio>;
|
||||
DVDD-supply = <&vio>;
|
||||
|
||||
ai3x-micbias-vg = <2>;
|
||||
};
|
||||
|
||||
tsl2563: tsl2563@29 {
|
||||
|
@ -456,6 +456,7 @@
|
||||
};
|
||||
|
||||
mmu_isp: mmu@480bd400 {
|
||||
#iommu-cells = <0>;
|
||||
compatible = "ti,omap2-iommu";
|
||||
reg = <0x480bd400 0x80>;
|
||||
interrupts = <24>;
|
||||
@ -464,6 +465,7 @@
|
||||
};
|
||||
|
||||
mmu_iva: mmu@5d000000 {
|
||||
#iommu-cells = <0>;
|
||||
compatible = "ti,omap2-iommu";
|
||||
reg = <0x5d000000 0x80>;
|
||||
interrupts = <28>;
|
||||
|
@ -128,7 +128,7 @@
|
||||
* hierarchy.
|
||||
*/
|
||||
ocp {
|
||||
compatible = "ti,omap4-l3-noc", "simple-bus";
|
||||
compatible = "ti,omap5-l3-noc", "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
@ -545,7 +545,7 @@
|
||||
compatible = "adi,adv7511w";
|
||||
reg = <0x39>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
adi,input-depth = <8>;
|
||||
adi,input-colorspace = "rgb";
|
||||
|
@ -1017,23 +1017,6 @@
|
||||
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 {
|
||||
compatible = "stericsson,mcde";
|
||||
reg = <0xa0350000 0x1000>, /* MCDE */
|
||||
|
@ -111,6 +111,21 @@
|
||||
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
|
||||
sdi0_per1@80126000 {
|
||||
arm,primecell-periphid = <0x10480180>;
|
||||
|
@ -146,8 +146,21 @@
|
||||
};
|
||||
|
||||
vmmci: regulator-gpio {
|
||||
compatible = "regulator-gpio";
|
||||
|
||||
gpios = <&gpio7 4 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
|
||||
|
@ -39,11 +39,14 @@ CONFIG_ARCH_HIP04=y
|
||||
CONFIG_ARCH_KEYSTONE=y
|
||||
CONFIG_ARCH_MESON=y
|
||||
CONFIG_ARCH_MXC=y
|
||||
CONFIG_SOC_IMX50=y
|
||||
CONFIG_SOC_IMX51=y
|
||||
CONFIG_SOC_IMX53=y
|
||||
CONFIG_SOC_IMX6Q=y
|
||||
CONFIG_SOC_IMX6SL=y
|
||||
CONFIG_SOC_IMX6SX=y
|
||||
CONFIG_SOC_VF610=y
|
||||
CONFIG_SOC_LS1021A=y
|
||||
CONFIG_ARCH_OMAP3=y
|
||||
CONFIG_ARCH_OMAP4=y
|
||||
CONFIG_SOC_OMAP5=y
|
||||
|
@ -393,7 +393,7 @@ CONFIG_TI_EDMA=y
|
||||
CONFIG_DMA_OMAP=y
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
CONFIG_EXTCON=m
|
||||
CONFIG_EXTCON_GPIO=m
|
||||
CONFIG_EXTCON_USB_GPIO=m
|
||||
CONFIG_EXTCON_PALMAS=m
|
||||
CONFIG_TI_EMIF=m
|
||||
CONFIG_PWM=y
|
||||
|
@ -25,7 +25,7 @@ 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);
|
||||
|
||||
|
@ -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,
|
||||
unsigned long pfn,
|
||||
unsigned long mfn);
|
||||
unsigned long xen_get_swiotlb_free_pages(unsigned int order);
|
||||
|
||||
#endif /* _ASM_ARM_XEN_PAGE_H */
|
||||
|
@ -303,12 +303,17 @@ static int probe_current_pmu(struct arm_pmu *pmu)
|
||||
|
||||
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);
|
||||
|
||||
if (!irqs)
|
||||
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) {
|
||||
struct device_node *dn;
|
||||
int cpu;
|
||||
@ -317,7 +322,7 @@ static int of_pmu_irq_cfg(struct platform_device *pdev)
|
||||
i);
|
||||
if (!dn) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
|
@ -112,6 +112,7 @@
|
||||
#define OMAP3430_VC_CMD_ONLP_SHIFT 16
|
||||
#define OMAP3430_VC_CMD_RET_SHIFT 8
|
||||
#define OMAP3430_VC_CMD_OFF_SHIFT 0
|
||||
#define OMAP3430_SREN_MASK (1 << 4)
|
||||
#define OMAP3430_HSEN_MASK (1 << 3)
|
||||
#define OMAP3430_MCODE_MASK (0x7 << 0)
|
||||
#define OMAP3430_VALID_MASK (1 << 24)
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT 1
|
||||
#define OMAP4430_GLOBAL_WUEN_MASK (1 << 16)
|
||||
#define OMAP4430_HSMCODE_MASK (0x7 << 0)
|
||||
#define OMAP4430_SRMODEEN_MASK (1 << 4)
|
||||
#define OMAP4430_HSMODEEN_MASK (1 << 3)
|
||||
#define OMAP4430_HSSCLL_SHIFT 24
|
||||
#define OMAP4430_ICEPICK_RST_SHIFT 9
|
||||
|
@ -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.
|
||||
* Note that no actual voltage scaling during off-idle will
|
||||
* 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);
|
||||
if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) {
|
||||
@ -704,9 +705,16 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
|
||||
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;
|
||||
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_reg);
|
||||
|
||||
|
@ -34,6 +34,7 @@ struct voltagedomain;
|
||||
* @cmd_ret_shift: RET 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_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_mcode_mask: MCODE field mask for I2C config register
|
||||
*
|
||||
@ -52,6 +53,7 @@ struct omap_vc_common {
|
||||
u8 cmd_ret_shift;
|
||||
u8 cmd_off_shift;
|
||||
u8 i2c_cfg_reg;
|
||||
u8 i2c_cfg_clear_mask;
|
||||
u8 i2c_cfg_hsen_mask;
|
||||
u8 i2c_mcode_mask;
|
||||
};
|
||||
|
@ -40,6 +40,7 @@ static struct omap_vc_common omap3_vc_common = {
|
||||
.cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT,
|
||||
.cmd_ret_shift = OMAP3430_VC_CMD_RET_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_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET,
|
||||
.i2c_mcode_mask = OMAP3430_MCODE_MASK,
|
||||
|
@ -42,6 +42,7 @@ static const struct omap_vc_common omap4_vc_common = {
|
||||
.cmd_ret_shift = OMAP4430_RET_SHIFT,
|
||||
.cmd_off_shift = OMAP4430_OFF_SHIFT,
|
||||
.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_mcode_mask = OMAP4430_HSMCODE_MASK,
|
||||
};
|
||||
|
@ -691,4 +691,13 @@ config SHARPSL_PM_MAX1111
|
||||
config PXA310_ULPI
|
||||
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
|
||||
|
@ -90,4 +90,5 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o
|
||||
obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o
|
||||
obj-$(CONFIG_MACH_ZIPIT2) += z2.o
|
||||
|
||||
obj-$(CONFIG_PXA_SYSTEMS_CPLDS) += pxa_cplds_irqs.o
|
||||
obj-$(CONFIG_TOSA_BT) += tosa-bt.o
|
||||
|
@ -37,7 +37,9 @@
|
||||
#define LUB_GP __LUB_REG(LUBBOCK_FPGA_PHYS + 0x100)
|
||||
|
||||
/* 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_SA1111_IRQ LUBBOCK_IRQ(1)
|
||||
#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_LAST_IRQ LUBBOCK_IRQ(6)
|
||||
|
||||
#define LUBBOCK_SA1111_IRQ_BASE (IRQ_BOARD_START + 16)
|
||||
#define LUBBOCK_NR_IRQS (IRQ_BOARD_START + 16 + 55)
|
||||
#define LUBBOCK_SA1111_IRQ_BASE (LUBBOCK_NR_IRQS + 32)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);
|
||||
|
@ -120,7 +120,9 @@
|
||||
#define MST_PCMCIA_PWR_VCC_50 0x4 /* voltage VCC = 5.0V */
|
||||
|
||||
/* 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_USIM_IRQ MAINSTONE_IRQ(1)
|
||||
#define MAINSTONE_USBC_IRQ MAINSTONE_IRQ(2)
|
||||
@ -136,6 +138,4 @@
|
||||
#define MAINSTONE_S1_STSCHG_IRQ MAINSTONE_IRQ(14)
|
||||
#define MAINSTONE_S1_IRQ MAINSTONE_IRQ(15)
|
||||
|
||||
#define MAINSTONE_NR_IRQS (IRQ_BOARD_START + 16)
|
||||
|
||||
#endif
|
||||
|
@ -12,6 +12,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.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);
|
||||
|
||||
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)
|
||||
{
|
||||
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 = {
|
||||
&sa1111_device,
|
||||
&smc91x_device,
|
||||
&lubbock_flash_device[0],
|
||||
&lubbock_flash_device[1],
|
||||
&lubbock_cplds_device,
|
||||
};
|
||||
|
||||
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. */
|
||||
.map_io = lubbock_map_io,
|
||||
.nr_irqs = LUBBOCK_NR_IRQS,
|
||||
.init_irq = lubbock_init_irq,
|
||||
.init_irq = pxa25x_init_irq,
|
||||
.handle_irq = pxa25x_handle_irq,
|
||||
.init_time = pxa_timer_init,
|
||||
.init_machine = lubbock_init,
|
||||
|
@ -13,6 +13,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
@ -122,92 +123,6 @@ static unsigned long mainstone_pin_config[] = {
|
||||
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[] = {
|
||||
[0] = {
|
||||
.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 = {
|
||||
&smc91x_device,
|
||||
&mst_flash_device[0],
|
||||
&mst_flash_device[1],
|
||||
&mst_gpio_keys_device,
|
||||
&mst_cplds_device,
|
||||
};
|
||||
|
||||
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 */
|
||||
.map_io = mainstone_map_io,
|
||||
.nr_irqs = MAINSTONE_NR_IRQS,
|
||||
.init_irq = mainstone_init_irq,
|
||||
.init_irq = pxa27x_init_irq,
|
||||
.handle_irq = pxa27x_handle_irq,
|
||||
.init_time = pxa_timer_init,
|
||||
.init_machine = mainstone_init,
|
||||
|
200
arch/arm/mach-pxa/pxa_cplds_irqs.c
Normal file
200
arch/arm/mach-pxa/pxa_cplds_irqs.c
Normal 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");
|
@ -44,9 +44,11 @@ static void __iomem *rk3288_bootram_base;
|
||||
static phys_addr_t rk3288_bootram_phy;
|
||||
|
||||
static struct regmap *pmu_regmap;
|
||||
static struct regmap *grf_regmap;
|
||||
static struct regmap *sgrf_regmap;
|
||||
|
||||
static u32 rk3288_pmu_pwr_mode_con;
|
||||
static u32 rk3288_grf_soc_con0;
|
||||
static u32 rk3288_sgrf_soc_con0;
|
||||
|
||||
static inline u32 rk3288_l2_config(void)
|
||||
@ -70,11 +72,25 @@ static void rk3288_slp_mode_set(int level)
|
||||
{
|
||||
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(pmu_regmap, RK3288_PMU_PWRMODE_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
|
||||
* 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_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 */
|
||||
regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
|
||||
rk3288_bootram_phy);
|
||||
@ -128,6 +151,9 @@ static void rk3288_slp_mode_set_resume(void)
|
||||
regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
|
||||
rk3288_sgrf_soc_con0 | SGRF_PCLK_WDT_GATE_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)
|
||||
@ -186,6 +212,13 @@ static int rk3288_suspend_init(struct device_node *np)
|
||||
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,
|
||||
"rockchip,rk3288-pmu-sram");
|
||||
if (!sram_np) {
|
||||
|
@ -48,6 +48,10 @@ static inline void rockchip_suspend_init(void)
|
||||
#define RK3288_PMU_WAKEUP_RST_CLR_CNT 0x44
|
||||
#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_FAST_BOOT_ADDR (0x0120)
|
||||
#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_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_SEL0_CON 0x60
|
||||
#define RK3288_CRU_SEL1_CON 0x64
|
||||
|
@ -30,11 +30,30 @@
|
||||
#include "pm.h"
|
||||
|
||||
#define RK3288_GRF_SOC_CON0 0x244
|
||||
#define RK3288_TIMER6_7_PHYS 0xff810000
|
||||
|
||||
static void __init rockchip_timer_init(void)
|
||||
{
|
||||
if (of_machine_is_compatible("rockchip,rk3288")) {
|
||||
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
|
||||
|
@ -1878,7 +1878,7 @@ struct dma_map_ops iommu_coherent_ops = {
|
||||
* arm_iommu_attach_device function.
|
||||
*/
|
||||
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 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 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)
|
||||
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)
|
||||
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);
|
||||
if (IS_ERR(mapping)) {
|
||||
pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
|
||||
|
@ -22,8 +22,6 @@
|
||||
*
|
||||
* These are the low level assembler for performing cache and TLB
|
||||
* functions on the arm1020.
|
||||
*
|
||||
* CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -22,8 +22,6 @@
|
||||
*
|
||||
* These are the low level assembler for performing cache and TLB
|
||||
* functions on the arm1020e.
|
||||
*
|
||||
* CONFIG_CPU_ARM1020_CPU_IDLE -> nohlt
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -441,9 +441,6 @@ ENTRY(cpu_arm925_set_pte_ext)
|
||||
.type __arm925_setup, #function
|
||||
__arm925_setup:
|
||||
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 */
|
||||
orr r0,r0,#1 << 1 @ transparent mode on
|
||||
|
@ -602,7 +602,6 @@ __\name\()_proc_info:
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
initfn __feroceon_setup, __\name\()_proc_info
|
||||
.long __feroceon_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
@ -21,6 +22,20 @@
|
||||
#include <asm/xen/hypercall.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 {
|
||||
DMA_UNMAP,
|
||||
DMA_MAP,
|
||||
|
@ -31,6 +31,7 @@ config ARM64
|
||||
select GENERIC_EARLY_IOREMAP
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_IRQ_SHOW_LEVEL
|
||||
select GENERIC_PCI_IOMAP
|
||||
select GENERIC_SCHED_CLOCK
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
|
@ -65,6 +65,14 @@ do { \
|
||||
do { \
|
||||
compiletime_assert_atomic_type(*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: \
|
||||
asm volatile ("stlr %w1, %0" \
|
||||
: "=Q" (*p) : "r" (v) : "memory"); \
|
||||
@ -81,6 +89,14 @@ do { \
|
||||
typeof(*p) ___p1; \
|
||||
compiletime_assert_atomic_type(*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: \
|
||||
asm volatile ("ldar %w0, %1" \
|
||||
: "=r" (___p1) : "Q" (*p) : "memory"); \
|
||||
|
@ -1310,7 +1310,7 @@ static const struct of_device_id armpmu_of_device_ids[] = {
|
||||
|
||||
static int armpmu_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i, *irqs;
|
||||
int i, irq, *irqs;
|
||||
|
||||
if (!cpu_pmu)
|
||||
return -ENODEV;
|
||||
@ -1319,6 +1319,11 @@ static int armpmu_device_probe(struct platform_device *pdev)
|
||||
if (!irqs)
|
||||
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) {
|
||||
struct device_node *dn;
|
||||
int cpu;
|
||||
@ -1327,7 +1332,7 @@ static int armpmu_device_probe(struct platform_device *pdev)
|
||||
i);
|
||||
if (!dn) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
ptr = (void *)val;
|
||||
if (flags & __GFP_ZERO)
|
||||
memset(ptr, 0, size);
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
@ -105,7 +104,6 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
|
||||
struct page *page;
|
||||
void *addr;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
page = dma_alloc_from_contiguous(dev, size >> PAGE_SHIFT,
|
||||
get_order(size));
|
||||
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));
|
||||
addr = page_address(page);
|
||||
if (flags & __GFP_ZERO)
|
||||
memset(addr, 0, size);
|
||||
memset(addr, 0, size);
|
||||
return addr;
|
||||
} else {
|
||||
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));
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
if (!is_device_dma_coherent(dev)) {
|
||||
if (__free_from_pool(vaddr, size))
|
||||
return;
|
||||
|
@ -45,7 +45,7 @@ static volatile unsigned long flushcache_cpumask = 0;
|
||||
/*
|
||||
* For flush_tlb_others()
|
||||
*/
|
||||
static volatile cpumask_t flush_cpumask;
|
||||
static cpumask_t flush_cpumask;
|
||||
static struct mm_struct *flush_mm;
|
||||
static struct vm_area_struct *flush_vma;
|
||||
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);
|
||||
|
||||
while (!cpumask_empty((cpumask_t*)&flush_cpumask)) {
|
||||
while (!cpumask_empty(&flush_cpumask)) {
|
||||
/* nothing. lockup detection does not belong here */
|
||||
mb();
|
||||
}
|
||||
@ -468,7 +468,7 @@ void smp_invalidate_interrupt(void)
|
||||
__flush_tlb_page(va);
|
||||
}
|
||||
}
|
||||
cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask);
|
||||
cpumask_clear_cpu(cpu_id, &flush_cpumask);
|
||||
}
|
||||
|
||||
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define TM_CAUSE_RESCHED 0xde
|
||||
#define TM_CAUSE_TLBI 0xdc
|
||||
#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_SIGNAL 0xd4
|
||||
#define TM_CAUSE_ALIGNMENT 0xd2
|
||||
|
@ -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_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
|
||||
eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev);
|
||||
eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
|
||||
break;
|
||||
case pcie_hot_reset:
|
||||
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
|
||||
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
||||
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
|
||||
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
|
||||
eeh_ops->reset(pe, EEH_RESET_HOT);
|
||||
break;
|
||||
case pcie_warm_reset:
|
||||
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
|
||||
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
||||
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
|
||||
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
|
||||
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
|
||||
break;
|
||||
default:
|
||||
eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
|
||||
eeh_pe_state_clear(pe, EEH_PE_ISOLATED | EEH_PE_CFG_BLOCKED);
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
@ -1058,6 +1061,9 @@ void eeh_add_device_early(struct pci_dn *pdn)
|
||||
if (!edev || !eeh_enabled())
|
||||
return;
|
||||
|
||||
if (!eeh_has_flag(EEH_PROBE_MODE_DEVTREE))
|
||||
return;
|
||||
|
||||
/* USB Bus children of PCI devices will not have BUID's */
|
||||
phb = edev->phb;
|
||||
if (NULL == phb ||
|
||||
@ -1112,6 +1118,9 @@ void eeh_add_device_late(struct pci_dev *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (eeh_has_flag(EEH_PROBE_MODE_DEV))
|
||||
eeh_ops->probe(pdn, NULL);
|
||||
|
||||
/*
|
||||
* The EEH cache might not be removed correctly because of
|
||||
* unbalanced kref to the device during unplug time, which
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <asm/ftrace.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include <asm/context_tracking.h>
|
||||
#include <asm/tm.h>
|
||||
|
||||
/*
|
||||
* System calls.
|
||||
@ -146,24 +145,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
|
||||
andi. r11,r10,_TIF_SYSCALL_DOTRACE
|
||||
bne syscall_dotrace
|
||||
.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
|
||||
bge- syscall_enosys
|
||||
|
||||
|
@ -501,9 +501,11 @@ BEGIN_FTR_SECTION
|
||||
CHECK_HMI_INTERRUPT
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
|
||||
ld r1,PACAR1(r13)
|
||||
ld r6,_CCR(r1)
|
||||
ld r4,_MSR(r1)
|
||||
ld r5,_NIP(r1)
|
||||
addi r1,r1,INT_FRAME_SIZE
|
||||
mtcr r6
|
||||
mtspr SPRN_SRR1,r4
|
||||
mtspr SPRN_SRR0,r5
|
||||
rfid
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/kvm_book3s.h>
|
||||
@ -20,7 +21,6 @@
|
||||
#include <asm/xics.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/spinlock.h>
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
@ -2693,7 +2693,6 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,
|
||||
hose->last_busno = 0xff;
|
||||
}
|
||||
hose->private_data = phb;
|
||||
hose->controller_ops = pnv_pci_controller_ops;
|
||||
phb->hub_id = hub_id;
|
||||
phb->opal_id = phb_id;
|
||||
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.window_alignment = pnv_pci_window_alignment;
|
||||
pnv_pci_controller_ops.reset_secondary_bus = pnv_pci_reset_secondary_bus;
|
||||
hose->controller_ops = pnv_pci_controller_ops;
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov_resources;
|
||||
|
@ -412,6 +412,10 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
||||
if (rc)
|
||||
return -EINVAL;
|
||||
|
||||
rc = dlpar_acquire_drc(drc_index);
|
||||
if (rc)
|
||||
return -EINVAL;
|
||||
|
||||
parent = of_find_node_by_path("/cpus");
|
||||
if (!parent)
|
||||
return -ENODEV;
|
||||
@ -422,12 +426,6 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
|
||||
|
||||
of_node_put(parent);
|
||||
|
||||
rc = dlpar_acquire_drc(drc_index);
|
||||
if (rc) {
|
||||
dlpar_free_cc_nodes(dn);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = dlpar_attach_node(dn);
|
||||
if (rc) {
|
||||
dlpar_release_drc(drc_index);
|
||||
|
@ -115,7 +115,7 @@ config S390
|
||||
select HAVE_ARCH_SECCOMP_FILTER
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
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_LOCAL
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
|
@ -3,9 +3,10 @@
|
||||
*
|
||||
* Support for s390 cryptographic instructions.
|
||||
*
|
||||
* Copyright IBM Corp. 2003, 2007
|
||||
* Copyright IBM Corp. 2003, 2015
|
||||
* Author(s): Thomas Spatzier
|
||||
* 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
|
||||
* 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_MSA3 0x2
|
||||
#define CRYPT_S390_MSA4 0x4
|
||||
#define CRYPT_S390_MSA5 0x8
|
||||
|
||||
/* s390 cryptographic operations */
|
||||
enum crypt_s390_operations {
|
||||
CRYPT_S390_KM = 0x0100,
|
||||
CRYPT_S390_KMC = 0x0200,
|
||||
CRYPT_S390_KIMD = 0x0300,
|
||||
CRYPT_S390_KLMD = 0x0400,
|
||||
CRYPT_S390_KMAC = 0x0500,
|
||||
CRYPT_S390_KMCTR = 0x0600
|
||||
CRYPT_S390_KM = 0x0100,
|
||||
CRYPT_S390_KMC = 0x0200,
|
||||
CRYPT_S390_KIMD = 0x0300,
|
||||
CRYPT_S390_KLMD = 0x0400,
|
||||
CRYPT_S390_KMAC = 0x0500,
|
||||
CRYPT_S390_KMCTR = 0x0600,
|
||||
CRYPT_S390_PPNO = 0x0700
|
||||
};
|
||||
|
||||
/*
|
||||
@ -138,6 +141,16 @@ enum crypt_s390_kmac_func {
|
||||
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:
|
||||
* @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;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rre,0xb92e0000,%3,%1\n" /* KM opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\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" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||
if (ret < 0)
|
||||
@ -198,11 +211,11 @@ static inline int crypt_s390_kmc(long func, void *param,
|
||||
int ret;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rre,0xb92f0000,%3,%1\n" /* KMC opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\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" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||
if (ret < 0)
|
||||
@ -233,11 +246,11 @@ static inline int crypt_s390_kimd(long func, void *param,
|
||||
int ret;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rre,0xb93e0000,%1,%1\n" /* KIMD opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\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" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||
if (ret < 0)
|
||||
@ -267,11 +280,11 @@ static inline int crypt_s390_klmd(long func, void *param,
|
||||
int ret;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rre,0xb93f0000,%1,%1\n" /* KLMD opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\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" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||
if (ret < 0)
|
||||
@ -302,11 +315,11 @@ static inline int crypt_s390_kmac(long func, void *param,
|
||||
int ret;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rre,0xb91e0000,%1,%1\n" /* KLAC opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\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" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||
if (ret < 0)
|
||||
@ -340,11 +353,11 @@ static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
|
||||
int ret = -1;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rrf,0xb92d0000,%3,%1,%4,0\n" /* KMCTR opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\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),
|
||||
"+a" (__ctr)
|
||||
: "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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* @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;
|
||||
if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77))
|
||||
return 0;
|
||||
if (facility_mask & CRYPT_S390_MSA5 && !test_facility(57))
|
||||
return 0;
|
||||
|
||||
switch (func & CRYPT_S390_OP_MASK) {
|
||||
case CRYPT_S390_KM:
|
||||
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);
|
||||
break;
|
||||
case CRYPT_S390_KMCTR:
|
||||
ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0,
|
||||
NULL);
|
||||
ret = crypt_s390_kmctr(KMCTR_QUERY, &status,
|
||||
NULL, NULL, 0, NULL);
|
||||
break;
|
||||
case CRYPT_S390_PPNO:
|
||||
ret = crypt_s390_ppno(PPNO_QUERY, &status,
|
||||
NULL, 0, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@ -419,15 +480,14 @@ static inline int crypt_s390_pcc(long func, void *param)
|
||||
int ret = -1;
|
||||
|
||||
asm volatile(
|
||||
"0: .insn rre,0xb92c0000,0,0 \n" /* PCC opcode */
|
||||
"1: brc 1,0b \n" /* handle partial completion */
|
||||
"0: .insn rre,0xb92c0000,0,0\n" /* PCC opcode */
|
||||
"1: brc 1,0b\n" /* handle partial completion */
|
||||
" la %0,0\n"
|
||||
"2:\n"
|
||||
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
||||
EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
|
||||
: "+d" (ret)
|
||||
: "d" (__func), "a" (__param) : "cc", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
|
||||
|
@ -1,106 +1,529 @@
|
||||
/*
|
||||
* Copyright IBM Corp. 2006, 2007
|
||||
* Copyright IBM Corp. 2006, 2015
|
||||
* Author(s): Jan Glauber <jan.glauber@de.ibm.com>
|
||||
* Harald Freudenberger <freude@de.ibm.com>
|
||||
* 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/fips.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/timex.h>
|
||||
|
||||
#include "crypt_s390.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
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");
|
||||
|
||||
static int prng_entropy_limit = 4096;
|
||||
module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
|
||||
MODULE_PARM_DESC(prng_entropy_limit,
|
||||
"PRNG add entropy after that much bytes were produced");
|
||||
|
||||
#define PRNG_RESEED_LIMIT_TDES 4096
|
||||
#define PRNG_RESEED_LIMIT_TDES_LOWER 4096
|
||||
#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,
|
||||
* of course, in a state of sin. -- John von Neumann
|
||||
*/
|
||||
|
||||
struct s390_prng_data {
|
||||
unsigned long count; /* how many bytes were produced */
|
||||
char *buf;
|
||||
static int prng_errorflag;
|
||||
|
||||
#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;
|
||||
|
||||
/* copied from libica, use a non-zero initial parameter block */
|
||||
static unsigned char parm_block[32] = {
|
||||
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,
|
||||
struct ppno_ws_s {
|
||||
u32 res;
|
||||
u32 reseed_counter;
|
||||
u64 stream_bytes;
|
||||
u8 V[112];
|
||||
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];
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
|
||||
(char *)entropy, sizeof(entropy));
|
||||
ret = crypt_s390_kmc(KMC_PRNG, prng_data->prngws.parm_block,
|
||||
(char *)entropy, (char *)entropy,
|
||||
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];
|
||||
int i = 0;
|
||||
|
||||
BUG_ON(nbytes > 16);
|
||||
BUG_ON(nbytes > sizeof(buf));
|
||||
|
||||
get_random_bytes(buf, nbytes);
|
||||
|
||||
/* Add the entropy */
|
||||
while (nbytes >= 8) {
|
||||
*((__u64 *)parm_block) ^= *((__u64 *)(buf+i));
|
||||
prng_add_entropy();
|
||||
*((__u64 *)prng_data->prngws.parm_block) ^= *((__u64 *)(buf+i));
|
||||
prng_tdes_add_entropy();
|
||||
i += 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) {
|
||||
/* same as in extract_entropy_user in random.c */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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 */
|
||||
n = (chunk + 7) & -8;
|
||||
|
||||
if (p->count > prng_entropy_limit)
|
||||
prng_seed(8);
|
||||
if (prng_data->prngws.reseed_counter > prng_reseed_limit)
|
||||
prng_tdes_seed(8);
|
||||
|
||||
/* if the CPU supports PRNG stckf is present too */
|
||||
asm volatile(".insn s,0xb27c0000,%0"
|
||||
: "=m" (*((unsigned long long *)p->buf)) : : "cc");
|
||||
*((unsigned long long *)prng_data->buf) = get_tod_clock_fast();
|
||||
|
||||
/*
|
||||
* 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
|
||||
* prng_chunk_size to 8 bytes.
|
||||
*/
|
||||
tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
|
||||
BUG_ON((tmp < 0) || (tmp != n));
|
||||
tmp = crypt_s390_kmc(KMC_PRNG, prng_data->prngws.parm_block,
|
||||
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;
|
||||
|
||||
nbytes -= chunk;
|
||||
ret += chunk;
|
||||
ubuf += chunk;
|
||||
}
|
||||
|
||||
/* unlock prng_data struct */
|
||||
mutex_unlock(&prng_data->mutex);
|
||||
|
||||
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,
|
||||
.open = &prng_open,
|
||||
.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,
|
||||
};
|
||||
|
||||
static struct miscdevice prng_dev = {
|
||||
static struct miscdevice prng_sha512_dev = {
|
||||
.name = "prandom",
|
||||
.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)
|
||||
{
|
||||
@ -169,43 +815,105 @@ static int __init prng_init(void)
|
||||
if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (prng_chunk_size < 8)
|
||||
return -EINVAL;
|
||||
|
||||
p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
p->count = 0;
|
||||
|
||||
p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
|
||||
if (!p->buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
/* choose prng mode */
|
||||
if (prng_mode != PRNG_MODE_TDES) {
|
||||
/* check for MSA5 support for PPNO operations */
|
||||
if (!crypt_s390_func_available(PPNO_SHA512_DRNG_GEN,
|
||||
CRYPT_S390_MSA5)) {
|
||||
if (prng_mode == PRNG_MODE_SHA512) {
|
||||
pr_err("The prng module cannot "
|
||||
"start in SHA-512 mode\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
prng_mode = PRNG_MODE_TDES;
|
||||
} else
|
||||
prng_mode = PRNG_MODE_SHA512;
|
||||
}
|
||||
|
||||
/* initialize the PRNG, add 128 bits of entropy */
|
||||
prng_seed(16);
|
||||
if (prng_mode == PRNG_MODE_SHA512) {
|
||||
|
||||
ret = misc_register(&prng_dev);
|
||||
if (ret)
|
||||
goto out_buf;
|
||||
return 0;
|
||||
/* SHA512 mode */
|
||||
|
||||
out_buf:
|
||||
kfree(p->buf);
|
||||
out_free:
|
||||
kfree(p);
|
||||
if (prng_chunk_size < PRNG_CHUNKSIZE_SHA512_MIN
|
||||
|| prng_chunk_size > PRNG_CHUNKSIZE_SHA512_MAX)
|
||||
return -EINVAL;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static void __exit prng_exit(void)
|
||||
{
|
||||
/* wipe me */
|
||||
kzfree(p->buf);
|
||||
kfree(p);
|
||||
|
||||
misc_deregister(&prng_dev);
|
||||
if (prng_mode == PRNG_MODE_SHA512) {
|
||||
sysfs_remove_group(&prng_sha512_dev.this_device->kobj,
|
||||
&prng_sha512_dev_attr_group);
|
||||
misc_deregister(&prng_sha512_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_exit(prng_exit);
|
||||
|
@ -26,6 +26,9 @@
|
||||
/* Not more than 2GB */
|
||||
#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 */
|
||||
#define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL)
|
||||
|
||||
|
@ -14,7 +14,9 @@ typedef struct {
|
||||
unsigned long asce_bits;
|
||||
unsigned long asce_limit;
|
||||
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;
|
||||
/* The mmu context uses storage keys. */
|
||||
unsigned int use_skey:1;
|
||||
|
@ -20,8 +20,11 @@ static inline int init_new_context(struct task_struct *tsk,
|
||||
mm->context.flush_mm = 0;
|
||||
mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
|
||||
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.use_skey = 0;
|
||||
#endif
|
||||
mm->context.asce_limit = STACK_TOP_MAX;
|
||||
crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
|
||||
return 0;
|
||||
|
@ -21,6 +21,7 @@ void crst_table_free(struct mm_struct *, unsigned long *);
|
||||
unsigned long *page_table_alloc(struct mm_struct *);
|
||||
void page_table_free(struct mm_struct *, 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,
|
||||
unsigned long key, bool nq);
|
||||
|
@ -12,12 +12,9 @@
|
||||
#define _ASM_S390_PGTABLE_H
|
||||
|
||||
/*
|
||||
* The Linux memory management assumes a three-level page table setup. For
|
||||
* s390 31 bit we "fold" the mid level into the top-level page table, so
|
||||
* that we physically have the same two-level page table as the s390 mmu
|
||||
* 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 Linux memory management assumes a three-level page table setup.
|
||||
* For s390 64 bit we use up to four of the five levels the hardware
|
||||
* provides (region first tables are not used).
|
||||
*
|
||||
* 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
|
||||
@ -101,8 +98,8 @@ extern unsigned long zero_page_mask;
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* The vmalloc and module area will always be on the topmost area of the kernel
|
||||
* mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc and modules.
|
||||
* The vmalloc and module area will always be on the topmost area of the
|
||||
* 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
|
||||
* modules will reside. That makes sure that inter module branches always
|
||||
* 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:
|
||||
* | PFRA |0IPC| OS |
|
||||
* 0000000000111111111122222222223333333333444444444455555555556666
|
||||
@ -220,7 +185,6 @@ static inline int is_module_addr(void *addr)
|
||||
|
||||
/* Software bits in the page table entry */
|
||||
#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_DIRTY 0x008 /* SW pte dirty bit */
|
||||
#define _PAGE_READ 0x010 /* SW pte read bit */
|
||||
@ -240,31 +204,34 @@ static inline int is_module_addr(void *addr)
|
||||
* table lock held.
|
||||
*
|
||||
* 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
|
||||
* 000084210000
|
||||
* 000000008421
|
||||
* .IR...wrdytp
|
||||
* empty .10...000000
|
||||
* swap .10...xxxx10
|
||||
* file .11...xxxxx0
|
||||
* prot-none, clean, old .11...000001
|
||||
* prot-none, clean, young .11...000101
|
||||
* prot-none, dirty, old .10...001001
|
||||
* prot-none, dirty, young .10...001101
|
||||
* read-only, clean, old .11...010001
|
||||
* read-only, clean, young .01...010101
|
||||
* read-only, dirty, old .11...011001
|
||||
* read-only, dirty, young .01...011101
|
||||
* read-write, clean, old .11...110001
|
||||
* read-write, clean, young .01...110101
|
||||
* read-write, dirty, old .10...111001
|
||||
* read-write, dirty, young .00...111101
|
||||
* .IR.uswrdy.p
|
||||
* empty .10.00000000
|
||||
* swap .11..ttttt.0
|
||||
* prot-none, clean, old .11.xx0000.1
|
||||
* prot-none, clean, young .11.xx0001.1
|
||||
* prot-none, dirty, old .10.xx0010.1
|
||||
* prot-none, dirty, young .10.xx0011.1
|
||||
* read-only, clean, old .11.xx0100.1
|
||||
* read-only, clean, young .01.xx0101.1
|
||||
* read-only, dirty, old .11.xx0110.1
|
||||
* read-only, dirty, young .01.xx0111.1
|
||||
* read-write, clean, old .11.xx1100.1
|
||||
* read-write, clean, young .01.xx1101.1
|
||||
* read-write, dirty, old .10.xx1110.1
|
||||
* read-write, dirty, young .00.xx1111.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
|
||||
*
|
||||
* pte_present is true for the bit pattern .xx...xxxxx1, (pte & 0x001) == 0x001
|
||||
* pte_none is true for the bit pattern .10...xxxx00, (pte & 0x603) == 0x400
|
||||
* pte_swap is true for the bit pattern .10...xxxx10, (pte & 0x603) == 0x402
|
||||
* pte_none is true for the bit pattern .10.00000000, pte == 0x400
|
||||
* pte_swap is true for the bit pattern .11..ooooo.0, (pte & 0x201) == 0x200
|
||||
* pte_present is true for the bit pattern .xx.xxxxxx.1, (pte & 0x001) == 0x001
|
||||
*/
|
||||
|
||||
/* 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
|
||||
* The segment table origin is used to distinguish empty (origin==0) from
|
||||
* 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 */
|
||||
@ -423,6 +392,15 @@ static inline int mm_has_pgste(struct mm_struct *mm)
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
/* Bit pattern: (pte & 0x603) == 0x402 */
|
||||
return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT |
|
||||
_PAGE_TYPE | _PAGE_PRESENT))
|
||||
== (_PAGE_INVALID | _PAGE_TYPE);
|
||||
/* Bit pattern: (pte & 0x201) == 0x200 */
|
||||
return (pte_val(pte) & (_PAGE_PROTECT | _PAGE_PRESENT))
|
||||
== _PAGE_PROTECT;
|
||||
}
|
||||
|
||||
static inline int pte_special(pte_t pte)
|
||||
@ -1586,51 +1563,51 @@ static inline int has_transparent_hugepage(void)
|
||||
#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:
|
||||
* 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
|
||||
* 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 53, 54, 62 and 63 are used to indicate the page type.
|
||||
* A swap pte is indicated by bit pattern (pte & 0x603) == 0x402
|
||||
* This leaves the bits 0-51 and bits 56-61 to store type and offset.
|
||||
* We use the 5 bits from 57-61 for the type and the 53 bits from 0-51
|
||||
* plus 56 for the offset.
|
||||
* | offset |0110|o|type |00|
|
||||
* 0000000000111111111122222222223333333333444444444455 5555 5 55566 66
|
||||
* 0123456789012345678901234567890123456789012345678901 2345 6 78901 23
|
||||
* Bits 54 and 63 are used to indicate the page type.
|
||||
* A swap pte is indicated by bit pattern (pte & 0x201) == 0x200
|
||||
* 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 52 bits from 0-51
|
||||
* for the offset.
|
||||
* | offset |01100|type |00|
|
||||
* |0000000000111111111122222222223333333333444444444455|55555|55566|66|
|
||||
* |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)
|
||||
{
|
||||
pte_t pte;
|
||||
offset &= __SWP_OFFSET_MASK;
|
||||
pte_val(pte) = _PAGE_INVALID | _PAGE_TYPE | ((type & 0x1f) << 2) |
|
||||
((offset & 1UL) << 7) | ((offset & ~1UL) << 11);
|
||||
|
||||
pte_val(pte) = _PAGE_INVALID | _PAGE_PROTECT;
|
||||
pte_val(pte) |= (offset & __SWP_OFFSET_MASK) << __SWP_OFFSET_SHIFT;
|
||||
pte_val(pte) |= (type & __SWP_TYPE_MASK) << __SWP_TYPE_SHIFT;
|
||||
return pte;
|
||||
}
|
||||
|
||||
#define __swp_type(entry) (((entry).val >> 2) & 0x1f)
|
||||
#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))) })
|
||||
static inline unsigned long __swp_type(swp_entry_t entry)
|
||||
{
|
||||
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 __swp_entry_to_pte(x) ((pte_t) { (x).val })
|
||||
|
@ -14,20 +14,23 @@ static inline pmd_t __pte_to_pmd(pte_t pte)
|
||||
|
||||
/*
|
||||
* Convert encoding pte bits pmd bits
|
||||
* .IR...wrdytp dy..R...I...wr
|
||||
* empty .10...000000 -> 00..0...1...00
|
||||
* prot-none, clean, old .11...000001 -> 00..1...1...00
|
||||
* prot-none, clean, young .11...000101 -> 01..1...1...00
|
||||
* prot-none, dirty, old .10...001001 -> 10..1...1...00
|
||||
* prot-none, dirty, young .10...001101 -> 11..1...1...00
|
||||
* read-only, clean, old .11...010001 -> 00..1...1...01
|
||||
* read-only, clean, young .01...010101 -> 01..1...0...01
|
||||
* read-only, dirty, old .11...011001 -> 10..1...1...01
|
||||
* read-only, dirty, young .01...011101 -> 11..1...0...01
|
||||
* read-write, clean, old .11...110001 -> 00..0...1...11
|
||||
* read-write, clean, young .01...110101 -> 01..0...0...11
|
||||
* read-write, dirty, old .10...111001 -> 10..0...1...11
|
||||
* read-write, dirty, young .00...111101 -> 11..0...0...11
|
||||
* lIR.uswrdy.p dy..R...I...wr
|
||||
* empty 010.000000.0 -> 00..0...1...00
|
||||
* prot-none, clean, old 111.000000.1 -> 00..1...1...00
|
||||
* prot-none, clean, young 111.000001.1 -> 01..1...1...00
|
||||
* prot-none, dirty, old 111.000010.1 -> 10..1...1...00
|
||||
* prot-none, dirty, young 111.000011.1 -> 11..1...1...00
|
||||
* read-only, clean, old 111.000100.1 -> 00..1...1...01
|
||||
* read-only, clean, young 101.000101.1 -> 01..1...0...01
|
||||
* read-only, dirty, old 111.000110.1 -> 10..1...1...01
|
||||
* read-only, dirty, young 101.000111.1 -> 11..1...0...01
|
||||
* read-write, clean, old 111.001100.1 -> 00..1...1...11
|
||||
* read-write, clean, young 101.001101.1 -> 01..1...0...11
|
||||
* read-write, dirty, old 110.001110.1 -> 10..0...1...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)) {
|
||||
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
|
||||
* dy..R...I...wr .IR...wrdytp
|
||||
* empty 00..0...1...00 -> .10...001100
|
||||
* prot-none, clean, old 00..0...1...00 -> .10...000001
|
||||
* prot-none, clean, young 01..0...1...00 -> .10...000101
|
||||
* prot-none, dirty, old 10..0...1...00 -> .10...001001
|
||||
* prot-none, dirty, young 11..0...1...00 -> .10...001101
|
||||
* read-only, clean, old 00..1...1...01 -> .11...010001
|
||||
* read-only, clean, young 01..1...1...01 -> .11...010101
|
||||
* read-only, dirty, old 10..1...1...01 -> .11...011001
|
||||
* read-only, dirty, young 11..1...1...01 -> .11...011101
|
||||
* read-write, clean, old 00..0...1...11 -> .10...110001
|
||||
* read-write, clean, young 01..0...1...11 -> .10...110101
|
||||
* read-write, dirty, old 10..0...1...11 -> .10...111001
|
||||
* read-write, dirty, young 11..0...1...11 -> .10...111101
|
||||
* dy..R...I...wr lIR.uswrdy.p
|
||||
* empty 00..0...1...00 -> 010.000000.0
|
||||
* prot-none, clean, old 00..1...1...00 -> 111.000000.1
|
||||
* prot-none, clean, young 01..1...1...00 -> 111.000001.1
|
||||
* prot-none, dirty, old 10..1...1...00 -> 111.000010.1
|
||||
* prot-none, dirty, young 11..1...1...00 -> 111.000011.1
|
||||
* read-only, clean, old 00..1...1...01 -> 111.000100.1
|
||||
* read-only, clean, young 01..1...0...01 -> 101.000101.1
|
||||
* read-only, dirty, old 10..1...1...01 -> 111.000110.1
|
||||
* read-only, dirty, young 11..1...0...01 -> 101.000111.1
|
||||
* read-write, clean, old 00..1...1...11 -> 111.001100.1
|
||||
* read-write, clean, young 01..1...0...11 -> 101.001101.1
|
||||
* read-write, dirty, old 10..0...1...11 -> 110.001110.1
|
||||
* 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)) {
|
||||
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_INVALID) << 5;
|
||||
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT);
|
||||
pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10;
|
||||
pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10;
|
||||
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) >> 10;
|
||||
pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) >> 10;
|
||||
} else
|
||||
pte_val(pte) = _PAGE_INVALID;
|
||||
return pte;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/swapops.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/ksm.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);
|
||||
|
||||
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 */
|
||||
|
||||
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);
|
||||
unsigned int mask, bit;
|
||||
|
||||
if (mm_has_pgste(mm))
|
||||
if (mm_alloc_pgste(mm))
|
||||
return page_table_alloc_pgste(mm);
|
||||
/* Allocate fragments of a 4K page as 1K/2K page table */
|
||||
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 */
|
||||
|
||||
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)
|
||||
*/
|
||||
int s390_enable_sie(void)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct mm_struct *mm = tsk->mm;
|
||||
struct mmu_gather tlb;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
/* Do we have pgstes? if yes, we are done */
|
||||
if (mm_has_pgste(tsk->mm))
|
||||
if (mm_has_pgste(mm))
|
||||
return 0;
|
||||
|
||||
/* Fail if the page tables are 2K */
|
||||
if (!mm_alloc_pgste(mm))
|
||||
return -EINVAL;
|
||||
down_write(&mm->mmap_sem);
|
||||
mm->context.has_pgste = 1;
|
||||
/* split thp mappings and disable thp for future mappings */
|
||||
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);
|
||||
return mm->context.has_pgste ? 0 : -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s390_enable_sie);
|
||||
|
||||
|
@ -774,7 +774,7 @@ static void __init zone_sizes_init(void)
|
||||
* though, there'll be no lowmem, so we just alloc_bootmem
|
||||
* 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] =
|
||||
alloc_bootmem_pfn(0, memmap_size, 0);
|
||||
BUG_ON(node_percpu[i] != 0);
|
||||
|
@ -1109,6 +1109,8 @@ struct boot_params *make_boot_params(struct efi_config *c)
|
||||
if (!cmdline_ptr)
|
||||
goto fail;
|
||||
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_size = 0;
|
||||
|
@ -50,7 +50,7 @@ extern const struct hypervisor_x86 *x86_hyper;
|
||||
/* Recognized hypervisors */
|
||||
extern const struct hypervisor_x86 x86_hyper_vmware;
|
||||
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 void init_hypervisor(struct cpuinfo_x86 *c);
|
||||
|
@ -95,7 +95,6 @@ unsigned __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src,
|
||||
|
||||
struct pvclock_vsyscall_time_info {
|
||||
struct pvclock_vcpu_time_info pvti;
|
||||
u32 migrate_count;
|
||||
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
|
||||
|
||||
#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
|
||||
|
@ -169,7 +169,7 @@ static inline int arch_spin_is_contended(arch_spinlock_t *lock)
|
||||
struct __raw_tickets tmp = READ_ONCE(lock->tickets);
|
||||
|
||||
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
|
||||
|
||||
|
@ -269,4 +269,9 @@ static inline bool xen_arch_need_swiotlb(struct device *dev,
|
||||
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 */
|
||||
|
@ -27,8 +27,8 @@
|
||||
|
||||
static const __initconst struct hypervisor_x86 * const hypervisors[] =
|
||||
{
|
||||
#ifdef CONFIG_XEN_PVHVM
|
||||
&x86_hyper_xen_hvm,
|
||||
#ifdef CONFIG_XEN
|
||||
&x86_hyper_xen,
|
||||
#endif
|
||||
&x86_hyper_vmware,
|
||||
&x86_hyper_ms_hyperv,
|
||||
|
@ -2533,34 +2533,6 @@ ssize_t intel_event_sysfs_show(char *page, u64 config)
|
||||
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 *regs;
|
||||
@ -2743,6 +2715,44 @@ static struct attribute *intel_arch3_formats_attr[] = {
|
||||
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 = {
|
||||
.name = "Intel",
|
||||
.handle_irq = intel_pmu_handle_irq,
|
||||
|
@ -1,6 +1,13 @@
|
||||
/* Nehalem/SandBridge/Haswell uncore support */
|
||||
#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 */
|
||||
#define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff
|
||||
#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),
|
||||
.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 */ },
|
||||
};
|
||||
|
||||
@ -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_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_U_IMC, &hsw_uncore_pci_driver), /* 4th Gen Core ULT Mobile Processor */
|
||||
{ /* end marker */ }
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,7 @@ __visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, cpu_tss) = {
|
||||
.io_bitmap = { [0 ... IO_BITMAP_LONGS] = ~0 },
|
||||
#endif
|
||||
};
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(cpu_tss);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_tss);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
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. */
|
||||
drop_fpu(tsk);
|
||||
free_thread_xstate(tsk);
|
||||
} else if (!used_math()) {
|
||||
/* kthread execs. TODO: cleanup this horror. */
|
||||
if (WARN_ON(init_fpu(tsk)))
|
||||
force_sig(SIGKILL, tsk);
|
||||
user_fpu_begin();
|
||||
} else {
|
||||
if (!tsk_used_math(tsk)) {
|
||||
/* kthread execs. TODO: cleanup this horror. */
|
||||
if (WARN_ON(init_fpu(tsk)))
|
||||
force_sig(SIGKILL, tsk);
|
||||
user_fpu_begin();
|
||||
}
|
||||
restore_init_xstate();
|
||||
}
|
||||
}
|
||||
|
@ -141,46 +141,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
|
||||
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
|
||||
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
|
||||
* 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);
|
||||
|
||||
pvclock_vdso_info = i;
|
||||
|
||||
for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
|
||||
__set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
|
||||
__pa(i) + (idx*PAGE_SIZE),
|
||||
PAGE_KERNEL_VVAR);
|
||||
}
|
||||
|
||||
|
||||
register_task_migration_notifier(&pvclock_migrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1669,12 +1669,28 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
|
||||
&guest_hv_clock, sizeof(guest_hv_clock))))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The interface expects us to write an even number signaling that the
|
||||
* update is finished. Since the guest won't see the intermediate
|
||||
* state, we just increase by 2 at the end.
|
||||
/* This VCPU is paused, but it's legal for a guest to read another
|
||||
* VCPU's kvmclock, so we really have to follow the specification where
|
||||
* it says that version is odd if data is being modified, and even after
|
||||
* 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 */
|
||||
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,
|
||||
&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;
|
||||
}
|
||||
|
||||
|
@ -351,18 +351,20 @@ int arch_ioremap_pmd_supported(void)
|
||||
*/
|
||||
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(start >> PAGE_SHIFT))
|
||||
return __va(phys);
|
||||
|
||||
addr = (void __force *)ioremap_cache(start, PAGE_SIZE);
|
||||
if (addr)
|
||||
addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
|
||||
vaddr = (unsigned long)ioremap_cache(start, PAGE_SIZE);
|
||||
/* Only add the offset on success and return NULL if the ioremap() failed: */
|
||||
if (vaddr)
|
||||
vaddr += offset;
|
||||
|
||||
return addr;
|
||||
return (void *)vaddr;
|
||||
}
|
||||
|
||||
void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
|
||||
|
@ -325,6 +325,26 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
|
||||
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,
|
||||
struct acpi_device *device,
|
||||
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");
|
||||
else
|
||||
resource_list_for_each_entry_safe(entry, tmp, list) {
|
||||
if ((entry->res->flags & IORESOURCE_WINDOW) == 0 ||
|
||||
(entry->res->flags & IORESOURCE_DISABLED))
|
||||
if ((entry->res->flags & IORESOURCE_DISABLED) ||
|
||||
resource_is_pcicfg_ioport(entry->res))
|
||||
resource_list_destroy_entry(entry);
|
||||
else
|
||||
entry->res->name = info->name;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user