mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Conflicts: drivers/mtd/mtd_blkdevs.c Merge Grant's device-tree bits so that we can apply the subsequent fixes. Signed-off-by: David Woodhouse <[email protected]>
This commit is contained in:
commit
67577927e8
5688 changed files with 329306 additions and 218414 deletions
|
|
@ -138,6 +138,7 @@ config PPC
|
|||
select HAVE_OPROFILE
|
||||
select HAVE_SYSCALL_WRAPPERS if PPC64
|
||||
select GENERIC_ATOMIC64 if PPC32
|
||||
select HAVE_IRQ_WORK
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include <string.h>
|
||||
|
||||
/* CHRP note section */
|
||||
char arch[] = "PowerPC";
|
||||
static const char arch[] = "PowerPC";
|
||||
|
||||
#define N_DESCR 6
|
||||
unsigned int descr[N_DESCR] = {
|
||||
|
|
@ -33,7 +33,7 @@ unsigned int descr[N_DESCR] = {
|
|||
};
|
||||
|
||||
/* RPA note section */
|
||||
char rpaname[] = "IBM,RPA-Client-Config";
|
||||
static const char rpaname[] = "IBM,RPA-Client-Config";
|
||||
|
||||
/*
|
||||
* Note: setting ignore_my_client_config *should* mean that OF ignores
|
||||
|
|
|
|||
254
arch/powerpc/boot/dts/bluestone.dts
Normal file
254
arch/powerpc/boot/dts/bluestone.dts
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Device Tree for Bluestone (APM821xx) board.
|
||||
*
|
||||
* Copyright (c) 2010, Applied Micro Circuits Corporation
|
||||
* Author: Tirumala R Marri <tmarri@apm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
model = "apm,bluestone";
|
||||
compatible = "apm,bluestone";
|
||||
dcr-parent = <&{/cpus/cpu@0}>;
|
||||
|
||||
aliases {
|
||||
ethernet0 = &EMAC0;
|
||||
serial0 = &UART0;
|
||||
serial1 = &UART1;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
model = "PowerPC,apm821xx";
|
||||
reg = <0x00000000>;
|
||||
clock-frequency = <0>; /* Filled in by U-Boot */
|
||||
timebase-frequency = <0>; /* Filled in by U-Boot */
|
||||
i-cache-line-size = <32>;
|
||||
d-cache-line-size = <32>;
|
||||
i-cache-size = <32768>;
|
||||
d-cache-size = <32768>;
|
||||
dcr-controller;
|
||||
dcr-access-method = "native";
|
||||
next-level-cache = <&L2C0>;
|
||||
};
|
||||
};
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
|
||||
};
|
||||
|
||||
UIC0: interrupt-controller0 {
|
||||
compatible = "ibm,uic";
|
||||
interrupt-controller;
|
||||
cell-index = <0>;
|
||||
dcr-reg = <0x0c0 0x009>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
UIC1: interrupt-controller1 {
|
||||
compatible = "ibm,uic";
|
||||
interrupt-controller;
|
||||
cell-index = <1>;
|
||||
dcr-reg = <0x0d0 0x009>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
|
||||
interrupt-parent = <&UIC0>;
|
||||
};
|
||||
|
||||
UIC2: interrupt-controller2 {
|
||||
compatible = "ibm,uic";
|
||||
interrupt-controller;
|
||||
cell-index = <2>;
|
||||
dcr-reg = <0x0e0 0x009>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
|
||||
interrupt-parent = <&UIC0>;
|
||||
};
|
||||
|
||||
UIC3: interrupt-controller3 {
|
||||
compatible = "ibm,uic";
|
||||
interrupt-controller;
|
||||
cell-index = <3>;
|
||||
dcr-reg = <0x0f0 0x009>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
|
||||
interrupt-parent = <&UIC0>;
|
||||
};
|
||||
|
||||
SDR0: sdr {
|
||||
compatible = "ibm,sdr-apm821xx";
|
||||
dcr-reg = <0x00e 0x002>;
|
||||
};
|
||||
|
||||
CPR0: cpr {
|
||||
compatible = "ibm,cpr-apm821xx";
|
||||
dcr-reg = <0x00c 0x002>;
|
||||
};
|
||||
|
||||
plb {
|
||||
compatible = "ibm,plb4";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
clock-frequency = <0>; /* Filled in by U-Boot */
|
||||
|
||||
SDRAM0: sdram {
|
||||
compatible = "ibm,sdram-apm821xx";
|
||||
dcr-reg = <0x010 0x002>;
|
||||
};
|
||||
|
||||
MAL0: mcmal {
|
||||
compatible = "ibm,mcmal2";
|
||||
descriptor-memory = "ocm";
|
||||
dcr-reg = <0x180 0x062>;
|
||||
num-tx-chans = <1>;
|
||||
num-rx-chans = <1>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = <&UIC2>;
|
||||
interrupts = < /*TXEOB*/ 0x6 0x4
|
||||
/*RXEOB*/ 0x7 0x4
|
||||
/*SERR*/ 0x3 0x4
|
||||
/*TXDE*/ 0x4 0x4
|
||||
/*RXDE*/ 0x5 0x4
|
||||
};
|
||||
|
||||
POB0: opb {
|
||||
compatible = "ibm,opb";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
|
||||
clock-frequency = <0>; /* Filled in by U-Boot */
|
||||
|
||||
EBC0: ebc {
|
||||
compatible = "ibm,ebc";
|
||||
dcr-reg = <0x012 0x002>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
clock-frequency = <0>; /* Filled in by U-Boot */
|
||||
/* ranges property is supplied by U-Boot */
|
||||
ranges = < 0x00000003 0x00000000 0xe0000000 0x8000000>;
|
||||
interrupts = <0x6 0x4>;
|
||||
interrupt-parent = <&UIC1>;
|
||||
|
||||
nor_flash@0,0 {
|
||||
compatible = "amd,s29gl512n", "cfi-flash";
|
||||
bank-width = <2>;
|
||||
reg = <0x00000000 0x00000000 0x00400000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
partition@0 {
|
||||
label = "kernel";
|
||||
reg = <0x00000000 0x00180000>;
|
||||
};
|
||||
partition@180000 {
|
||||
label = "env";
|
||||
reg = <0x00180000 0x00020000>;
|
||||
};
|
||||
partition@1a0000 {
|
||||
label = "u-boot";
|
||||
reg = <0x001a0000 0x00060000>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
UART0: serial@ef600300 {
|
||||
device_type = "serial";
|
||||
compatible = "ns16550";
|
||||
reg = <0xef600300 0x00000008>;
|
||||
virtual-reg = <0xef600300>;
|
||||
clock-frequency = <0>; /* Filled in by U-Boot */
|
||||
current-speed = <0>; /* Filled in by U-Boot */
|
||||
interrupt-parent = <&UIC1>;
|
||||
interrupts = <0x1 0x4>;
|
||||
};
|
||||
|
||||
IIC0: i2c@ef600700 {
|
||||
compatible = "ibm,iic";
|
||||
reg = <0xef600700 0x00000014>;
|
||||
interrupt-parent = <&UIC0>;
|
||||
interrupts = <0x2 0x4>;
|
||||
};
|
||||
|
||||
IIC1: i2c@ef600800 {
|
||||
compatible = "ibm,iic";
|
||||
reg = <0xef600800 0x00000014>;
|
||||
interrupt-parent = <&UIC0>;
|
||||
interrupts = <0x3 0x4>;
|
||||
};
|
||||
|
||||
RGMII0: emac-rgmii@ef601500 {
|
||||
compatible = "ibm,rgmii";
|
||||
reg = <0xef601500 0x00000008>;
|
||||
has-mdio;
|
||||
};
|
||||
|
||||
TAH0: emac-tah@ef601350 {
|
||||
compatible = "ibm,tah";
|
||||
reg = <0xef601350 0x00000030>;
|
||||
};
|
||||
|
||||
EMAC0: ethernet@ef600c00 {
|
||||
device_type = "network";
|
||||
compatible = "ibm,emac4sync";
|
||||
interrupt-parent = <&EMAC0>;
|
||||
interrupts = <0x0 0x1>;
|
||||
#interrupt-cells = <1>;
|
||||
#address-cells = <0>;
|
||||
#size-cells = <0>;
|
||||
interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
|
||||
/*Wake*/ 0x1 &UIC2 0x14 0x4>;
|
||||
reg = <0xef600c00 0x000000c4>;
|
||||
local-mac-address = [000000000000]; /* Filled in by U-Boot */
|
||||
mal-device = <&MAL0>;
|
||||
mal-tx-channel = <0>;
|
||||
mal-rx-channel = <0>;
|
||||
cell-index = <0>;
|
||||
max-frame-size = <9000>;
|
||||
rx-fifo-size = <16384>;
|
||||
tx-fifo-size = <2048>;
|
||||
phy-mode = "rgmii";
|
||||
phy-map = <0x00000000>;
|
||||
rgmii-device = <&RGMII0>;
|
||||
rgmii-channel = <0>;
|
||||
tah-device = <&TAH0>;
|
||||
tah-channel = <0>;
|
||||
has-inverted-stacr-oc;
|
||||
has-new-stacr-staopc;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
332
arch/powerpc/boot/dts/mpc8308_p1m.dts
Normal file
332
arch/powerpc/boot/dts/mpc8308_p1m.dts
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* mpc8308_p1m Device Tree Source
|
||||
*
|
||||
* Copyright 2010 Ilya Yanok, Emcraft Systems, yanok@emcraft.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
compatible = "denx,mpc8308_p1m";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
aliases {
|
||||
ethernet0 = &enet0;
|
||||
ethernet1 = &enet1;
|
||||
serial0 = &serial0;
|
||||
serial1 = &serial1;
|
||||
pci0 = &pci0;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
PowerPC,8308@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0x0>;
|
||||
d-cache-line-size = <32>;
|
||||
i-cache-line-size = <32>;
|
||||
d-cache-size = <16384>;
|
||||
i-cache-size = <16384>;
|
||||
timebase-frequency = <0>; // from bootloader
|
||||
bus-frequency = <0>; // from bootloader
|
||||
clock-frequency = <0>; // from bootloader
|
||||
};
|
||||
};
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x08000000>; // 128MB at 0
|
||||
};
|
||||
|
||||
localbus@e0005000 {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
compatible = "fsl,mpc8315-elbc", "fsl,elbc", "simple-bus";
|
||||
reg = <0xe0005000 0x1000>;
|
||||
interrupts = <77 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
|
||||
ranges = <0x0 0x0 0xfc000000 0x04000000
|
||||
0x1 0x0 0xfbff0000 0x00008000
|
||||
0x2 0x0 0xfbff8000 0x00008000>;
|
||||
|
||||
flash@0,0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "cfi-flash";
|
||||
reg = <0x0 0x0 0x4000000>;
|
||||
bank-width = <2>;
|
||||
device-width = <1>;
|
||||
|
||||
u-boot@0 {
|
||||
reg = <0x0 0x60000>;
|
||||
read-only;
|
||||
};
|
||||
env@60000 {
|
||||
reg = <0x60000 0x20000>;
|
||||
};
|
||||
env1@80000 {
|
||||
reg = <0x80000 0x20000>;
|
||||
};
|
||||
kernel@a0000 {
|
||||
reg = <0xa0000 0x200000>;
|
||||
};
|
||||
dtb@2a0000 {
|
||||
reg = <0x2a0000 0x20000>;
|
||||
};
|
||||
ramdisk@2c0000 {
|
||||
reg = <0x2c0000 0x640000>;
|
||||
};
|
||||
user@700000 {
|
||||
reg = <0x700000 0x3900000>;
|
||||
};
|
||||
};
|
||||
|
||||
can@1,0 {
|
||||
compatible = "nxp,sja1000";
|
||||
reg = <0x1 0x0 0x80>;
|
||||
interrupts = <18 0x8>;
|
||||
interrups-parent = <&ipic>;
|
||||
};
|
||||
|
||||
cpld@2,0 {
|
||||
compatible = "denx,mpc8308_p1m-cpld";
|
||||
reg = <0x2 0x0 0x8>;
|
||||
interrupts = <48 0x8>;
|
||||
interrups-parent = <&ipic>;
|
||||
};
|
||||
};
|
||||
|
||||
immr@e0000000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "fsl,mpc8308-immr", "simple-bus";
|
||||
ranges = <0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
||||
i2c@3000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl-i2c";
|
||||
reg = <0x3000 0x100>;
|
||||
interrupts = <14 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
dfsrr;
|
||||
fram@50 {
|
||||
compatible = "ramtron,24c64";
|
||||
reg = <0x50>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@3100 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl-i2c";
|
||||
reg = <0x3100 0x100>;
|
||||
interrupts = <15 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
dfsrr;
|
||||
pwm@28 {
|
||||
compatible = "maxim,ds1050";
|
||||
reg = <0x28>;
|
||||
};
|
||||
sensor@48 {
|
||||
compatible = "maxim,max6625";
|
||||
reg = <0x48>;
|
||||
};
|
||||
sensor@49 {
|
||||
compatible = "maxim,max6625";
|
||||
reg = <0x49>;
|
||||
};
|
||||
sensor@4b {
|
||||
compatible = "maxim,max6625";
|
||||
reg = <0x4b>;
|
||||
};
|
||||
};
|
||||
|
||||
usb@23000 {
|
||||
compatible = "fsl-usb2-dr";
|
||||
reg = <0x23000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = <&ipic>;
|
||||
interrupts = <38 0x8>;
|
||||
dr_mode = "peripheral";
|
||||
phy_type = "ulpi";
|
||||
};
|
||||
|
||||
enet0: ethernet@24000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x0 0x24000 0x1000>;
|
||||
|
||||
cell-index = <0>;
|
||||
device_type = "network";
|
||||
model = "eTSEC";
|
||||
compatible = "gianfar";
|
||||
reg = <0x24000 0x1000>;
|
||||
local-mac-address = [ 00 00 00 00 00 00 ];
|
||||
interrupts = <32 0x8 33 0x8 34 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
phy-handle = < &phy1 >;
|
||||
|
||||
mdio@520 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,gianfar-mdio";
|
||||
reg = <0x520 0x20>;
|
||||
phy1: ethernet-phy@1 {
|
||||
interrupt-parent = <&ipic>;
|
||||
interrupts = <17 0x8>;
|
||||
reg = <0x1>;
|
||||
device_type = "ethernet-phy";
|
||||
};
|
||||
phy2: ethernet-phy@2 {
|
||||
interrupt-parent = <&ipic>;
|
||||
interrupts = <19 0x8>;
|
||||
reg = <0x2>;
|
||||
device_type = "ethernet-phy";
|
||||
};
|
||||
tbi0: tbi-phy@11 {
|
||||
reg = <0x11>;
|
||||
device_type = "tbi-phy";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
enet1: ethernet@25000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
cell-index = <1>;
|
||||
device_type = "network";
|
||||
model = "eTSEC";
|
||||
compatible = "gianfar";
|
||||
reg = <0x25000 0x1000>;
|
||||
ranges = <0x0 0x25000 0x1000>;
|
||||
local-mac-address = [ 00 00 00 00 00 00 ];
|
||||
interrupts = <35 0x8 36 0x8 37 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
phy-handle = < &phy2 >;
|
||||
|
||||
mdio@520 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,gianfar-tbi";
|
||||
reg = <0x520 0x20>;
|
||||
tbi1: tbi-phy@11 {
|
||||
reg = <0x11>;
|
||||
device_type = "tbi-phy";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
serial0: serial@4500 {
|
||||
cell-index = <0>;
|
||||
device_type = "serial";
|
||||
compatible = "ns16550";
|
||||
reg = <0x4500 0x100>;
|
||||
clock-frequency = <133333333>;
|
||||
interrupts = <9 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
};
|
||||
|
||||
serial1: serial@4600 {
|
||||
cell-index = <1>;
|
||||
device_type = "serial";
|
||||
compatible = "ns16550";
|
||||
reg = <0x4600 0x100>;
|
||||
clock-frequency = <133333333>;
|
||||
interrupts = <10 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
};
|
||||
|
||||
gpio@c00 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "fsl,mpc8308-gpio", "fsl,mpc8349-gpio";
|
||||
reg = <0xc00 0x18>;
|
||||
interrupts = <74 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
gpio-controller;
|
||||
};
|
||||
|
||||
timer@500 {
|
||||
compatible = "fsl,mpc8308-gtm", "fsl,gtm";
|
||||
reg = <0x500 0x100>;
|
||||
interrupts = <90 8 78 8 84 8 72 8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
clock-frequency = <133333333>;
|
||||
};
|
||||
|
||||
/* IPIC
|
||||
* interrupts cell = <intr #, sense>
|
||||
* sense values match linux IORESOURCE_IRQ_* defines:
|
||||
* sense == 8: Level, low assertion
|
||||
* sense == 2: Edge, high-to-low change
|
||||
*/
|
||||
ipic: interrupt-controller@700 {
|
||||
compatible = "fsl,ipic";
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0x700 0x100>;
|
||||
device_type = "ipic";
|
||||
};
|
||||
|
||||
ipic-msi@7c0 {
|
||||
compatible = "fsl,ipic-msi";
|
||||
reg = <0x7c0 0x40>;
|
||||
msi-available-ranges = <0x0 0x100>;
|
||||
interrupts = < 0x43 0x8
|
||||
0x4 0x8
|
||||
0x51 0x8
|
||||
0x52 0x8
|
||||
0x56 0x8
|
||||
0x57 0x8
|
||||
0x58 0x8
|
||||
0x59 0x8 >;
|
||||
interrupt-parent = < &ipic >;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
pci0: pcie@e0009000 {
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
device_type = "pci";
|
||||
compatible = "fsl,mpc8308-pcie", "fsl,mpc8314-pcie";
|
||||
reg = <0xe0009000 0x00001000
|
||||
0xb0000000 0x01000000>;
|
||||
ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
|
||||
0x01000000 0 0x00000000 0xb1000000 0 0x00800000>;
|
||||
bus-range = <0 0>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &ipic 1 8>;
|
||||
interrupts = <0x1 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
clock-frequency = <0>;
|
||||
|
||||
pcie@0 {
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
reg = <0 0 0 0 0>;
|
||||
ranges = <0x02000000 0 0xa0000000
|
||||
0x02000000 0 0xa0000000
|
||||
0 0x10000000
|
||||
0x01000000 0 0x00000000
|
||||
0x01000000 0 0x00000000
|
||||
0 0x00800000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -108,6 +108,58 @@
|
|||
};
|
||||
};
|
||||
|
||||
spi@7000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,mpc8536-espi";
|
||||
reg = <0x7000 0x1000>;
|
||||
interrupts = <59 0x2>;
|
||||
interrupt-parent = <&mpic>;
|
||||
fsl,espi-num-chipselects = <4>;
|
||||
|
||||
flash@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "spansion,s25sl12801";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
partition@u-boot {
|
||||
label = "u-boot";
|
||||
reg = <0x00000000 0x00100000>;
|
||||
read-only;
|
||||
};
|
||||
partition@kernel {
|
||||
label = "kernel";
|
||||
reg = <0x00100000 0x00500000>;
|
||||
read-only;
|
||||
};
|
||||
partition@dtb {
|
||||
label = "dtb";
|
||||
reg = <0x00600000 0x00100000>;
|
||||
read-only;
|
||||
};
|
||||
partition@fs {
|
||||
label = "file system";
|
||||
reg = <0x00700000 0x00900000>;
|
||||
};
|
||||
};
|
||||
flash@1 {
|
||||
compatible = "spansion,s25sl12801";
|
||||
reg = <1>;
|
||||
spi-max-frequency = <40000000>;
|
||||
};
|
||||
flash@2 {
|
||||
compatible = "spansion,s25sl12801";
|
||||
reg = <2>;
|
||||
spi-max-frequency = <40000000>;
|
||||
};
|
||||
flash@3 {
|
||||
compatible = "spansion,s25sl12801";
|
||||
reg = <3>;
|
||||
spi-max-frequency = <40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
dma@21300 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
|
|
|||
|
|
@ -148,6 +148,17 @@
|
|||
label = "reserved-nand";
|
||||
};
|
||||
};
|
||||
|
||||
board-control@3,0 {
|
||||
compatible = "fsl,p1022ds-pixis";
|
||||
reg = <3 0 0x30>;
|
||||
interrupt-parent = <&mpic>;
|
||||
/*
|
||||
* IRQ8 is generated if the "EVENT" switch is pressed
|
||||
* and PX_CTL[EVESEL] is set to 00.
|
||||
*/
|
||||
interrupts = <8 8>;
|
||||
};
|
||||
};
|
||||
|
||||
soc@fffe00000 {
|
||||
|
|
|
|||
|
|
@ -236,22 +236,19 @@
|
|||
};
|
||||
|
||||
spi@110000 {
|
||||
cell-index = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,espi";
|
||||
compatible = "fsl,p4080-espi", "fsl,mpc8536-espi";
|
||||
reg = <0x110000 0x1000>;
|
||||
interrupts = <53 0x2>;
|
||||
interrupt-parent = <&mpic>;
|
||||
espi,num-ss-bits = <4>;
|
||||
mode = "cpu";
|
||||
fsl,espi-num-chipselects = <4>;
|
||||
|
||||
fsl_m25p80@0 {
|
||||
flash@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "fsl,espi-flash";
|
||||
compatible = "spansion,s25sl12801";
|
||||
reg = <0>;
|
||||
linux,modalias = "fsl_m25p80";
|
||||
spi-max-frequency = <40000000>; /* input clock */
|
||||
partition@u-boot {
|
||||
label = "u-boot";
|
||||
|
|
|
|||
68
arch/powerpc/configs/44x/bluestone_defconfig
Normal file
68
arch/powerpc/configs/44x/bluestone_defconfig
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
CONFIG_44x=y
|
||||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||
# CONFIG_PCI_QUIRKS is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_BLUESTONE=y
|
||||
# CONFIG_EBONY is not set
|
||||
# CONFIG_KVM_GUEST is not set
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
CONFIG_CMDLINE_BOOL=y
|
||||
CONFIG_CMDLINE=""
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_PNP=y
|
||||
CONFIG_IP_PNP_DHCP=y
|
||||
CONFIG_IP_PNP_BOOTP=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_CONNECTOR=y
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_PARTITIONS=y
|
||||
CONFIG_MTD_CMDLINE_PARTS=y
|
||||
CONFIG_MTD_OF_PARTS=y
|
||||
CONFIG_MTD_CHAR=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_CFI=y
|
||||
CONFIG_MTD_CFI_AMDSTD=y
|
||||
CONFIG_MTD_PHYSMAP_OF=y
|
||||
CONFIG_PROC_DEVICETREE=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=35000
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_NET_ETHERNET=y
|
||||
CONFIG_IBM_NEW_EMAC=y
|
||||
CONFIG_IBM_NEW_EMAC_RXB=256
|
||||
CONFIG_IBM_NEW_EMAC_TXB=256
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_SERIAL_8250_NR_UARTS=2
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_SERIAL_OF_PLATFORM=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_IBM_IIC=y
|
||||
CONFIG_SENSORS_AD7414=y
|
||||
# CONFIG_HID_SUPPORT is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_M41T80=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_CRAMFS=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_NFS_V3=y
|
||||
CONFIG_ROOT_NFS=y
|
||||
CONFIG_NLS=y
|
||||
84
arch/powerpc/configs/e55xx_smp_defconfig
Normal file
84
arch/powerpc/configs/e55xx_smp_defconfig
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
CONFIG_PPC64=y
|
||||
CONFIG_PPC_BOOK3E_64=y
|
||||
# CONFIG_VIRT_CPU_ACCOUNTING is not set
|
||||
CONFIG_SMP=y
|
||||
CONFIG_NR_CPUS=2
|
||||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_SYSFS_DEPRECATED_V2=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
CONFIG_EMBEDDED=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_KALLSYMS_EXTRA_PASS=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
CONFIG_P5020_DS=y
|
||||
# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BINFMT_MISC=m
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
# CONFIG_PCI is not set
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_PROC_DEVICETREE=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=131072
|
||||
CONFIG_EEPROM_LEGACY=y
|
||||
CONFIG_INPUT_FF_MEMLESS=m
|
||||
# CONFIG_INPUT_MOUSEDEV is not set
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_SERIO_LIBPS2=y
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_MANY_PORTS=y
|
||||
CONFIG_SERIAL_8250_DETECT_IRQ=y
|
||||
CONFIG_SERIAL_8250_RSA=y
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_VIDEO_OUTPUT_CONTROL=y
|
||||
# CONFIG_HID_SUPPORT is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_FSL_DMA=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_TMPFS=y
|
||||
# CONFIG_MISC_FILESYSTEMS is not set
|
||||
CONFIG_PARTITION_ADVANCED=y
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NLS_UTF8=m
|
||||
CONFIG_CRC_T10DIF=y
|
||||
CONFIG_CRC_ITU_T=m
|
||||
CONFIG_LIBCRC32C=m
|
||||
CONFIG_FRAME_WARN=1024
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
# CONFIG_DEBUG_BUGVERBOSE is not set
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
|
||||
CONFIG_SYSCTL_SYSCALL_CHECK=y
|
||||
CONFIG_VIRQ_DEBUG=y
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_PCBC=m
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_MD5=y
|
||||
CONFIG_CRYPTO_SHA1=m
|
||||
CONFIG_CRYPTO_DES=y
|
||||
# CONFIG_CRYPTO_ANSI_CPRNG is not set
|
||||
CONFIG_CRYPTO_DEV_TALITOS=y
|
||||
|
|
@ -12,6 +12,7 @@ CONFIG_MODULES=y
|
|||
CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
CONFIG_BAMBOO=y
|
||||
CONFIG_BLUESTONE=y
|
||||
CONFIG_SAM440EP=y
|
||||
CONFIG_SEQUOIA=y
|
||||
CONFIG_TAISHAN=y
|
||||
|
|
@ -97,14 +98,17 @@ CONFIG_USB_STORAGE=m
|
|||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT3_FS=m
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
CONFIG_INOTIFY=y
|
||||
CONFIG_VFAT_FS=m
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_JFFS2_FS=y
|
||||
CONFIG_UBIFS_FS=m
|
||||
CONFIG_UBIFS_FS_XATTR=y
|
||||
CONFIG_LOGFS=m
|
||||
CONFIG_CRAMFS=y
|
||||
CONFIG_SQUASHFS=m
|
||||
CONFIG_SQUASHFS_XATTR=y
|
||||
CONFIG_SQUASHFS_LZO=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_NFS_V3=y
|
||||
CONFIG_ROOT_NFS=y
|
||||
|
|
@ -116,11 +120,8 @@ CONFIG_DEBUG_KERNEL=y
|
|||
CONFIG_DETECT_HUNG_TASK=y
|
||||
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
|
||||
CONFIG_SYSCTL_SYSCALL_CHECK=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_PCBC=y
|
||||
CONFIG_CRYPTO_MD5=y
|
||||
CONFIG_CRYPTO_DES=y
|
||||
# CONFIG_CRYPTO_ANSI_CPRNG is not set
|
||||
# CONFIG_CRYPTO_HW is not set
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ CONFIG_MODULES=y
|
|||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
CONFIG_MODULE_SRCVERSION_ALL=y
|
||||
CONFIG_P5020_DS=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
|
|
@ -256,7 +257,6 @@ CONFIG_HID_ZEROPLUS=y
|
|||
CONFIG_USB=y
|
||||
CONFIG_USB_DEVICEFS=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_EHCI_TT_NEWSCHED=y
|
||||
# CONFIG_USB_EHCI_HCD_PPC_OF is not set
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_STORAGE=m
|
||||
|
|
@ -290,7 +290,6 @@ CONFIG_JFS_POSIX_ACL=y
|
|||
CONFIG_JFS_SECURITY=y
|
||||
CONFIG_XFS_FS=m
|
||||
CONFIG_XFS_POSIX_ACL=y
|
||||
CONFIG_INOTIFY=y
|
||||
CONFIG_AUTOFS4_FS=m
|
||||
CONFIG_ISO9660_FS=y
|
||||
CONFIG_UDF_FS=m
|
||||
|
|
@ -384,7 +383,6 @@ CONFIG_CRYPTO_TGR192=m
|
|||
CONFIG_CRYPTO_WP512=m
|
||||
CONFIG_CRYPTO_AES=m
|
||||
CONFIG_CRYPTO_ANUBIS=m
|
||||
CONFIG_CRYPTO_ARC4=m
|
||||
CONFIG_CRYPTO_BLOWFISH=m
|
||||
CONFIG_CRYPTO_CAST6=m
|
||||
CONFIG_CRYPTO_KHAZAD=m
|
||||
|
|
|
|||
|
|
@ -52,12 +52,22 @@ extern __wsum csum_partial(const void *buff, int len, __wsum sum);
|
|||
extern __wsum csum_partial_copy_generic(const void *src, void *dst,
|
||||
int len, __wsum sum,
|
||||
int *src_err, int *dst_err);
|
||||
|
||||
#ifdef __powerpc64__
|
||||
#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
|
||||
extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
|
||||
int len, __wsum sum, int *err_ptr);
|
||||
#define HAVE_CSUM_COPY_USER
|
||||
extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
|
||||
int len, __wsum sum, int *err_ptr);
|
||||
#else
|
||||
/*
|
||||
* the same as csum_partial, but copies from src to dst while it
|
||||
* checksums.
|
||||
*/
|
||||
#define csum_partial_copy_from_user(src, dst, len, sum, errp) \
|
||||
csum_partial_copy_generic((__force const void *)(src), (dst), (len), (sum), (errp), NULL)
|
||||
#endif
|
||||
|
||||
#define csum_partial_copy_nocheck(src, dst, len, sum) \
|
||||
csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ static inline void __user *arch_compat_alloc_user_space(long len)
|
|||
* We cant access below the stack pointer in the 32bit ABI and
|
||||
* can access 288 bytes in the 64bit ABI
|
||||
*/
|
||||
if (!(test_thread_flag(TIF_32BIT)))
|
||||
if (!is_32bit_task())
|
||||
usp -= 288;
|
||||
|
||||
return (void __user *) (usp - len);
|
||||
|
|
@ -213,7 +213,7 @@ struct compat_shmid64_ds {
|
|||
|
||||
static inline int is_compat_task(void)
|
||||
{
|
||||
return test_thread_flag(TIF_32BIT);
|
||||
return is_32bit_task();
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ extern const char *powerpc_base_platform;
|
|||
#define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
|
||||
#define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0080000000000000)
|
||||
#define CPU_FTR_ASYM_SMT LONG_ASM_CONST(0x0100000000000000)
|
||||
#define CPU_FTR_STCX_CHECKS_ADDRESS LONG_ASM_CONST(0x0200000000000000)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
|
@ -392,28 +393,31 @@ extern const char *powerpc_base_platform;
|
|||
CPU_FTR_MMCRA | CPU_FTR_CTRL)
|
||||
#define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
|
||||
CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ)
|
||||
CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ | \
|
||||
CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
#define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
|
||||
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \
|
||||
CPU_FTR_CP_USE_DCBTZ)
|
||||
CPU_FTR_CP_USE_DCBTZ | CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
#define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
|
||||
CPU_FTR_MMCRA | CPU_FTR_SMT | \
|
||||
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
|
||||
CPU_FTR_PURR)
|
||||
CPU_FTR_PURR | CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
#define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
|
||||
CPU_FTR_MMCRA | CPU_FTR_SMT | \
|
||||
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
|
||||
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
|
||||
CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD)
|
||||
CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \
|
||||
CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
#define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
|
||||
CPU_FTR_MMCRA | CPU_FTR_SMT | \
|
||||
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
|
||||
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
|
||||
CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT)
|
||||
CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \
|
||||
CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
|
||||
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
|
||||
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
|
||||
|
|
|
|||
|
|
@ -127,19 +127,7 @@ static inline int dma_supported(struct device *dev, u64 mask)
|
|||
return dma_ops->dma_supported(dev, mask);
|
||||
}
|
||||
|
||||
static inline int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
{
|
||||
struct dma_map_ops *dma_ops = get_dma_ops(dev);
|
||||
|
||||
if (unlikely(dma_ops == NULL))
|
||||
return -EIO;
|
||||
if (dma_ops->set_dma_mask != NULL)
|
||||
return dma_ops->set_dma_mask(dev, dma_mask);
|
||||
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
|
||||
return -EIO;
|
||||
*dev->dma_mask = dma_mask;
|
||||
return 0;
|
||||
}
|
||||
extern int dma_set_mask(struct device *dev, u64 dma_mask);
|
||||
|
||||
static inline void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ do { \
|
|||
* the 64bit ABI has never had these issues dont enable the workaround
|
||||
* even if we have an executable stack.
|
||||
*/
|
||||
# define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \
|
||||
# define elf_read_implies_exec(ex, exec_stk) (is_32bit_task() ? \
|
||||
(exec_stk == EXSTACK_DEFAULT) : 0)
|
||||
#else
|
||||
# define SET_PERSONALITY(ex) \
|
||||
|
|
|
|||
|
|
@ -137,7 +137,8 @@
|
|||
li r10,0; \
|
||||
ld r11,exception_marker@toc(r2); \
|
||||
std r10,RESULT(r1); /* clear regs->result */ \
|
||||
std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */
|
||||
std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ \
|
||||
ACCOUNT_STOLEN_TIME
|
||||
|
||||
/*
|
||||
* Exception vectors.
|
||||
|
|
|
|||
48
arch/powerpc/include/asm/fsl_85xx_cache_sram.h
Normal file
48
arch/powerpc/include/asm/fsl_85xx_cache_sram.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* Cache SRAM handling for QorIQ platform
|
||||
*
|
||||
* Author: Vivek Mahajan <vivek.mahajan@freescale.com>
|
||||
|
||||
* This file is derived from the original work done
|
||||
* by Sylvain Munaut for the Bestcomm SRAM allocator.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
|
||||
#define __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
|
||||
|
||||
#include <asm/rheap.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/*
|
||||
* Cache-SRAM
|
||||
*/
|
||||
|
||||
struct mpc85xx_cache_sram {
|
||||
phys_addr_t base_phys;
|
||||
void *base_virt;
|
||||
unsigned int size;
|
||||
rh_info_t *rh;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
extern void mpc85xx_cache_sram_free(void *ptr);
|
||||
extern void *mpc85xx_cache_sram_alloc(unsigned int size,
|
||||
phys_addr_t *phys, unsigned int align);
|
||||
|
||||
#endif /* __AMS_POWERPC_FSL_85XX_CACHE_SRAM_H__ */
|
||||
|
|
@ -16,42 +16,57 @@ extern void timer_interrupt(struct pt_regs *);
|
|||
#ifdef CONFIG_PPC64
|
||||
#include <asm/paca.h>
|
||||
|
||||
static inline unsigned long local_get_flags(void)
|
||||
static inline unsigned long arch_local_save_flags(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
__asm__ __volatile__("lbz %0,%1(13)"
|
||||
: "=r" (flags)
|
||||
: "i" (offsetof(struct paca_struct, soft_enabled)));
|
||||
asm volatile(
|
||||
"lbz %0,%1(13)"
|
||||
: "=r" (flags)
|
||||
: "i" (offsetof(struct paca_struct, soft_enabled)));
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline unsigned long raw_local_irq_disable(void)
|
||||
static inline unsigned long arch_local_irq_disable(void)
|
||||
{
|
||||
unsigned long flags, zero;
|
||||
|
||||
__asm__ __volatile__("li %1,0; lbz %0,%2(13); stb %1,%2(13)"
|
||||
: "=r" (flags), "=&r" (zero)
|
||||
: "i" (offsetof(struct paca_struct, soft_enabled))
|
||||
: "memory");
|
||||
asm volatile(
|
||||
"li %1,0; lbz %0,%2(13); stb %1,%2(13)"
|
||||
: "=r" (flags), "=&r" (zero)
|
||||
: "i" (offsetof(struct paca_struct, soft_enabled))
|
||||
: "memory");
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
extern void raw_local_irq_restore(unsigned long);
|
||||
extern void arch_local_irq_restore(unsigned long);
|
||||
extern void iseries_handle_interrupts(void);
|
||||
|
||||
#define raw_local_irq_enable() raw_local_irq_restore(1)
|
||||
#define raw_local_save_flags(flags) ((flags) = local_get_flags())
|
||||
#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable())
|
||||
static inline void arch_local_irq_enable(void)
|
||||
{
|
||||
arch_local_irq_restore(1);
|
||||
}
|
||||
|
||||
#define raw_irqs_disabled() (local_get_flags() == 0)
|
||||
#define raw_irqs_disabled_flags(flags) ((flags) == 0)
|
||||
static inline unsigned long arch_local_irq_save(void)
|
||||
{
|
||||
return arch_local_irq_disable();
|
||||
}
|
||||
|
||||
static inline bool arch_irqs_disabled_flags(unsigned long flags)
|
||||
{
|
||||
return flags == 0;
|
||||
}
|
||||
|
||||
static inline bool arch_irqs_disabled(void)
|
||||
{
|
||||
return arch_irqs_disabled_flags(arch_local_save_flags());
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3E
|
||||
#define __hard_irq_enable() __asm__ __volatile__("wrteei 1": : :"memory");
|
||||
#define __hard_irq_disable() __asm__ __volatile__("wrteei 0": : :"memory");
|
||||
#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory");
|
||||
#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory");
|
||||
#else
|
||||
#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1)
|
||||
#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1)
|
||||
|
|
@ -64,64 +79,66 @@ extern void iseries_handle_interrupts(void);
|
|||
get_paca()->hard_enabled = 0; \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
#else /* CONFIG_PPC64 */
|
||||
|
||||
#if defined(CONFIG_BOOKE)
|
||||
#define SET_MSR_EE(x) mtmsr(x)
|
||||
#define raw_local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
|
||||
#else
|
||||
#define SET_MSR_EE(x) mtmsr(x)
|
||||
#define raw_local_irq_restore(flags) mtmsr(flags)
|
||||
#endif
|
||||
|
||||
static inline void raw_local_irq_disable(void)
|
||||
static inline unsigned long arch_local_save_flags(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOKE
|
||||
__asm__ __volatile__("wrteei 0": : :"memory");
|
||||
#else
|
||||
unsigned long msr;
|
||||
return mfmsr();
|
||||
}
|
||||
|
||||
msr = mfmsr();
|
||||
SET_MSR_EE(msr & ~MSR_EE);
|
||||
static inline void arch_local_irq_restore(unsigned long flags)
|
||||
{
|
||||
#if defined(CONFIG_BOOKE)
|
||||
asm volatile("wrtee %0" : : "r" (flags) : "memory");
|
||||
#else
|
||||
mtmsr(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void raw_local_irq_enable(void)
|
||||
static inline unsigned long arch_local_irq_save(void)
|
||||
{
|
||||
unsigned long flags = arch_local_save_flags();
|
||||
#ifdef CONFIG_BOOKE
|
||||
asm volatile("wrteei 0" : : : "memory");
|
||||
#else
|
||||
SET_MSR_EE(flags & ~MSR_EE);
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void arch_local_irq_disable(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOKE
|
||||
__asm__ __volatile__("wrteei 1": : :"memory");
|
||||
asm volatile("wrteei 0" : : : "memory");
|
||||
#else
|
||||
unsigned long msr;
|
||||
arch_local_irq_save();
|
||||
#endif
|
||||
}
|
||||
|
||||
msr = mfmsr();
|
||||
static inline void arch_local_irq_enable(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOKE
|
||||
asm volatile("wrteei 1" : : : "memory");
|
||||
#else
|
||||
unsigned long msr = mfmsr();
|
||||
SET_MSR_EE(msr | MSR_EE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void raw_local_irq_save_ptr(unsigned long *flags)
|
||||
{
|
||||
unsigned long msr;
|
||||
msr = mfmsr();
|
||||
*flags = msr;
|
||||
#ifdef CONFIG_BOOKE
|
||||
__asm__ __volatile__("wrteei 0": : :"memory");
|
||||
#else
|
||||
SET_MSR_EE(msr & ~MSR_EE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define raw_local_save_flags(flags) ((flags) = mfmsr())
|
||||
#define raw_local_irq_save(flags) raw_local_irq_save_ptr(&flags)
|
||||
#define raw_irqs_disabled() ((mfmsr() & MSR_EE) == 0)
|
||||
#define raw_irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0)
|
||||
|
||||
#define hard_irq_disable() raw_local_irq_disable()
|
||||
|
||||
static inline int irqs_disabled_flags(unsigned long flags)
|
||||
static inline bool arch_irqs_disabled_flags(unsigned long flags)
|
||||
{
|
||||
return (flags & MSR_EE) == 0;
|
||||
}
|
||||
|
||||
static inline bool arch_irqs_disabled(void)
|
||||
{
|
||||
return arch_irqs_disabled_flags(arch_local_save_flags());
|
||||
}
|
||||
|
||||
#define hard_irq_disable() arch_local_irq_disable()
|
||||
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
* © Copyright 1995 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* It's available online from http://chrp.apple.com/MacTech.pdf.
|
||||
* It's available online from http://www.cpu.lu/~mlan/ftp/MacTech.pdf
|
||||
* You can obtain paper copies of this book from computer bookstores or by
|
||||
* writing Morgan Kaufmann Publishers, Inc., 340 Pine Street, Sixth Floor, San
|
||||
* Francisco, CA 94104. Reference ISBN 1-55860-393-X.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* Get definitions for raw_local_save_flags(x), etc.
|
||||
* Get definitions for arch_local_save_flags(x), etc.
|
||||
*/
|
||||
#include <asm/hw_irq.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ extern void machine_kexec_simple(struct kimage *image);
|
|||
extern void crash_kexec_secondary(struct pt_regs *regs);
|
||||
extern int overlaps_crashkernel(unsigned long start, unsigned long size);
|
||||
extern void reserve_crashkernel(void);
|
||||
extern void machine_kexec_mask_interrupts(void);
|
||||
|
||||
#else /* !CONFIG_KEXEC */
|
||||
static inline int kexec_sr_activated(int cpu) { return 0; }
|
||||
|
|
|
|||
|
|
@ -86,5 +86,6 @@ struct kvm_guest_debug_arch {
|
|||
|
||||
#define KVM_INTERRUPT_SET -1U
|
||||
#define KVM_INTERRUPT_UNSET -2U
|
||||
#define KVM_INTERRUPT_SET_LEVEL -3U
|
||||
|
||||
#endif /* __LINUX_KVM_POWERPC_H */
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#define BOOK3S_INTERRUPT_INST_STORAGE 0x400
|
||||
#define BOOK3S_INTERRUPT_INST_SEGMENT 0x480
|
||||
#define BOOK3S_INTERRUPT_EXTERNAL 0x500
|
||||
#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501
|
||||
#define BOOK3S_INTERRUPT_ALIGNMENT 0x600
|
||||
#define BOOK3S_INTERRUPT_PROGRAM 0x700
|
||||
#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800
|
||||
|
|
@ -84,7 +85,8 @@
|
|||
#define BOOK3S_IRQPRIO_EXTERNAL 13
|
||||
#define BOOK3S_IRQPRIO_DECREMENTER 14
|
||||
#define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15
|
||||
#define BOOK3S_IRQPRIO_MAX 16
|
||||
#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 16
|
||||
#define BOOK3S_IRQPRIO_MAX 17
|
||||
|
||||
#define BOOK3S_HFLAG_DCBZ32 0x1
|
||||
#define BOOK3S_HFLAG_SLB 0x2
|
||||
|
|
|
|||
|
|
@ -38,15 +38,6 @@ struct kvmppc_slb {
|
|||
bool class : 1;
|
||||
};
|
||||
|
||||
struct kvmppc_sr {
|
||||
u32 raw;
|
||||
u32 vsid;
|
||||
bool Ks : 1;
|
||||
bool Kp : 1;
|
||||
bool nx : 1;
|
||||
bool valid : 1;
|
||||
};
|
||||
|
||||
struct kvmppc_bat {
|
||||
u64 raw;
|
||||
u32 bepi;
|
||||
|
|
@ -69,6 +60,13 @@ struct kvmppc_sid_map {
|
|||
#define SID_MAP_NUM (1 << SID_MAP_BITS)
|
||||
#define SID_MAP_MASK (SID_MAP_NUM - 1)
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
#define SID_CONTEXTS 1
|
||||
#else
|
||||
#define SID_CONTEXTS 128
|
||||
#define VSID_POOL_SIZE (SID_CONTEXTS * 16)
|
||||
#endif
|
||||
|
||||
struct kvmppc_vcpu_book3s {
|
||||
struct kvm_vcpu vcpu;
|
||||
struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
|
||||
|
|
@ -79,20 +77,22 @@ struct kvmppc_vcpu_book3s {
|
|||
u64 vsid;
|
||||
} slb_shadow[64];
|
||||
u8 slb_shadow_max;
|
||||
struct kvmppc_sr sr[16];
|
||||
struct kvmppc_bat ibat[8];
|
||||
struct kvmppc_bat dbat[8];
|
||||
u64 hid[6];
|
||||
u64 gqr[8];
|
||||
int slb_nr;
|
||||
u32 dsisr;
|
||||
u64 sdr1;
|
||||
u64 hior;
|
||||
u64 msr_mask;
|
||||
u64 vsid_first;
|
||||
u64 vsid_next;
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
u32 vsid_pool[VSID_POOL_SIZE];
|
||||
#else
|
||||
u64 vsid_first;
|
||||
u64 vsid_max;
|
||||
int context_id;
|
||||
#endif
|
||||
int context_id[SID_CONTEXTS];
|
||||
ulong prog_flags; /* flags to inject when giving a 700 trap */
|
||||
};
|
||||
|
||||
|
|
@ -131,9 +131,10 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
|
|||
bool upper, u32 val);
|
||||
extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
|
||||
extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
|
||||
extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
|
||||
|
||||
extern u32 kvmppc_trampoline_lowmem;
|
||||
extern u32 kvmppc_trampoline_enter;
|
||||
extern ulong kvmppc_trampoline_lowmem;
|
||||
extern ulong kvmppc_trampoline_enter;
|
||||
extern void kvmppc_rmcall(ulong srr0, ulong srr1);
|
||||
extern void kvmppc_load_up_fpu(void);
|
||||
extern void kvmppc_load_up_altivec(void);
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ FPD_THREE_IN(fmadd)
|
|||
FPD_THREE_IN(fnmsub)
|
||||
FPD_THREE_IN(fnmadd)
|
||||
|
||||
extern void kvm_cvt_fd(u32 *from, u64 *to, u64 *fpscr);
|
||||
extern void kvm_cvt_df(u64 *from, u32 *to, u64 *fpscr);
|
||||
extern void kvm_cvt_fd(u32 *from, u64 *to);
|
||||
extern void kvm_cvt_df(u64 *from, u32 *to);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kvm_types.h>
|
||||
#include <linux/kvm_para.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
|
||||
#define KVM_MAX_VCPUS 1
|
||||
|
|
@ -41,12 +42,17 @@
|
|||
|
||||
#define HPTEG_CACHE_NUM (1 << 15)
|
||||
#define HPTEG_HASH_BITS_PTE 13
|
||||
#define HPTEG_HASH_BITS_PTE_LONG 12
|
||||
#define HPTEG_HASH_BITS_VPTE 13
|
||||
#define HPTEG_HASH_BITS_VPTE_LONG 5
|
||||
#define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE)
|
||||
#define HPTEG_HASH_NUM_PTE_LONG (1 << HPTEG_HASH_BITS_PTE_LONG)
|
||||
#define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE)
|
||||
#define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG)
|
||||
|
||||
/* Physical Address Mask - allowed range of real mode RAM access */
|
||||
#define KVM_PAM 0x0fffffffffffffffULL
|
||||
|
||||
struct kvm;
|
||||
struct kvm_run;
|
||||
struct kvm_vcpu;
|
||||
|
|
@ -159,8 +165,10 @@ struct kvmppc_mmu {
|
|||
|
||||
struct hpte_cache {
|
||||
struct hlist_node list_pte;
|
||||
struct hlist_node list_pte_long;
|
||||
struct hlist_node list_vpte;
|
||||
struct hlist_node list_vpte_long;
|
||||
struct rcu_head rcu_head;
|
||||
u64 host_va;
|
||||
u64 pfn;
|
||||
ulong slot;
|
||||
|
|
@ -210,28 +218,20 @@ struct kvm_vcpu_arch {
|
|||
u32 cr;
|
||||
#endif
|
||||
|
||||
ulong msr;
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
ulong shadow_msr;
|
||||
ulong hflags;
|
||||
ulong guest_owned_ext;
|
||||
#endif
|
||||
u32 mmucr;
|
||||
ulong sprg0;
|
||||
ulong sprg1;
|
||||
ulong sprg2;
|
||||
ulong sprg3;
|
||||
ulong sprg4;
|
||||
ulong sprg5;
|
||||
ulong sprg6;
|
||||
ulong sprg7;
|
||||
ulong srr0;
|
||||
ulong srr1;
|
||||
ulong csrr0;
|
||||
ulong csrr1;
|
||||
ulong dsrr0;
|
||||
ulong dsrr1;
|
||||
ulong dear;
|
||||
ulong esr;
|
||||
u32 dec;
|
||||
u32 decar;
|
||||
|
|
@ -290,12 +290,17 @@ struct kvm_vcpu_arch {
|
|||
struct tasklet_struct tasklet;
|
||||
u64 dec_jiffies;
|
||||
unsigned long pending_exceptions;
|
||||
struct kvm_vcpu_arch_shared *shared;
|
||||
unsigned long magic_page_pa; /* phys addr to map the magic page to */
|
||||
unsigned long magic_page_ea; /* effect. addr to map the magic page to */
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
|
||||
struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
|
||||
struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
|
||||
struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
|
||||
int hpte_cache_count;
|
||||
spinlock_t mmu_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,16 +20,153 @@
|
|||
#ifndef __POWERPC_KVM_PARA_H__
|
||||
#define __POWERPC_KVM_PARA_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct kvm_vcpu_arch_shared {
|
||||
__u64 scratch1;
|
||||
__u64 scratch2;
|
||||
__u64 scratch3;
|
||||
__u64 critical; /* Guest may not get interrupts if == r1 */
|
||||
__u64 sprg0;
|
||||
__u64 sprg1;
|
||||
__u64 sprg2;
|
||||
__u64 sprg3;
|
||||
__u64 srr0;
|
||||
__u64 srr1;
|
||||
__u64 dar;
|
||||
__u64 msr;
|
||||
__u32 dsisr;
|
||||
__u32 int_pending; /* Tells the guest if we have an interrupt */
|
||||
__u32 sr[16];
|
||||
};
|
||||
|
||||
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
|
||||
#define HC_VENDOR_KVM (42 << 16)
|
||||
#define HC_EV_SUCCESS 0
|
||||
#define HC_EV_UNIMPLEMENTED 12
|
||||
|
||||
#define KVM_FEATURE_MAGIC_PAGE 1
|
||||
|
||||
#define KVM_MAGIC_FEAT_SR (1 << 0)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#ifdef CONFIG_KVM_GUEST
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
static inline int kvm_para_available(void)
|
||||
{
|
||||
struct device_node *hyper_node;
|
||||
|
||||
hyper_node = of_find_node_by_path("/hypervisor");
|
||||
if (!hyper_node)
|
||||
return 0;
|
||||
|
||||
if (!of_device_is_compatible(hyper_node, "linux,kvm"))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern unsigned long kvm_hypercall(unsigned long *in,
|
||||
unsigned long *out,
|
||||
unsigned long nr);
|
||||
|
||||
#else
|
||||
|
||||
static inline int kvm_para_available(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long kvm_hypercall(unsigned long *in,
|
||||
unsigned long *out,
|
||||
unsigned long nr)
|
||||
{
|
||||
return HC_EV_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
|
||||
{
|
||||
unsigned long in[8];
|
||||
unsigned long out[8];
|
||||
unsigned long r;
|
||||
|
||||
r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
|
||||
*r2 = out[0];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline long kvm_hypercall0(unsigned int nr)
|
||||
{
|
||||
unsigned long in[8];
|
||||
unsigned long out[8];
|
||||
|
||||
return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
|
||||
}
|
||||
|
||||
static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
|
||||
{
|
||||
unsigned long in[8];
|
||||
unsigned long out[8];
|
||||
|
||||
in[0] = p1;
|
||||
return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
|
||||
}
|
||||
|
||||
static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
|
||||
unsigned long p2)
|
||||
{
|
||||
unsigned long in[8];
|
||||
unsigned long out[8];
|
||||
|
||||
in[0] = p1;
|
||||
in[1] = p2;
|
||||
return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
|
||||
}
|
||||
|
||||
static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
|
||||
unsigned long p2, unsigned long p3)
|
||||
{
|
||||
unsigned long in[8];
|
||||
unsigned long out[8];
|
||||
|
||||
in[0] = p1;
|
||||
in[1] = p2;
|
||||
in[2] = p3;
|
||||
return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
|
||||
}
|
||||
|
||||
static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
|
||||
unsigned long p2, unsigned long p3,
|
||||
unsigned long p4)
|
||||
{
|
||||
unsigned long in[8];
|
||||
unsigned long out[8];
|
||||
|
||||
in[0] = p1;
|
||||
in[1] = p2;
|
||||
in[2] = p3;
|
||||
in[3] = p4;
|
||||
return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned int kvm_arch_para_features(void)
|
||||
{
|
||||
return 0;
|
||||
unsigned long r;
|
||||
|
||||
if (!kvm_para_available())
|
||||
return 0;
|
||||
|
||||
if(kvm_hypercall0_1(KVM_HC_FEATURES, &r))
|
||||
return 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ extern int kvmppc_booke_init(void);
|
|||
extern void kvmppc_booke_exit(void);
|
||||
|
||||
extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
|
||||
extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu);
|
||||
|
||||
/*
|
||||
* Cuts out inst bits with ordering according to spec.
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ struct lppaca {
|
|||
|
||||
extern struct lppaca lppaca[];
|
||||
|
||||
#define lppaca_of(cpu) (*paca[cpu].lppaca_ptr)
|
||||
|
||||
/*
|
||||
* SLB shadow buffer structure as defined in the PAPR. The save_area
|
||||
* contains adjacent ESID and VSID pairs for each shadowed SLB. The
|
||||
|
|
@ -170,6 +172,33 @@ struct slb_shadow {
|
|||
|
||||
extern struct slb_shadow slb_shadow[];
|
||||
|
||||
/*
|
||||
* Layout of entries in the hypervisor's dispatch trace log buffer.
|
||||
*/
|
||||
struct dtl_entry {
|
||||
u8 dispatch_reason;
|
||||
u8 preempt_reason;
|
||||
u16 processor_id;
|
||||
u32 enqueue_to_dispatch_time;
|
||||
u32 ready_to_enqueue_time;
|
||||
u32 waiting_to_ready_time;
|
||||
u64 timebase;
|
||||
u64 fault_addr;
|
||||
u64 srr0;
|
||||
u64 srr1;
|
||||
};
|
||||
|
||||
#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
|
||||
#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
|
||||
|
||||
/*
|
||||
* When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
|
||||
* reading from the dispatch trace log. If other code wants to consume
|
||||
* DTL entries, it can set this pointer to a function that will get
|
||||
* called once for each DTL entry that gets processed.
|
||||
*/
|
||||
extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
|
||||
|
||||
#endif /* CONFIG_PPC_BOOK3S */
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _ASM_POWERPC_LPPACA_H */
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ struct machdep_calls {
|
|||
void (*pci_dma_dev_setup)(struct pci_dev *dev);
|
||||
void (*pci_dma_bus_setup)(struct pci_bus *bus);
|
||||
|
||||
/* Platform set_dma_mask override */
|
||||
int (*dma_set_mask)(struct device *dev, u64 dma_mask);
|
||||
|
||||
int (*probe)(void);
|
||||
void (*setup_arch)(void); /* Optional, may be NULL */
|
||||
void (*init_early)(void);
|
||||
|
|
|
|||
|
|
@ -5,11 +5,4 @@
|
|||
|
||||
#define MEMBLOCK_DBG(fmt...) udbg_printf(fmt)
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
extern phys_addr_t lowmem_end_addr;
|
||||
#define MEMBLOCK_REAL_LIMIT lowmem_end_addr
|
||||
#else
|
||||
#define MEMBLOCK_REAL_LIMIT 0
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_POWERPC_MEMBLOCK_H */
|
||||
|
|
|
|||
|
|
@ -114,6 +114,17 @@
|
|||
|
||||
#define MAS7_RPN 0xFFFFFFFF
|
||||
|
||||
/* Bit definitions for MMUCFG */
|
||||
#define MMUCFG_MAVN 0x00000003 /* MMU Architecture Version Number */
|
||||
#define MMUCFG_MAVN_V1 0x00000000 /* v1.0 */
|
||||
#define MMUCFG_MAVN_V2 0x00000001 /* v2.0 */
|
||||
#define MMUCFG_NTLBS 0x0000000c /* Number of TLBs */
|
||||
#define MMUCFG_PIDSIZE 0x000007c0 /* PID Reg Size */
|
||||
#define MMUCFG_TWC 0x00008000 /* TLB Write Conditional (v2.0) */
|
||||
#define MMUCFG_LRAT 0x00010000 /* LRAT Supported (v2.0) */
|
||||
#define MMUCFG_RASIZE 0x00fe0000 /* Real Addr Size */
|
||||
#define MMUCFG_LPIDSIZE 0x0f000000 /* LPID Reg Size */
|
||||
|
||||
/* Bit definitions for MMUCSR0 */
|
||||
#define MMUCSR0_TLB1FI 0x00000002 /* TLB1 Flash invalidate */
|
||||
#define MMUCSR0_TLB0FI 0x00000004 /* TLB0 Flash invalidate */
|
||||
|
|
@ -133,6 +144,10 @@
|
|||
#define TLBnCFG_GTWE 0x00010000 /* Guest can write */
|
||||
#define TLBnCFG_IND 0x00020000 /* IND entries supported */
|
||||
#define TLBnCFG_PT 0x00040000 /* Can load from page table */
|
||||
#define TLBnCFG_MINSIZE 0x00f00000 /* Minimum Page Size (v1.0) */
|
||||
#define TLBnCFG_MINSIZE_SHIFT 20
|
||||
#define TLBnCFG_MAXSIZE 0x000f0000 /* Maximum Page Size (v1.0) */
|
||||
#define TLBnCFG_MAXSIZE_SHIFT 16
|
||||
#define TLBnCFG_ASSOC 0xff000000 /* Associativity */
|
||||
|
||||
/* TLBnPS encoding */
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#define _ASM_POWERPC_MMU_H_
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/asm-compat.h>
|
||||
#include <asm/feature-fixups.h>
|
||||
|
||||
|
|
@ -82,6 +84,16 @@ extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
|
|||
extern void early_init_mmu(void);
|
||||
extern void early_init_mmu_secondary(void);
|
||||
|
||||
extern void setup_initial_memory_limit(phys_addr_t first_memblock_base,
|
||||
phys_addr_t first_memblock_size);
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
/* This is our real memory area size on ppc64 server, on embedded, we
|
||||
* make it match the size our of bolted TLB area
|
||||
*/
|
||||
extern u64 ppc64_rma_size;
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
/* The kernel use the constants below to index in the page sizes array.
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ struct paca_struct {
|
|||
u8 kexec_state; /* set when kexec down has irqs off */
|
||||
#ifdef CONFIG_PPC_STD_MMU_64
|
||||
struct slb_shadow *slb_shadow_ptr;
|
||||
struct dtl_entry *dispatch_log;
|
||||
struct dtl_entry *dispatch_log_end;
|
||||
|
||||
/*
|
||||
* Now, starting in cacheline 2, the exception save areas
|
||||
|
|
@ -129,13 +131,19 @@ struct paca_struct {
|
|||
u8 soft_enabled; /* irq soft-enable flag */
|
||||
u8 hard_enabled; /* set if irqs are enabled in MSR */
|
||||
u8 io_sync; /* writel() needs spin_unlock sync */
|
||||
u8 perf_event_pending; /* PM interrupt while soft-disabled */
|
||||
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
|
||||
|
||||
/* Stuff for accurate time accounting */
|
||||
u64 user_time; /* accumulated usermode TB ticks */
|
||||
u64 system_time; /* accumulated system TB ticks */
|
||||
u64 startpurr; /* PURR/TB value snapshot */
|
||||
u64 user_time_scaled; /* accumulated usermode SPURR ticks */
|
||||
u64 starttime; /* TB value snapshot */
|
||||
u64 starttime_user; /* TB value on exit to usermode */
|
||||
u64 startspurr; /* SPURR value snapshot */
|
||||
u64 utime_sspurr; /* ->user_time when ->startspurr set */
|
||||
u64 stolen_time; /* TB ticks taken by hypervisor */
|
||||
u64 dtl_ridx; /* read index in dispatch log */
|
||||
struct dtl_entry *dtl_curr; /* pointer corresponding to dtl_ridx */
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_HANDLER
|
||||
/* We use this to store guest state in */
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ do { \
|
|||
#endif /* !CONFIG_HUGETLB_PAGE */
|
||||
|
||||
#define VM_DATA_DEFAULT_FLAGS \
|
||||
(test_thread_flag(TIF_32BIT) ? \
|
||||
(is_32bit_task() ? \
|
||||
VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
|
||||
|
||||
/*
|
||||
|
|
@ -179,7 +179,7 @@ do { \
|
|||
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
|
||||
|
||||
#define VM_STACK_DEFAULT_FLAGS \
|
||||
(test_thread_flag(TIF_32BIT) ? \
|
||||
(is_32bit_task() ? \
|
||||
VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
|
||||
|
||||
#include <asm-generic/getorder.h>
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ extern void find_and_init_phbs(void);
|
|||
extern struct pci_dev *isa_bridge_pcidev; /* may be NULL if no ISA bus */
|
||||
|
||||
/** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
|
||||
#define BUID_HI(buid) ((buid) >> 32)
|
||||
#define BUID_LO(buid) ((buid) & 0xffffffff)
|
||||
#define BUID_HI(buid) upper_32_bits(buid)
|
||||
#define BUID_LO(buid) lower_32_bits(buid)
|
||||
|
||||
/* PCI device_node operations */
|
||||
struct device_node;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <asm/asm-compat.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ppc-opcode.h>
|
||||
#include <asm/firmware.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#error __FILE__ should only be used in assembler files
|
||||
|
|
@ -26,17 +27,13 @@
|
|||
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
|
||||
#define ACCOUNT_CPU_USER_ENTRY(ra, rb)
|
||||
#define ACCOUNT_CPU_USER_EXIT(ra, rb)
|
||||
#define ACCOUNT_STOLEN_TIME
|
||||
#else
|
||||
#define ACCOUNT_CPU_USER_ENTRY(ra, rb) \
|
||||
beq 2f; /* if from kernel mode */ \
|
||||
BEGIN_FTR_SECTION; \
|
||||
mfspr ra,SPRN_PURR; /* get processor util. reg */ \
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
|
||||
BEGIN_FTR_SECTION; \
|
||||
MFTB(ra); /* or get TB if no PURR */ \
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
|
||||
ld rb,PACA_STARTPURR(r13); \
|
||||
std ra,PACA_STARTPURR(r13); \
|
||||
MFTB(ra); /* get timebase */ \
|
||||
ld rb,PACA_STARTTIME_USER(r13); \
|
||||
std ra,PACA_STARTTIME(r13); \
|
||||
subf rb,rb,ra; /* subtract start value */ \
|
||||
ld ra,PACA_USER_TIME(r13); \
|
||||
add ra,ra,rb; /* add on to user time */ \
|
||||
|
|
@ -44,19 +41,34 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
|
|||
2:
|
||||
|
||||
#define ACCOUNT_CPU_USER_EXIT(ra, rb) \
|
||||
BEGIN_FTR_SECTION; \
|
||||
mfspr ra,SPRN_PURR; /* get processor util. reg */ \
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
|
||||
BEGIN_FTR_SECTION; \
|
||||
MFTB(ra); /* or get TB if no PURR */ \
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
|
||||
ld rb,PACA_STARTPURR(r13); \
|
||||
std ra,PACA_STARTPURR(r13); \
|
||||
MFTB(ra); /* get timebase */ \
|
||||
ld rb,PACA_STARTTIME(r13); \
|
||||
std ra,PACA_STARTTIME_USER(r13); \
|
||||
subf rb,rb,ra; /* subtract start value */ \
|
||||
ld ra,PACA_SYSTEM_TIME(r13); \
|
||||
add ra,ra,rb; /* add on to user time */ \
|
||||
std ra,PACA_SYSTEM_TIME(r13);
|
||||
#endif
|
||||
add ra,ra,rb; /* add on to system time */ \
|
||||
std ra,PACA_SYSTEM_TIME(r13)
|
||||
|
||||
#ifdef CONFIG_PPC_SPLPAR
|
||||
#define ACCOUNT_STOLEN_TIME \
|
||||
BEGIN_FW_FTR_SECTION; \
|
||||
beq 33f; \
|
||||
/* from user - see if there are any DTL entries to process */ \
|
||||
ld r10,PACALPPACAPTR(r13); /* get ptr to VPA */ \
|
||||
ld r11,PACA_DTL_RIDX(r13); /* get log read index */ \
|
||||
ld r10,LPPACA_DTLIDX(r10); /* get log write index */ \
|
||||
cmpd cr1,r11,r10; \
|
||||
beq+ cr1,33f; \
|
||||
bl .accumulate_stolen_time; \
|
||||
33: \
|
||||
END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
|
||||
|
||||
#else /* CONFIG_PPC_SPLPAR */
|
||||
#define ACCOUNT_STOLEN_TIME
|
||||
|
||||
#endif /* CONFIG_PPC_SPLPAR */
|
||||
|
||||
#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
|
||||
|
||||
/*
|
||||
* Macros for storing registers into and loading registers from
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ extern struct task_struct *last_task_used_spe;
|
|||
#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4))
|
||||
#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4))
|
||||
|
||||
#define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)) ? \
|
||||
#define TASK_UNMAPPED_BASE ((is_32bit_task()) ? \
|
||||
TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 )
|
||||
#endif
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ extern struct task_struct *last_task_used_spe;
|
|||
#define STACK_TOP_USER64 TASK_SIZE_USER64
|
||||
#define STACK_TOP_USER32 TASK_SIZE_USER32
|
||||
|
||||
#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
|
||||
#define STACK_TOP (is_32bit_task() ? \
|
||||
STACK_TOP_USER32 : STACK_TOP_USER64)
|
||||
|
||||
#define STACK_TOP_MAX STACK_TOP_USER64
|
||||
|
|
|
|||
|
|
@ -171,6 +171,13 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
|
|||
/* Make modules code happy. We don't set RO yet */
|
||||
#define PAGE_KERNEL_EXEC PAGE_KERNEL_X
|
||||
|
||||
/*
|
||||
* Don't just check for any non zero bits in __PAGE_USER, since for book3e
|
||||
* and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
|
||||
* _PAGE_USER. Need to explictly match _PAGE_BAP_UR bit in that case too.
|
||||
*/
|
||||
#define pte_user(val) ((val & _PAGE_USER) == _PAGE_USER)
|
||||
|
||||
/* Advertise special mapping type for AGP */
|
||||
#define PAGE_AGP (PAGE_KERNEL_NC)
|
||||
#define HAVE_PAGE_AGP
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ extern void rtas_progress(char *s, unsigned short hex);
|
|||
extern void rtas_initialize(void);
|
||||
extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data);
|
||||
extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data);
|
||||
extern int rtas_ibm_suspend_me(struct rtas_args *);
|
||||
|
||||
struct rtc_time;
|
||||
extern unsigned long rtas_get_boot_time(void);
|
||||
|
|
|
|||
|
|
@ -329,3 +329,22 @@ COMPAT_SYS(rt_tgsigqueueinfo)
|
|||
SYSCALL(fanotify_init)
|
||||
COMPAT_SYS(fanotify_mark)
|
||||
SYSCALL_SPU(prlimit64)
|
||||
SYSCALL_SPU(socket)
|
||||
SYSCALL_SPU(bind)
|
||||
SYSCALL_SPU(connect)
|
||||
SYSCALL_SPU(listen)
|
||||
SYSCALL_SPU(accept)
|
||||
SYSCALL_SPU(getsockname)
|
||||
SYSCALL_SPU(getpeername)
|
||||
SYSCALL_SPU(socketpair)
|
||||
SYSCALL_SPU(send)
|
||||
SYSCALL_SPU(sendto)
|
||||
COMPAT_SYS_SPU(recv)
|
||||
COMPAT_SYS_SPU(recvfrom)
|
||||
SYSCALL_SPU(shutdown)
|
||||
COMPAT_SYS_SPU(setsockopt)
|
||||
COMPAT_SYS_SPU(getsockopt)
|
||||
COMPAT_SYS_SPU(sendmsg)
|
||||
COMPAT_SYS_SPU(recvmsg)
|
||||
COMPAT_SYS_SPU(recvmmsg)
|
||||
SYSCALL_SPU(accept4)
|
||||
|
|
|
|||
|
|
@ -154,8 +154,8 @@ extern void enable_kernel_spe(void);
|
|||
extern void giveup_spe(struct task_struct *);
|
||||
extern void load_up_spe(struct task_struct *);
|
||||
extern int fix_alignment(struct pt_regs *);
|
||||
extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
|
||||
extern void cvt_df(double *from, float *to, struct thread_struct *thread);
|
||||
extern void cvt_fd(float *from, double *to);
|
||||
extern void cvt_df(double *from, float *to);
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
extern void discard_lazy_cpu_state(void);
|
||||
|
|
@ -542,10 +542,6 @@ extern void reloc_got2(unsigned long);
|
|||
|
||||
#define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x)))
|
||||
|
||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
|
||||
extern void account_system_vtime(struct task_struct *);
|
||||
#endif
|
||||
|
||||
extern struct dentry *powerpc_debugfs_root;
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ extern void to_tm(int tim, struct rtc_time * tm);
|
|||
extern void GregorianDay(struct rtc_time *tm);
|
||||
|
||||
extern void generic_calibrate_decr(void);
|
||||
extern void snapshot_timebase(void);
|
||||
|
||||
extern void set_dec_cpu6(unsigned int val);
|
||||
|
||||
|
|
@ -212,12 +211,8 @@ struct cpu_usage {
|
|||
DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
|
||||
|
||||
#if defined(CONFIG_VIRT_CPU_ACCOUNTING)
|
||||
extern void calculate_steal_time(void);
|
||||
extern void snapshot_timebases(void);
|
||||
#define account_process_vtime(tsk) account_process_tick(tsk, 0)
|
||||
#else
|
||||
#define calculate_steal_time() do { } while (0)
|
||||
#define snapshot_timebases() do { } while (0)
|
||||
#define account_process_vtime(tsk) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -348,10 +348,29 @@
|
|||
#define __NR_fanotify_init 323
|
||||
#define __NR_fanotify_mark 324
|
||||
#define __NR_prlimit64 325
|
||||
#define __NR_socket 326
|
||||
#define __NR_bind 327
|
||||
#define __NR_connect 328
|
||||
#define __NR_listen 329
|
||||
#define __NR_accept 330
|
||||
#define __NR_getsockname 331
|
||||
#define __NR_getpeername 332
|
||||
#define __NR_socketpair 333
|
||||
#define __NR_send 334
|
||||
#define __NR_sendto 335
|
||||
#define __NR_recv 336
|
||||
#define __NR_recvfrom 337
|
||||
#define __NR_shutdown 338
|
||||
#define __NR_setsockopt 339
|
||||
#define __NR_getsockopt 340
|
||||
#define __NR_sendmsg 341
|
||||
#define __NR_recvmsg 342
|
||||
#define __NR_recvmmsg 343
|
||||
#define __NR_accept4 344
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define __NR_syscalls 326
|
||||
#define __NR_syscalls 345
|
||||
|
||||
#define __NR__exit __NR_exit
|
||||
#define NR_syscalls __NR_syscalls
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ obj-$(CONFIG_IBMVIO) += vio.o
|
|||
obj-$(CONFIG_IBMEBUS) += ibmebus.o
|
||||
obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
|
||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
ifeq ($(CONFIG_PPC32),y)
|
||||
obj-$(CONFIG_E500) += idle_e500.o
|
||||
endif
|
||||
obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
|
||||
obj-$(CONFIG_TAU) += tau_6xx.o
|
||||
obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o
|
||||
|
|
@ -67,7 +69,7 @@ endif
|
|||
obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o
|
||||
obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
|
||||
obj-$(CONFIG_44x) += cpu_setup_44x.o
|
||||
obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o dbell.o
|
||||
obj-$(CONFIG_PPC_FSL_BOOK3E) += cpu_setup_fsl_booke.o dbell.o
|
||||
obj-$(CONFIG_PPC_BOOK3E_64) += dbell.o
|
||||
|
||||
extra-y := head_$(CONFIG_WORD_SIZE).o
|
||||
|
|
@ -127,6 +129,8 @@ ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
|
|||
obj-y += ppc_save_regs.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_KVM_GUEST) += kvm.o kvm_emul.o
|
||||
|
||||
# Disable GCOV in odd or sensitive code
|
||||
GCOV_PROFILE_prom_init.o := n
|
||||
GCOV_PROFILE_ftrace.o := n
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ int fix_alignment(struct pt_regs *regs)
|
|||
#ifdef CONFIG_PPC_FPU
|
||||
preempt_disable();
|
||||
enable_kernel_fp();
|
||||
cvt_df(&data.dd, (float *)&data.v[4], ¤t->thread);
|
||||
cvt_df(&data.dd, (float *)&data.v[4]);
|
||||
preempt_enable();
|
||||
#else
|
||||
return 0;
|
||||
|
|
@ -933,7 +933,7 @@ int fix_alignment(struct pt_regs *regs)
|
|||
#ifdef CONFIG_PPC_FPU
|
||||
preempt_disable();
|
||||
enable_kernel_fp();
|
||||
cvt_fd((float *)&data.v[4], &data.dd, ¤t->thread);
|
||||
cvt_fd((float *)&data.v[4], &data.dd);
|
||||
preempt_enable();
|
||||
#else
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -48,11 +48,11 @@
|
|||
#ifdef CONFIG_PPC_ISERIES
|
||||
#include <asm/iseries/alpaca.h>
|
||||
#endif
|
||||
#ifdef CONFIG_KVM
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST)
|
||||
#include <linux/kvm_host.h>
|
||||
#ifndef CONFIG_BOOKE
|
||||
#include <asm/kvm_book3s.h>
|
||||
#endif
|
||||
#if defined(CONFIG_KVM) && defined(CONFIG_PPC_BOOK3S)
|
||||
#include <asm/kvm_book3s.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FSL_BOOKE)
|
||||
#if defined(CONFIG_PPC_FSL_BOOK3E)
|
||||
#include "../mm/mmu_decl.h"
|
||||
#endif
|
||||
|
||||
|
|
@ -181,17 +181,19 @@ int main(void)
|
|||
offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
|
||||
DEFINE(SLBSHADOW_STACKESID,
|
||||
offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
|
||||
DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
|
||||
DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
|
||||
DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
|
||||
DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
|
||||
DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
|
||||
DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
|
||||
DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx));
|
||||
DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx));
|
||||
#endif /* CONFIG_PPC_STD_MMU_64 */
|
||||
DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
|
||||
DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
|
||||
DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
|
||||
DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr));
|
||||
DEFINE(PACA_STARTSPURR, offsetof(struct paca_struct, startspurr));
|
||||
DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
|
||||
DEFINE(PACA_STARTTIME_USER, offsetof(struct paca_struct, starttime_user));
|
||||
DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
|
||||
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
|
||||
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
|
||||
|
|
@ -394,12 +396,13 @@ int main(void)
|
|||
DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
|
||||
DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
|
||||
DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
|
||||
DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
|
||||
DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
|
||||
DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
|
||||
DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
|
||||
DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
|
||||
DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
|
||||
DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared));
|
||||
DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
|
||||
|
||||
/* book3s */
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
|
|
@ -464,11 +467,27 @@ int main(void)
|
|||
DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
|
||||
#endif /* CONFIG_PPC_BOOK3S */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_GUEST
|
||||
DEFINE(KVM_MAGIC_SCRATCH1, offsetof(struct kvm_vcpu_arch_shared,
|
||||
scratch1));
|
||||
DEFINE(KVM_MAGIC_SCRATCH2, offsetof(struct kvm_vcpu_arch_shared,
|
||||
scratch2));
|
||||
DEFINE(KVM_MAGIC_SCRATCH3, offsetof(struct kvm_vcpu_arch_shared,
|
||||
scratch3));
|
||||
DEFINE(KVM_MAGIC_INT, offsetof(struct kvm_vcpu_arch_shared,
|
||||
int_pending));
|
||||
DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
|
||||
DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared,
|
||||
critical));
|
||||
DEFINE(KVM_MAGIC_SR, offsetof(struct kvm_vcpu_arch_shared, sr));
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_44x
|
||||
DEFINE(PGD_T_LOG2, PGD_T_LOG2);
|
||||
DEFINE(PTE_T_LOG2, PTE_T_LOG2);
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_BOOKE
|
||||
#ifdef CONFIG_PPC_FSL_BOOK3E
|
||||
DEFINE(TLBCAM_SIZE, sizeof(struct tlbcam));
|
||||
DEFINE(TLBCAM_MAS0, offsetof(struct tlbcam, MAS0));
|
||||
DEFINE(TLBCAM_MAS1, offsetof(struct tlbcam, MAS1));
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ _GLOBAL(__setup_cpu_440grx)
|
|||
_GLOBAL(__setup_cpu_460ex)
|
||||
_GLOBAL(__setup_cpu_460gt)
|
||||
_GLOBAL(__setup_cpu_460sx)
|
||||
_GLOBAL(__setup_cpu_apm821xx)
|
||||
mflr r4
|
||||
bl __init_fpu_44x
|
||||
bl __fixup_440A_mcheck
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ _GLOBAL(__e500_dcache_setup)
|
|||
isync
|
||||
blr
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
_GLOBAL(__setup_cpu_e200)
|
||||
/* enable dedicated debug exception handling resources (Debug APU) */
|
||||
mfspr r3,SPRN_HID0
|
||||
|
|
@ -72,3 +73,17 @@ _GLOBAL(__setup_cpu_e500mc)
|
|||
bl __setup_e500mc_ivors
|
||||
mtlr r4
|
||||
blr
|
||||
#endif
|
||||
/* Right now, restore and setup are the same thing */
|
||||
_GLOBAL(__restore_cpu_e5500)
|
||||
_GLOBAL(__setup_cpu_e5500)
|
||||
mflr r4
|
||||
bl __e500_icache_setup
|
||||
bl __e500_dcache_setup
|
||||
#ifdef CONFIG_PPC_BOOK3E_64
|
||||
bl .__setup_base_ivors
|
||||
#else
|
||||
bl __setup_e500mc_ivors
|
||||
#endif
|
||||
mtlr r4
|
||||
blr
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec);
|
|||
extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec);
|
||||
extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec);
|
||||
extern void __setup_cpu_460sx(unsigned long offset, struct cpu_spec *spec);
|
||||
extern void __setup_cpu_apm821xx(unsigned long offset, struct cpu_spec *spec);
|
||||
extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
|
||||
extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
|
||||
extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
|
||||
|
|
@ -66,6 +67,10 @@ extern void __restore_cpu_ppc970(void);
|
|||
extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
|
||||
extern void __restore_cpu_power7(void);
|
||||
#endif /* CONFIG_PPC64 */
|
||||
#if defined(CONFIG_E500)
|
||||
extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
|
||||
extern void __restore_cpu_e5500(void);
|
||||
#endif /* CONFIG_E500 */
|
||||
|
||||
/* This table only contains "desktop" CPUs, it need to be filled with embedded
|
||||
* ones as well...
|
||||
|
|
@ -1805,6 +1810,20 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.machine_check = machine_check_440A,
|
||||
.platform = "ppc440",
|
||||
},
|
||||
{ /* 464 in APM821xx */
|
||||
.pvr_mask = 0xffffff00,
|
||||
.pvr_value = 0x12C41C80,
|
||||
.cpu_name = "APM821XX",
|
||||
.cpu_features = CPU_FTRS_44X,
|
||||
.cpu_user_features = COMMON_USER_BOOKE |
|
||||
PPC_FEATURE_HAS_FPU,
|
||||
.mmu_features = MMU_FTR_TYPE_44x,
|
||||
.icache_bsize = 32,
|
||||
.dcache_bsize = 32,
|
||||
.cpu_setup = __setup_cpu_apm821xx,
|
||||
.machine_check = machine_check_440A,
|
||||
.platform = "ppc440",
|
||||
},
|
||||
{ /* 476 core */
|
||||
.pvr_mask = 0xffff0000,
|
||||
.pvr_value = 0x11a50000,
|
||||
|
|
@ -1891,7 +1910,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.platform = "ppc5554",
|
||||
}
|
||||
#endif /* CONFIG_E200 */
|
||||
#endif /* CONFIG_PPC32 */
|
||||
#ifdef CONFIG_E500
|
||||
#ifdef CONFIG_PPC32
|
||||
{ /* e500 */
|
||||
.pvr_mask = 0xffff0000,
|
||||
.pvr_value = 0x80200000,
|
||||
|
|
@ -1946,6 +1967,26 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.machine_check = machine_check_e500mc,
|
||||
.platform = "ppce500mc",
|
||||
},
|
||||
#endif /* CONFIG_PPC32 */
|
||||
{ /* e5500 */
|
||||
.pvr_mask = 0xffff0000,
|
||||
.pvr_value = 0x80240000,
|
||||
.cpu_name = "e5500",
|
||||
.cpu_features = CPU_FTRS_E500MC,
|
||||
.cpu_user_features = COMMON_USER_BOOKE,
|
||||
.mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
|
||||
MMU_FTR_USE_TLBILX,
|
||||
.icache_bsize = 64,
|
||||
.dcache_bsize = 64,
|
||||
.num_pmcs = 4,
|
||||
.oprofile_cpu_type = "ppc/e500mc",
|
||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||
.cpu_setup = __setup_cpu_e5500,
|
||||
.cpu_restore = __restore_cpu_e5500,
|
||||
.machine_check = machine_check_e500mc,
|
||||
.platform = "ppce5500",
|
||||
},
|
||||
#ifdef CONFIG_PPC32
|
||||
{ /* default match */
|
||||
.pvr_mask = 0x00000000,
|
||||
.pvr_value = 0x00000000,
|
||||
|
|
@ -1960,8 +2001,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.machine_check = machine_check_e500,
|
||||
.platform = "powerpc",
|
||||
}
|
||||
#endif /* CONFIG_E500 */
|
||||
#endif /* CONFIG_PPC32 */
|
||||
#endif /* CONFIG_E500 */
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3E_64
|
||||
{ /* This is a default entry to get going, to be replaced by
|
||||
|
|
|
|||
|
|
@ -414,18 +414,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
|
|||
crash_kexec_wait_realmode(crashing_cpu);
|
||||
#endif
|
||||
|
||||
for_each_irq(i) {
|
||||
struct irq_desc *desc = irq_to_desc(i);
|
||||
|
||||
if (!desc || !desc->chip || !desc->chip->eoi)
|
||||
continue;
|
||||
|
||||
if (desc->status & IRQ_INPROGRESS)
|
||||
desc->chip->eoi(i);
|
||||
|
||||
if (!(desc->status & IRQ_DISABLED))
|
||||
desc->chip->shutdown(i);
|
||||
}
|
||||
machine_kexec_mask_interrupts();
|
||||
|
||||
/*
|
||||
* Call registered shutdown routines savely. Swap out
|
||||
|
|
|
|||
|
|
@ -74,16 +74,17 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask)
|
|||
{
|
||||
struct iommu_table *tbl = get_iommu_table_base(dev);
|
||||
|
||||
if (!tbl || tbl->it_offset > mask) {
|
||||
printk(KERN_INFO
|
||||
"Warning: IOMMU offset too big for device mask\n");
|
||||
if (tbl)
|
||||
printk(KERN_INFO
|
||||
"mask: 0x%08llx, table offset: 0x%08lx\n",
|
||||
mask, tbl->it_offset);
|
||||
else
|
||||
printk(KERN_INFO "mask: 0x%08llx, table unavailable\n",
|
||||
mask);
|
||||
if (!tbl) {
|
||||
dev_info(dev, "Warning: IOMMU dma not supported: mask 0x%08llx"
|
||||
", table unavailable\n", mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((tbl->it_offset + tbl->it_size) > (mask >> IOMMU_PAGE_SHIFT)) {
|
||||
dev_info(dev, "Warning: IOMMU window too big for device mask\n");
|
||||
dev_info(dev, "mask: 0x%08llx, table end: 0x%08lx\n",
|
||||
mask, (tbl->it_offset + tbl->it_size) <<
|
||||
IOMMU_PAGE_SHIFT);
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/memblock.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/abs_addr.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
/*
|
||||
* Generic direct DMA implementation
|
||||
|
|
@ -89,7 +90,7 @@ static int dma_direct_dma_supported(struct device *dev, u64 mask)
|
|||
/* Could be improved so platforms can set the limit in case
|
||||
* they have limited DMA windows
|
||||
*/
|
||||
return mask >= (memblock_end_of_DRAM() - 1);
|
||||
return mask >= get_dma_offset(dev) + (memblock_end_of_DRAM() - 1);
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
|
|
@ -154,6 +155,23 @@ EXPORT_SYMBOL(dma_direct_ops);
|
|||
|
||||
#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
|
||||
|
||||
int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
{
|
||||
struct dma_map_ops *dma_ops = get_dma_ops(dev);
|
||||
|
||||
if (ppc_md.dma_set_mask)
|
||||
return ppc_md.dma_set_mask(dev, dma_mask);
|
||||
if (unlikely(dma_ops == NULL))
|
||||
return -EIO;
|
||||
if (dma_ops->set_dma_mask != NULL)
|
||||
return dma_ops->set_dma_mask(dev, dma_mask);
|
||||
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
|
||||
return -EIO;
|
||||
*dev->dma_mask = dma_mask;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_set_mask);
|
||||
|
||||
static int __init dma_init(void)
|
||||
{
|
||||
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
|
||||
|
|
|
|||
|
|
@ -97,6 +97,24 @@ system_call_common:
|
|||
addi r9,r1,STACK_FRAME_OVERHEAD
|
||||
ld r11,exception_marker@toc(r2)
|
||||
std r11,-16(r9) /* "regshere" marker */
|
||||
#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)
|
||||
BEGIN_FW_FTR_SECTION
|
||||
beq 33f
|
||||
/* if from user, see if there are any DTL entries to process */
|
||||
ld r10,PACALPPACAPTR(r13) /* get ptr to VPA */
|
||||
ld r11,PACA_DTL_RIDX(r13) /* get log read index */
|
||||
ld r10,LPPACA_DTLIDX(r10) /* get log write index */
|
||||
cmpd cr1,r11,r10
|
||||
beq+ cr1,33f
|
||||
bl .accumulate_stolen_time
|
||||
REST_GPR(0,r1)
|
||||
REST_4GPRS(3,r1)
|
||||
REST_2GPRS(7,r1)
|
||||
addi r9,r1,STACK_FRAME_OVERHEAD
|
||||
33:
|
||||
END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
|
||||
#endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */
|
||||
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
bl .trace_hardirqs_on
|
||||
REST_GPR(0,r1)
|
||||
|
|
@ -202,7 +220,9 @@ syscall_exit:
|
|||
bge- syscall_error
|
||||
syscall_error_cont:
|
||||
ld r7,_NIP(r1)
|
||||
BEGIN_FTR_SECTION
|
||||
stdcx. r0,0,r1 /* to clear the reservation */
|
||||
END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
andi. r6,r8,MSR_PR
|
||||
ld r4,_LINK(r1)
|
||||
/*
|
||||
|
|
@ -419,6 +439,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
|||
sync
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
/*
|
||||
* If we optimise away the clear of the reservation in system
|
||||
* calls because we know the CPU tracks the address of the
|
||||
* reservation, then we need to clear it here to cover the
|
||||
* case that the kernel context switch path has no larx
|
||||
* instructions.
|
||||
*/
|
||||
BEGIN_FTR_SECTION
|
||||
ldarx r6,0,r1
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
|
||||
addi r6,r4,-THREAD /* Convert THREAD to 'current' */
|
||||
std r6,PACACURRENT(r13) /* Set new 'current' */
|
||||
|
||||
|
|
@ -576,7 +607,16 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
|
|||
andi. r0,r3,MSR_RI
|
||||
beq- unrecov_restore
|
||||
|
||||
/*
|
||||
* Clear the reservation. If we know the CPU tracks the address of
|
||||
* the reservation then we can potentially save some cycles and use
|
||||
* a larx. On POWER6 and POWER7 this is significantly faster.
|
||||
*/
|
||||
BEGIN_FTR_SECTION
|
||||
stdcx. r0,0,r1 /* to clear the reservation */
|
||||
FTR_SECTION_ELSE
|
||||
ldarx r4,0,r1
|
||||
ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
|
||||
|
||||
/*
|
||||
* Clear RI before restoring r13. If we are returning to
|
||||
|
|
|
|||
|
|
@ -299,6 +299,12 @@ slb_miss_user_pseries:
|
|||
b . /* prevent spec. execution */
|
||||
#endif /* __DISABLED__ */
|
||||
|
||||
/* KVM's trampoline code needs to be close to the interrupt handlers */
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
|
||||
#include "../kvm/book3s_rmhandlers.S"
|
||||
#endif
|
||||
|
||||
.align 7
|
||||
.globl __end_interrupts
|
||||
__end_interrupts:
|
||||
|
|
@ -818,12 +824,12 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
|
|||
|
||||
/*
|
||||
* hash_page couldn't handle it, set soft interrupt enable back
|
||||
* to what it was before the trap. Note that .raw_local_irq_restore
|
||||
* to what it was before the trap. Note that .arch_local_irq_restore
|
||||
* handles any interrupts pending at this point.
|
||||
*/
|
||||
ld r3,SOFTE(r1)
|
||||
TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f)
|
||||
bl .raw_local_irq_restore
|
||||
bl .arch_local_irq_restore
|
||||
b 11f
|
||||
|
||||
/* We have a data breakpoint exception - handle it */
|
||||
|
|
|
|||
|
|
@ -163,24 +163,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
|
|||
/*
|
||||
* These are used in the alignment trap handler when emulating
|
||||
* single-precision loads and stores.
|
||||
* We restore and save the fpscr so the task gets the same result
|
||||
* and exceptions as if the cpu had performed the load or store.
|
||||
*/
|
||||
|
||||
_GLOBAL(cvt_fd)
|
||||
lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */
|
||||
MTFSF_L(0)
|
||||
lfs 0,0(r3)
|
||||
stfd 0,0(r4)
|
||||
mffs 0
|
||||
stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */
|
||||
blr
|
||||
|
||||
_GLOBAL(cvt_df)
|
||||
lfd 0,THREAD_FPSCR(r5) /* load up fpscr value */
|
||||
MTFSF_L(0)
|
||||
lfd 0,0(r3)
|
||||
stfs 0,0(r4)
|
||||
mffs 0
|
||||
stfd 0,THREAD_FPSCR(r5) /* save new fpscr value */
|
||||
blr
|
||||
|
|
|
|||
|
|
@ -923,11 +923,7 @@ initial_mmu:
|
|||
mtspr SPRN_PID,r0
|
||||
sync
|
||||
|
||||
/* Configure and load two entries into TLB slots 62 and 63.
|
||||
* In case we are pinning TLBs, these are reserved in by the
|
||||
* other TLB functions. If not reserving, then it doesn't
|
||||
* matter where they are loaded.
|
||||
*/
|
||||
/* Configure and load one entry into TLB slots 63 */
|
||||
clrrwi r4,r4,10 /* Mask off the real page number */
|
||||
ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
|
||||
|
||||
|
|
|
|||
|
|
@ -166,12 +166,6 @@ exception_marker:
|
|||
#include "exceptions-64s.S"
|
||||
#endif
|
||||
|
||||
/* KVM trampoline code needs to be close to the interrupt handlers */
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
|
||||
#include "../kvm/book3s_rmhandlers.S"
|
||||
#endif
|
||||
|
||||
_GLOBAL(generic_secondary_thread_init)
|
||||
mr r24,r3
|
||||
|
||||
|
|
|
|||
|
|
@ -152,8 +152,11 @@ _ENTRY(__early_start)
|
|||
/* Check to see if we're the second processor, and jump
|
||||
* to the secondary_start code if so
|
||||
*/
|
||||
mfspr r24,SPRN_PIR
|
||||
cmpwi r24,0
|
||||
lis r24, boot_cpuid@h
|
||||
ori r24, r24, boot_cpuid@l
|
||||
lwz r24, 0(r24)
|
||||
cmpwi r24, -1
|
||||
mfspr r24,SPRN_PIR
|
||||
bne __secondary_start
|
||||
#endif
|
||||
|
||||
|
|
@ -175,6 +178,9 @@ _ENTRY(__early_start)
|
|||
li r0,0
|
||||
stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
|
||||
|
||||
rlwinm r22,r1,0,0,31-THREAD_SHIFT /* current thread_info */
|
||||
stw r24, TI_CPU(r22)
|
||||
|
||||
bl early_init
|
||||
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
|
|
|
|||
|
|
@ -162,13 +162,10 @@ static int ibmebus_create_device(struct device_node *dn)
|
|||
dev->dev.bus = &ibmebus_bus_type;
|
||||
dev->dev.archdata.dma_ops = &ibmebus_dma_ops;
|
||||
|
||||
ret = of_device_register(dev);
|
||||
if (ret) {
|
||||
of_device_free(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = of_device_add(dev);
|
||||
if (ret)
|
||||
platform_device_put(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ibmebus_create_devices(const struct of_device_id *matches)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static inline notrace void set_soft_enabled(unsigned long enable)
|
|||
: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
|
||||
}
|
||||
|
||||
notrace void raw_local_irq_restore(unsigned long en)
|
||||
notrace void arch_local_irq_restore(unsigned long en)
|
||||
{
|
||||
/*
|
||||
* get_paca()->soft_enabled = en;
|
||||
|
|
@ -192,7 +192,7 @@ notrace void raw_local_irq_restore(unsigned long en)
|
|||
|
||||
__hard_irq_enable();
|
||||
}
|
||||
EXPORT_SYMBOL(raw_local_irq_restore);
|
||||
EXPORT_SYMBOL(arch_local_irq_restore);
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
static int show_other_interrupts(struct seq_file *p, int prec)
|
||||
|
|
@ -587,8 +587,10 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
|
|||
* this will be fixed once slab is made available early
|
||||
* instead of the current cruft
|
||||
*/
|
||||
if (mem_init_done)
|
||||
if (mem_init_done) {
|
||||
of_node_put(host->of_node);
|
||||
kfree(host);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
irq_map[0].host = host;
|
||||
|
|
@ -1143,7 +1145,7 @@ static int virq_debug_show(struct seq_file *m, void *private)
|
|||
unsigned long flags;
|
||||
struct irq_desc *desc;
|
||||
const char *p;
|
||||
char none[] = "none";
|
||||
static const char none[] = "none";
|
||||
int i;
|
||||
|
||||
seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq",
|
||||
|
|
|
|||
596
arch/powerpc/kernel/kvm.c
Normal file
596
arch/powerpc/kernel/kvm.c
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
/*
|
||||
* Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Graf <agraf@suse.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 Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kvm_para.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/reg.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/disassemble.h>
|
||||
|
||||
#define KVM_MAGIC_PAGE (-4096L)
|
||||
#define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
|
||||
|
||||
#define KVM_INST_LWZ 0x80000000
|
||||
#define KVM_INST_STW 0x90000000
|
||||
#define KVM_INST_LD 0xe8000000
|
||||
#define KVM_INST_STD 0xf8000000
|
||||
#define KVM_INST_NOP 0x60000000
|
||||
#define KVM_INST_B 0x48000000
|
||||
#define KVM_INST_B_MASK 0x03ffffff
|
||||
#define KVM_INST_B_MAX 0x01ffffff
|
||||
|
||||
#define KVM_MASK_RT 0x03e00000
|
||||
#define KVM_RT_30 0x03c00000
|
||||
#define KVM_MASK_RB 0x0000f800
|
||||
#define KVM_INST_MFMSR 0x7c0000a6
|
||||
#define KVM_INST_MFSPR_SPRG0 0x7c1042a6
|
||||
#define KVM_INST_MFSPR_SPRG1 0x7c1142a6
|
||||
#define KVM_INST_MFSPR_SPRG2 0x7c1242a6
|
||||
#define KVM_INST_MFSPR_SPRG3 0x7c1342a6
|
||||
#define KVM_INST_MFSPR_SRR0 0x7c1a02a6
|
||||
#define KVM_INST_MFSPR_SRR1 0x7c1b02a6
|
||||
#define KVM_INST_MFSPR_DAR 0x7c1302a6
|
||||
#define KVM_INST_MFSPR_DSISR 0x7c1202a6
|
||||
|
||||
#define KVM_INST_MTSPR_SPRG0 0x7c1043a6
|
||||
#define KVM_INST_MTSPR_SPRG1 0x7c1143a6
|
||||
#define KVM_INST_MTSPR_SPRG2 0x7c1243a6
|
||||
#define KVM_INST_MTSPR_SPRG3 0x7c1343a6
|
||||
#define KVM_INST_MTSPR_SRR0 0x7c1a03a6
|
||||
#define KVM_INST_MTSPR_SRR1 0x7c1b03a6
|
||||
#define KVM_INST_MTSPR_DAR 0x7c1303a6
|
||||
#define KVM_INST_MTSPR_DSISR 0x7c1203a6
|
||||
|
||||
#define KVM_INST_TLBSYNC 0x7c00046c
|
||||
#define KVM_INST_MTMSRD_L0 0x7c000164
|
||||
#define KVM_INST_MTMSRD_L1 0x7c010164
|
||||
#define KVM_INST_MTMSR 0x7c000124
|
||||
|
||||
#define KVM_INST_WRTEEI_0 0x7c000146
|
||||
#define KVM_INST_WRTEEI_1 0x7c008146
|
||||
|
||||
#define KVM_INST_MTSRIN 0x7c0001e4
|
||||
|
||||
static bool kvm_patching_worked = true;
|
||||
static char kvm_tmp[1024 * 1024];
|
||||
static int kvm_tmp_index;
|
||||
|
||||
static inline void kvm_patch_ins(u32 *inst, u32 new_inst)
|
||||
{
|
||||
*inst = new_inst;
|
||||
flush_icache_range((ulong)inst, (ulong)inst + 4);
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_ll(u32 *inst, long addr, u32 rt)
|
||||
{
|
||||
#ifdef CONFIG_64BIT
|
||||
kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
|
||||
#else
|
||||
kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000fffc));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_ld(u32 *inst, long addr, u32 rt)
|
||||
{
|
||||
#ifdef CONFIG_64BIT
|
||||
kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
|
||||
#else
|
||||
kvm_patch_ins(inst, KVM_INST_LWZ | rt | ((addr + 4) & 0x0000fffc));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_lwz(u32 *inst, long addr, u32 rt)
|
||||
{
|
||||
kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000ffff));
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_std(u32 *inst, long addr, u32 rt)
|
||||
{
|
||||
#ifdef CONFIG_64BIT
|
||||
kvm_patch_ins(inst, KVM_INST_STD | rt | (addr & 0x0000fffc));
|
||||
#else
|
||||
kvm_patch_ins(inst, KVM_INST_STW | rt | ((addr + 4) & 0x0000fffc));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_stw(u32 *inst, long addr, u32 rt)
|
||||
{
|
||||
kvm_patch_ins(inst, KVM_INST_STW | rt | (addr & 0x0000fffc));
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_nop(u32 *inst)
|
||||
{
|
||||
kvm_patch_ins(inst, KVM_INST_NOP);
|
||||
}
|
||||
|
||||
static void kvm_patch_ins_b(u32 *inst, int addr)
|
||||
{
|
||||
#ifdef CONFIG_RELOCATABLE
|
||||
/* On relocatable kernels interrupts handlers and our code
|
||||
can be in different regions, so we don't patch them */
|
||||
|
||||
extern u32 __end_interrupts;
|
||||
if ((ulong)inst < (ulong)&__end_interrupts)
|
||||
return;
|
||||
#endif
|
||||
|
||||
kvm_patch_ins(inst, KVM_INST_B | (addr & KVM_INST_B_MASK));
|
||||
}
|
||||
|
||||
static u32 *kvm_alloc(int len)
|
||||
{
|
||||
u32 *p;
|
||||
|
||||
if ((kvm_tmp_index + len) > ARRAY_SIZE(kvm_tmp)) {
|
||||
printk(KERN_ERR "KVM: No more space (%d + %d)\n",
|
||||
kvm_tmp_index, len);
|
||||
kvm_patching_worked = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = (void*)&kvm_tmp[kvm_tmp_index];
|
||||
kvm_tmp_index += len;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
extern u32 kvm_emulate_mtmsrd_branch_offs;
|
||||
extern u32 kvm_emulate_mtmsrd_reg_offs;
|
||||
extern u32 kvm_emulate_mtmsrd_orig_ins_offs;
|
||||
extern u32 kvm_emulate_mtmsrd_len;
|
||||
extern u32 kvm_emulate_mtmsrd[];
|
||||
|
||||
static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
|
||||
{
|
||||
u32 *p;
|
||||
int distance_start;
|
||||
int distance_end;
|
||||
ulong next_inst;
|
||||
|
||||
p = kvm_alloc(kvm_emulate_mtmsrd_len * 4);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
/* Find out where we are and put everything there */
|
||||
distance_start = (ulong)p - (ulong)inst;
|
||||
next_inst = ((ulong)inst + 4);
|
||||
distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs];
|
||||
|
||||
/* Make sure we only write valid b instructions */
|
||||
if (distance_start > KVM_INST_B_MAX) {
|
||||
kvm_patching_worked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Modify the chunk to fit the invocation */
|
||||
memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4);
|
||||
p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK;
|
||||
switch (get_rt(rt)) {
|
||||
case 30:
|
||||
kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
|
||||
magic_var(scratch2), KVM_RT_30);
|
||||
break;
|
||||
case 31:
|
||||
kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
|
||||
magic_var(scratch1), KVM_RT_30);
|
||||
break;
|
||||
default:
|
||||
p[kvm_emulate_mtmsrd_reg_offs] |= rt;
|
||||
break;
|
||||
}
|
||||
|
||||
p[kvm_emulate_mtmsrd_orig_ins_offs] = *inst;
|
||||
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4);
|
||||
|
||||
/* Patch the invocation */
|
||||
kvm_patch_ins_b(inst, distance_start);
|
||||
}
|
||||
|
||||
extern u32 kvm_emulate_mtmsr_branch_offs;
|
||||
extern u32 kvm_emulate_mtmsr_reg1_offs;
|
||||
extern u32 kvm_emulate_mtmsr_reg2_offs;
|
||||
extern u32 kvm_emulate_mtmsr_orig_ins_offs;
|
||||
extern u32 kvm_emulate_mtmsr_len;
|
||||
extern u32 kvm_emulate_mtmsr[];
|
||||
|
||||
static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
|
||||
{
|
||||
u32 *p;
|
||||
int distance_start;
|
||||
int distance_end;
|
||||
ulong next_inst;
|
||||
|
||||
p = kvm_alloc(kvm_emulate_mtmsr_len * 4);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
/* Find out where we are and put everything there */
|
||||
distance_start = (ulong)p - (ulong)inst;
|
||||
next_inst = ((ulong)inst + 4);
|
||||
distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsr_branch_offs];
|
||||
|
||||
/* Make sure we only write valid b instructions */
|
||||
if (distance_start > KVM_INST_B_MAX) {
|
||||
kvm_patching_worked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Modify the chunk to fit the invocation */
|
||||
memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4);
|
||||
p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK;
|
||||
|
||||
/* Make clobbered registers work too */
|
||||
switch (get_rt(rt)) {
|
||||
case 30:
|
||||
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
|
||||
magic_var(scratch2), KVM_RT_30);
|
||||
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
|
||||
magic_var(scratch2), KVM_RT_30);
|
||||
break;
|
||||
case 31:
|
||||
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
|
||||
magic_var(scratch1), KVM_RT_30);
|
||||
kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
|
||||
magic_var(scratch1), KVM_RT_30);
|
||||
break;
|
||||
default:
|
||||
p[kvm_emulate_mtmsr_reg1_offs] |= rt;
|
||||
p[kvm_emulate_mtmsr_reg2_offs] |= rt;
|
||||
break;
|
||||
}
|
||||
|
||||
p[kvm_emulate_mtmsr_orig_ins_offs] = *inst;
|
||||
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4);
|
||||
|
||||
/* Patch the invocation */
|
||||
kvm_patch_ins_b(inst, distance_start);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOKE
|
||||
|
||||
extern u32 kvm_emulate_wrteei_branch_offs;
|
||||
extern u32 kvm_emulate_wrteei_ee_offs;
|
||||
extern u32 kvm_emulate_wrteei_len;
|
||||
extern u32 kvm_emulate_wrteei[];
|
||||
|
||||
static void kvm_patch_ins_wrteei(u32 *inst)
|
||||
{
|
||||
u32 *p;
|
||||
int distance_start;
|
||||
int distance_end;
|
||||
ulong next_inst;
|
||||
|
||||
p = kvm_alloc(kvm_emulate_wrteei_len * 4);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
/* Find out where we are and put everything there */
|
||||
distance_start = (ulong)p - (ulong)inst;
|
||||
next_inst = ((ulong)inst + 4);
|
||||
distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs];
|
||||
|
||||
/* Make sure we only write valid b instructions */
|
||||
if (distance_start > KVM_INST_B_MAX) {
|
||||
kvm_patching_worked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Modify the chunk to fit the invocation */
|
||||
memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4);
|
||||
p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK;
|
||||
p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE);
|
||||
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4);
|
||||
|
||||
/* Patch the invocation */
|
||||
kvm_patch_ins_b(inst, distance_start);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
|
||||
extern u32 kvm_emulate_mtsrin_branch_offs;
|
||||
extern u32 kvm_emulate_mtsrin_reg1_offs;
|
||||
extern u32 kvm_emulate_mtsrin_reg2_offs;
|
||||
extern u32 kvm_emulate_mtsrin_orig_ins_offs;
|
||||
extern u32 kvm_emulate_mtsrin_len;
|
||||
extern u32 kvm_emulate_mtsrin[];
|
||||
|
||||
static void kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb)
|
||||
{
|
||||
u32 *p;
|
||||
int distance_start;
|
||||
int distance_end;
|
||||
ulong next_inst;
|
||||
|
||||
p = kvm_alloc(kvm_emulate_mtsrin_len * 4);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
/* Find out where we are and put everything there */
|
||||
distance_start = (ulong)p - (ulong)inst;
|
||||
next_inst = ((ulong)inst + 4);
|
||||
distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs];
|
||||
|
||||
/* Make sure we only write valid b instructions */
|
||||
if (distance_start > KVM_INST_B_MAX) {
|
||||
kvm_patching_worked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Modify the chunk to fit the invocation */
|
||||
memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4);
|
||||
p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK;
|
||||
p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10);
|
||||
p[kvm_emulate_mtsrin_reg2_offs] |= rt;
|
||||
p[kvm_emulate_mtsrin_orig_ins_offs] = *inst;
|
||||
flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4);
|
||||
|
||||
/* Patch the invocation */
|
||||
kvm_patch_ins_b(inst, distance_start);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void kvm_map_magic_page(void *data)
|
||||
{
|
||||
u32 *features = data;
|
||||
|
||||
ulong in[8];
|
||||
ulong out[8];
|
||||
|
||||
in[0] = KVM_MAGIC_PAGE;
|
||||
in[1] = KVM_MAGIC_PAGE;
|
||||
|
||||
kvm_hypercall(in, out, HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE);
|
||||
|
||||
*features = out[0];
|
||||
}
|
||||
|
||||
static void kvm_check_ins(u32 *inst, u32 features)
|
||||
{
|
||||
u32 _inst = *inst;
|
||||
u32 inst_no_rt = _inst & ~KVM_MASK_RT;
|
||||
u32 inst_rt = _inst & KVM_MASK_RT;
|
||||
|
||||
switch (inst_no_rt) {
|
||||
/* Loads */
|
||||
case KVM_INST_MFMSR:
|
||||
kvm_patch_ins_ld(inst, magic_var(msr), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_SPRG0:
|
||||
kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_SPRG1:
|
||||
kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_SPRG2:
|
||||
kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_SPRG3:
|
||||
kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_SRR0:
|
||||
kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_SRR1:
|
||||
kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_DAR:
|
||||
kvm_patch_ins_ld(inst, magic_var(dar), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MFSPR_DSISR:
|
||||
kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt);
|
||||
break;
|
||||
|
||||
/* Stores */
|
||||
case KVM_INST_MTSPR_SPRG0:
|
||||
kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_SPRG1:
|
||||
kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_SPRG2:
|
||||
kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_SPRG3:
|
||||
kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_SRR0:
|
||||
kvm_patch_ins_std(inst, magic_var(srr0), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_SRR1:
|
||||
kvm_patch_ins_std(inst, magic_var(srr1), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_DAR:
|
||||
kvm_patch_ins_std(inst, magic_var(dar), inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTSPR_DSISR:
|
||||
kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt);
|
||||
break;
|
||||
|
||||
/* Nops */
|
||||
case KVM_INST_TLBSYNC:
|
||||
kvm_patch_ins_nop(inst);
|
||||
break;
|
||||
|
||||
/* Rewrites */
|
||||
case KVM_INST_MTMSRD_L1:
|
||||
kvm_patch_ins_mtmsrd(inst, inst_rt);
|
||||
break;
|
||||
case KVM_INST_MTMSR:
|
||||
case KVM_INST_MTMSRD_L0:
|
||||
kvm_patch_ins_mtmsr(inst, inst_rt);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (inst_no_rt & ~KVM_MASK_RB) {
|
||||
#ifdef CONFIG_PPC_BOOK3S_32
|
||||
case KVM_INST_MTSRIN:
|
||||
if (features & KVM_MAGIC_FEAT_SR) {
|
||||
u32 inst_rb = _inst & KVM_MASK_RB;
|
||||
kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (_inst) {
|
||||
#ifdef CONFIG_BOOKE
|
||||
case KVM_INST_WRTEEI_0:
|
||||
case KVM_INST_WRTEEI_1:
|
||||
kvm_patch_ins_wrteei(inst);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_use_magic_page(void)
|
||||
{
|
||||
u32 *p;
|
||||
u32 *start, *end;
|
||||
u32 tmp;
|
||||
u32 features;
|
||||
|
||||
/* Tell the host to map the magic page to -4096 on all CPUs */
|
||||
on_each_cpu(kvm_map_magic_page, &features, 1);
|
||||
|
||||
/* Quick self-test to see if the mapping works */
|
||||
if (__get_user(tmp, (u32*)KVM_MAGIC_PAGE)) {
|
||||
kvm_patching_worked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now loop through all code and find instructions */
|
||||
start = (void*)_stext;
|
||||
end = (void*)_etext;
|
||||
|
||||
for (p = start; p < end; p++)
|
||||
kvm_check_ins(p, features);
|
||||
|
||||
printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
|
||||
kvm_patching_worked ? "worked" : "failed");
|
||||
}
|
||||
|
||||
unsigned long kvm_hypercall(unsigned long *in,
|
||||
unsigned long *out,
|
||||
unsigned long nr)
|
||||
{
|
||||
unsigned long register r0 asm("r0");
|
||||
unsigned long register r3 asm("r3") = in[0];
|
||||
unsigned long register r4 asm("r4") = in[1];
|
||||
unsigned long register r5 asm("r5") = in[2];
|
||||
unsigned long register r6 asm("r6") = in[3];
|
||||
unsigned long register r7 asm("r7") = in[4];
|
||||
unsigned long register r8 asm("r8") = in[5];
|
||||
unsigned long register r9 asm("r9") = in[6];
|
||||
unsigned long register r10 asm("r10") = in[7];
|
||||
unsigned long register r11 asm("r11") = nr;
|
||||
unsigned long register r12 asm("r12");
|
||||
|
||||
asm volatile("bl kvm_hypercall_start"
|
||||
: "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
|
||||
"=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
|
||||
"=r"(r12)
|
||||
: "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
|
||||
"r"(r9), "r"(r10), "r"(r11)
|
||||
: "memory", "cc", "xer", "ctr", "lr");
|
||||
|
||||
out[0] = r4;
|
||||
out[1] = r5;
|
||||
out[2] = r6;
|
||||
out[3] = r7;
|
||||
out[4] = r8;
|
||||
out[5] = r9;
|
||||
out[6] = r10;
|
||||
out[7] = r11;
|
||||
|
||||
return r3;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_hypercall);
|
||||
|
||||
static int kvm_para_setup(void)
|
||||
{
|
||||
extern u32 kvm_hypercall_start;
|
||||
struct device_node *hyper_node;
|
||||
u32 *insts;
|
||||
int len, i;
|
||||
|
||||
hyper_node = of_find_node_by_path("/hypervisor");
|
||||
if (!hyper_node)
|
||||
return -1;
|
||||
|
||||
insts = (u32*)of_get_property(hyper_node, "hcall-instructions", &len);
|
||||
if (len % 4)
|
||||
return -1;
|
||||
if (len > (4 * 4))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < (len / 4); i++)
|
||||
kvm_patch_ins(&(&kvm_hypercall_start)[i], insts[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init void kvm_free_tmp(void)
|
||||
{
|
||||
unsigned long start, end;
|
||||
|
||||
start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
|
||||
end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
|
||||
|
||||
/* Free the tmp space we don't need */
|
||||
for (; start < end; start += PAGE_SIZE) {
|
||||
ClearPageReserved(virt_to_page(start));
|
||||
init_page_count(virt_to_page(start));
|
||||
free_page(start);
|
||||
totalram_pages++;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init kvm_guest_init(void)
|
||||
{
|
||||
if (!kvm_para_available())
|
||||
goto free_tmp;
|
||||
|
||||
if (kvm_para_setup())
|
||||
goto free_tmp;
|
||||
|
||||
if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
|
||||
kvm_use_magic_page();
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
/* Enable napping */
|
||||
powersave_nap = 1;
|
||||
#endif
|
||||
|
||||
free_tmp:
|
||||
kvm_free_tmp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
postcore_initcall(kvm_guest_init);
|
||||
302
arch/powerpc/kernel/kvm_emul.S
Normal file
302
arch/powerpc/kernel/kvm_emul.S
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright SUSE Linux Products GmbH 2010
|
||||
*
|
||||
* Authors: Alexander Graf <agraf@suse.de>
|
||||
*/
|
||||
|
||||
#include <asm/ppc_asm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/reg.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
/* Hypercall entry point. Will be patched with device tree instructions. */
|
||||
|
||||
.global kvm_hypercall_start
|
||||
kvm_hypercall_start:
|
||||
li r3, -1
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
blr
|
||||
|
||||
#define KVM_MAGIC_PAGE (-4096)
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define LL64(reg, offs, reg2) ld reg, (offs)(reg2)
|
||||
#define STL64(reg, offs, reg2) std reg, (offs)(reg2)
|
||||
#else
|
||||
#define LL64(reg, offs, reg2) lwz reg, (offs + 4)(reg2)
|
||||
#define STL64(reg, offs, reg2) stw reg, (offs + 4)(reg2)
|
||||
#endif
|
||||
|
||||
#define SCRATCH_SAVE \
|
||||
/* Enable critical section. We are critical if \
|
||||
shared->critical == r1 */ \
|
||||
STL64(r1, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0); \
|
||||
\
|
||||
/* Save state */ \
|
||||
PPC_STL r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0); \
|
||||
PPC_STL r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0); \
|
||||
mfcr r31; \
|
||||
stw r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);
|
||||
|
||||
#define SCRATCH_RESTORE \
|
||||
/* Restore state */ \
|
||||
PPC_LL r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0); \
|
||||
lwz r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0); \
|
||||
mtcr r30; \
|
||||
PPC_LL r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0); \
|
||||
\
|
||||
/* Disable critical section. We are critical if \
|
||||
shared->critical == r1 and r2 is always != r1 */ \
|
||||
STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
|
||||
|
||||
.global kvm_emulate_mtmsrd
|
||||
kvm_emulate_mtmsrd:
|
||||
|
||||
SCRATCH_SAVE
|
||||
|
||||
/* Put MSR & ~(MSR_EE|MSR_RI) in r31 */
|
||||
LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
lis r30, (~(MSR_EE | MSR_RI))@h
|
||||
ori r30, r30, (~(MSR_EE | MSR_RI))@l
|
||||
and r31, r31, r30
|
||||
|
||||
/* OR the register's (MSR_EE|MSR_RI) on MSR */
|
||||
kvm_emulate_mtmsrd_reg:
|
||||
ori r30, r0, 0
|
||||
andi. r30, r30, (MSR_EE|MSR_RI)
|
||||
or r31, r31, r30
|
||||
|
||||
/* Put MSR back into magic page */
|
||||
STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
|
||||
/* Check if we have to fetch an interrupt */
|
||||
lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
|
||||
cmpwi r31, 0
|
||||
beq+ no_check
|
||||
|
||||
/* Check if we may trigger an interrupt */
|
||||
andi. r30, r30, MSR_EE
|
||||
beq no_check
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
/* Nag hypervisor */
|
||||
kvm_emulate_mtmsrd_orig_ins:
|
||||
tlbsync
|
||||
|
||||
b kvm_emulate_mtmsrd_branch
|
||||
|
||||
no_check:
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
/* Go back to caller */
|
||||
kvm_emulate_mtmsrd_branch:
|
||||
b .
|
||||
kvm_emulate_mtmsrd_end:
|
||||
|
||||
.global kvm_emulate_mtmsrd_branch_offs
|
||||
kvm_emulate_mtmsrd_branch_offs:
|
||||
.long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4
|
||||
|
||||
.global kvm_emulate_mtmsrd_reg_offs
|
||||
kvm_emulate_mtmsrd_reg_offs:
|
||||
.long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4
|
||||
|
||||
.global kvm_emulate_mtmsrd_orig_ins_offs
|
||||
kvm_emulate_mtmsrd_orig_ins_offs:
|
||||
.long (kvm_emulate_mtmsrd_orig_ins - kvm_emulate_mtmsrd) / 4
|
||||
|
||||
.global kvm_emulate_mtmsrd_len
|
||||
kvm_emulate_mtmsrd_len:
|
||||
.long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
|
||||
|
||||
|
||||
#define MSR_SAFE_BITS (MSR_EE | MSR_CE | MSR_ME | MSR_RI)
|
||||
#define MSR_CRITICAL_BITS ~MSR_SAFE_BITS
|
||||
|
||||
.global kvm_emulate_mtmsr
|
||||
kvm_emulate_mtmsr:
|
||||
|
||||
SCRATCH_SAVE
|
||||
|
||||
/* Fetch old MSR in r31 */
|
||||
LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
|
||||
/* Find the changed bits between old and new MSR */
|
||||
kvm_emulate_mtmsr_reg1:
|
||||
ori r30, r0, 0
|
||||
xor r31, r30, r31
|
||||
|
||||
/* Check if we need to really do mtmsr */
|
||||
LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS)
|
||||
and. r31, r31, r30
|
||||
|
||||
/* No critical bits changed? Maybe we can stay in the guest. */
|
||||
beq maybe_stay_in_guest
|
||||
|
||||
do_mtmsr:
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
/* Just fire off the mtmsr if it's critical */
|
||||
kvm_emulate_mtmsr_orig_ins:
|
||||
mtmsr r0
|
||||
|
||||
b kvm_emulate_mtmsr_branch
|
||||
|
||||
maybe_stay_in_guest:
|
||||
|
||||
/* Get the target register in r30 */
|
||||
kvm_emulate_mtmsr_reg2:
|
||||
ori r30, r0, 0
|
||||
|
||||
/* Check if we have to fetch an interrupt */
|
||||
lwz r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
|
||||
cmpwi r31, 0
|
||||
beq+ no_mtmsr
|
||||
|
||||
/* Check if we may trigger an interrupt */
|
||||
andi. r31, r30, MSR_EE
|
||||
beq no_mtmsr
|
||||
|
||||
b do_mtmsr
|
||||
|
||||
no_mtmsr:
|
||||
|
||||
/* Put MSR into magic page because we don't call mtmsr */
|
||||
STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
/* Go back to caller */
|
||||
kvm_emulate_mtmsr_branch:
|
||||
b .
|
||||
kvm_emulate_mtmsr_end:
|
||||
|
||||
.global kvm_emulate_mtmsr_branch_offs
|
||||
kvm_emulate_mtmsr_branch_offs:
|
||||
.long (kvm_emulate_mtmsr_branch - kvm_emulate_mtmsr) / 4
|
||||
|
||||
.global kvm_emulate_mtmsr_reg1_offs
|
||||
kvm_emulate_mtmsr_reg1_offs:
|
||||
.long (kvm_emulate_mtmsr_reg1 - kvm_emulate_mtmsr) / 4
|
||||
|
||||
.global kvm_emulate_mtmsr_reg2_offs
|
||||
kvm_emulate_mtmsr_reg2_offs:
|
||||
.long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4
|
||||
|
||||
.global kvm_emulate_mtmsr_orig_ins_offs
|
||||
kvm_emulate_mtmsr_orig_ins_offs:
|
||||
.long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4
|
||||
|
||||
.global kvm_emulate_mtmsr_len
|
||||
kvm_emulate_mtmsr_len:
|
||||
.long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
|
||||
|
||||
|
||||
|
||||
.global kvm_emulate_wrteei
|
||||
kvm_emulate_wrteei:
|
||||
|
||||
SCRATCH_SAVE
|
||||
|
||||
/* Fetch old MSR in r31 */
|
||||
LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
|
||||
/* Remove MSR_EE from old MSR */
|
||||
li r30, 0
|
||||
ori r30, r30, MSR_EE
|
||||
andc r31, r31, r30
|
||||
|
||||
/* OR new MSR_EE onto the old MSR */
|
||||
kvm_emulate_wrteei_ee:
|
||||
ori r31, r31, 0
|
||||
|
||||
/* Write new MSR value back */
|
||||
STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
/* Go back to caller */
|
||||
kvm_emulate_wrteei_branch:
|
||||
b .
|
||||
kvm_emulate_wrteei_end:
|
||||
|
||||
.global kvm_emulate_wrteei_branch_offs
|
||||
kvm_emulate_wrteei_branch_offs:
|
||||
.long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
|
||||
|
||||
.global kvm_emulate_wrteei_ee_offs
|
||||
kvm_emulate_wrteei_ee_offs:
|
||||
.long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
|
||||
|
||||
.global kvm_emulate_wrteei_len
|
||||
kvm_emulate_wrteei_len:
|
||||
.long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
|
||||
|
||||
|
||||
.global kvm_emulate_mtsrin
|
||||
kvm_emulate_mtsrin:
|
||||
|
||||
SCRATCH_SAVE
|
||||
|
||||
LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
|
||||
andi. r31, r31, MSR_DR | MSR_IR
|
||||
beq kvm_emulate_mtsrin_reg1
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
kvm_emulate_mtsrin_orig_ins:
|
||||
nop
|
||||
b kvm_emulate_mtsrin_branch
|
||||
|
||||
kvm_emulate_mtsrin_reg1:
|
||||
/* rX >> 26 */
|
||||
rlwinm r30,r0,6,26,29
|
||||
|
||||
kvm_emulate_mtsrin_reg2:
|
||||
stw r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30)
|
||||
|
||||
SCRATCH_RESTORE
|
||||
|
||||
/* Go back to caller */
|
||||
kvm_emulate_mtsrin_branch:
|
||||
b .
|
||||
kvm_emulate_mtsrin_end:
|
||||
|
||||
.global kvm_emulate_mtsrin_branch_offs
|
||||
kvm_emulate_mtsrin_branch_offs:
|
||||
.long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4
|
||||
|
||||
.global kvm_emulate_mtsrin_reg1_offs
|
||||
kvm_emulate_mtsrin_reg1_offs:
|
||||
.long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4
|
||||
|
||||
.global kvm_emulate_mtsrin_reg2_offs
|
||||
kvm_emulate_mtsrin_reg2_offs:
|
||||
.long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4
|
||||
|
||||
.global kvm_emulate_mtsrin_orig_ins_offs
|
||||
kvm_emulate_mtsrin_orig_ins_offs:
|
||||
.long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4
|
||||
|
||||
.global kvm_emulate_mtsrin_len
|
||||
kvm_emulate_mtsrin_len:
|
||||
.long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
|
||||
|
|
@ -52,14 +52,14 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
|
|||
phys_addr_t taddr, unsigned long irq,
|
||||
upf_t flags, int irq_check_parent)
|
||||
{
|
||||
const u32 *clk, *spd;
|
||||
const __be32 *clk, *spd;
|
||||
u32 clock = BASE_BAUD * 16;
|
||||
int index;
|
||||
|
||||
/* get clock freq. if present */
|
||||
clk = of_get_property(np, "clock-frequency", NULL);
|
||||
if (clk && *clk)
|
||||
clock = *clk;
|
||||
clock = be32_to_cpup(clk);
|
||||
|
||||
/* get default speed if present */
|
||||
spd = of_get_property(np, "current-speed", NULL);
|
||||
|
|
@ -109,7 +109,7 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
|
|||
legacy_serial_infos[index].taddr = taddr;
|
||||
legacy_serial_infos[index].np = of_node_get(np);
|
||||
legacy_serial_infos[index].clock = clock;
|
||||
legacy_serial_infos[index].speed = spd ? *spd : 0;
|
||||
legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0;
|
||||
legacy_serial_infos[index].irq_check_parent = irq_check_parent;
|
||||
|
||||
printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
|
||||
|
|
@ -168,7 +168,7 @@ static int __init add_legacy_soc_port(struct device_node *np,
|
|||
static int __init add_legacy_isa_port(struct device_node *np,
|
||||
struct device_node *isa_brg)
|
||||
{
|
||||
const u32 *reg;
|
||||
const __be32 *reg;
|
||||
const char *typep;
|
||||
int index = -1;
|
||||
u64 taddr;
|
||||
|
|
@ -181,7 +181,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
|
|||
return -1;
|
||||
|
||||
/* Verify it's an IO port, we don't support anything else */
|
||||
if (!(reg[0] & 0x00000001))
|
||||
if (!(be32_to_cpu(reg[0]) & 0x00000001))
|
||||
return -1;
|
||||
|
||||
/* Now look for an "ibm,aix-loc" property that gives us ordering
|
||||
|
|
@ -202,7 +202,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
|
|||
taddr = 0;
|
||||
|
||||
/* Add port, irq will be dealt with later */
|
||||
return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
|
||||
return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]), taddr,
|
||||
NO_IRQ, UPF_BOOT_AUTOCONF, 0);
|
||||
|
||||
}
|
||||
|
|
@ -251,9 +251,9 @@ static int __init add_legacy_pci_port(struct device_node *np,
|
|||
* we get to their "reg" property
|
||||
*/
|
||||
if (np != pci_dev) {
|
||||
const u32 *reg = of_get_property(np, "reg", NULL);
|
||||
if (reg && (*reg < 4))
|
||||
index = lindex = *reg;
|
||||
const __be32 *reg = of_get_property(np, "reg", NULL);
|
||||
if (reg && (be32_to_cpup(reg) < 4))
|
||||
index = lindex = be32_to_cpup(reg);
|
||||
}
|
||||
|
||||
/* Local index means it's the Nth port in the PCI chip. Unfortunately
|
||||
|
|
@ -507,7 +507,7 @@ static int __init check_legacy_serial_console(void)
|
|||
struct device_node *prom_stdout = NULL;
|
||||
int i, speed = 0, offset = 0;
|
||||
const char *name;
|
||||
const u32 *spd;
|
||||
const __be32 *spd;
|
||||
|
||||
DBG(" -> check_legacy_serial_console()\n");
|
||||
|
||||
|
|
@ -547,7 +547,7 @@ static int __init check_legacy_serial_console(void)
|
|||
}
|
||||
spd = of_get_property(prom_stdout, "current-speed", NULL);
|
||||
if (spd)
|
||||
speed = *spd;
|
||||
speed = be32_to_cpup(spd);
|
||||
|
||||
if (strcmp(name, "serial") != 0)
|
||||
goto not_found;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ static unsigned long get_purr(void)
|
|||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (firmware_has_feature(FW_FEATURE_ISERIES))
|
||||
sum_purr += lppaca[cpu].emulated_time_base;
|
||||
sum_purr += lppaca_of(cpu).emulated_time_base;
|
||||
else {
|
||||
struct cpu_usage *cu;
|
||||
|
||||
|
|
@ -263,7 +263,7 @@ static void parse_ppp_data(struct seq_file *m)
|
|||
ppp_data.active_system_procs);
|
||||
|
||||
/* pool related entries are apropriate for shared configs */
|
||||
if (lppaca[0].shared_proc) {
|
||||
if (lppaca_of(0).shared_proc) {
|
||||
unsigned long pool_idle_time, pool_procs;
|
||||
|
||||
seq_printf(m, "pool=%d\n", ppp_data.pool_num);
|
||||
|
|
@ -460,8 +460,8 @@ static void pseries_cmo_data(struct seq_file *m)
|
|||
return;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
cmo_faults += lppaca[cpu].cmo_faults;
|
||||
cmo_fault_time += lppaca[cpu].cmo_fault_time;
|
||||
cmo_faults += lppaca_of(cpu).cmo_faults;
|
||||
cmo_fault_time += lppaca_of(cpu).cmo_fault_time;
|
||||
}
|
||||
|
||||
seq_printf(m, "cmo_faults=%lu\n", cmo_faults);
|
||||
|
|
@ -479,8 +479,8 @@ static void splpar_dispatch_data(struct seq_file *m)
|
|||
unsigned long dispatch_dispersions = 0;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
dispatches += lppaca[cpu].yield_count;
|
||||
dispatch_dispersions += lppaca[cpu].dispersion_count;
|
||||
dispatches += lppaca_of(cpu).yield_count;
|
||||
dispatch_dispersions += lppaca_of(cpu).dispersion_count;
|
||||
}
|
||||
|
||||
seq_printf(m, "dispatches=%lu\n", dispatches);
|
||||
|
|
@ -545,7 +545,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
|
|||
seq_printf(m, "partition_potential_processors=%d\n",
|
||||
partition_potential_processors);
|
||||
|
||||
seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
|
||||
seq_printf(m, "shared_processor_mode=%d\n", lppaca_of(0).shared_proc);
|
||||
|
||||
seq_printf(m, "slb_size=%d\n", mmu_slb_size);
|
||||
|
||||
|
|
@ -780,6 +780,7 @@ static const struct file_operations lparcfg_fops = {
|
|||
.write = lparcfg_write,
|
||||
.open = lparcfg_open,
|
||||
.release = single_release,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static int __init lparcfg_init(void)
|
||||
|
|
|
|||
|
|
@ -14,10 +14,34 @@
|
|||
#include <linux/threads.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
void machine_kexec_mask_interrupts(void) {
|
||||
unsigned int i;
|
||||
|
||||
for_each_irq(i) {
|
||||
struct irq_desc *desc = irq_to_desc(i);
|
||||
|
||||
if (!desc || !desc->chip)
|
||||
continue;
|
||||
|
||||
if (desc->chip->eoi &&
|
||||
desc->status & IRQ_INPROGRESS)
|
||||
desc->chip->eoi(i);
|
||||
|
||||
if (desc->chip->mask)
|
||||
desc->chip->mask(i);
|
||||
|
||||
if (desc->chip->disable &&
|
||||
!(desc->status & IRQ_DISABLED))
|
||||
desc->chip->disable(i);
|
||||
}
|
||||
}
|
||||
|
||||
void machine_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
if (ppc_md.machine_crash_shutdown)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ void default_machine_kexec(struct kimage *image)
|
|||
/* Interrupts aren't acceptable while we reboot */
|
||||
local_irq_disable();
|
||||
|
||||
/* mask each interrupt so we are in a more sane state for the
|
||||
* kexec kernel */
|
||||
machine_kexec_mask_interrupts();
|
||||
|
||||
page_list = image->head;
|
||||
|
||||
/* we need both effective and real address here */
|
||||
|
|
|
|||
|
|
@ -63,11 +63,6 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
const Elf_Shdr *sechdrs, struct module *me)
|
||||
{
|
||||
const Elf_Shdr *sect;
|
||||
int err;
|
||||
|
||||
err = module_bug_finalize(hdr, sechdrs, me);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Apply feature fixups */
|
||||
sect = find_section(hdr, sechdrs, "__ftr_fixup");
|
||||
|
|
@ -101,5 +96,4 @@ int module_finalize(const Elf_Ehdr *hdr,
|
|||
|
||||
void module_arch_cleanup(struct module *mod)
|
||||
{
|
||||
module_bug_cleanup(mod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,20 @@ extern unsigned long __toc_start;
|
|||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
|
||||
/*
|
||||
* We only have to have statically allocated lppaca structs on
|
||||
* legacy iSeries, which supports at most 64 cpus.
|
||||
*/
|
||||
#ifdef CONFIG_PPC_ISERIES
|
||||
#if NR_CPUS < 64
|
||||
#define NR_LPPACAS NR_CPUS
|
||||
#else
|
||||
#define NR_LPPACAS 64
|
||||
#endif
|
||||
#else /* not iSeries */
|
||||
#define NR_LPPACAS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The structure which the hypervisor knows about - this structure
|
||||
* should not cross a page boundary. The vpa_init/register_vpa call
|
||||
|
|
@ -36,7 +50,7 @@ extern unsigned long __toc_start;
|
|||
* will suffice to ensure that it doesn't cross a page boundary.
|
||||
*/
|
||||
struct lppaca lppaca[] = {
|
||||
[0 ... (NR_CPUS-1)] = {
|
||||
[0 ... (NR_LPPACAS-1)] = {
|
||||
.desc = 0xd397d781, /* "LpPa" */
|
||||
.size = sizeof(struct lppaca),
|
||||
.dyn_proc_status = 2,
|
||||
|
|
@ -49,6 +63,54 @@ struct lppaca lppaca[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct lppaca *extra_lppacas;
|
||||
static long __initdata lppaca_size;
|
||||
|
||||
static void allocate_lppacas(int nr_cpus, unsigned long limit)
|
||||
{
|
||||
if (nr_cpus <= NR_LPPACAS)
|
||||
return;
|
||||
|
||||
lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) *
|
||||
(nr_cpus - NR_LPPACAS));
|
||||
extra_lppacas = __va(memblock_alloc_base(lppaca_size,
|
||||
PAGE_SIZE, limit));
|
||||
}
|
||||
|
||||
static struct lppaca *new_lppaca(int cpu)
|
||||
{
|
||||
struct lppaca *lp;
|
||||
|
||||
if (cpu < NR_LPPACAS)
|
||||
return &lppaca[cpu];
|
||||
|
||||
lp = extra_lppacas + (cpu - NR_LPPACAS);
|
||||
*lp = lppaca[0];
|
||||
|
||||
return lp;
|
||||
}
|
||||
|
||||
static void free_lppacas(void)
|
||||
{
|
||||
long new_size = 0, nr;
|
||||
|
||||
if (!lppaca_size)
|
||||
return;
|
||||
nr = num_possible_cpus() - NR_LPPACAS;
|
||||
if (nr > 0)
|
||||
new_size = PAGE_ALIGN(nr * sizeof(struct lppaca));
|
||||
if (new_size >= lppaca_size)
|
||||
return;
|
||||
|
||||
memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size);
|
||||
lppaca_size = new_size;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void allocate_lppacas(int nr_cpus, unsigned long limit) { }
|
||||
static inline void free_lppacas(void) { }
|
||||
|
||||
#endif /* CONFIG_PPC_BOOK3S */
|
||||
|
||||
#ifdef CONFIG_PPC_STD_MMU_64
|
||||
|
|
@ -88,7 +150,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
|
|||
unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL;
|
||||
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
new_paca->lppaca_ptr = &lppaca[cpu];
|
||||
new_paca->lppaca_ptr = new_lppaca(cpu);
|
||||
#else
|
||||
new_paca->kernel_pgd = swapper_pg_dir;
|
||||
#endif
|
||||
|
|
@ -127,7 +189,7 @@ void __init allocate_pacas(void)
|
|||
* the first segment. On iSeries they must be within the area mapped
|
||||
* by the HV, which is HvPagesToMap * HVPAGESIZE bytes.
|
||||
*/
|
||||
limit = min(0x10000000ULL, memblock.rmo_size);
|
||||
limit = min(0x10000000ULL, ppc64_rma_size);
|
||||
if (firmware_has_feature(FW_FEATURE_ISERIES))
|
||||
limit = min(limit, HvPagesToMap * HVPAGESIZE);
|
||||
|
||||
|
|
@ -144,6 +206,8 @@ void __init allocate_pacas(void)
|
|||
printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
|
||||
paca_size, nr_cpus, paca);
|
||||
|
||||
allocate_lppacas(nr_cpus, limit);
|
||||
|
||||
/* Can't use for_each_*_cpu, as they aren't functional yet */
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++)
|
||||
initialise_paca(&paca[cpu], cpu);
|
||||
|
|
@ -164,4 +228,6 @@ void __init free_unused_pacas(void)
|
|||
paca_size - new_size);
|
||||
|
||||
paca_size = new_size;
|
||||
|
||||
free_lppacas();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1090,8 +1090,6 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
|
|||
bus->number, bus->self ? pci_name(bus->self) : "PHB");
|
||||
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
struct dev_archdata *sd = &dev->dev.archdata;
|
||||
|
||||
/* Cardbus can call us to add new devices to a bus, so ignore
|
||||
* those who are already fully discovered
|
||||
*/
|
||||
|
|
@ -1107,7 +1105,7 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
|
|||
set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
|
||||
|
||||
/* Hook up default DMA ops */
|
||||
sd->dma_ops = pci_dma_ops;
|
||||
set_dma_ops(&dev->dev, pci_dma_ops);
|
||||
set_dma_offset(&dev->dev, PCI_DRAM_OFFSET);
|
||||
|
||||
/* Additional platform DMA/iommu setup */
|
||||
|
|
|
|||
|
|
@ -23,18 +23,6 @@
|
|||
#include "ppc32.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Store another value in a callchain_entry.
|
||||
*/
|
||||
static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
|
||||
{
|
||||
unsigned int nr = entry->nr;
|
||||
|
||||
if (nr < PERF_MAX_STACK_DEPTH) {
|
||||
entry->ip[nr] = ip;
|
||||
entry->nr = nr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Is sp valid as the address of the next kernel stack frame after prev_sp?
|
||||
|
|
@ -58,8 +46,8 @@ static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void perf_callchain_kernel(struct pt_regs *regs,
|
||||
struct perf_callchain_entry *entry)
|
||||
void
|
||||
perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
{
|
||||
unsigned long sp, next_sp;
|
||||
unsigned long next_ip;
|
||||
|
|
@ -69,8 +57,7 @@ static void perf_callchain_kernel(struct pt_regs *regs,
|
|||
|
||||
lr = regs->link;
|
||||
sp = regs->gpr[1];
|
||||
callchain_store(entry, PERF_CONTEXT_KERNEL);
|
||||
callchain_store(entry, regs->nip);
|
||||
perf_callchain_store(entry, regs->nip);
|
||||
|
||||
if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
|
||||
return;
|
||||
|
|
@ -89,7 +76,7 @@ static void perf_callchain_kernel(struct pt_regs *regs,
|
|||
next_ip = regs->nip;
|
||||
lr = regs->link;
|
||||
level = 0;
|
||||
callchain_store(entry, PERF_CONTEXT_KERNEL);
|
||||
perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
|
||||
|
||||
} else {
|
||||
if (level == 0)
|
||||
|
|
@ -111,7 +98,7 @@ static void perf_callchain_kernel(struct pt_regs *regs,
|
|||
++level;
|
||||
}
|
||||
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
if (!valid_next_sp(next_sp, sp))
|
||||
return;
|
||||
sp = next_sp;
|
||||
|
|
@ -233,8 +220,8 @@ static int sane_signal_64_frame(unsigned long sp)
|
|||
puc == (unsigned long) &sf->uc;
|
||||
}
|
||||
|
||||
static void perf_callchain_user_64(struct pt_regs *regs,
|
||||
struct perf_callchain_entry *entry)
|
||||
static void perf_callchain_user_64(struct perf_callchain_entry *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned long sp, next_sp;
|
||||
unsigned long next_ip;
|
||||
|
|
@ -246,8 +233,7 @@ static void perf_callchain_user_64(struct pt_regs *regs,
|
|||
next_ip = regs->nip;
|
||||
lr = regs->link;
|
||||
sp = regs->gpr[1];
|
||||
callchain_store(entry, PERF_CONTEXT_USER);
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
|
||||
for (;;) {
|
||||
fp = (unsigned long __user *) sp;
|
||||
|
|
@ -276,14 +262,14 @@ static void perf_callchain_user_64(struct pt_regs *regs,
|
|||
read_user_stack_64(&uregs[PT_R1], &sp))
|
||||
return;
|
||||
level = 0;
|
||||
callchain_store(entry, PERF_CONTEXT_USER);
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, PERF_CONTEXT_USER);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (level == 0)
|
||||
next_ip = lr;
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
++level;
|
||||
sp = next_sp;
|
||||
}
|
||||
|
|
@ -315,8 +301,8 @@ static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
|
|||
return __get_user_inatomic(*ret, ptr);
|
||||
}
|
||||
|
||||
static inline void perf_callchain_user_64(struct pt_regs *regs,
|
||||
struct perf_callchain_entry *entry)
|
||||
static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -435,8 +421,8 @@ static unsigned int __user *signal_frame_32_regs(unsigned int sp,
|
|||
return mctx->mc_gregs;
|
||||
}
|
||||
|
||||
static void perf_callchain_user_32(struct pt_regs *regs,
|
||||
struct perf_callchain_entry *entry)
|
||||
static void perf_callchain_user_32(struct perf_callchain_entry *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned int sp, next_sp;
|
||||
unsigned int next_ip;
|
||||
|
|
@ -447,8 +433,7 @@ static void perf_callchain_user_32(struct pt_regs *regs,
|
|||
next_ip = regs->nip;
|
||||
lr = regs->link;
|
||||
sp = regs->gpr[1];
|
||||
callchain_store(entry, PERF_CONTEXT_USER);
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
|
||||
while (entry->nr < PERF_MAX_STACK_DEPTH) {
|
||||
fp = (unsigned int __user *) (unsigned long) sp;
|
||||
|
|
@ -470,45 +455,24 @@ static void perf_callchain_user_32(struct pt_regs *regs,
|
|||
read_user_stack_32(&uregs[PT_R1], &sp))
|
||||
return;
|
||||
level = 0;
|
||||
callchain_store(entry, PERF_CONTEXT_USER);
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, PERF_CONTEXT_USER);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (level == 0)
|
||||
next_ip = lr;
|
||||
callchain_store(entry, next_ip);
|
||||
perf_callchain_store(entry, next_ip);
|
||||
++level;
|
||||
sp = next_sp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we can't get PMU interrupts inside a PMU interrupt handler,
|
||||
* we don't need separate irq and nmi entries here.
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct perf_callchain_entry, cpu_perf_callchain);
|
||||
|
||||
struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
|
||||
void
|
||||
perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
{
|
||||
struct perf_callchain_entry *entry = &__get_cpu_var(cpu_perf_callchain);
|
||||
|
||||
entry->nr = 0;
|
||||
|
||||
if (!user_mode(regs)) {
|
||||
perf_callchain_kernel(regs, entry);
|
||||
if (current->mm)
|
||||
regs = task_pt_regs(current);
|
||||
else
|
||||
regs = NULL;
|
||||
}
|
||||
|
||||
if (regs) {
|
||||
if (current_is_64bit())
|
||||
perf_callchain_user_64(regs, entry);
|
||||
else
|
||||
perf_callchain_user_32(regs, entry);
|
||||
}
|
||||
|
||||
return entry;
|
||||
if (current_is_64bit())
|
||||
perf_callchain_user_64(entry, regs);
|
||||
else
|
||||
perf_callchain_user_32(entry, regs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,6 +402,9 @@ static void power_pmu_read(struct perf_event *event)
|
|||
{
|
||||
s64 val, delta, prev;
|
||||
|
||||
if (event->hw.state & PERF_HES_STOPPED)
|
||||
return;
|
||||
|
||||
if (!event->hw.idx)
|
||||
return;
|
||||
/*
|
||||
|
|
@ -517,7 +520,7 @@ static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
|
|||
* Disable all events to prevent PMU interrupts and to allow
|
||||
* events to be added or removed.
|
||||
*/
|
||||
void hw_perf_disable(void)
|
||||
static void power_pmu_disable(struct pmu *pmu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
unsigned long flags;
|
||||
|
|
@ -565,7 +568,7 @@ void hw_perf_disable(void)
|
|||
* If we were previously disabled and events were added, then
|
||||
* put the new config on the PMU.
|
||||
*/
|
||||
void hw_perf_enable(void)
|
||||
static void power_pmu_enable(struct pmu *pmu)
|
||||
{
|
||||
struct perf_event *event;
|
||||
struct cpu_hw_events *cpuhw;
|
||||
|
|
@ -672,6 +675,8 @@ void hw_perf_enable(void)
|
|||
}
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
event->hw.idx = idx;
|
||||
if (event->hw.state & PERF_HES_STOPPED)
|
||||
val = 0;
|
||||
write_pmc(idx, val);
|
||||
perf_event_update_userpage(event);
|
||||
}
|
||||
|
|
@ -727,7 +732,7 @@ static int collect_events(struct perf_event *group, int max_count,
|
|||
* re-enable the PMU in order to get hw_perf_enable to do the
|
||||
* actual work of reconfiguring the PMU.
|
||||
*/
|
||||
static int power_pmu_enable(struct perf_event *event)
|
||||
static int power_pmu_add(struct perf_event *event, int ef_flags)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
unsigned long flags;
|
||||
|
|
@ -735,7 +740,7 @@ static int power_pmu_enable(struct perf_event *event)
|
|||
int ret = -EAGAIN;
|
||||
|
||||
local_irq_save(flags);
|
||||
perf_disable();
|
||||
perf_pmu_disable(event->pmu);
|
||||
|
||||
/*
|
||||
* Add the event to the list (if there is room)
|
||||
|
|
@ -749,6 +754,9 @@ static int power_pmu_enable(struct perf_event *event)
|
|||
cpuhw->events[n0] = event->hw.config;
|
||||
cpuhw->flags[n0] = event->hw.event_base;
|
||||
|
||||
if (!(ef_flags & PERF_EF_START))
|
||||
event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
|
||||
|
||||
/*
|
||||
* If group events scheduling transaction was started,
|
||||
* skip the schedulability test here, it will be peformed
|
||||
|
|
@ -769,7 +777,7 @@ nocheck:
|
|||
|
||||
ret = 0;
|
||||
out:
|
||||
perf_enable();
|
||||
perf_pmu_enable(event->pmu);
|
||||
local_irq_restore(flags);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -777,14 +785,14 @@ nocheck:
|
|||
/*
|
||||
* Remove a event from the PMU.
|
||||
*/
|
||||
static void power_pmu_disable(struct perf_event *event)
|
||||
static void power_pmu_del(struct perf_event *event, int ef_flags)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
long i;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
perf_disable();
|
||||
perf_pmu_disable(event->pmu);
|
||||
|
||||
power_pmu_read(event);
|
||||
|
||||
|
|
@ -821,34 +829,60 @@ static void power_pmu_disable(struct perf_event *event)
|
|||
cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
|
||||
}
|
||||
|
||||
perf_enable();
|
||||
perf_pmu_enable(event->pmu);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-enable interrupts on a event after they were throttled
|
||||
* because they were coming too fast.
|
||||
* POWER-PMU does not support disabling individual counters, hence
|
||||
* program their cycle counter to their max value and ignore the interrupts.
|
||||
*/
|
||||
static void power_pmu_unthrottle(struct perf_event *event)
|
||||
|
||||
static void power_pmu_start(struct perf_event *event, int ef_flags)
|
||||
{
|
||||
unsigned long flags;
|
||||
s64 left;
|
||||
|
||||
if (!event->hw.idx || !event->hw.sample_period)
|
||||
return;
|
||||
|
||||
if (!(event->hw.state & PERF_HES_STOPPED))
|
||||
return;
|
||||
|
||||
if (ef_flags & PERF_EF_RELOAD)
|
||||
WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
|
||||
|
||||
local_irq_save(flags);
|
||||
perf_pmu_disable(event->pmu);
|
||||
|
||||
event->hw.state = 0;
|
||||
left = local64_read(&event->hw.period_left);
|
||||
write_pmc(event->hw.idx, left);
|
||||
|
||||
perf_event_update_userpage(event);
|
||||
perf_pmu_enable(event->pmu);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void power_pmu_stop(struct perf_event *event, int ef_flags)
|
||||
{
|
||||
s64 val, left;
|
||||
unsigned long flags;
|
||||
|
||||
if (!event->hw.idx || !event->hw.sample_period)
|
||||
return;
|
||||
|
||||
if (event->hw.state & PERF_HES_STOPPED)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
perf_disable();
|
||||
perf_pmu_disable(event->pmu);
|
||||
|
||||
power_pmu_read(event);
|
||||
left = event->hw.sample_period;
|
||||
event->hw.last_period = left;
|
||||
val = 0;
|
||||
if (left < 0x80000000L)
|
||||
val = 0x80000000L - left;
|
||||
write_pmc(event->hw.idx, val);
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
local64_set(&event->hw.period_left, left);
|
||||
event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
|
||||
write_pmc(event->hw.idx, 0);
|
||||
|
||||
perf_event_update_userpage(event);
|
||||
perf_enable();
|
||||
perf_pmu_enable(event->pmu);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
|
@ -857,10 +891,11 @@ static void power_pmu_unthrottle(struct perf_event *event)
|
|||
* Set the flag to make pmu::enable() not perform the
|
||||
* schedulability test, it will be performed at commit time
|
||||
*/
|
||||
void power_pmu_start_txn(const struct pmu *pmu)
|
||||
void power_pmu_start_txn(struct pmu *pmu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
|
||||
|
||||
perf_pmu_disable(pmu);
|
||||
cpuhw->group_flag |= PERF_EVENT_TXN;
|
||||
cpuhw->n_txn_start = cpuhw->n_events;
|
||||
}
|
||||
|
|
@ -870,11 +905,12 @@ void power_pmu_start_txn(const struct pmu *pmu)
|
|||
* Clear the flag and pmu::enable() will perform the
|
||||
* schedulability test.
|
||||
*/
|
||||
void power_pmu_cancel_txn(const struct pmu *pmu)
|
||||
void power_pmu_cancel_txn(struct pmu *pmu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
|
||||
|
||||
cpuhw->group_flag &= ~PERF_EVENT_TXN;
|
||||
perf_pmu_enable(pmu);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -882,7 +918,7 @@ void power_pmu_cancel_txn(const struct pmu *pmu)
|
|||
* Perform the group schedulability test as a whole
|
||||
* Return 0 if success
|
||||
*/
|
||||
int power_pmu_commit_txn(const struct pmu *pmu)
|
||||
int power_pmu_commit_txn(struct pmu *pmu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
long i, n;
|
||||
|
|
@ -901,19 +937,10 @@ int power_pmu_commit_txn(const struct pmu *pmu)
|
|||
cpuhw->event[i]->hw.config = cpuhw->events[i];
|
||||
|
||||
cpuhw->group_flag &= ~PERF_EVENT_TXN;
|
||||
perf_pmu_enable(pmu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pmu power_pmu = {
|
||||
.enable = power_pmu_enable,
|
||||
.disable = power_pmu_disable,
|
||||
.read = power_pmu_read,
|
||||
.unthrottle = power_pmu_unthrottle,
|
||||
.start_txn = power_pmu_start_txn,
|
||||
.cancel_txn = power_pmu_cancel_txn,
|
||||
.commit_txn = power_pmu_commit_txn,
|
||||
};
|
||||
|
||||
/*
|
||||
* Return 1 if we might be able to put event on a limited PMC,
|
||||
* or 0 if not.
|
||||
|
|
@ -1014,7 +1041,7 @@ static int hw_perf_cache_event(u64 config, u64 *eventp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct pmu *hw_perf_event_init(struct perf_event *event)
|
||||
static int power_pmu_event_init(struct perf_event *event)
|
||||
{
|
||||
u64 ev;
|
||||
unsigned long flags;
|
||||
|
|
@ -1026,25 +1053,27 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
struct cpu_hw_events *cpuhw;
|
||||
|
||||
if (!ppmu)
|
||||
return ERR_PTR(-ENXIO);
|
||||
return -ENOENT;
|
||||
|
||||
switch (event->attr.type) {
|
||||
case PERF_TYPE_HARDWARE:
|
||||
ev = event->attr.config;
|
||||
if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
return -EOPNOTSUPP;
|
||||
ev = ppmu->generic_events[ev];
|
||||
break;
|
||||
case PERF_TYPE_HW_CACHE:
|
||||
err = hw_perf_cache_event(event->attr.config, &ev);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return err;
|
||||
break;
|
||||
case PERF_TYPE_RAW:
|
||||
ev = event->attr.config;
|
||||
break;
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
event->hw.config_base = ev;
|
||||
event->hw.idx = 0;
|
||||
|
||||
|
|
@ -1063,7 +1092,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
* XXX we should check if the task is an idle task.
|
||||
*/
|
||||
flags = 0;
|
||||
if (event->ctx->task)
|
||||
if (event->attach_state & PERF_ATTACH_TASK)
|
||||
flags |= PPMU_ONLY_COUNT_RUN;
|
||||
|
||||
/*
|
||||
|
|
@ -1081,7 +1110,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
*/
|
||||
ev = normal_pmc_alternative(ev, flags);
|
||||
if (!ev)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1095,19 +1124,19 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
n = collect_events(event->group_leader, ppmu->n_counter - 1,
|
||||
ctrs, events, cflags);
|
||||
if (n < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
events[n] = ev;
|
||||
ctrs[n] = event;
|
||||
cflags[n] = flags;
|
||||
if (check_excludes(ctrs, cflags, n, 1))
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
|
||||
cpuhw = &get_cpu_var(cpu_hw_events);
|
||||
err = power_check_constraints(cpuhw, events, cflags, n + 1);
|
||||
put_cpu_var(cpu_hw_events);
|
||||
if (err)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
|
||||
event->hw.config = events[n];
|
||||
event->hw.event_base = cflags[n];
|
||||
|
|
@ -1132,11 +1161,23 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
}
|
||||
event->destroy = hw_perf_event_destroy;
|
||||
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return &power_pmu;
|
||||
return err;
|
||||
}
|
||||
|
||||
struct pmu power_pmu = {
|
||||
.pmu_enable = power_pmu_enable,
|
||||
.pmu_disable = power_pmu_disable,
|
||||
.event_init = power_pmu_event_init,
|
||||
.add = power_pmu_add,
|
||||
.del = power_pmu_del,
|
||||
.start = power_pmu_start,
|
||||
.stop = power_pmu_stop,
|
||||
.read = power_pmu_read,
|
||||
.start_txn = power_pmu_start_txn,
|
||||
.cancel_txn = power_pmu_cancel_txn,
|
||||
.commit_txn = power_pmu_commit_txn,
|
||||
};
|
||||
|
||||
/*
|
||||
* A counter has overflowed; update its count and record
|
||||
* things if requested. Note that interrupts are hard-disabled
|
||||
|
|
@ -1149,6 +1190,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
|
|||
s64 prev, delta, left;
|
||||
int record = 0;
|
||||
|
||||
if (event->hw.state & PERF_HES_STOPPED) {
|
||||
write_pmc(event->hw.idx, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we don't have to worry about interrupts here */
|
||||
prev = local64_read(&event->hw.prev_count);
|
||||
delta = (val - prev) & 0xfffffffful;
|
||||
|
|
@ -1171,6 +1217,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
|
|||
val = 0x80000000LL - left;
|
||||
}
|
||||
|
||||
write_pmc(event->hw.idx, val);
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
local64_set(&event->hw.period_left, left);
|
||||
perf_event_update_userpage(event);
|
||||
|
||||
/*
|
||||
* Finally record data if requested.
|
||||
*/
|
||||
|
|
@ -1183,23 +1234,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
|
|||
if (event->attr.sample_type & PERF_SAMPLE_ADDR)
|
||||
perf_get_data_addr(regs, &data.addr);
|
||||
|
||||
if (perf_event_overflow(event, nmi, &data, regs)) {
|
||||
/*
|
||||
* Interrupts are coming too fast - throttle them
|
||||
* by setting the event to 0, so it will be
|
||||
* at least 2^30 cycles until the next interrupt
|
||||
* (assuming each event counts at most 2 counts
|
||||
* per cycle).
|
||||
*/
|
||||
val = 0;
|
||||
left = ~0ULL >> 1;
|
||||
}
|
||||
if (perf_event_overflow(event, nmi, &data, regs))
|
||||
power_pmu_stop(event, 0);
|
||||
}
|
||||
|
||||
write_pmc(event->hw.idx, val);
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
local64_set(&event->hw.period_left, left);
|
||||
perf_event_update_userpage(event);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1342,6 +1379,7 @@ int register_power_pmu(struct power_pmu *pmu)
|
|||
freeze_events_kernel = MMCR0_FCHV;
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
perf_pmu_register(&power_pmu);
|
||||
perf_cpu_notifier(power_pmu_notifier);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ static void fsl_emb_pmu_read(struct perf_event *event)
|
|||
{
|
||||
s64 val, delta, prev;
|
||||
|
||||
if (event->hw.state & PERF_HES_STOPPED)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Performance monitor interrupts come even when interrupts
|
||||
* are soft-disabled, as long as interrupts are hard-enabled.
|
||||
|
|
@ -177,7 +180,7 @@ static void fsl_emb_pmu_read(struct perf_event *event)
|
|||
* Disable all events to prevent PMU interrupts and to allow
|
||||
* events to be added or removed.
|
||||
*/
|
||||
void hw_perf_disable(void)
|
||||
static void fsl_emb_pmu_disable(struct pmu *pmu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
unsigned long flags;
|
||||
|
|
@ -216,7 +219,7 @@ void hw_perf_disable(void)
|
|||
* If we were previously disabled and events were added, then
|
||||
* put the new config on the PMU.
|
||||
*/
|
||||
void hw_perf_enable(void)
|
||||
static void fsl_emb_pmu_enable(struct pmu *pmu)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
unsigned long flags;
|
||||
|
|
@ -262,8 +265,8 @@ static int collect_events(struct perf_event *group, int max_count,
|
|||
return n;
|
||||
}
|
||||
|
||||
/* perf must be disabled, context locked on entry */
|
||||
static int fsl_emb_pmu_enable(struct perf_event *event)
|
||||
/* context locked on entry */
|
||||
static int fsl_emb_pmu_add(struct perf_event *event, int flags)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
int ret = -EAGAIN;
|
||||
|
|
@ -271,6 +274,7 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
|
|||
u64 val;
|
||||
int i;
|
||||
|
||||
perf_pmu_disable(event->pmu);
|
||||
cpuhw = &get_cpu_var(cpu_hw_events);
|
||||
|
||||
if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
|
||||
|
|
@ -301,6 +305,12 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
|
|||
val = 0x80000000L - left;
|
||||
}
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
|
||||
if (!(flags & PERF_EF_START)) {
|
||||
event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
|
||||
val = 0;
|
||||
}
|
||||
|
||||
write_pmc(i, val);
|
||||
perf_event_update_userpage(event);
|
||||
|
||||
|
|
@ -310,15 +320,17 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
|
|||
ret = 0;
|
||||
out:
|
||||
put_cpu_var(cpu_hw_events);
|
||||
perf_pmu_enable(event->pmu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* perf must be disabled, context locked on entry */
|
||||
static void fsl_emb_pmu_disable(struct perf_event *event)
|
||||
/* context locked on entry */
|
||||
static void fsl_emb_pmu_del(struct perf_event *event, int flags)
|
||||
{
|
||||
struct cpu_hw_events *cpuhw;
|
||||
int i = event->hw.idx;
|
||||
|
||||
perf_pmu_disable(event->pmu);
|
||||
if (i < 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -346,45 +358,58 @@ static void fsl_emb_pmu_disable(struct perf_event *event)
|
|||
cpuhw->n_events--;
|
||||
|
||||
out:
|
||||
perf_pmu_enable(event->pmu);
|
||||
put_cpu_var(cpu_hw_events);
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-enable interrupts on a event after they were throttled
|
||||
* because they were coming too fast.
|
||||
*
|
||||
* Context is locked on entry, but perf is not disabled.
|
||||
*/
|
||||
static void fsl_emb_pmu_unthrottle(struct perf_event *event)
|
||||
static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
|
||||
{
|
||||
unsigned long flags;
|
||||
s64 left;
|
||||
|
||||
if (event->hw.idx < 0 || !event->hw.sample_period)
|
||||
return;
|
||||
|
||||
if (!(event->hw.state & PERF_HES_STOPPED))
|
||||
return;
|
||||
|
||||
if (ef_flags & PERF_EF_RELOAD)
|
||||
WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
|
||||
|
||||
local_irq_save(flags);
|
||||
perf_pmu_disable(event->pmu);
|
||||
|
||||
event->hw.state = 0;
|
||||
left = local64_read(&event->hw.period_left);
|
||||
write_pmc(event->hw.idx, left);
|
||||
|
||||
perf_event_update_userpage(event);
|
||||
perf_pmu_enable(event->pmu);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void fsl_emb_pmu_stop(struct perf_event *event, int ef_flags)
|
||||
{
|
||||
s64 val, left;
|
||||
unsigned long flags;
|
||||
|
||||
if (event->hw.idx < 0 || !event->hw.sample_period)
|
||||
return;
|
||||
|
||||
if (event->hw.state & PERF_HES_STOPPED)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
perf_disable();
|
||||
perf_pmu_disable(event->pmu);
|
||||
|
||||
fsl_emb_pmu_read(event);
|
||||
left = event->hw.sample_period;
|
||||
event->hw.last_period = left;
|
||||
val = 0;
|
||||
if (left < 0x80000000L)
|
||||
val = 0x80000000L - left;
|
||||
write_pmc(event->hw.idx, val);
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
local64_set(&event->hw.period_left, left);
|
||||
event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
|
||||
write_pmc(event->hw.idx, 0);
|
||||
|
||||
perf_event_update_userpage(event);
|
||||
perf_enable();
|
||||
perf_pmu_enable(event->pmu);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static struct pmu fsl_emb_pmu = {
|
||||
.enable = fsl_emb_pmu_enable,
|
||||
.disable = fsl_emb_pmu_disable,
|
||||
.read = fsl_emb_pmu_read,
|
||||
.unthrottle = fsl_emb_pmu_unthrottle,
|
||||
};
|
||||
|
||||
/*
|
||||
* Release the PMU if this is the last perf_event.
|
||||
*/
|
||||
|
|
@ -428,7 +453,7 @@ static int hw_perf_cache_event(u64 config, u64 *eventp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct pmu *hw_perf_event_init(struct perf_event *event)
|
||||
static int fsl_emb_pmu_event_init(struct perf_event *event)
|
||||
{
|
||||
u64 ev;
|
||||
struct perf_event *events[MAX_HWEVENTS];
|
||||
|
|
@ -441,14 +466,14 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
case PERF_TYPE_HARDWARE:
|
||||
ev = event->attr.config;
|
||||
if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
return -EOPNOTSUPP;
|
||||
ev = ppmu->generic_events[ev];
|
||||
break;
|
||||
|
||||
case PERF_TYPE_HW_CACHE:
|
||||
err = hw_perf_cache_event(event->attr.config, &ev);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return err;
|
||||
break;
|
||||
|
||||
case PERF_TYPE_RAW:
|
||||
|
|
@ -456,12 +481,12 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
break;
|
||||
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
event->hw.config = ppmu->xlate_event(ev);
|
||||
if (!(event->hw.config & FSL_EMB_EVENT_VALID))
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If this is in a group, check if it can go on with all the
|
||||
|
|
@ -473,7 +498,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
n = collect_events(event->group_leader,
|
||||
ppmu->n_counter - 1, events);
|
||||
if (n < 0)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
|
||||
|
|
@ -484,7 +509,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
}
|
||||
|
||||
if (num_restricted >= ppmu->n_restricted)
|
||||
return ERR_PTR(-EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
event->hw.idx = -1;
|
||||
|
|
@ -497,7 +522,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
if (event->attr.exclude_kernel)
|
||||
event->hw.config_base |= PMLCA_FCS;
|
||||
if (event->attr.exclude_idle)
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
return -ENOTSUPP;
|
||||
|
||||
event->hw.last_period = event->hw.sample_period;
|
||||
local64_set(&event->hw.period_left, event->hw.last_period);
|
||||
|
|
@ -523,11 +548,20 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
|
|||
}
|
||||
event->destroy = hw_perf_event_destroy;
|
||||
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return &fsl_emb_pmu;
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct pmu fsl_emb_pmu = {
|
||||
.pmu_enable = fsl_emb_pmu_enable,
|
||||
.pmu_disable = fsl_emb_pmu_disable,
|
||||
.event_init = fsl_emb_pmu_event_init,
|
||||
.add = fsl_emb_pmu_add,
|
||||
.del = fsl_emb_pmu_del,
|
||||
.start = fsl_emb_pmu_start,
|
||||
.stop = fsl_emb_pmu_stop,
|
||||
.read = fsl_emb_pmu_read,
|
||||
};
|
||||
|
||||
/*
|
||||
* A counter has overflowed; update its count and record
|
||||
* things if requested. Note that interrupts are hard-disabled
|
||||
|
|
@ -540,6 +574,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
|
|||
s64 prev, delta, left;
|
||||
int record = 0;
|
||||
|
||||
if (event->hw.state & PERF_HES_STOPPED) {
|
||||
write_pmc(event->hw.idx, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we don't have to worry about interrupts here */
|
||||
prev = local64_read(&event->hw.prev_count);
|
||||
delta = (val - prev) & 0xfffffffful;
|
||||
|
|
@ -562,6 +601,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
|
|||
val = 0x80000000LL - left;
|
||||
}
|
||||
|
||||
write_pmc(event->hw.idx, val);
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
local64_set(&event->hw.period_left, left);
|
||||
perf_event_update_userpage(event);
|
||||
|
||||
/*
|
||||
* Finally record data if requested.
|
||||
*/
|
||||
|
|
@ -571,23 +615,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
|
|||
perf_sample_data_init(&data, 0);
|
||||
data.period = event->hw.last_period;
|
||||
|
||||
if (perf_event_overflow(event, nmi, &data, regs)) {
|
||||
/*
|
||||
* Interrupts are coming too fast - throttle them
|
||||
* by setting the event to 0, so it will be
|
||||
* at least 2^30 cycles until the next interrupt
|
||||
* (assuming each event counts at most 2 counts
|
||||
* per cycle).
|
||||
*/
|
||||
val = 0;
|
||||
left = ~0ULL >> 1;
|
||||
}
|
||||
if (perf_event_overflow(event, nmi, &data, regs))
|
||||
fsl_emb_pmu_stop(event, 0);
|
||||
}
|
||||
|
||||
write_pmc(event->hw.idx, val);
|
||||
local64_set(&event->hw.prev_count, val);
|
||||
local64_set(&event->hw.period_left, left);
|
||||
perf_event_update_userpage(event);
|
||||
}
|
||||
|
||||
static void perf_event_interrupt(struct pt_regs *regs)
|
||||
|
|
@ -651,5 +681,7 @@ int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
|
|||
pr_info("%s performance monitor hardware support registered\n",
|
||||
pmu->name);
|
||||
|
||||
perf_pmu_register(&fsl_emb_pmu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,9 +169,11 @@ static int p970_marked_instr_event(u64 event)
|
|||
switch (unit) {
|
||||
case PM_VPU:
|
||||
mask = 0x4c; /* byte 0 bits 2,3,6 */
|
||||
break;
|
||||
case PM_LSU0:
|
||||
/* byte 2 bits 0,2,3,4,6; all of byte 1 */
|
||||
mask = 0x085dff00;
|
||||
break;
|
||||
case PM_LSU1L:
|
||||
mask = 0x50 << 24; /* byte 3 bits 4,6 */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -517,7 +517,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
|||
|
||||
account_system_vtime(current);
|
||||
account_process_vtime(current);
|
||||
calculate_steal_time();
|
||||
|
||||
/*
|
||||
* We can't take a PMU exception inside _switch() since there is a
|
||||
|
|
@ -1298,14 +1297,3 @@ unsigned long randomize_et_dyn(unsigned long base)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int arch_sd_sibling_asym_packing(void)
|
||||
{
|
||||
if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
|
||||
printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
|
||||
return SD_ASYM_PACKING;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
int __initdata iommu_is_off;
|
||||
int __initdata iommu_force_on;
|
||||
unsigned long tce_alloc_start, tce_alloc_end;
|
||||
u64 ppc64_rma_size;
|
||||
#endif
|
||||
|
||||
static int __init early_parse_mem(char *p)
|
||||
|
|
@ -98,7 +99,7 @@ static void __init move_device_tree(void)
|
|||
|
||||
if ((memory_limit && (start + size) > memory_limit) ||
|
||||
overlaps_crashkernel(start, size)) {
|
||||
p = __va(memblock_alloc_base(size, PAGE_SIZE, memblock.rmo_size));
|
||||
p = __va(memblock_alloc(size, PAGE_SIZE));
|
||||
memcpy(p, initial_boot_params, size);
|
||||
initial_boot_params = (struct boot_param_header *)p;
|
||||
DBG("Moved device tree to 0x%p\n", p);
|
||||
|
|
@ -363,10 +364,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __init early_init_dt_scan_chosen_arch(unsigned long node)
|
||||
int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
|
||||
int depth, void *data)
|
||||
{
|
||||
unsigned long *lprop;
|
||||
|
||||
/* Use common scan routine to determine if this is the chosen node */
|
||||
if (early_init_dt_scan_chosen(node, uname, depth, data) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
/* check if iommu is forced on or off */
|
||||
if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
|
||||
|
|
@ -398,6 +404,9 @@ void __init early_init_dt_scan_chosen_arch(unsigned long node)
|
|||
if (lprop)
|
||||
crashk_res.end = crashk_res.start + *lprop - 1;
|
||||
#endif
|
||||
|
||||
/* break now */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
|
|
@ -492,7 +501,7 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,
|
|||
|
||||
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
|
||||
{
|
||||
#if defined(CONFIG_PPC64)
|
||||
#ifdef CONFIG_PPC64
|
||||
if (iommu_is_off) {
|
||||
if (base >= 0x80000000ul)
|
||||
return;
|
||||
|
|
@ -501,9 +510,13 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
|
|||
}
|
||||
#endif
|
||||
|
||||
memblock_add(base, size);
|
||||
|
||||
/* First MEMBLOCK added, do some special initializations */
|
||||
if (memstart_addr == ~(phys_addr_t)0)
|
||||
setup_initial_memory_limit(base, size);
|
||||
memstart_addr = min((u64)memstart_addr, base);
|
||||
|
||||
/* Add the chunk to the MEMBLOCK list */
|
||||
memblock_add(base, size);
|
||||
}
|
||||
|
||||
u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
|
||||
|
|
@ -655,7 +668,6 @@ static void __init phyp_dump_reserve_mem(void)
|
|||
static inline void __init phyp_dump_reserve_mem(void) {}
|
||||
#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */
|
||||
|
||||
|
||||
void __init early_init_devtree(void *params)
|
||||
{
|
||||
phys_addr_t limit;
|
||||
|
|
@ -679,10 +691,11 @@ void __init early_init_devtree(void *params)
|
|||
* device-tree, including the platform type, initrd location and
|
||||
* size, TCE reserve, and more ...
|
||||
*/
|
||||
of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
|
||||
of_scan_flat_dt(early_init_dt_scan_chosen_ppc, NULL);
|
||||
|
||||
/* Scan memory nodes and rebuild MEMBLOCKs */
|
||||
memblock_init();
|
||||
|
||||
of_scan_flat_dt(early_init_dt_scan_root, NULL);
|
||||
of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -1681,7 +1681,7 @@ long do_syscall_trace_enter(struct pt_regs *regs)
|
|||
|
||||
if (unlikely(current->audit_context)) {
|
||||
#ifdef CONFIG_PPC64
|
||||
if (!test_thread_flag(TIF_32BIT))
|
||||
if (!is_32bit_task())
|
||||
audit_syscall_entry(AUDIT_ARCH_PPC64,
|
||||
regs->gpr[0],
|
||||
regs->gpr[3], regs->gpr[4],
|
||||
|
|
|
|||
|
|
@ -805,7 +805,7 @@ static void rtas_percpu_suspend_me(void *info)
|
|||
__rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
|
||||
}
|
||||
|
||||
static int rtas_ibm_suspend_me(struct rtas_args *args)
|
||||
int rtas_ibm_suspend_me(struct rtas_args *args)
|
||||
{
|
||||
long state;
|
||||
long rc;
|
||||
|
|
@ -855,7 +855,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
|
|||
return atomic_read(&data.error);
|
||||
}
|
||||
#else /* CONFIG_PPC_PSERIES */
|
||||
static int rtas_ibm_suspend_me(struct rtas_args *args)
|
||||
int rtas_ibm_suspend_me(struct rtas_args *args)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
@ -969,7 +969,7 @@ void __init rtas_initialize(void)
|
|||
*/
|
||||
#ifdef CONFIG_PPC64
|
||||
if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) {
|
||||
rtas_region = min(memblock.rmo_size, RTAS_INSTANTIATE_MAX);
|
||||
rtas_region = min(ppc64_rma_size, RTAS_INSTANTIATE_MAX);
|
||||
ibm_suspend_me_token = rtas_token("ibm,suspend-me");
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -716,6 +716,7 @@ static const struct file_operations rtas_flash_operations = {
|
|||
.write = rtas_flash_write,
|
||||
.open = rtas_excl_open,
|
||||
.release = rtas_flash_release,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations manage_flash_operations = {
|
||||
|
|
@ -724,6 +725,7 @@ static const struct file_operations manage_flash_operations = {
|
|||
.write = manage_flash_write,
|
||||
.open = rtas_excl_open,
|
||||
.release = rtas_excl_release,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations validate_flash_operations = {
|
||||
|
|
@ -732,6 +734,7 @@ static const struct file_operations validate_flash_operations = {
|
|||
.write = validate_flash_write,
|
||||
.open = rtas_excl_open,
|
||||
.release = validate_flash_release,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int __init rtas_flash_init(void)
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ static const struct file_operations proc_rtas_log_operations = {
|
|||
.poll = rtas_log_poll,
|
||||
.open = rtas_log_open,
|
||||
.release = rtas_log_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static int enable_surveillance(int timeout)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
extern void bootx_init(unsigned long r4, unsigned long phys);
|
||||
|
||||
int boot_cpuid;
|
||||
int boot_cpuid = -1;
|
||||
EXPORT_SYMBOL_GPL(boot_cpuid);
|
||||
int boot_cpuid_phys;
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ static void __init irqstack_early_init(void)
|
|||
unsigned int i;
|
||||
|
||||
/* interrupt stacks must be in lowmem, we get that for free on ppc32
|
||||
* as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */
|
||||
* as the memblock is limited to lowmem by default */
|
||||
for_each_possible_cpu(i) {
|
||||
softirq_ctx[i] = (struct thread_info *)
|
||||
__va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ static void __init emergency_stack_init(void)
|
|||
* bringup, we need to get at them in real mode. This means they
|
||||
* must also be within the RMO region.
|
||||
*/
|
||||
limit = min(slb0_limit(), memblock.rmo_size);
|
||||
limit = min(slb0_limit(), ppc64_rma_size);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
unsigned long sp;
|
||||
|
|
|
|||
|
|
@ -508,9 +508,6 @@ int __devinit start_secondary(void *unused)
|
|||
if (smp_ops->take_timebase)
|
||||
smp_ops->take_timebase();
|
||||
|
||||
if (system_state > SYSTEM_BOOTING)
|
||||
snapshot_timebase();
|
||||
|
||||
secondary_cpu_time_init();
|
||||
|
||||
ipi_call_lock();
|
||||
|
|
@ -575,11 +572,18 @@ void __init smp_cpus_done(unsigned int max_cpus)
|
|||
|
||||
free_cpumask_var(old_mask);
|
||||
|
||||
snapshot_timebases();
|
||||
|
||||
dump_numa_cpu_topology();
|
||||
}
|
||||
|
||||
int arch_sd_sibling_asym_packing(void)
|
||||
{
|
||||
if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
|
||||
printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
|
||||
return SD_ASYM_PACKING;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int __cpu_disable(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
#include <linux/posix-timers.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <asm/trace.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
|
@ -161,10 +161,9 @@ extern struct timezone sys_tz;
|
|||
static long timezone_offset;
|
||||
|
||||
unsigned long ppc_proc_freq;
|
||||
EXPORT_SYMBOL(ppc_proc_freq);
|
||||
EXPORT_SYMBOL_GPL(ppc_proc_freq);
|
||||
unsigned long ppc_tb_freq;
|
||||
|
||||
static DEFINE_PER_CPU(u64, last_jiffy);
|
||||
EXPORT_SYMBOL_GPL(ppc_tb_freq);
|
||||
|
||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
|
||||
/*
|
||||
|
|
@ -185,6 +184,8 @@ DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
|
|||
|
||||
cputime_t cputime_one_jiffy;
|
||||
|
||||
void (*dtl_consumer)(struct dtl_entry *, u64);
|
||||
|
||||
static void calc_cputime_factors(void)
|
||||
{
|
||||
struct div_result res;
|
||||
|
|
@ -200,62 +201,153 @@ static void calc_cputime_factors(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Read the PURR on systems that have it, otherwise the timebase.
|
||||
* Read the SPURR on systems that have it, otherwise the PURR,
|
||||
* or if that doesn't exist return the timebase value passed in.
|
||||
*/
|
||||
static u64 read_purr(void)
|
||||
static u64 read_spurr(u64 tb)
|
||||
{
|
||||
if (cpu_has_feature(CPU_FTR_SPURR))
|
||||
return mfspr(SPRN_SPURR);
|
||||
if (cpu_has_feature(CPU_FTR_PURR))
|
||||
return mfspr(SPRN_PURR);
|
||||
return mftb();
|
||||
return tb;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_SPLPAR
|
||||
|
||||
/*
|
||||
* Scan the dispatch trace log and count up the stolen time.
|
||||
* Should be called with interrupts disabled.
|
||||
*/
|
||||
static u64 scan_dispatch_log(u64 stop_tb)
|
||||
{
|
||||
u64 i = local_paca->dtl_ridx;
|
||||
struct dtl_entry *dtl = local_paca->dtl_curr;
|
||||
struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
|
||||
struct lppaca *vpa = local_paca->lppaca_ptr;
|
||||
u64 tb_delta;
|
||||
u64 stolen = 0;
|
||||
u64 dtb;
|
||||
|
||||
if (i == vpa->dtl_idx)
|
||||
return 0;
|
||||
while (i < vpa->dtl_idx) {
|
||||
if (dtl_consumer)
|
||||
dtl_consumer(dtl, i);
|
||||
dtb = dtl->timebase;
|
||||
tb_delta = dtl->enqueue_to_dispatch_time +
|
||||
dtl->ready_to_enqueue_time;
|
||||
barrier();
|
||||
if (i + N_DISPATCH_LOG < vpa->dtl_idx) {
|
||||
/* buffer has overflowed */
|
||||
i = vpa->dtl_idx - N_DISPATCH_LOG;
|
||||
dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
|
||||
continue;
|
||||
}
|
||||
if (dtb > stop_tb)
|
||||
break;
|
||||
stolen += tb_delta;
|
||||
++i;
|
||||
++dtl;
|
||||
if (dtl == dtl_end)
|
||||
dtl = local_paca->dispatch_log;
|
||||
}
|
||||
local_paca->dtl_ridx = i;
|
||||
local_paca->dtl_curr = dtl;
|
||||
return stolen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the SPURR on systems that have it, otherwise the purr
|
||||
* Accumulate stolen time by scanning the dispatch trace log.
|
||||
* Called on entry from user mode.
|
||||
*/
|
||||
static u64 read_spurr(u64 purr)
|
||||
void accumulate_stolen_time(void)
|
||||
{
|
||||
/*
|
||||
* cpus without PURR won't have a SPURR
|
||||
* We already know the former when we use this, so tell gcc
|
||||
*/
|
||||
if (cpu_has_feature(CPU_FTR_PURR) && cpu_has_feature(CPU_FTR_SPURR))
|
||||
return mfspr(SPRN_SPURR);
|
||||
return purr;
|
||||
u64 sst, ust;
|
||||
|
||||
sst = scan_dispatch_log(get_paca()->starttime_user);
|
||||
ust = scan_dispatch_log(get_paca()->starttime);
|
||||
get_paca()->system_time -= sst;
|
||||
get_paca()->user_time -= ust;
|
||||
get_paca()->stolen_time += ust + sst;
|
||||
}
|
||||
|
||||
static inline u64 calculate_stolen_time(u64 stop_tb)
|
||||
{
|
||||
u64 stolen = 0;
|
||||
|
||||
if (get_paca()->dtl_ridx != get_paca()->lppaca_ptr->dtl_idx) {
|
||||
stolen = scan_dispatch_log(stop_tb);
|
||||
get_paca()->system_time -= stolen;
|
||||
}
|
||||
|
||||
stolen += get_paca()->stolen_time;
|
||||
get_paca()->stolen_time = 0;
|
||||
return stolen;
|
||||
}
|
||||
|
||||
#else /* CONFIG_PPC_SPLPAR */
|
||||
static inline u64 calculate_stolen_time(u64 stop_tb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PPC_SPLPAR */
|
||||
|
||||
/*
|
||||
* Account time for a transition between system, hard irq
|
||||
* or soft irq state.
|
||||
*/
|
||||
void account_system_vtime(struct task_struct *tsk)
|
||||
{
|
||||
u64 now, nowscaled, delta, deltascaled, sys_time;
|
||||
u64 now, nowscaled, delta, deltascaled;
|
||||
unsigned long flags;
|
||||
u64 stolen, udelta, sys_scaled, user_scaled;
|
||||
|
||||
local_irq_save(flags);
|
||||
now = read_purr();
|
||||
now = mftb();
|
||||
nowscaled = read_spurr(now);
|
||||
delta = now - get_paca()->startpurr;
|
||||
get_paca()->system_time += now - get_paca()->starttime;
|
||||
get_paca()->starttime = now;
|
||||
deltascaled = nowscaled - get_paca()->startspurr;
|
||||
get_paca()->startpurr = now;
|
||||
get_paca()->startspurr = nowscaled;
|
||||
if (!in_interrupt()) {
|
||||
/* deltascaled includes both user and system time.
|
||||
* Hence scale it based on the purr ratio to estimate
|
||||
* the system time */
|
||||
sys_time = get_paca()->system_time;
|
||||
if (get_paca()->user_time)
|
||||
deltascaled = deltascaled * sys_time /
|
||||
(sys_time + get_paca()->user_time);
|
||||
delta += sys_time;
|
||||
get_paca()->system_time = 0;
|
||||
|
||||
stolen = calculate_stolen_time(now);
|
||||
|
||||
delta = get_paca()->system_time;
|
||||
get_paca()->system_time = 0;
|
||||
udelta = get_paca()->user_time - get_paca()->utime_sspurr;
|
||||
get_paca()->utime_sspurr = get_paca()->user_time;
|
||||
|
||||
/*
|
||||
* Because we don't read the SPURR on every kernel entry/exit,
|
||||
* deltascaled includes both user and system SPURR ticks.
|
||||
* Apportion these ticks to system SPURR ticks and user
|
||||
* SPURR ticks in the same ratio as the system time (delta)
|
||||
* and user time (udelta) values obtained from the timebase
|
||||
* over the same interval. The system ticks get accounted here;
|
||||
* the user ticks get saved up in paca->user_time_scaled to be
|
||||
* used by account_process_tick.
|
||||
*/
|
||||
sys_scaled = delta;
|
||||
user_scaled = udelta;
|
||||
if (deltascaled != delta + udelta) {
|
||||
if (udelta) {
|
||||
sys_scaled = deltascaled * delta / (delta + udelta);
|
||||
user_scaled = deltascaled - sys_scaled;
|
||||
} else {
|
||||
sys_scaled = deltascaled;
|
||||
}
|
||||
}
|
||||
get_paca()->user_time_scaled += user_scaled;
|
||||
|
||||
if (in_irq() || idle_task(smp_processor_id()) != tsk) {
|
||||
account_system_time(tsk, 0, delta, sys_scaled);
|
||||
if (stolen)
|
||||
account_steal_time(stolen);
|
||||
} else {
|
||||
account_idle_time(delta + stolen);
|
||||
}
|
||||
if (in_irq() || idle_task(smp_processor_id()) != tsk)
|
||||
account_system_time(tsk, 0, delta, deltascaled);
|
||||
else
|
||||
account_idle_time(delta);
|
||||
__get_cpu_var(cputime_last_delta) = delta;
|
||||
__get_cpu_var(cputime_scaled_last_delta) = deltascaled;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(account_system_vtime);
|
||||
|
|
@ -265,125 +357,26 @@ EXPORT_SYMBOL_GPL(account_system_vtime);
|
|||
* by the exception entry and exit code to the generic process
|
||||
* user and system time records.
|
||||
* Must be called with interrupts disabled.
|
||||
* Assumes that account_system_vtime() has been called recently
|
||||
* (i.e. since the last entry from usermode) so that
|
||||
* get_paca()->user_time_scaled is up to date.
|
||||
*/
|
||||
void account_process_tick(struct task_struct *tsk, int user_tick)
|
||||
{
|
||||
cputime_t utime, utimescaled;
|
||||
|
||||
utime = get_paca()->user_time;
|
||||
utimescaled = get_paca()->user_time_scaled;
|
||||
get_paca()->user_time = 0;
|
||||
utimescaled = cputime_to_scaled(utime);
|
||||
get_paca()->user_time_scaled = 0;
|
||||
get_paca()->utime_sspurr = 0;
|
||||
account_user_time(tsk, utime, utimescaled);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff for accounting stolen time.
|
||||
*/
|
||||
struct cpu_purr_data {
|
||||
int initialized; /* thread is running */
|
||||
u64 tb; /* last TB value read */
|
||||
u64 purr; /* last PURR value read */
|
||||
u64 spurr; /* last SPURR value read */
|
||||
};
|
||||
|
||||
/*
|
||||
* Each entry in the cpu_purr_data array is manipulated only by its
|
||||
* "owner" cpu -- usually in the timer interrupt but also occasionally
|
||||
* in process context for cpu online. As long as cpus do not touch
|
||||
* each others' cpu_purr_data, disabling local interrupts is
|
||||
* sufficient to serialize accesses.
|
||||
*/
|
||||
static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data);
|
||||
|
||||
static void snapshot_tb_and_purr(void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
|
||||
|
||||
local_irq_save(flags);
|
||||
p->tb = get_tb_or_rtc();
|
||||
p->purr = mfspr(SPRN_PURR);
|
||||
wmb();
|
||||
p->initialized = 1;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called during boot when all cpus have come up.
|
||||
*/
|
||||
void snapshot_timebases(void)
|
||||
{
|
||||
if (!cpu_has_feature(CPU_FTR_PURR))
|
||||
return;
|
||||
on_each_cpu(snapshot_tb_and_purr, NULL, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with interrupts disabled.
|
||||
*/
|
||||
void calculate_steal_time(void)
|
||||
{
|
||||
u64 tb, purr;
|
||||
s64 stolen;
|
||||
struct cpu_purr_data *pme;
|
||||
|
||||
pme = &__get_cpu_var(cpu_purr_data);
|
||||
if (!pme->initialized)
|
||||
return; /* !CPU_FTR_PURR or early in early boot */
|
||||
tb = mftb();
|
||||
purr = mfspr(SPRN_PURR);
|
||||
stolen = (tb - pme->tb) - (purr - pme->purr);
|
||||
if (stolen > 0) {
|
||||
if (idle_task(smp_processor_id()) != current)
|
||||
account_steal_time(stolen);
|
||||
else
|
||||
account_idle_time(stolen);
|
||||
}
|
||||
pme->tb = tb;
|
||||
pme->purr = purr;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_SPLPAR
|
||||
/*
|
||||
* Must be called before the cpu is added to the online map when
|
||||
* a cpu is being brought up at runtime.
|
||||
*/
|
||||
static void snapshot_purr(void)
|
||||
{
|
||||
struct cpu_purr_data *pme;
|
||||
unsigned long flags;
|
||||
|
||||
if (!cpu_has_feature(CPU_FTR_PURR))
|
||||
return;
|
||||
local_irq_save(flags);
|
||||
pme = &__get_cpu_var(cpu_purr_data);
|
||||
pme->tb = mftb();
|
||||
pme->purr = mfspr(SPRN_PURR);
|
||||
pme->initialized = 1;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PPC_SPLPAR */
|
||||
|
||||
#else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
|
||||
#define calc_cputime_factors()
|
||||
#define calculate_steal_time() do { } while (0)
|
||||
#endif
|
||||
|
||||
#if !(defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR))
|
||||
#define snapshot_purr() do { } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called when a cpu comes up after the system has finished booting,
|
||||
* i.e. as a result of a hotplug cpu action.
|
||||
*/
|
||||
void snapshot_timebase(void)
|
||||
{
|
||||
__get_cpu_var(last_jiffy) = get_tb_or_rtc();
|
||||
snapshot_purr();
|
||||
}
|
||||
|
||||
void __delay(unsigned long loops)
|
||||
{
|
||||
unsigned long start;
|
||||
|
|
@ -493,60 +486,60 @@ void __init iSeries_time_init_early(void)
|
|||
}
|
||||
#endif /* CONFIG_PPC_ISERIES */
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
#ifdef CONFIG_IRQ_WORK
|
||||
|
||||
/*
|
||||
* 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
|
||||
*/
|
||||
#ifdef CONFIG_PPC64
|
||||
static inline unsigned long test_perf_event_pending(void)
|
||||
static inline unsigned long test_irq_work_pending(void)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
asm volatile("lbz %0,%1(13)"
|
||||
: "=r" (x)
|
||||
: "i" (offsetof(struct paca_struct, perf_event_pending)));
|
||||
: "i" (offsetof(struct paca_struct, irq_work_pending)));
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline void set_perf_event_pending_flag(void)
|
||||
static inline void set_irq_work_pending_flag(void)
|
||||
{
|
||||
asm volatile("stb %0,%1(13)" : :
|
||||
"r" (1),
|
||||
"i" (offsetof(struct paca_struct, perf_event_pending)));
|
||||
"i" (offsetof(struct paca_struct, irq_work_pending)));
|
||||
}
|
||||
|
||||
static inline void clear_perf_event_pending(void)
|
||||
static inline void clear_irq_work_pending(void)
|
||||
{
|
||||
asm volatile("stb %0,%1(13)" : :
|
||||
"r" (0),
|
||||
"i" (offsetof(struct paca_struct, perf_event_pending)));
|
||||
"i" (offsetof(struct paca_struct, irq_work_pending)));
|
||||
}
|
||||
|
||||
#else /* 32-bit */
|
||||
|
||||
DEFINE_PER_CPU(u8, perf_event_pending);
|
||||
DEFINE_PER_CPU(u8, irq_work_pending);
|
||||
|
||||
#define set_perf_event_pending_flag() __get_cpu_var(perf_event_pending) = 1
|
||||
#define test_perf_event_pending() __get_cpu_var(perf_event_pending)
|
||||
#define clear_perf_event_pending() __get_cpu_var(perf_event_pending) = 0
|
||||
#define set_irq_work_pending_flag() __get_cpu_var(irq_work_pending) = 1
|
||||
#define test_irq_work_pending() __get_cpu_var(irq_work_pending)
|
||||
#define clear_irq_work_pending() __get_cpu_var(irq_work_pending) = 0
|
||||
|
||||
#endif /* 32 vs 64 bit */
|
||||
|
||||
void set_perf_event_pending(void)
|
||||
void set_irq_work_pending(void)
|
||||
{
|
||||
preempt_disable();
|
||||
set_perf_event_pending_flag();
|
||||
set_irq_work_pending_flag();
|
||||
set_dec(1);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
#else /* CONFIG_PERF_EVENTS */
|
||||
#else /* CONFIG_IRQ_WORK */
|
||||
|
||||
#define test_perf_event_pending() 0
|
||||
#define clear_perf_event_pending()
|
||||
#define test_irq_work_pending() 0
|
||||
#define clear_irq_work_pending()
|
||||
|
||||
#endif /* CONFIG_PERF_EVENTS */
|
||||
#endif /* CONFIG_IRQ_WORK */
|
||||
|
||||
/*
|
||||
* For iSeries shared processors, we have to let the hypervisor
|
||||
|
|
@ -585,11 +578,9 @@ void timer_interrupt(struct pt_regs * regs)
|
|||
old_regs = set_irq_regs(regs);
|
||||
irq_enter();
|
||||
|
||||
calculate_steal_time();
|
||||
|
||||
if (test_perf_event_pending()) {
|
||||
clear_perf_event_pending();
|
||||
perf_event_do_pending();
|
||||
if (test_irq_work_pending()) {
|
||||
clear_irq_work_pending();
|
||||
irq_work_run();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_ISERIES
|
||||
|
|
|
|||
|
|
@ -538,6 +538,11 @@ int machine_check_e500(struct pt_regs *regs)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int machine_check_generic(struct pt_regs *regs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#elif defined(CONFIG_E200)
|
||||
int machine_check_e200(struct pt_regs *regs)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
|
|||
{
|
||||
int i;
|
||||
|
||||
if (!vma || test_thread_flag(TIF_32BIT)) {
|
||||
if (!vma || is_32bit_task()) {
|
||||
printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
|
||||
for (i=0; i<vdso32_pages; i++) {
|
||||
struct page *pg = virt_to_page(vdso32_kbase +
|
||||
|
|
@ -170,7 +170,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
|
|||
dump_one_vdso_page(pg, upg);
|
||||
}
|
||||
}
|
||||
if (!vma || !test_thread_flag(TIF_32BIT)) {
|
||||
if (!vma || !is_32bit_task()) {
|
||||
printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
|
||||
for (i=0; i<vdso64_pages; i++) {
|
||||
struct page *pg = virt_to_page(vdso64_kbase +
|
||||
|
|
@ -200,7 +200,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
|||
return 0;
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
if (is_32bit_task()) {
|
||||
vdso_pagelist = vdso32_pagelist;
|
||||
vdso_pages = vdso32_pages;
|
||||
vdso_base = VDSO32_MBASE;
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
|
|||
|
||||
GCOV_PROFILE := n
|
||||
|
||||
EXTRA_CFLAGS := -shared -fno-common -fno-builtin
|
||||
EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
|
||||
ccflags-y := -shared -fno-common -fno-builtin
|
||||
ccflags-y += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
|
||||
$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
|
||||
EXTRA_AFLAGS := -D__VDSO32__ -s
|
||||
asflags-y := -D__VDSO32__ -s
|
||||
|
||||
obj-y += vdso32_wrapper.o
|
||||
extra-y += vdso32.lds
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
|
|||
|
||||
GCOV_PROFILE := n
|
||||
|
||||
EXTRA_CFLAGS := -shared -fno-common -fno-builtin
|
||||
EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
|
||||
ccflags-y := -shared -fno-common -fno-builtin
|
||||
ccflags-y += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
|
||||
$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
|
||||
EXTRA_AFLAGS := -D__VDSO64__ -s
|
||||
asflags-y := -D__VDSO64__ -s
|
||||
|
||||
obj-y += vdso64_wrapper.o
|
||||
extra-y += vdso64.lds
|
||||
|
|
|
|||
|
|
@ -1184,7 +1184,12 @@ EXPORT_SYMBOL(vio_unregister_driver);
|
|||
/* vio_dev refcount hit 0 */
|
||||
static void __devinit vio_dev_release(struct device *dev)
|
||||
{
|
||||
/* XXX should free TCE table */
|
||||
struct iommu_table *tbl = get_iommu_table_base(dev);
|
||||
|
||||
/* iSeries uses a common table for all vio devices */
|
||||
if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl)
|
||||
iommu_free_table(tbl, dev->of_node ?
|
||||
dev->of_node->full_name : dev_name(dev));
|
||||
of_node_put(dev->of_node);
|
||||
kfree(to_vio_dev(dev));
|
||||
}
|
||||
|
|
@ -1254,8 +1259,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
|
|||
if (device_register(&viodev->dev)) {
|
||||
printk(KERN_ERR "%s: failed to register device %s\n",
|
||||
__func__, dev_name(&viodev->dev));
|
||||
/* XXX free TCE table */
|
||||
kfree(viodev);
|
||||
put_device(&viodev->dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ int kvmppc_core_check_processor_compat(void)
|
|||
{
|
||||
int r;
|
||||
|
||||
if (strcmp(cur_cpu_spec->platform, "ppc440") == 0)
|
||||
if (strncmp(cur_cpu_spec->platform, "ppc440", 6) == 0)
|
||||
r = 0;
|
||||
else
|
||||
r = -ENOTSUPP;
|
||||
|
|
@ -72,6 +72,7 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
|
|||
/* Since the guest can directly access the timebase, it must know the
|
||||
* real timebase frequency. Accordingly, it must see the state of
|
||||
* CCR1[TCS]. */
|
||||
/* XXX CCR1 doesn't exist on all 440 SoCs. */
|
||||
vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++)
|
||||
|
|
@ -123,8 +124,14 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|||
if (err)
|
||||
goto free_vcpu;
|
||||
|
||||
vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO);
|
||||
if (!vcpu->arch.shared)
|
||||
goto uninit_vcpu;
|
||||
|
||||
return vcpu;
|
||||
|
||||
uninit_vcpu:
|
||||
kvm_vcpu_uninit(vcpu);
|
||||
free_vcpu:
|
||||
kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
|
||||
out:
|
||||
|
|
@ -135,6 +142,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
|
||||
|
||||
free_page((unsigned long)vcpu->arch.shared);
|
||||
kvm_vcpu_uninit(vcpu);
|
||||
kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#ifdef DEBUG
|
||||
void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
|
||||
struct kvmppc_44x_tlbe *tlbe;
|
||||
int i;
|
||||
|
||||
|
|
@ -221,14 +222,14 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index,
|
|||
|
||||
int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
|
||||
{
|
||||
unsigned int as = !!(vcpu->arch.msr & MSR_IS);
|
||||
unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
|
||||
|
||||
return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
|
||||
}
|
||||
|
||||
int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
|
||||
{
|
||||
unsigned int as = !!(vcpu->arch.msr & MSR_DS);
|
||||
unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
|
||||
|
||||
return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
|
||||
}
|
||||
|
|
@ -354,7 +355,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
|
|||
|
||||
stlbe.word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
|
||||
stlbe.word2 = kvmppc_44x_tlb_shadow_attrib(flags,
|
||||
vcpu->arch.msr & MSR_PR);
|
||||
vcpu->arch.shared->msr & MSR_PR);
|
||||
stlbe.tid = !(asid & 0xff);
|
||||
|
||||
/* Keep track of the reference so we can properly release it later. */
|
||||
|
|
@ -423,7 +424,7 @@ static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
|
|||
|
||||
/* Does it match current guest AS? */
|
||||
/* XXX what about IS != DS? */
|
||||
if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
|
||||
if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
|
||||
return 0;
|
||||
|
||||
gpa = get_tlb_raddr(tlbe);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
|
||||
|
||||
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
|
||||
ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
|
||||
|
||||
common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kvm_host.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include "trace.h"
|
||||
|
||||
#include <asm/reg.h>
|
||||
#include <asm/cputable.h>
|
||||
|
|
@ -35,7 +36,6 @@
|
|||
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
|
||||
|
||||
/* #define EXIT_DEBUG */
|
||||
/* #define EXIT_DEBUG_SIMPLE */
|
||||
/* #define DEBUG_EXT */
|
||||
|
||||
static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
|
||||
|
|
@ -105,65 +105,71 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
|
|||
kvmppc_giveup_ext(vcpu, MSR_VSX);
|
||||
}
|
||||
|
||||
#if defined(EXIT_DEBUG)
|
||||
static u32 kvmppc_get_dec(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 jd = mftb() - vcpu->arch.dec_jiffies;
|
||||
return vcpu->arch.dec - jd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.shadow_msr = vcpu->arch.msr;
|
||||
ulong smsr = vcpu->arch.shared->msr;
|
||||
|
||||
/* Guest MSR values */
|
||||
vcpu->arch.shadow_msr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE |
|
||||
MSR_BE | MSR_DE;
|
||||
smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE;
|
||||
/* Process MSR values */
|
||||
vcpu->arch.shadow_msr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR |
|
||||
MSR_EE;
|
||||
smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
|
||||
/* External providers the guest reserved */
|
||||
vcpu->arch.shadow_msr |= (vcpu->arch.msr & vcpu->arch.guest_owned_ext);
|
||||
smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext);
|
||||
/* 64-bit Process MSR values */
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
vcpu->arch.shadow_msr |= MSR_ISF | MSR_HV;
|
||||
smsr |= MSR_ISF | MSR_HV;
|
||||
#endif
|
||||
vcpu->arch.shadow_msr = smsr;
|
||||
}
|
||||
|
||||
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
|
||||
{
|
||||
ulong old_msr = vcpu->arch.msr;
|
||||
ulong old_msr = vcpu->arch.shared->msr;
|
||||
|
||||
#ifdef EXIT_DEBUG
|
||||
printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr);
|
||||
#endif
|
||||
|
||||
msr &= to_book3s(vcpu)->msr_mask;
|
||||
vcpu->arch.msr = msr;
|
||||
vcpu->arch.shared->msr = msr;
|
||||
kvmppc_recalc_shadow_msr(vcpu);
|
||||
|
||||
if (msr & (MSR_WE|MSR_POW)) {
|
||||
if (msr & MSR_POW) {
|
||||
if (!vcpu->arch.pending_exceptions) {
|
||||
kvm_vcpu_block(vcpu);
|
||||
vcpu->stat.halt_wakeup++;
|
||||
|
||||
/* Unset POW bit after we woke up */
|
||||
msr &= ~MSR_POW;
|
||||
vcpu->arch.shared->msr = msr;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) !=
|
||||
if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) !=
|
||||
(old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
|
||||
kvmppc_mmu_flush_segments(vcpu);
|
||||
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
|
||||
|
||||
/* Preload magic page segment when in kernel mode */
|
||||
if (!(msr & MSR_PR) && vcpu->arch.magic_page_pa) {
|
||||
struct kvm_vcpu_arch *a = &vcpu->arch;
|
||||
|
||||
if (msr & MSR_DR)
|
||||
kvmppc_mmu_map_segment(vcpu, a->magic_page_ea);
|
||||
else
|
||||
kvmppc_mmu_map_segment(vcpu, a->magic_page_pa);
|
||||
}
|
||||
}
|
||||
|
||||
/* Preload FPU if it's enabled */
|
||||
if (vcpu->arch.msr & MSR_FP)
|
||||
if (vcpu->arch.shared->msr & MSR_FP)
|
||||
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
|
||||
}
|
||||
|
||||
void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
|
||||
{
|
||||
vcpu->arch.srr0 = kvmppc_get_pc(vcpu);
|
||||
vcpu->arch.srr1 = vcpu->arch.msr | flags;
|
||||
vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu);
|
||||
vcpu->arch.shared->srr1 = vcpu->arch.shared->msr | flags;
|
||||
kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec);
|
||||
vcpu->arch.mmu.reset_msr(vcpu);
|
||||
}
|
||||
|
|
@ -180,6 +186,7 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec)
|
|||
case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break;
|
||||
case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break;
|
||||
case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break;
|
||||
case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL; break;
|
||||
case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break;
|
||||
case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break;
|
||||
case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break;
|
||||
|
|
@ -199,6 +206,9 @@ static void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
clear_bit(kvmppc_book3s_vec2irqprio(vec),
|
||||
&vcpu->arch.pending_exceptions);
|
||||
|
||||
if (!vcpu->arch.pending_exceptions)
|
||||
vcpu->arch.shared->int_pending = 0;
|
||||
}
|
||||
|
||||
void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
|
||||
|
|
@ -237,13 +247,19 @@ void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
|
|||
void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
|
||||
struct kvm_interrupt *irq)
|
||||
{
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
|
||||
unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL;
|
||||
|
||||
if (irq->irq == KVM_INTERRUPT_SET_LEVEL)
|
||||
vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL;
|
||||
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec);
|
||||
}
|
||||
|
||||
void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
|
||||
struct kvm_interrupt *irq)
|
||||
{
|
||||
kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
|
||||
kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
|
||||
}
|
||||
|
||||
int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
|
||||
|
|
@ -251,14 +267,29 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
|
|||
int deliver = 1;
|
||||
int vec = 0;
|
||||
ulong flags = 0ULL;
|
||||
ulong crit_raw = vcpu->arch.shared->critical;
|
||||
ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
|
||||
bool crit;
|
||||
|
||||
/* Truncate crit indicators in 32 bit mode */
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF)) {
|
||||
crit_raw &= 0xffffffff;
|
||||
crit_r1 &= 0xffffffff;
|
||||
}
|
||||
|
||||
/* Critical section when crit == r1 */
|
||||
crit = (crit_raw == crit_r1);
|
||||
/* ... and we're in supervisor mode */
|
||||
crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
|
||||
|
||||
switch (priority) {
|
||||
case BOOK3S_IRQPRIO_DECREMENTER:
|
||||
deliver = vcpu->arch.msr & MSR_EE;
|
||||
deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
|
||||
vec = BOOK3S_INTERRUPT_DECREMENTER;
|
||||
break;
|
||||
case BOOK3S_IRQPRIO_EXTERNAL:
|
||||
deliver = vcpu->arch.msr & MSR_EE;
|
||||
case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
|
||||
deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
|
||||
vec = BOOK3S_INTERRUPT_EXTERNAL;
|
||||
break;
|
||||
case BOOK3S_IRQPRIO_SYSTEM_RESET:
|
||||
|
|
@ -320,9 +351,27 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
|
|||
return deliver;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function determines if an irqprio should be cleared once issued.
|
||||
*/
|
||||
static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority)
|
||||
{
|
||||
switch (priority) {
|
||||
case BOOK3S_IRQPRIO_DECREMENTER:
|
||||
/* DEC interrupts get cleared by mtdec */
|
||||
return false;
|
||||
case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
|
||||
/* External interrupts get cleared by userspace */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long *pending = &vcpu->arch.pending_exceptions;
|
||||
unsigned long old_pending = vcpu->arch.pending_exceptions;
|
||||
unsigned int priority;
|
||||
|
||||
#ifdef EXIT_DEBUG
|
||||
|
|
@ -332,8 +381,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
|
|||
priority = __ffs(*pending);
|
||||
while (priority < BOOK3S_IRQPRIO_MAX) {
|
||||
if (kvmppc_book3s_irqprio_deliver(vcpu, priority) &&
|
||||
(priority != BOOK3S_IRQPRIO_DECREMENTER)) {
|
||||
/* DEC interrupts get cleared by mtdec */
|
||||
clear_irqprio(vcpu, priority)) {
|
||||
clear_bit(priority, &vcpu->arch.pending_exceptions);
|
||||
break;
|
||||
}
|
||||
|
|
@ -342,6 +390,12 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
|
|||
BITS_PER_BYTE * sizeof(*pending),
|
||||
priority + 1);
|
||||
}
|
||||
|
||||
/* Tell the guest about our interrupt status */
|
||||
if (*pending)
|
||||
vcpu->arch.shared->int_pending = 1;
|
||||
else if (old_pending)
|
||||
vcpu->arch.shared->int_pending = 0;
|
||||
}
|
||||
|
||||
void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
|
||||
|
|
@ -398,6 +452,25 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
|
|||
}
|
||||
}
|
||||
|
||||
pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn)
|
||||
{
|
||||
ulong mp_pa = vcpu->arch.magic_page_pa;
|
||||
|
||||
/* Magic page override */
|
||||
if (unlikely(mp_pa) &&
|
||||
unlikely(((gfn << PAGE_SHIFT) & KVM_PAM) ==
|
||||
((mp_pa & PAGE_MASK) & KVM_PAM))) {
|
||||
ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
|
||||
pfn_t pfn;
|
||||
|
||||
pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
|
||||
get_page(pfn_to_page(pfn));
|
||||
return pfn;
|
||||
}
|
||||
|
||||
return gfn_to_pfn(vcpu->kvm, gfn);
|
||||
}
|
||||
|
||||
/* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To
|
||||
* make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to
|
||||
* emulate 32 bytes dcbz length.
|
||||
|
|
@ -415,8 +488,10 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
|
|||
int i;
|
||||
|
||||
hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
|
||||
if (is_error_page(hpage))
|
||||
if (is_error_page(hpage)) {
|
||||
kvm_release_page_clean(hpage);
|
||||
return;
|
||||
}
|
||||
|
||||
hpage_offset = pte->raddr & ~PAGE_MASK;
|
||||
hpage_offset &= ~0xFFFULL;
|
||||
|
|
@ -437,14 +512,14 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
|
|||
static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
|
||||
struct kvmppc_pte *pte)
|
||||
{
|
||||
int relocated = (vcpu->arch.msr & (data ? MSR_DR : MSR_IR));
|
||||
int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR));
|
||||
int r;
|
||||
|
||||
if (relocated) {
|
||||
r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data);
|
||||
} else {
|
||||
pte->eaddr = eaddr;
|
||||
pte->raddr = eaddr & 0xffffffff;
|
||||
pte->raddr = eaddr & KVM_PAM;
|
||||
pte->vpage = VSID_REAL | eaddr >> 12;
|
||||
pte->may_read = true;
|
||||
pte->may_write = true;
|
||||
|
|
@ -533,6 +608,13 @@ mmio:
|
|||
|
||||
static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)
|
||||
{
|
||||
ulong mp_pa = vcpu->arch.magic_page_pa;
|
||||
|
||||
if (unlikely(mp_pa) &&
|
||||
unlikely((mp_pa & KVM_PAM) >> PAGE_SHIFT == gfn)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return kvm_is_visible_gfn(vcpu->kvm, gfn);
|
||||
}
|
||||
|
||||
|
|
@ -545,8 +627,8 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
int page_found = 0;
|
||||
struct kvmppc_pte pte;
|
||||
bool is_mmio = false;
|
||||
bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
|
||||
bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
|
||||
bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false;
|
||||
bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false;
|
||||
u64 vsid;
|
||||
|
||||
relocated = data ? dr : ir;
|
||||
|
|
@ -558,12 +640,12 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
pte.may_execute = true;
|
||||
pte.may_read = true;
|
||||
pte.may_write = true;
|
||||
pte.raddr = eaddr & 0xffffffff;
|
||||
pte.raddr = eaddr & KVM_PAM;
|
||||
pte.eaddr = eaddr;
|
||||
pte.vpage = eaddr >> 12;
|
||||
}
|
||||
|
||||
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
case 0:
|
||||
pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
|
||||
break;
|
||||
|
|
@ -571,7 +653,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
case MSR_IR:
|
||||
vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
|
||||
|
||||
if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR)
|
||||
if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR)
|
||||
pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
|
||||
else
|
||||
pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
|
||||
|
|
@ -594,20 +676,23 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
|
||||
if (page_found == -ENOENT) {
|
||||
/* Page not found in guest PTE entries */
|
||||
vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
|
||||
to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
|
||||
vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
|
||||
vcpu->arch.shared->msr |=
|
||||
(to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec);
|
||||
} else if (page_found == -EPERM) {
|
||||
/* Storage protection */
|
||||
vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
|
||||
to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
|
||||
to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT;
|
||||
vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
vcpu->arch.shared->dsisr =
|
||||
to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
|
||||
vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
|
||||
vcpu->arch.shared->msr |=
|
||||
(to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec);
|
||||
} else if (page_found == -EINVAL) {
|
||||
/* Page not found in guest SLB */
|
||||
vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
|
||||
} else if (!is_mmio &&
|
||||
kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
|
||||
|
|
@ -695,9 +780,11 @@ static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
|
|||
|
||||
ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
|
||||
if (ret == -ENOENT) {
|
||||
vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 33, 1);
|
||||
vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 34, 36, 0);
|
||||
vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
|
||||
ulong msr = vcpu->arch.shared->msr;
|
||||
|
||||
msr = kvmppc_set_field(msr, 33, 33, 1);
|
||||
msr = kvmppc_set_field(msr, 34, 36, 0);
|
||||
vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
|
||||
return EMULATE_AGAIN;
|
||||
}
|
||||
|
|
@ -736,7 +823,7 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
|
|||
if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)
|
||||
return RESUME_GUEST;
|
||||
|
||||
if (!(vcpu->arch.msr & msr)) {
|
||||
if (!(vcpu->arch.shared->msr & msr)) {
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
|
|
@ -796,16 +883,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
|
||||
run->exit_reason = KVM_EXIT_UNKNOWN;
|
||||
run->ready_for_interrupt_injection = 1;
|
||||
#ifdef EXIT_DEBUG
|
||||
printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n",
|
||||
exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
|
||||
kvmppc_get_dec(vcpu), to_svcpu(vcpu)->shadow_srr1);
|
||||
#elif defined (EXIT_DEBUG_SIMPLE)
|
||||
if ((exit_nr != 0x900) && (exit_nr != 0x500))
|
||||
printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n",
|
||||
exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
|
||||
vcpu->arch.msr);
|
||||
#endif
|
||||
|
||||
trace_kvm_book3s_exit(exit_nr, vcpu);
|
||||
kvm_resched(vcpu);
|
||||
switch (exit_nr) {
|
||||
case BOOK3S_INTERRUPT_INST_STORAGE:
|
||||
|
|
@ -836,9 +915,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
|
||||
r = RESUME_GUEST;
|
||||
} else {
|
||||
vcpu->arch.msr |= to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
|
||||
vcpu->arch.shared->msr |=
|
||||
to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
|
||||
r = RESUME_GUEST;
|
||||
}
|
||||
break;
|
||||
|
|
@ -861,17 +940,16 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) {
|
||||
r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
|
||||
} else {
|
||||
vcpu->arch.dear = dar;
|
||||
to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
|
||||
vcpu->arch.shared->dar = dar;
|
||||
vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFUL);
|
||||
r = RESUME_GUEST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BOOK3S_INTERRUPT_DATA_SEGMENT:
|
||||
if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) {
|
||||
vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
|
||||
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
|
||||
kvmppc_book3s_queue_irqprio(vcpu,
|
||||
BOOK3S_INTERRUPT_DATA_SEGMENT);
|
||||
}
|
||||
|
|
@ -904,7 +982,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
program_interrupt:
|
||||
flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull;
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR) {
|
||||
if (vcpu->arch.shared->msr & MSR_PR) {
|
||||
#ifdef EXIT_DEBUG
|
||||
printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
|
||||
#endif
|
||||
|
|
@ -941,10 +1019,10 @@ program_interrupt:
|
|||
break;
|
||||
}
|
||||
case BOOK3S_INTERRUPT_SYSCALL:
|
||||
// XXX make user settable
|
||||
if (vcpu->arch.osi_enabled &&
|
||||
(((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
|
||||
(((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
|
||||
/* MOL hypercalls */
|
||||
u64 *gprs = run->osi.gprs;
|
||||
int i;
|
||||
|
||||
|
|
@ -953,8 +1031,13 @@ program_interrupt:
|
|||
gprs[i] = kvmppc_get_gpr(vcpu, i);
|
||||
vcpu->arch.osi_needed = 1;
|
||||
r = RESUME_HOST_NV;
|
||||
|
||||
} else if (!(vcpu->arch.shared->msr & MSR_PR) &&
|
||||
(((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
|
||||
/* KVM PV hypercalls */
|
||||
kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
|
||||
r = RESUME_GUEST;
|
||||
} else {
|
||||
/* Guest syscalls */
|
||||
vcpu->stat.syscall_exits++;
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
r = RESUME_GUEST;
|
||||
|
|
@ -989,9 +1072,9 @@ program_interrupt:
|
|||
}
|
||||
case BOOK3S_INTERRUPT_ALIGNMENT:
|
||||
if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
|
||||
to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu,
|
||||
vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu,
|
||||
kvmppc_get_last_inst(vcpu));
|
||||
vcpu->arch.dear = kvmppc_alignment_dar(vcpu,
|
||||
vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu,
|
||||
kvmppc_get_last_inst(vcpu));
|
||||
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
|
||||
}
|
||||
|
|
@ -1031,9 +1114,7 @@ program_interrupt:
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef EXIT_DEBUG
|
||||
printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, kvmppc_get_pc(vcpu), r);
|
||||
#endif
|
||||
trace_kvm_book3s_reenter(r, vcpu);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1052,14 +1133,14 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|||
regs->ctr = kvmppc_get_ctr(vcpu);
|
||||
regs->lr = kvmppc_get_lr(vcpu);
|
||||
regs->xer = kvmppc_get_xer(vcpu);
|
||||
regs->msr = vcpu->arch.msr;
|
||||
regs->srr0 = vcpu->arch.srr0;
|
||||
regs->srr1 = vcpu->arch.srr1;
|
||||
regs->msr = vcpu->arch.shared->msr;
|
||||
regs->srr0 = vcpu->arch.shared->srr0;
|
||||
regs->srr1 = vcpu->arch.shared->srr1;
|
||||
regs->pid = vcpu->arch.pid;
|
||||
regs->sprg0 = vcpu->arch.sprg0;
|
||||
regs->sprg1 = vcpu->arch.sprg1;
|
||||
regs->sprg2 = vcpu->arch.sprg2;
|
||||
regs->sprg3 = vcpu->arch.sprg3;
|
||||
regs->sprg0 = vcpu->arch.shared->sprg0;
|
||||
regs->sprg1 = vcpu->arch.shared->sprg1;
|
||||
regs->sprg2 = vcpu->arch.shared->sprg2;
|
||||
regs->sprg3 = vcpu->arch.shared->sprg3;
|
||||
regs->sprg5 = vcpu->arch.sprg4;
|
||||
regs->sprg6 = vcpu->arch.sprg5;
|
||||
regs->sprg7 = vcpu->arch.sprg6;
|
||||
|
|
@ -1080,12 +1161,12 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|||
kvmppc_set_lr(vcpu, regs->lr);
|
||||
kvmppc_set_xer(vcpu, regs->xer);
|
||||
kvmppc_set_msr(vcpu, regs->msr);
|
||||
vcpu->arch.srr0 = regs->srr0;
|
||||
vcpu->arch.srr1 = regs->srr1;
|
||||
vcpu->arch.sprg0 = regs->sprg0;
|
||||
vcpu->arch.sprg1 = regs->sprg1;
|
||||
vcpu->arch.sprg2 = regs->sprg2;
|
||||
vcpu->arch.sprg3 = regs->sprg3;
|
||||
vcpu->arch.shared->srr0 = regs->srr0;
|
||||
vcpu->arch.shared->srr1 = regs->srr1;
|
||||
vcpu->arch.shared->sprg0 = regs->sprg0;
|
||||
vcpu->arch.shared->sprg1 = regs->sprg1;
|
||||
vcpu->arch.shared->sprg2 = regs->sprg2;
|
||||
vcpu->arch.shared->sprg3 = regs->sprg3;
|
||||
vcpu->arch.sprg5 = regs->sprg4;
|
||||
vcpu->arch.sprg6 = regs->sprg5;
|
||||
vcpu->arch.sprg7 = regs->sprg6;
|
||||
|
|
@ -1111,10 +1192,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
|
|||
sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 16; i++) {
|
||||
sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
|
||||
sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
|
||||
}
|
||||
for (i = 0; i < 16; i++)
|
||||
sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw;
|
||||
sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw;
|
||||
|
|
@ -1225,6 +1305,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|||
struct kvmppc_vcpu_book3s *vcpu_book3s;
|
||||
struct kvm_vcpu *vcpu;
|
||||
int err = -ENOMEM;
|
||||
unsigned long p;
|
||||
|
||||
vcpu_book3s = vmalloc(sizeof(struct kvmppc_vcpu_book3s));
|
||||
if (!vcpu_book3s)
|
||||
|
|
@ -1242,6 +1323,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|||
if (err)
|
||||
goto free_shadow_vcpu;
|
||||
|
||||
p = __get_free_page(GFP_KERNEL|__GFP_ZERO);
|
||||
/* the real shared page fills the last 4k of our page */
|
||||
vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096);
|
||||
if (!p)
|
||||
goto uninit_vcpu;
|
||||
|
||||
vcpu->arch.host_retip = kvm_return_point;
|
||||
vcpu->arch.host_msr = mfmsr();
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
|
|
@ -1268,10 +1355,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
|
|||
|
||||
err = kvmppc_mmu_init(vcpu);
|
||||
if (err < 0)
|
||||
goto free_shadow_vcpu;
|
||||
goto uninit_vcpu;
|
||||
|
||||
return vcpu;
|
||||
|
||||
uninit_vcpu:
|
||||
kvm_vcpu_uninit(vcpu);
|
||||
free_shadow_vcpu:
|
||||
kfree(vcpu_book3s->shadow_vcpu);
|
||||
free_vcpu:
|
||||
|
|
@ -1284,6 +1373,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
|
|||
{
|
||||
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
|
||||
|
||||
free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);
|
||||
kvm_vcpu_uninit(vcpu);
|
||||
kfree(vcpu_book3s->shadow_vcpu);
|
||||
vfree(vcpu_book3s);
|
||||
|
|
@ -1346,7 +1436,7 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
|
|||
local_irq_enable();
|
||||
|
||||
/* Preload FPU if it's enabled */
|
||||
if (vcpu->arch.msr & MSR_FP)
|
||||
if (vcpu->arch.shared->msr & MSR_FP)
|
||||
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
|
||||
|
||||
ret = __kvmppc_vcpu_entry(kvm_run, vcpu);
|
||||
|
|
|
|||
|
|
@ -58,14 +58,39 @@ static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline u32 sr_vsid(u32 sr_raw)
|
||||
{
|
||||
return sr_raw & 0x0fffffff;
|
||||
}
|
||||
|
||||
static inline bool sr_valid(u32 sr_raw)
|
||||
{
|
||||
return (sr_raw & 0x80000000) ? false : true;
|
||||
}
|
||||
|
||||
static inline bool sr_ks(u32 sr_raw)
|
||||
{
|
||||
return (sr_raw & 0x40000000) ? true: false;
|
||||
}
|
||||
|
||||
static inline bool sr_kp(u32 sr_raw)
|
||||
{
|
||||
return (sr_raw & 0x20000000) ? true: false;
|
||||
}
|
||||
|
||||
static inline bool sr_nx(u32 sr_raw)
|
||||
{
|
||||
return (sr_raw & 0x10000000) ? true: false;
|
||||
}
|
||||
|
||||
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
struct kvmppc_pte *pte, bool data);
|
||||
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
||||
u64 *vsid);
|
||||
|
||||
static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr)
|
||||
static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr)
|
||||
{
|
||||
return &vcpu_book3s->sr[(eaddr >> 28) & 0xf];
|
||||
return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf];
|
||||
}
|
||||
|
||||
static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
|
|
@ -87,7 +112,7 @@ static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s,
|
||||
struct kvmppc_sr *sre, gva_t eaddr,
|
||||
u32 sre, gva_t eaddr,
|
||||
bool primary)
|
||||
{
|
||||
u32 page, hash, pteg, htabmask;
|
||||
|
|
@ -96,7 +121,7 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
|
|||
page = (eaddr & 0x0FFFFFFF) >> 12;
|
||||
htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0;
|
||||
|
||||
hash = ((sre->vsid ^ page) << 6);
|
||||
hash = ((sr_vsid(sre) ^ page) << 6);
|
||||
if (!primary)
|
||||
hash = ~hash;
|
||||
hash &= htabmask;
|
||||
|
|
@ -104,8 +129,8 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
|
|||
pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash;
|
||||
|
||||
dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n",
|
||||
vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg,
|
||||
sre->vsid);
|
||||
kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg,
|
||||
sr_vsid(sre));
|
||||
|
||||
r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT);
|
||||
if (kvm_is_error_hva(r))
|
||||
|
|
@ -113,10 +138,9 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
|
|||
return r | (pteg & ~PAGE_MASK);
|
||||
}
|
||||
|
||||
static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr,
|
||||
bool primary)
|
||||
static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary)
|
||||
{
|
||||
return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) |
|
||||
return ((eaddr & 0x0fffffff) >> 22) | (sr_vsid(sre) << 7) |
|
||||
(primary ? 0 : 0x40) | 0x80000000;
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +157,7 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|||
else
|
||||
bat = &vcpu_book3s->ibat[i];
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR) {
|
||||
if (vcpu->arch.shared->msr & MSR_PR) {
|
||||
if (!bat->vp)
|
||||
continue;
|
||||
} else {
|
||||
|
|
@ -180,17 +204,17 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|||
bool primary)
|
||||
{
|
||||
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
|
||||
struct kvmppc_sr *sre;
|
||||
u32 sre;
|
||||
hva_t ptegp;
|
||||
u32 pteg[16];
|
||||
u32 ptem = 0;
|
||||
int i;
|
||||
int found = 0;
|
||||
|
||||
sre = find_sr(vcpu_book3s, eaddr);
|
||||
sre = find_sr(vcpu, eaddr);
|
||||
|
||||
dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28,
|
||||
sre->vsid, sre->raw);
|
||||
sr_vsid(sre), sre);
|
||||
|
||||
pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
|
||||
|
||||
|
|
@ -214,8 +238,8 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|||
pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF);
|
||||
pp = pteg[i+1] & 3;
|
||||
|
||||
if ((sre->Kp && (vcpu->arch.msr & MSR_PR)) ||
|
||||
(sre->Ks && !(vcpu->arch.msr & MSR_PR)))
|
||||
if ((sr_kp(sre) && (vcpu->arch.shared->msr & MSR_PR)) ||
|
||||
(sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR)))
|
||||
pp |= 4;
|
||||
|
||||
pte->may_write = false;
|
||||
|
|
@ -269,7 +293,7 @@ no_page_found:
|
|||
dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n",
|
||||
to_book3s(vcpu)->sdr1, ptegp);
|
||||
for (i=0; i<16; i+=2) {
|
||||
dprintk_pte(" %02d: 0x%x - 0x%x (0x%llx)\n",
|
||||
dprintk_pte(" %02d: 0x%x - 0x%x (0x%x)\n",
|
||||
i, pteg[i], pteg[i+1], ptem);
|
||||
}
|
||||
}
|
||||
|
|
@ -281,8 +305,24 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|||
struct kvmppc_pte *pte, bool data)
|
||||
{
|
||||
int r;
|
||||
ulong mp_ea = vcpu->arch.magic_page_ea;
|
||||
|
||||
pte->eaddr = eaddr;
|
||||
|
||||
/* Magic page override */
|
||||
if (unlikely(mp_ea) &&
|
||||
unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
|
||||
pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff);
|
||||
pte->raddr &= KVM_PAM;
|
||||
pte->may_execute = true;
|
||||
pte->may_read = true;
|
||||
pte->may_write = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data);
|
||||
if (r < 0)
|
||||
r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true);
|
||||
|
|
@ -295,30 +335,13 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|||
|
||||
static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum)
|
||||
{
|
||||
return to_book3s(vcpu)->sr[srnum].raw;
|
||||
return vcpu->arch.shared->sr[srnum];
|
||||
}
|
||||
|
||||
static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
|
||||
ulong value)
|
||||
{
|
||||
struct kvmppc_sr *sre;
|
||||
|
||||
sre = &to_book3s(vcpu)->sr[srnum];
|
||||
|
||||
/* Flush any left-over shadows from the previous SR */
|
||||
|
||||
/* XXX Not necessary? */
|
||||
/* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */
|
||||
|
||||
/* And then put in the new SR */
|
||||
sre->raw = value;
|
||||
sre->vsid = (value & 0x0fffffff);
|
||||
sre->valid = (value & 0x80000000) ? false : true;
|
||||
sre->Ks = (value & 0x40000000) ? true : false;
|
||||
sre->Kp = (value & 0x20000000) ? true : false;
|
||||
sre->nx = (value & 0x10000000) ? true : false;
|
||||
|
||||
/* Map the new segment */
|
||||
vcpu->arch.shared->sr[srnum] = value;
|
||||
kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT);
|
||||
}
|
||||
|
||||
|
|
@ -331,19 +354,19 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
|||
u64 *vsid)
|
||||
{
|
||||
ulong ea = esid << SID_SHIFT;
|
||||
struct kvmppc_sr *sr;
|
||||
u32 sr;
|
||||
u64 gvsid = esid;
|
||||
|
||||
if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||
sr = find_sr(to_book3s(vcpu), ea);
|
||||
if (sr->valid)
|
||||
gvsid = sr->vsid;
|
||||
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
sr = find_sr(vcpu, ea);
|
||||
if (sr_valid(sr))
|
||||
gvsid = sr_vsid(sr);
|
||||
}
|
||||
|
||||
/* In case we only have one of MSR_IR or MSR_DR set, let's put
|
||||
that in the real-mode context (and hope RM doesn't access
|
||||
high memory) */
|
||||
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
case 0:
|
||||
*vsid = VSID_REAL | esid;
|
||||
break;
|
||||
|
|
@ -354,8 +377,8 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
|||
*vsid = VSID_REAL_DR | gvsid;
|
||||
break;
|
||||
case MSR_DR|MSR_IR:
|
||||
if (sr->valid)
|
||||
*vsid = sr->vsid;
|
||||
if (sr_valid(sr))
|
||||
*vsid = sr_vsid(sr);
|
||||
else
|
||||
*vsid = VSID_BAT | gvsid;
|
||||
break;
|
||||
|
|
@ -363,7 +386,7 @@ static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR)
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
*vsid |= VSID_PR;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/hash.h>
|
||||
|
||||
#include <asm/kvm_ppc.h>
|
||||
#include <asm/kvm_book3s.h>
|
||||
|
|
@ -77,7 +76,14 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
|||
* a hash, so we don't waste cycles on looping */
|
||||
static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
{
|
||||
return hash_64(gvsid, SID_MAP_BITS);
|
||||
return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,7 +92,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
|
|||
struct kvmppc_sid_map *map;
|
||||
u16 sid_map_mask;
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR)
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
|
||||
|
|
@ -147,8 +153,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
|
|||
struct hpte_cache *pte;
|
||||
|
||||
/* Get host physical address for gpa */
|
||||
hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
|
||||
if (kvm_is_error_hva(hpaddr)) {
|
||||
hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
|
||||
if (is_error_pfn(hpaddr)) {
|
||||
printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
|
||||
orig_pte->eaddr);
|
||||
return -EINVAL;
|
||||
|
|
@ -253,7 +259,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
|
|||
u16 sid_map_mask;
|
||||
static int backwards_map = 0;
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR)
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
/* We might get collisions that trap in preceding order, so let's
|
||||
|
|
@ -269,18 +275,15 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
|
|||
backwards_map = !backwards_map;
|
||||
|
||||
/* Uh-oh ... out of mappings. Let's flush! */
|
||||
if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) {
|
||||
vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
|
||||
if (vcpu_book3s->vsid_next >= VSID_POOL_SIZE) {
|
||||
vcpu_book3s->vsid_next = 0;
|
||||
memset(vcpu_book3s->sid_map, 0,
|
||||
sizeof(struct kvmppc_sid_map) * SID_MAP_NUM);
|
||||
kvmppc_mmu_pte_flush(vcpu, 0, 0);
|
||||
kvmppc_mmu_flush_segments(vcpu);
|
||||
}
|
||||
map->host_vsid = vcpu_book3s->vsid_next;
|
||||
|
||||
/* Would have to be 111 to be completely aligned with the rest of
|
||||
Linux, but that is just way too little space! */
|
||||
vcpu_book3s->vsid_next+=1;
|
||||
map->host_vsid = vcpu_book3s->vsid_pool[vcpu_book3s->vsid_next];
|
||||
vcpu_book3s->vsid_next++;
|
||||
|
||||
map->guest_vsid = gvsid;
|
||||
map->valid = true;
|
||||
|
|
@ -327,40 +330,38 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
|
|||
|
||||
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
kvmppc_mmu_hpte_destroy(vcpu);
|
||||
preempt_disable();
|
||||
__destroy_context(to_book3s(vcpu)->context_id);
|
||||
for (i = 0; i < SID_CONTEXTS; i++)
|
||||
__destroy_context(to_book3s(vcpu)->context_id[i]);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
/* From mm/mmu_context_hash32.c */
|
||||
#define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff)
|
||||
#define CTX_TO_VSID(c, id) ((((c) * (897 * 16)) + (id * 0x111)) & 0xffffff)
|
||||
|
||||
int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
|
||||
int err;
|
||||
ulong sdr1;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
err = __init_new_context();
|
||||
if (err < 0)
|
||||
return -1;
|
||||
vcpu3s->context_id = err;
|
||||
for (i = 0; i < SID_CONTEXTS; i++) {
|
||||
err = __init_new_context();
|
||||
if (err < 0)
|
||||
goto init_fail;
|
||||
vcpu3s->context_id[i] = err;
|
||||
|
||||
vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1;
|
||||
vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id);
|
||||
/* Remember context id for this combination */
|
||||
for (j = 0; j < 16; j++)
|
||||
vcpu3s->vsid_pool[(i * 16) + j] = CTX_TO_VSID(err, j);
|
||||
}
|
||||
|
||||
#if 0 /* XXX still doesn't guarantee uniqueness */
|
||||
/* We could collide with the Linux vsid space because the vsid
|
||||
* wraps around at 24 bits. We're safe if we do our own space
|
||||
* though, so let's always set the highest bit. */
|
||||
|
||||
vcpu3s->vsid_max |= 0x00800000;
|
||||
vcpu3s->vsid_first |= 0x00800000;
|
||||
#endif
|
||||
BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first);
|
||||
|
||||
vcpu3s->vsid_next = vcpu3s->vsid_first;
|
||||
vcpu3s->vsid_next = 0;
|
||||
|
||||
/* Remember where the HTAB is */
|
||||
asm ( "mfsdr1 %0" : "=r"(sdr1) );
|
||||
|
|
@ -370,4 +371,14 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
|
|||
kvmppc_mmu_hpte_init(vcpu);
|
||||
|
||||
return 0;
|
||||
|
||||
init_fail:
|
||||
for (j = 0; j < i; j++) {
|
||||
if (!vcpu3s->context_id[j])
|
||||
continue;
|
||||
|
||||
__destroy_context(to_book3s(vcpu)->context_id[j]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,22 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
|||
bool found = false;
|
||||
bool perm_err = false;
|
||||
int second = 0;
|
||||
ulong mp_ea = vcpu->arch.magic_page_ea;
|
||||
|
||||
/* Magic page override */
|
||||
if (unlikely(mp_ea) &&
|
||||
unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
gpte->eaddr = eaddr;
|
||||
gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);
|
||||
gpte->raddr = vcpu->arch.magic_page_pa | (gpte->raddr & 0xfff);
|
||||
gpte->raddr &= KVM_PAM;
|
||||
gpte->may_execute = true;
|
||||
gpte->may_read = true;
|
||||
gpte->may_write = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr);
|
||||
if (!slbe)
|
||||
|
|
@ -180,9 +196,9 @@ do_second:
|
|||
goto no_page_found;
|
||||
}
|
||||
|
||||
if ((vcpu->arch.msr & MSR_PR) && slbe->Kp)
|
||||
if ((vcpu->arch.shared->msr & MSR_PR) && slbe->Kp)
|
||||
key = 4;
|
||||
else if (!(vcpu->arch.msr & MSR_PR) && slbe->Ks)
|
||||
else if (!(vcpu->arch.shared->msr & MSR_PR) && slbe->Ks)
|
||||
key = 4;
|
||||
|
||||
for (i=0; i<16; i+=2) {
|
||||
|
|
@ -381,7 +397,7 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
|
|||
for (i = 1; i < vcpu_book3s->slb_nr; i++)
|
||||
vcpu_book3s->slb[i].valid = false;
|
||||
|
||||
if (vcpu->arch.msr & MSR_IR) {
|
||||
if (vcpu->arch.shared->msr & MSR_IR) {
|
||||
kvmppc_mmu_flush_segments(vcpu);
|
||||
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
|
||||
}
|
||||
|
|
@ -445,14 +461,15 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
|||
ulong ea = esid << SID_SHIFT;
|
||||
struct kvmppc_slb *slb;
|
||||
u64 gvsid = esid;
|
||||
ulong mp_ea = vcpu->arch.magic_page_ea;
|
||||
|
||||
if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
|
||||
if (slb)
|
||||
gvsid = slb->vsid;
|
||||
}
|
||||
|
||||
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
|
||||
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
|
||||
case 0:
|
||||
*vsid = VSID_REAL | esid;
|
||||
break;
|
||||
|
|
@ -464,7 +481,7 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
|||
break;
|
||||
case MSR_DR|MSR_IR:
|
||||
if (!slb)
|
||||
return -ENOENT;
|
||||
goto no_slb;
|
||||
|
||||
*vsid = gvsid;
|
||||
break;
|
||||
|
|
@ -473,10 +490,21 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
|
|||
break;
|
||||
}
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR)
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
*vsid |= VSID_PR;
|
||||
|
||||
return 0;
|
||||
|
||||
no_slb:
|
||||
/* Catch magic page case */
|
||||
if (unlikely(mp_ea) &&
|
||||
unlikely(esid == (mp_ea >> SID_SHIFT)) &&
|
||||
!(vcpu->arch.shared->msr & MSR_PR)) {
|
||||
*vsid = VSID_REAL | esid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool kvmppc_mmu_book3s_64_is_dcbz32(struct kvm_vcpu *vcpu)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/hash.h>
|
||||
|
||||
#include <asm/kvm_ppc.h>
|
||||
#include <asm/kvm_book3s.h>
|
||||
|
|
@ -28,24 +27,9 @@
|
|||
#include <asm/machdep.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/hw_irq.h>
|
||||
#include "trace.h"
|
||||
|
||||
#define PTE_SIZE 12
|
||||
#define VSID_ALL 0
|
||||
|
||||
/* #define DEBUG_MMU */
|
||||
/* #define DEBUG_SLB */
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
|
||||
#else
|
||||
#define dprintk_mmu(a, ...) do { } while(0)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_SLB
|
||||
#define dprintk_slb(a, ...) printk(KERN_INFO a, __VA_ARGS__)
|
||||
#else
|
||||
#define dprintk_slb(a, ...) do { } while(0)
|
||||
#endif
|
||||
|
||||
void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
||||
{
|
||||
|
|
@ -58,34 +42,39 @@ void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
|||
* a hash, so we don't waste cycles on looping */
|
||||
static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
{
|
||||
return hash_64(gvsid, SID_MAP_BITS);
|
||||
return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
|
||||
((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
|
||||
}
|
||||
|
||||
|
||||
static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
|
||||
{
|
||||
struct kvmppc_sid_map *map;
|
||||
u16 sid_map_mask;
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR)
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
|
||||
map = &to_book3s(vcpu)->sid_map[sid_map_mask];
|
||||
if (map->guest_vsid == gvsid) {
|
||||
dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n",
|
||||
gvsid, map->host_vsid);
|
||||
if (map->valid && (map->guest_vsid == gvsid)) {
|
||||
trace_kvm_book3s_slb_found(gvsid, map->host_vsid);
|
||||
return map;
|
||||
}
|
||||
|
||||
map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask];
|
||||
if (map->guest_vsid == gvsid) {
|
||||
dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n",
|
||||
gvsid, map->host_vsid);
|
||||
if (map->valid && (map->guest_vsid == gvsid)) {
|
||||
trace_kvm_book3s_slb_found(gvsid, map->host_vsid);
|
||||
return map;
|
||||
}
|
||||
|
||||
dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n",
|
||||
sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid);
|
||||
trace_kvm_book3s_slb_fail(sid_map_mask, gvsid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -101,18 +90,13 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
|
|||
struct kvmppc_sid_map *map;
|
||||
|
||||
/* Get host physical address for gpa */
|
||||
hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
|
||||
if (kvm_is_error_hva(hpaddr)) {
|
||||
hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
|
||||
if (is_error_pfn(hpaddr)) {
|
||||
printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
hpaddr <<= PAGE_SHIFT;
|
||||
#if PAGE_SHIFT == 12
|
||||
#elif PAGE_SHIFT == 16
|
||||
hpaddr |= orig_pte->raddr & 0xf000;
|
||||
#else
|
||||
#error Unknown page size
|
||||
#endif
|
||||
hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
|
||||
|
||||
/* and write the mapping ea -> hpa into the pt */
|
||||
vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
|
||||
|
|
@ -161,10 +145,7 @@ map_again:
|
|||
} else {
|
||||
struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
|
||||
|
||||
dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
|
||||
((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
|
||||
(rflags & HPTE_R_N) ? '-' : 'x',
|
||||
orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr);
|
||||
trace_kvm_book3s_64_mmu_map(rflags, hpteg, va, hpaddr, orig_pte);
|
||||
|
||||
/* The ppc_md code may give us a secondary entry even though we
|
||||
asked for a primary. Fix up. */
|
||||
|
|
@ -191,7 +172,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
|
|||
u16 sid_map_mask;
|
||||
static int backwards_map = 0;
|
||||
|
||||
if (vcpu->arch.msr & MSR_PR)
|
||||
if (vcpu->arch.shared->msr & MSR_PR)
|
||||
gvsid |= VSID_PR;
|
||||
|
||||
/* We might get collisions that trap in preceding order, so let's
|
||||
|
|
@ -219,8 +200,7 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
|
|||
map->guest_vsid = gvsid;
|
||||
map->valid = true;
|
||||
|
||||
dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n",
|
||||
sid_map_mask, gvsid, map->host_vsid);
|
||||
trace_kvm_book3s_slb_map(sid_map_mask, gvsid, map->host_vsid);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
@ -292,7 +272,7 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
|
|||
to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
|
||||
to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
|
||||
|
||||
dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid);
|
||||
trace_kvm_book3s_slbmte(slb_vsid, slb_esid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -306,7 +286,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
|
|||
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
kvmppc_mmu_hpte_destroy(vcpu);
|
||||
__destroy_context(to_book3s(vcpu)->context_id);
|
||||
__destroy_context(to_book3s(vcpu)->context_id[0]);
|
||||
}
|
||||
|
||||
int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -317,10 +297,10 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
|
|||
err = __init_new_context();
|
||||
if (err < 0)
|
||||
return -1;
|
||||
vcpu3s->context_id = err;
|
||||
vcpu3s->context_id[0] = err;
|
||||
|
||||
vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1;
|
||||
vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
|
||||
vcpu3s->vsid_max = ((vcpu3s->context_id[0] + 1) << USER_ESID_BITS) - 1;
|
||||
vcpu3s->vsid_first = vcpu3s->context_id[0] << USER_ESID_BITS;
|
||||
vcpu3s->vsid_next = vcpu3s->vsid_first;
|
||||
|
||||
kvmppc_mmu_hpte_init(vcpu);
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
switch (get_xop(inst)) {
|
||||
case OP_19_XOP_RFID:
|
||||
case OP_19_XOP_RFI:
|
||||
kvmppc_set_pc(vcpu, vcpu->arch.srr0);
|
||||
kvmppc_set_msr(vcpu, vcpu->arch.srr1);
|
||||
kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);
|
||||
kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
|
||||
*advance = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -86,14 +86,15 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
case 31:
|
||||
switch (get_xop(inst)) {
|
||||
case OP_31_XOP_MFMSR:
|
||||
kvmppc_set_gpr(vcpu, get_rt(inst), vcpu->arch.msr);
|
||||
kvmppc_set_gpr(vcpu, get_rt(inst),
|
||||
vcpu->arch.shared->msr);
|
||||
break;
|
||||
case OP_31_XOP_MTMSRD:
|
||||
{
|
||||
ulong rs = kvmppc_get_gpr(vcpu, get_rs(inst));
|
||||
if (inst & 0x10000) {
|
||||
vcpu->arch.msr &= ~(MSR_RI | MSR_EE);
|
||||
vcpu->arch.msr |= rs & (MSR_RI | MSR_EE);
|
||||
vcpu->arch.shared->msr &= ~(MSR_RI | MSR_EE);
|
||||
vcpu->arch.shared->msr |= rs & (MSR_RI | MSR_EE);
|
||||
} else
|
||||
kvmppc_set_msr(vcpu, rs);
|
||||
break;
|
||||
|
|
@ -204,14 +205,14 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
ra = kvmppc_get_gpr(vcpu, get_ra(inst));
|
||||
|
||||
addr = (ra + rb) & ~31ULL;
|
||||
if (!(vcpu->arch.msr & MSR_SF))
|
||||
if (!(vcpu->arch.shared->msr & MSR_SF))
|
||||
addr &= 0xffffffff;
|
||||
vaddr = addr;
|
||||
|
||||
r = kvmppc_st(vcpu, &addr, 32, zeros, true);
|
||||
if ((r == -ENOENT) || (r == -EPERM)) {
|
||||
*advance = 0;
|
||||
vcpu->arch.dear = vaddr;
|
||||
vcpu->arch.shared->dar = vaddr;
|
||||
to_svcpu(vcpu)->fault_dar = vaddr;
|
||||
|
||||
dsisr = DSISR_ISSTORE;
|
||||
|
|
@ -220,7 +221,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
|||
else if (r == -EPERM)
|
||||
dsisr |= DSISR_PROTFAULT;
|
||||
|
||||
to_book3s(vcpu)->dsisr = dsisr;
|
||||
vcpu->arch.shared->dsisr = dsisr;
|
||||
to_svcpu(vcpu)->fault_dsisr = dsisr;
|
||||
|
||||
kvmppc_book3s_queue_irqprio(vcpu,
|
||||
|
|
@ -263,7 +264,7 @@ void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper,
|
|||
}
|
||||
}
|
||||
|
||||
static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn)
|
||||
static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn)
|
||||
{
|
||||
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
|
||||
struct kvmppc_bat *bat;
|
||||
|
|
@ -285,35 +286,7 @@ static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (sprn % 2)
|
||||
return bat->raw >> 32;
|
||||
else
|
||||
return bat->raw;
|
||||
}
|
||||
|
||||
static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val)
|
||||
{
|
||||
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
|
||||
struct kvmppc_bat *bat;
|
||||
|
||||
switch (sprn) {
|
||||
case SPRN_IBAT0U ... SPRN_IBAT3L:
|
||||
bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2];
|
||||
break;
|
||||
case SPRN_IBAT4U ... SPRN_IBAT7L:
|
||||
bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)];
|
||||
break;
|
||||
case SPRN_DBAT0U ... SPRN_DBAT3L:
|
||||
bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2];
|
||||
break;
|
||||
case SPRN_DBAT4U ... SPRN_DBAT7L:
|
||||
bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)];
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
kvmppc_set_bat(vcpu, bat, !(sprn % 2), val);
|
||||
return bat;
|
||||
}
|
||||
|
||||
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
|
||||
|
|
@ -326,10 +299,10 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
|
|||
to_book3s(vcpu)->sdr1 = spr_val;
|
||||
break;
|
||||
case SPRN_DSISR:
|
||||
to_book3s(vcpu)->dsisr = spr_val;
|
||||
vcpu->arch.shared->dsisr = spr_val;
|
||||
break;
|
||||
case SPRN_DAR:
|
||||
vcpu->arch.dear = spr_val;
|
||||
vcpu->arch.shared->dar = spr_val;
|
||||
break;
|
||||
case SPRN_HIOR:
|
||||
to_book3s(vcpu)->hior = spr_val;
|
||||
|
|
@ -338,12 +311,16 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
|
|||
case SPRN_IBAT4U ... SPRN_IBAT7L:
|
||||
case SPRN_DBAT0U ... SPRN_DBAT3L:
|
||||
case SPRN_DBAT4U ... SPRN_DBAT7L:
|
||||
kvmppc_write_bat(vcpu, sprn, (u32)spr_val);
|
||||
{
|
||||
struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);
|
||||
|
||||
kvmppc_set_bat(vcpu, bat, !(sprn % 2), (u32)spr_val);
|
||||
/* BAT writes happen so rarely that we're ok to flush
|
||||
* everything here */
|
||||
kvmppc_mmu_pte_flush(vcpu, 0, 0);
|
||||
kvmppc_mmu_flush_segments(vcpu);
|
||||
break;
|
||||
}
|
||||
case SPRN_HID0:
|
||||
to_book3s(vcpu)->hid[0] = spr_val;
|
||||
break;
|
||||
|
|
@ -433,16 +410,24 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
|
|||
case SPRN_IBAT4U ... SPRN_IBAT7L:
|
||||
case SPRN_DBAT0U ... SPRN_DBAT3L:
|
||||
case SPRN_DBAT4U ... SPRN_DBAT7L:
|
||||
kvmppc_set_gpr(vcpu, rt, kvmppc_read_bat(vcpu, sprn));
|
||||
{
|
||||
struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);
|
||||
|
||||
if (sprn % 2)
|
||||
kvmppc_set_gpr(vcpu, rt, bat->raw >> 32);
|
||||
else
|
||||
kvmppc_set_gpr(vcpu, rt, bat->raw);
|
||||
|
||||
break;
|
||||
}
|
||||
case SPRN_SDR1:
|
||||
kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
|
||||
break;
|
||||
case SPRN_DSISR:
|
||||
kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->dsisr);
|
||||
kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dsisr);
|
||||
break;
|
||||
case SPRN_DAR:
|
||||
kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear);
|
||||
kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar);
|
||||
break;
|
||||
case SPRN_HIOR:
|
||||
kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hior);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/kvm_host.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/slab.h>
|
||||
#include "trace.h"
|
||||
|
||||
#include <asm/kvm_ppc.h>
|
||||
#include <asm/kvm_book3s.h>
|
||||
|
|
@ -30,14 +31,6 @@
|
|||
|
||||
#define PTE_SIZE 12
|
||||
|
||||
/* #define DEBUG_MMU */
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
|
||||
#else
|
||||
#define dprintk_mmu(a, ...) do { } while(0)
|
||||
#endif
|
||||
|
||||
static struct kmem_cache *hpte_cache;
|
||||
|
||||
static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
|
||||
|
|
@ -45,6 +38,12 @@ static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
|
|||
return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
|
||||
}
|
||||
|
||||
static inline u64 kvmppc_mmu_hash_pte_long(u64 eaddr)
|
||||
{
|
||||
return hash_64((eaddr & 0x0ffff000) >> PTE_SIZE,
|
||||
HPTEG_HASH_BITS_PTE_LONG);
|
||||
}
|
||||
|
||||
static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
|
||||
{
|
||||
return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
|
||||
|
|
@ -60,77 +59,128 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
|||
{
|
||||
u64 index;
|
||||
|
||||
trace_kvm_book3s_mmu_map(pte);
|
||||
|
||||
spin_lock(&vcpu->arch.mmu_lock);
|
||||
|
||||
/* Add to ePTE list */
|
||||
index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
|
||||
hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
|
||||
hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
|
||||
|
||||
/* Add to ePTE_long list */
|
||||
index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
|
||||
hlist_add_head_rcu(&pte->list_pte_long,
|
||||
&vcpu->arch.hpte_hash_pte_long[index]);
|
||||
|
||||
/* Add to vPTE list */
|
||||
index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
|
||||
hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
|
||||
hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
|
||||
|
||||
/* Add to vPTE_long list */
|
||||
index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
|
||||
hlist_add_head(&pte->list_vpte_long,
|
||||
&vcpu->arch.hpte_hash_vpte_long[index]);
|
||||
hlist_add_head_rcu(&pte->list_vpte_long,
|
||||
&vcpu->arch.hpte_hash_vpte_long[index]);
|
||||
|
||||
spin_unlock(&vcpu->arch.mmu_lock);
|
||||
}
|
||||
|
||||
static void free_pte_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head);
|
||||
kmem_cache_free(hpte_cache, pte);
|
||||
}
|
||||
|
||||
static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
|
||||
{
|
||||
dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
|
||||
pte->pte.eaddr, pte->pte.vpage, pte->host_va);
|
||||
trace_kvm_book3s_mmu_invalidate(pte);
|
||||
|
||||
/* Different for 32 and 64 bit */
|
||||
kvmppc_mmu_invalidate_pte(vcpu, pte);
|
||||
|
||||
spin_lock(&vcpu->arch.mmu_lock);
|
||||
|
||||
/* pte already invalidated in between? */
|
||||
if (hlist_unhashed(&pte->list_pte)) {
|
||||
spin_unlock(&vcpu->arch.mmu_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
hlist_del_init_rcu(&pte->list_pte);
|
||||
hlist_del_init_rcu(&pte->list_pte_long);
|
||||
hlist_del_init_rcu(&pte->list_vpte);
|
||||
hlist_del_init_rcu(&pte->list_vpte_long);
|
||||
|
||||
if (pte->pte.may_write)
|
||||
kvm_release_pfn_dirty(pte->pfn);
|
||||
else
|
||||
kvm_release_pfn_clean(pte->pfn);
|
||||
|
||||
hlist_del(&pte->list_pte);
|
||||
hlist_del(&pte->list_vpte);
|
||||
hlist_del(&pte->list_vpte_long);
|
||||
spin_unlock(&vcpu->arch.mmu_lock);
|
||||
|
||||
vcpu->arch.hpte_cache_count--;
|
||||
kmem_cache_free(hpte_cache, pte);
|
||||
call_rcu(&pte->rcu_head, free_pte_rcu);
|
||||
}
|
||||
|
||||
static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct hpte_cache *pte;
|
||||
struct hlist_node *node, *tmp;
|
||||
struct hlist_node *node;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
|
||||
struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
|
||||
|
||||
hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
|
||||
invalidate_pte(vcpu, pte);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
|
||||
{
|
||||
struct hlist_head *list;
|
||||
struct hlist_node *node, *tmp;
|
||||
struct hlist_node *node;
|
||||
struct hpte_cache *pte;
|
||||
|
||||
/* Find the list of entries in the map */
|
||||
list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Check the list for matching entries and invalidate */
|
||||
hlist_for_each_entry_safe(pte, node, tmp, list, list_pte)
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_pte)
|
||||
if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
|
||||
invalidate_pte(vcpu, pte);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea)
|
||||
{
|
||||
struct hlist_head *list;
|
||||
struct hlist_node *node;
|
||||
struct hpte_cache *pte;
|
||||
|
||||
/* Find the list of entries in the map */
|
||||
list = &vcpu->arch.hpte_hash_pte_long[
|
||||
kvmppc_mmu_hash_pte_long(guest_ea)];
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Check the list for matching entries and invalidate */
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_pte_long)
|
||||
if ((pte->pte.eaddr & 0x0ffff000UL) == guest_ea)
|
||||
invalidate_pte(vcpu, pte);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
|
||||
{
|
||||
u64 i;
|
||||
|
||||
dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
|
||||
vcpu->arch.hpte_cache_count, guest_ea, ea_mask);
|
||||
|
||||
trace_kvm_book3s_mmu_flush("", vcpu, guest_ea, ea_mask);
|
||||
guest_ea &= ea_mask;
|
||||
|
||||
switch (ea_mask) {
|
||||
|
|
@ -138,9 +188,7 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
|
|||
kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
|
||||
break;
|
||||
case 0x0ffff000:
|
||||
/* 32-bit flush w/o segment, go through all possible segments */
|
||||
for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
|
||||
kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
|
||||
kvmppc_mmu_pte_flush_long(vcpu, guest_ea);
|
||||
break;
|
||||
case 0:
|
||||
/* Doing a complete flush -> start from scratch */
|
||||
|
|
@ -156,39 +204,46 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
|
|||
static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
|
||||
{
|
||||
struct hlist_head *list;
|
||||
struct hlist_node *node, *tmp;
|
||||
struct hlist_node *node;
|
||||
struct hpte_cache *pte;
|
||||
u64 vp_mask = 0xfffffffffULL;
|
||||
|
||||
list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Check the list for matching entries and invalidate */
|
||||
hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte)
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_vpte)
|
||||
if ((pte->pte.vpage & vp_mask) == guest_vp)
|
||||
invalidate_pte(vcpu, pte);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* Flush with mask 0xffffff000 */
|
||||
static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
|
||||
{
|
||||
struct hlist_head *list;
|
||||
struct hlist_node *node, *tmp;
|
||||
struct hlist_node *node;
|
||||
struct hpte_cache *pte;
|
||||
u64 vp_mask = 0xffffff000ULL;
|
||||
|
||||
list = &vcpu->arch.hpte_hash_vpte_long[
|
||||
kvmppc_mmu_hash_vpte_long(guest_vp)];
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Check the list for matching entries and invalidate */
|
||||
hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
|
||||
if ((pte->pte.vpage & vp_mask) == guest_vp)
|
||||
invalidate_pte(vcpu, pte);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
|
||||
{
|
||||
dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
|
||||
vcpu->arch.hpte_cache_count, guest_vp, vp_mask);
|
||||
trace_kvm_book3s_mmu_flush("v", vcpu, guest_vp, vp_mask);
|
||||
guest_vp &= vp_mask;
|
||||
|
||||
switch(vp_mask) {
|
||||
|
|
@ -206,21 +261,24 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
|
|||
|
||||
void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
|
||||
{
|
||||
struct hlist_node *node, *tmp;
|
||||
struct hlist_node *node;
|
||||
struct hpte_cache *pte;
|
||||
int i;
|
||||
|
||||
dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n",
|
||||
vcpu->arch.hpte_cache_count, pa_start, pa_end);
|
||||
trace_kvm_book3s_mmu_flush("p", vcpu, pa_start, pa_end);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
|
||||
struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
|
||||
|
||||
hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
|
||||
hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
|
||||
if ((pte->pte.raddr >= pa_start) &&
|
||||
(pte->pte.raddr < pa_end))
|
||||
invalidate_pte(vcpu, pte);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -254,11 +312,15 @@ int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
|
|||
/* init hpte lookup hashes */
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long));
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
|
||||
kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
|
||||
ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
|
||||
|
||||
spin_lock_init(&vcpu->arch.mmu_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue