Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (151 commits)
  powerpc: Fix usage of 64-bit instruction in 32-bit altivec code
  MAINTAINERS: Add PowerPC patterns
  powerpc/pseries: Track previous CPPR values to correctly EOI interrupts
  powerpc/pseries: Correct pseries/dlpar.c build break without CONFIG_SMP
  powerpc: Make "intspec" pointers in irq_host->xlate() const
  powerpc/8xx: DTLB Miss cleanup
  powerpc/8xx: Remove DIRTY pte handling in DTLB Error.
  powerpc/8xx: Start using dcbX instructions in various copy routines
  powerpc/8xx: Restore _PAGE_WRITETHRU
  powerpc/8xx: Add missing Guarded setting in DTLB Error.
  powerpc/8xx: Fixup DAR from buggy dcbX instructions.
  powerpc/8xx: Tag DAR with 0x00f0 to catch buggy instructions.
  powerpc/8xx: Update TLB asm so it behaves as linux mm expects.
  powerpc/8xx: Invalidate non present TLBs
  powerpc/pseries: Serialize cpu hotplug operations during deactivate Vs deallocate
  pseries/pseries: Add code to online/offline CPUs of a DLPAR node
  powerpc: stop_this_cpu: remove the cpu from the online map.
  powerpc/pseries: Add kernel based CPU DLPAR handling
  sysfs/cpu: Add probe/release files
  powerpc/pseries: Kernel DLPAR Infrastructure
  ...
This commit is contained in:
Linus Torvalds 2009-12-12 14:27:24 -08:00
commit 09cea96caa
234 changed files with 13150 additions and 2737 deletions

View file

@ -62,6 +62,21 @@ Description: CPU topology files that describe kernel limits related to
See Documentation/cputopology.txt for more information.
What: /sys/devices/system/cpu/probe
/sys/devices/system/cpu/release
Date: November 2009
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
Description: Dynamic addition and removal of CPU's. This is not hotplug
removal, this is meant complete removal/addition of the CPU
from the system.
probe: writes to this file will dynamically add a CPU to the
system. Information written to the file to add CPU's is
architecture specific.
release: writes to this file dynamically remove a CPU from
the system. Information writtento the file to remove CPU's
is architecture specific.
What: /sys/devices/system/cpu/cpu#/node
Date: October 2009

View file

@ -49,6 +49,12 @@ maxcpus=n Restrict boot time cpus to n. Say if you have 4 cpus, using
additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets
cpu_possible_map = cpu_present_map + additional_cpus
cede_offline={"off","on"} Use this option to disable/enable putting offlined
processors to an extended H_CEDE state on
supported pseries platforms.
If nothing is specified,
cede_offline is set to "on".
(*) Option valid only for following architectures
- ia64

View file

@ -20,12 +20,16 @@ Required properities:
- compatible : should be "fsl,fpga-pixis".
- reg : should contain the address and the length of the FPPGA register
set.
- interrupt-parent: should specify phandle for the interrupt controller.
- interrupts : should specify event (wakeup) IRQ.
Example (MPC8610HPCD):
board-control@e8000000 {
compatible = "fsl,fpga-pixis";
reg = <0xe8000000 32>;
interrupt-parent = <&mpic>;
interrupts = <8 8>;
};
* Freescale BCSR GPIO banks

View file

@ -103,7 +103,22 @@ fsl,mpc5200-gpt nodes
---------------------
On the mpc5200 and 5200b, GPT0 has a watchdog timer function. If the board
design supports the internal wdt, then the device node for GPT0 should
include the empty property 'fsl,has-wdt'.
include the empty property 'fsl,has-wdt'. Note that this does not activate
the watchdog. The timer will function as a GPT if the timer api is used, and
it will function as watchdog if the watchdog device is used. The watchdog
mode has priority over the gpt mode, i.e. if the watchdog is activated, any
gpt api call to this timer will fail with -EBUSY.
If you add the property
fsl,wdt-on-boot = <n>;
GPT0 will be marked as in-use watchdog, i.e. blocking every gpt access to it.
If n>0, the watchdog is started with a timeout of n seconds. If n=0, the
configuration of the watchdog is not touched. This is useful in two cases:
- just mark GPT0 as watchdog, blocking gpt accesses, and configure it later;
- do not touch a configuration assigned by the boot loader which supervises
the boot process itself.
The watchdog will respect the CONFIG_WATCHDOG_NOWAYOUT option.
An mpc5200-gpt can be used as a single line GPIO controller. To do so,
add the following properties to the gpt node:

View file

@ -3260,6 +3260,7 @@ LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <paulus@au.ibm.com>
W: http://www.ibm.com/linux/ltc/projects/ppc
S: Supported
F: arch/powerpc/boot/rs6000.h
LINUX FOR POWERPC (32-BIT AND 64-BIT)
M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
@ -3268,18 +3269,24 @@ W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git
S: Supported
F: Documentation/powerpc/
F: arch/powerpc/
LINUX FOR POWER MACINTOSH
M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
S: Maintained
F: arch/powerpc/platforms/powermac/
F: drivers/macintosh/
LINUX FOR POWERPC EMBEDDED MPC5XXX
M: Grant Likely <grant.likely@secretlab.ca>
L: linuxppc-dev@ozlabs.org
T: git git://git.secretlab.ca/git/linux-2.6.git
S: Maintained
F: arch/powerpc/platforms/512x/
F: arch/powerpc/platforms/52xx/
LINUX FOR POWERPC EMBEDDED PPC4XX
M: Josh Boyer <jwboyer@linux.vnet.ibm.com>
@ -3288,6 +3295,8 @@ W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
S: Maintained
F: arch/powerpc/platforms/40x/
F: arch/powerpc/platforms/44x/
LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
M: Grant Likely <grant.likely@secretlab.ca>
@ -3295,6 +3304,8 @@ W: http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex
L: linuxppc-dev@ozlabs.org
T: git git://git.secretlab.ca/git/linux-2.6.git
S: Maintained
F: arch/powerpc/*/*virtex*
F: arch/powerpc/*/*/*virtex*
LINUX FOR POWERPC EMBEDDED PPC8XX
M: Vitaly Bordug <vitb@kernel.crashing.org>
@ -3308,12 +3319,16 @@ M: Kumar Gala <galak@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@ozlabs.org
S: Maintained
F: arch/powerpc/platforms/83xx/
LINUX FOR POWERPC PA SEMI PWRFICIENT
M: Olof Johansson <olof@lixom.net>
W: http://www.pasemi.com/
L: linuxppc-dev@ozlabs.org
S: Supported
F: arch/powerpc/platforms/pasemi/
F: drivers/*/*pasemi*
F: drivers/*/*/*pasemi*
LINUX SECURITY MODULE (LSM) FRAMEWORK
M: Chris Wright <chrisw@sous-sol.org>

View file

@ -56,6 +56,16 @@ config IRQ_PER_CPU
bool
default y
config NR_IRQS
int "Number of virtual interrupt numbers"
range 32 512
default "512"
help
This defines the number of virtual interrupt numbers the kernel
can manage. Virtual interrupt numbers are what you see in
/proc/interrupts. If you configure your system to have too few,
drivers will fail to load or worse - handle with care.
config STACKTRACE_SUPPORT
bool
default y
@ -199,24 +209,14 @@ config DEFAULT_UIMAGE
config REDBOOT
bool
config HIBERNATE_32
bool
depends on (PPC_PMAC && !SMP) || BROKEN
default y
config HIBERNATE_64
bool
depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL)
default y
config ARCH_HIBERNATION_POSSIBLE
bool
depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
default y
config ARCH_SUSPEND_POSSIBLE
def_bool y
depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx
depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
PPC_85xx || PPC_86xx
config PPC_DCR_NATIVE
bool
@ -320,6 +320,10 @@ config HOTPLUG_CPU
Say N if you are unsure.
config ARCH_CPU_PROBE_RELEASE
def_bool y
depends on HOTPLUG_CPU
config ARCH_ENABLE_MEMORY_HOTPLUG
def_bool y
@ -378,6 +382,19 @@ config IRQ_ALL_CPUS
CPU. Generally saying Y is safe, although some problems have been
reported with SMP Power Macintoshes with this option enabled.
config SPARSE_IRQ
bool "Support sparse irq numbering"
default y
help
This enables support for sparse irqs. This is useful for distro
kernels that want to define a high CONFIG_NR_CPUS value but still
want to have low kernel memory footprint on smaller machines.
( Sparse IRQs can also be beneficial on NUMA boxes, as they spread
out the irq_desc[] array in a more NUMA-friendly way. )
If you don't know what to do here, say Y.
config NUMA
bool "NUMA support"
depends on PPC64
@ -652,6 +669,14 @@ config FSL_PCI
select PPC_INDIRECT_PCI
select PCI_QUIRKS
config FSL_PMC
bool
default y
depends on SUSPEND && (PPC_85xx || PPC_86xx)
help
Freescale MPC85xx/MPC86xx power management controller support
(suspend/resume). For MPC83xx see platforms/83xx/suspend.c
config 4xx_SOC
bool

View file

@ -352,6 +352,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
@ -381,6 +382,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;

View file

@ -316,6 +316,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
@ -345,6 +346,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
@ -375,6 +377,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>; /* emac2&3 only */
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII1>;
@ -403,6 +407,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>; /* emac2&3 only */
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII1>;

View file

@ -118,6 +118,12 @@
};
};
nvram@3,0 {
device_type = "nvram";
compatible = "simtek,stk14ca8";
reg = <0x3 0x0 0x20000>;
};
fpga@4,0 {
compatible = "gef,ppc9a-fpga-regs";
reg = <0x4 0x0 0x40>;

View file

@ -115,6 +115,12 @@
};
};
nvram@3,0 {
device_type = "nvram";
compatible = "simtek,stk14ca8";
reg = <0x3 0x0 0x20000>;
};
fpga@4,0 {
compatible = "gef,fpga-regs";
reg = <0x4 0x0 0x40>;

View file

@ -84,6 +84,12 @@
6 0 0xfd000000 0x00800000 // IO FPGA (8-bit)
7 0 0xfd800000 0x00800000>; // IO FPGA (32-bit)
nvram@3,0 {
device_type = "nvram";
compatible = "simtek,stk14ca8";
reg = <0x3 0x0 0x20000>;
};
fpga@4,0 {
compatible = "gef,fpga-regs";
reg = <0x4 0x0 0x40>;

View file

@ -292,6 +292,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
@ -321,6 +322,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
@ -351,6 +353,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>; /* emac2&3 only */
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII1>;
@ -379,6 +383,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>; /* emac2&3 only */
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII1>;

View file

@ -226,6 +226,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;

View file

@ -16,7 +16,7 @@
/ {
#address-cells = <2>;
#size-cells = <1>;
#size-cells = <2>;
model = "amcc,katmai";
compatible = "amcc,katmai";
dcr-parent = <&{/cpus/cpu@0}>;
@ -49,7 +49,7 @@
memory {
device_type = "memory";
reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by zImage */
reg = <0x0 0x00000000 0x0 0x00000000>; /* Filled in by U-Boot */
};
UIC0: interrupt-controller0 {
@ -112,7 +112,15 @@
compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4";
#address-cells = <2>;
#size-cells = <1>;
ranges;
/* addr-child addr-parent size */
ranges = <0x4 0xe0000000 0x4 0xe0000000 0x20000000
0xc 0x00000000 0xc 0x00000000 0x20000000
0xd 0x00000000 0xd 0x00000000 0x80000000
0xd 0x80000000 0xd 0x80000000 0x80000000
0xe 0x00000000 0xe 0x00000000 0x80000000
0xe 0x80000000 0xe 0x80000000 0x80000000
0xf 0x00000000 0xf 0x00000000 0x80000000
0xf 0x80000000 0xf 0x80000000 0x80000000>;
clock-frequency = <0>; /* Filled in by zImage */
SDRAM0: sdram {
@ -245,8 +253,8 @@
ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* Inbound 4GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
/* This drives busses 0 to 0xf */
bus-range = <0x0 0xf>;
@ -289,10 +297,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* Inbound 4GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
/* This drives busses 10 to 0x1f */
/* This drives busses 0x10 to 0x1f */
bus-range = <0x10 0x1f>;
/* Legacy interrupts (note the weird polarity, the bridge seems
@ -330,10 +338,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* Inbound 4GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
/* This drives busses 10 to 0x1f */
/* This drives busses 0x20 to 0x2f */
bus-range = <0x20 0x2f>;
/* Legacy interrupts (note the weird polarity, the bridge seems
@ -371,10 +379,10 @@
ranges = <0x02000000 0x00000000 0x80000000 0x0000000f 0x00000000 0x00000000 0x80000000
0x01000000 0x00000000 0x00000000 0x0000000f 0x80020000 0x00000000 0x00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* Inbound 4GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
/* This drives busses 10 to 0x1f */
/* This drives busses 0x30 to 0x3f */
bus-range = <0x30 0x3f>;
/* Legacy interrupts (note the weird polarity, the bridge seems

View file

@ -272,6 +272,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;
@ -300,6 +302,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;

View file

@ -59,6 +59,13 @@
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; /* Filled in by U-Boot */
pmc: power@b00 {
compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc";
reg = <0xb00 0x100 0xa00 0x100>;
interrupts = <80 0x8>;
interrupt-parent = <&ipic>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;

View file

@ -227,6 +227,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x0000003f>; /* Start at 6 */
rgmii-device = <&RGMII0>;
@ -255,6 +257,8 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
tx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;

View file

@ -79,6 +79,13 @@
reg = <0x200 0x100>;
};
pmc: power@b00 {
compatible = "fsl,mpc8323-pmc", "fsl,mpc8349-pmc";
reg = <0xb00 0x100 0xa00 0x100>;
interrupts = <80 0x8>;
interrupt-parent = <&ipic>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
@ -163,6 +170,7 @@
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0x4c>;
fsl,descriptor-types-mask = <0x0122003f>;
sleep = <&pmc 0x03000000>;
};
ipic: pic@700 {
@ -428,5 +436,6 @@
0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
sleep = <&pmc 0x00010000>;
};
};

View file

@ -62,6 +62,13 @@
reg = <0x200 0x100>;
};
pmc: power@b00 {
compatible = "fsl,mpc8323-pmc", "fsl,mpc8349-pmc";
reg = <0xb00 0x100 0xa00 0x100>;
interrupts = <80 0x8>;
interrupt-parent = <&ipic>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
@ -141,6 +148,7 @@
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0x4c>;
fsl,descriptor-types-mask = <0x0122003f>;
sleep = <&pmc 0x03000000>;
};
ipic:pic@700 {
@ -360,5 +368,6 @@
0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
sleep = <&pmc 0x00010000>;
};
};

View file

@ -99,6 +99,13 @@
reg = <0x200 0x100>;
};
pmc: power@b00 {
compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc";
reg = <0xb00 0x100 0xa00 0x100>;
interrupts = <80 0x8>;
interrupt-parent = <&ipic>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
@ -194,6 +201,7 @@
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0x7e>;
fsl,descriptor-types-mask = <0x01010ebf>;
sleep = <&pmc 0x03000000>;
};
ipic: pic@700 {
@ -470,5 +478,6 @@
0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
sleep = <&pmc 0x00010000>;
};
};

View file

@ -71,6 +71,13 @@
reg = <0x200 0x100>;
};
pmc: power@b00 {
compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc";
reg = <0xb00 0x100 0xa00 0x100>;
interrupts = <80 0x8>;
interrupt-parent = <&ipic>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
@ -161,6 +168,7 @@
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0x7e>;
fsl,descriptor-types-mask = <0x01010ebf>;
sleep = <&pmc 0x03000000>;
};
ipic: interrupt-controller@700 {
@ -455,6 +463,7 @@
0xa800 0 0 2 &ipic 20 8
0xa800 0 0 3 &ipic 21 8
0xa800 0 0 4 &ipic 18 8>;
sleep = <&pmc 0x00010000>;
/* filled by u-boot */
bus-range = <0 0>;
clock-frequency = <0>;

View file

@ -40,6 +40,8 @@
i-cache-line-size = <32>; // 32 bytes
d-cache-size = <0x8000>; // L1, 32K
i-cache-size = <0x8000>; // L1, 32K
sleep = <&pmc 0x00008000 // core
&pmc 0x00004000>; // timebase
timebase-frequency = <0>;
bus-frequency = <0>;
clock-frequency = <0>;
@ -94,6 +96,13 @@
interrupts = <16 2>;
};
i2c-sleep-nexus {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
sleep = <&pmc 0x00000004>;
ranges;
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
@ -107,6 +116,8 @@
rtc@68 {
compatible = "dallas,ds1374";
reg = <0x68>;
interrupts = <3 1>;
interrupt-parent = <&mpic>;
};
};
@ -120,6 +131,7 @@
interrupt-parent = <&mpic>;
dfsrr;
};
};
dma@21300 {
#address-cells = <1>;
@ -128,6 +140,8 @@
reg = <0x21300 0x4>;
ranges = <0x0 0x21100 0x200>;
cell-index = <0>;
sleep = <&pmc 0x00000400>;
dma-channel@0 {
compatible = "fsl,mpc8568-dma-channel",
"fsl,eloplus-dma-channel";
@ -176,6 +190,7 @@
interrupt-parent = <&mpic>;
tbi-handle = <&tbi0>;
phy-handle = <&phy2>;
sleep = <&pmc 0x00000080>;
mdio@520 {
#address-cells = <1>;
@ -228,6 +243,7 @@
interrupt-parent = <&mpic>;
tbi-handle = <&tbi1>;
phy-handle = <&phy3>;
sleep = <&pmc 0x00000040>;
mdio@520 {
#address-cells = <1>;
@ -242,6 +258,13 @@
};
};
duart-sleep-nexus {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
sleep = <&pmc 0x00000002>;
ranges;
serial0: serial@4500 {
cell-index = <0>;
device_type = "serial";
@ -252,12 +275,6 @@
interrupt-parent = <&mpic>;
};
global-utilities@e0000 { //global utilities block
compatible = "fsl,mpc8548-guts";
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
serial1: serial@4600 {
cell-index = <1>;
device_type = "serial";
@ -267,6 +284,22 @@
interrupts = <42 2>;
interrupt-parent = <&mpic>;
};
};
global-utilities@e0000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,mpc8568-guts", "fsl,mpc8548-guts";
reg = <0xe0000 0x1000>;
ranges = <0 0xe0000 0x1000>;
fsl,has-rstcr;
pmc: power@70 {
compatible = "fsl,mpc8568-pmc",
"fsl,mpc8548-pmc";
reg = <0x70 0x20>;
};
};
crypto@30000 {
compatible = "fsl,sec2.1", "fsl,sec2.0";
@ -277,6 +310,7 @@
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0xfe>;
fsl,descriptor-types-mask = <0x12b0ebf>;
sleep = <&pmc 0x01000000>;
};
mpic: pic@40000 {
@ -376,6 +410,7 @@
compatible = "fsl,qe";
ranges = <0x0 0xe0080000 0x40000>;
reg = <0xe0080000 0x480>;
sleep = <&pmc 0x00000800>;
brg-frequency = <0>;
bus-frequency = <396000000>;
fsl,qe-num-riscs = <2>;
@ -509,6 +544,7 @@
bus-range = <0 255>;
ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000
0x1000000 0x0 0x0 0xe2000000 0x0 0x800000>;
sleep = <&pmc 0x80000000>;
clock-frequency = <66666666>;
#interrupt-cells = <1>;
#size-cells = <2>;
@ -534,6 +570,7 @@
bus-range = <0 255>;
ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
0x1000000 0x0 0x0 0xe2800000 0x0 0x800000>;
sleep = <&pmc 0x20000000>;
clock-frequency = <33333333>;
#interrupt-cells = <1>;
#size-cells = <2>;
@ -570,5 +607,7 @@
55 2 /* msg2_tx */
56 2 /* msg2_rx */>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x00080000 /* controller */
&pmc 0x00040000>; /* message unit */
};
};

View file

@ -41,6 +41,8 @@
i-cache-line-size = <32>; // 32 bytes
d-cache-size = <0x8000>; // L1, 32K
i-cache-size = <0x8000>; // L1, 32K
sleep = <&pmc 0x00008000 // core
&pmc 0x00004000>; // timebase
timebase-frequency = <0>;
bus-frequency = <0>;
clock-frequency = <0>;
@ -59,6 +61,7 @@
reg = <0xe0005000 0x1000>;
interrupts = <19 2>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x08000000>;
ranges = <0x0 0x0 0xfe000000 0x02000000
0x1 0x0 0xf8000000 0x00008000
@ -158,6 +161,13 @@
interrupts = <18 2>;
};
i2c-sleep-nexus {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
sleep = <&pmc 0x00000004>;
ranges;
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
@ -171,6 +181,8 @@
rtc@68 {
compatible = "dallas,ds1374";
reg = <0x68>;
interrupts = <3 1>;
interrupt-parent = <&mpic>;
};
};
@ -184,6 +196,14 @@
interrupt-parent = <&mpic>;
dfsrr;
};
};
duart-sleep-nexus {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
sleep = <&pmc 0x00000002>;
ranges;
serial0: serial@4500 {
cell-index = <0>;
@ -204,6 +224,7 @@
interrupts = <42 2>;
interrupt-parent = <&mpic>;
};
};
L2: l2-cache-controller@20000 {
compatible = "fsl,mpc8569-l2-cache-controller";
@ -260,6 +281,7 @@
reg = <0x2e000 0x1000>;
interrupts = <72 0x8>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x00200000>;
/* Filled in by U-Boot */
clock-frequency = <0>;
status = "disabled";
@ -276,6 +298,7 @@
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0xbfe>;
fsl,descriptor-types-mask = <0x3ab0ebf>;
sleep = <&pmc 0x01000000>;
};
mpic: pic@40000 {
@ -304,9 +327,18 @@
};
global-utilities@e0000 {
compatible = "fsl,mpc8569-guts";
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,mpc8569-guts", "fsl,mpc8548-guts";
reg = <0xe0000 0x1000>;
ranges = <0 0xe0000 0x1000>;
fsl,has-rstcr;
pmc: power@70 {
compatible = "fsl,mpc8569-pmc",
"fsl,mpc8548-pmc";
reg = <0x70 0x20>;
};
};
par_io@e0100 {
@ -422,6 +454,7 @@
compatible = "fsl,qe";
ranges = <0x0 0xe0080000 0x40000>;
reg = <0xe0080000 0x480>;
sleep = <&pmc 0x00000800>;
brg-frequency = <0>;
bus-frequency = <0>;
fsl,qe-num-riscs = <4>;
@ -684,6 +717,7 @@
bus-range = <0 255>;
ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
0x1000000 0x0 0x00000000 0xe2800000 0x0 0x00800000>;
sleep = <&pmc 0x20000000>;
clock-frequency = <33333333>;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
@ -714,5 +748,6 @@
55 2 /* msg2_tx */
56 2 /* msg2_rx */>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x00080000>;
};
};

View file

@ -35,6 +35,8 @@
i-cache-line-size = <32>;
d-cache-size = <32768>; // L1
i-cache-size = <32768>; // L1
sleep = <&pmc 0x00008000 0 // core
&pmc 0x00004000 0>; // timebase
timebase-frequency = <0>; // From uboot
bus-frequency = <0>; // From uboot
clock-frequency = <0>; // From uboot
@ -60,6 +62,7 @@
5 0 0xe8480000 0x00008000
6 0 0xe84c0000 0x00008000
3 0 0xe8000000 0x00000020>;
sleep = <&pmc 0x08000000 0>;
flash@0,0 {
compatible = "cfi-flash";
@ -105,6 +108,8 @@
compatible = "fsl,fpga-pixis";
reg = <3 0 0x20>;
ranges = <0 3 0 0x20>;
interrupt-parent = <&mpic>;
interrupts = <8 8>;
sdcsr_pio: gpio-controller@a {
#gpio-cells = <2>;
@ -163,6 +168,7 @@
reg = <0x3100 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x00000004 0>;
dfsrr;
};
@ -174,6 +180,7 @@
clock-frequency = <0>;
interrupts = <42 2>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x00000002 0>;
};
serial1: serial@4600 {
@ -184,6 +191,7 @@
clock-frequency = <0>;
interrupts = <42 2>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x00000008 0>;
};
spi@7000 {
@ -196,6 +204,7 @@
interrupt-parent = <&mpic>;
mode = "cpu";
gpios = <&sdcsr_pio 7 0>;
sleep = <&pmc 0x00000800 0>;
mmc-slot@0 {
compatible = "fsl,mpc8610hpcd-mmc-slot",
@ -213,6 +222,7 @@
reg = <0x2c000 100>;
interrupts = <72 2>;
interrupt-parent = <&mpic>;
sleep = <&pmc 0x04000000 0>;
};
mpic: interrupt-controller@40000 {
@ -241,9 +251,18 @@
};
global-utilities@e0000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,mpc8610-guts";
reg = <0xe0000 0x1000>;
ranges = <0 0xe0000 0x1000>;
fsl,has-rstcr;
pmc: power@70 {
compatible = "fsl,mpc8610-pmc",
"fsl,mpc8641d-pmc";
reg = <0x70 0x20>;
};
};
wdt@e4000 {
@ -262,6 +281,7 @@
fsl,playback-dma = <&dma00>;
fsl,capture-dma = <&dma01>;
fsl,fifo-depth = <8>;
sleep = <&pmc 0 0x08000000>;
};
ssi@16100 {
@ -271,6 +291,7 @@
interrupt-parent = <&mpic>;
interrupts = <63 2>;
fsl,fifo-depth = <8>;
sleep = <&pmc 0 0x04000000>;
};
dma@21300 {
@ -280,6 +301,7 @@
cell-index = <0>;
reg = <0x21300 0x4>; /* DMA general status register */
ranges = <0x0 0x21100 0x200>;
sleep = <&pmc 0x00000400 0>;
dma00: dma-channel@0 {
compatible = "fsl,mpc8610-dma-channel",
@ -322,6 +344,7 @@
cell-index = <1>;
reg = <0xc300 0x4>; /* DMA general status register */
ranges = <0x0 0xc100 0x200>;
sleep = <&pmc 0x00000200 0>;
dma-channel@0 {
compatible = "fsl,mpc8610-dma-channel",
@ -369,6 +392,7 @@
bus-range = <0 0>;
ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000
0x01000000 0x0 0x00000000 0xe1000000 0x0 0x00100000>;
sleep = <&pmc 0x80000000 0>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <24 2>;
@ -398,6 +422,7 @@
bus-range = <1 3>;
ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
0x01000000 0x0 0x00000000 0xe3000000 0x0 0x00100000>;
sleep = <&pmc 0x40000000 0>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <26 2>;
@ -474,6 +499,7 @@
0x0000 0 0 4 &mpic 7 1>;
interrupt-parent = <&mpic>;
interrupts = <25 2>;
sleep = <&pmc 0x20000000 0>;
clock-frequency = <33333333>;
};
};

View file

@ -0,0 +1,477 @@
/*
* P1020 RDB Device Tree Source
*
* Copyright 2009 Freescale Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
/dts-v1/;
/ {
model = "fsl,P1020";
compatible = "fsl,P1020RDB";
#address-cells = <2>;
#size-cells = <2>;
aliases {
serial0 = &serial0;
serial1 = &serial1;
pci0 = &pci0;
pci1 = &pci1;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,P1020@0 {
device_type = "cpu";
reg = <0x0>;
next-level-cache = <&L2>;
};
PowerPC,P1020@1 {
device_type = "cpu";
reg = <0x1>;
next-level-cache = <&L2>;
};
};
memory {
device_type = "memory";
};
localbus@ffe05000 {
#address-cells = <2>;
#size-cells = <1>;
compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus";
reg = <0 0xffe05000 0 0x1000>;
interrupts = <19 2>;
interrupt-parent = <&mpic>;
/* NOR, NAND Flashes and Vitesse 5 port L2 switch */
ranges = <0x0 0x0 0x0 0xef000000 0x01000000
0x1 0x0 0x0 0xffa00000 0x00040000
0x2 0x0 0x0 0xffb00000 0x00020000>;
nor@0,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x0 0x0 0x1000000>;
bank-width = <2>;
device-width = <1>;
partition@0 {
/* This location must not be altered */
/* 256KB for Vitesse 7385 Switch firmware */
reg = <0x0 0x00040000>;
label = "NOR (RO) Vitesse-7385 Firmware";
read-only;
};
partition@40000 {
/* 256KB for DTB Image */
reg = <0x00040000 0x00040000>;
label = "NOR (RO) DTB Image";
read-only;
};
partition@80000 {
/* 3.5 MB for Linux Kernel Image */
reg = <0x00080000 0x00380000>;
label = "NOR (RO) Linux Kernel Image";
read-only;
};
partition@400000 {
/* 11MB for JFFS2 based Root file System */
reg = <0x00400000 0x00b00000>;
label = "NOR (RW) JFFS2 Root File System";
};
partition@f00000 {
/* This location must not be altered */
/* 512KB for u-boot Bootloader Image */
/* 512KB for u-boot Environment Variables */
reg = <0x00f00000 0x00100000>;
label = "NOR (RO) U-Boot Image";
read-only;
};
};
nand@1,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,p1020-fcm-nand",
"fsl,elbc-fcm-nand";
reg = <0x1 0x0 0x40000>;
partition@0 {
/* This location must not be altered */
/* 1MB for u-boot Bootloader Image */
reg = <0x0 0x00100000>;
label = "NAND (RO) U-Boot Image";
read-only;
};
partition@100000 {
/* 1MB for DTB Image */
reg = <0x00100000 0x00100000>;
label = "NAND (RO) DTB Image";
read-only;
};
partition@200000 {
/* 4MB for Linux Kernel Image */
reg = <0x00200000 0x00400000>;
label = "NAND (RO) Linux Kernel Image";
read-only;
};
partition@600000 {
/* 4MB for Compressed Root file System Image */
reg = <0x00600000 0x00400000>;
label = "NAND (RO) Compressed RFS Image";
read-only;
};
partition@a00000 {
/* 7MB for JFFS2 based Root file System */
reg = <0x00a00000 0x00700000>;
label = "NAND (RW) JFFS2 Root File System";
};
partition@1100000 {
/* 15MB for JFFS2 based Root file System */
reg = <0x01100000 0x00f00000>;
label = "NAND (RW) Writable User area";
};
};
L2switch@2,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "vitesse-7385";
reg = <0x2 0x0 0x20000>;
};
};
soc@ffe00000 {
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
compatible = "fsl,p1020-immr", "simple-bus";
ranges = <0x0 0x0 0xffe00000 0x100000>;
bus-frequency = <0>; // Filled out by uboot.
ecm-law@0 {
compatible = "fsl,ecm-law";
reg = <0x0 0x1000>;
fsl,num-laws = <12>;
};
ecm@1000 {
compatible = "fsl,p1020-ecm", "fsl,ecm";
reg = <0x1000 0x1000>;
interrupts = <16 2>;
interrupt-parent = <&mpic>;
};
memory-controller@2000 {
compatible = "fsl,p1020-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <16 2>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
dfsrr;
rtc@68 {
compatible = "dallas,ds1339";
reg = <0x68>;
};
};
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <1>;
compatible = "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
serial0: serial@4500 {
cell-index = <0>;
device_type = "serial";
compatible = "ns16550";
reg = <0x4500 0x100>;
clock-frequency = <0>;
interrupts = <42 2>;
interrupt-parent = <&mpic>;
};
serial1: serial@4600 {
cell-index = <1>;
device_type = "serial";
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
interrupts = <42 2>;
interrupt-parent = <&mpic>;
};
spi@7000 {
cell-index = <0>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,espi";
reg = <0x7000 0x1000>;
interrupts = <59 0x2>;
interrupt-parent = <&mpic>;
mode = "cpu";
fsl_m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,espi-flash";
reg = <0>;
linux,modalias = "fsl_m25p80";
modal = "s25sl128b";
spi-max-frequency = <50000000>;
mode = <0>;
partition@0 {
/* 512KB for u-boot Bootloader Image */
reg = <0x0 0x00080000>;
label = "SPI (RO) U-Boot Image";
read-only;
};
partition@80000 {
/* 512KB for DTB Image */
reg = <0x00080000 0x00080000>;
label = "SPI (RO) DTB Image";
read-only;
};
partition@100000 {
/* 4MB for Linux Kernel Image */
reg = <0x00100000 0x00400000>;
label = "SPI (RO) Linux Kernel Image";
read-only;
};
partition@500000 {
/* 4MB for Compressed RFS Image */
reg = <0x00500000 0x00400000>;
label = "SPI (RO) Compressed RFS Image";
read-only;
};
partition@900000 {
/* 7MB for JFFS2 based RFS */
reg = <0x00900000 0x00700000>;
label = "SPI (RW) JFFS2 RFS";
};
};
};
gpio: gpio-controller@f000 {
#gpio-cells = <2>;
compatible = "fsl,mpc8572-gpio";
reg = <0xf000 0x100>;
interrupts = <47 0x2>;
interrupt-parent = <&mpic>;
gpio-controller;
};
L2: l2-cache-controller@20000 {
compatible = "fsl,p1020-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2,256K
interrupt-parent = <&mpic>;
interrupts = <16 2>;
};
dma@21300 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,eloplus-dma";
reg = <0x21300 0x4>;
ranges = <0x0 0x21100 0x200>;
cell-index = <0>;
dma-channel@0 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupt-parent = <&mpic>;
interrupts = <20 2>;
};
dma-channel@80 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&mpic>;
interrupts = <21 2>;
};
dma-channel@100 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&mpic>;
interrupts = <22 2>;
};
dma-channel@180 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
interrupt-parent = <&mpic>;
interrupts = <23 2>;
};
};
usb@22000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl-usb2-dr";
reg = <0x22000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <28 0x2>;
phy_type = "ulpi";
};
usb@23000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl-usb2-dr";
reg = <0x23000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <46 0x2>;
phy_type = "ulpi";
};
sdhci@2e000 {
compatible = "fsl,p1020-esdhc", "fsl,esdhc";
reg = <0x2e000 0x1000>;
interrupts = <72 0x2>;
interrupt-parent = <&mpic>;
/* Filled in by U-Boot */
clock-frequency = <0>;
};
crypto@30000 {
compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4",
"fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
reg = <0x30000 0x10000>;
interrupts = <45 2 58 2>;
interrupt-parent = <&mpic>;
fsl,num-channels = <4>;
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0xbfe>;
fsl,descriptor-types-mask = <0x3ab0ebf>;
};
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
reg = <0x40000 0x40000>;
compatible = "chrp,open-pic";
device_type = "open-pic";
};
msi@41600 {
compatible = "fsl,p1020-msi", "fsl,mpic-msi";
reg = <0x41600 0x80>;
msi-available-ranges = <0 0x100>;
interrupts = <
0xe0 0
0xe1 0
0xe2 0
0xe3 0
0xe4 0
0xe5 0
0xe6 0
0xe7 0>;
interrupt-parent = <&mpic>;
};
global-utilities@e0000 { //global utilities block
compatible = "fsl,p1020-guts";
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
};
pci0: pcie@ffe09000 {
compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0 0xffe09000 0 0x1000>;
bus-range = <0 255>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc30000 0x0 0x10000>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <16 2>;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x2000000 0x0 0xa0000000
0x2000000 0x0 0xa0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
pci1: pcie@ffe0a000 {
compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0 0xffe0a000 0 0x1000>;
bus-range = <0 255>;
ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <16 2>;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x2000000 0x0 0xc0000000
0x2000000 0x0 0xc0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
};

View file

@ -0,0 +1,363 @@
/*
* P2020 RDB Core0 Device Tree Source in CAMP mode.
*
* In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
* can be shared, all the other devices must be assigned to one core only.
* This dts file allows core0 to have memory, l2, i2c, spi, gpio, dma1, usb,
* eth1, eth2, sdhc, crypto, global-util, pci0.
*
* Copyright 2009 Freescale Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
/dts-v1/;
/ {
model = "fsl,P2020";
compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
#address-cells = <2>;
#size-cells = <2>;
aliases {
ethernet1 = &enet1;
ethernet2 = &enet2;
serial0 = &serial0;
pci0 = &pci0;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,P2020@0 {
device_type = "cpu";
reg = <0x0>;
next-level-cache = <&L2>;
};
};
memory {
device_type = "memory";
};
soc@ffe00000 {
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
compatible = "fsl,p2020-immr", "simple-bus";
ranges = <0x0 0x0 0xffe00000 0x100000>;
bus-frequency = <0>; // Filled out by uboot.
ecm-law@0 {
compatible = "fsl,ecm-law";
reg = <0x0 0x1000>;
fsl,num-laws = <12>;
};
ecm@1000 {
compatible = "fsl,p2020-ecm", "fsl,ecm";
reg = <0x1000 0x1000>;
interrupts = <17 2>;
interrupt-parent = <&mpic>;
};
memory-controller@2000 {
compatible = "fsl,p2020-memory-controller";
reg = <0x2000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <18 2>;
};
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
dfsrr;
rtc@68 {
compatible = "dallas,ds1339";
reg = <0x68>;
};
};
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <1>;
compatible = "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
serial0: serial@4500 {
cell-index = <0>;
device_type = "serial";
compatible = "ns16550";
reg = <0x4500 0x100>;
clock-frequency = <0>;
};
spi@7000 {
cell-index = <0>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,espi";
reg = <0x7000 0x1000>;
interrupts = <59 0x2>;
interrupt-parent = <&mpic>;
mode = "cpu";
fsl_m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,espi-flash";
reg = <0>;
linux,modalias = "fsl_m25p80";
modal = "s25sl128b";
spi-max-frequency = <50000000>;
mode = <0>;
partition@0 {
/* 512KB for u-boot Bootloader Image */
reg = <0x0 0x00080000>;
label = "SPI (RO) U-Boot Image";
read-only;
};
partition@80000 {
/* 512KB for DTB Image */
reg = <0x00080000 0x00080000>;
label = "SPI (RO) DTB Image";
read-only;
};
partition@100000 {
/* 4MB for Linux Kernel Image */
reg = <0x00100000 0x00400000>;
label = "SPI (RO) Linux Kernel Image";
read-only;
};
partition@500000 {
/* 4MB for Compressed RFS Image */
reg = <0x00500000 0x00400000>;
label = "SPI (RO) Compressed RFS Image";
read-only;
};
partition@900000 {
/* 7MB for JFFS2 based RFS */
reg = <0x00900000 0x00700000>;
label = "SPI (RW) JFFS2 RFS";
};
};
};
gpio: gpio-controller@f000 {
#gpio-cells = <2>;
compatible = "fsl,mpc8572-gpio";
reg = <0xf000 0x100>;
interrupts = <47 0x2>;
interrupt-parent = <&mpic>;
gpio-controller;
};
L2: l2-cache-controller@20000 {
compatible = "fsl,p2020-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x80000>; // L2,512K
interrupt-parent = <&mpic>;
interrupts = <16 2>;
};
dma@21300 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,eloplus-dma";
reg = <0x21300 0x4>;
ranges = <0x0 0x21100 0x200>;
cell-index = <0>;
dma-channel@0 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupt-parent = <&mpic>;
interrupts = <20 2>;
};
dma-channel@80 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&mpic>;
interrupts = <21 2>;
};
dma-channel@100 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&mpic>;
interrupts = <22 2>;
};
dma-channel@180 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
interrupt-parent = <&mpic>;
interrupts = <23 2>;
};
};
usb@22000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl-usb2-dr";
reg = <0x22000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <28 0x2>;
phy_type = "ulpi";
};
mdio@24520 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,gianfar-mdio";
reg = <0x24520 0x20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
interrupts = <3 1>;
reg = <0x0>;
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
interrupts = <3 1>;
reg = <0x1>;
};
};
mdio@25520 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,gianfar-tbi";
reg = <0x26520 0x20>;
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 2 36 2 40 2>;
interrupt-parent = <&mpic>;
tbi-handle = <&tbi0>;
phy-handle = <&phy0>;
phy-connection-type = "sgmii";
};
enet2: ethernet@26000 {
#address-cells = <1>;
#size-cells = <1>;
cell-index = <2>;
device_type = "network";
model = "eTSEC";
compatible = "gianfar";
reg = <0x26000 0x1000>;
ranges = <0x0 0x26000 0x1000>;
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <31 2 32 2 33 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
phy-connection-type = "rgmii-id";
};
sdhci@2e000 {
compatible = "fsl,p2020-esdhc", "fsl,esdhc";
reg = <0x2e000 0x1000>;
interrupts = <72 0x2>;
interrupt-parent = <&mpic>;
/* Filled in by U-Boot */
clock-frequency = <0>;
};
crypto@30000 {
compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4",
"fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
reg = <0x30000 0x10000>;
interrupts = <45 2 58 2>;
interrupt-parent = <&mpic>;
fsl,num-channels = <4>;
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0xbfe>;
fsl,descriptor-types-mask = <0x3ab0ebf>;
};
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
reg = <0x40000 0x40000>;
compatible = "chrp,open-pic";
device_type = "open-pic";
protected-sources = <
42 76 77 78 79 /* serial1 , dma2 */
29 30 34 26 /* enet0, pci1 */
0xe0 0xe1 0xe2 0xe3 /* msi */
0xe4 0xe5 0xe6 0xe7
>;
};
global-utilities@e0000 {
compatible = "fsl,p2020-guts";
reg = <0xe0000 0x1000>;
fsl,has-rstcr;
};
};
pci0: pcie@ffe09000 {
compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0 0xffe09000 0 0x1000>;
bus-range = <0 255>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc30000 0x0 0x10000>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <25 2>;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x2000000 0x0 0xa0000000
0x2000000 0x0 0xa0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
};

View file

@ -0,0 +1,184 @@
/*
* P2020 RDB Core1 Device Tree Source in CAMP mode.
*
* In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
* can be shared, all the other devices must be assigned to one core only.
* This dts allows core1 to have l2, dma2, eth0, pci1, msi.
*
* Please note to add "-b 1" for core1's dts compiling.
*
* Copyright 2009 Freescale Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
/dts-v1/;
/ {
model = "fsl,P2020";
compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
#address-cells = <2>;
#size-cells = <2>;
aliases {
ethernet0 = &enet0;
serial0 = &serial0;
pci1 = &pci1;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,P2020@1 {
device_type = "cpu";
reg = <0x1>;
next-level-cache = <&L2>;
};
};
memory {
device_type = "memory";
};
soc@ffe00000 {
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
compatible = "fsl,p2020-immr", "simple-bus";
ranges = <0x0 0x0 0xffe00000 0x100000>;
bus-frequency = <0>; // Filled out by uboot.
serial0: serial@4600 {
cell-index = <1>;
device_type = "serial";
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
};
dma@c300 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,eloplus-dma";
reg = <0xc300 0x4>;
ranges = <0x0 0xc100 0x200>;
cell-index = <1>;
dma-channel@0 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupt-parent = <&mpic>;
interrupts = <76 2>;
};
dma-channel@80 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&mpic>;
interrupts = <77 2>;
};
dma-channel@100 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&mpic>;
interrupts = <78 2>;
};
dma-channel@180 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
interrupt-parent = <&mpic>;
interrupts = <79 2>;
};
};
L2: l2-cache-controller@20000 {
compatible = "fsl,p2020-l2-cache-controller";
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x80000>; // L2,512K
interrupt-parent = <&mpic>;
};
enet0: ethernet@24000 {
#address-cells = <1>;
#size-cells = <1>;
cell-index = <0>;
device_type = "network";
model = "eTSEC";
compatible = "gianfar";
reg = <0x24000 0x1000>;
ranges = <0x0 0x24000 0x1000>;
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <29 2 30 2 34 2>;
interrupt-parent = <&mpic>;
fixed-link = <1 1 1000 0 0>;
phy-connection-type = "rgmii-id";
};
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
reg = <0x40000 0x40000>;
compatible = "chrp,open-pic";
device_type = "open-pic";
protected-sources = <
17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */
16 20 21 22 23 28 /* L2, dma1, USB */
03 35 36 40 31 32 33 /* mdio, enet1, enet2 */
72 45 58 25 /* sdhci, crypto , pci */
>;
};
msi@41600 {
compatible = "fsl,p2020-msi", "fsl,mpic-msi";
reg = <0x41600 0x80>;
msi-available-ranges = <0 0x100>;
interrupts = <
0xe0 0
0xe1 0
0xe2 0
0xe3 0
0xe4 0
0xe5 0
0xe6 0
0xe7 0>;
interrupt-parent = <&mpic>;
};
};
pci1: pcie@ffe0a000 {
compatible = "fsl,mpc8548-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0 0xffe0a000 0 0x1000>;
bus-range = <0 255>;
ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
clock-frequency = <33333333>;
interrupt-parent = <&mpic>;
interrupts = <26 2>;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x2000000 0x0 0xc0000000
0x2000000 0x0 0xc0000000
0x0 0x20000000
0x1000000 0x0 0x0
0x1000000 0x0 0x0
0x0 0x100000>;
};
};
};

View file

@ -0,0 +1,554 @@
/*
* P4080DS Device Tree Source
*
* Copyright 2009 Freescale Semiconductor Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
/dts-v1/;
/ {
model = "fsl,P4080DS";
compatible = "fsl,P4080DS";
#address-cells = <2>;
#size-cells = <2>;
aliases {
ccsr = &soc;
serial0 = &serial0;
serial1 = &serial1;
serial2 = &serial2;
serial3 = &serial3;
pci0 = &pci0;
pci1 = &pci1;
pci2 = &pci2;
usb0 = &usb0;
usb1 = &usb1;
dma0 = &dma0;
dma1 = &dma1;
sdhc = &sdhc;
rio0 = &rapidio0;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: PowerPC,4080@0 {
device_type = "cpu";
reg = <0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
};
};
cpu1: PowerPC,4080@1 {
device_type = "cpu";
reg = <1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
};
};
cpu2: PowerPC,4080@2 {
device_type = "cpu";
reg = <2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
};
};
cpu3: PowerPC,4080@3 {
device_type = "cpu";
reg = <3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
};
};
cpu4: PowerPC,4080@4 {
device_type = "cpu";
reg = <4>;
next-level-cache = <&L2_4>;
L2_4: l2-cache {
};
};
cpu5: PowerPC,4080@5 {
device_type = "cpu";
reg = <5>;
next-level-cache = <&L2_5>;
L2_5: l2-cache {
};
};
cpu6: PowerPC,4080@6 {
device_type = "cpu";
reg = <6>;
next-level-cache = <&L2_6>;
L2_6: l2-cache {
};
};
cpu7: PowerPC,4080@7 {
device_type = "cpu";
reg = <7>;
next-level-cache = <&L2_7>;
L2_7: l2-cache {
};
};
};
memory {
device_type = "memory";
};
soc: soc@ffe000000 {
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
compatible = "simple-bus";
ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
reg = <0xf 0xfe000000 0 0x00001000>;
corenet-law@0 {
compatible = "fsl,corenet-law";
reg = <0x0 0x1000>;
fsl,num-laws = <32>;
};
memory-controller@8000 {
compatible = "fsl,p4080-memory-controller";
reg = <0x8000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <0x12 2>;
};
memory-controller@9000 {
compatible = "fsl,p4080-memory-controller";
reg = <0x9000 0x1000>;
interrupt-parent = <&mpic>;
interrupts = <0x12 2>;
};
corenet-cf@18000 {
compatible = "fsl,corenet-cf";
reg = <0x18000 0x1000>;
fsl,ccf-num-csdids = <32>;
fsl,ccf-num-snoopids = <32>;
};
iommu@20000 {
compatible = "fsl,p4080-pamu";
reg = <0x20000 0x10000>;
interrupts = <24 2>;
interrupt-parent = <&mpic>;
};
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
reg = <0x40000 0x40000>;
compatible = "chrp,open-pic";
device_type = "open-pic";
};
dma0: dma@100300 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,p4080-dma", "fsl,eloplus-dma";
reg = <0x100300 0x4>;
ranges = <0x0 0x100100 0x200>;
cell-index = <0>;
dma-channel@0 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupt-parent = <&mpic>;
interrupts = <28 2>;
};
dma-channel@80 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&mpic>;
interrupts = <29 2>;
};
dma-channel@100 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&mpic>;
interrupts = <30 2>;
};
dma-channel@180 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
interrupt-parent = <&mpic>;
interrupts = <31 2>;
};
};
dma1: dma@101300 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,p4080-dma", "fsl,eloplus-dma";
reg = <0x101300 0x4>;
ranges = <0x0 0x101100 0x200>;
cell-index = <1>;
dma-channel@0 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupt-parent = <&mpic>;
interrupts = <32 2>;
};
dma-channel@80 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupt-parent = <&mpic>;
interrupts = <33 2>;
};
dma-channel@100 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
interrupt-parent = <&mpic>;
interrupts = <34 2>;
};
dma-channel@180 {
compatible = "fsl,p4080-dma-channel",
"fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
interrupt-parent = <&mpic>;
interrupts = <35 2>;
};
};
spi@110000 {
cell-index = <0>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,espi";
reg = <0x110000 0x1000>;
interrupts = <53 0x2>;
interrupt-parent = <&mpic>;
espi,num-ss-bits = <4>;
mode = "cpu";
fsl_m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,espi-flash";
reg = <0>;
linux,modalias = "fsl_m25p80";
spi-max-frequency = <40000000>; /* input clock */
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>;
};
};
};
sdhc: sdhc@114000 {
compatible = "fsl,p4080-esdhc", "fsl,esdhc";
reg = <0x114000 0x1000>;
interrupts = <48 2>;
interrupt-parent = <&mpic>;
};
i2c@118000 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
compatible = "fsl-i2c";
reg = <0x118000 0x100>;
interrupts = <38 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
i2c@118100 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <1>;
compatible = "fsl-i2c";
reg = <0x118100 0x100>;
interrupts = <38 2>;
interrupt-parent = <&mpic>;
dfsrr;
eeprom@51 {
compatible = "at24,24c256";
reg = <0x51>;
};
eeprom@52 {
compatible = "at24,24c256";
reg = <0x52>;
};
rtc@68 {
compatible = "dallas,ds3232";
reg = <0x68>;
interrupts = <0 0x1>;
interrupt-parent = <&mpic>;
};
};
i2c@119000 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <2>;
compatible = "fsl-i2c";
reg = <0x119000 0x100>;
interrupts = <39 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
i2c@119100 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <3>;
compatible = "fsl-i2c";
reg = <0x119100 0x100>;
interrupts = <39 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
serial0: serial@11c500 {
cell-index = <0>;
device_type = "serial";
compatible = "ns16550";
reg = <0x11c500 0x100>;
clock-frequency = <0>;
interrupts = <36 2>;
interrupt-parent = <&mpic>;
};
serial1: serial@11c600 {
cell-index = <1>;
device_type = "serial";
compatible = "ns16550";
reg = <0x11c600 0x100>;
clock-frequency = <0>;
interrupts = <36 2>;
interrupt-parent = <&mpic>;
};
serial2: serial@11d500 {
cell-index = <2>;
device_type = "serial";
compatible = "ns16550";
reg = <0x11d500 0x100>;
clock-frequency = <0>;
interrupts = <37 2>;
interrupt-parent = <&mpic>;
};
serial3: serial@11d600 {
cell-index = <3>;
device_type = "serial";
compatible = "ns16550";
reg = <0x11d600 0x100>;
clock-frequency = <0>;
interrupts = <37 2>;
interrupt-parent = <&mpic>;
};
gpio0: gpio@130000 {
compatible = "fsl,p4080-gpio";
reg = <0x130000 0x1000>;
interrupts = <55 2>;
interrupt-parent = <&mpic>;
#gpio-cells = <2>;
gpio-controller;
};
usb0: usb@210000 {
compatible = "fsl,p4080-usb2-mph",
"fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
reg = <0x210000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&mpic>;
interrupts = <44 0x2>;
phy_type = "ulpi";
};
usb1: usb@211000 {
compatible = "fsl,p4080-usb2-dr",
"fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
reg = <0x211000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&mpic>;
interrupts = <45 0x2>;
dr_mode = "host";
phy_type = "ulpi";
};
};
rapidio0: rapidio@ffe0c0000 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "fsl,rapidio-delta";
reg = <0xf 0xfe0c0000 0 0x20000>;
ranges = <0 0 0xf 0xf5000000 0 0x01000000>;
interrupt-parent = <&mpic>;
/* err_irq bell_outb_irq bell_inb_irq
msg1_tx_irq msg1_rx_irq msg2_tx_irq msg2_rx_irq */
interrupts = <16 2 56 2 57 2 60 2 61 2 62 2 63 2>;
};
localbus@ffe124000 {
compatible = "fsl,p4080-elbc", "fsl,elbc", "simple-bus";
reg = <0xf 0xfe124000 0 0x1000>;
interrupts = <25 2>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0xf 0xe8000000 0x08000000>;
flash@0,0 {
compatible = "cfi-flash";
reg = <0 0 0x08000000>;
bank-width = <2>;
device-width = <2>;
};
};
pci0: pcie@ffe200000 {
compatible = "fsl,p4080-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0xf 0xfe200000 0 0x1000>;
bus-range = <0x0 0xff>;
ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
clock-frequency = <0x1fca055>;
interrupt-parent = <&mpic>;
interrupts = <16 2>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
0000 0 0 1 &mpic 40 1
0000 0 0 2 &mpic 1 1
0000 0 0 3 &mpic 2 1
0000 0 0 4 &mpic 3 1
>;
pcie@0 {
reg = <0 0 0 0 0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x02000000 0 0xe0000000
0x02000000 0 0xe0000000
0 0x20000000
0x01000000 0 0x00000000
0x01000000 0 0x00000000
0 0x00010000>;
};
};
pci1: pcie@ffe201000 {
compatible = "fsl,p4080-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0xf 0xfe201000 0 0x1000>;
bus-range = <0 0xff>;
ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
clock-frequency = <0x1fca055>;
interrupt-parent = <&mpic>;
interrupts = <16 2>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
0000 0 0 1 &mpic 41 1
0000 0 0 2 &mpic 5 1
0000 0 0 3 &mpic 6 1
0000 0 0 4 &mpic 7 1
>;
pcie@0 {
reg = <0 0 0 0 0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x02000000 0 0xe0000000
0x02000000 0 0xe0000000
0 0x20000000
0x01000000 0 0x00000000
0x01000000 0 0x00000000
0 0x00010000>;
};
};
pci2: pcie@ffe202000 {
compatible = "fsl,p4080-pcie";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = <0xf 0xfe202000 0 0x1000>;
bus-range = <0x0 0xff>;
ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
clock-frequency = <0x1fca055>;
interrupt-parent = <&mpic>;
interrupts = <16 2>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
0000 0 0 1 &mpic 42 1
0000 0 0 2 &mpic 9 1
0000 0 0 3 &mpic 10 1
0000 0 0 4 &mpic 11 1
>;
pcie@0 {
reg = <0 0 0 0 0>;
#size-cells = <2>;
#address-cells = <3>;
device_type = "pci";
ranges = <0x02000000 0 0xe0000000
0x02000000 0 0xe0000000
0 0x20000000
0x01000000 0 0x00000000
0x01000000 0 0x00000000
0 0x00010000>;
};
};
};

View file

@ -226,6 +226,7 @@
max-frame-size = <9000>;
rx-fifo-size = <4096>;
tx-fifo-size = <2048>;
rx-fifo-size-gige = <16384>;
phy-mode = "rgmii";
phy-map = <0x00000000>;
rgmii-device = <&RGMII0>;

View file

@ -282,20 +282,10 @@
/* Inbound 2GB range starting at 0 */
dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
/* Bamboo has all 4 IRQ pins tied together per slot */
interrupt-map-mask = <0xf800 0x0 0x0 0x0>;
interrupt-map = <
/* IDSEL 1 */
0x800 0x0 0x0 0x0 &UIC0 0x1c 0x8
/* IDSEL 2 */
0x1000 0x0 0x0 0x0 &UIC0 0x1b 0x8
/* IDSEL 3 */
0x1800 0x0 0x0 0x0 &UIC0 0x1a 0x8
/* IDSEL 4 */
0x2000 0x0 0x0 0x0 &UIC0 0x19 0x8
/* IDSEL 12 */
0x6000 0x0 0x0 0x0 &UIC0 0x19 0x8
>;
};
};

View file

@ -218,7 +218,7 @@ CONFIG_MPIC=y
# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_MMIO_NVRAM=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
# CONFIG_PPC_INDIRECT_IO is not set

View file

@ -218,7 +218,7 @@ CONFIG_MPIC=y
# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_MMIO_NVRAM=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
# CONFIG_PPC_INDIRECT_IO is not set

View file

@ -219,7 +219,7 @@ CONFIG_MPIC=y
# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_MMIO_NVRAM=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
# CONFIG_PPC_INDIRECT_IO is not set
@ -1124,7 +1124,7 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_TIMERIOMEM is not set
# CONFIG_NVRAM is not set
CONFIG_NVRAM=y
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_RAW_DRIVER is not set

View file

@ -3,8 +3,47 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/of.h>
/*
* USB Controller pram common to QE and CPM.
*/
struct usb_ctlr {
u8 usb_usmod;
u8 usb_usadr;
u8 usb_uscom;
u8 res1[1];
__be16 usb_usep[4];
u8 res2[4];
__be16 usb_usber;
u8 res3[2];
__be16 usb_usbmr;
u8 res4[1];
u8 usb_usbs;
/* Fields down below are QE-only */
__be16 usb_ussft;
u8 res5[2];
__be16 usb_usfrn;
u8 res6[0x22];
} __attribute__ ((packed));
/*
* Function code bits, usually generic to devices.
*/
#ifdef CONFIG_CPM1
#define CPMFCR_GBL ((u_char)0x00) /* Flag doesn't exist in CPM1 */
#define CPMFCR_TC2 ((u_char)0x00) /* Flag doesn't exist in CPM1 */
#define CPMFCR_DTB ((u_char)0x00) /* Flag doesn't exist in CPM1 */
#define CPMFCR_BDB ((u_char)0x00) /* Flag doesn't exist in CPM1 */
#else
#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */
#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */
#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */
#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */
#endif
#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */
/* Opcodes common to CPM1 and CPM2
*/
#define CPM_CR_INIT_TRX ((ushort)0x0000)
@ -93,13 +132,56 @@ typedef struct cpm_buf_desc {
#define BD_I2C_START (0x0400)
int cpm_muram_init(void);
#if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE)
unsigned long cpm_muram_alloc(unsigned long size, unsigned long align);
int cpm_muram_free(unsigned long offset);
unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size);
void __iomem *cpm_muram_addr(unsigned long offset);
unsigned long cpm_muram_offset(void __iomem *addr);
dma_addr_t cpm_muram_dma(void __iomem *addr);
#else
static inline unsigned long cpm_muram_alloc(unsigned long size,
unsigned long align)
{
return -ENOSYS;
}
static inline int cpm_muram_free(unsigned long offset)
{
return -ENOSYS;
}
static inline unsigned long cpm_muram_alloc_fixed(unsigned long offset,
unsigned long size)
{
return -ENOSYS;
}
static inline void __iomem *cpm_muram_addr(unsigned long offset)
{
return NULL;
}
static inline unsigned long cpm_muram_offset(void __iomem *addr)
{
return -ENOSYS;
}
static inline dma_addr_t cpm_muram_dma(void __iomem *addr)
{
return 0;
}
#endif /* defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) */
#ifdef CONFIG_CPM
int cpm_command(u32 command, u8 opcode);
#else
static inline int cpm_command(u32 command, u8 opcode)
{
return -ENOSYS;
}
#endif /* CONFIG_CPM */
int cpm2_gpiochip_add32(struct device_node *np);

View file

@ -478,51 +478,6 @@ typedef struct iic {
char res2[2]; /* Reserved */
} iic_t;
/* SPI parameter RAM.
*/
typedef struct spi {
ushort spi_rbase; /* Rx Buffer descriptor base address */
ushort spi_tbase; /* Tx Buffer descriptor base address */
u_char spi_rfcr; /* Rx function code */
u_char spi_tfcr; /* Tx function code */
ushort spi_mrblr; /* Max receive buffer length */
uint spi_rstate; /* Internal */
uint spi_rdp; /* Internal */
ushort spi_rbptr; /* Internal */
ushort spi_rbc; /* Internal */
uint spi_rxtmp; /* Internal */
uint spi_tstate; /* Internal */
uint spi_tdp; /* Internal */
ushort spi_tbptr; /* Internal */
ushort spi_tbc; /* Internal */
uint spi_txtmp; /* Internal */
uint spi_res;
ushort spi_rpbase; /* Relocation pointer */
ushort spi_res2;
} spi_t;
/* SPI Mode register.
*/
#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */
#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */
#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */
#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */
#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */
#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */
#define SPMODE_EN ((ushort)0x0100) /* Enable */
#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */
#define SPMODE_LEN4 ((ushort)0x0030) /* 4 bits per char */
#define SPMODE_LEN8 ((ushort)0x0070) /* 8 bits per char */
#define SPMODE_LEN16 ((ushort)0x00f0) /* 16 bits per char */
#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */
/* SPIE fields */
#define SPIE_MME 0x20
#define SPIE_TXE 0x10
#define SPIE_BSY 0x04
#define SPIE_TXB 0x02
#define SPIE_RXB 0x01
/*
* RISC Controller Configuration Register definitons
*/

View file

@ -124,14 +124,6 @@ static inline void cpm2_fastbrg(uint brg, uint rate, int div16)
__cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT);
}
/* Function code bits, usually generic to devices.
*/
#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */
#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */
#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */
#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */
#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */
/* Parameter RAM offsets from the base.
*/
#define PROFF_SCC1 ((uint)0x8000)
@ -654,45 +646,6 @@ typedef struct iic {
uint iic_txtmp; /* Internal */
} iic_t;
/* SPI parameter RAM.
*/
typedef struct spi {
ushort spi_rbase; /* Rx Buffer descriptor base address */
ushort spi_tbase; /* Tx Buffer descriptor base address */
u_char spi_rfcr; /* Rx function code */
u_char spi_tfcr; /* Tx function code */
ushort spi_mrblr; /* Max receive buffer length */
uint spi_rstate; /* Internal */
uint spi_rdp; /* Internal */
ushort spi_rbptr; /* Internal */
ushort spi_rbc; /* Internal */
uint spi_rxtmp; /* Internal */
uint spi_tstate; /* Internal */
uint spi_tdp; /* Internal */
ushort spi_tbptr; /* Internal */
ushort spi_tbc; /* Internal */
uint spi_txtmp; /* Internal */
uint spi_res; /* Tx temp. */
uint spi_res1[4]; /* SDMA temp. */
} spi_t;
/* SPI Mode register.
*/
#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */
#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */
#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */
#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */
#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */
#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */
#define SPMODE_EN ((ushort)0x0100) /* Enable */
#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */
#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */
#define SPMODE_LEN(x) ((((x)-1)&0xF)<<4)
#define SPMODE_PM(x) ((x) &0xF)
#define SPI_EB ((u_char)0x10) /* big endian byte order */
/* IDMA parameter RAM
*/
typedef struct idma {

View file

@ -147,6 +147,7 @@
.globl label##_pSeries; \
label##_pSeries: \
HMT_MEDIUM; \
DO_KVM n; \
mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
@ -170,6 +171,7 @@ label##_pSeries: \
.globl label##_pSeries; \
label##_pSeries: \
HMT_MEDIUM; \
DO_KVM n; \
mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \
std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \

View file

@ -3,6 +3,10 @@
#include <asm/page.h>
pte_t *huge_pte_offset_and_shift(struct mm_struct *mm,
unsigned long addr, unsigned *shift);
void flush_dcache_icache_hugepage(struct page *page);
int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
unsigned long len);
@ -11,12 +15,6 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr,
unsigned long end, unsigned long floor,
unsigned long ceiling);
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte);
pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep);
/*
* The version of vma_mmu_pagesize() in arch/powerpc/mm/hugetlbpage.c needs
* to override the version in mm/hugetlb.c
@ -42,9 +40,26 @@ static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
{
}
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
set_pte_at(mm, addr, ptep, pte);
}
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1);
return __pte(old);
}
static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
pte_t pte;
pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
flush_tlb_page(vma, addr);
}
static inline int huge_pte_none(pte_t pte)

View file

@ -212,6 +212,19 @@
#define H_QUERY_INT_STATE 0x1E4
#define H_POLL_PENDING 0x1D8
#define H_ILLAN_ATTRIBUTES 0x244
#define H_MODIFY_HEA_QP 0x250
#define H_QUERY_HEA_QP 0x254
#define H_QUERY_HEA 0x258
#define H_QUERY_HEA_PORT 0x25C
#define H_MODIFY_HEA_PORT 0x260
#define H_REG_BCMC 0x264
#define H_DEREG_BCMC 0x268
#define H_REGISTER_HEA_RPAGES 0x26C
#define H_DISABLE_AND_GET_HEA 0x270
#define H_GET_HEA_INFO 0x274
#define H_ALLOC_HEA_RESOURCE 0x278
#define H_ADD_CONN 0x284
#define H_DEL_CONN 0x288
#define H_JOIN 0x298
#define H_VASI_STATE 0x2A4
#define H_ENABLE_CRQ 0x2B0

View file

@ -64,11 +64,6 @@ extern void iseries_handle_interrupts(void);
get_paca()->hard_enabled = 0; \
} while(0)
static inline int irqs_disabled_flags(unsigned long flags)
{
return flags == 0;
}
#else
#if defined(CONFIG_BOOKE)

View file

@ -549,7 +549,7 @@ typedef struct comm_proc {
/* USB Controller.
*/
typedef struct usb_ctlr {
typedef struct cpm_usb_ctlr {
u8 usb_usmod;
u8 usb_usadr;
u8 usb_uscom;

View file

@ -210,7 +210,7 @@ struct sir {
} __attribute__ ((packed));
/* USB Controller */
struct usb_ctlr {
struct qe_usb_ctlr {
u8 usb_usmod;
u8 usb_usadr;
u8 usb_uscom;
@ -229,7 +229,7 @@ struct usb_ctlr {
} __attribute__ ((packed));
/* MCC */
struct mcc {
struct qe_mcc {
__be32 mcce; /* MCC event register */
__be32 mccm; /* MCC mask register */
__be32 mccf; /* MCC configuration register */
@ -431,9 +431,9 @@ struct qe_immap {
struct qe_mux qmx; /* QE Multiplexer */
struct qe_timers qet; /* QE Timers */
struct spi spi[0x2]; /* spi */
struct mcc mcc; /* mcc */
struct qe_mcc mcc; /* mcc */
struct qe_brg brg; /* brg */
struct usb_ctlr usb; /* USB */
struct qe_usb_ctlr usb; /* USB */
struct si1 si1; /* SI */
u8 res11[0x800];
struct sir sir; /* SI Routing Tables */

View file

@ -17,8 +17,6 @@
#include <asm/atomic.h>
#define get_irq_desc(irq) (&irq_desc[(irq)])
/* Define a way to iterate across irqs. */
#define for_each_irq(i) \
for ((i) = 0; (i) < NR_IRQS; ++(i))
@ -34,12 +32,15 @@ extern atomic_t ppc_n_lost_interrupts;
*/
#define NO_IRQ_IGNORE ((unsigned int)-1)
/* Total number of virq in the platform (make it a CONFIG_* option ? */
#define NR_IRQS 512
/* Total number of virq in the platform */
#define NR_IRQS CONFIG_NR_IRQS
/* Number of irqs reserved for the legacy controller */
#define NUM_ISA_INTERRUPTS 16
/* Same thing, used by the generic IRQ code */
#define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS
/* This type is the placeholder for a hardware interrupt number. It has to
* be big enough to enclose whatever representation is used by a given
* platform.
@ -99,7 +100,7 @@ struct irq_host_ops {
* interrupt controller has for that line)
*/
int (*xlate)(struct irq_host *h, struct device_node *ctrler,
u32 *intspec, unsigned int intsize,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type);
};
@ -313,7 +314,7 @@ extern void irq_free_virt(unsigned int virq, unsigned int count);
* of the of_irq_map_*() functions.
*/
extern unsigned int irq_create_of_mapping(struct device_node *controller,
u32 *intspec, unsigned int intsize);
const u32 *intspec, unsigned int intsize);
/**
* irq_of_parse_and_map - Parse and Map an interrupt into linux virq space

View file

@ -46,6 +46,24 @@ struct kvm_regs {
};
struct kvm_sregs {
__u32 pvr;
union {
struct {
__u64 sdr1;
struct {
struct {
__u64 slbe;
__u64 slbv;
} slb[64];
} ppc64;
struct {
__u32 sr[16];
__u64 ibat[8];
__u64 dbat[8];
} ppc32;
} s;
__u8 pad[1020];
} u;
};
struct kvm_fpu {

View file

@ -49,6 +49,46 @@
#define BOOKE_INTERRUPT_SPE_FP_ROUND 34
#define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35
/* book3s */
#define BOOK3S_INTERRUPT_SYSTEM_RESET 0x100
#define BOOK3S_INTERRUPT_MACHINE_CHECK 0x200
#define BOOK3S_INTERRUPT_DATA_STORAGE 0x300
#define BOOK3S_INTERRUPT_DATA_SEGMENT 0x380
#define BOOK3S_INTERRUPT_INST_STORAGE 0x400
#define BOOK3S_INTERRUPT_INST_SEGMENT 0x480
#define BOOK3S_INTERRUPT_EXTERNAL 0x500
#define BOOK3S_INTERRUPT_ALIGNMENT 0x600
#define BOOK3S_INTERRUPT_PROGRAM 0x700
#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800
#define BOOK3S_INTERRUPT_DECREMENTER 0x900
#define BOOK3S_INTERRUPT_SYSCALL 0xc00
#define BOOK3S_INTERRUPT_TRACE 0xd00
#define BOOK3S_INTERRUPT_PERFMON 0xf00
#define BOOK3S_INTERRUPT_ALTIVEC 0xf20
#define BOOK3S_INTERRUPT_VSX 0xf40
#define BOOK3S_IRQPRIO_SYSTEM_RESET 0
#define BOOK3S_IRQPRIO_DATA_SEGMENT 1
#define BOOK3S_IRQPRIO_INST_SEGMENT 2
#define BOOK3S_IRQPRIO_DATA_STORAGE 3
#define BOOK3S_IRQPRIO_INST_STORAGE 4
#define BOOK3S_IRQPRIO_ALIGNMENT 5
#define BOOK3S_IRQPRIO_PROGRAM 6
#define BOOK3S_IRQPRIO_FP_UNAVAIL 7
#define BOOK3S_IRQPRIO_ALTIVEC 8
#define BOOK3S_IRQPRIO_VSX 9
#define BOOK3S_IRQPRIO_SYSCALL 10
#define BOOK3S_IRQPRIO_MACHINE_CHECK 11
#define BOOK3S_IRQPRIO_DEBUG 12
#define BOOK3S_IRQPRIO_EXTERNAL 13
#define BOOK3S_IRQPRIO_DECREMENTER 14
#define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15
#define BOOK3S_IRQPRIO_MAX 16
#define BOOK3S_HFLAG_DCBZ32 0x1
#define BOOK3S_HFLAG_SLB 0x2
#define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */
#define RESUME_FLAG_HOST (1<<1) /* Resume host? */

View file

@ -0,0 +1,139 @@
/*
* 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 2009
*
* Authors: Alexander Graf <agraf@suse.de>
*/
#ifndef __ASM_KVM_BOOK3S_H__
#define __ASM_KVM_BOOK3S_H__
#include <linux/types.h>
#include <linux/kvm_host.h>
#include <asm/kvm_ppc.h>
struct kvmppc_slb {
u64 esid;
u64 vsid;
u64 orige;
u64 origv;
bool valid;
bool Ks;
bool Kp;
bool nx;
bool large;
bool class;
};
struct kvmppc_sr {
u32 raw;
u32 vsid;
bool Ks;
bool Kp;
bool nx;
};
struct kvmppc_bat {
u64 raw;
u32 bepi;
u32 bepi_mask;
bool vs;
bool vp;
u32 brpn;
u8 wimg;
u8 pp;
};
struct kvmppc_sid_map {
u64 guest_vsid;
u64 guest_esid;
u64 host_vsid;
bool valid;
};
#define SID_MAP_BITS 9
#define SID_MAP_NUM (1 << SID_MAP_BITS)
#define SID_MAP_MASK (SID_MAP_NUM - 1)
struct kvmppc_vcpu_book3s {
struct kvm_vcpu vcpu;
struct kvmppc_sid_map sid_map[SID_MAP_NUM];
struct kvmppc_slb slb[64];
struct {
u64 esid;
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];
int slb_nr;
u64 sdr1;
u64 dsisr;
u64 hior;
u64 msr_mask;
u64 vsid_first;
u64 vsid_next;
u64 vsid_max;
int context_id;
};
#define CONTEXT_HOST 0
#define CONTEXT_GUEST 1
#define CONTEXT_GUEST_END 2
#define VSID_REAL 0xfffffffffff00000
#define VSID_REAL_DR 0xffffffffffe00000
#define VSID_REAL_IR 0xffffffffffd00000
#define VSID_BAT 0xffffffffffc00000
#define VSID_PR 0x8000000000000000
extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 ea, u64 ea_mask);
extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask);
extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end);
extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr);
extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu);
extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu);
extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data);
extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, bool data);
extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr);
extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec);
extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
bool upper, u32 val);
extern u32 kvmppc_trampoline_lowmem;
extern u32 kvmppc_trampoline_enter;
static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
{
return container_of(vcpu, struct kvmppc_vcpu_book3s, vcpu);
}
static inline ulong dsisr(void)
{
ulong r;
asm ( "mfdsisr %0 " : "=r" (r) );
return r;
}
extern void kvm_return_point(void);
#define INS_DCBZ 0x7c0007ec
#endif /* __ASM_KVM_BOOK3S_H__ */

View file

@ -0,0 +1,58 @@
/*
* 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 2009
*
* Authors: Alexander Graf <agraf@suse.de>
*/
#ifndef __ASM_KVM_BOOK3S_ASM_H__
#define __ASM_KVM_BOOK3S_ASM_H__
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
#include <asm/kvm_asm.h>
.macro DO_KVM intno
.if (\intno == BOOK3S_INTERRUPT_SYSTEM_RESET) || \
(\intno == BOOK3S_INTERRUPT_MACHINE_CHECK) || \
(\intno == BOOK3S_INTERRUPT_DATA_STORAGE) || \
(\intno == BOOK3S_INTERRUPT_INST_STORAGE) || \
(\intno == BOOK3S_INTERRUPT_DATA_SEGMENT) || \
(\intno == BOOK3S_INTERRUPT_INST_SEGMENT) || \
(\intno == BOOK3S_INTERRUPT_EXTERNAL) || \
(\intno == BOOK3S_INTERRUPT_ALIGNMENT) || \
(\intno == BOOK3S_INTERRUPT_PROGRAM) || \
(\intno == BOOK3S_INTERRUPT_FP_UNAVAIL) || \
(\intno == BOOK3S_INTERRUPT_DECREMENTER) || \
(\intno == BOOK3S_INTERRUPT_SYSCALL) || \
(\intno == BOOK3S_INTERRUPT_TRACE) || \
(\intno == BOOK3S_INTERRUPT_PERFMON) || \
(\intno == BOOK3S_INTERRUPT_ALTIVEC) || \
(\intno == BOOK3S_INTERRUPT_VSX)
b kvmppc_trampoline_\intno
kvmppc_resume_\intno:
.endif
.endm
#else
.macro DO_KVM intno
.endm
#endif /* CONFIG_KVM_BOOK3S_64_HANDLER */
#endif /* __ASM_KVM_BOOK3S_ASM_H__ */

View file

@ -21,7 +21,8 @@
#define __POWERPC_KVM_HOST_H__
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/kvm_types.h>
#include <asm/kvm_asm.h>
@ -37,6 +38,8 @@
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
#define HPTEG_CACHE_NUM 1024
struct kvm;
struct kvm_run;
struct kvm_vcpu;
@ -63,6 +66,17 @@ struct kvm_vcpu_stat {
u32 dec_exits;
u32 ext_intr_exits;
u32 halt_wakeup;
#ifdef CONFIG_PPC64
u32 pf_storage;
u32 pf_instruc;
u32 sp_storage;
u32 sp_instruc;
u32 queue_intr;
u32 ld;
u32 ld_slow;
u32 st;
u32 st_slow;
#endif
};
enum kvm_exit_types {
@ -109,9 +123,53 @@ struct kvmppc_exit_timing {
struct kvm_arch {
};
struct kvmppc_pte {
u64 eaddr;
u64 vpage;
u64 raddr;
bool may_read;
bool may_write;
bool may_execute;
};
struct kvmppc_mmu {
/* book3s_64 only */
void (*slbmte)(struct kvm_vcpu *vcpu, u64 rb, u64 rs);
u64 (*slbmfee)(struct kvm_vcpu *vcpu, u64 slb_nr);
u64 (*slbmfev)(struct kvm_vcpu *vcpu, u64 slb_nr);
void (*slbie)(struct kvm_vcpu *vcpu, u64 slb_nr);
void (*slbia)(struct kvm_vcpu *vcpu);
/* book3s */
void (*mtsrin)(struct kvm_vcpu *vcpu, u32 srnum, ulong value);
u32 (*mfsrin)(struct kvm_vcpu *vcpu, u32 srnum);
int (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data);
void (*reset_msr)(struct kvm_vcpu *vcpu);
void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large);
int (*esid_to_vsid)(struct kvm_vcpu *vcpu, u64 esid, u64 *vsid);
u64 (*ea_to_vp)(struct kvm_vcpu *vcpu, gva_t eaddr, bool data);
bool (*is_dcbz32)(struct kvm_vcpu *vcpu);
};
struct hpte_cache {
u64 host_va;
u64 pfn;
ulong slot;
struct kvmppc_pte pte;
};
struct kvm_vcpu_arch {
u32 host_stack;
ulong host_stack;
u32 host_pid;
#ifdef CONFIG_PPC64
ulong host_msr;
ulong host_r2;
void *host_retip;
ulong trampoline_lowmem;
ulong trampoline_enter;
ulong highmem_handler;
ulong host_paca_phys;
struct kvmppc_mmu mmu;
#endif
u64 fpr[32];
ulong gpr[32];
@ -123,6 +181,10 @@ struct kvm_vcpu_arch {
ulong xer;
ulong msr;
#ifdef CONFIG_PPC64
ulong shadow_msr;
ulong hflags;
#endif
u32 mmucr;
ulong sprg0;
ulong sprg1;
@ -149,6 +211,7 @@ struct kvm_vcpu_arch {
u32 ivor[64];
ulong ivpr;
u32 pir;
u32 pvr;
u32 shadow_pid;
u32 pid;
@ -174,6 +237,9 @@ struct kvm_vcpu_arch {
#endif
u32 last_inst;
#ifdef CONFIG_PPC64
ulong fault_dsisr;
#endif
ulong fault_dear;
ulong fault_esr;
gpa_t paddr_accessed;
@ -185,8 +251,15 @@ struct kvm_vcpu_arch {
u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
struct timer_list dec_timer;
struct hrtimer dec_timer;
struct tasklet_struct tasklet;
u64 dec_jiffies;
unsigned long pending_exceptions;
#ifdef CONFIG_PPC64
struct hpte_cache hpte_cache[HPTEG_CACHE_NUM];
int hpte_cache_offset;
#endif
};
#endif /* __POWERPC_KVM_HOST_H__ */

View file

@ -39,6 +39,7 @@ enum emulation_result {
extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
extern char kvmppc_handlers_start[];
extern unsigned long kvmppc_handler_len;
extern void kvmppc_handler_highmem(void);
extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,

View file

@ -100,7 +100,14 @@ struct lppaca {
// Used to pass parms from the OS to PLIC for SetAsrAndRfid
u64 saved_gpr3; // Saved GPR3 x20-x27
u64 saved_gpr4; // Saved GPR4 x28-x2F
u64 saved_gpr5; // Saved GPR5 x30-x37
union {
u64 saved_gpr5; /* Saved GPR5 x30-x37 */
struct {
u8 cede_latency_hint; /* x30 */
u8 reserved[7]; /* x31-x36 */
} fields;
} gpr5_dword;
u8 dtl_enable_mask; // Dispatch Trace Log mask x38-x38
u8 donate_dedicated_cpu; // Donate dedicated CPU cycles x39-x39

View file

@ -266,6 +266,11 @@ struct machdep_calls {
void (*suspend_disable_irqs)(void);
void (*suspend_enable_irqs)(void);
#endif
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
ssize_t (*cpu_probe)(const char *, size_t);
ssize_t (*cpu_release)(const char *, size_t);
#endif
};
extern void e500_idle(void);

View file

@ -39,6 +39,7 @@ struct macio_dev
struct macio_bus *bus; /* macio bus this device is on */
struct macio_dev *media_bay; /* Device is part of a media bay */
struct of_device ofdev;
struct device_dma_parameters dma_parms; /* ide needs that */
int n_resources;
struct resource resource[MACIO_DEV_COUNT_RESOURCES];
int n_interrupts;
@ -78,6 +79,8 @@ static inline unsigned long macio_resource_len(struct macio_dev *dev, int resour
return res->end - res->start + 1;
}
extern int macio_enable_devres(struct macio_dev *dev);
extern int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name);
extern void macio_release_resource(struct macio_dev *dev, int resource_no);
extern int macio_request_resources(struct macio_dev *dev, const char *name);
@ -131,6 +134,9 @@ struct macio_driver
int (*resume)(struct macio_dev* dev);
int (*shutdown)(struct macio_dev* dev);
#ifdef CONFIG_PMAC_MEDIABAY
void (*mediabay_event)(struct macio_dev* dev, int mb_state);
#endif
struct device_driver driver;
};
#define to_macio_driver(drv) container_of(drv,struct macio_driver, driver)

View file

@ -17,26 +17,31 @@
#define MB_POWER 6 /* media bay contains a Power device (???) */
#define MB_NO 7 /* media bay contains nothing */
/* Number of bays in the machine or 0 */
extern int media_bay_count;
struct macio_dev;
#ifdef CONFIG_BLK_DEV_IDE_PMAC
#include <linux/ide.h>
#ifdef CONFIG_PMAC_MEDIABAY
int check_media_bay_by_base(unsigned long base, int what);
/* called by IDE PMAC host driver to register IDE controller for media bay */
int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base,
int irq, ide_hwif_t *hwif);
/* Check the content type of the bay, returns MB_NO if the bay is still
* transitionning
*/
extern int check_media_bay(struct macio_dev *bay);
int check_media_bay(struct device_node *which_bay, int what);
/* The ATA driver uses the calls below to temporarily hold on the
* media bay callbacks while initializing the interface
*/
extern void lock_media_bay(struct macio_dev *bay);
extern void unlock_media_bay(struct macio_dev *bay);
#else
static inline int check_media_bay(struct device_node *which_bay, int what)
static inline int check_media_bay(struct macio_dev *bay)
{
return -ENODEV;
return MB_NO;
}
static inline void lock_media_bay(struct macio_dev *bay) { }
static inline void unlock_media_bay(struct macio_dev *bay) { }
#endif
#endif /* __KERNEL__ */

View file

@ -173,14 +173,6 @@ extern unsigned long tce_alloc_start, tce_alloc_end;
*/
extern int mmu_ci_restrictions;
#ifdef CONFIG_HUGETLB_PAGE
/*
* The page size indexes of the huge pages for use by hugetlbfs
*/
extern unsigned int mmu_huge_psizes[MMU_PAGE_COUNT];
#endif /* CONFIG_HUGETLB_PAGE */
/*
* This function sets the AVPN and L fields of the HPTE appropriately
* for the page size
@ -253,10 +245,11 @@ extern int __hash_page_64K(unsigned long ea, unsigned long access,
unsigned long vsid, pte_t *ptep, unsigned long trap,
unsigned int local, int ssize);
struct mm_struct;
unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap);
extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap);
extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
unsigned long ea, unsigned long vsid, int local,
unsigned long trap);
int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
pte_t *ptep, unsigned long trap, int local, int ssize,
unsigned int shift, unsigned int mmu_psize);
extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
unsigned long pstart, unsigned long prot,
@ -380,6 +373,38 @@ extern void slb_set_size(u16 size);
#ifndef __ASSEMBLY__
#ifdef CONFIG_PPC_SUBPAGE_PROT
/*
* For the sub-page protection option, we extend the PGD with one of
* these. Basically we have a 3-level tree, with the top level being
* the protptrs array. To optimize speed and memory consumption when
* only addresses < 4GB are being protected, pointers to the first
* four pages of sub-page protection words are stored in the low_prot
* array.
* Each page of sub-page protection words protects 1GB (4 bytes
* protects 64k). For the 3-level tree, each page of pointers then
* protects 8TB.
*/
struct subpage_prot_table {
unsigned long maxaddr; /* only addresses < this are protected */
unsigned int **protptrs[2];
unsigned int *low_prot[4];
};
#define SBP_L1_BITS (PAGE_SHIFT - 2)
#define SBP_L2_BITS (PAGE_SHIFT - 3)
#define SBP_L1_COUNT (1 << SBP_L1_BITS)
#define SBP_L2_COUNT (1 << SBP_L2_BITS)
#define SBP_L2_SHIFT (PAGE_SHIFT + SBP_L1_BITS)
#define SBP_L3_SHIFT (SBP_L2_SHIFT + SBP_L2_BITS)
extern void subpage_prot_free(struct mm_struct *mm);
extern void subpage_prot_init_new_context(struct mm_struct *mm);
#else
static inline void subpage_prot_free(struct mm_struct *mm) {}
static inline void subpage_prot_init_new_context(struct mm_struct *mm) { }
#endif /* CONFIG_PPC_SUBPAGE_PROT */
typedef unsigned long mm_context_id_t;
typedef struct {
@ -393,6 +418,9 @@ typedef struct {
u16 sllp; /* SLB page size encoding */
#endif
unsigned long vdso_base;
#ifdef CONFIG_PPC_SUBPAGE_PROT
struct subpage_prot_table spt;
#endif /* CONFIG_PPC_SUBPAGE_PROT */
} mm_context_t;

View file

@ -23,6 +23,8 @@ extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm);
extern void set_context(unsigned long id, pgd_t *pgd);
#ifdef CONFIG_PPC_BOOK3S_64
extern int __init_new_context(void);
extern void __destroy_context(int context_id);
static inline void mmu_context_init(void) { }
#else
extern void mmu_context_init(void);

View file

@ -276,6 +276,53 @@ extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node);
extern void mpc52xx_restart(char *cmd);
/* mpc52xx_gpt.c */
struct mpc52xx_gpt_priv;
extern struct mpc52xx_gpt_priv *mpc52xx_gpt_from_irq(int irq);
extern int mpc52xx_gpt_start_timer(struct mpc52xx_gpt_priv *gpt, u64 period,
int continuous);
extern u64 mpc52xx_gpt_timer_period(struct mpc52xx_gpt_priv *gpt);
extern int mpc52xx_gpt_stop_timer(struct mpc52xx_gpt_priv *gpt);
/* mpc52xx_lpbfifo.c */
#define MPC52XX_LPBFIFO_FLAG_READ (0)
#define MPC52XX_LPBFIFO_FLAG_WRITE (1<<0)
#define MPC52XX_LPBFIFO_FLAG_NO_INCREMENT (1<<1)
#define MPC52XX_LPBFIFO_FLAG_NO_DMA (1<<2)
#define MPC52XX_LPBFIFO_FLAG_POLL_DMA (1<<3)
struct mpc52xx_lpbfifo_request {
struct list_head list;
/* localplus bus address */
unsigned int cs;
size_t offset;
/* Memory address */
void *data;
phys_addr_t data_phys;
/* Details of transfer */
size_t size;
size_t pos; /* current position of transfer */
int flags;
/* What to do when finished */
void (*callback)(struct mpc52xx_lpbfifo_request *);
void *priv; /* Driver private data */
/* statistics */
int irq_count;
int irq_ticks;
u8 last_byte;
int buffer_not_done_cnt;
};
extern int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req);
extern void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req);
extern void mpc52xx_lpbfifo_poll(void);
/* mpc52xx_pic.c */
extern void mpc52xx_init_irq(void);
extern unsigned int mpc52xx_get_irq(void);

View file

@ -73,7 +73,6 @@ extern int nvram_write_error_log(char * buff, int length,
extern int nvram_read_error_log(char * buff, int length,
unsigned int * err_type, unsigned int *err_seq);
extern int nvram_clear_error_log(void);
extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
extern int pSeries_nvram_init(void);

View file

@ -17,6 +17,7 @@
#ifdef CONFIG_PPC_PSERIES
extern int pSeries_reconfig_notifier_register(struct notifier_block *);
extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
extern struct blocking_notifier_head pSeries_reconfig_chain;
#else /* !CONFIG_PPC_PSERIES */
static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{

View file

@ -129,6 +129,15 @@ struct paca_struct {
u64 system_time; /* accumulated system TB ticks */
u64 startpurr; /* PURR/TB value snapshot */
u64 startspurr; /* SPURR value snapshot */
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
struct {
u64 esid;
u64 vsid;
} kvm_slb[64]; /* guest SLB */
u8 kvm_slb_max; /* highest used guest slb entry */
u8 kvm_in_guest; /* are we inside the guest? */
#endif
};
extern struct paca_struct paca[];

View file

@ -229,6 +229,20 @@ typedef unsigned long pgprot_t;
#endif
typedef struct { signed long pd; } hugepd_t;
#define HUGEPD_SHIFT_MASK 0x3f
#ifdef CONFIG_HUGETLB_PAGE
static inline int hugepd_ok(hugepd_t hpd)
{
return (hpd.pd > 0);
}
#define is_hugepd(pdep) (hugepd_ok(*((hugepd_t *)(pdep))))
#else /* CONFIG_HUGETLB_PAGE */
#define is_hugepd(pdep) 0
#endif /* CONFIG_HUGETLB_PAGE */
struct page;
extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
extern void copy_user_page(void *to, void *from, unsigned long vaddr,

View file

@ -90,7 +90,7 @@ extern unsigned int HPAGE_SHIFT;
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#define HUGE_MAX_HSTATE 3
#define HUGE_MAX_HSTATE (MMU_PAGE_COUNT-1)
#endif /* __ASSEMBLY__ */

View file

@ -3,7 +3,8 @@
#include <linux/threads.h>
#define PTE_NONCACHE_NUM 0 /* dummy for now to share code w/ppc64 */
/* For 32-bit, all levels of page tables are just drawn from get_free_page() */
#define MAX_PGTABLE_INDEX_SIZE 0
extern void __bad_pte(pmd_t *pmd);
@ -36,11 +37,10 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr);
static inline void pgtable_free(pgtable_free_t pgf)
static inline void pgtable_free(void *table, unsigned index_size)
{
void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
free_page((unsigned long)p);
BUG_ON(index_size); /* 32-bit doesn't use this */
free_page((unsigned long)table);
}
#define check_pgt_cache() do { } while (0)

View file

@ -11,27 +11,34 @@
#include <linux/cpumask.h>
#include <linux/percpu.h>
#ifndef CONFIG_PPC_SUBPAGE_PROT
static inline void subpage_prot_free(pgd_t *pgd) {}
#endif
/*
* Functions that deal with pagetables that could be at any level of
* the table need to be passed an "index_size" so they know how to
* handle allocation. For PTE pages (which are linked to a struct
* page for now, and drawn from the main get_free_pages() pool), the
* allocation size will be (2^index_size * sizeof(pointer)) and
* allocations are drawn from the kmem_cache in PGT_CACHE(index_size).
*
* The maximum index size needs to be big enough to allow any
* pagetable sizes we need, but small enough to fit in the low bits of
* any page table pointer. In other words all pagetables, even tiny
* ones, must be aligned to allow at least enough low 0 bits to
* contain this value. This value is also used as a mask, so it must
* be one less than a power of two.
*/
#define MAX_PGTABLE_INDEX_SIZE 0xf
extern struct kmem_cache *pgtable_cache[];
#define PGD_CACHE_NUM 0
#define PUD_CACHE_NUM 1
#define PMD_CACHE_NUM 1
#define HUGEPTE_CACHE_NUM 2
#define PTE_NONCACHE_NUM 7 /* from GFP rather than kmem_cache */
#define PGT_CACHE(shift) (pgtable_cache[(shift)-1])
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), GFP_KERNEL);
}
static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
subpage_prot_free(pgd);
kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
kmem_cache_free(PGT_CACHE(PGD_INDEX_SIZE), pgd);
}
#ifndef CONFIG_PPC_64K_PAGES
@ -40,13 +47,13 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],
return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE),
GFP_KERNEL|__GFP_REPEAT);
}
static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
kmem_cache_free(PGT_CACHE(PUD_INDEX_SIZE), pud);
}
static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
@ -78,13 +85,13 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],
return kmem_cache_alloc(PGT_CACHE(PMD_INDEX_SIZE),
GFP_KERNEL|__GFP_REPEAT);
}
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
kmem_cache_free(PGT_CACHE(PMD_INDEX_SIZE), pmd);
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
@ -107,24 +114,22 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
return page;
}
static inline void pgtable_free(pgtable_free_t pgf)
static inline void pgtable_free(void *table, unsigned index_size)
{
void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
int cachenum = pgf.val & PGF_CACHENUM_MASK;
if (cachenum == PTE_NONCACHE_NUM)
free_page((unsigned long)p);
else
kmem_cache_free(pgtable_cache[cachenum], p);
if (!index_size)
free_page((unsigned long)table);
else {
BUG_ON(index_size > MAX_PGTABLE_INDEX_SIZE);
kmem_cache_free(PGT_CACHE(index_size), table);
}
}
#define __pmd_free_tlb(tlb, pmd, addr) \
pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
pgtable_free_tlb(tlb, pmd, PMD_INDEX_SIZE)
#ifndef CONFIG_PPC_64K_PAGES
#define __pud_free_tlb(tlb, pud, addr) \
pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
pgtable_free_tlb(tlb, pud, PUD_INDEX_SIZE)
#endif /* CONFIG_PPC_64K_PAGES */
#define check_pgt_cache() do { } while (0)

View file

@ -24,25 +24,6 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
__free_page(ptepage);
}
typedef struct pgtable_free {
unsigned long val;
} pgtable_free_t;
/* This needs to be big enough to allow for MMU_PAGE_COUNT + 2 to be stored
* and small enough to fit in the low bits of any naturally aligned page
* table cache entry. Arbitrarily set to 0x1f, that should give us some
* room to grow
*/
#define PGF_CACHENUM_MASK 0x1f
static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
unsigned long mask)
{
BUG_ON(cachenum > PGF_CACHENUM_MASK);
return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
}
#ifdef CONFIG_PPC64
#include <asm/pgalloc-64.h>
#else
@ -50,12 +31,12 @@ static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
#endif
#ifdef CONFIG_SMP
extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift);
extern void pte_free_finish(void);
#else /* CONFIG_SMP */
static inline void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
{
pgtable_free(pgf);
pgtable_free(table, shift);
}
static inline void pte_free_finish(void) { }
#endif /* !CONFIG_SMP */
@ -63,12 +44,9 @@ static inline void pte_free_finish(void) { }
static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
unsigned long address)
{
pgtable_free_t pgf = pgtable_free_cache(page_address(ptepage),
PTE_NONCACHE_NUM,
PTE_TABLE_SIZE-1);
tlb_flush_pgtable(tlb, address);
pgtable_page_dtor(ptepage);
pgtable_free_tlb(tlb, pgf);
pgtable_free_tlb(tlb, page_address(ptepage), 0);
}
#endif /* __KERNEL__ */

View file

@ -354,6 +354,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
#define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT)
void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
void pgtable_cache_init(void);
/*
@ -378,7 +379,18 @@ void pgtable_cache_init(void);
return pt;
}
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address);
#ifdef CONFIG_HUGETLB_PAGE
pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
unsigned *shift);
#else
static inline pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
unsigned *shift)
{
if (shift)
*shift = 0;
return find_linux_pte(pgdir, ea);
}
#endif /* !CONFIG_HUGETLB_PAGE */
#endif /* __ASSEMBLY__ */

View file

@ -211,6 +211,9 @@ extern void paging_init(void);
*/
extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
extern int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr);
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */

View file

@ -33,21 +33,21 @@
#define _PAGE_NO_CACHE 0x0002 /* I: cache inhibit */
#define _PAGE_SHARED 0x0004 /* No ASID (context) compare */
#define _PAGE_SPECIAL 0x0008 /* SW entry, forced to 0 by the TLB miss */
#define _PAGE_DIRTY 0x0100 /* C: page changed */
/* These five software bits must be masked out when the entry is loaded
* into the TLB.
/* These 4 software bits must be masked out when the entry is loaded
* into the TLB, 1 SW bit left(0x0080).
*/
#define _PAGE_GUARDED 0x0010 /* software: guarded access */
#define _PAGE_DIRTY 0x0020 /* software: page changed */
#define _PAGE_RW 0x0040 /* software: user write access allowed */
#define _PAGE_ACCESSED 0x0080 /* software: page referenced */
#define _PAGE_ACCESSED 0x0020 /* software: page referenced */
#define _PAGE_WRITETHRU 0x0040 /* software: caching is write through */
/* Setting any bits in the nibble with the follow two controls will
* require a TLB exception handler change. It is assumed unused bits
* are always zero.
*/
#define _PAGE_HWWRITE 0x0100 /* h/w write enable: never set in Linux PTE */
#define _PAGE_USER 0x0800 /* One of the PP bits, the other is USER&~RW */
#define _PAGE_RW 0x0400 /* lsb PP bits, inverted in HW */
#define _PAGE_USER 0x0800 /* msb PP bits */
#define _PMD_PRESENT 0x0001
#define _PMD_BAD 0x0ff0

View file

@ -76,41 +76,4 @@
remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
#ifdef CONFIG_PPC_SUBPAGE_PROT
/*
* For the sub-page protection option, we extend the PGD with one of
* these. Basically we have a 3-level tree, with the top level being
* the protptrs array. To optimize speed and memory consumption when
* only addresses < 4GB are being protected, pointers to the first
* four pages of sub-page protection words are stored in the low_prot
* array.
* Each page of sub-page protection words protects 1GB (4 bytes
* protects 64k). For the 3-level tree, each page of pointers then
* protects 8TB.
*/
struct subpage_prot_table {
unsigned long maxaddr; /* only addresses < this are protected */
unsigned int **protptrs[2];
unsigned int *low_prot[4];
};
#undef PGD_TABLE_SIZE
#define PGD_TABLE_SIZE ((sizeof(pgd_t) << PGD_INDEX_SIZE) + \
sizeof(struct subpage_prot_table))
#define SBP_L1_BITS (PAGE_SHIFT - 2)
#define SBP_L2_BITS (PAGE_SHIFT - 3)
#define SBP_L1_COUNT (1 << SBP_L1_BITS)
#define SBP_L2_COUNT (1 << SBP_L2_BITS)
#define SBP_L2_SHIFT (PAGE_SHIFT + SBP_L1_BITS)
#define SBP_L3_SHIFT (SBP_L2_SHIFT + SBP_L2_BITS)
extern void subpage_prot_free(pgd_t *pgd);
static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
{
return (struct subpage_prot_table *)(pgd + PTRS_PER_PGD);
}
#endif /* CONFIG_PPC_SUBPAGE_PROT */
#endif /* __ASSEMBLY__ */

View file

@ -87,7 +87,7 @@ extern spinlock_t cmxgcr_lock;
/* Export QE common operations */
#ifdef CONFIG_QUICC_ENGINE
extern void __init qe_reset(void);
extern void qe_reset(void);
#else
static inline void qe_reset(void) {}
#endif
@ -145,8 +145,17 @@ static inline void qe_pin_set_gpio(struct qe_pin *qe_pin) {}
static inline void qe_pin_set_dedicated(struct qe_pin *pin) {}
#endif /* CONFIG_QE_GPIO */
/* QE internal API */
#ifdef CONFIG_QUICC_ENGINE
int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input);
#else
static inline int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol,
u32 cmd_input)
{
return -ENOSYS;
}
#endif /* CONFIG_QUICC_ENGINE */
/* QE internal API */
enum qe_clock qe_clock_source(const char *source);
unsigned int qe_get_brg_clk(void);
int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier);
@ -154,7 +163,28 @@ int qe_get_snum(void);
void qe_put_snum(u8 snum);
unsigned int qe_get_num_of_risc(void);
unsigned int qe_get_num_of_snums(void);
int qe_alive_during_sleep(void);
static inline int qe_alive_during_sleep(void)
{
/*
* MPC8568E reference manual says:
*
* "...power down sequence waits for all I/O interfaces to become idle.
* In some applications this may happen eventually without actively
* shutting down interfaces, but most likely, software will have to
* take steps to shut down the eTSEC, QUICC Engine Block, and PCI
* interfaces before issuing the command (either the write to the core
* MSR[WE] as described above or writing to POWMGTCSR) to put the
* device into sleep state."
*
* MPC8569E reference manual has a similar paragraph.
*/
#ifdef CONFIG_PPC_85xx
return 0;
#else
return 1;
#endif
}
/* we actually use cpm_muram implementation, define this for convenience */
#define qe_muram_init cpm_muram_init
@ -210,8 +240,15 @@ struct qe_firmware_info {
u64 extended_modes; /* Extended modes */
};
#ifdef CONFIG_QUICC_ENGINE
/* Upload a firmware to the QE */
int qe_upload_firmware(const struct qe_firmware *firmware);
#else
static inline int qe_upload_firmware(const struct qe_firmware *firmware)
{
return -ENOSYS;
}
#endif /* CONFIG_QUICC_ENGINE */
/* Obtain information on the uploaded firmware */
struct qe_firmware_info *qe_get_firmware_info(void);

View file

@ -145,7 +145,7 @@ SYSCALL_SPU(setfsuid)
SYSCALL_SPU(setfsgid)
SYSCALL_SPU(llseek)
COMPAT_SYS_SPU(getdents)
SYSX_SPU(sys_select,ppc32_select,ppc_select)
SYSX_SPU(sys_select,ppc32_select,sys_select)
SYSCALL_SPU(flock)
SYSCALL_SPU(msync)
COMPAT_SYS_SPU(readv)

View file

@ -42,10 +42,11 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
obj-$(CONFIG_PPC_CLOCK) += clock.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
procfs-y := proc_powerpc.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o
obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y)
obj-$(CONFIG_PPC_RTAS_DAEMON) += rtasd.o
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o

View file

@ -190,6 +190,11 @@ int main(void)
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
DEFINE(PACA_KVM_IN_GUEST, offsetof(struct paca_struct, kvm_in_guest));
DEFINE(PACA_KVM_SLB, offsetof(struct paca_struct, kvm_slb));
DEFINE(PACA_KVM_SLB_MAX, offsetof(struct paca_struct, kvm_slb_max));
#endif
#endif /* CONFIG_PPC64 */
/* RTAS */
@ -398,14 +403,24 @@ int main(void)
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
/* book3s_64 */
#ifdef CONFIG_PPC64
DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip));
DEFINE(VCPU_HOST_R2, offsetof(struct kvm_vcpu, arch.host_r2));
DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr));
DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr));
DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem));
DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter));
DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler));
DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags));
#endif
#endif
#ifdef CONFIG_44x
DEFINE(PGD_T_LOG2, PGD_T_LOG2);
DEFINE(PTE_T_LOG2, PTE_T_LOG2);
#endif
#ifdef CONFIG_FSL_BOOKE
DEFINE(TLBCAM_SIZE, sizeof(struct tlbcam));
#endif
#ifdef CONFIG_KVM_EXIT_TIMING
DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu,

View file

@ -373,7 +373,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
hard_irq_disable();
for_each_irq(i) {
struct irq_desc *desc = irq_desc + i;
struct irq_desc *desc = irq_to_desc(i);
if (desc->status & IRQ_INPROGRESS)
desc->chip->eoi(i);

View file

@ -21,7 +21,6 @@
#include <asm/dma.h>
#include <asm/abs_addr.h>
int swiotlb __read_mostly;
unsigned int ppc_swiotlb_enable;
/*

View file

@ -41,6 +41,7 @@ __start_interrupts:
. = 0x200
_machine_check_pSeries:
HMT_MEDIUM
DO_KVM 0x200
mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
@ -48,6 +49,7 @@ _machine_check_pSeries:
.globl data_access_pSeries
data_access_pSeries:
HMT_MEDIUM
DO_KVM 0x300
mtspr SPRN_SPRG_SCRATCH0,r13
BEGIN_FTR_SECTION
mfspr r13,SPRN_SPRG_PACA
@ -77,6 +79,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
.globl data_access_slb_pSeries
data_access_slb_pSeries:
HMT_MEDIUM
DO_KVM 0x380
mtspr SPRN_SPRG_SCRATCH0,r13
mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
std r3,PACA_EXSLB+EX_R3(r13)
@ -115,6 +118,7 @@ data_access_slb_pSeries:
.globl instruction_access_slb_pSeries
instruction_access_slb_pSeries:
HMT_MEDIUM
DO_KVM 0x480
mtspr SPRN_SPRG_SCRATCH0,r13
mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
std r3,PACA_EXSLB+EX_R3(r13)
@ -154,6 +158,7 @@ instruction_access_slb_pSeries:
.globl system_call_pSeries
system_call_pSeries:
HMT_MEDIUM
DO_KVM 0xc00
BEGIN_FTR_SECTION
cmpdi r0,0x1ebe
beq- 1f
@ -187,14 +192,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
*/
performance_monitor_pSeries_1:
. = 0xf00
DO_KVM 0xf00
b performance_monitor_pSeries
altivec_unavailable_pSeries_1:
. = 0xf20
DO_KVM 0xf20
b altivec_unavailable_pSeries
vsx_unavailable_pSeries_1:
. = 0xf40
DO_KVM 0xf40
b vsx_unavailable_pSeries
#ifdef CONFIG_CBE_RAS

View file

@ -37,6 +37,7 @@
#include <asm/firmware.h>
#include <asm/page_64.h>
#include <asm/irqflags.h>
#include <asm/kvm_book3s_64_asm.h>
/* The physical memory is layed out such that the secondary processor
* spin code sits at 0x0000...0x00ff. On server, the vectors follow
@ -165,6 +166,12 @@ 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_64_rmhandlers.S"
#endif
_GLOBAL(generic_secondary_thread_init)
mr r24,r3

View file

@ -206,6 +206,8 @@ MachineCheck:
EXCEPTION_PROLOG
mfspr r4,SPRN_DAR
stw r4,_DAR(r11)
li r5,0x00f0
mtspr SPRN_DAR,r5 /* Tag DAR, to be used in DTLB Error */
mfspr r5,SPRN_DSISR
stw r5,_DSISR(r11)
addi r3,r1,STACK_FRAME_OVERHEAD
@ -222,6 +224,8 @@ DataAccess:
stw r10,_DSISR(r11)
mr r5,r10
mfspr r4,SPRN_DAR
li r10,0x00f0
mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */
EXC_XFER_EE_LITE(0x300, handle_page_fault)
/* Instruction access exception.
@ -244,6 +248,8 @@ Alignment:
EXCEPTION_PROLOG
mfspr r4,SPRN_DAR
stw r4,_DAR(r11)
li r5,0x00f0
mtspr SPRN_DAR,r5 /* Tag DAR, to be used in DTLB Error */
mfspr r5,SPRN_DSISR
stw r5,_DSISR(r11)
addi r3,r1,STACK_FRAME_OVERHEAD
@ -333,26 +339,20 @@ InstructionTLBMiss:
mfspr r11, SPRN_MD_TWC /* ....and get the pte address */
lwz r10, 0(r11) /* Get the pte */
#ifdef CONFIG_SWAP
/* do not set the _PAGE_ACCESSED bit of a non-present page */
andi. r11, r10, _PAGE_PRESENT
beq 4f
ori r10, r10, _PAGE_ACCESSED
mfspr r11, SPRN_MD_TWC /* get the pte address again */
stw r10, 0(r11)
4:
#else
ori r10, r10, _PAGE_ACCESSED
stw r10, 0(r11)
#endif
andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT
cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT
bne- cr0, 2f
/* Clear PP lsb, 0x400 */
rlwinm r10, r10, 0, 22, 20
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21, 22 and 28 must be clear.
* Software indicator bits 22 and 28 must be clear.
* Software indicator bits 24, 25, 26, and 27 must be
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
2: li r11, 0x00f0
li r11, 0x00f0
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
DO_8xx_CPU6(0x2d80, r3)
mtspr SPRN_MI_RPN, r10 /* Update TLB entry */
@ -365,6 +365,22 @@ InstructionTLBMiss:
lwz r3, 8(r0)
#endif
rfi
2:
mfspr r11, SPRN_SRR1
/* clear all error bits as TLB Miss
* sets a few unconditionally
*/
rlwinm r11, r11, 0, 0xffff
mtspr SPRN_SRR1, r11
mfspr r10, SPRN_M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
b InstructionAccess
. = 0x1200
DataStoreTLBMiss:
@ -406,29 +422,45 @@ DataStoreTLBMiss:
* above.
*/
rlwimi r11, r10, 0, 27, 27
/* Insert the WriteThru flag into the TWC from the Linux PTE.
* It is bit 25 in the Linux PTE and bit 30 in the TWC
*/
rlwimi r11, r10, 32-5, 30, 30
DO_8xx_CPU6(0x3b80, r3)
mtspr SPRN_MD_TWC, r11
#ifdef CONFIG_SWAP
/* do not set the _PAGE_ACCESSED bit of a non-present page */
andi. r11, r10, _PAGE_PRESENT
beq 4f
ori r10, r10, _PAGE_ACCESSED
4:
/* and update pte in table */
#else
ori r10, r10, _PAGE_ACCESSED
#endif
mfspr r11, SPRN_MD_TWC /* get the pte address again */
stw r10, 0(r11)
/* Both _PAGE_ACCESSED and _PAGE_PRESENT has to be set.
* We also need to know if the insn is a load/store, so:
* Clear _PAGE_PRESENT and load that which will
* trap into DTLB Error with store bit set accordinly.
*/
/* PRESENT=0x1, ACCESSED=0x20
* r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5));
* r10 = (r10 & ~PRESENT) | r11;
*/
rlwinm r11, r10, 32-5, _PAGE_PRESENT
and r11, r11, r10
rlwimi r10, r11, 0, _PAGE_PRESENT
/* Honour kernel RO, User NA */
/* 0x200 == Extended encoding, bit 22 */
/* r11 = (r10 & _PAGE_USER) >> 2 */
rlwinm r11, r10, 32-2, 0x200
or r10, r11, r10
/* r11 = (r10 & _PAGE_RW) >> 1 */
rlwinm r11, r10, 32-1, 0x200
or r10, r11, r10
/* invert RW and 0x200 bits */
xori r10, r10, _PAGE_RW | 0x200
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21, 22 and 28 must be clear.
* Software indicator bits 22 and 28 must be clear.
* Software indicator bits 24, 25, 26, and 27 must be
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
2: li r11, 0x00f0
mtspr SPRN_DAR,r11 /* Tag DAR */
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
DO_8xx_CPU6(0x3d80, r3)
mtspr SPRN_MD_RPN, r10 /* Update TLB entry */
@ -469,97 +501,10 @@ DataTLBError:
stw r10, 0(r0)
stw r11, 4(r0)
/* First, make sure this was a store operation.
*/
mfspr r10, SPRN_DSISR
andis. r11, r10, 0x0200 /* If set, indicates store op */
beq 2f
/* The EA of a data TLB miss is automatically stored in the MD_EPN
* register. The EA of a data TLB error is automatically stored in
* the DAR, but not the MD_EPN register. We must copy the 20 most
* significant bits of the EA from the DAR to MD_EPN before we
* start walking the page tables. We also need to copy the CASID
* value from the M_CASID register.
* Addendum: The EA of a data TLB error is _supposed_ to be stored
* in DAR, but it seems that this doesn't happen in some cases, such
* as when the error is due to a dcbi instruction to a page with a
* TLB that doesn't have the changed bit set. In such cases, there
* does not appear to be any way to recover the EA of the error
* since it is neither in DAR nor MD_EPN. As a workaround, the
* _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs
* are initialized in mapin_ram(). This will avoid the problem,
* assuming we only use the dcbi instruction on kernel addresses.
*/
mfspr r10, SPRN_DAR
rlwinm r11, r10, 0, 0, 19
ori r11, r11, MD_EVALID
mfspr r10, SPRN_M_CASID
rlwimi r11, r10, 0, 28, 31
DO_8xx_CPU6(0x3780, r3)
mtspr SPRN_MD_EPN, r11
mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */
/* If we are faulting a kernel address, we have to use the
* kernel page tables.
*/
andi. r11, r10, 0x0800
beq 3f
lis r11, swapper_pg_dir@h
ori r11, r11, swapper_pg_dir@l
rlwimi r10, r11, 0, 2, 19
3:
lwz r11, 0(r10) /* Get the level 1 entry */
rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
beq 2f /* If zero, bail */
/* We have a pte table, so fetch the pte from the table.
*/
ori r11, r11, 1 /* Set valid bit in physical L2 page */
DO_8xx_CPU6(0x3b80, r3)
mtspr SPRN_MD_TWC, r11 /* Load pte table base address */
mfspr r11, SPRN_MD_TWC /* ....and get the pte address */
lwz r10, 0(r11) /* Get the pte */
andi. r11, r10, _PAGE_RW /* Is it writeable? */
beq 2f /* Bail out if not */
/* Update 'changed', among others.
*/
#ifdef CONFIG_SWAP
ori r10, r10, _PAGE_DIRTY|_PAGE_HWWRITE
/* do not set the _PAGE_ACCESSED bit of a non-present page */
andi. r11, r10, _PAGE_PRESENT
beq 4f
ori r10, r10, _PAGE_ACCESSED
4:
#else
ori r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
#endif
mfspr r11, SPRN_MD_TWC /* Get pte address again */
stw r10, 0(r11) /* and update pte in table */
/* The Linux PTE won't go exactly into the MMU TLB.
* Software indicator bits 21, 22 and 28 must be clear.
* Software indicator bits 24, 25, 26, and 27 must be
* set. All other Linux PTE bits control the behavior
* of the MMU.
*/
li r11, 0x00f0
rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */
DO_8xx_CPU6(0x3d80, r3)
mtspr SPRN_MD_RPN, r10 /* Update TLB entry */
mfspr r10, SPRN_M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
lwz r11, 4(r0)
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0)
#endif
rfi
2:
cmpwi cr0, r10, 0x00f0
beq- FixupDAR /* must be a buggy dcbX, icbi insn. */
DARFixed:/* Return from dcbx instruction bug workaround, r10 holds value of DAR */
mfspr r10, SPRN_M_TW /* Restore registers */
lwz r11, 0(r0)
mtcr r11
@ -588,6 +533,140 @@ DataTLBError:
. = 0x2000
/* This is the procedure to calculate the data EA for buggy dcbx,dcbi instructions
* by decoding the registers used by the dcbx instruction and adding them.
* DAR is set to the calculated address and r10 also holds the EA on exit.
*/
/* define if you don't want to use self modifying code */
#define NO_SELF_MODIFYING_CODE
FixupDAR:/* Entry point for dcbx workaround. */
/* fetch instruction from memory. */
mfspr r10, SPRN_SRR0
DO_8xx_CPU6(0x3780, r3)
mtspr SPRN_MD_EPN, r10
mfspr r11, SPRN_M_TWB /* Get level 1 table entry address */
cmplwi cr0, r11, 0x0800
blt- 3f /* Branch if user space */
lis r11, (swapper_pg_dir-PAGE_OFFSET)@h
ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l
rlwimi r11, r10, 32-20, 0xffc /* r11 = r11&~0xffc|(r10>>20)&0xffc */
3: lwz r11, 0(r11) /* Get the level 1 entry */
DO_8xx_CPU6(0x3b80, r3)
mtspr SPRN_MD_TWC, r11 /* Load pte table base address */
mfspr r11, SPRN_MD_TWC /* ....and get the pte address */
lwz r11, 0(r11) /* Get the pte */
/* concat physical page address(r11) and page offset(r10) */
rlwimi r11, r10, 0, 20, 31
lwz r11,0(r11)
/* Check if it really is a dcbx instruction. */
/* dcbt and dcbtst does not generate DTLB Misses/Errors,
* no need to include them here */
srwi r10, r11, 26 /* check if major OP code is 31 */
cmpwi cr0, r10, 31
bne- 141f
rlwinm r10, r11, 0, 21, 30
cmpwi cr0, r10, 2028 /* Is dcbz? */
beq+ 142f
cmpwi cr0, r10, 940 /* Is dcbi? */
beq+ 142f
cmpwi cr0, r10, 108 /* Is dcbst? */
beq+ 144f /* Fix up store bit! */
cmpwi cr0, r10, 172 /* Is dcbf? */
beq+ 142f
cmpwi cr0, r10, 1964 /* Is icbi? */
beq+ 142f
141: mfspr r10, SPRN_DAR /* r10 must hold DAR at exit */
b DARFixed /* Nope, go back to normal TLB processing */
144: mfspr r10, SPRN_DSISR
rlwinm r10, r10,0,7,5 /* Clear store bit for buggy dcbst insn */
mtspr SPRN_DSISR, r10
142: /* continue, it was a dcbx, dcbi instruction. */
#ifdef CONFIG_8xx_CPU6
lwz r3, 8(r0) /* restore r3 from memory */
#endif
#ifndef NO_SELF_MODIFYING_CODE
andis. r10,r11,0x1f /* test if reg RA is r0 */
li r10,modified_instr@l
dcbtst r0,r10 /* touch for store */
rlwinm r11,r11,0,0,20 /* Zero lower 10 bits */
oris r11,r11,640 /* Transform instr. to a "add r10,RA,RB" */
ori r11,r11,532
stw r11,0(r10) /* store add/and instruction */
dcbf 0,r10 /* flush new instr. to memory. */
icbi 0,r10 /* invalidate instr. cache line */
lwz r11, 4(r0) /* restore r11 from memory */
mfspr r10, SPRN_M_TW /* restore r10 from M_TW */
isync /* Wait until new instr is loaded from memory */
modified_instr:
.space 4 /* this is where the add instr. is stored */
bne+ 143f
subf r10,r0,r10 /* r10=r10-r0, only if reg RA is r0 */
143: mtdar r10 /* store faulting EA in DAR */
b DARFixed /* Go back to normal TLB handling */
#else
mfctr r10
mtdar r10 /* save ctr reg in DAR */
rlwinm r10, r11, 24, 24, 28 /* offset into jump table for reg RB */
addi r10, r10, 150f@l /* add start of table */
mtctr r10 /* load ctr with jump address */
xor r10, r10, r10 /* sum starts at zero */
bctr /* jump into table */
150:
add r10, r10, r0 ;b 151f
add r10, r10, r1 ;b 151f
add r10, r10, r2 ;b 151f
add r10, r10, r3 ;b 151f
add r10, r10, r4 ;b 151f
add r10, r10, r5 ;b 151f
add r10, r10, r6 ;b 151f
add r10, r10, r7 ;b 151f
add r10, r10, r8 ;b 151f
add r10, r10, r9 ;b 151f
mtctr r11 ;b 154f /* r10 needs special handling */
mtctr r11 ;b 153f /* r11 needs special handling */
add r10, r10, r12 ;b 151f
add r10, r10, r13 ;b 151f
add r10, r10, r14 ;b 151f
add r10, r10, r15 ;b 151f
add r10, r10, r16 ;b 151f
add r10, r10, r17 ;b 151f
add r10, r10, r18 ;b 151f
add r10, r10, r19 ;b 151f
add r10, r10, r20 ;b 151f
add r10, r10, r21 ;b 151f
add r10, r10, r22 ;b 151f
add r10, r10, r23 ;b 151f
add r10, r10, r24 ;b 151f
add r10, r10, r25 ;b 151f
add r10, r10, r26 ;b 151f
add r10, r10, r27 ;b 151f
add r10, r10, r28 ;b 151f
add r10, r10, r29 ;b 151f
add r10, r10, r30 ;b 151f
add r10, r10, r31
151:
rlwinm. r11,r11,19,24,28 /* offset into jump table for reg RA */
beq 152f /* if reg RA is zero, don't add it */
addi r11, r11, 150b@l /* add start of table */
mtctr r11 /* load ctr with jump address */
rlwinm r11,r11,0,16,10 /* make sure we don't execute this more than once */
bctr /* jump into table */
152:
mfdar r11
mtctr r11 /* restore ctr reg from DAR */
mtdar r10 /* save fault EA to DAR */
b DARFixed /* Go back to normal TLB handling */
/* special handling for r10,r11 since these are modified already */
153: lwz r11, 4(r0) /* load r11 from memory */
b 155f
154: mfspr r11, SPRN_M_TW /* load r10 from M_TW */
155: add r10, r10, r11 /* add it */
mfctr r11 /* restore r11 */
b 151b
#endif
.globl giveup_fpu
giveup_fpu:
blr

View file

@ -943,28 +943,6 @@ _GLOBAL(__setup_e500mc_ivors)
sync
blr
/*
* extern void loadcam_entry(unsigned int index)
*
* Load TLBCAM[index] entry in to the L2 CAM MMU
*/
_GLOBAL(loadcam_entry)
lis r4,TLBCAM@ha
addi r4,r4,TLBCAM@l
mulli r5,r3,TLBCAM_SIZE
add r3,r5,r4
lwz r4,0(r3)
mtspr SPRN_MAS0,r4
lwz r4,4(r3)
mtspr SPRN_MAS1,r4
lwz r4,8(r3)
mtspr SPRN_MAS2,r4
lwz r4,12(r3)
mtspr SPRN_MAS3,r4
tlbwe
isync
blr
/*
* extern void giveup_altivec(struct task_struct *prev)
*

View file

@ -161,7 +161,7 @@ void _memcpy_fromio(void *dest, const volatile void __iomem *src,
dest++;
n--;
}
while(n > 4) {
while(n >= 4) {
*((u32 *)dest) = *((volatile u32 *)vsrc);
eieio();
vsrc += 4;
@ -190,7 +190,7 @@ void _memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
vdest++;
n--;
}
while(n > 4) {
while(n >= 4) {
*((volatile u32 *)vdest) = *((volatile u32 *)src);
src += 4;
vdest += 4;

View file

@ -87,7 +87,10 @@ extern int tau_interrupts(int);
#endif /* CONFIG_PPC32 */
#ifdef CONFIG_PPC64
#ifndef CONFIG_SPARSE_IRQ
EXPORT_SYMBOL(irq_desc);
#endif
int distribute_irqs = 1;
@ -189,33 +192,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "CPU%d ", j);
seq_putc(p, '\n');
}
if (i < NR_IRQS) {
desc = get_irq_desc(i);
spin_lock_irqsave(&desc->lock, flags);
action = desc->action;
if (!action || !action->handler)
goto skip;
seq_printf(p, "%3d: ", i);
#ifdef CONFIG_SMP
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#else
seq_printf(p, "%10u ", kstat_irqs(i));
#endif /* CONFIG_SMP */
if (desc->chip)
seq_printf(p, " %s ", desc->chip->typename);
else
seq_puts(p, " None ");
seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge ");
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name);
seq_putc(p, '\n');
skip:
spin_unlock_irqrestore(&desc->lock, flags);
} else if (i == NR_IRQS) {
} else if (i == nr_irqs) {
#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT)
if (tau_initialized){
seq_puts(p, "TAU: ");
@ -225,30 +202,68 @@ skip:
}
#endif /* CONFIG_PPC32 && CONFIG_TAU_INT*/
seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts);
return 0;
}
desc = irq_to_desc(i);
if (!desc)
return 0;
spin_lock_irqsave(&desc->lock, flags);
action = desc->action;
if (!action || !action->handler)
goto skip;
seq_printf(p, "%3d: ", i);
#ifdef CONFIG_SMP
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#else
seq_printf(p, "%10u ", kstat_irqs(i));
#endif /* CONFIG_SMP */
if (desc->chip)
seq_printf(p, " %s ", desc->chip->name);
else
seq_puts(p, " None ");
seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge ");
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name);
seq_putc(p, '\n');
skip:
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
void fixup_irqs(cpumask_t map)
{
struct irq_desc *desc;
unsigned int irq;
static int warned;
for_each_irq(irq) {
cpumask_t mask;
if (irq_desc[irq].status & IRQ_PER_CPU)
desc = irq_to_desc(irq);
if (desc && desc->status & IRQ_PER_CPU)
continue;
cpumask_and(&mask, irq_desc[irq].affinity, &map);
cpumask_and(&mask, desc->affinity, &map);
if (any_online_cpu(mask) == NR_CPUS) {
printk("Breaking affinity for irq %i\n", irq);
mask = map;
}
if (irq_desc[irq].chip->set_affinity)
irq_desc[irq].chip->set_affinity(irq, &mask);
else if (irq_desc[irq].action && !(warned++))
if (desc->chip->set_affinity)
desc->chip->set_affinity(irq, &mask);
else if (desc->action && !(warned++))
printk("Cannot set affinity for irq %i\n", irq);
}
@ -275,7 +290,7 @@ static inline void handle_one_irq(unsigned int irq)
return;
}
desc = irq_desc + irq;
desc = irq_to_desc(irq);
saved_sp_limit = current->thread.ksp_limit;
irqtp->task = curtp->task;
@ -541,7 +556,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
smp_wmb();
/* Clear norequest flags */
get_irq_desc(i)->status &= ~IRQ_NOREQUEST;
irq_to_desc(i)->status &= ~IRQ_NOREQUEST;
/* Legacy flags are left to default at this point,
* one can then use irq_create_mapping() to
@ -607,8 +622,16 @@ void irq_set_virq_count(unsigned int count)
static int irq_setup_virq(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
struct irq_desc *desc;
desc = irq_to_desc_alloc_node(virq, 0);
if (!desc) {
pr_debug("irq: -> allocating desc failed\n");
goto error;
}
/* Clear IRQ_NOREQUEST flag */
get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
desc->status &= ~IRQ_NOREQUEST;
/* map it */
smp_wmb();
@ -617,11 +640,14 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
if (host->ops->map(host, virq, hwirq)) {
pr_debug("irq: -> mapping failed, freeing\n");
irq_free_virt(virq, 1);
return -1;
goto error;
}
return 0;
error:
irq_free_virt(virq, 1);
return -1;
}
unsigned int irq_create_direct_mapping(struct irq_host *host)
@ -705,7 +731,7 @@ unsigned int irq_create_mapping(struct irq_host *host,
EXPORT_SYMBOL_GPL(irq_create_mapping);
unsigned int irq_create_of_mapping(struct device_node *controller,
u32 *intspec, unsigned int intsize)
const u32 *intspec, unsigned int intsize)
{
struct irq_host *host;
irq_hw_number_t hwirq;
@ -738,7 +764,7 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
/* Set type if specified and different than the current one */
if (type != IRQ_TYPE_NONE &&
type != (get_irq_desc(virq)->status & IRQF_TRIGGER_MASK))
type != (irq_to_desc(virq)->status & IRQF_TRIGGER_MASK))
set_irq_type(virq, type);
return virq;
}
@ -810,7 +836,7 @@ void irq_dispose_mapping(unsigned int virq)
irq_map[virq].hwirq = host->inval_irq;
/* Set some flags */
get_irq_desc(virq)->status |= IRQ_NOREQUEST;
irq_to_desc(virq)->status |= IRQ_NOREQUEST;
/* Free it */
irq_free_virt(virq, 1);
@ -1002,12 +1028,24 @@ void irq_free_virt(unsigned int virq, unsigned int count)
spin_unlock_irqrestore(&irq_big_lock, flags);
}
void irq_early_init(void)
int arch_early_irq_init(void)
{
unsigned int i;
struct irq_desc *desc;
int i;
for (i = 0; i < NR_IRQS; i++)
get_irq_desc(i)->status |= IRQ_NOREQUEST;
for (i = 0; i < NR_IRQS; i++) {
desc = irq_to_desc(i);
if (desc)
desc->status |= IRQ_NOREQUEST;
}
return 0;
}
int arch_init_chip_data(struct irq_desc *desc, int node)
{
desc->status |= IRQ_NOREQUEST;
return 0;
}
/* We need to create the radix trees late */
@ -1069,16 +1107,19 @@ static int virq_debug_show(struct seq_file *m, void *private)
seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq",
"chip name", "host name");
for (i = 1; i < NR_IRQS; i++) {
desc = get_irq_desc(i);
for (i = 1; i < nr_irqs; i++) {
desc = irq_to_desc(i);
if (!desc)
continue;
spin_lock_irqsave(&desc->lock, flags);
if (desc->action && desc->action->handler) {
seq_printf(m, "%5d ", i);
seq_printf(m, "0x%05lx ", virq_to_hw(i));
if (desc->chip && desc->chip->typename)
p = desc->chip->typename;
if (desc->chip && desc->chip->name)
p = desc->chip->name;
else
p = none;
seq_printf(m, "%-15s ", p);

View file

@ -781,9 +781,9 @@ static int __init lparcfg_init(void)
!firmware_has_feature(FW_FEATURE_ISERIES))
mode |= S_IWUSR;
ent = proc_create("ppc64/lparcfg", mode, NULL, &lparcfg_fops);
ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops);
if (!ent) {
printk(KERN_ERR "Failed to create ppc64/lparcfg\n");
printk(KERN_ERR "Failed to create powerpc/lparcfg\n");
return -EIO;
}

View file

@ -502,15 +502,7 @@ _GLOBAL(clear_pages)
li r0,PAGE_SIZE/L1_CACHE_BYTES
slw r0,r0,r4
mtctr r0
#ifdef CONFIG_8xx
li r4, 0
1: stw r4, 0(r3)
stw r4, 4(r3)
stw r4, 8(r3)
stw r4, 12(r3)
#else
1: dcbz 0,r3
#endif
addi r3,r3,L1_CACHE_BYTES
bdnz 1b
blr
@ -535,15 +527,6 @@ _GLOBAL(copy_page)
addi r3,r3,-4
addi r4,r4,-4
#ifdef CONFIG_8xx
/* don't use prefetch on 8xx */
li r0,4096/L1_CACHE_BYTES
mtctr r0
1: COPY_16_BYTES
bdnz 1b
blr
#else /* not 8xx, we can prefetch */
li r5,4
#if MAX_COPY_PREFETCH > 1
@ -584,7 +567,6 @@ _GLOBAL(copy_page)
li r0,MAX_COPY_PREFETCH
li r11,4
b 2b
#endif /* CONFIG_8xx */
/*
* void atomic_clear_mask(atomic_t mask, atomic_t *addr)

View file

@ -139,8 +139,8 @@ out:
}
static int dev_nvram_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
static long dev_nvram_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
#ifdef CONFIG_PPC_PMAC
@ -173,7 +173,7 @@ const struct file_operations nvram_fops = {
.llseek = dev_nvram_llseek,
.read = dev_nvram_read,
.write = dev_nvram_write,
.ioctl = dev_nvram_ioctl,
.unlocked_ioctl = dev_nvram_ioctl,
};
static struct miscdevice nvram_dev = {
@ -184,7 +184,7 @@ static struct miscdevice nvram_dev = {
#ifdef DEBUG_NVRAM
static void nvram_print_partitions(char * label)
static void __init nvram_print_partitions(char * label)
{
struct list_head * p;
struct nvram_partition * tmp_part;
@ -202,7 +202,7 @@ static void nvram_print_partitions(char * label)
#endif
static int nvram_write_header(struct nvram_partition * part)
static int __init nvram_write_header(struct nvram_partition * part)
{
loff_t tmp_index;
int rc;
@ -214,7 +214,7 @@ static int nvram_write_header(struct nvram_partition * part)
}
static unsigned char nvram_checksum(struct nvram_header *p)
static unsigned char __init nvram_checksum(struct nvram_header *p)
{
unsigned int c_sum, c_sum2;
unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
@ -228,32 +228,7 @@ static unsigned char nvram_checksum(struct nvram_header *p)
return c_sum;
}
/*
* Find an nvram partition, sig can be 0 for any
* partition or name can be NULL for any name, else
* tries to match both
*/
struct nvram_partition *nvram_find_partition(int sig, const char *name)
{
struct nvram_partition * part;
struct list_head * p;
list_for_each(p, &nvram_part->partition) {
part = list_entry(p, struct nvram_partition, partition);
if (sig && part->header.signature != sig)
continue;
if (name && 0 != strncmp(name, part->header.name, 12))
continue;
return part;
}
return NULL;
}
EXPORT_SYMBOL(nvram_find_partition);
static int nvram_remove_os_partition(void)
static int __init nvram_remove_os_partition(void)
{
struct list_head *i;
struct list_head *j;
@ -319,7 +294,7 @@ static int nvram_remove_os_partition(void)
* Will create a partition starting at the first free
* space found if space has enough room.
*/
static int nvram_create_os_partition(void)
static int __init nvram_create_os_partition(void)
{
struct nvram_partition *part;
struct nvram_partition *new_part;
@ -422,7 +397,7 @@ static int nvram_create_os_partition(void)
* 5.) If the max chunk cannot be allocated then try finding a chunk
* that will satisfy the minum needed (NVRAM_MIN_REQ).
*/
static int nvram_setup_partition(void)
static int __init nvram_setup_partition(void)
{
struct list_head * p;
struct nvram_partition * part;
@ -480,7 +455,7 @@ static int nvram_setup_partition(void)
}
static int nvram_scan_partitions(void)
static int __init nvram_scan_partitions(void)
{
loff_t cur_index = 0;
struct nvram_header phead;
@ -706,6 +681,9 @@ int nvram_clear_error_log(void)
int clear_word = ERR_FLAG_ALREADY_LOGGED;
int rc;
if (nvram_error_log_index == -1)
return -1;
tmp_index = nvram_error_log_index;
rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);

View file

@ -119,13 +119,6 @@ static void perf_callchain_kernel(struct pt_regs *regs,
}
#ifdef CONFIG_PPC64
#ifdef CONFIG_HUGETLB_PAGE
#define is_huge_psize(pagesize) (HPAGE_SHIFT && mmu_huge_psizes[pagesize])
#else
#define is_huge_psize(pagesize) 0
#endif
/*
* On 64-bit we don't want to invoke hash_page on user addresses from
* interrupt context, so if the access faults, we read the page tables
@ -135,7 +128,7 @@ static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
{
pgd_t *pgdir;
pte_t *ptep, pte;
int pagesize;
unsigned shift;
unsigned long addr = (unsigned long) ptr;
unsigned long offset;
unsigned long pfn;
@ -145,17 +138,14 @@ static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
if (!pgdir)
return -EFAULT;
pagesize = get_slice_psize(current->mm, addr);
ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
if (!shift)
shift = PAGE_SHIFT;
/* align address to page boundary */
offset = addr & ((1ul << mmu_psize_defs[pagesize].shift) - 1);
offset = addr & ((1UL << shift) - 1);
addr -= offset;
if (is_huge_psize(pagesize))
ptep = huge_pte_offset(current->mm, addr);
else
ptep = find_linux_pte(pgdir, addr);
if (ptep == NULL)
return -EFAULT;
pte = *ptep;

View file

@ -96,8 +96,6 @@ EXPORT_SYMBOL(copy_4K_page);
EXPORT_SYMBOL(isa_io_base);
EXPORT_SYMBOL(isa_mem_base);
EXPORT_SYMBOL(pci_dram_offset);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL(start_thread);
@ -162,7 +160,6 @@ EXPORT_SYMBOL(screen_info);
#ifdef CONFIG_PPC32
EXPORT_SYMBOL(timer_interrupt);
EXPORT_SYMBOL(irq_desc);
EXPORT_SYMBOL(tb_ticks_per_jiffy);
EXPORT_SYMBOL(cacheable_memcpy);
EXPORT_SYMBOL(cacheable_memzero);

View file

@ -28,55 +28,7 @@
#include <asm/uaccess.h>
#include <asm/prom.h>
static loff_t page_map_seek( struct file *file, loff_t off, int whence);
static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos);
static int page_map_mmap( struct file *file, struct vm_area_struct *vma );
static const struct file_operations page_map_fops = {
.llseek = page_map_seek,
.read = page_map_read,
.mmap = page_map_mmap
};
/*
* Create the ppc64 and ppc64/rtas directories early. This allows us to
* assume that they have been previously created in drivers.
*/
static int __init proc_ppc64_create(void)
{
struct proc_dir_entry *root;
root = proc_mkdir("ppc64", NULL);
if (!root)
return 1;
if (!of_find_node_by_path("/rtas"))
return 0;
if (!proc_mkdir("rtas", root))
return 1;
if (!proc_symlink("rtas", NULL, "ppc64/rtas"))
return 1;
return 0;
}
core_initcall(proc_ppc64_create);
static int __init proc_ppc64_init(void)
{
struct proc_dir_entry *pde;
pde = proc_create_data("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL,
&page_map_fops, vdso_data);
if (!pde)
return 1;
pde->size = PAGE_SIZE;
return 0;
}
__initcall(proc_ppc64_init);
#ifdef CONFIG_PPC64
static loff_t page_map_seek( struct file *file, loff_t off, int whence)
{
@ -120,3 +72,55 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
return 0;
}
static const struct file_operations page_map_fops = {
.llseek = page_map_seek,
.read = page_map_read,
.mmap = page_map_mmap
};
static int __init proc_ppc64_init(void)
{
struct proc_dir_entry *pde;
pde = proc_create_data("powerpc/systemcfg", S_IFREG|S_IRUGO, NULL,
&page_map_fops, vdso_data);
if (!pde)
return 1;
pde->size = PAGE_SIZE;
return 0;
}
__initcall(proc_ppc64_init);
#endif /* CONFIG_PPC64 */
/*
* Create the ppc64 and ppc64/rtas directories early. This allows us to
* assume that they have been previously created in drivers.
*/
static int __init proc_ppc64_create(void)
{
struct proc_dir_entry *root;
root = proc_mkdir("powerpc", NULL);
if (!root)
return 1;
#ifdef CONFIG_PPC64
if (!proc_symlink("ppc64", NULL, "powerpc"))
pr_err("Failed to create link /proc/ppc64 -> /proc/powerpc\n");
#endif
if (!of_find_node_by_path("/rtas"))
return 0;
if (!proc_mkdir("rtas", root))
return 1;
if (!proc_symlink("rtas", NULL, "powerpc/rtas"))
return 1;
return 0;
}
core_initcall(proc_ppc64_create);

View file

@ -6,7 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* /proc/ppc64/rtas/firmware_flash interface
* /proc/powerpc/rtas/firmware_flash interface
*
* This file implements a firmware_flash interface to pump a firmware
* image into the kernel. At reboot time rtas_restart() will see the
@ -740,7 +740,7 @@ static int __init rtas_flash_init(void)
return 1;
}
firmware_flash_pde = create_flash_pde("ppc64/rtas/"
firmware_flash_pde = create_flash_pde("powerpc/rtas/"
FIRMWARE_FLASH_NAME,
&rtas_flash_operations);
if (firmware_flash_pde == NULL) {
@ -754,7 +754,7 @@ static int __init rtas_flash_init(void)
if (rc != 0)
goto cleanup;
firmware_update_pde = create_flash_pde("ppc64/rtas/"
firmware_update_pde = create_flash_pde("powerpc/rtas/"
FIRMWARE_UPDATE_NAME,
&rtas_flash_operations);
if (firmware_update_pde == NULL) {
@ -768,7 +768,7 @@ static int __init rtas_flash_init(void)
if (rc != 0)
goto cleanup;
validate_pde = create_flash_pde("ppc64/rtas/" VALIDATE_FLASH_NAME,
validate_pde = create_flash_pde("powerpc/rtas/" VALIDATE_FLASH_NAME,
&validate_flash_operations);
if (validate_pde == NULL) {
rc = -ENOMEM;
@ -781,7 +781,7 @@ static int __init rtas_flash_init(void)
if (rc != 0)
goto cleanup;
manage_pde = create_flash_pde("ppc64/rtas/" MANAGE_FLASH_NAME,
manage_pde = create_flash_pde("powerpc/rtas/" MANAGE_FLASH_NAME,
&manage_flash_operations);
if (manage_pde == NULL) {
rc = -ENOMEM;

View file

@ -39,6 +39,7 @@ static unsigned long rtas_log_start;
static unsigned long rtas_log_size;
static int surveillance_timeout = -1;
static unsigned int rtas_error_log_max;
static unsigned int rtas_error_log_buffer_max;
@ -213,9 +214,11 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)
return;
}
#ifdef CONFIG_PPC64
/* Write error to NVRAM */
if (logging_enabled && !(err_type & ERR_FLAG_BOOT))
nvram_write_error_log(buf, len, err_type, error_log_cnt);
#endif /* CONFIG_PPC64 */
/*
* rtas errors can occur during boot, and we do want to capture
@ -264,7 +267,6 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)
}
static int rtas_log_open(struct inode * inode, struct file * file)
{
return 0;
@ -300,6 +302,7 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf,
return -ENOMEM;
spin_lock_irqsave(&rtasd_log_lock, s);
/* if it's 0, then we know we got the last one (the one in NVRAM) */
while (rtas_log_size == 0) {
if (file->f_flags & O_NONBLOCK) {
@ -313,7 +316,9 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf,
error = -ENODATA;
goto out;
}
#ifdef CONFIG_PPC64
nvram_clear_error_log();
#endif /* CONFIG_PPC64 */
spin_unlock_irqrestore(&rtasd_log_lock, s);
error = wait_event_interruptible(rtas_log_wait, rtas_log_size);
@ -427,27 +432,38 @@ static void rtas_event_scan(struct work_struct *w)
put_online_cpus();
}
static void start_event_scan(void)
#ifdef CONFIG_PPC64
static void retreive_nvram_error_log(void)
{
unsigned int err_type ;
int rc ;
printk(KERN_DEBUG "RTAS daemon started\n");
pr_debug("rtasd: will sleep for %d milliseconds\n",
(30000 / rtas_event_scan_rate));
/* See if we have any error stored in NVRAM */
memset(logdata, 0, rtas_error_log_max);
rc = nvram_read_error_log(logdata, rtas_error_log_max,
&err_type, &error_log_cnt);
/* We can use rtas_log_buf now */
logging_enabled = 1;
if (!rc) {
if (err_type != ERR_FLAG_ALREADY_LOGGED) {
pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0);
}
}
}
#else /* CONFIG_PPC64 */
static void retreive_nvram_error_log(void)
{
}
#endif /* CONFIG_PPC64 */
static void start_event_scan(void)
{
printk(KERN_DEBUG "RTAS daemon started\n");
pr_debug("rtasd: will sleep for %d milliseconds\n",
(30000 / rtas_event_scan_rate));
/* Retreive errors from nvram if any */
retreive_nvram_error_log();
schedule_delayed_work_on(first_cpu(cpu_online_map), &event_scan_work,
event_scan_delay);
@ -457,13 +473,13 @@ static int __init rtas_init(void)
{
struct proc_dir_entry *entry;
if (!machine_is(pseries))
if (!machine_is(pseries) && !machine_is(chrp))
return 0;
/* No RTAS */
event_scan = rtas_token("event-scan");
if (event_scan == RTAS_UNKNOWN_SERVICE) {
printk(KERN_DEBUG "rtasd: no event-scan on system\n");
printk(KERN_INFO "rtasd: No event-scan on system\n");
return -ENODEV;
}
@ -483,7 +499,7 @@ static int __init rtas_init(void)
return -ENOMEM;
}
entry = proc_create("ppc64/rtas/error_log", S_IRUSR, NULL,
entry = proc_create("powerpc/rtas/error_log", S_IRUSR, NULL,
&proc_rtas_log_operations);
if (!entry)
printk(KERN_ERR "Failed to create error_log proc entry\n");
@ -492,11 +508,16 @@ static int __init rtas_init(void)
return 0;
}
__initcall(rtas_init);
static int __init surveillance_setup(char *str)
{
int i;
/* We only do surveillance on pseries */
if (!machine_is(pseries))
return 0;
if (get_option(&str,&i)) {
if (i >= 0 && i <= 255)
surveillance_timeout = i;
@ -504,6 +525,7 @@ static int __init surveillance_setup(char *str)
return 1;
}
__setup("surveillance=", surveillance_setup);
static int __init rtasmsgs_setup(char *str)
{
@ -514,6 +536,4 @@ static int __init rtasmsgs_setup(char *str)
return 1;
}
__initcall(rtas_init);
__setup("surveillance=", surveillance_setup);
__setup("rtasmsgs=", rtasmsgs_setup);

View file

@ -356,11 +356,6 @@ void __init setup_system(void)
*/
initialize_cache_info();
/*
* Initialize irq remapping subsystem
*/
irq_early_init();
#ifdef CONFIG_PPC_RTAS
/*
* Initialize RTAS if available

View file

@ -218,6 +218,9 @@ void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
static void stop_this_cpu(void *dummy)
{
/* Remove this CPU */
set_cpu_online(smp_processor_id(), false);
local_irq_disable();
while (1)
;

View file

@ -461,6 +461,25 @@ static void unregister_cpu_online(unsigned int cpu)
cacheinfo_cpu_offline(cpu);
}
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
ssize_t arch_cpu_probe(const char *buf, size_t count)
{
if (ppc_md.cpu_probe)
return ppc_md.cpu_probe(buf, count);
return -EINVAL;
}
ssize_t arch_cpu_release(const char *buf, size_t count)
{
if (ppc_md.cpu_release)
return ppc_md.cpu_release(buf, count);
return -EINVAL;
}
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
#endif /* CONFIG_HOTPLUG_CPU */
static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,

View file

@ -269,6 +269,7 @@ void account_system_vtime(struct task_struct *tsk)
per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled;
local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(account_system_vtime);
/*
* Transfer the user and system times accumulated in the paca

View file

@ -198,28 +198,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
info.si_code = code;
info.si_addr = (void __user *) addr;
force_sig_info(signr, &info, current);
/*
* Init gets no signals that it doesn't have a handler for.
* That's all very well, but if it has caused a synchronous
* exception and we ignore the resulting signal, it will just
* generate the same exception over and over again and we get
* nowhere. Better to kill it and let the kernel panic.
*/
if (is_global_init(current)) {
__sighandler_t handler;
spin_lock_irq(&current->sighand->siglock);
handler = current->sighand->action[signr-1].sa.sa_handler;
spin_unlock_irq(&current->sighand->siglock);
if (handler == SIG_DFL) {
/* init has generated a synchronous exception
and it doesn't have a handler for the signal */
printk(KERN_CRIT "init has generated signal %d "
"but has no handler for it\n", signr);
do_exit(signr);
}
}
}
#ifdef CONFIG_PPC64

View file

@ -58,7 +58,7 @@ _GLOBAL(load_up_altivec)
* all 1's
*/
mfspr r4,SPRN_VRSAVE
cmpdi 0,r4,0
cmpwi 0,r4,0
bne+ 1f
li r4,-1
mtspr SPRN_VRSAVE,r4

View file

@ -21,6 +21,23 @@ config KVM
select PREEMPT_NOTIFIERS
select ANON_INODES
config KVM_BOOK3S_64_HANDLER
bool
config KVM_BOOK3S_64
tristate "KVM support for PowerPC book3s_64 processors"
depends on EXPERIMENTAL && PPC64
select KVM
select KVM_BOOK3S_64_HANDLER
---help---
Support running unmodified book3s_64 and book3s_32 guest kernels
in virtual machines on book3s_64 host processors.
This module provides access to the hardware capabilities through
a character device node named /dev/kvm.
If unsure, say N.
config KVM_440
bool "KVM support for PowerPC 440 processors"
depends on EXPERIMENTAL && 44x

View file

@ -12,26 +12,45 @@ CFLAGS_44x_tlb.o := -I.
CFLAGS_e500_tlb.o := -I.
CFLAGS_emulate.o := -I.
kvm-objs := $(common-objs-y) powerpc.o emulate.o
common-objs-y += powerpc.o emulate.o
obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o
obj-$(CONFIG_KVM) += kvm.o
obj-$(CONFIG_KVM_BOOK3S_64_HANDLER) += book3s_64_exports.o
AFLAGS_booke_interrupts.o := -I$(obj)
kvm-440-objs := \
$(common-objs-y) \
booke.o \
booke_emulate.o \
booke_interrupts.o \
44x.o \
44x_tlb.o \
44x_emulate.o
obj-$(CONFIG_KVM_440) += kvm-440.o
kvm-objs-$(CONFIG_KVM_440) := $(kvm-440-objs)
kvm-e500-objs := \
$(common-objs-y) \
booke.o \
booke_emulate.o \
booke_interrupts.o \
e500.o \
e500_tlb.o \
e500_emulate.o
obj-$(CONFIG_KVM_E500) += kvm-e500.o
kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs)
kvm-book3s_64-objs := \
$(common-objs-y) \
book3s.o \
book3s_64_emulate.o \
book3s_64_interrupts.o \
book3s_64_mmu_host.o \
book3s_64_mmu.o \
book3s_32_mmu.o
kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-objs)
kvm-objs := $(kvm-objs-m) $(kvm-objs-y)
obj-$(CONFIG_KVM_440) += kvm.o
obj-$(CONFIG_KVM_E500) += kvm.o
obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o

974
arch/powerpc/kvm/book3s.c Normal file
View file

@ -0,0 +1,974 @@
/*
* Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved.
*
* Authors:
* Alexander Graf <agraf@suse.de>
* Kevin Wolf <mail@kevin-wolf.de>
*
* Description:
* This file is derived from arch/powerpc/kvm/44x.c,
* by Hollis Blanchard <hollisb@us.ibm.com>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*/
#include <linux/kvm_host.h>
#include <linux/err.h>
#include <asm/reg.h>
#include <asm/cputable.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
#include <asm/mmu_context.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
/* #define EXIT_DEBUG */
/* #define EXIT_DEBUG_SIMPLE */
/* Without AGGRESSIVE_DEC we only fire off a DEC interrupt when DEC turns 0.
* When set, we retrigger a DEC interrupt after that if DEC <= 0.
* PPC32 Linux runs faster without AGGRESSIVE_DEC, PPC64 Linux requires it. */
/* #define AGGRESSIVE_DEC */
struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "exits", VCPU_STAT(sum_exits) },
{ "mmio", VCPU_STAT(mmio_exits) },
{ "sig", VCPU_STAT(signal_exits) },
{ "sysc", VCPU_STAT(syscall_exits) },
{ "inst_emu", VCPU_STAT(emulated_inst_exits) },
{ "dec", VCPU_STAT(dec_exits) },
{ "ext_intr", VCPU_STAT(ext_intr_exits) },
{ "queue_intr", VCPU_STAT(queue_intr) },
{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
{ "pf_storage", VCPU_STAT(pf_storage) },
{ "sp_storage", VCPU_STAT(sp_storage) },
{ "pf_instruc", VCPU_STAT(pf_instruc) },
{ "sp_instruc", VCPU_STAT(sp_instruc) },
{ "ld", VCPU_STAT(ld) },
{ "ld_slow", VCPU_STAT(ld_slow) },
{ "st", VCPU_STAT(st) },
{ "st_slow", VCPU_STAT(st_slow) },
{ NULL }
};
void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu)
{
}
void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu)
{
}
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
memcpy(get_paca()->kvm_slb, to_book3s(vcpu)->slb_shadow, sizeof(get_paca()->kvm_slb));
get_paca()->kvm_slb_max = to_book3s(vcpu)->slb_shadow_max;
}
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
{
memcpy(to_book3s(vcpu)->slb_shadow, get_paca()->kvm_slb, sizeof(get_paca()->kvm_slb));
to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max;
}
#if defined(AGGRESSIVE_DEC) || 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
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
{
ulong old_msr = vcpu->arch.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.shadow_msr = msr | MSR_USER32;
vcpu->arch.shadow_msr &= ( MSR_VEC | MSR_VSX | MSR_FP | MSR_FE0 |
MSR_USER64 | MSR_SE | MSR_BE | MSR_DE |
MSR_FE1);
if (msr & (MSR_WE|MSR_POW)) {
if (!vcpu->arch.pending_exceptions) {
kvm_vcpu_block(vcpu);
vcpu->stat.halt_wakeup++;
}
}
if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) ||
(vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) {
kvmppc_mmu_flush_segments(vcpu);
kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc);
}
}
void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
{
vcpu->arch.srr0 = vcpu->arch.pc;
vcpu->arch.srr1 = vcpu->arch.msr | flags;
vcpu->arch.pc = to_book3s(vcpu)->hior + vec;
vcpu->arch.mmu.reset_msr(vcpu);
}
void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
{
unsigned int prio;
vcpu->stat.queue_intr++;
switch (vec) {
case 0x100: prio = BOOK3S_IRQPRIO_SYSTEM_RESET; break;
case 0x200: prio = BOOK3S_IRQPRIO_MACHINE_CHECK; break;
case 0x300: prio = BOOK3S_IRQPRIO_DATA_STORAGE; break;
case 0x380: prio = BOOK3S_IRQPRIO_DATA_SEGMENT; break;
case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break;
case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break;
case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break;
case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break;
case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break;
case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break;
case 0x900: prio = BOOK3S_IRQPRIO_DECREMENTER; break;
case 0xc00: prio = BOOK3S_IRQPRIO_SYSCALL; break;
case 0xd00: prio = BOOK3S_IRQPRIO_DEBUG; break;
case 0xf20: prio = BOOK3S_IRQPRIO_ALTIVEC; break;
case 0xf40: prio = BOOK3S_IRQPRIO_VSX; break;
default: prio = BOOK3S_IRQPRIO_MAX; break;
}
set_bit(prio, &vcpu->arch.pending_exceptions);
#ifdef EXIT_DEBUG
printk(KERN_INFO "Queueing interrupt %x\n", vec);
#endif
}
void kvmppc_core_queue_program(struct kvm_vcpu *vcpu)
{
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_PROGRAM);
}
void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu)
{
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER);
}
int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu)
{
return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions);
}
void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq)
{
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
}
int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
{
int deliver = 1;
int vec = 0;
switch (priority) {
case BOOK3S_IRQPRIO_DECREMENTER:
deliver = vcpu->arch.msr & MSR_EE;
vec = BOOK3S_INTERRUPT_DECREMENTER;
break;
case BOOK3S_IRQPRIO_EXTERNAL:
deliver = vcpu->arch.msr & MSR_EE;
vec = BOOK3S_INTERRUPT_EXTERNAL;
break;
case BOOK3S_IRQPRIO_SYSTEM_RESET:
vec = BOOK3S_INTERRUPT_SYSTEM_RESET;
break;
case BOOK3S_IRQPRIO_MACHINE_CHECK:
vec = BOOK3S_INTERRUPT_MACHINE_CHECK;
break;
case BOOK3S_IRQPRIO_DATA_STORAGE:
vec = BOOK3S_INTERRUPT_DATA_STORAGE;
break;
case BOOK3S_IRQPRIO_INST_STORAGE:
vec = BOOK3S_INTERRUPT_INST_STORAGE;
break;
case BOOK3S_IRQPRIO_DATA_SEGMENT:
vec = BOOK3S_INTERRUPT_DATA_SEGMENT;
break;
case BOOK3S_IRQPRIO_INST_SEGMENT:
vec = BOOK3S_INTERRUPT_INST_SEGMENT;
break;
case BOOK3S_IRQPRIO_ALIGNMENT:
vec = BOOK3S_INTERRUPT_ALIGNMENT;
break;
case BOOK3S_IRQPRIO_PROGRAM:
vec = BOOK3S_INTERRUPT_PROGRAM;
break;
case BOOK3S_IRQPRIO_VSX:
vec = BOOK3S_INTERRUPT_VSX;
break;
case BOOK3S_IRQPRIO_ALTIVEC:
vec = BOOK3S_INTERRUPT_ALTIVEC;
break;
case BOOK3S_IRQPRIO_FP_UNAVAIL:
vec = BOOK3S_INTERRUPT_FP_UNAVAIL;
break;
case BOOK3S_IRQPRIO_SYSCALL:
vec = BOOK3S_INTERRUPT_SYSCALL;
break;
case BOOK3S_IRQPRIO_DEBUG:
vec = BOOK3S_INTERRUPT_TRACE;
break;
case BOOK3S_IRQPRIO_PERFORMANCE_MONITOR:
vec = BOOK3S_INTERRUPT_PERFMON;
break;
default:
deliver = 0;
printk(KERN_ERR "KVM: Unknown interrupt: 0x%x\n", priority);
break;
}
#if 0
printk(KERN_INFO "Deliver interrupt 0x%x? %x\n", vec, deliver);
#endif
if (deliver)
kvmppc_inject_interrupt(vcpu, vec, 0ULL);
return deliver;
}
void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
{
unsigned long *pending = &vcpu->arch.pending_exceptions;
unsigned int priority;
/* XXX be more clever here - no need to mftb() on every entry */
/* Issue DEC again if it's still active */
#ifdef AGGRESSIVE_DEC
if (vcpu->arch.msr & MSR_EE)
if (kvmppc_get_dec(vcpu) & 0x80000000)
kvmppc_core_queue_dec(vcpu);
#endif
#ifdef EXIT_DEBUG
if (vcpu->arch.pending_exceptions)
printk(KERN_EMERG "KVM: Check pending: %lx\n", vcpu->arch.pending_exceptions);
#endif
priority = __ffs(*pending);
while (priority <= (sizeof(unsigned int) * 8)) {
if (kvmppc_book3s_irqprio_deliver(vcpu, priority)) {
clear_bit(priority, &vcpu->arch.pending_exceptions);
break;
}
priority = find_next_bit(pending,
BITS_PER_BYTE * sizeof(*pending),
priority + 1);
}
}
void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
{
vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB;
vcpu->arch.pvr = pvr;
if ((pvr >= 0x330000) && (pvr < 0x70330000)) {
kvmppc_mmu_book3s_64_init(vcpu);
to_book3s(vcpu)->hior = 0xfff00000;
to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL;
} else {
kvmppc_mmu_book3s_32_init(vcpu);
to_book3s(vcpu)->hior = 0;
to_book3s(vcpu)->msr_mask = 0xffffffffULL;
}
/* If we are in hypervisor level on 970, we can tell the CPU to
* treat DCBZ as 32 bytes store */
vcpu->arch.hflags &= ~BOOK3S_HFLAG_DCBZ32;
if (vcpu->arch.mmu.is_dcbz32(vcpu) && (mfmsr() & MSR_HV) &&
!strcmp(cur_cpu_spec->platform, "ppc970"))
vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
}
/* 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.
*
* The Book3s_64 inventors also realized this case and implemented a special bit
* in the HID5 register, which is a hypervisor ressource. Thus we can't use it.
*
* My approach here is to patch the dcbz instruction on executing pages.
*/
static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
{
bool touched = false;
hva_t hpage;
u32 *page;
int i;
hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
if (kvm_is_error_hva(hpage))
return;
hpage |= pte->raddr & ~PAGE_MASK;
hpage &= ~0xFFFULL;
page = vmalloc(HW_PAGE_SIZE);
if (copy_from_user(page, (void __user *)hpage, HW_PAGE_SIZE))
goto out;
for (i=0; i < HW_PAGE_SIZE / 4; i++)
if ((page[i] & 0xff0007ff) == INS_DCBZ) {
page[i] &= 0xfffffff7; // reserved instruction, so we trap
touched = true;
}
if (touched)
copy_to_user((void __user *)hpage, page, HW_PAGE_SIZE);
out:
vfree(page);
}
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 r;
if (relocated) {
r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data);
} else {
pte->eaddr = eaddr;
pte->raddr = eaddr & 0xffffffff;
pte->vpage = eaddr >> 12;
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
case 0:
pte->vpage |= VSID_REAL;
case MSR_DR:
pte->vpage |= VSID_REAL_DR;
case MSR_IR:
pte->vpage |= VSID_REAL_IR;
}
pte->may_read = true;
pte->may_write = true;
pte->may_execute = true;
r = 0;
}
return r;
}
static hva_t kvmppc_bad_hva(void)
{
return PAGE_OFFSET;
}
static hva_t kvmppc_pte_to_hva(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte,
bool read)
{
hva_t hpage;
if (read && !pte->may_read)
goto err;
if (!read && !pte->may_write)
goto err;
hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
if (kvm_is_error_hva(hpage))
goto err;
return hpage | (pte->raddr & ~PAGE_MASK);
err:
return kvmppc_bad_hva();
}
int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr)
{
struct kvmppc_pte pte;
hva_t hva = eaddr;
vcpu->stat.st++;
if (kvmppc_xlate(vcpu, eaddr, false, &pte))
goto err;
hva = kvmppc_pte_to_hva(vcpu, &pte, false);
if (kvm_is_error_hva(hva))
goto err;
if (copy_to_user((void __user *)hva, ptr, size)) {
printk(KERN_INFO "kvmppc_st at 0x%lx failed\n", hva);
goto err;
}
return 0;
err:
return -ENOENT;
}
int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr,
bool data)
{
struct kvmppc_pte pte;
hva_t hva = eaddr;
vcpu->stat.ld++;
if (kvmppc_xlate(vcpu, eaddr, data, &pte))
goto err;
hva = kvmppc_pte_to_hva(vcpu, &pte, true);
if (kvm_is_error_hva(hva))
goto err;
if (copy_from_user(ptr, (void __user *)hva, size)) {
printk(KERN_INFO "kvmppc_ld at 0x%lx failed\n", hva);
goto err;
}
return 0;
err:
return -ENOENT;
}
static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)
{
return kvm_is_visible_gfn(vcpu->kvm, gfn);
}
int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
ulong eaddr, int vec)
{
bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE);
int r = RESUME_GUEST;
int relocated;
int page_found = 0;
struct kvmppc_pte pte;
bool is_mmio = false;
if ( vec == BOOK3S_INTERRUPT_DATA_STORAGE ) {
relocated = (vcpu->arch.msr & MSR_DR);
} else {
relocated = (vcpu->arch.msr & MSR_IR);
}
/* Resolve real address if translation turned on */
if (relocated) {
page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data);
} else {
pte.may_execute = true;
pte.may_read = true;
pte.may_write = true;
pte.raddr = eaddr & 0xffffffff;
pte.eaddr = eaddr;
pte.vpage = eaddr >> 12;
switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
case 0:
pte.vpage |= VSID_REAL;
case MSR_DR:
pte.vpage |= VSID_REAL_DR;
case MSR_IR:
pte.vpage |= VSID_REAL_IR;
}
}
if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
(!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) {
/*
* If we do the dcbz hack, we have to NX on every execution,
* so we can patch the executing code. This renders our guest
* NX-less.
*/
pte.may_execute = !data;
}
if (page_found == -ENOENT) {
/* Page not found in guest PTE entries */
vcpu->arch.dear = vcpu->arch.fault_dear;
to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr;
vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x00000000f8000000ULL);
kvmppc_book3s_queue_irqprio(vcpu, vec);
} else if (page_found == -EPERM) {
/* Storage protection */
vcpu->arch.dear = vcpu->arch.fault_dear;
to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE;
to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT;
vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x00000000f8000000ULL);
kvmppc_book3s_queue_irqprio(vcpu, vec);
} else if (page_found == -EINVAL) {
/* Page not found in guest SLB */
vcpu->arch.dear = vcpu->arch.fault_dear;
kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
} else if (!is_mmio &&
kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
/* The guest's PTE is not mapped yet. Map on the host */
kvmppc_mmu_map_page(vcpu, &pte);
if (data)
vcpu->stat.sp_storage++;
else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
(!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32)))
kvmppc_patch_dcbz(vcpu, &pte);
} else {
/* MMIO */
vcpu->stat.mmio_exits++;
vcpu->arch.paddr_accessed = pte.raddr;
r = kvmppc_emulate_mmio(run, vcpu);
if ( r == RESUME_HOST_NV )
r = RESUME_HOST;
if ( r == RESUME_GUEST_NV )
r = RESUME_GUEST;
}
return r;
}
int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int exit_nr)
{
int r = RESUME_HOST;
vcpu->stat.sum_exits++;
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, vcpu->arch.pc, vcpu->arch.fault_dear,
kvmppc_get_dec(vcpu), vcpu->arch.msr);
#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, vcpu->arch.pc, vcpu->arch.fault_dear,
vcpu->arch.msr);
#endif
kvm_resched(vcpu);
switch (exit_nr) {
case BOOK3S_INTERRUPT_INST_STORAGE:
vcpu->stat.pf_instruc++;
/* only care about PTEG not found errors, but leave NX alone */
if (vcpu->arch.shadow_msr & 0x40000000) {
r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.pc, exit_nr);
vcpu->stat.sp_instruc++;
} else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
(!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) {
/*
* XXX If we do the dcbz hack we use the NX bit to flush&patch the page,
* so we can't use the NX bit inside the guest. Let's cross our fingers,
* that no guest that needs the dcbz hack does NX.
*/
kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL);
} else {
vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x58000000);
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL);
r = RESUME_GUEST;
}
break;
case BOOK3S_INTERRUPT_DATA_STORAGE:
vcpu->stat.pf_storage++;
/* The only case we need to handle is missing shadow PTEs */
if (vcpu->arch.fault_dsisr & DSISR_NOHPTE) {
r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.fault_dear, exit_nr);
} else {
vcpu->arch.dear = vcpu->arch.fault_dear;
to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr;
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFULL);
r = RESUME_GUEST;
}
break;
case BOOK3S_INTERRUPT_DATA_SEGMENT:
if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.fault_dear) < 0) {
vcpu->arch.dear = vcpu->arch.fault_dear;
kvmppc_book3s_queue_irqprio(vcpu,
BOOK3S_INTERRUPT_DATA_SEGMENT);
}
r = RESUME_GUEST;
break;
case BOOK3S_INTERRUPT_INST_SEGMENT:
if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc) < 0) {
kvmppc_book3s_queue_irqprio(vcpu,
BOOK3S_INTERRUPT_INST_SEGMENT);
}
r = RESUME_GUEST;
break;
/* We're good on these - the host merely wanted to get our attention */
case BOOK3S_INTERRUPT_DECREMENTER:
vcpu->stat.dec_exits++;
r = RESUME_GUEST;
break;
case BOOK3S_INTERRUPT_EXTERNAL:
vcpu->stat.ext_intr_exits++;
r = RESUME_GUEST;
break;
case BOOK3S_INTERRUPT_PROGRAM:
{
enum emulation_result er;
if (vcpu->arch.msr & MSR_PR) {
#ifdef EXIT_DEBUG
printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", vcpu->arch.pc, vcpu->arch.last_inst);
#endif
if ((vcpu->arch.last_inst & 0xff0007ff) !=
(INS_DCBZ & 0xfffffff7)) {
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
r = RESUME_GUEST;
break;
}
}
vcpu->stat.emulated_inst_exits++;
er = kvmppc_emulate_instruction(run, vcpu);
switch (er) {
case EMULATE_DONE:
r = RESUME_GUEST;
break;
case EMULATE_FAIL:
printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
__func__, vcpu->arch.pc, vcpu->arch.last_inst);
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
r = RESUME_GUEST;
break;
default:
BUG();
}
break;
}
case BOOK3S_INTERRUPT_SYSCALL:
#ifdef EXIT_DEBUG
printk(KERN_INFO "Syscall Nr %d\n", (int)vcpu->arch.gpr[0]);
#endif
vcpu->stat.syscall_exits++;
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
r = RESUME_GUEST;
break;
case BOOK3S_INTERRUPT_MACHINE_CHECK:
case BOOK3S_INTERRUPT_FP_UNAVAIL:
case BOOK3S_INTERRUPT_TRACE:
case BOOK3S_INTERRUPT_ALTIVEC:
case BOOK3S_INTERRUPT_VSX:
kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
r = RESUME_GUEST;
break;
default:
/* Ugh - bork here! What did we get? */
printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", exit_nr, vcpu->arch.pc, vcpu->arch.shadow_msr);
r = RESUME_HOST;
BUG();
break;
}
if (!(r & RESUME_HOST)) {
/* To avoid clobbering exit_reason, only check for signals if
* we aren't already exiting to userspace for some other
* reason. */
if (signal_pending(current)) {
#ifdef EXIT_DEBUG
printk(KERN_EMERG "KVM: Going back to host\n");
#endif
vcpu->stat.signal_exits++;
run->exit_reason = KVM_EXIT_INTR;
r = -EINTR;
} else {
/* In case an interrupt came in that was triggered
* from userspace (like DEC), we need to check what
* to inject now! */
kvmppc_core_deliver_interrupts(vcpu);
}
}
#ifdef EXIT_DEBUG
printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, vcpu->arch.pc, r);
#endif
return r;
}
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
return 0;
}
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
int i;
regs->pc = vcpu->arch.pc;
regs->cr = vcpu->arch.cr;
regs->ctr = vcpu->arch.ctr;
regs->lr = vcpu->arch.lr;
regs->xer = vcpu->arch.xer;
regs->msr = vcpu->arch.msr;
regs->srr0 = vcpu->arch.srr0;
regs->srr1 = vcpu->arch.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->sprg5 = vcpu->arch.sprg4;
regs->sprg6 = vcpu->arch.sprg5;
regs->sprg7 = vcpu->arch.sprg6;
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
regs->gpr[i] = vcpu->arch.gpr[i];
return 0;
}
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
int i;
vcpu->arch.pc = regs->pc;
vcpu->arch.cr = regs->cr;
vcpu->arch.ctr = regs->ctr;
vcpu->arch.lr = regs->lr;
vcpu->arch.xer = 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.sprg5 = regs->sprg4;
vcpu->arch.sprg6 = regs->sprg5;
vcpu->arch.sprg7 = regs->sprg6;
for (i = 0; i < ARRAY_SIZE(vcpu->arch.gpr); i++)
vcpu->arch.gpr[i] = regs->gpr[i];
return 0;
}
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int i;
sregs->pvr = vcpu->arch.pvr;
sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1;
if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) {
for (i = 0; i < 64; i++) {
sregs->u.s.ppc64.slb[i].slbe = vcpu3s->slb[i].orige | i;
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 < 8; i++) {
sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw;
sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw;
}
}
return 0;
}
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int i;
kvmppc_set_pvr(vcpu, sregs->pvr);
vcpu3s->sdr1 = sregs->u.s.sdr1;
if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) {
for (i = 0; i < 64; i++) {
vcpu->arch.mmu.slbmte(vcpu, sregs->u.s.ppc64.slb[i].slbv,
sregs->u.s.ppc64.slb[i].slbe);
}
} else {
for (i = 0; i < 16; i++) {
vcpu->arch.mmu.mtsrin(vcpu, i, sregs->u.s.ppc32.sr[i]);
}
for (i = 0; i < 8; i++) {
kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), false,
(u32)sregs->u.s.ppc32.ibat[i]);
kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), true,
(u32)(sregs->u.s.ppc32.ibat[i] >> 32));
kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), false,
(u32)sregs->u.s.ppc32.dbat[i]);
kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), true,
(u32)(sregs->u.s.ppc32.dbat[i] >> 32));
}
}
/* Flush the MMU after messing with the segments */
kvmppc_mmu_pte_flush(vcpu, 0, 0);
return 0;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
return -ENOTSUPP;
}
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
return -ENOTSUPP;
}
int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
struct kvm_translation *tr)
{
return 0;
}
/*
* Get (and clear) the dirty memory log for a memory slot.
*/
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_dirty_log *log)
{
struct kvm_memory_slot *memslot;
struct kvm_vcpu *vcpu;
ulong ga, ga_end;
int is_dirty = 0;
int r, n;
down_write(&kvm->slots_lock);
r = kvm_get_dirty_log(kvm, log, &is_dirty);
if (r)
goto out;
/* If nothing is dirty, don't bother messing with page tables. */
if (is_dirty) {
memslot = &kvm->memslots[log->slot];
ga = memslot->base_gfn << PAGE_SHIFT;
ga_end = ga + (memslot->npages << PAGE_SHIFT);
kvm_for_each_vcpu(n, vcpu, kvm)
kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
memset(memslot->dirty_bitmap, 0, n);
}
r = 0;
out:
up_write(&kvm->slots_lock);
return r;
}
int kvmppc_core_check_processor_compat(void)
{
return 0;
}
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;
vcpu_book3s = (struct kvmppc_vcpu_book3s *)__get_free_pages( GFP_KERNEL | __GFP_ZERO,
get_order(sizeof(struct kvmppc_vcpu_book3s)));
if (!vcpu_book3s) {
err = -ENOMEM;
goto out;
}
vcpu = &vcpu_book3s->vcpu;
err = kvm_vcpu_init(vcpu, kvm, id);
if (err)
goto free_vcpu;
vcpu->arch.host_retip = kvm_return_point;
vcpu->arch.host_msr = mfmsr();
/* default to book3s_64 (970fx) */
vcpu->arch.pvr = 0x3C0301;
kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
vcpu_book3s->slb_nr = 64;
/* remember where some real-mode handlers are */
vcpu->arch.trampoline_lowmem = kvmppc_trampoline_lowmem;
vcpu->arch.trampoline_enter = kvmppc_trampoline_enter;
vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem;
vcpu->arch.shadow_msr = MSR_USER64;
err = __init_new_context();
if (err < 0)
goto free_vcpu;
vcpu_book3s->context_id = err;
vcpu_book3s->vsid_max = ((vcpu_book3s->context_id + 1) << USER_ESID_BITS) - 1;
vcpu_book3s->vsid_first = vcpu_book3s->context_id << USER_ESID_BITS;
vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
return vcpu;
free_vcpu:
free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s)));
out:
return ERR_PTR(err);
}
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
__destroy_context(vcpu_book3s->context_id);
kvm_vcpu_uninit(vcpu);
free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s)));
}
extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
int ret;
/* No need to go into the guest when all we do is going out */
if (signal_pending(current)) {
kvm_run->exit_reason = KVM_EXIT_INTR;
return -EINTR;
}
/* XXX we get called with irq disabled - change that! */
local_irq_enable();
ret = __kvmppc_vcpu_entry(kvm_run, vcpu);
local_irq_disable();
return ret;
}
static int kvmppc_book3s_init(void)
{
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), THIS_MODULE);
}
static void kvmppc_book3s_exit(void)
{
kvm_exit();
}
module_init(kvmppc_book3s_init);
module_exit(kvmppc_book3s_exit);

View file

@ -0,0 +1,372 @@
/*
* 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 2009
*
* Authors: Alexander Graf <agraf@suse.de>
*/
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
#include <linux/highmem.h>
#include <asm/tlbflush.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
/* #define DEBUG_MMU */
/* #define DEBUG_MMU_PTE */
/* #define DEBUG_MMU_PTE_IP 0xfff14c40 */
#ifdef DEBUG_MMU
#define dprintk(X...) printk(KERN_INFO X)
#else
#define dprintk(X...) do { } while(0)
#endif
#ifdef DEBUG_PTE
#define dprintk_pte(X...) printk(KERN_INFO X)
#else
#define dprintk_pte(X...) do { } while(0)
#endif
#define PTEG_FLAG_ACCESSED 0x00000100
#define PTEG_FLAG_DIRTY 0x00000080
static inline bool check_debug_ip(struct kvm_vcpu *vcpu)
{
#ifdef DEBUG_MMU_PTE_IP
return vcpu->arch.pc == DEBUG_MMU_PTE_IP;
#else
return true;
#endif
}
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data);
static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr)
{
return &vcpu_book3s->sr[(eaddr >> 28) & 0xf];
}
static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
bool data)
{
struct kvmppc_sr *sre = find_sr(to_book3s(vcpu), eaddr);
struct kvmppc_pte pte;
if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data))
return pte.vpage;
return (((u64)eaddr >> 12) & 0xffff) | (((u64)sre->vsid) << 16);
}
static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu)
{
kvmppc_set_msr(vcpu, 0);
}
static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s,
struct kvmppc_sr *sre, gva_t eaddr,
bool primary)
{
u32 page, hash, pteg, htabmask;
hva_t r;
page = (eaddr & 0x0FFFFFFF) >> 12;
htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0;
hash = ((sre->vsid ^ page) << 6);
if (!primary)
hash = ~hash;
hash &= htabmask;
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);
r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT);
if (kvm_is_error_hva(r))
return r;
return r | (pteg & ~PAGE_MASK);
}
static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr,
bool primary)
{
return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) |
(primary ? 0 : 0x40) | 0x80000000;
}
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_bat *bat;
int i;
for (i = 0; i < 8; i++) {
if (data)
bat = &vcpu_book3s->dbat[i];
else
bat = &vcpu_book3s->ibat[i];
if (vcpu->arch.msr & MSR_PR) {
if (!bat->vp)
continue;
} else {
if (!bat->vs)
continue;
}
if (check_debug_ip(vcpu))
{
dprintk_pte("%cBAT %02d: 0x%lx - 0x%x (0x%x)\n",
data ? 'd' : 'i', i, eaddr, bat->bepi,
bat->bepi_mask);
}
if ((eaddr & bat->bepi_mask) == bat->bepi) {
pte->raddr = bat->brpn | (eaddr & ~bat->bepi_mask);
pte->vpage = (eaddr >> 12) | VSID_BAT;
pte->may_read = bat->pp;
pte->may_write = bat->pp > 1;
pte->may_execute = true;
if (!pte->may_read) {
printk(KERN_INFO "BAT is not readable!\n");
continue;
}
if (!pte->may_write) {
/* let's treat r/o BATs as not-readable for now */
dprintk_pte("BAT is read-only!\n");
continue;
}
return 0;
}
}
return -ENOENT;
}
static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data,
bool primary)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_sr *sre;
hva_t ptegp;
u32 pteg[16];
u64 ptem = 0;
int i;
int found = 0;
sre = find_sr(vcpu_book3s, eaddr);
dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28,
sre->vsid, sre->raw);
pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
ptegp = kvmppc_mmu_book3s_32_get_pteg(vcpu_book3s, sre, eaddr, primary);
if (kvm_is_error_hva(ptegp)) {
printk(KERN_INFO "KVM: Invalid PTEG!\n");
goto no_page_found;
}
ptem = kvmppc_mmu_book3s_32_get_ptem(sre, eaddr, primary);
if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) {
printk(KERN_ERR "KVM: Can't copy data from 0x%lx!\n", ptegp);
goto no_page_found;
}
for (i=0; i<16; i+=2) {
if (ptem == pteg[i]) {
u8 pp;
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)))
pp |= 4;
pte->may_write = false;
pte->may_read = false;
pte->may_execute = true;
switch (pp) {
case 0:
case 1:
case 2:
case 6:
pte->may_write = true;
case 3:
case 5:
case 7:
pte->may_read = true;
break;
}
if ( !pte->may_read )
continue;
dprintk_pte("MMU: Found PTE -> %x %x - %x\n",
pteg[i], pteg[i+1], pp);
found = 1;
break;
}
}
/* Update PTE C and A bits, so the guest's swapper knows we used the
page */
if (found) {
u32 oldpte = pteg[i+1];
if (pte->may_read)
pteg[i+1] |= PTEG_FLAG_ACCESSED;
if (pte->may_write)
pteg[i+1] |= PTEG_FLAG_DIRTY;
else
dprintk_pte("KVM: Mapping read-only page!\n");
/* Write back into the PTEG */
if (pteg[i+1] != oldpte)
copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
return 0;
}
no_page_found:
if (check_debug_ip(vcpu)) {
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",
i, pteg[i], pteg[i+1], ptem);
}
}
return -ENOENT;
}
static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data)
{
int r;
pte->eaddr = eaddr;
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);
if (r < 0)
r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, false);
return r;
}
static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum)
{
return to_book3s(vcpu)->sr[srnum].raw;
}
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->Ks = (value & 0x40000000) ? true : false;
sre->Kp = (value & 0x20000000) ? true : false;
sre->nx = (value & 0x10000000) ? true : false;
/* Map the new segment */
kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT);
}
static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large)
{
kvmppc_mmu_pte_flush(vcpu, ea, ~0xFFFULL);
}
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid,
u64 *vsid)
{
/* 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)) {
case 0:
*vsid = (VSID_REAL >> 16) | esid;
break;
case MSR_IR:
*vsid = (VSID_REAL_IR >> 16) | esid;
break;
case MSR_DR:
*vsid = (VSID_REAL_DR >> 16) | esid;
break;
case MSR_DR|MSR_IR:
{
ulong ea;
ea = esid << SID_SHIFT;
*vsid = find_sr(to_book3s(vcpu), ea)->vsid;
break;
}
default:
BUG();
}
return 0;
}
static bool kvmppc_mmu_book3s_32_is_dcbz32(struct kvm_vcpu *vcpu)
{
return true;
}
void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu)
{
struct kvmppc_mmu *mmu = &vcpu->arch.mmu;
mmu->mtsrin = kvmppc_mmu_book3s_32_mtsrin;
mmu->mfsrin = kvmppc_mmu_book3s_32_mfsrin;
mmu->xlate = kvmppc_mmu_book3s_32_xlate;
mmu->reset_msr = kvmppc_mmu_book3s_32_reset_msr;
mmu->tlbie = kvmppc_mmu_book3s_32_tlbie;
mmu->esid_to_vsid = kvmppc_mmu_book3s_32_esid_to_vsid;
mmu->ea_to_vp = kvmppc_mmu_book3s_32_ea_to_vp;
mmu->is_dcbz32 = kvmppc_mmu_book3s_32_is_dcbz32;
mmu->slbmte = NULL;
mmu->slbmfee = NULL;
mmu->slbmfev = NULL;
mmu->slbie = NULL;
mmu->slbia = NULL;
}

View file

@ -0,0 +1,345 @@
/*
* 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 2009
*
* Authors: Alexander Graf <agraf@suse.de>
*/
#include <asm/kvm_ppc.h>
#include <asm/disassemble.h>
#include <asm/kvm_book3s.h>
#include <asm/reg.h>
#define OP_19_XOP_RFID 18
#define OP_19_XOP_RFI 50
#define OP_31_XOP_MFMSR 83
#define OP_31_XOP_MTMSR 146
#define OP_31_XOP_MTMSRD 178
#define OP_31_XOP_MTSRIN 242
#define OP_31_XOP_TLBIEL 274
#define OP_31_XOP_TLBIE 306
#define OP_31_XOP_SLBMTE 402
#define OP_31_XOP_SLBIE 434
#define OP_31_XOP_SLBIA 498
#define OP_31_XOP_MFSRIN 659
#define OP_31_XOP_SLBMFEV 851
#define OP_31_XOP_EIOIO 854
#define OP_31_XOP_SLBMFEE 915
/* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */
#define OP_31_XOP_DCBZ 1010
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance)
{
int emulated = EMULATE_DONE;
switch (get_op(inst)) {
case 19:
switch (get_xop(inst)) {
case OP_19_XOP_RFID:
case OP_19_XOP_RFI:
vcpu->arch.pc = vcpu->arch.srr0;
kvmppc_set_msr(vcpu, vcpu->arch.srr1);
*advance = 0;
break;
default:
emulated = EMULATE_FAIL;
break;
}
break;
case 31:
switch (get_xop(inst)) {
case OP_31_XOP_MFMSR:
vcpu->arch.gpr[get_rt(inst)] = vcpu->arch.msr;
break;
case OP_31_XOP_MTMSRD:
{
ulong rs = vcpu->arch.gpr[get_rs(inst)];
if (inst & 0x10000) {
vcpu->arch.msr &= ~(MSR_RI | MSR_EE);
vcpu->arch.msr |= rs & (MSR_RI | MSR_EE);
} else
kvmppc_set_msr(vcpu, rs);
break;
}
case OP_31_XOP_MTMSR:
kvmppc_set_msr(vcpu, vcpu->arch.gpr[get_rs(inst)]);
break;
case OP_31_XOP_MFSRIN:
{
int srnum;
srnum = (vcpu->arch.gpr[get_rb(inst)] >> 28) & 0xf;
if (vcpu->arch.mmu.mfsrin) {
u32 sr;
sr = vcpu->arch.mmu.mfsrin(vcpu, srnum);
vcpu->arch.gpr[get_rt(inst)] = sr;
}
break;
}
case OP_31_XOP_MTSRIN:
vcpu->arch.mmu.mtsrin(vcpu,
(vcpu->arch.gpr[get_rb(inst)] >> 28) & 0xf,
vcpu->arch.gpr[get_rs(inst)]);
break;
case OP_31_XOP_TLBIE:
case OP_31_XOP_TLBIEL:
{
bool large = (inst & 0x00200000) ? true : false;
ulong addr = vcpu->arch.gpr[get_rb(inst)];
vcpu->arch.mmu.tlbie(vcpu, addr, large);
break;
}
case OP_31_XOP_EIOIO:
break;
case OP_31_XOP_SLBMTE:
if (!vcpu->arch.mmu.slbmte)
return EMULATE_FAIL;
vcpu->arch.mmu.slbmte(vcpu, vcpu->arch.gpr[get_rs(inst)],
vcpu->arch.gpr[get_rb(inst)]);
break;
case OP_31_XOP_SLBIE:
if (!vcpu->arch.mmu.slbie)
return EMULATE_FAIL;
vcpu->arch.mmu.slbie(vcpu, vcpu->arch.gpr[get_rb(inst)]);
break;
case OP_31_XOP_SLBIA:
if (!vcpu->arch.mmu.slbia)
return EMULATE_FAIL;
vcpu->arch.mmu.slbia(vcpu);
break;
case OP_31_XOP_SLBMFEE:
if (!vcpu->arch.mmu.slbmfee) {
emulated = EMULATE_FAIL;
} else {
ulong t, rb;
rb = vcpu->arch.gpr[get_rb(inst)];
t = vcpu->arch.mmu.slbmfee(vcpu, rb);
vcpu->arch.gpr[get_rt(inst)] = t;
}
break;
case OP_31_XOP_SLBMFEV:
if (!vcpu->arch.mmu.slbmfev) {
emulated = EMULATE_FAIL;
} else {
ulong t, rb;
rb = vcpu->arch.gpr[get_rb(inst)];
t = vcpu->arch.mmu.slbmfev(vcpu, rb);
vcpu->arch.gpr[get_rt(inst)] = t;
}
break;
case OP_31_XOP_DCBZ:
{
ulong rb = vcpu->arch.gpr[get_rb(inst)];
ulong ra = 0;
ulong addr;
u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
if (get_ra(inst))
ra = vcpu->arch.gpr[get_ra(inst)];
addr = (ra + rb) & ~31ULL;
if (!(vcpu->arch.msr & MSR_SF))
addr &= 0xffffffff;
if (kvmppc_st(vcpu, addr, 32, zeros)) {
vcpu->arch.dear = addr;
vcpu->arch.fault_dear = addr;
to_book3s(vcpu)->dsisr = DSISR_PROTFAULT |
DSISR_ISSTORE;
kvmppc_book3s_queue_irqprio(vcpu,
BOOK3S_INTERRUPT_DATA_STORAGE);
kvmppc_mmu_pte_flush(vcpu, addr, ~0xFFFULL);
}
break;
}
default:
emulated = EMULATE_FAIL;
}
break;
default:
emulated = EMULATE_FAIL;
}
return emulated;
}
void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper,
u32 val)
{
if (upper) {
/* Upper BAT */
u32 bl = (val >> 2) & 0x7ff;
bat->bepi_mask = (~bl << 17);
bat->bepi = val & 0xfffe0000;
bat->vs = (val & 2) ? 1 : 0;
bat->vp = (val & 1) ? 1 : 0;
bat->raw = (bat->raw & 0xffffffff00000000ULL) | val;
} else {
/* Lower BAT */
bat->brpn = val & 0xfffe0000;
bat->wimg = (val >> 3) & 0xf;
bat->pp = val & 3;
bat->raw = (bat->raw & 0x00000000ffffffffULL) | ((u64)val << 32);
}
}
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[(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[(sprn - SPRN_DBAT4U) / 2];
break;
default:
BUG();
}
kvmppc_set_bat(vcpu, bat, !(sprn % 2), val);
}
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
{
int emulated = EMULATE_DONE;
switch (sprn) {
case SPRN_SDR1:
to_book3s(vcpu)->sdr1 = vcpu->arch.gpr[rs];
break;
case SPRN_DSISR:
to_book3s(vcpu)->dsisr = vcpu->arch.gpr[rs];
break;
case SPRN_DAR:
vcpu->arch.dear = vcpu->arch.gpr[rs];
break;
case SPRN_HIOR:
to_book3s(vcpu)->hior = vcpu->arch.gpr[rs];
break;
case SPRN_IBAT0U ... SPRN_IBAT3L:
case SPRN_IBAT4U ... SPRN_IBAT7L:
case SPRN_DBAT0U ... SPRN_DBAT3L:
case SPRN_DBAT4U ... SPRN_DBAT7L:
kvmppc_write_bat(vcpu, sprn, (u32)vcpu->arch.gpr[rs]);
/* BAT writes happen so rarely that we're ok to flush
* everything here */
kvmppc_mmu_pte_flush(vcpu, 0, 0);
break;
case SPRN_HID0:
to_book3s(vcpu)->hid[0] = vcpu->arch.gpr[rs];
break;
case SPRN_HID1:
to_book3s(vcpu)->hid[1] = vcpu->arch.gpr[rs];
break;
case SPRN_HID2:
to_book3s(vcpu)->hid[2] = vcpu->arch.gpr[rs];
break;
case SPRN_HID4:
to_book3s(vcpu)->hid[4] = vcpu->arch.gpr[rs];
break;
case SPRN_HID5:
to_book3s(vcpu)->hid[5] = vcpu->arch.gpr[rs];
/* guest HID5 set can change is_dcbz32 */
if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
(mfmsr() & MSR_HV))
vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
break;
case SPRN_ICTC:
case SPRN_THRM1:
case SPRN_THRM2:
case SPRN_THRM3:
case SPRN_CTRLF:
case SPRN_CTRLT:
break;
default:
printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn);
#ifndef DEBUG_SPR
emulated = EMULATE_FAIL;
#endif
break;
}
return emulated;
}
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
{
int emulated = EMULATE_DONE;
switch (sprn) {
case SPRN_SDR1:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->sdr1;
break;
case SPRN_DSISR:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->dsisr;
break;
case SPRN_DAR:
vcpu->arch.gpr[rt] = vcpu->arch.dear;
break;
case SPRN_HIOR:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->hior;
break;
case SPRN_HID0:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[0];
break;
case SPRN_HID1:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[1];
break;
case SPRN_HID2:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[2];
break;
case SPRN_HID4:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[4];
break;
case SPRN_HID5:
vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[5];
break;
case SPRN_THRM1:
case SPRN_THRM2:
case SPRN_THRM3:
case SPRN_CTRLF:
case SPRN_CTRLT:
vcpu->arch.gpr[rt] = 0;
break;
default:
printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn);
#ifndef DEBUG_SPR
emulated = EMULATE_FAIL;
#endif
break;
}
return emulated;
}

View file

@ -0,0 +1,24 @@
/*
* 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 2009
*
* Authors: Alexander Graf <agraf@suse.de>
*/
#include <linux/module.h>
#include <asm/kvm_book3s.h>
EXPORT_SYMBOL_GPL(kvmppc_trampoline_enter);
EXPORT_SYMBOL_GPL(kvmppc_trampoline_lowmem);

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