* [PATCH V2 0/3] Add new PowerPC specific ELF core notes
From: Anshuman Khandual @ 2014-05-05 7:54 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: mikey, avagin, palves, oleg, michael, roland, Anshuman Khandual
This patch series adds five new ELF core note sections which can be
used with existing ptrace request PTRACE_GETREGSET/SETREGSET for accessing
various transactional memory and miscellaneous register sets on PowerPC
platform. Please find a test program exploiting these new ELF core note
types on a POWER8 system.
RFC: https://lkml.org/lkml/2014/4/1/292
V1: https://lkml.org/lkml/2014/4/2/43
Changes in V2
=============
(1) Removed all the power specific ptrace requests corresponding to new NT_PPC_*
elf core note types. Now all the register sets can be accessed from ptrace
through PTRACE_GETREGSET/PTRACE_SETREGSET using the individual NT_PPC* core
note type instead
(2) Fixed couple of attribute values for REGSET_TM_CGPR register set
(3) Renamed flush_tmreg_to_thread as flush_tmregs_to_thread
(4) Fixed 32 bit checkpointed GPR support
(5) Changed commit messages accordingly
Outstanding Issues
==================
(1) Running DSCR register value inside a transaction does not seem to be saved
at thread.dscr when the process stops for ptrace examination.
Test programs
=============
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <linux/elf.h>
#include <linux/types.h>
#include <linux/ptrace.h>
typedef long long u64;
typedef unsigned int u32;
typedef __vector128 vector128;
/* TM CFPR */
struct tm_cfpr {
u64 fpr[32];
u64 fpscr;
};
/* TM CVMX */
struct tm_cvmx {
vector128 vr[32] __attribute__((aligned(16)));
vector128 vscr __attribute__((aligned(16)));
u32 vrsave;
};
/* TM SPR */
struct tm_spr_regs {
u64 tm_tfhar;
u64 tm_texasr;
u64 tm_tfiar;
u64 tm_orig_msr;
u64 tm_tar;
u64 tm_ppr;
u64 tm_dscr;
};
/* Miscellaneous registers */
struct misc_regs {
u64 dscr;
u64 ppr;
u64 tar;
};
/* TM instructions */
#define TBEGIN ".long 0x7C00051D ;"
#define TEND ".long 0x7C00055D ;"
/* SPR number */
#define SPRN_DSCR 0x3
#define SPRN_TAR 815
/* ELF core notes */
#define NT_PPC_TM_SPR 0x103 /* PowerPC transactional memory special registers */
#define NT_PPC_TM_CGPR 0x104 /* PowerpC transactional memory checkpointed GPR */
#define NT_PPC_TM_CFPR 0x105 /* PowerPC transactional memory checkpointed FPR */
#define NT_PPC_TM_CVMX 0x106 /* PowerPC transactional memory checkpointed VMX */
#define NT_PPC_MISC 0x107 /* PowerPC miscellaneous registers */
#define VAL1 1
#define VAL2 2
#define VAL3 3
#define VAL4 4
int main(int argc, char *argv[])
{
struct tm_spr_regs *tmr1;
struct pt_regs *pregs1, *pregs2;
struct tm_cfpr *fpr, *fpr1;
struct misc_regs *dbr1;
struct iovec iov;
pid_t child;
int ret = 0, status = 0, i = 0, flag = 1;
pregs2 = (struct pt_regs *) malloc(sizeof(struct pt_regs));
fpr = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));
child = fork();
if (child < 0) {
printf("fork() failed \n");
exit(-1);
}
/* Child code */
if (child == 0) {
asm __volatile__(
"6: ;" /* TM checkpointed values */
"li 1, %[val1];" /* GPR[1] */
".long 0x7C210166;" /* FPR[1] */
"li 2, %[val2];" /* GPR[2] */
".long 0x7C420166;" /* FPR[2] */
"mtspr %[tar], 1;" /* TAR */
"mtspr %[dscr], 2;" /* DSCR */
"1: ;"
TBEGIN /* TM running values */
"beq 2f ;"
"li 1, %[val3];" /* GPR[1] */
".long 0x7C210166;" /* FPR[1] */
"li 2, %[val4];" /* GPR[2] */
".long 0x7C420166;" /* FPR[2] */
"mtspr %[tar], 1;" /* TAR */
"mtspr %[dscr], 2;" /* DSCR */
"b .;"
TEND
"2: ;" /* Abort handler */
"b 1b;" /* Start from TBEGIN */
"3: ;"
"b 6b;" /* Start all over again */
:: [dscr]"i"(SPRN_DSCR), [tar]"i"(SPRN_TAR), [val1]"i"(VAL1), [val2]"i"(VAL2), [val3]"i"(VAL3), [val4]"i"(VAL4)
: "memory", "r7");
}
/* Parent */
if (child) {
do {
memset(pregs2, 0 , sizeof(struct pt_regs));
memset(fpr, 0 , sizeof(struct tm_cfpr));
/* Wait till child hits "b ." instruction */
sleep(3);
/* Attach tracee */
ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
if (ret == -1) {
printf("PTRACE_ATTACH failed: %s\n", strerror(errno));
exit(-1);
}
ret = waitpid(child, NULL, 0);
if (ret != child) {
printf("PID does not match\n");
exit(-1);
}
/* TM specific SPR */
iov.iov_base = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs));
iov.iov_len = sizeof(struct tm_spr_regs);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_TM_SPR failed %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct tm_spr_regs)) {
printf("NT_PPC_TM_SPR: Length returned is wrong\n");
exit(-1);
}
tmr1 = iov.iov_base;
printf("-------TM specific SPR------\n");
printf("TM TFHAR: %llx\n", tmr1->tm_tfhar);
printf("TM TEXASR: %llx\n", tmr1->tm_texasr);
printf("TM TFIAR: %llx\n", tmr1->tm_tfiar);
printf("TM CH ORIG_MSR: %llx\n", tmr1->tm_orig_msr);
printf("TM CH TAR: %llx\n", tmr1->tm_tar);
printf("TM CH PPR: %llx\n", tmr1->tm_ppr);
printf("TM CH DSCR: %llx\n", tmr1->tm_dscr);
if (tmr1->tm_tar == VAL1)
printf("TAR PASSED\n");
else
printf("TAR FAILED\n");
if (tmr1->tm_dscr == VAL2)
printf("DSCR PASSED\n");
else
printf("DSCR FAILED\n");
/* TM checkpointed GPR */
iov.iov_base = (struct pt_regs *) malloc(sizeof(struct pt_regs));;
iov.iov_len = sizeof(struct pt_regs);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_TM_CGPR failed: %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct pt_regs)) {
printf("NT_PPC_TM_CGPR: Length returned is wrong\n");
exit(-1);
}
pregs1 = iov.iov_base;
printf("-------TM checkpointed GPR-----\n");
printf("TM CH GPR[1]: %x\n", pregs1->gpr[1]);
printf("TM CH GPR[2]: %x\n", pregs1->gpr[2]);
printf("TM CH NIP: %x\n", pregs1->nip);
printf("TM CH LINK: %x\n", pregs1->link);
printf("TM CH CCR: %x\n", pregs1->ccr);
if (pregs1->gpr[1] == VAL1)
printf("GPR[1] PASSED\n");
else
printf("GPR[1] FAILED\n");
if (pregs1->gpr[2] == VAL2)
printf("GPR[2] PASSED\n");
else
printf("GPR[2] FAILED\n");
/* TM running GPR */
ret = ptrace(PTRACE_GETREGS, child, NULL, pregs2);
if (ret == -1) {
printf("PTRACE_GETREGS fail: %s\n", strerror(errno));
exit(-1);
}
printf("-------TM running GPR-----\n");
printf("TM RN GPR[1]: %x\n", pregs2->gpr[1]);
printf("TM RN GPR[2]: %x\n", pregs2->gpr[2]);
printf("TM RN NIP: %x\n", pregs2->nip);
printf("TM RN LINK: %x\n", pregs2->link);
printf("TM RN CCR: %x\n", pregs2->ccr);
if (pregs2->gpr[1] == VAL3)
printf("GPR[1] PASSED\n");
else
printf("GPR[1] FAILED\n");
if (pregs2->gpr[2] == VAL4)
printf("GPR[2] PASSED\n");
else
printf("GPR[2] FAILED\n");
/* TM checkpointed FPR */
iov.iov_base = (struct tm_cfpr *) malloc(sizeof(struct tm_cfpr));;
iov.iov_len = sizeof(struct tm_cfpr);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_TM_CFPR: Failed: %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct tm_cfpr)) {
printf("NT_PPC_TM_CFPR: Length returned is wrong\n");
exit(-1);
}
fpr1 = iov.iov_base;
printf("-------TM checkpointed FPR-----\n");
printf("TM CH FPR[1]: %llx\n", fpr1->fpr[1]);
printf("TM CH FPR[2]: %llx\n", fpr1->fpr[2]);
printf("TM CH FPSCR: %llx\n", fpr1->fpscr);
if (fpr1->fpr[1] == VAL1)
printf("FPR[1] PASSED\n");
else
printf("FPR[1] FAILED\n");
if (fpr1->fpr[2] == VAL2)
printf("FPR[2] PASSED\n");
else
printf("FPR[2] FAILED\n");
/* TM running FPR */
ret = ptrace(PTRACE_GETFPREGS, child, NULL, fpr);
if (ret == -1) {
printf("PTRACE_GETFPREGS failed: %s\n", strerror(errno));
exit(-1);
}
printf("-------TM running FPR-----\n");
printf("TM RN FPR[1]: %llx\n", fpr->fpr[1]);
printf("TM RN FPR[2]: %llx\n", fpr->fpr[2]);
printf("TM RN FPSCR: %llx\n", fpr->fpscr);
if (fpr->fpr[1] == VAL3)
printf("FPR[1] PASSED\n");
else
printf("FPR[1] FAILED\n");
if (fpr->fpr[2] == VAL4)
printf("FPR[2] PASSED\n");
else
printf("FPR[2] FAILED\n");
/* Misc registers */
iov.iov_base = (struct misc_regs *) malloc(sizeof(struct misc_regs));
iov.iov_len = sizeof(struct misc_regs);
ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_MISC, &iov);
if (ret == -1) {
printf("PTRACE_GETREGSET: NT_PPC_MISC: Failed: %s\n", strerror(errno));
exit(-1);
}
if (iov.iov_len != sizeof(struct misc_regs)) {
printf("NT_PPC_TM_MISC: Length returned is wrong\n");
exit(-1);
}
dbr1 = iov.iov_base;
printf("-------Running miscellaneous registers-------\n");
printf("TM RN DSCR: %llx\n", dbr1->dscr);
printf("TM RN PPR: %llx\n", dbr1->ppr);
printf("TM RN TAR: %llx\n", dbr1->tar);
if (dbr1->tar == VAL3)
printf("TAR PASSED\n");
else
printf("TAR FAILED\n");
if (dbr1->dscr == VAL4)
printf("DSCR PASSED\n");
else
printf("DSCR FAILED\n");
/* Detach tracee */
ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
if (ret == -1) {
printf("PTRACE_DETACH failed: %s\n", strerror(errno));
exit(-1);
}
} while (0);
}
return 0;
}
Test Results
============
(1) 64 bit application ==>
-------TM specific SPR------
TM TFHAR: 10000960
TM TEXASR: de000001ac000001
TM TFIAR: c00000000003f9a6
TM CH ORIG_MSR: 900000050000f032
TM CH TAR: 1
TM CH PPR: c000000000000
TM CH DSCR: 2
TAR PASSED
DSCR PASSED
-------TM checkpointed GPR-----
TM CH GPR[1]: 1
TM CH GPR[2]: 2
TM CH NIP: 10000960
TM CH LINK: 10000904
TM CH CCR: 22000022
GPR[1] PASSED
GPR[2] PASSED
-------TM running GPR-----
TM RN GPR[1]: 3
TM RN GPR[2]: 4
TM RN NIP: 1000097c
TM RN LINK: 10000904
TM RN CCR: 2000022
GPR[1] PASSED
GPR[2] PASSED
-------TM checkpointed FPR-----
TM CH FPR[1]: 1
TM CH FPR[2]: 2
TM CH FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------TM running FPR-----
TM RN FPR[1]: 3
TM RN FPR[2]: 4
TM RN FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------Running miscellaneous registers-------
TM RN DSCR: 0
TM RN PPR: c000000000000
TM RN TAR: 3
TAR PASSED
DSCR FAILED
(2) 32 bit application ==>
-------TM specific SPR------
TM TFHAR: 100006b8
TM TEXASR: de000001ac000001
TM TFIAR: c00000000003f9a6
TM CH ORIG_MSR: 100000050000f032
TM CH TAR: 1
TM CH PPR: c000000000000
TM CH DSCR: 2
TAR PASSED
DSCR PASSED
-------TM checkpointed GPR-----
TM CH GPR[1]: 1
TM CH GPR[2]: 2
TM CH NIP: 100006b8
TM CH LINK: 1000066c
TM CH CCR: 22000022
GPR[1] PASSED
GPR[2] PASSED
-------TM running GPR-----
TM RN GPR[1]: 3
TM RN GPR[2]: 4
TM RN NIP: 100006d4
TM RN LINK: 1000066c
TM RN CCR: 2000022
GPR[1] PASSED
GPR[2] PASSED
TM CH FPR[2]: 2
TM CH FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------TM running FPR-----
TM RN FPR[1]: 3
TM RN FPR[2]: 4
TM RN FPSCR: 0
FPR[1] PASSED
FPR[2] PASSED
-------Running miscellaneous registers-------
TM RN DSCR: 0
TM RN PPR: c000000000000
TM RN TAR: 3
TAR PASSED
DSCR FAILED
Anshuman Khandual (3):
elf: Add some new PowerPC specifc note sections
powerpc, ptrace: Enable support for transactional memory register sets
powerpc, ptrace: Enable support for miscellaneous registers
arch/powerpc/include/asm/switch_to.h | 8 +
arch/powerpc/kernel/process.c | 24 ++
arch/powerpc/kernel/ptrace.c | 764 +++++++++++++++++++++++++++++++++--
include/uapi/linux/elf.h | 5 +
4 files changed, 773 insertions(+), 28 deletions(-)
--
1.7.11.7
^ permalink raw reply
* Re: [PATCH] powerpc/eeh: Fix build error for celleb
From: Michael Neuling @ 2014-05-05 6:12 UTC (permalink / raw)
To: Gavin Shan; +Cc: linuxppc-dev, Stephen Rothwell
In-Reply-To: <1399255745-2745-1-git-send-email-gwshan@linux.vnet.ibm.com>
On Mon, 2014-05-05 at 12:09 +1000, Gavin Shan wrote:
> Commit 7f52a526f ("powerpc/eeh: Allow to disable EEH") caused
> following build error with "celleb_defconfig" as being catched
> by Mikey on linux-next.
>=20
> arch/powerpc/kernel/eeh.c: In function 'eeh_init_proc':
> arch/powerpc/kernel/eeh.c:1173:37: error: 'powerpc_debugfs_root' \
> undeclared (first use in this function)
> arch/powerpc/kernel/eeh.c:1173:37: note: each undeclared identifier \
> is reported only once for each function it appears in
>=20
> Reported-by: Michael Neuling <mikey@neuling.org>
> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Thanks.
> ---
> arch/powerpc/kernel/eeh.c | 1 +
> 1 file changed, 1 insertion(+)
>=20
> diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
> index 33d683a..9c6b899 100644
> --- a/arch/powerpc/kernel/eeh.c
> +++ b/arch/powerpc/kernel/eeh.c
> @@ -36,6 +36,7 @@
> #include <linux/of.h>
> =20
> #include <linux/atomic.h>
> +#include <asm/debug.h>
> #include <asm/eeh.h>
> #include <asm/eeh_event.h>
> #include <asm/io.h>
^ permalink raw reply
* Re: Boot problems with a PA6T board
From: Michael Ellerman @ 2014-05-05 5:48 UTC (permalink / raw)
To: Christian Zigotzky; +Cc: linuxppc-dev
In-Reply-To: <5366649E.4030102@xenosoft.de>
On Sun, 2014-05-04 at 18:02 +0200, Christian Zigotzky wrote:
> Hi All,
>
> The RC 1, 2, and 3 of the kernel 3.15 don't boot on my PA6T board with a
> Radeon HD 6870 graphics card.
>
> Screenshot:
> http://forum.hyperion-entertainment.biz/download/file.php?id=1060&mode=view
>
> The kernel 3.14 starts without any problems. Has anyone a tip for me,
> please?
The line that says "starting cpu hw idx 0... failed" looks a little worrying.
Do you see that on 3.14 as well?
Otherwise bisection is probably your best bet.
cheers
^ permalink raw reply
* [PATCH] powerpc: Fix comment around arch specific definition of RECLAIM_DISTANCE
From: Preeti U Murthy @ 2014-05-05 5:17 UTC (permalink / raw)
To: linuxppc-dev; +Cc: anton, kosaki.motohiro
Commit 32e45ff43eaf5c17f changed the default value of
RECLAIM_DISTANCE to 30. However the comment around arch
specifc definition of RECLAIM_DISTANCE is not updated to
reflect the same. Correct the value mentioned in the comment.
Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Cc: Anton Blanchard <anton@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
---
arch/powerpc/include/asm/topology.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index c920215..356546d 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -12,7 +12,7 @@ struct device_node;
* Before going off node we want the VM to try and reclaim from the local
* node. It does this if the remote distance is larger than RECLAIM_DISTANCE.
* With the default REMOTE_DISTANCE of 20 and the default RECLAIM_DISTANCE of
- * 20, we never reclaim and go off node straight away.
+ * 30, we never reclaim and go off node straight away.
*
* To fix this we choose a smaller value of RECLAIM_DISTANCE.
*/
^ permalink raw reply related
* [PATCH V5] KVM: PPC: BOOK3S: PR: Enable Little Endian PR guest
From: Aneesh Kumar K.V @ 2014-05-05 3:09 UTC (permalink / raw)
To: agraf, benh, paulus; +Cc: linuxppc-dev, kvm, kvm-ppc, Aneesh Kumar K.V
This patch make sure we inherit the LE bit correctly in different case
so that we can run Little Endian distro in PR mode
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
Changes from V4:
* Don't check for MSR_LE bit while setting LPCR.
arch/powerpc/include/asm/kvm_host.h | 2 +-
arch/powerpc/kernel/asm-offsets.c | 2 +-
arch/powerpc/kvm/book3s_64_mmu.c | 2 +-
arch/powerpc/kvm/book3s_pr.c | 23 ++++++++++++++++++++++-
4 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 1eaea2dea174..d342f8efc843 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -562,6 +562,7 @@ struct kvm_vcpu_arch {
#ifdef CONFIG_PPC_BOOK3S
ulong fault_dar;
u32 fault_dsisr;
+ unsigned long intr_msr;
#endif
#ifdef CONFIG_BOOKE
@@ -654,7 +655,6 @@ struct kvm_vcpu_arch {
spinlock_t tbacct_lock;
u64 busy_stolen;
u64 busy_preempt;
- unsigned long intr_msr;
#endif
};
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index dba8140ebc20..6a4b77d197f3 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -493,7 +493,6 @@ int main(void)
DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty));
- DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
#endif
#ifdef CONFIG_PPC_BOOK3S
DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
@@ -528,6 +527,7 @@ int main(void)
DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
+ DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c
index 83da1f868fd5..8231b83c493b 100644
--- a/arch/powerpc/kvm/book3s_64_mmu.c
+++ b/arch/powerpc/kvm/book3s_64_mmu.c
@@ -38,7 +38,7 @@
static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu)
{
- kvmppc_set_msr(vcpu, MSR_SF);
+ kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
}
static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index f30cdfee800d..01a7156d055c 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -249,7 +249,7 @@ static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
ulong smsr = vcpu->arch.shared->msr;
/* Guest MSR values */
- smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE;
+ smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_LE;
/* Process MSR values */
smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
/* External providers the guest reserved */
@@ -1118,6 +1118,15 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_HIOR:
*val = get_reg_val(id, to_book3s(vcpu)->hior);
break;
+ case KVM_REG_PPC_LPCR:
+ /*
+ * We are only interested in the LPCR_ILE bit
+ */
+ if (vcpu->arch.intr_msr & MSR_LE)
+ *val = get_reg_val(id, LPCR_ILE);
+ else
+ *val = get_reg_val(id, 0);
+ break;
default:
r = -EINVAL;
break;
@@ -1126,6 +1135,14 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
return r;
}
+static void kvmppc_set_lpcr_pr(struct kvm_vcpu *vcpu, u64 new_lpcr)
+{
+ if (new_lpcr & LPCR_ILE)
+ vcpu->arch.intr_msr |= MSR_LE;
+ else
+ vcpu->arch.intr_msr &= ~MSR_LE;
+}
+
static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val)
{
@@ -1136,6 +1153,9 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
to_book3s(vcpu)->hior = set_reg_val(id, *val);
to_book3s(vcpu)->hior_explicit = true;
break;
+ case KVM_REG_PPC_LPCR:
+ kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));
+ break;
default:
r = -EINVAL;
break;
@@ -1188,6 +1208,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm,
vcpu->arch.pvr = 0x3C0301;
if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
vcpu->arch.pvr = mfspr(SPRN_PVR);
+ vcpu->arch.intr_msr = MSR_SF;
#else
/* default to book3s_32 (750) */
vcpu->arch.pvr = 0x84202;
--
1.9.1
^ permalink raw reply related
* [PATCH] powerpc/eeh: Fix build error for celleb
From: Gavin Shan @ 2014-05-05 2:09 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, Gavin Shan
Commit 7f52a526f ("powerpc/eeh: Allow to disable EEH") caused
following build error with "celleb_defconfig" as being catched
by Mikey on linux-next.
arch/powerpc/kernel/eeh.c: In function 'eeh_init_proc':
arch/powerpc/kernel/eeh.c:1173:37: error: 'powerpc_debugfs_root' \
undeclared (first use in this function)
arch/powerpc/kernel/eeh.c:1173:37: note: each undeclared identifier \
is reported only once for each function it appears in
Reported-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 33d683a..9c6b899 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -36,6 +36,7 @@
#include <linux/of.h>
#include <linux/atomic.h>
+#include <asm/debug.h>
#include <asm/eeh.h>
#include <asm/eeh_event.h>
#include <asm/io.h>
--
1.8.3.2
^ permalink raw reply related
* [PATCH 22/22] powerpc/powernv: Support PCI error injection
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces the infrastructure of error injection backend
for PowerNV platform. For now, we just implement logic to inject
PCI errors. We need support injecting other types of errors in
future.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/book3s_errinjct.h | 19 +++
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/errinjct.c | 215 +++++++++++++++++++++++++++++
3 files changed, 235 insertions(+)
create mode 100644 arch/powerpc/platforms/powernv/errinjct.c
diff --git a/arch/powerpc/include/asm/book3s_errinjct.h b/arch/powerpc/include/asm/book3s_errinjct.h
index 35712be..75443ad 100644
--- a/arch/powerpc/include/asm/book3s_errinjct.h
+++ b/arch/powerpc/include/asm/book3s_errinjct.h
@@ -56,6 +56,25 @@ struct kvm_errinjct_token {
struct list_head list;
};
+/* Argument buffer for various operations */
+struct kvm_errinjct_ioa_bus {
+ uint32_t addr;
+ uint32_t mask;
+ uint32_t cfg_addr;
+ uint32_t buid_hi;
+ uint32_t buid_lo;
+ uint32_t op;
+};
+
+struct kvm_errinjct_ioa_bus64 {
+ uint64_t addr;
+ uint64_t mask;
+ uint32_t cfg_addr;
+ uint32_t buid_hi;
+ uint32_t buid_lo;
+ uint32_t op;
+};
+
int kvm_errinjct_register(int opcode, kvm_errinjct_func handler);
int kvm_errinjct_unregister(int opcode);
void kvmppc_errinjct_rtas(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index d8ea670..d096b18 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o
obj-$(CONFIG_KVM_EEH) += eeh-rtas.o
+obj-$(CONFIG_KVM_ERRINJCT) += errinjct.o
obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o
diff --git a/arch/powerpc/platforms/powernv/errinjct.c b/arch/powerpc/platforms/powernv/errinjct.c
new file mode 100644
index 0000000..ccc7853
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/errinjct.c
@@ -0,0 +1,215 @@
+/*
+ * Backend for error injection implemented on PowerNV platform.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+#include <asm/iommu.h>
+#include <asm/eeh.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_ppc.h>
+#include <asm/book3s_errinjct.h>
+#include <asm/hvcall.h>
+#include <asm/msi_bitmap.h>
+#include <asm/opal.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+static int powernv_errinjct_ioa(struct kvm_vcpu *vcpu, rtas_arg_t buf)
+{
+ struct OpalErrinjct ej;
+ struct kvm_errinjct_ioa_bus args;
+ struct eeh_vfio_pci_addr addr;
+ struct eeh_pe *pe;
+ struct pnv_phb *phb;
+ long rc;
+ int ret = 0;
+
+ /* Word aligned buffer */
+ if (buf & 0x3) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Copy over argument */
+ ret = kvm_read_guest(vcpu->kvm, buf, &args, sizeof(args));
+ if (ret) {
+ pr_warn("%s: Can't copyover arguments (%d)\n",
+ __func__, ret);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Sanity check on operation. We don't support optional
+ * operation (20) and last one (21) for now.
+ */
+ if (args.op < 0 || args.op > 21) {
+ ret = -3;
+ goto out;
+ } else if (args.op >= 20) {
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Only do error injection on passthrou PE. It's notable
+ * the "cfg_addr" is guest PE address
+ */
+ addr.kvm = vcpu->kvm;
+ addr.buid_hi = args.buid_hi;
+ addr.buid_lo = args.buid_lo;
+ addr.pe_addr = args.cfg_addr;
+ pe = eeh_vfio_pe_get(&addr);
+ if (!pe) {
+ pr_warn("%s: Can't find passed PE (%08x-%08x-%08x)\n",
+ __func__, args.buid_hi, args.buid_lo, args.cfg_addr);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Calling to OPAL API. We need host PE address
+ * and PHB host BUID.
+ */
+ phb = pe->phb->private_data;
+
+ ej.type = OpalErrinjctTypeIoaBusError;
+ ej.ioa.addr = args.addr;
+ ej.ioa.mask = args.mask;
+ ej.ioa.phb_id = phb->opal_id;
+ ej.ioa.pe = pe->addr;
+ ej.ioa.function = args.op;
+ rc = opal_err_injct(&ej);
+ if (rc != OPAL_SUCCESS) {
+ pr_warn("%s: OPAL API returns %ld\n", __func__, rc);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int powernv_errinjct_ioa64(struct kvm_vcpu *vcpu, rtas_arg_t buf)
+{
+ struct OpalErrinjct ej;
+ struct kvm_errinjct_ioa_bus64 args;
+ struct eeh_vfio_pci_addr addr;
+ struct eeh_pe *pe;
+ struct pnv_phb *phb;
+ long rc;
+ int ret = 0;
+
+ /* Double word aligned buffer */
+ if (buf & 0x7) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Copy over argument */
+ ret = kvm_read_guest(vcpu->kvm, buf, &args, sizeof(args));
+ if (ret) {
+ pr_warn("%s: Can't copyover arguments (%d)\n",
+ __func__, ret);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Sanity check on operation. We don't support optional
+ * operation (20) and last one (21) for now.
+ */
+ if (args.op < 0 || args.op > 21) {
+ ret = -3;
+ goto out;
+ } else if (args.op >= 20) {
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Only do error injection on passthrou PE. It's notable
+ * that "cfg_addr" is guest PE address
+ */
+ addr.kvm = vcpu->kvm;
+ addr.buid_hi = args.buid_hi;
+ addr.buid_lo = args.buid_lo;
+ addr.pe_addr = args.cfg_addr;
+ pe = eeh_vfio_pe_get(&addr);
+ if (!pe) {
+ pr_warn("%s: Can't find passed PE (%08x-%08x-%08x)\n",
+ __func__, args.buid_hi, args.buid_lo, args.cfg_addr);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Calling to OPAL API. We need host PE address
+ * and PHB host BUID.
+ */
+ phb = pe->phb->private_data;
+
+ ej.type = OpalErrinjctTypeIoaBusError64;
+ ej.ioa64.addr = args.addr;
+ ej.ioa64.mask = args.mask;
+ ej.ioa64.phb_id = phb->opal_id;
+ ej.ioa64.pe = pe->addr;
+ ej.ioa64.function = args.op;
+ rc = opal_err_injct(&ej);
+ if (rc != OPAL_SUCCESS) {
+ pr_warn("%s: OPAL API returns %ld\n", __func__, rc);
+ ret = -1;
+ goto out;
+ }
+
+ /* Success */
+ ret = 0;
+out:
+ return ret;
+}
+
+static struct kvm_errinjct_handler handlers[] = {
+ { .opcode = kvm_errinjct_ioa_bus_error,
+ .handler = powernv_errinjct_ioa
+ },
+ { .opcode = kvm_errinjct_ioa_bus_error_64,
+ .handler = powernv_errinjct_ioa64
+ }
+};
+
+static int __init powernv_errinjct_init(void)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+ ret = kvm_errinjct_register(handlers[i].opcode,
+ handlers[i].handler);
+ if (ret) {
+ pr_warn("%s: Failure registering handler %d (%d)\n",
+ __func__, handlers[i].opcode, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+module_init(powernv_errinjct_init);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 19/22] powerpc: Introduce CONFIG_KVM_ERRINJCT
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces kernel configuration option KVM_ERRINJCT. It
enables emulating error injection RTAS services used on IBM POWER
(pSeries) servers.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kvm/Kconfig | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 6764fc5..914ab05 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -198,6 +198,14 @@ config KVM_EEH
Enable support for emulating EEH RTAS services used on IBM
POWER (pSeries) servers.
+config KVM_ERRINJCT
+ bool "KVM in-kernel error injection emulation"
+ depends on KVM_EEH
+ default y
+ ---help---
+ Enable support for emulating error injection services used
+ on IBM POWER (pSeries) servers
+
source drivers/vhost/Kconfig
endif # VIRTUALIZATION
--
1.8.3.2
^ permalink raw reply related
* [PATCH 21/22] powerpc/powernv: Sync OPAL header file with firmware
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch synchronizes OPAL header file with firmware so that the
host kernel can make OPAL call to do error injection.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/opal.h | 65 ++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/opal-wrappers.S | 1 +
2 files changed, 66 insertions(+)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 66ad7a7..ca55d9c 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -175,6 +175,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_SET_PARAM 90
#define OPAL_DUMP_RESEND 91
#define OPAL_DUMP_INFO2 94
+#define OPAL_ERR_INJECT 96
#ifndef __ASSEMBLY__
@@ -219,6 +220,69 @@ enum OpalPciErrorSeverity {
OPAL_EEH_SEV_INF = 5
};
+enum OpalErrinjctType {
+ OpalErrinjctTypeFirst = 0,
+ OpalErrinjctTypeFatal = 1,
+ OpalErrinjctTypeRecoverRandomEvent = 2,
+ OpalErrinjctTypeRecoverSpecialEvent = 3,
+ OpalErrinjctTypeCorruptedPage = 4,
+ OpalErrinjctTypeCorruptedSlb = 5,
+ OpalErrinjctTypeTranslatorFailure = 6,
+ OpalErrinjctTypeIoaBusError = 7,
+ OpalErrinjctTypeIoaBusError64 = 8,
+ OpalErrinjctTypePlatformSpecific = 9,
+ OpalErrinjctTypeDcacheStart = 10,
+ OpalErrinjctTypeDcacheEnd = 11,
+ OpalErrinjctTypeIcacheStart = 12,
+ OpalErrinjctTypeIcacheEnd = 13,
+ OpalErrinjctTypeTlbStart = 14,
+ OpalErrinjctTypeTlbEnd = 15,
+ OpalErrinjctTypeUpstreamIoError = 16,
+ OpalErrinjctTypeLast = 17,
+
+ /* IoaBusError & IoaBusError64 */
+ OpalEjtIoaLoadMemAddr = 0,
+ OpalEjtIoaLoadMemData = 1,
+ OpalEjtIoaLoadIoAddr = 2,
+ OpalEjtIoaLoadIoData = 3,
+ OpalEjtIoaLoadConfigAddr = 4,
+ OpalEjtIoaLoadConfigData = 5,
+ OpalEjtIoaStoreMemAddr = 6,
+ OpalEjtIoaStoreMemData = 7,
+ OpalEjtIoaStoreIoAddr = 8,
+ OpalEjtIoaStoreIoData = 9,
+ OpalEjtIoaStoreConfigAddr = 10,
+ OpalEjtIoaStoreConfigData = 11,
+ OpalEjtIoaDmaReadMemAddr = 12,
+ OpalEjtIoaDmaReadMemData = 13,
+ OpalEjtIoaDmaReadMemMaster = 14,
+ OpalEjtIoaDmaReadMemTarget = 15,
+ OpalEjtIoaDmaWriteMemAddr = 16,
+ OpalEjtIoaDmaWriteMemData = 17,
+ OpalEjtIoaDmaWriteMemMaster = 18,
+ OpalEjtIoaDmaWriteMemTarget = 19,
+};
+
+struct OpalErrinjct {
+ int32_t type;
+ union {
+ struct {
+ uint32_t addr;
+ uint32_t mask;
+ uint64_t phb_id;
+ uint32_t pe;
+ uint32_t function;
+ }ioa;
+ struct {
+ uint64_t addr;
+ uint64_t mask;
+ uint64_t phb_id;
+ uint32_t pe;
+ uint32_t function;
+ }ioa64;
+ };
+};
+
enum OpalShpcAction {
OPAL_SHPC_GET_LINK_STATE = 0,
OPAL_SHPC_GET_SLOT_STATE = 1
@@ -839,6 +903,7 @@ int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer,
uint64_t diag_buffer_len);
int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id, void *diag_buffer,
uint64_t diag_buffer_len);
+int64_t opal_err_injct(void *data);
int64_t opal_pci_fence_phb(uint64_t phb_id);
int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data);
int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index f531ffe..46265de 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -119,6 +119,7 @@ OPAL_CALL(opal_pci_next_error, OPAL_PCI_NEXT_ERROR);
OPAL_CALL(opal_pci_poll, OPAL_PCI_POLL);
OPAL_CALL(opal_pci_msi_eoi, OPAL_PCI_MSI_EOI);
OPAL_CALL(opal_pci_get_phb_diag_data2, OPAL_PCI_GET_PHB_DIAG_DATA2);
+OPAL_CALL(opal_err_injct, OPAL_ERR_INJECT);
OPAL_CALL(opal_xscom_read, OPAL_XSCOM_READ);
OPAL_CALL(opal_xscom_write, OPAL_XSCOM_WRITE);
OPAL_CALL(opal_lpc_read, OPAL_LPC_READ);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 20/22] powerpc/kvm: Infrastructure for error injection
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch intends to implements the infrastructure for error injection.
RTAS calls "ibm,{open-errinjct, close-errinjct, errinjct}" are handled
in the host directly. Each VM is allowed to have one opened token at
once.
There're multiple types of error injection to be supported by the system.
So we maintain an array of handlers with error type as index. The array
supports dynamic registration.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/book3s_errinjct.h | 78 +++++++
arch/powerpc/kvm/Makefile | 3 +
arch/powerpc/kvm/book3s_errinjct.c | 329 +++++++++++++++++++++++++++++
arch/powerpc/kvm/book3s_rtas.c | 29 ++-
4 files changed, 438 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/book3s_errinjct.h
create mode 100644 arch/powerpc/kvm/book3s_errinjct.c
diff --git a/arch/powerpc/include/asm/book3s_errinjct.h b/arch/powerpc/include/asm/book3s_errinjct.h
new file mode 100644
index 0000000..35712be
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s_errinjct.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __POWERPC_BOOK3S_ERRINJCT_H__
+#define __POWERPC_BOOK3S_ERRINJCT_H__
+
+/* Error injection handler */
+typedef int (*kvm_errinjct_func)(struct kvm_vcpu *vcpu, rtas_arg_t buf);
+
+#ifdef CONFIG_KVM_ERRINJCT
+
+/* RTAS services for error injection */
+enum {
+ kvm_errinjct_open_token,
+ kvm_errinjct_close_token,
+ kvm_errinjct_errinjct
+};
+
+/* Supported types of error injection */
+enum {
+ kvm_errinjct_min = 0,
+ kvm_errinjct_fatal,
+ kvm_errinjct_recover_random_evt,
+ kvm_errinjct_recover_special_evt,
+ kvm_errinjct_corrupted_page,
+ kvm_errinjct_corrupted_slb,
+ kvm_errinjct_translator_failure,
+ kvm_errinjct_ioa_bus_error,
+ kvm_errinjct_ioa_bus_error_64,
+ kvm_errinjct_platform_specific,
+ kvm_errinjct_corrupted_dcache_start,
+ kvm_errinjct_corrupted_dcache_end,
+ kvm_errinjct_corrupted_icache_start,
+ kvm_errinjct_corrupted_icache_end,
+ kvm_errinjct_corrupted_tlb_start,
+ kvm_errinjct_corrupted_tlb_end,
+ kvm_errinjct_upstream_io_error,
+ kvm_errinjct_max
+};
+
+/* Handler for specific type of error injection */
+struct kvm_errinjct_handler {
+ int opcode;
+ kvm_errinjct_func handler;
+};
+
+/* Tokens that have been opened */
+struct kvm_errinjct_token {
+ struct kvm *kvm;
+ int token;
+ struct list_head list;
+};
+
+int kvm_errinjct_register(int opcode, kvm_errinjct_func handler);
+int kvm_errinjct_unregister(int opcode);
+void kvmppc_errinjct_rtas(struct kvm_vcpu *vcpu,
+ struct rtas_args *args, int flag);
+
+#else
+
+static inline int kvm_errinjct_register(int opcode,
+ kvm_errinjct_func handler)
+{
+ return 0;
+}
+
+static inline int kvm_errinjct_unregister(int opcode);
+{
+ return 0;
+}
+
+#endif /* CONFIG_KVM_ERRINJCT */
+#endif /* __POWERPC_BOOK3S_ERRINJCT_H__ */
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 673038d..f221f66 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -97,6 +97,9 @@ endif
kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
book3s_xics.o
+kvm-book3s_64-objs-$(CONFIG_KVM_ERRINJCT) += \
+ book3s_errinjct.o
+
kvm-book3s_64-objs-$(CONFIG_KVM_VFIO) += \
$(addprefix ../../../virt/kvm/, vfio.o)
diff --git a/arch/powerpc/kvm/book3s_errinjct.c b/arch/powerpc/kvm/book3s_errinjct.c
new file mode 100644
index 0000000..27a49ab
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_errinjct.c
@@ -0,0 +1,329 @@
+/*
+ * The file intends to implement RTAS errinjct functionality for book3s
+ * architecture. Due to the individual errors injected to the system
+ * are defined by device tree node, it's reasonable to introduce the
+ * mechanism to register the supported errors and their corresponding
+ * handlers.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <asm/uaccess.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_ppc.h>
+#include <asm/book3s_errinjct.h>
+#include <asm/hvcall.h>
+
+static struct kvm_errinjct_handler handlers[kvm_errinjct_max];
+static DEFINE_SPINLOCK(handler_lock);
+static LIST_HEAD(open_token_list);
+static DEFINE_SPINLOCK(token_lock);
+static unsigned long *token_bitmap = NULL;
+static int token_max = 1024;
+
+/**
+ * kvm_errinjct_register - Register error injection handler
+ * @opcode: to idenfity the error type to be injected
+ * @handler: function to handler the error type
+ *
+ * Register function handler for the specified type of error.
+ */
+int kvm_errinjct_register(int opcode, kvm_errinjct_func handler)
+{
+ spin_lock(&handler_lock);
+ if (!opcode || !handler) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Invalid argument\n", __func__);
+ return -EINVAL;
+ }
+
+ if (opcode <= kvm_errinjct_min ||
+ opcode >= kvm_errinjct_max) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Opcode %d out of range (%d, %d)\n",
+ __func__, opcode, kvm_errinjct_min, kvm_errinjct_max);
+ return -ERANGE;
+ }
+
+ if (handlers[opcode].handler) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Opcode %d had attached handler\n",
+ __func__, opcode);
+ return -EBUSY;
+ }
+
+ handlers[opcode].opcode = opcode;
+ handlers[opcode].handler = handler;
+ spin_unlock(&handler_lock);
+
+ return 0;
+}
+
+/**
+ * kvm_errinjct_unregister - Unregister error injection handler
+ * @opcode: to identify the error type
+ *
+ * Unregister function handler for the specified type of error.
+ */
+int kvm_errinjct_unregister(int opcode)
+{
+ spin_lock(&handler_lock);
+
+ if (opcode <= kvm_errinjct_min ||
+ opcode >= kvm_errinjct_max) {
+ spin_unlock(&handler_lock);
+ pr_warn("%s: Opcode %d out of range (%d, %d)\n",
+ __func__, opcode, kvm_errinjct_min, kvm_errinjct_max);
+ return -ERANGE;
+ }
+
+ handlers[opcode].opcode = 0;
+ handlers[opcode].handler = NULL;
+ spin_unlock(&handler_lock);
+
+ return 0;
+}
+
+/* Allocate token from the bitmap */
+static int kvm_errinjct_token_alloc(void)
+{
+ int token;
+
+ /* The token bitmap isn't initialized yet */
+ if (unlikely(!token_bitmap)) {
+ unsigned long size;
+ unsigned long *mem;
+
+ size = _ALIGN_UP(token_max, sizeof(unsigned long));
+ mem = kzalloc(size, GFP_KERNEL);
+ if (!mem) {
+ pr_err("%s: Out of memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* In case some body else did it */
+ if (unlikely(token_bitmap))
+ kfree(mem);
+ else
+ token_bitmap = mem;
+ }
+
+ /* Allocate token */
+ do {
+ token = find_next_zero_bit(token_bitmap, token_max, 0);
+ if (token >= token_max)
+ return -ERANGE;
+ } while(test_and_set_bit(token, token_bitmap));
+
+ return token;
+}
+
+/* Free token to the bitmap */
+static void kvm_errinjct_token_free(int token)
+{
+ if (unlikely(!token_bitmap))
+ return;
+ if (unlikely(token >= token_max))
+ return;
+
+ clear_bit(token, token_bitmap);
+}
+
+/* Check if the specified VM has opened token or not */
+static bool kvm_errinjct_token_get(struct kvm *kvm,
+ struct kvm_errinjct_token **token)
+{
+ struct kvm_errinjct_token *t;
+
+ list_for_each_entry(t, &open_token_list, list) {
+ if (t->kvm == kvm) {
+ if (token)
+ *token = t;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Emulation handler for opening token */
+static int kvmppc_errinjct_open(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct kvm_errinjct_token *t;
+ int token;
+ int ret = 0;
+
+ /* Check the parameters */
+ if (args->nargs != 0 || args->nret != 2) {
+ pr_warn("%s: Breaking rule (#args: 0, #rets: 2)\n",
+ __func__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Check if the guest has opened token */
+ spin_lock(&token_lock);
+ if (kvm_errinjct_token_get(vcpu->kvm, NULL)) {
+ ret = -4;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+
+ /* Allocate token */
+ token = kvm_errinjct_token_alloc();
+ if (token > token_max) {
+ ret = -1;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+
+ /* Attach open token */
+ t = kzalloc(sizeof(*t), GFP_KERNEL);
+ if (!t) {
+ ret = -2;
+ pr_warn("%s: Out of memory !\n", __func__);
+ kvm_errinjct_token_free(token);
+ spin_unlock(&token_lock);
+ goto out;
+ }
+ t->kvm = vcpu->kvm;
+ t->token = token;
+ INIT_LIST_HEAD(&t->list);
+ list_add_tail(&t->list, &open_token_list);
+ spin_unlock(&token_lock);
+out:
+ args->rets[1] = ret;
+ return ret == 0 ? token : -1;
+}
+
+/* Emulation handler for closing token */
+static int kvmppc_errinjct_close(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct kvm_errinjct_token *t;
+ int ret = 0;
+
+ /* Check the parameters */
+ if (args->nargs != 1 || args->nret != 1) {
+ pr_warn("%s: Breaking rule (#args: 1, #rets: 1)\n",
+ __func__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Search the opened token */
+ spin_lock(&token_lock);
+ if (!kvm_errinjct_token_get(vcpu->kvm, &t)) {
+ ret = -4;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+
+ /* Detach and free it */
+ list_del(&t->list);
+ kvm_errinjct_token_free(t->token);
+ spin_unlock(&token_lock);
+
+ kfree(t);
+out:
+ return ret;
+}
+
+/*
+ * Emulation handler for error injection. After checking
+ * the arguments, we will dispatch the request to the
+ * dynamically registered handler if possible.
+ */
+static int kvmppc_errinjct(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct kvm_errinjct_token *t;
+ int token, opcode, ret = 0;
+ rtas_arg_t buf;
+
+ /* Check the parameters */
+ if (args->nargs != 3 || args->nret != 1) {
+ pr_warn("%s: Breaking rule (#args: 3, #rets: 1)\n",
+ __func__);
+ ret = -3;
+ goto out;
+ }
+
+ /* Check opcode and buffer */
+ opcode = args->args[0];
+ token = args->args[1];
+ buf = args->args[2];
+ if (opcode < kvm_errinjct_min ||
+ opcode >= kvm_errinjct_max ||
+ (buf & 0x3fful)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Check if the VM has the opened token */
+ spin_lock(&token_lock);
+ if (!kvm_errinjct_token_get(vcpu->kvm, &t) ||
+ t->token != token) {
+ ret = -4;
+ spin_unlock(&token_lock);
+ goto out;
+ }
+ spin_unlock(&token_lock);
+
+ /* Dispatch the request */
+ spin_lock(&handler_lock);
+ if (handlers[opcode].handler)
+ ret = handlers[opcode].handler(vcpu, buf);
+ else
+ ret = -3;
+ spin_unlock(&handler_lock);
+out:
+ return ret;
+}
+
+/**
+ * kvmppc_errinjct_rtas - Common handler for error injection emulation
+ * @vcpu: KVM virtual CPU
+ * @args: RTAS call arguments
+ * @flag: error injection service indicator
+ *
+ * The function is the common handler to emulate error injection RTAS.
+ * All error injection requests will trigger the function and in turn,
+ * the requests will be distributed to individual handler.
+ */
+void kvmppc_errinjct_rtas(struct kvm_vcpu *vcpu,
+ struct rtas_args *args, int flag)
+{
+ int ret = -1;
+
+ /* Parse the requested service */
+ switch (flag) {
+ case kvm_errinjct_open_token:
+ ret = kvmppc_errinjct_open(vcpu, args);
+ break;
+ case kvm_errinjct_close_token:
+ ret = kvmppc_errinjct_close(vcpu, args);
+ break;
+ case kvm_errinjct_errinjct:
+ ret = kvmppc_errinjct(vcpu, args);
+ break;
+ default:
+ pr_warn("%s: Unsupported option %d\n",
+ __func__, flag);
+ }
+
+ /* Update the return value */
+ args->rets[0] = ret;
+}
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c
index 17bdb4a..030b006 100644
--- a/arch/powerpc/kvm/book3s_rtas.c
+++ b/arch/powerpc/kvm/book3s_rtas.c
@@ -18,6 +18,7 @@
#include <asm/rtas.h>
#include <asm/ppc-pci.h>
#include <asm/eeh.h>
+#include <asm/book3s_errinjct.h>
#ifdef CONFIG_KVM_XICS
static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
@@ -123,6 +124,21 @@ KVM_RTAS_EEH_FUNC(configure_pe, eeh_rtas_configure_pe)
#endif /* CONFIG_KVM_EEH */
+#ifdef CONFIG_KVM_ERRINJCT
+
+#define KVM_RTAS_ERRINJCT_FUNC(name, flag) \
+static void kvm_rtas_errinjct_##name(struct kvm_vcpu *vcpu, \
+ struct rtas_args *args) \
+{ \
+ kvmppc_errinjct_rtas(vcpu, args, flag); \
+}
+
+KVM_RTAS_ERRINJCT_FUNC(open_token, kvm_errinjct_open_token);
+KVM_RTAS_ERRINJCT_FUNC(close_token, kvm_errinjct_close_token);
+KVM_RTAS_ERRINJCT_FUNC(errinjct, kvm_errinjct_errinjct);
+
+#endif /* CONFIG_KVM_ERRINJCT */
+
struct rtas_handler {
void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
char *name;
@@ -153,8 +169,19 @@ static struct rtas_handler rtas_handlers[] = {
},
{ .name = "ibm,configure-pe",
.handler = kvm_rtas_eeh_configure_pe
- }
+ },
#endif /* CONFIG_KVM_EEH */
+#ifdef CONFIG_KVM_ERRINJCT
+ { .name = "ibm,open-errinjct",
+ .handler = kvm_rtas_errinjct_open_token
+ },
+ { .name = "ibm,close-errinjct",
+ .handler = kvm_rtas_errinjct_close_token
+ },
+ { .name = "ibm,errinjct",
+ .handler = kvm_rtas_errinjct_errinjct
+ },
+#endif /* CONFIG_KVM_ERRINJCT */
};
struct rtas_token_definition {
--
1.8.3.2
^ permalink raw reply related
* [PATCH 17/22] powerpc/kvm: Connect EEH RTAS emulation backend
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch intends to connect the KVM module with the backend for
EEH RTAS emulation. In turn, we can handle the EEH RTAS services
from the guest.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/kvm_ppc.h | 7 +++++++
arch/powerpc/kvm/book3s_rtas.c | 40 ++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 4096f16..18b51a1 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -29,6 +29,9 @@
#include <linux/kvm_types.h>
#include <linux/kvm_host.h>
#include <linux/bug.h>
+#ifdef CONFIG_KVM_EEH
+#include <asm/rtas.h>
+#endif
#ifdef CONFIG_PPC_BOOK3S
#include <asm/kvm_book3s.h>
#else
@@ -166,6 +169,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
extern int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp);
extern int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu);
extern void kvmppc_rtas_tokens_free(struct kvm *kvm);
+#ifdef CONFIG_KVM_EEH
+extern void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu,
+ struct rtas_args *args, int flag);
+#endif
extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server,
u32 priority);
extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c
index 7a05315..17bdb4a 100644
--- a/arch/powerpc/kvm/book3s_rtas.c
+++ b/arch/powerpc/kvm/book3s_rtas.c
@@ -16,6 +16,8 @@
#include <asm/kvm_ppc.h>
#include <asm/hvcall.h>
#include <asm/rtas.h>
+#include <asm/ppc-pci.h>
+#include <asm/eeh.h>
#ifdef CONFIG_KVM_XICS
static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
@@ -103,6 +105,24 @@ out:
}
#endif /* CONFIG_KVM_XICS */
+#ifdef CONFIG_KVM_EEH
+
+#define KVM_RTAS_EEH_FUNC(name, flag) \
+static void kvm_rtas_eeh_##name(struct kvm_vcpu *vcpu, \
+ struct rtas_args *args) \
+{ \
+ kvmppc_eeh_rtas(vcpu, args, flag); \
+}
+
+KVM_RTAS_EEH_FUNC(set_option, eeh_rtas_set_option)
+KVM_RTAS_EEH_FUNC(set_reset, eeh_rtas_set_slot_reset)
+KVM_RTAS_EEH_FUNC(read_state2, eeh_rtas_read_slot_reset_state2)
+KVM_RTAS_EEH_FUNC(addr_info2, eeh_rtas_get_config_addr_info2)
+KVM_RTAS_EEH_FUNC(error_detail, eeh_rtas_slot_error_detail)
+KVM_RTAS_EEH_FUNC(configure_pe, eeh_rtas_configure_pe)
+
+#endif /* CONFIG_KVM_EEH */
+
struct rtas_handler {
void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
char *name;
@@ -115,6 +135,26 @@ static struct rtas_handler rtas_handlers[] = {
{ .name = "ibm,int-off", .handler = kvm_rtas_int_off },
{ .name = "ibm,int-on", .handler = kvm_rtas_int_on },
#endif
+#ifdef CONFIG_KVM_EEH
+ { .name = "ibm,set-eeh-option",
+ .handler = kvm_rtas_eeh_set_option
+ },
+ { .name = "ibm,set-slot-reset",
+ .handler = kvm_rtas_eeh_set_reset
+ },
+ { .name = "ibm,read-slot-reset-state2",
+ .handler = kvm_rtas_eeh_read_state2
+ },
+ { .name = "ibm,get-config-addr-info2",
+ .handler = kvm_rtas_eeh_addr_info2
+ },
+ { .name = "ibm,slot-error-detail",
+ .handler = kvm_rtas_eeh_error_detail
+ },
+ { .name = "ibm,configure-pe",
+ .handler = kvm_rtas_eeh_configure_pe
+ }
+#endif /* CONFIG_KVM_EEH */
};
struct rtas_token_definition {
--
1.8.3.2
^ permalink raw reply related
* [PATCH 18/22] powerpc/eeh: Avoid event on passed PE
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
If we detects frozen state on PE that has been passed to guest, we
needn't handle it. Instead, we rely on the guest to detect and recover
it. The patch avoid EEH event on the frozen passed PE so that the guest
can have chance to handle that.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh.c | 8 ++++++++
arch/powerpc/platforms/powernv/eeh-ioda.c | 3 ++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 33d683a..a2121e8 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -399,6 +399,14 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
if (ret > 0)
return ret;
+ /*
+ * If the PE has been passed to guest, we won't check the
+ * state. Instead, let the guest handle it if the PE has
+ * been frozen.
+ */
+ if (eeh_pe_passed(pe))
+ return 0;
+
/* If we already have a pending isolation event for this
* slot, we know it's bad already, we don't need to check.
* Do this checking under a lock; as multiple PCI devices
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 1b5982f..03a3ed2 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -890,7 +890,8 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
opal_pci_eeh_freeze_clear(phb->opal_id, frozen_pe_no,
OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
ret = EEH_NEXT_ERR_NONE;
- } else if ((*pe)->state & EEH_PE_ISOLATED) {
+ } else if ((*pe)->state & EEH_PE_ISOLATED ||
+ eeh_pe_passed(*pe)) {
ret = EEH_NEXT_ERR_NONE;
} else {
pr_err("EEH: Frozen PHB#%x-PE#%x (%s) detected\n",
--
1.8.3.2
^ permalink raw reply related
* [PATCH 14/22] powerpc/eeh: Emulate RTAS call ibm, get-config-addr-info2
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,get-config-addr-info2" is being used by guest
to retrieve the corresponding PE number for the specified PCI device.
The patch implements the backend to support the emulation of the
RTAS call.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 59 +++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 031ee8c..4a9c2c7 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -334,6 +334,62 @@ out:
return ret;
}
+static int kvmppc_eeh_get_addr2(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int opcode;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 4 || args->nret != 2) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (4, 2)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Check on the operation code */
+ opcode = args->args[3];
+ if (opcode != 0 && opcode != 1) {
+ pr_warn("%s: opcode %d out of range (0, 1)\n",
+ __func__, opcode);
+ ret = -3;
+ goto out;
+ }
+
+ /* Figure out address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, true, &edev, &pe)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Insure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%d\n",
+ __func__, hose->global_number);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * Fill result according to opcode. We don't differentiate
+ * PCI bus and device sensitive PE here.
+ */
+ if (opcode == 0)
+ args->rets[1] = pe->gaddr.pe_addr;
+ else
+ args->rets[1] = 1;
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -359,6 +415,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_read_slot_reset_state2:
ret = kvmppc_eeh_get_state2(vcpu, args);
break;
+ case eeh_rtas_get_config_addr_info2:
+ ret = kvmppc_eeh_get_addr2(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 16/22] powerpc/eeh: Emulate RTAS call ibm,configure-pe
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,configure-pe" is being used to restore everything
after PE reset. The patch implements the backend to emulate the
RTAS call. In that, we restores BARs for the affected PCI device in
host side because the guest might not have full access to the config
space.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 49 +++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 8934564..a663cd8 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -462,6 +462,52 @@ out:
return ret;
}
+static int kvmppc_eeh_configure_pe(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 3 || args->nret != 1) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (3, 1)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Figure out the address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, false, &edev, &pe)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Make sure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%x\n",
+ __func__, hose->global_number);
+ ret = -3;
+ goto out;
+ }
+
+ /*
+ * The access to PCI config space on VFIO device has some
+ * limitations. Part of PCI config space, including BAR
+ * registers are not readable and writable. So the guest
+ * should have stale values for those registers and we have
+ * to restore them in host side.
+ */
+ eeh_pe_restore_bars(pe);
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -493,6 +539,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_slot_error_detail:
ret = kvmppc_eeh_get_error(vcpu, args);
break;
+ case eeh_rtas_configure_pe:
+ ret = kvmppc_eeh_configure_pe(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 13/22] powerpc/eeh: Emulate RTAS call ibm, read-slot-reset-state2
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,read-slot-reset-state2" is being used to retrieve
the various states of the specified PE, e.g. reset state, frozen DMA,
frozen MMIO etc. The patch implements the backend to emulate the
RTAS call.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 77 +++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 3e38d13..031ee8c 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -260,6 +260,80 @@ out:
return ret;
}
+static int kvmppc_eeh_get_state2(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int result, ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 3 || (args->nret != 4 && args->nret != 5)) {
+ pr_warn("%s: Non-matched argument (%d, %d) - (3, 4/5)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Figure out the address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, false, &edev, &pe)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Make sure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%d\n",
+ __func__, hose->global_number);
+ ret = -3;
+ args->rets[2] = 0;
+ goto out;
+ }
+
+ /*
+ * Mark EEH supported on the PCI device. Otherwise,
+ * the PE state is meaningless to the guest
+ */
+ args->rets[2] = 1;
+
+ /* Call to the IOC dependent function */
+ if (phb->eeh_ops && phb->eeh_ops->get_state) {
+ result = phb->eeh_ops->get_state(pe);
+
+ if (!(result & EEH_STATE_RESET_ACTIVE) &&
+ (result & EEH_STATE_DMA_ENABLED) &&
+ (result & EEH_STATE_MMIO_ENABLED))
+ args->rets[1] = 0;
+ else if (result & EEH_STATE_RESET_ACTIVE)
+ args->rets[1] = 1;
+ else if (!(result & EEH_STATE_RESET_ACTIVE) &&
+ !(result & EEH_STATE_DMA_ENABLED) &&
+ !(result & EEH_STATE_MMIO_ENABLED))
+ args->rets[1] = 2;
+ else if (!(result & EEH_STATE_RESET_ACTIVE) &&
+ (result & EEH_STATE_DMA_ENABLED) &&
+ !(result & EEH_STATE_MMIO_ENABLED))
+ args->rets[1] = 4;
+ else {
+ args->rets[1] = 5;
+ args->rets[3] = 1000;
+ }
+
+ ret = 0;
+ } else {
+ pr_warn("%s: Unsupported request\n",
+ __func__);
+ ret = -3;
+ }
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -282,6 +356,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_set_slot_reset:
ret = kvmppc_eeh_set_reset(vcpu, args);
break;
+ case eeh_rtas_read_slot_reset_state2:
+ ret = kvmppc_eeh_get_state2(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 15/22] powerpc/eeh: Emulate RTAS call ibm,slot-error-detail
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,slot-error-detail" is being used to retrieve the
error log (either permanent or temporary) from the underlying firmware.
The patch implements the backend to emulate the RTAS call.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 75 +++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 4a9c2c7..8934564 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -390,6 +390,78 @@ out:
return ret;
}
+static int kvmppc_eeh_get_error(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ char *log;
+ int guest_log;
+ int len, severity;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 8 || args->nret != 1) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (8, 1)\n",
+ __func__, args->nargs, args->nret);
+ ret = 1;
+ goto out;
+ } else if (args->args[7] != 1 && args->args[7] != 2) {
+ pr_warn("%s: Invalid Log type\n", __func__);
+ ret = 1;
+ goto out;
+ }
+
+ /* Figure out the address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, false, &edev, &pe)) {
+ ret = 1;
+ goto out;
+ }
+
+ /* Make sure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%d\n",
+ __func__, hose->global_number);
+ ret = 1;
+ goto out;
+ }
+
+ /*
+ * Retrieve error log from PE. We don't have cached error
+ * log for one specific PE yet, which need to be figured
+ * out later.
+ */
+ if (phb->eeh_ops && phb->eeh_ops->get_log) {
+ guest_log = args->args[5];
+ len = args->args[6];
+ severity = args->args[7];
+ log = kzalloc(len, GFP_KERNEL);
+ if (!log) {
+ pr_err("%s: Out of memory!\n", __func__);
+ ret = 1;
+ goto out;
+ }
+
+ phb->eeh_ops->get_log(pe, severity, log, len);
+ if (kvm_write_guest(vcpu->kvm, guest_log, log, len)) {
+ pr_warn("%s: Fail pushing log to guest\n",
+ __func__);
+ ret = 1;
+ }
+
+ kfree(log);
+ } else {
+ ret = 1;
+ }
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -418,6 +490,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_get_config_addr_info2:
ret = kvmppc_eeh_get_addr2(vcpu, args);
break;
+ case eeh_rtas_slot_error_detail:
+ ret = kvmppc_eeh_get_error(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 11/22] powerpc/eeh: Emulate RTAS call ibm,set-eeh-option
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,set-eeh-option" is being used to enable/disable
EEH functionality on the specified PE, or enable MMIO/DMA for the
frozen PE. The patch emulates the RTAS call.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 83 +++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index f04b820..1a037fd 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -91,6 +91,86 @@ static int kvmppc_eeh_format_addr(struct kvm_vcpu *vcpu,
return 0;
}
+static int kvmppc_eeh_set_option(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int opcode;
+ bool is_legacy = false;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 4 || args->nret != 1) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (4, 1)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Check on opcode */
+ opcode = args->args[3];
+ if (opcode < EEH_OPT_DISABLE || opcode > EEH_OPT_THAW_DMA) {
+ pr_warn("%s: opcode %d out of range (%d, %d)\n",
+ __func__, opcode, EEH_OPT_DISABLE, EEH_OPT_THAW_DMA);
+ ret = -3;
+ goto out;
+ }
+
+ if (opcode == EEH_OPT_ENABLE)
+ is_legacy = true;
+
+ /* Figure out the address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, is_legacy, &edev, &pe)) {
+ ret = -7;
+ goto out;
+ }
+
+ /* Insure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disabled on PHB#%d\n",
+ __func__, hose->global_number);
+ ret = -7;
+ goto out;
+ }
+
+ /*
+ * The EEH functionality has been enabled on all PEs
+ * by default. So just return success. The same situation
+ * would be applied while we disable EEH functionality.
+ * However, the guest isn't expected to disable that
+ * at all.
+ */
+ if (opcode == EEH_OPT_DISABLE ||
+ opcode == EEH_OPT_ENABLE) {
+ ret = 0;
+ goto out;
+ }
+
+ /*
+ * Call into the IODA dependent backend in order
+ * to enable DMA or MMIO for the indicated PE.
+ */
+ if (phb->eeh_ops && phb->eeh_ops->set_option) {
+ if (phb->eeh_ops->set_option(pe, opcode)) {
+ pr_warn("%s: Failure from backend\n",
+ __func__);
+ ret = -1;
+ }
+ } else {
+ pr_warn("%s: Unsupported request\n",
+ __func__);
+ ret = -7;
+ }
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -107,6 +187,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
/* Parse the requested service */
switch (op) {
+ case eeh_rtas_set_option:
+ ret = kvmppc_eeh_set_option(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 12/22] powerpc/eeh: Emulate RTAS call ibm,set-slot-reset
From: Gavin Shan @ 2014-05-05 1:28 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The RTAS call "ibm,set-slot-reset" is being used to reset one
particular PE, either foundamental or hot reset. The patche intends
to implement the backend to emulate the RTAS call.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 92 +++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index 1a037fd..3e38d13 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -171,6 +171,95 @@ out:
return ret;
}
+static int kvmppc_eeh_set_reset(struct kvm_vcpu *vcpu,
+ struct rtas_args *args)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ struct eeh_vfio_pci_addr addr;
+ int opcode;
+ int ret = 0;
+
+ /* Sanity check on parameter */
+ if (args->nargs != 4 || args->nret != 1) {
+ pr_warn("%s: Non-matched arguments (%d, %d) - (4, 1)\n",
+ __func__, args->nargs, args->nret);
+ ret = -3;
+ goto out;
+ }
+
+ /* Sanity check on opcode */
+ opcode = args->args[3];
+ if (opcode != EEH_RESET_DEACTIVATE &&
+ opcode != EEH_RESET_HOT &&
+ opcode != EEH_RESET_FUNDAMENTAL) {
+ pr_warn("%s: Unsupported opcode %d\n",
+ __func__, opcode);
+ ret = -3;
+ goto out;
+ }
+
+ /* Figure out the address. We always have PE address */
+ if (kvmppc_eeh_format_addr(vcpu, args, &addr, false, &edev, &pe)) {
+ ret = -3;
+ goto out;
+ }
+
+ /* Insure that the EEH stuff has been initialized */
+ hose = pe->phb;
+ phb = hose->private_data;
+ if (!(phb->flags & PNV_PHB_FLAG_EEH)) {
+ pr_warn("%s: EEH disable on PHB#%d\n",
+ __func__, hose->global_number);
+ ret = -7;
+ goto out;
+ }
+
+ /* Call into the IODA dependent backend to do the reset */
+ if (!phb->eeh_ops ||
+ !phb->eeh_ops->set_option ||
+ !phb->eeh_ops->reset) {
+ pr_warn("%s: Unsupported request\n", __func__);
+ ret = -7;
+ } else {
+ /*
+ * The frozen PE might be caused by the mechanism called
+ * PAPR error injection, which is supposed to be one-shot
+ * without "sticky" bit as being stated by the spec. But
+ * the reality isn't that, at least on P7IOC. So we have
+ * to clear that to avoid recrusive error, which fail the
+ * recovery.
+ */
+ if (opcode == EEH_RESET_DEACTIVATE)
+ opal_pci_reset(phb->opal_id,
+ OPAL_PHB_ERROR,
+ OPAL_ASSERT_RESET);
+
+ if (phb->eeh_ops->reset(pe, opcode)) {
+ pr_warn("%s: Failure from backend\n",
+ __func__);
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * The PE is still in frozen state and we need clear that.
+ * It's good to clear frozen state after deassert to avoid
+ * messy IO access during reset, which might cause recrusive
+ * frozen PE.
+ */
+ if (opcode == EEH_RESET_DEACTIVATE) {
+ phb->eeh_ops->set_option(pe, EEH_OPT_THAW_MMIO);
+ phb->eeh_ops->set_option(pe, EEH_OPT_THAW_DMA);
+ }
+ }
+
+out:
+ return ret;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
@@ -190,6 +279,9 @@ void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
case eeh_rtas_set_option:
ret = kvmppc_eeh_set_option(vcpu, args);
break;
+ case eeh_rtas_set_slot_reset:
+ ret = kvmppc_eeh_set_reset(vcpu, args);
+ break;
default:
pr_warn("%s: Unsupported EEH RTAS service#%d\n",
__func__, op);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 09/22] powerpc/powernv: EEH RTAS emulation backend
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The implementation of EEH RTAS emulation is split up into 2 layers:
kvm and powernv platform layer. The KVM layer is quite simple to
dispatch RTAS requests from guest to powernv platform layer. After
that, the powernv platform layer takes care of the details, process
the request and return result to kvm layer.
The patch implements the infrastructure of powernv platform layer
for EEH RTAS emulation.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 18 +++++++++
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/eeh-rtas.c | 64 +++++++++++++++++++++++++++++++
3 files changed, 83 insertions(+)
create mode 100644 arch/powerpc/platforms/powernv/eeh-rtas.c
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 677c719..7384dee 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -49,6 +49,24 @@ struct device_node;
#define EEH_PE_RST_SETTLE_TIME 1800
#ifdef CONFIG_KVM_EEH
+
+/*
+ * Those EEH RTAS operations are going to be emulated.
+ * According to PAPR specification, there're much more
+ * operations. However, the following RTAS operations
+ * are enough for EEH in guest to work properly.
+ */
+enum {
+ eeh_rtas_first = 0,
+ eeh_rtas_set_option = 0,
+ eeh_rtas_set_slot_reset = 1,
+ eeh_rtas_read_slot_reset_state2 = 2,
+ eeh_rtas_get_config_addr_info2 = 3,
+ eeh_rtas_slot_error_detail = 4,
+ eeh_rtas_configure_pe = 5,
+ eeh_rtas_last = 5
+};
+
struct eeh_vfio_pci_addr {
struct kvm *kvm; /* KVM identifier */
unsigned int buid_hi; /* PHB BUID high */
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 63cebb9..d8ea670 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -6,5 +6,6 @@ obj-y += opal-msglog.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o
+obj-$(CONFIG_KVM_EEH) += eeh-rtas.o
obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
new file mode 100644
index 0000000..fded461
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -0,0 +1,64 @@
+/*
+ * The file intends to implement emulation for EEH related RTAS services,
+ * which is expected to be done inside hypervisor. The specific RTAS
+ * service is identified by its unique token. Currently, the tokens
+ * are assigned by QEMU in a dynamic way and the dedicated hcall (0xf000)
+ * was introduced for the purpose of RTAS emulation either in hypervisor
+ * or QEMU.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2014.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include <asm/rtas.h>
+#include <asm/eeh.h>
+#include <asm/eeh_event.h>
+#include <asm/io.h>
+#include <asm/iommu.h>
+#include <asm/opal.h>
+#include <asm/msi_bitmap.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+#include <asm/tce.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+/**
+ * kvmppc_eeh_rtas - Backend for EEH RTAS emulation
+ * @vcpu: KVM virtual CPU
+ * @args: RTAS parameter
+ * @op: identifier of the specific EEH RTAS service
+ *
+ * The function will be called when the hypervisor receives emulation
+ * request on EEH RTAS from guest. Accordingly, it will dispatch to
+ * specific functions to handle the request.
+ */
+void kvmppc_eeh_rtas(struct kvm_vcpu *vcpu, struct rtas_args *args, int op)
+{
+ int ret = -3;
+
+ /* Parse the requested service */
+ switch (op) {
+ default:
+ pr_warn("%s: Unsupported EEH RTAS service#%d\n",
+ __func__, op);
+ }
+
+ args->rets[0] = ret;
+}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 10/22] powerpc/eeh: Introduce kvmppc_eeh_format_addr()
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The guest will pass 2 kinds of addresses: tranditional bus/device/
function combo, and guest sensitive PE address returned from host.
The patch introduces function kvmppc_eeh_format_addr() to convert
the guest address information from RTAS call argument (struct rtas_args)
and retrieve the EEH device or PE instance if necessary. The function
will be used by subsequent patches.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/eeh-rtas.c | 52 +++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/eeh-rtas.c b/arch/powerpc/platforms/powernv/eeh-rtas.c
index fded461..f04b820 100644
--- a/arch/powerpc/platforms/powernv/eeh-rtas.c
+++ b/arch/powerpc/platforms/powernv/eeh-rtas.c
@@ -39,6 +39,58 @@
#include "powernv.h"
#include "pci.h"
+/*
+ * Guest is passing 2 types of addresses. First one would be
+ * traditional bus/device/function combo and another one is
+ * PE address, which starts from 0x10000
+ */
+static int kvmppc_eeh_format_addr(struct kvm_vcpu *vcpu,
+ struct rtas_args *args,
+ struct eeh_vfio_pci_addr *addr,
+ bool is_legacy,
+ struct eeh_dev **pedev,
+ struct eeh_pe **ppe)
+{
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+
+ if (pedev) *pedev = NULL;
+ if (ppe) *ppe = NULL;
+
+ addr->kvm = vcpu->kvm;
+ addr->buid_hi = args->args[1];
+ addr->buid_lo = args->args[2];
+ if (is_legacy) {
+ addr->bus = (args->args[0] >> 16) & 0xFF;
+ addr->devfn = (args->args[0] >> 8) & 0xFF;
+
+ edev = eeh_vfio_dev_get(addr);
+ if (!edev) {
+ pr_warn("%s: Can't find VFIO device "
+ "(%08x-%08x-%02x-%02x)\n",
+ __func__, addr->buid_hi,
+ addr->buid_lo, addr->bus, addr->devfn);
+ return -EEXIST;
+ }
+
+ if (pedev) *pedev = edev;
+ if (ppe) *ppe = edev->pe;
+ } else {
+ addr->pe_addr = args->args[0];
+ pe = eeh_vfio_pe_get(addr);
+ if (!pe) {
+ pr_warn("%s: Can't find PE (%08x-%08x-%x)\n",
+ __func__, addr->buid_hi,
+ addr->buid_lo, addr->pe_addr);
+ return -EEXIST;
+ }
+
+ if (ppe) *ppe = pe;
+ }
+
+ return 0;
+}
+
/**
* kvmppc_eeh_rtas - Backend for EEH RTAS emulation
* @vcpu: KVM virtual CPU
--
1.8.3.2
^ permalink raw reply related
* [PATCH 07/22] powerpc/eeh: Function to tear down address mapping
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces function kvm_vfio_eeh_dev_unmap(), which is
expected to be called on IOCTL command issued to the VM device, in
order to tear down the address mapping for VFIO PCI device.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh_pe.c | 82 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/kvm_host.h | 7 ++++
2 files changed, 89 insertions(+)
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 200cd5a..8398efc 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -420,6 +420,88 @@ int kvm_vfio_eeh_dev_map(struct kvm *kvm, int domain,
}
EXPORT_SYMBOL_GPL(kvm_vfio_eeh_dev_map);
+ /**
+ * kvm_vfio_eeh_dev_unmap - Tear down address mapping for VFIO PCI device
+ *
+ * @kvm: VM descriptor
+ * @domain: host domain
+ * @bdn: host bus/device/function number
+ *
+ * Tear down address mapping for VFIO PCI device.
+ */
+int kvm_vfio_eeh_dev_unmap(struct kvm *kvm, int domain, int bdn)
+{
+ struct pci_bus *bus;
+ struct pci_dev *dev;
+ struct eeh_pe *pe;
+ struct eeh_dev *edev, *tmp;
+ int bus_no, devfn;
+ bool passed;
+
+ /* Find the PCI device in host side */
+ bus_no = (bdn >> 8) & 0xff;
+ devfn = bdn & 0xff;
+ bus = pci_find_bus(domain, bus_no);
+ if (!bus) {
+ pr_warn("%s: PCI bus %04x:%02x not found\n",
+ __func__, domain, bus_no);
+ return -ENODEV;
+ }
+
+ dev = pci_get_slot(bus, devfn);
+ if (!dev) {
+ pr_warn("%s: PCI device %04x:%02x:%02x.%01x not found\n",
+ __func__, domain, bus_no,
+ PCI_SLOT(devfn), PCI_FUNC(devfn));
+ return -ENODEV;
+ }
+
+ /* Mark the EEH device as non-passed */
+ edev = pci_dev_to_eeh_dev(dev);
+ if (!edev) {
+ pr_warn("%s: No EEH dev for PCI device %s\n",
+ __func__, pci_name(dev));
+ return -ENODEV;
+ } else if (!eeh_dev_passed(edev) ||
+ !eeh_pe_passed(edev->pe) ||
+ edev->gaddr.kvm != kvm ||
+ edev->pe->gaddr.kvm != kvm) {
+ pr_warn("%s: Non-passsed PCI dev %s or PE\n",
+ __func__, pci_name(dev));
+ return 0;
+ }
+ memset(&edev->gaddr, 0, sizeof(edev->gaddr));
+ eeh_dev_set_passed(edev, false);
+ pr_debug("EEH: Host PCI device %s returned\n",
+ pci_name(dev));
+
+ /*
+ * Mark the PE as non-passed if all PCI devices
+ * except P2P bridges are non-passed.
+ */
+ pe = edev->pe;
+ passed = false;
+ eeh_pe_for_each_dev(pe, edev, tmp) {
+ dev = eeh_dev_to_pci_dev(edev);
+ if (dev && dev->subordinate)
+ continue;
+ if (eeh_dev_passed(edev)) {
+ passed = true;
+ break;
+ }
+ }
+
+ if (!passed) {
+ memset(&pe->gaddr, 0, sizeof(pe->gaddr));
+ eeh_pe_set_passed(pe, false);
+ pr_debug("EEH: PHB#%x-PE#%x returned to host\n",
+ pe->phb->global_number, pe->addr);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_vfio_eeh_dev_unmap);
+
static void *__kvmppc_eeh_vfio_release(void *data, void *flag)
{
struct eeh_pe *pe = (struct eeh_pe *)data;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 294ce48..520b3d0 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1106,14 +1106,21 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
#ifdef CONFIG_KVM_EEH
typedef int (*kvm_vfio_dev_eeh_map)(struct kvm *kvm, int domain,
int bdn, unsigned long buid, int gbdn);
+typedef int (*kvm_vfio_dev_eeh_unmap)(struct kvm *kvm, int domain, int bdn);
extern int kvm_vfio_eeh_dev_map(struct kvm *kvm, int domain,
int bdn, unsigned long buid, int gbdn);
+extern int kvm_vfio_eeh_dev_unmap(struct kvm *kvm, int domain, int bdn);
#else
static inline int kvm_vfio_eeh_dev_map(struct kvm *kvm, int domain,
int bdn, unsigned long buid, int gbdn)
{
return 0;
}
+
+static inline int kvm_vfio_eeh_dev_unmap(struct kvm *kvm, int domain, int bdn)
+{
+ return 0;
+}
#endif /* CONFIG_KVM_EEH */
#endif
--
1.8.3.2
^ permalink raw reply related
* [PATCH 08/22] kvm: Address mapping for VFIO device
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The address (domain/bus/slot/function) looks different from the
perspective of host and guest. We have to setup the mapping for
EEH and tear it down accordingly. The patch introduces additional
attributes to KVM VFIO device for address mapping or unmapping.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kvm/Kconfig | 1 +
arch/powerpc/kvm/Makefile | 3 +++
include/uapi/linux/kvm.h | 10 ++++++++
virt/kvm/vfio.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 743d2d9..6764fc5 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -64,6 +64,7 @@ config KVM_BOOK3S_64
select KVM_BOOK3S_64_HANDLER
select KVM
select KVM_BOOK3S_PR_POSSIBLE if !KVM_BOOK3S_HV_POSSIBLE
+ select KVM_VFIO if VFIO
---help---
Support running unmodified book3s_64 and book3s_32 guest kernels
in virtual machines on book3s_64 host processors.
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index ce569b6..673038d 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -97,6 +97,9 @@ endif
kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
book3s_xics.o
+kvm-book3s_64-objs-$(CONFIG_KVM_VFIO) += \
+ $(addprefix ../../../virt/kvm/, vfio.o)
+
kvm-book3s_64-module-objs += \
$(KVM)/kvm_main.o \
$(KVM)/eventfd.o \
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index a8f4ee5..97b4d1e 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -932,9 +932,19 @@ struct kvm_device_attr {
#define KVM_DEV_VFIO_GROUP 1
#define KVM_DEV_VFIO_GROUP_ADD 1
#define KVM_DEV_VFIO_GROUP_DEL 2
+#define KVM_DEV_VFIO_DEV 2
+#define KVM_DEV_VFIO_DEV_EEH_MAP 1
+#define KVM_DEV_VFIO_DEV_EEH_UNMAP 2
#define KVM_DEV_TYPE_ARM_VGIC_V2 5
#define KVM_DEV_TYPE_FLIC 6
+struct kvm_vfio_pci_addr {
+ __u32 domain; /* Host PHB domain */
+ __u32 bdn; /* Host bus/dev/func */
+ __u64 gbuid; /* Guet PHB BUID */
+ __u32 gbdn; /* Guest bus/dev/func */
+};
+
/*
* ioctls for VM fds
*/
diff --git a/virt/kvm/vfio.c b/virt/kvm/vfio.c
index ba1a93f..778015d 100644
--- a/virt/kvm/vfio.c
+++ b/virt/kvm/vfio.c
@@ -28,6 +28,10 @@ struct kvm_vfio {
struct list_head group_list;
struct mutex lock;
bool noncoherent;
+#ifdef CONFIG_KVM_EEH
+ kvm_vfio_dev_eeh_map eeh_map;
+ kvm_vfio_dev_eeh_unmap eeh_unmap;
+#endif
};
static struct vfio_group *kvm_vfio_group_get_external_user(struct file *filep)
@@ -201,12 +205,53 @@ static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
return -ENXIO;
}
+static int kvm_vfio_set_dev(struct kvm_device *dev, long attr, u64 arg)
+{
+ struct kvm_vfio *kv = dev->private;
+ struct kvm_vfio_pci_addr addr;
+ int ret = -ENXIO;
+
+ switch (attr) {
+#ifdef CONFIG_KVM_EEH
+ case KVM_DEV_VFIO_DEV_EEH_MAP:
+ if (copy_from_user(&addr, (void __user *)arg, sizeof(addr))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (kv->eeh_map)
+ ret = kv->eeh_map(dev->kvm, addr.domain,
+ addr.bdn, addr.gbuid, addr.gbdn);
+ else
+ ret = 0;
+
+ break;
+ case KVM_DEV_VFIO_DEV_EEH_UNMAP:
+ if (copy_from_user(&addr, (void __user *)arg, sizeof(addr))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (kv->eeh_unmap)
+ ret = kv->eeh_unmap(dev->kvm, addr.domain, addr.bdn);
+ else
+ ret = 0;
+
+ break;
+#endif
+ }
+
+ return ret;
+}
+
static int kvm_vfio_set_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
switch (attr->group) {
case KVM_DEV_VFIO_GROUP:
return kvm_vfio_set_group(dev, attr->attr, attr->addr);
+ case KVM_DEV_VFIO_DEV:
+ return kvm_vfio_set_dev(dev, attr->attr, attr->addr);
}
return -ENXIO;
@@ -224,6 +269,16 @@ static int kvm_vfio_has_attr(struct kvm_device *dev,
}
break;
+ case KVM_DEV_VFIO_DEV:
+ switch (attr->attr) {
+#ifdef CONFIG_KVM_EEH
+ case KVM_DEV_VFIO_DEV_EEH_MAP:
+ case KVM_DEV_VFIO_DEV_EEH_UNMAP:
+ return 0;
+#endif
+ }
+
+ break;
}
return -ENXIO;
@@ -262,7 +317,10 @@ static int kvm_vfio_create(struct kvm_device *dev, u32 type)
INIT_LIST_HEAD(&kv->group_list);
mutex_init(&kv->lock);
-
+#ifdef CONFIG_KVM_EEH
+ kv->eeh_map = kvm_vfio_eeh_dev_map;
+ kv->eeh_unmap = kvm_vfio_eeh_dev_unmap;
+#endif
dev->private = kv;
return 0;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 03/22] powerpc/eeh: Search EEH device by guest address
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces function eeh_vfio_dev_get() to search the EEH
device according to its guest address, which is made up of VM indicator,
PHB BUID, bus, slot and function number. The function is useful in the
backends for EEH RTAS emulation.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 6 ++++++
arch/powerpc/kernel/eeh_pe.c | 45 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 8bfb167..b12e3e9 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -384,6 +384,12 @@ static inline void eeh_remove_device(struct pci_dev *dev) { }
#define EEH_IO_ERROR_VALUE(size) (-1UL)
#endif /* CONFIG_EEH */
+
+#ifdef CONFIG_KVM_EEH
+struct eeh_dev *eeh_vfio_dev_get(struct eeh_vfio_pci_addr *addr);
+
+#endif /* CONFIG_KVM_EEH */
+
#ifdef CONFIG_PPC64
/*
* MMIO read/write operations with EEH support.
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index fbd01eb..dba7c82 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -248,6 +248,51 @@ struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
return pe;
}
+#ifdef CONFIG_KVM_EEH
+static void *__eeh_vfio_dev_get(void *data, void *flag)
+{
+ struct eeh_pe *pe = (struct eeh_pe *)data;
+ struct eeh_vfio_pci_addr *addr = (struct eeh_vfio_pci_addr *)flag;
+ struct eeh_dev *edev, *tmp;
+
+ eeh_pe_for_each_dev(pe, edev, tmp) {
+ if (!eeh_dev_passed(edev))
+ continue;
+
+ /* Comparing the address in the guest */
+ if (addr->kvm == edev->gaddr.kvm &&
+ addr->buid_hi == edev->gaddr.buid_hi &&
+ addr->buid_lo == edev->gaddr.buid_lo &&
+ addr->bus == edev->gaddr.bus &&
+ addr->devfn == edev->gaddr.devfn)
+ return edev;
+ }
+
+ return NULL;
+}
+
+/**
+ * eeh_vfio_dev_get - Search EEH device based on guest's address
+ * @addr: EEH device guest address
+ *
+ * Search the EEH device according to its guest's address, which
+ * is made up of PHB BUID, and PCI config address.
+ */
+struct eeh_dev *eeh_vfio_dev_get(struct eeh_vfio_pci_addr *addr)
+{
+ struct eeh_pe *root;
+ struct eeh_dev *edev;
+
+ list_for_each_entry(root, &eeh_phb_pe, child) {
+ edev = eeh_pe_traverse(root, __eeh_vfio_dev_get, addr);
+ if (edev)
+ return edev;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_KVM_EEH */
+
/**
* eeh_pe_get_parent - Retrieve the parent PE
* @edev: EEH device
--
1.8.3.2
^ permalink raw reply related
* [PATCH 06/22] powerpc/eeh: Function for address mapping
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces function kvm_vfio_eeh_dev_map(), which is
expected to be called on IOCTL command issued to the VM device, in
order to build the address mapping for VFIO PCI device.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/kernel/eeh_pe.c | 88 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/kvm_host.h | 14 +++++++
2 files changed, 102 insertions(+)
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 9e73188..200cd5a 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -332,6 +332,94 @@ struct eeh_dev *eeh_vfio_dev_get(struct eeh_vfio_pci_addr *addr)
return NULL;
}
+/**
+ * kvm_vfio_eeh_dev_map - Build the address mapping for VFIO device
+ *
+ * @kvm: VM descriptor
+ * @domain: host domain of PCI device
+ * @bdn: host bus/device/function number
+ * @buid: BUID of guest PHB
+ * @gbdn: guest bus/device/function number
+ *
+ * Build the address mapping between host and guest deivce. It's called
+ * while passing through PCI device from host to guest.
+ */
+int kvm_vfio_eeh_dev_map(struct kvm *kvm, int domain,
+ int bdn, unsigned long buid, int gbdn)
+{
+ struct pci_bus *bus, *pe_bus;
+ struct pci_dev *dev;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ int bus_no, devfn;
+
+ /* Find the PCI device in host side */
+ bus_no = (bdn >> 8) & 0xff;
+ devfn = bdn & 0xff;
+ bus = pci_find_bus(domain, bus_no);
+ if (!bus) {
+ pr_warn("%s: PCI bus %04x:%02x not found\n",
+ __func__, domain, bus_no);
+ return -ENODEV;
+ }
+
+ dev = pci_get_slot(bus, devfn);
+ if (!dev) {
+ pr_warn("%s: PCI device %04x:%02x:%02x.%01x not found\n",
+ __func__, domain, bus_no,
+ PCI_SLOT(devfn), PCI_FUNC(devfn));
+ return -ENODEV;
+ }
+
+ /*
+ * Mark the EEH device as passed. We allow dynamic change
+ * on the address mapping.
+ */
+ edev = pci_dev_to_eeh_dev(dev);
+ if (!edev) {
+ pr_warn("%s: No EEH dev for PCI device %s\n",
+ __func__, pci_name(dev));
+ return -ENODEV;
+ }
+
+ /*
+ * The PE configuration address is exactly PCI config address
+ * of the PE primary bus. That has format 00BBSS00 defined in
+ * PAPR.
+ */
+ pe = edev->pe;
+ if (!eeh_pe_passed(pe)) {
+ pe_bus = eeh_pe_bus_get(pe);
+ BUG_ON(!pe_bus);
+
+ pe->gaddr.kvm = kvm;
+ pe->gaddr.buid_hi = BUID_HI(buid);
+ pe->gaddr.buid_lo = BUID_LO(buid);
+ pe->gaddr.pe_addr = pe_bus->number << 16;
+ eeh_pe_set_passed(pe, true);
+ } else if (pe->gaddr.kvm != kvm ||
+ pe->gaddr.buid_hi != BUID_HI(buid) ||
+ pe->gaddr.buid_lo != BUID_LO(buid)) {
+ pr_warn("%s: Mismatched VM or PHB on passing %s\n",
+ __func__, pci_name(dev));
+ return -EINVAL;
+ }
+
+ edev->gaddr.kvm = kvm;
+ edev->gaddr.buid_hi = BUID_HI(buid);
+ edev->gaddr.buid_lo = BUID_LO(buid);
+ edev->gaddr.bus = (gbdn >> 8) & 0xff;
+ edev->gaddr.devfn = gbdn & 0xff;
+ eeh_dev_set_passed(edev, true);
+
+ pr_debug("EEH: Host PCI device %s passed to %lx-%02x:%02x.%01x\n",
+ pci_name(dev), buid, (gbdn >> 8) & 0xff,
+ PCI_SLOT(gbdn & 0xff), PCI_FUNC(gbdn & 0xff));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_vfio_eeh_dev_map);
+
static void *__kvmppc_eeh_vfio_release(void *data, void *flag)
{
struct eeh_pe *pe = (struct eeh_pe *)data;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7d21cf9..294ce48 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1102,5 +1102,19 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
{
}
#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
+
+#ifdef CONFIG_KVM_EEH
+typedef int (*kvm_vfio_dev_eeh_map)(struct kvm *kvm, int domain,
+ int bdn, unsigned long buid, int gbdn);
+extern int kvm_vfio_eeh_dev_map(struct kvm *kvm, int domain,
+ int bdn, unsigned long buid, int gbdn);
+#else
+static inline int kvm_vfio_eeh_dev_map(struct kvm *kvm, int domain,
+ int bdn, unsigned long buid, int gbdn)
+{
+ return 0;
+}
+#endif /* CONFIG_KVM_EEH */
+
#endif
--
1.8.3.2
^ permalink raw reply related
* [PATCH 04/22] powerpc/eeh: Search EEH PE by guest address
From: Gavin Shan @ 2014-05-05 1:27 UTC (permalink / raw)
To: linuxppc-dev, kvm, kvm-ppc; +Cc: aik, alex.williamson, qiudayu, Gavin Shan
In-Reply-To: <1399253291-3975-1-git-send-email-gwshan@linux.vnet.ibm.com>
The patch introduces function eeh_vfio_pe_get() to search the EEH
PE according to its guest address, which is made up of KVM indicator,
PHB ID and PE configuration address. The function will be useful in
backends for EEH RTAS emulation.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 1 +
arch/powerpc/kernel/eeh_pe.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index b12e3e9..3807167 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -387,6 +387,7 @@ static inline void eeh_remove_device(struct pci_dev *dev) { }
#ifdef CONFIG_KVM_EEH
struct eeh_dev *eeh_vfio_dev_get(struct eeh_vfio_pci_addr *addr);
+struct eeh_pe *eeh_vfio_pe_get(struct eeh_vfio_pci_addr *addr);
#endif /* CONFIG_KVM_EEH */
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index dba7c82..1bd7b1f 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -249,6 +249,46 @@ struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
}
#ifdef CONFIG_KVM_EEH
+static void *__eeh_vfio_pe_get(void *data, void *flag)
+{
+ struct eeh_pe *pe = (struct eeh_pe *)data;
+ struct eeh_vfio_pci_addr *addr = (struct eeh_vfio_pci_addr *)flag;
+
+ if (!eeh_pe_passed(pe))
+ return NULL;
+
+ /* Comparing the address */
+ if (addr->kvm == pe->gaddr.kvm &&
+ addr->buid_hi == pe->gaddr.buid_hi &&
+ addr->buid_lo == pe->gaddr.buid_lo &&
+ addr->pe_addr == pe->gaddr.pe_addr)
+ return pe;
+
+ return NULL;
+}
+
+/**
+ * eeh_vfio_pe_get - Search EEH PE based on guest's address
+ * @addr: EEH PE guest address
+ *
+ * Search the EEH PE according to the guest address, which
+ * is made up of VM indicator, PHB BUID, and PE configuration
+ * address.
+ */
+struct eeh_pe *eeh_vfio_pe_get(struct eeh_vfio_pci_addr *addr)
+{
+ struct eeh_pe *root;
+ struct eeh_pe *pe;
+
+ list_for_each_entry(root, &eeh_phb_pe, child) {
+ pe = eeh_pe_traverse(root, __eeh_vfio_pe_get, addr);
+ if (pe)
+ return pe;
+ }
+
+ return NULL;
+}
+
static void *__eeh_vfio_dev_get(void *data, void *flag)
{
struct eeh_pe *pe = (struct eeh_pe *)data;
--
1.8.3.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox