* linux-next: manual merge of the powerpc tree with the asm-generic tree
From: Stephen Rothwell @ 2018-03-20 23:26 UTC (permalink / raw)
To: Michael Ellerman, Benjamin Herrenschmidt, PowerPC, Arnd Bergmann
Cc: Linux-Next Mailing List, Linux Kernel Mailing List, Matt Brown
[-- Attachment #1: Type: text/plain, Size: 2115 bytes --]
Hi all,
Today's linux-next merge of the powerpc tree got a conflict in:
lib/raid6/test/Makefile
between commit:
fa523d54a7eb ("raid: remove tile specific raid6 implementation")
from the asm-generic tree and commit:
751ba79cc552 ("lib/raid6/altivec: Add vpermxor implementation for raid6 Q syndrome")
from the powerpc tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
--
Cheers,
Stephen Rothwell
diff --cc lib/raid6/test/Makefile
index fabc477b1417,5050e270c06b..000000000000
--- a/lib/raid6/test/Makefile
+++ b/lib/raid6/test/Makefile
@@@ -45,12 -45,17 +45,14 @@@ else ifeq ($(HAS_NEON),yes
CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1
else
HAS_ALTIVEC := $(shell printf '\#include <altivec.h>\nvector int a;\n' |\
- gcc -c -x c - >&/dev/null && \
- rm ./-.o && echo yes)
+ gcc -c -x c - >/dev/null && rm ./-.o && echo yes)
ifeq ($(HAS_ALTIVEC),yes)
- OBJS += altivec1.o altivec2.o altivec4.o altivec8.o
+ CFLAGS += -I../../../arch/powerpc/include
+ CFLAGS += -DCONFIG_ALTIVEC
+ OBJS += altivec1.o altivec2.o altivec4.o altivec8.o \
+ vpermxor1.o vpermxor2.o vpermxor4.o vpermxor8.o
endif
endif
-ifeq ($(ARCH),tilegx)
-OBJS += tilegx8.o
-endif
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
@@@ -117,7 -137,8 +131,7 @@@ tables.c: mktable
./mktables > tables.c
clean:
- rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c neon*.c tables.c raid6test
+ rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c vpermxor*.c neon*.c tables.c raid6test
- rm -f tilegx*.c
spotless: clean
rm -f *~
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH v3 8/9] powerpc/eeh: Factor out common code eeh_reset_device()
From: Sam Bobroff @ 2018-03-21 2:06 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <557d0231968935f1212c7b500f39363a47cb6acc.1521427331.git.sam.bobroff@au1.ibm.com>
The caller will always pass NULL for 'rmv_data' when
'eeh_aware_driver' is true, so the first two calls to
eeh_pe_dev_traverse() can be combined without changing behaviour as
can the two arms of the final 'if' block.
This should not change behaviour.
Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
---
====== v2 -> v3: ======
Corrected two missed cases of eeh_aware_driver -> driver_eeh_aware.
arch/powerpc/kernel/eeh_driver.c | 32 ++++++++++----------------------
1 file changed, 10 insertions(+), 22 deletions(-)
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 93fc22e791fa..43ceb6263cd8 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -647,16 +647,12 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
* into pci_hp_add_devices().
*/
eeh_pe_state_mark(pe, EEH_PE_KEEP);
- if (!driver_eeh_aware) {
- if (pe->type & EEH_PE_VF) {
- eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
- } else {
- pci_lock_rescan_remove();
- pci_hp_remove_devices(bus);
- pci_unlock_rescan_remove();
- }
- } else {
+ if (driver_eeh_aware || (pe->type & EEH_PE_VF)) {
eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data);
+ } else {
+ pci_lock_rescan_remove();
+ pci_hp_remove_devices(bus);
+ pci_unlock_rescan_remove();
}
/*
@@ -691,8 +687,9 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
* the device up before the scripts have taken it down,
* potentially weird things happen.
*/
- if (!driver_eeh_aware) {
- pr_info("EEH: Sleep 5s ahead of complete hotplug\n");
+ if (!driver_eeh_aware || rmv_data->removed) {
+ pr_info("EEH: Sleep 5s ahead of %s hotplug\n",
+ (driver_eeh_aware ? "partial" : "complete"));
ssleep(5);
/*
@@ -705,19 +702,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
if (pe->type & EEH_PE_VF) {
eeh_add_virt_device(edev, NULL);
} else {
- eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
+ if (!driver_eeh_aware)
+ eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
pci_hp_add_devices(bus);
}
- } else if (rmv_data->removed) {
- pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
- ssleep(5);
-
- edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
- eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
- if (pe->type & EEH_PE_VF)
- eeh_add_virt_device(edev, NULL);
- else
- pci_hp_add_devices(bus);
}
eeh_pe_state_clear(pe, EEH_PE_KEEP);
--
2.16.1.74.g9b0b1f47b
^ permalink raw reply related
* [PATCH] powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened
From: Nicholas Piggin @ 2018-03-21 2:22 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin, Benjamin Herrenschmidt
force_external_irq_replay() can be called in the do_IRQ path with
interrupts hard enabled and soft disabled if may_hard_irq_enable() set
MSR[EE]=1. It updates local_paca->irq_happened with a load, modify,
store sequence. If a maskable interrupt hits during this sequence, it
will go to the masked handler to be marked pending in irq_happened.
This update will be lost when the interrupt returns and the store
instruction executes. This can result in unpredictable latencies,
timeouts, lockups, etc.
Fix this by ensuring hard interrupts are disabled before modifying
irq_happened.
This could cause any maskable asynchronous interrupt to get lost, but
it was noticed on P9 SMP system doing RDMA NVMe target over 100GbE,
so very high external interrupt rate and high IPI rate. The hang was
bisected down to enabling doorbell interrupts for IPIs. These provided
an interrupt type that could run at high rates in the do_IRQ path,
stressing the race.
Fixes: 1d607bb3bd ("powerpc/irq: Add mechanism to force a replay of interrupts")
Reported-by: Carol L. Soto <clsoto@us.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
This has survived stress testing quite well so far, may need a little
more testing but I'd like to post it now to get some more comments.
We can optimise the mtmsr a bit more (e.g., skip it if interrupts are
already disabled or EE alrady set), but I've got some other patches
pending which change things there slightly, so I prefer to have this
minimal fix now, then make such changes upstream later.
---
arch/powerpc/kernel/irq.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index f88038847790..061aa0f47bb1 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -476,6 +476,14 @@ void force_external_irq_replay(void)
*/
WARN_ON(!arch_irqs_disabled());
+ /*
+ * Interrupts must always be hard disabled before irq_happened is
+ * modified (to prevent lost update in case of interrupt between
+ * load and store).
+ */
+ __hard_irq_disable();
+ local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+
/* Indicate in the PACA that we have an interrupt to replay */
local_paca->irq_happened |= PACA_IRQ_EE;
}
--
2.16.1
^ permalink raw reply related
* Re: [PATCH] powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened
From: Benjamin Herrenschmidt @ 2018-03-21 2:32 UTC (permalink / raw)
To: Nicholas Piggin, linuxppc-dev
In-Reply-To: <20180321022228.9606-1-npiggin@gmail.com>
On Wed, 2018-03-21 at 12:22 +1000, Nicholas Piggin wrote:
> force_external_irq_replay() can be called in the do_IRQ path with
> interrupts hard enabled and soft disabled if may_hard_irq_enable() set
> MSR[EE]=1. It updates local_paca->irq_happened with a load, modify,
> store sequence. If a maskable interrupt hits during this sequence, it
> will go to the masked handler to be marked pending in irq_happened.
> This update will be lost when the interrupt returns and the store
> instruction executes. This can result in unpredictable latencies,
> timeouts, lockups, etc.
>
> Fix this by ensuring hard interrupts are disabled before modifying
> irq_happened.
>
> This could cause any maskable asynchronous interrupt to get lost, but
> it was noticed on P9 SMP system doing RDMA NVMe target over 100GbE,
> so very high external interrupt rate and high IPI rate. The hang was
> bisected down to enabling doorbell interrupts for IPIs. These provided
> an interrupt type that could run at high rates in the do_IRQ path,
> stressing the race.
>
> Fixes: 1d607bb3bd ("powerpc/irq: Add mechanism to force a replay of interrupts")
> Reported-by: Carol L. Soto <clsoto@us.ibm.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
Nice one. We need that back into the distros asap.
> This has survived stress testing quite well so far, may need a little
> more testing but I'd like to post it now to get some more comments.
>
> We can optimise the mtmsr a bit more (e.g., skip it if interrupts are
> already disabled or EE alrady set), but I've got some other patches
> pending which change things there slightly, so I prefer to have this
> minimal fix now, then make such changes upstream later.
>
> ---
> arch/powerpc/kernel/irq.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index f88038847790..061aa0f47bb1 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -476,6 +476,14 @@ void force_external_irq_replay(void)
> */
> WARN_ON(!arch_irqs_disabled());
>
> + /*
> + * Interrupts must always be hard disabled before irq_happened is
> + * modified (to prevent lost update in case of interrupt between
> + * load and store).
> + */
> + __hard_irq_disable();
> + local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
> +
> /* Indicate in the PACA that we have an interrupt to replay */
> local_paca->irq_happened |= PACA_IRQ_EE;
> }
^ permalink raw reply
* RFC on writel and writel_relaxed
From: Sinan Kaya @ 2018-03-21 3:07 UTC (permalink / raw)
To: open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
linux-rdma@vger.kernel.org
Hi PPC Maintainers,
We are seeking feedback on the status of relaxed write API implementation.
What is the motivation for not implementing the relaxed API?
I see that network drivers are working around the issue by calling
__raw_write() API directly but this also breaks other architectures
like SPARC since the semantics of __raw_writel() seems to be system dependent.
This is putting drivers into a tight position and they cannot achieve true
multi-arch enablement and are forced into calling __raw APIs flavors
directly with #ifdef BIG_ENDIAN ugliness.
Sinan
--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* Re: [PATCH] powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened
From: Nicholas Piggin @ 2018-03-21 3:16 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Carol L. Soto
In-Reply-To: <1521599548.16434.263.camel@kernel.crashing.org>
Adding Carol...
On Wed, 21 Mar 2018 13:32:28 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> On Wed, 2018-03-21 at 12:22 +1000, Nicholas Piggin wrote:
> > force_external_irq_replay() can be called in the do_IRQ path with
> > interrupts hard enabled and soft disabled if may_hard_irq_enable() set
> > MSR[EE]=1. It updates local_paca->irq_happened with a load, modify,
> > store sequence. If a maskable interrupt hits during this sequence, it
> > will go to the masked handler to be marked pending in irq_happened.
> > This update will be lost when the interrupt returns and the store
> > instruction executes. This can result in unpredictable latencies,
> > timeouts, lockups, etc.
> >
> > Fix this by ensuring hard interrupts are disabled before modifying
> > irq_happened.
> >
> > This could cause any maskable asynchronous interrupt to get lost, but
> > it was noticed on P9 SMP system doing RDMA NVMe target over 100GbE,
> > so very high external interrupt rate and high IPI rate. The hang was
> > bisected down to enabling doorbell interrupts for IPIs. These provided
> > an interrupt type that could run at high rates in the do_IRQ path,
> > stressing the race.
> >
> > Fixes: 1d607bb3bd ("powerpc/irq: Add mechanism to force a replay of interrupts")
> > Reported-by: Carol L. Soto <clsoto@us.ibm.com>
> > Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> > ---
>
> Nice one. We need that back into the distros asap.
Yes Carol is working on this with distros. Backporting should be
simple, so hoping to get this upstream soon to help the process.
We can take that as a Reviewed-by:? :)
Thanks,
Nick
^ permalink raw reply
* Re: RFC on writel and writel_relaxed
From: Oliver @ 2018-03-21 3:40 UTC (permalink / raw)
To: Sinan Kaya
Cc: open list:LINUX FOR POWERPC (32-BIT AND 64-BIT),
linux-rdma@vger.kernel.org, Benjamin Herrenschmidt
In-Reply-To: <3611eabe-2999-1482-b2b4-6d216bbe4762@codeaurora.org>
On Wed, Mar 21, 2018 at 2:07 PM, Sinan Kaya <okaya@codeaurora.org> wrote:
> Hi PPC Maintainers,
>
> We are seeking feedback on the status of relaxed write API implementation.
> What is the motivation for not implementing the relaxed API?
Hmm, good question.
Looks like we've implemented the relaxed_* variants by aliasing them
to the normal version since the dawn of time. There's a comment in
io.h saying something about us not having the expected semantics for
the relaxed variants, but I don't see what the issue is... Ben?
> I see that network drivers are working around the issue by calling
> __raw_write() API directly but this also breaks other architectures
> like SPARC since the semantics of __raw_writel() seems to be system dependent.
Yeah that's pretty gross. Which drivers are doing this?
> This is putting drivers into a tight position and they cannot achieve true
> multi-arch enablement and are forced into calling __raw APIs flavors
> directly with #ifdef BIG_ENDIAN ugliness.
>
> Sinan
>
> --
> Sinan Kaya
> Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
> Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* Re: [PATCH] powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened
From: Benjamin Herrenschmidt @ 2018-03-21 4:11 UTC (permalink / raw)
To: Nicholas Piggin; +Cc: linuxppc-dev, Carol L. Soto
In-Reply-To: <20180321131615.7b8bd8e4@roar.ozlabs.ibm.com>
On Wed, 2018-03-21 at 13:16 +1000, Nicholas Piggin wrote:
> Yes Carol is working on this with distros. Backporting should be
> simple, so hoping to get this upstream soon to help the process.
> We can take that as a Reviewed-by:? :)
Ah yup.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH v2 0/9] EEH refactoring 1
From: Alexey Kardashevskiy @ 2018-03-21 5:16 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Sam Bobroff
In-Reply-To: <cover.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:45 pm, Sam Bobroff wrote:
> Hello everyone,
>
> Here is a set of some small, mostly idempotent, changes to improve
> maintainability in some of the EEH code, primarily in eeh_driver.c.
>
> I've kept them all small to aid review but perhaps they should be squashed down
> before being applied.
>
> Cheers,
> Sam.
>
> Patch set changelog follows:
>
> ====== v1 -> v2: ======
>
> Patch 1/9: powerpc/eeh: Remove eeh_handle_event()
>
> Patch 2/9: powerpc/eeh: Manage EEH_PE_RECOVERING inside eeh_handle_normal_event()
>
> Patch 3/9: powerpc/eeh: Fix misleading comment in __eeh_addr_cache_get_device()
>
> Patch 4/9: powerpc/eeh: Remove misleading test in eeh_handle_normal_event()
>
> Patch 5/9: powerpc/eeh: Rename frozen_bus to bus in eeh_handle_normal_event()
>
> Patch 6/9: powerpc/eeh: Clarify arguments to eeh_reset_device()
> * Re-ordered parameters to eeh_reset_device() to keep pe first.
> * Changed eeh_aware_driver to driver_eeh_aware.
>
> Patch 7/9: powerpc/eeh: Remove always-true tests in eeh_reset_device()
>
> Patch 8/9: powerpc/eeh: Factor out common code eeh_reset_device()
> * In one case, added braces to "if" to match "else".
>
> Patch 9/9: powerpc/eeh: Add eeh_state_active() helper
>
> ====== v1: ======
>
> Patch 1/9: powerpc/eeh: Remove eeh_handle_event()
> Patch 2/9: powerpc/eeh: Manage EEH_PE_RECOVERING inside eeh_handle_normal_event()
> Patch 3/9: powerpc/eeh: Fix misleading comment in __eeh_addr_cache_get_device()
> Patch 4/9: powerpc/eeh: Remove misleading test in eeh_handle_normal_event()
> Patch 5/9: powerpc/eeh: Rename frozen_bus to bus in eeh_handle_normal_event()
> Patch 6/9: powerpc/eeh: Clarify arguments to eeh_reset_device()
> Patch 7/9: powerpc/eeh: Remove always-true tests in eeh_reset_device()
> Patch 8/9: powerpc/eeh: Factor out common code eeh_reset_device()
> Patch 9/9: powerpc/eeh: Add eeh_state_active() helper
>
> Sam Bobroff (9):
> powerpc/eeh: Remove eeh_handle_event()
> powerpc/eeh: Manage EEH_PE_RECOVERING inside eeh_handle_normal_event()
> powerpc/eeh: Fix misleading comment in __eeh_addr_cache_get_device()
> powerpc/eeh: Remove misleading test in eeh_handle_normal_event()
> powerpc/eeh: Rename frozen_bus to bus in eeh_handle_normal_event()
> powerpc/eeh: Clarify arguments to eeh_reset_device()
> powerpc/eeh: Remove always-true tests in eeh_reset_device()
> powerpc/eeh: Factor out common code eeh_reset_device()
> powerpc/eeh: Add eeh_state_active() helper
>
> arch/powerpc/include/asm/eeh.h | 6 ++
> arch/powerpc/include/asm/eeh_event.h | 3 +-
> arch/powerpc/kernel/eeh.c | 19 ++--
> arch/powerpc/kernel/eeh_cache.c | 3 +-
> arch/powerpc/kernel/eeh_driver.c | 137 +++++++++++----------------
> arch/powerpc/kernel/eeh_event.c | 6 +-
> arch/powerpc/platforms/powernv/eeh-powernv.c | 9 +-
> 7 files changed, 72 insertions(+), 111 deletions(-)
>
Nice cleanup,
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 1/9] powerpc/eeh: Remove eeh_handle_event()
From: Alexey Kardashevskiy @ 2018-03-21 5:17 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <d3d01073da02a5eb844cc8998fdac602b8121b62.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:46 pm, Sam Bobroff wrote:
> The function eeh_handle_event(pe) does nothing other than switching
> between calling eeh_handle_normal_event(pe) and
> eeh_handle_special_event(). However it is only called in two places,
> one where pe can't be NULL and the other where it must be NULL (see
> eeh_event_handler()) so it does nothing but obscure the flow of
> control.
>
> So, remove it.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/include/asm/eeh_event.h | 3 ++-
> arch/powerpc/kernel/eeh_driver.c | 42 +++++++++++++-----------------------
> arch/powerpc/kernel/eeh_event.c | 4 ++--
> 3 files changed, 19 insertions(+), 30 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h
> index 1e551a2d6f82..0a168038882d 100644
> --- a/arch/powerpc/include/asm/eeh_event.h
> +++ b/arch/powerpc/include/asm/eeh_event.h
> @@ -34,7 +34,8 @@ struct eeh_event {
> int eeh_event_init(void);
> int eeh_send_failure_event(struct eeh_pe *pe);
> void eeh_remove_event(struct eeh_pe *pe, bool force);
> -void eeh_handle_event(struct eeh_pe *pe);
> +bool eeh_handle_normal_event(struct eeh_pe *pe);
> +void eeh_handle_special_event(void);
>
> #endif /* __KERNEL__ */
> #endif /* ASM_POWERPC_EEH_EVENT_H */
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index 0c0b66fc5bfb..51b21c97910f 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -738,9 +738,22 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> * Attempts to recover the given PE. If recovery fails or the PE has failed
> * too many times, remove the PE.
> *
> + * While PHB detects address or data parity errors on particular PCI
> + * slot, the associated PE will be frozen. Besides, DMA's occurring
> + * to wild addresses (which usually happen due to bugs in device
> + * drivers or in PCI adapter firmware) can cause EEH error. #SERR,
> + * #PERR or other misc PCI-related errors also can trigger EEH errors.
> + *
> + * Recovery process consists of unplugging the device driver (which
> + * generated hotplug events to userspace), then issuing a PCI #RST to
> + * the device, then reconfiguring the PCI config space for all bridges
> + * & devices under this slot, and then finally restarting the device
> + * drivers (which cause a second set of hotplug events to go out to
> + * userspace).
> + *
> * Returns true if @pe should no longer be used, else false.
> */
> -static bool eeh_handle_normal_event(struct eeh_pe *pe)
> +bool eeh_handle_normal_event(struct eeh_pe *pe)
> {
> struct pci_bus *frozen_bus;
> struct eeh_dev *edev, *tmp;
> @@ -942,7 +955,7 @@ static bool eeh_handle_normal_event(struct eeh_pe *pe)
> * specific PE. Iterates through possible failures and handles them as
> * necessary.
> */
> -static void eeh_handle_special_event(void)
> +void eeh_handle_special_event(void)
> {
> struct eeh_pe *pe, *phb_pe;
> struct pci_bus *bus;
> @@ -1049,28 +1062,3 @@ static void eeh_handle_special_event(void)
> break;
> } while (rc != EEH_NEXT_ERR_NONE);
> }
> -
> -/**
> - * eeh_handle_event - Reset a PCI device after hard lockup.
> - * @pe: EEH PE
> - *
> - * While PHB detects address or data parity errors on particular PCI
> - * slot, the associated PE will be frozen. Besides, DMA's occurring
> - * to wild addresses (which usually happen due to bugs in device
> - * drivers or in PCI adapter firmware) can cause EEH error. #SERR,
> - * #PERR or other misc PCI-related errors also can trigger EEH errors.
> - *
> - * Recovery process consists of unplugging the device driver (which
> - * generated hotplug events to userspace), then issuing a PCI #RST to
> - * the device, then reconfiguring the PCI config space for all bridges
> - * & devices under this slot, and then finally restarting the device
> - * drivers (which cause a second set of hotplug events to go out to
> - * userspace).
> - */
> -void eeh_handle_event(struct eeh_pe *pe)
> -{
> - if (pe)
> - eeh_handle_normal_event(pe);
> - else
> - eeh_handle_special_event();
> -}
> diff --git a/arch/powerpc/kernel/eeh_event.c b/arch/powerpc/kernel/eeh_event.c
> index accbf8b5fd46..872bcfe8f90e 100644
> --- a/arch/powerpc/kernel/eeh_event.c
> +++ b/arch/powerpc/kernel/eeh_event.c
> @@ -81,10 +81,10 @@ static int eeh_event_handler(void * dummy)
> pr_info("EEH: Detected PCI bus error on "
> "PHB#%x-PE#%x\n",
> pe->phb->global_number, pe->addr);
> - eeh_handle_event(pe);
> + eeh_handle_normal_event(pe);
> eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
> } else {
> - eeh_handle_event(NULL);
> + eeh_handle_special_event();
> }
>
> kfree(event);
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 2/9] powerpc/eeh: Manage EEH_PE_RECOVERING inside eeh_handle_normal_event()
From: Alexey Kardashevskiy @ 2018-03-21 5:17 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <163b24ef504d753f4abf1510d9193962bbac32b7.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:46 pm, Sam Bobroff wrote:
> Currently the EEH_PE_RECOVERING flag for a PE is managed by both the
> caller and callee of eeh_handle_normal_event() (among other places not
> considered here). This is complicated by the fact that the PE may
> or may not have been invalidated by the call.
>
> So move the callee's handling into eeh_handle_normal_event(), which
> clarifies it and allows the return type to be changed to void (because
> it no longer needs to indicate at the PE has been invalidated).
>
> This should not change behaviour except in eeh_event_handler() where
> it was previously possible to cause eeh_pe_state_clear() to be called
> on an invalid PE, which is now avoided.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/include/asm/eeh_event.h | 2 +-
> arch/powerpc/kernel/eeh_driver.c | 29 +++++++++++------------------
> arch/powerpc/kernel/eeh_event.c | 2 --
> 3 files changed, 12 insertions(+), 21 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h
> index 0a168038882d..9884e872686f 100644
> --- a/arch/powerpc/include/asm/eeh_event.h
> +++ b/arch/powerpc/include/asm/eeh_event.h
> @@ -34,7 +34,7 @@ struct eeh_event {
> int eeh_event_init(void);
> int eeh_send_failure_event(struct eeh_pe *pe);
> void eeh_remove_event(struct eeh_pe *pe, bool force);
> -bool eeh_handle_normal_event(struct eeh_pe *pe);
> +void eeh_handle_normal_event(struct eeh_pe *pe);
> void eeh_handle_special_event(void);
>
> #endif /* __KERNEL__ */
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index 51b21c97910f..5b7a5ed4db4d 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -733,7 +733,8 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
>
> /**
> * eeh_handle_normal_event - Handle EEH events on a specific PE
> - * @pe: EEH PE
> + * @pe: EEH PE - which should not be used after we return, as it may
> + * have been invalidated.
> *
> * Attempts to recover the given PE. If recovery fails or the PE has failed
> * too many times, remove the PE.
> @@ -750,10 +751,8 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> * & devices under this slot, and then finally restarting the device
> * drivers (which cause a second set of hotplug events to go out to
> * userspace).
> - *
> - * Returns true if @pe should no longer be used, else false.
> */
> -bool eeh_handle_normal_event(struct eeh_pe *pe)
> +void eeh_handle_normal_event(struct eeh_pe *pe)
> {
> struct pci_bus *frozen_bus;
> struct eeh_dev *edev, *tmp;
> @@ -765,9 +764,11 @@ bool eeh_handle_normal_event(struct eeh_pe *pe)
> if (!frozen_bus) {
> pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n",
> __func__, pe->phb->global_number, pe->addr);
> - return false;
> + return;
> }
>
> + eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
> +
> eeh_pe_update_time_stamp(pe);
> pe->freeze_count++;
> if (pe->freeze_count > eeh_max_freezes) {
> @@ -904,7 +905,7 @@ bool eeh_handle_normal_event(struct eeh_pe *pe)
> pr_info("EEH: Notify device driver to resume\n");
> eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
>
> - return false;
> + goto final;
>
> hard_fail:
> /*
> @@ -940,12 +941,12 @@ bool eeh_handle_normal_event(struct eeh_pe *pe)
> pci_lock_rescan_remove();
> pci_hp_remove_devices(frozen_bus);
> pci_unlock_rescan_remove();
> -
> /* The passed PE should no longer be used */
> - return true;
> + return;
> }
> }
> - return false;
> +final:
> + eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
> }
>
> /**
> @@ -1018,15 +1019,7 @@ void eeh_handle_special_event(void)
> */
> if (rc == EEH_NEXT_ERR_FROZEN_PE ||
> rc == EEH_NEXT_ERR_FENCED_PHB) {
> - /*
> - * eeh_handle_normal_event() can make the PE stale if it
> - * determines that the PE cannot possibly be recovered.
> - * Don't modify the PE state if that's the case.
> - */
> - if (eeh_handle_normal_event(pe))
> - continue;
> -
> - eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
> + eeh_handle_normal_event(pe);
> } else {
> pci_lock_rescan_remove();
> list_for_each_entry(hose, &hose_list, list_node) {
> diff --git a/arch/powerpc/kernel/eeh_event.c b/arch/powerpc/kernel/eeh_event.c
> index 872bcfe8f90e..61c9356bf9c9 100644
> --- a/arch/powerpc/kernel/eeh_event.c
> +++ b/arch/powerpc/kernel/eeh_event.c
> @@ -73,7 +73,6 @@ static int eeh_event_handler(void * dummy)
> /* We might have event without binding PE */
> pe = event->pe;
> if (pe) {
> - eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
> if (pe->type & EEH_PE_PHB)
> pr_info("EEH: Detected error on PHB#%x\n",
> pe->phb->global_number);
> @@ -82,7 +81,6 @@ static int eeh_event_handler(void * dummy)
> "PHB#%x-PE#%x\n",
> pe->phb->global_number, pe->addr);
> eeh_handle_normal_event(pe);
> - eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
> } else {
> eeh_handle_special_event();
> }
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 3/9] powerpc/eeh: Fix misleading comment in __eeh_addr_cache_get_device()
From: Alexey Kardashevskiy @ 2018-03-21 5:17 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <a08f33ca4af93b1a6ec066b8091953c855d52f45.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:46 pm, Sam Bobroff wrote:
> Commit "0ba178888b05 powerpc/eeh: Remove reference to PCI device"
> removed a call to pci_dev_get() from __eeh_addr_cache_get_device() but
> did not update the comment to match.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/kernel/eeh_cache.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/kernel/eeh_cache.c b/arch/powerpc/kernel/eeh_cache.c
> index d4cc26618809..201943d54a6e 100644
> --- a/arch/powerpc/kernel/eeh_cache.c
> +++ b/arch/powerpc/kernel/eeh_cache.c
> @@ -84,8 +84,7 @@ static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr)
> * @addr: mmio (PIO) phys address or i/o port number
> *
> * Given an mmio phys address, or a port number, find a pci device
> - * that implements this address. Be sure to pci_dev_put the device
> - * when finished. I/O port numbers are assumed to be offset
> + * that implements this address. I/O port numbers are assumed to be offset
> * from zero (that is, they do *not* have pci_io_addr added in).
> * It is safe to call this function within an interrupt.
> */
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 4/9] powerpc/eeh: Remove misleading test in eeh_handle_normal_event()
From: Alexey Kardashevskiy @ 2018-03-21 5:18 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <52c15c0414d248981e251386384ed2a716315003.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:46 pm, Sam Bobroff wrote:
> Remove a test that checks if "frozen_bus" is NULL, because it cannot
> have changed since it was tested at the start of the function and so
> must be true here.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/kernel/eeh_driver.c | 24 +++++++++++-------------
> 1 file changed, 11 insertions(+), 13 deletions(-)
>
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index 5b7a5ed4db4d..04a5d9db5499 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -930,20 +930,18 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
> * all removed devices correctly to avoid access
> * the their PCI config any more.
> */
> - if (frozen_bus) {
> - if (pe->type & EEH_PE_VF) {
> - eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
> - eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
> - } else {
> - eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
> - eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
> + if (pe->type & EEH_PE_VF) {
> + eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
> + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
> + } else {
> + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
> + eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
>
> - pci_lock_rescan_remove();
> - pci_hp_remove_devices(frozen_bus);
> - pci_unlock_rescan_remove();
> - /* The passed PE should no longer be used */
> - return;
> - }
> + pci_lock_rescan_remove();
> + pci_hp_remove_devices(frozen_bus);
> + pci_unlock_rescan_remove();
> + /* The passed PE should no longer be used */
> + return;
> }
> final:
> eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 5/9] powerpc/eeh: Rename frozen_bus to bus in eeh_handle_normal_event()
From: Alexey Kardashevskiy @ 2018-03-21 5:18 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <a8d5f7792b761721852b68363c68519c6c8b62ff.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:47 pm, Sam Bobroff wrote:
> The name "frozen_bus" is misleading: it's not necessarily frozen, it's
> just the PE's PCI bus.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/kernel/eeh_driver.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index 04a5d9db5499..cb584d72b0a5 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -754,14 +754,14 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> */
> void eeh_handle_normal_event(struct eeh_pe *pe)
> {
> - struct pci_bus *frozen_bus;
> + struct pci_bus *bus;
> struct eeh_dev *edev, *tmp;
> int rc = 0;
> enum pci_ers_result result = PCI_ERS_RESULT_NONE;
> struct eeh_rmv_data rmv_data = {LIST_HEAD_INIT(rmv_data.edev_list), 0};
>
> - frozen_bus = eeh_pe_bus_get(pe);
> - if (!frozen_bus) {
> + bus = eeh_pe_bus_get(pe);
> + if (!bus) {
> pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n",
> __func__, pe->phb->global_number, pe->addr);
> return;
> @@ -820,7 +820,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
> */
> if (result == PCI_ERS_RESULT_NONE) {
> pr_info("EEH: Reset with hotplug activity\n");
> - rc = eeh_reset_device(pe, frozen_bus, NULL);
> + rc = eeh_reset_device(pe, bus, NULL);
> if (rc) {
> pr_warn("%s: Unable to reset, err=%d\n",
> __func__, rc);
> @@ -938,7 +938,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
> eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
>
> pci_lock_rescan_remove();
> - pci_hp_remove_devices(frozen_bus);
> + pci_hp_remove_devices(bus);
> pci_unlock_rescan_remove();
> /* The passed PE should no longer be used */
> return;
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 6/9] powerpc/eeh: Clarify arguments to eeh_reset_device()
From: Alexey Kardashevskiy @ 2018-03-21 5:18 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <17133177f6095a830824e54a6dcd3354ae0d04e7.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:48 pm, Sam Bobroff wrote:
> It is currently difficult to understand the behaviour of
> eeh_reset_device() due to the way it's parameters are used. In
> particular, when 'bus' is NULL, it's value is still necessary so the
> same value is looked up again locally under a different name
> ('frozen_bus') but behaviour is changed.
>
> To clarify this, add a new parameter 'driver_eeh_aware', and have the
> caller set it when it would have passed NULL for 'bus' and always pass
> a value for 'bus'. Then change any test that was on 'bus' to one on
> '!driver_eeh_aware' and replace uses of 'frozen_bus' with 'bus'.
>
> Also update the function's comment.
>
> This should not change behaviour.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/kernel/eeh_driver.c | 20 +++++++++++---------
> 1 file changed, 11 insertions(+), 9 deletions(-)
>
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index cb584d72b0a5..07437d765434 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -619,17 +619,19 @@ int eeh_pe_reset_and_recover(struct eeh_pe *pe)
>
> /**
> * eeh_reset_device - Perform actual reset of a pci slot
> + * @driver_eeh_aware: Does the device's driver provide EEH support?
> * @pe: EEH PE
> * @bus: PCI bus corresponding to the isolcated slot
> + * @rmv_data: Optional, list to record removed devices
> *
> * This routine must be called to do reset on the indicated PE.
> * During the reset, udev might be invoked because those affected
> * PCI devices will be removed and then added.
> */
> static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> - struct eeh_rmv_data *rmv_data)
> + struct eeh_rmv_data *rmv_data,
> + bool driver_eeh_aware)
> {
> - struct pci_bus *frozen_bus = eeh_pe_bus_get(pe);
> time64_t tstamp;
> int cnt, rc;
> struct eeh_dev *edev;
> @@ -645,7 +647,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> * into pci_hp_add_devices().
> */
> eeh_pe_state_mark(pe, EEH_PE_KEEP);
> - if (bus) {
> + if (!driver_eeh_aware) {
> if (pe->type & EEH_PE_VF) {
> eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
> } else {
> @@ -653,7 +655,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> pci_hp_remove_devices(bus);
> pci_unlock_rescan_remove();
> }
> - } else if (frozen_bus) {
> + } else if (bus) {
> eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data);
> }
>
> @@ -689,7 +691,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> * the device up before the scripts have taken it down,
> * potentially weird things happen.
> */
> - if (bus) {
> + if (!driver_eeh_aware) {
> pr_info("EEH: Sleep 5s ahead of complete hotplug\n");
> ssleep(5);
>
> @@ -706,7 +708,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
> pci_hp_add_devices(bus);
> }
> - } else if (frozen_bus && rmv_data->removed) {
> + } else if (bus && rmv_data->removed) {
> pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
> ssleep(5);
>
> @@ -715,7 +717,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> if (pe->type & EEH_PE_VF)
> eeh_add_virt_device(edev, NULL);
> else
> - pci_hp_add_devices(frozen_bus);
> + pci_hp_add_devices(bus);
> }
> eeh_pe_state_clear(pe, EEH_PE_KEEP);
>
> @@ -820,7 +822,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
> */
> if (result == PCI_ERS_RESULT_NONE) {
> pr_info("EEH: Reset with hotplug activity\n");
> - rc = eeh_reset_device(pe, bus, NULL);
> + rc = eeh_reset_device(pe, bus, NULL, false);
> if (rc) {
> pr_warn("%s: Unable to reset, err=%d\n",
> __func__, rc);
> @@ -872,7 +874,7 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
> /* If any device called out for a reset, then reset the slot */
> if (result == PCI_ERS_RESULT_NEED_RESET) {
> pr_info("EEH: Reset without hotplug activity\n");
> - rc = eeh_reset_device(pe, NULL, &rmv_data);
> + rc = eeh_reset_device(pe, bus, &rmv_data, true);
> if (rc) {
> pr_warn("%s: Cannot reset, err=%d\n",
> __func__, rc);
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 7/9] powerpc/eeh: Remove always-true tests in eeh_reset_device()
From: Alexey Kardashevskiy @ 2018-03-21 5:18 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <5a636a21f3352efa7a41bf4032f3a57973c4c18b.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:49 pm, Sam Bobroff wrote:
> eeh_reset_device() tests the value of 'bus' more than once but the
> only caller, eeh_handle_normal_device() does this test itself and will
> never pass NULL.
>
> So, remove the dead tests.
>
> This should not change behaviour.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/kernel/eeh_driver.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index 07437d765434..93fc22e791fa 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -655,7 +655,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> pci_hp_remove_devices(bus);
> pci_unlock_rescan_remove();
> }
> - } else if (bus) {
> + } else {
> eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data);
> }
>
> @@ -708,7 +708,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
> pci_hp_add_devices(bus);
> }
> - } else if (bus && rmv_data->removed) {
> + } else if (rmv_data->removed) {
> pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
> ssleep(5);
>
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v3 8/9] powerpc/eeh: Factor out common code eeh_reset_device()
From: Alexey Kardashevskiy @ 2018-03-21 5:18 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <168a19fad005f7f3dffe700978db75e7e976b946.1521523452.git.sam.bobroff@au1.ibm.com>
On 21/3/18 1:06 pm, Sam Bobroff wrote:
> The caller will always pass NULL for 'rmv_data' when
> 'eeh_aware_driver' is true, so the first two calls to
> eeh_pe_dev_traverse() can be combined without changing behaviour as
> can the two arms of the final 'if' block.
>
> This should not change behaviour.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> ====== v2 -> v3: ======
> Corrected two missed cases of eeh_aware_driver -> driver_eeh_aware.
>
> arch/powerpc/kernel/eeh_driver.c | 32 ++++++++++----------------------
> 1 file changed, 10 insertions(+), 22 deletions(-)
>
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index 93fc22e791fa..43ceb6263cd8 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -647,16 +647,12 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> * into pci_hp_add_devices().
> */
> eeh_pe_state_mark(pe, EEH_PE_KEEP);
> - if (!driver_eeh_aware) {
> - if (pe->type & EEH_PE_VF) {
> - eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL);
> - } else {
> - pci_lock_rescan_remove();
> - pci_hp_remove_devices(bus);
> - pci_unlock_rescan_remove();
> - }
> - } else {
> + if (driver_eeh_aware || (pe->type & EEH_PE_VF)) {
> eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data);
> + } else {
> + pci_lock_rescan_remove();
> + pci_hp_remove_devices(bus);
> + pci_unlock_rescan_remove();
> }
>
> /*
> @@ -691,8 +687,9 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> * the device up before the scripts have taken it down,
> * potentially weird things happen.
> */
> - if (!driver_eeh_aware) {
> - pr_info("EEH: Sleep 5s ahead of complete hotplug\n");
> + if (!driver_eeh_aware || rmv_data->removed) {
> + pr_info("EEH: Sleep 5s ahead of %s hotplug\n",
> + (driver_eeh_aware ? "partial" : "complete"));
> ssleep(5);
>
> /*
> @@ -705,19 +702,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
> if (pe->type & EEH_PE_VF) {
> eeh_add_virt_device(edev, NULL);
> } else {
> - eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
> + if (!driver_eeh_aware)
> + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
> pci_hp_add_devices(bus);
> }
> - } else if (rmv_data->removed) {
> - pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
> - ssleep(5);
> -
> - edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
> - eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
> - if (pe->type & EEH_PE_VF)
> - eeh_add_virt_device(edev, NULL);
> - else
> - pci_hp_add_devices(bus);
> }
> eeh_pe_state_clear(pe, EEH_PE_KEEP);
>
>
--
Alexey
^ permalink raw reply
* Re: [PATCH v2 9/9] powerpc/eeh: Add eeh_state_active() helper
From: Alexey Kardashevskiy @ 2018-03-21 5:20 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <c7cc2334ac3a7c88cc68b45337de890bcdcc80f7.1521427331.git.sam.bobroff@au1.ibm.com>
On 19/3/18 1:49 pm, Sam Bobroff wrote:
> Checking for a "fully active" device state requires testing two flag
> bits, which is open coded in several places, so add a function to do
> it.
>
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> arch/powerpc/include/asm/eeh.h | 6 ++++++
> arch/powerpc/kernel/eeh.c | 19 ++++++-------------
> arch/powerpc/platforms/powernv/eeh-powernv.c | 9 ++-------
> 3 files changed, 14 insertions(+), 20 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
> index fd37cc101f4f..c2266ca61853 100644
> --- a/arch/powerpc/include/asm/eeh.h
> +++ b/arch/powerpc/include/asm/eeh.h
> @@ -256,6 +256,12 @@ static inline void eeh_serialize_unlock(unsigned long flags)
> raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
> }
>
> +static inline bool eeh_state_active(int state)
> +{
> + return (state & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
> + == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
> +}
> +
> typedef void *(*eeh_traverse_func)(void *data, void *flag);
> void eeh_set_pe_aux_size(int size);
> int eeh_phb_pe_create(struct pci_controller *phb);
> diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
> index 2b9df0040d6b..bc640e4c5ca5 100644
> --- a/arch/powerpc/kernel/eeh.c
> +++ b/arch/powerpc/kernel/eeh.c
> @@ -394,9 +394,7 @@ static int eeh_phb_check_failure(struct eeh_pe *pe)
> /* Check PHB state */
> ret = eeh_ops->get_state(phb_pe, NULL);
> if ((ret < 0) ||
> - (ret == EEH_STATE_NOT_SUPPORT) ||
> - (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) ==
> - (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
> + (ret == EEH_STATE_NOT_SUPPORT) || eeh_state_active(ret)) {
> ret = 0;
> goto out;
> }
> @@ -433,7 +431,6 @@ static int eeh_phb_check_failure(struct eeh_pe *pe)
> int eeh_dev_check_failure(struct eeh_dev *edev)
> {
> int ret;
> - int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
> unsigned long flags;
> struct device_node *dn;
> struct pci_dev *dev;
> @@ -525,8 +522,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
> * state, PE is in good state.
> */
> if ((ret < 0) ||
> - (ret == EEH_STATE_NOT_SUPPORT) ||
> - ((ret & active_flags) == active_flags)) {
> + (ret == EEH_STATE_NOT_SUPPORT) || eeh_state_active(ret)) {
> eeh_stats.false_positives++;
> pe->false_positives++;
> rc = 0;
> @@ -546,8 +542,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
>
> /* Frozen parent PE ? */
> ret = eeh_ops->get_state(parent_pe, NULL);
> - if (ret > 0 &&
> - (ret & active_flags) != active_flags)
> + if (ret > 0 && !eeh_state_active(ret))
> pe = parent_pe;
>
> /* Next parent level */
> @@ -888,7 +883,6 @@ static void *eeh_set_dev_freset(void *data, void *flag)
> */
> int eeh_pe_reset_full(struct eeh_pe *pe)
> {
> - int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
> int reset_state = (EEH_PE_RESET | EEH_PE_CFG_BLOCKED);
> int type = EEH_RESET_HOT;
> unsigned int freset = 0;
> @@ -919,7 +913,7 @@ int eeh_pe_reset_full(struct eeh_pe *pe)
>
> /* Wait until the PE is in a functioning state */
> state = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
> - if ((state & active_flags) == active_flags)
> + if (eeh_state_active(state))
> break;
>
> if (state < 0) {
> @@ -1352,16 +1346,15 @@ static int eeh_pe_change_owner(struct eeh_pe *pe)
> struct eeh_dev *edev, *tmp;
> struct pci_dev *pdev;
> struct pci_device_id *id;
> - int flags, ret;
> + int ret;
>
> /* Check PE state */
> - flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
> ret = eeh_ops->get_state(pe, NULL);
> if (ret < 0 || ret == EEH_STATE_NOT_SUPPORT)
> return 0;
>
> /* Unfrozen PE, nothing to do */
> - if ((ret & flags) == flags)
> + if (eeh_state_active(ret))
> return 0;
>
> /* Frozen PE, check if it needs PE level reset */
> diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
> index 33c86c1a1720..ddfc3544d285 100644
> --- a/arch/powerpc/platforms/powernv/eeh-powernv.c
> +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
> @@ -1425,11 +1425,8 @@ static int pnv_eeh_get_pe(struct pci_controller *hose,
> dev_pe = dev_pe->parent;
> while (dev_pe && !(dev_pe->type & EEH_PE_PHB)) {
> int ret;
> - int active_flags = (EEH_STATE_MMIO_ACTIVE |
> - EEH_STATE_DMA_ACTIVE);
> -
> ret = eeh_ops->get_state(dev_pe, NULL);
> - if (ret <= 0 || (ret & active_flags) == active_flags) {
> + if (ret <= 0 || eeh_state_active(ret)) {
> dev_pe = dev_pe->parent;
> continue;
> }
> @@ -1463,7 +1460,6 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
> struct eeh_pe *phb_pe, *parent_pe;
> __be64 frozen_pe_no;
> __be16 err_type, severity;
> - int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
> long rc;
> int state, ret = EEH_NEXT_ERR_NONE;
>
> @@ -1626,8 +1622,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe)
>
> /* Frozen parent PE ? */
> state = eeh_ops->get_state(parent_pe, NULL);
> - if (state > 0 &&
> - (state & active_flags) != active_flags)
> + if (state > 0 && !eeh_state_active(state))
> *pe = parent_pe;
>
> /* Next parent level */
>
--
Alexey
^ permalink raw reply
* [PATCH 1/1] PCI set flag PCI_SCAN_ALL_PCIE_DEVS for P.A. Semi boards
From: Christian Zigotzky @ 2018-03-21 6:44 UTC (permalink / raw)
To: Michael Ellerman, Bjorn Helgaas, Bjorn Helgaas, linux-pci,
Olof Johansson, linuxppc-dev
In-Reply-To: <87tvtbg0i9.fsf@concordia.ellerman.id.au>
Michael,
Thanks for the hint because of removing tags and thanks a lot for adding
the patch to the official source code. This patch helps us a lot.
Have a nice day!
Christian
On 19 March 2018 at 11:32PM, Michael Ellerman wrote:
>
> I'm happy to take it, I've been meaning to check if Olof sent a SOB in
> his original mail but haven't got to it.
>
> ...
>
> Yes, he did, see below.
>
> So I'll merge that, I'll add a Tested-by for you Christian.
>
> Christian please don't remove any of the tags when submitting other
> peoples' patches in future.
>
> cheers
>
>
> >From a3b390277627b0342c8ccfc16e58679e0d8abdde Mon Sep 17 00:00:00 2001
> From: Olof Johansson <olof@lixom.net>
> Date: Sat, 2 Dec 2017 14:56:36 -0800
> Subject: [PATCH] powerpc/pasemi: set PCI_SCAN_ALL_PCI_DEVS
>
> Needed on Amiga X1000 with SB600.
>
> Reported-by: Christian Zigotzky <chzigotzky@xenosoft.de>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Signed-off-by: Olof Johansson <olof@lixom.net>
> ---
> arch/powerpc/platforms/pasemi/pci.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/arch/powerpc/platforms/pasemi/pci.c
b/arch/powerpc/platforms/pasemi/pci.c
> index 5ff6108..ea54ed2 100644
> --- a/arch/powerpc/platforms/pasemi/pci.c
> +++ b/arch/powerpc/platforms/pasemi/pci.c
> @@ -224,6 +224,8 @@ void __init pas_pci_init(void)
> return;
> }
>
> + pci_set_flag(PCI_SCAN_ALL_PCIE_DEVS):
> +
> for (np = NULL; (np = of_get_next_child(root, np)) != NULL;)
> if (np->name && !strcmp(np->name, "pxp") && !pas_add_bridge(np))
> of_node_get(np);
>
^ permalink raw reply
* Re: [bug?] Access was denied by memory protection keys in execute-only address
From: Li Wang @ 2018-03-21 6:53 UTC (permalink / raw)
To: Ram Pai
Cc: Michael Ellerman, Jan Stancek, ltp, linux-mm,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20180320215828.GA5825@ram.oc3035372033.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 5039 bytes --]
On Wed, Mar 21, 2018 at 5:58 AM, Ram Pai <linuxram@us.ibm.com> wrote:
> On Fri, Mar 09, 2018 at 11:43:00AM +0800, Li Wang wrote:
> > On Fri, Mar 9, 2018 at 12:45 AM, Ram Pai <[1]linuxram@us.ibm.com>
> wrote:
> >
> > On Thu, Mar 08, 2018 at 11:19:12PM +1100, Michael Ellerman wrote:
> > > Li Wang <[2]liwang@redhat.com> writes:
> > > > Hi,
> > > >
> > > > ltp/mprotect04[1] crashed by SEGV_PKUERR on ppc64(LPAR on P730,
> > Power 8
> > > > 8247-22L) with kernel-v4.16.0-rc4.
> > > >
> > > > 10000000-10020000 r-xp 00000000 fd:00 167223
> mprotect04
> > > > 10020000-10030000 r--p 00010000 fd:00 167223
> mprotect04
> > > > 10030000-10040000 rw-p 00020000 fd:00 167223
> mprotect04
> > > > 1001a380000-1001a3b0000 rw-p 00000000 00:00 0 [heap]
> > > > 7fffa6c60000-7fffa6c80000 --xp 00000000 00:00 0
> > > >
> > > > &exec_func = 0x10030170
> > > >
> > > > &func = 0x7fffa6c60170
> > > >
> > > > While perform
> > > > "(*func)();" we get the
> > > > segmentation fault.
> > > >
> > > >
> > > > strace log:
> > > >
> > > > -------------------
> > > > mprotect(0x7fffaed00000, 131072, PROT_EXEC) = 0
> > > > rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
> > > > --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_PKUERR,
> > si_addr=0x7fffaed00170}
> > > > ---
> > >
> > > Looks like a bug to me.
> > >
> > > Please Cc linuxppc-dev on powerpc bugs.
> > >
> > > I also can't reproduce this failure on my machine.
> > > Not sure what's going on?
> >
> > I could reproduce it on a power7 lpar. But not on a power8 lpar.
> >
> > The problem seems to be that the cpu generates a key exception if
> > the page with Read/Write-disable-but-execute-enable key is executed
> > on power7. If I enable read on that key, the exception disappears.
> >
> > After adding read permission on that key, reproducer get PASS on my
> power8
> > machine too.
> > (mprotect(..,PROT_READ | PROT_EXEC))
> >
> >
> > BTW: the testcase executes
> > mprotect(..,PROT_EXEC).
> > The mprotect(, PROT_EXEC) system call internally generates a
> > execute-only key and associates it with the pages in the
> address-range.
> >
> > Now since Li Wang claims that he can reproduce it on power8 as
> well, i
> > am wondering if the slightly different cpu behavior is dependent on
> the
> > version of the firmware/microcode?
> >
> > I also run this reproducer on series ppc kvm machines, but none of
> them
> > get the FAIL.
> > If you need some more HW info, pls let me know.
>
> Hi Li,
>
> Can you try the following patch and see if it solves your problem.
>
It only works on power7 lpar machine.
But for p8 lpar, it still get failure as that before, the thing I wondered
is
that why not disable the pkey_execute_disable_supported on p8 machine?
I tried to modify your patch and get PASS with the mprotect04 test on
power8 lpar machine.
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -105,7 +105,9 @@ int pkey_initialize(void)
* The device tree cannot be relied to indicate support for
* execute_disable support. Instead we use a PVR check.
*/
- if (pvr_version_is(PVR_POWER7) || pvr_version_is(PVR_POWER7p))
+ if (pvr_version_is(PVR_POWER7) || pvr_version_is(PVR_POWER7p) \
+ || pvr_version_is(PVR_POWER8E) ||
pvr_version_is(PVR_POWER8NVL) \
+ || pvr_version_is(PVR_POWER8))
pkey_execute_disable_supported = false;
else
pkey_execute_disable_supported = true;
@@ -395,7 +397,7 @@ int __arch_override_mprotect_pkey(struct vm_area_struct
*vma, int prot,
* The requested protection is execute-only. Hence let's use an
* execute-only pkey.
*/
- if (prot == PROT_EXEC) {
+ if (prot == PROT_EXEC && pkey_execute_disable_supported) {
pkey = execute_only_pkey(vma->vm_mm);
if (pkey > 0)
return pkey;
>
>
> diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
> index c269817..184a10a 100644
> --- a/arch/powerpc/mm/pkeys.c
> +++ b/arch/powerpc/mm/pkeys.c
> @@ -421,7 +421,7 @@ int __arch_override_mprotect_pkey(struct
> vm_area_struct *vma, int prot,
> * The requested protection is execute-only. Hence let's use an
> * execute-only pkey.
> */
> - if (prot == PROT_EXEC) {
>
> + if (prot == PROT_EXEC && pkey_execute_disable_supported) {
> pkey = execute_only_pkey(vma->vm_mm);
> if (pkey > 0)
> return pkey;
>
>
> Thanks
> RP
>
>
--
Li Wang
liwang@redhat.com
[-- Attachment #2: Type: text/html, Size: 7439 bytes --]
^ permalink raw reply
* [PATCH 0/5] KVM & powerpc: Work around POWER9 TM hardware bugs
From: Paul Mackerras @ 2018-03-21 10:24 UTC (permalink / raw)
To: kvm, linuxppc-dev; +Cc: kvm-ppc
This patch series applies on top of my patch series "powerpc: Free up
CPU feature bits".
POWER9 has some shortcomings in its implementation of transactional
memory. Starting with v2.2 of the "Nimbus" chip, some changes have
been made to the hardware which make it able to generate hypervisor
interrupts in the situations where hardware needs the hypervisor to
provide some assistance with the implementation. Specifically, the
core does not have enough storage to store a complete checkpoint of
all the architected state for all 4 threads, and therefore needs to
be able to offload the checkpointed state of threads which are in
transactional suspended state (for threads that are in transactional
state, the hardware can simply abort the transaction).
This series implements the hypervisor assistance for TM for KVM
guests, thus allowing them to use TM. This then means that we can
allow live migration of guests on POWER8 that may be using TM to
POWER9 hosts.
This version adds a feature bit for the XER[SO] bug workaround so that
it can be turned off on future systems which may still require
hypervisor assistance for TM but have the XER[SO] bug fixed. It also
makes the test in the idle code (which includes a sync instruction)
conditional on the XER[SO] bug feature bit, meaning that the code to
force SMT4 mode will only work when that feature bit is set.
Paul.
arch/powerpc/include/asm/asm-prototypes.h | 3 +
arch/powerpc/include/asm/cputable.h | 7 +-
arch/powerpc/include/asm/kvm_asm.h | 2 +
arch/powerpc/include/asm/kvm_book3s.h | 4 +
arch/powerpc/include/asm/kvm_book3s_64.h | 43 ++++++
arch/powerpc/include/asm/kvm_book3s_asm.h | 1 +
arch/powerpc/include/asm/kvm_host.h | 1 +
arch/powerpc/include/asm/paca.h | 3 +
arch/powerpc/include/asm/powernv.h | 1 +
arch/powerpc/include/asm/ppc-opcode.h | 4 +
arch/powerpc/include/asm/reg.h | 7 +
arch/powerpc/kernel/asm-offsets.c | 3 +
arch/powerpc/kernel/cputable.c | 23 +++-
arch/powerpc/kernel/dt_cpu_ftrs.c | 5 +
arch/powerpc/kernel/exceptions-64s.S | 4 +-
arch/powerpc/kernel/idle_book3s.S | 21 +++
arch/powerpc/kvm/Makefile | 7 +
arch/powerpc/kvm/book3s_hv.c | 18 ++-
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 166 ++++++++++++++++++++++-
arch/powerpc/kvm/book3s_hv_tm.c | 216 ++++++++++++++++++++++++++++++
arch/powerpc/kvm/book3s_hv_tm_builtin.c | 109 +++++++++++++++
arch/powerpc/kvm/powerpc.c | 5 +-
arch/powerpc/platforms/powernv/idle.c | 81 +++++++++++
23 files changed, 720 insertions(+), 14 deletions(-)
^ permalink raw reply
* [PATCH 1/5] powerpc: Add CPU feature bits for TM bug workarounds on POWER9 v2.2
From: Paul Mackerras @ 2018-03-21 10:24 UTC (permalink / raw)
To: kvm, linuxppc-dev; +Cc: kvm-ppc
In-Reply-To: <1521627901-13547-1-git-send-email-paulus@ozlabs.org>
This adds a CPU feature bit which is set for POWER9 "Nimbus" DD2.2
processors which will be used to enable the hypervisor to assist
hardware with the handling of checkpointed register values while the
CPU is in suspend state, in order to work around hardware bugs. The
hardware assistance for these workarounds introduced a new hardware
bug relating to the XER[SO] bit. We add a separate feature bit for
this bug in case future chips fix it while still requiring the
hypervisor assistance with suspend state.
When the dt_cpu_ftrs subsystem is in use, the software assistance can
be enabled using a "tm-suspend-hypervisor-assist" node in the device
tree, and a "tm-suspend-xer-so-bug" node enables the workarounds for
the XER[SO] bug. In the absence of such nodes, a quirk enables both
for POWER9 "Nimbus" DD2.2 processors.
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
---
arch/powerpc/include/asm/cputable.h | 7 ++++++-
arch/powerpc/kernel/cputable.c | 24 ++++++++++++++++++++++--
arch/powerpc/kernel/dt_cpu_ftrs.c | 5 +++++
3 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 49fd067..ecee84d 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -213,6 +213,8 @@ static inline void cpu_feature_keys_init(void) { }
#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x0000020000000000)
#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x0000040000000000)
#define CPU_FTR_POWER9_DD2_1 LONG_ASM_CONST(0x0000080000000000)
+#define CPU_FTR_P9_TM_HV_ASSIST LONG_ASM_CONST(0x0000100000000000)
+#define CPU_FTR_P9_TM_XER_SO_BUG LONG_ASM_CONST(0x0000200000000000)
#ifndef __ASSEMBLY__
@@ -469,6 +471,8 @@ static inline void cpu_feature_keys_init(void) { }
(~CPU_FTR_SAO))
#define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9
#define CPU_FTRS_POWER9_DD2_1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD2_1)
+#define CPU_FTRS_POWER9_DD2_2 (CPU_FTRS_POWER9 | CPU_FTR_P9_TM_HV_ASSIST | \
+ CPU_FTR_P9_TM_XER_SO_BUG)
#define CPU_FTRS_CELL (CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -488,7 +492,8 @@ static inline void cpu_feature_keys_init(void) { }
CPU_FTRS_POWER6 | CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | \
CPU_FTRS_POWER8 | CPU_FTRS_POWER8_DD1 | CPU_FTRS_CELL | \
CPU_FTRS_PA6T | CPU_FTR_VSX | CPU_FTRS_POWER9 | \
- CPU_FTRS_POWER9_DD1 | CPU_FTRS_POWER9_DD2_1)
+ CPU_FTRS_POWER9_DD1 | CPU_FTRS_POWER9_DD2_1 | \
+ CPU_FTRS_POWER9_DD2_2)
#endif
#else
enum {
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index c40a9fc..68052ea 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -553,11 +553,31 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check_early = __machine_check_early_realmode_p9,
.platform = "power9",
},
- { /* Power9 DD 2.1 or later (see DD2.0 above) */
+ { /* Power9 DD 2.1 */
+ .pvr_mask = 0xffffefff,
+ .pvr_value = 0x004e0201,
+ .cpu_name = "POWER9 (raw)",
+ .cpu_features = CPU_FTRS_POWER9_DD2_1,
+ .cpu_user_features = COMMON_USER_POWER9,
+ .cpu_user_features2 = COMMON_USER2_POWER9,
+ .mmu_features = MMU_FTRS_POWER9,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .num_pmcs = 6,
+ .pmc_type = PPC_PMC_IBM,
+ .oprofile_cpu_type = "ppc64/power9",
+ .oprofile_type = PPC_OPROFILE_INVALID,
+ .cpu_setup = __setup_cpu_power9,
+ .cpu_restore = __restore_cpu_power9,
+ .flush_tlb = __flush_tlb_power9,
+ .machine_check_early = __machine_check_early_realmode_p9,
+ .platform = "power9",
+ },
+ { /* Power9 DD2.2 or later */
.pvr_mask = 0xffff0000,
.pvr_value = 0x004e0000,
.cpu_name = "POWER9 (raw)",
- .cpu_features = CPU_FTRS_POWER9_DD2_1,
+ .cpu_features = CPU_FTRS_POWER9_DD2_2,
.cpu_user_features = COMMON_USER_POWER9,
.cpu_user_features2 = COMMON_USER2_POWER9,
.mmu_features = MMU_FTRS_POWER9,
diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c
index ee562ff..0a0c601 100644
--- a/arch/powerpc/kernel/dt_cpu_ftrs.c
+++ b/arch/powerpc/kernel/dt_cpu_ftrs.c
@@ -589,6 +589,8 @@ static struct dt_cpu_feature_match __initdata
{"virtual-page-class-key-protection", feat_enable, 0},
{"transactional-memory", feat_enable_tm, CPU_FTR_TM},
{"transactional-memory-v3", feat_enable_tm, 0},
+ {"tm-suspend-hypervisor-assist", feat_enable, CPU_FTR_P9_TM_HV_ASSIST},
+ {"tm-suspend-xer-so-bug", feat_enable, CPU_FTR_P9_TM_XER_SO_BUG},
{"idle-nap", feat_enable_idle_nap, 0},
{"alignment-interrupt-dsisr", feat_enable_align_dsisr, 0},
{"idle-stop", feat_enable_idle_stop, 0},
@@ -708,6 +710,9 @@ static __init void cpufeatures_cpu_quirks(void)
cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD1;
else if ((version & 0xffffefff) == 0x004e0201)
cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD2_1;
+ else if ((version & 0xffffefff) == 0x004e0202)
+ cur_cpu_spec->cpu_features |= CPU_FTR_P9_TM_HV_ASSIST |
+ CPU_FTR_P9_TM_XER_SO_BUG;
}
static void __init cpufeatures_setup_finished(void)
--
2.7.4
^ permalink raw reply related
* [PATCH 2/5] powerpc/powernv: Provide a way to force a core into SMT4 mode
From: Paul Mackerras @ 2018-03-21 10:24 UTC (permalink / raw)
To: kvm, linuxppc-dev; +Cc: kvm-ppc
In-Reply-To: <1521627901-13547-1-git-send-email-paulus@ozlabs.org>
POWER9 processors up to and including "Nimbus" v2.2 have hardware
bugs relating to transactional memory and thread reconfiguration.
One of these bugs has a workaround which is to get the core into
SMT4 state temporarily. This workaround is only needed when
running bare-metal.
This patch provides a function which gets the core into SMT4 mode
by preventing threads from going to a stop state, and waking up
those which are already in a stop state. Once at least 3 threads
are not in a stop state, the core will be in SMT4 and we can
continue.
To do this, we add a "dont_stop" flag to the paca to tell the
thread not to go into a stop state. If this flag is set,
power9_idle_stop() just returns immediately with a return value
of 0. The pnv_power9_force_smt4_catch() function does the following:
1. Set the dont_stop flag for each thread in the core, except
ourselves (in fact we use an atomic_inc() in case more than
one thread is calling this function concurrently).
2. See how many threads are awake, indicated by their
requested_psscr field in the paca being 0. If this is at
least 3, skip to step 5.
3. Send a doorbell interrupt to each thread that was seen as
being in a stop state in step 2.
4. Until at least 3 threads are awake, scan the threads to which
we sent a doorbell interrupt and check if they are awake now.
This relies on the following properties:
- Once dont_stop is non-zero, requested_psccr can't go from zero to
non-zero, except transiently (and without the thread doing stop).
- requested_psscr being zero guarantees that the thread isn't in
a state-losing stop state where thread reconfiguration could occur.
- Doing stop with a PSSCR value of 0 won't be a state-losing stop
and thus won't allow thread reconfiguration.
- Once threads_per_core/2 + 1 (i.e. 3) threads are awake, the core
must be in SMT4 mode, since SMT modes are powers of 2.
This does add a sync to power9_idle_stop(), which is necessary to
provide the correct ordering between setting requested_psscr and
checking dont_stop. The overhead of the sync should be unnoticeable
compared to the latency of going into and out of a stop state.
Because some objected to incurring this extra latency on systems where
the XER[SO] bug is not relevant, I have put the test in
power9_idle_stop inside a feature section. This means that
pnv_power9_force_smt4_catch() WILL NOT WORK correctly on systems
without the CPU_FTR_P9_TM_XER_SO_BUG feature bit set, and will
probably hang the system.
In order to cater for uses where the caller has an operation that
has to be done while the core is in SMT4, the core continues to be
kept in SMT4 after pnv_power9_force_smt4_catch() function returns,
until the pnv_power9_force_smt4_release() function is called.
It undoes the effect of step 1 above and allows the other threads
to go into a stop state.
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
---
arch/powerpc/include/asm/asm-prototypes.h | 3 ++
arch/powerpc/include/asm/paca.h | 3 ++
arch/powerpc/include/asm/powernv.h | 1 +
arch/powerpc/kernel/asm-offsets.c | 1 +
arch/powerpc/kernel/idle_book3s.S | 21 ++++++++
arch/powerpc/platforms/powernv/idle.c | 81 +++++++++++++++++++++++++++++++
6 files changed, 110 insertions(+)
diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h
index 0bdeff4..d9713ad 100644
--- a/arch/powerpc/include/asm/asm-prototypes.h
+++ b/arch/powerpc/include/asm/asm-prototypes.h
@@ -138,4 +138,7 @@ extern int __ucmpdi2(u64, u64);
void _mcount(void);
unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip);
+void pnv_power9_force_smt4_catch(void);
+void pnv_power9_force_smt4_release(void);
+
#endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index d2bf71d..c97b411 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -32,6 +32,7 @@
#include <asm/accounting.h>
#include <asm/hmi.h>
#include <asm/cpuidle.h>
+#include <asm/atomic.h>
register struct paca_struct *local_paca asm("r13");
@@ -177,6 +178,8 @@ struct paca_struct {
u8 thread_mask;
/* Mask to denote subcore sibling threads */
u8 subcore_sibling_mask;
+ /* Flag to request this thread not to stop */
+ atomic_t dont_stop;
/*
* Pointer to an array which contains pointer
* to the sibling threads' paca.
diff --git a/arch/powerpc/include/asm/powernv.h b/arch/powerpc/include/asm/powernv.h
index dc5f6a5..d1c2d2e6 100644
--- a/arch/powerpc/include/asm/powernv.h
+++ b/arch/powerpc/include/asm/powernv.h
@@ -40,6 +40,7 @@ static inline int pnv_npu2_handle_fault(struct npu_context *context,
}
static inline void pnv_tm_init(void) { }
+static inline void pnv_power9_force_smt4(void) { }
#endif
#endif /* _ASM_POWERNV_H */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index ea5eb91..dbefe30 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -759,6 +759,7 @@ int main(void)
OFFSET(PACA_SUBCORE_SIBLING_MASK, paca_struct, subcore_sibling_mask);
OFFSET(PACA_SIBLING_PACA_PTRS, paca_struct, thread_sibling_pacas);
OFFSET(PACA_REQ_PSSCR, paca_struct, requested_psscr);
+ OFFSET(PACA_DONT_STOP, paca_struct, dont_stop);
#define STOP_SPR(x, f) OFFSET(x, paca_struct, stop_sprs.f)
STOP_SPR(STOP_PID, pid);
STOP_SPR(STOP_LDBAR, ldbar);
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index 01e1c19..72b8d19 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -339,6 +339,7 @@ power_enter_stop:
bne .Lhandle_esl_ec_set
PPC_STOP
li r3,0 /* Since we didn't lose state, return 0 */
+ std r3, PACA_REQ_PSSCR(r13)
/*
* pnv_wakeup_noloss() expects r12 to contain the SRR1 value so
@@ -429,11 +430,29 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66); \
* r3 contains desired PSSCR register value.
*/
_GLOBAL(power9_idle_stop)
+BEGIN_FEATURE_SECTION
+ lwz r5, PACA_DONT_STOP(r13)
+ cmpwi r5, 0
+ bne 1f
std r3, PACA_REQ_PSSCR(r13)
+ sync
+ lwz r5, PACA_DONT_STOP(r13)
+ cmpwi r5, 0
+ bne 1f
+END_FEATURE_SECTION_IFSET(CPU_FTR_P9_TM_XER_SO_BUG)
mtspr SPRN_PSSCR,r3
LOAD_REG_ADDR(r4,power_enter_stop)
b pnv_powersave_common
/* No return */
+1:
+ /*
+ * We get here when TM / thread reconfiguration bug workaround
+ * code wants to get the CPU into SMT4 mode, and therefore
+ * we are being asked not to stop.
+ */
+ li r3, 0
+ std r3, PACA_REQ_PSSCR(r13)
+ blr /* return 0 for wakeup cause / SRR1 value */
/*
* On waking up from stop 0,1,2 with ESL=1 on POWER9 DD1,
@@ -584,6 +603,8 @@ FTR_SECTION_ELSE_NESTED(71)
mfspr r5, SPRN_PSSCR
rldicl r5,r5,4,60
ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_POWER9_DD1, 71)
+ li r0, 0 /* clear requested_psscr to say we're awake */
+ std r0, PACA_REQ_PSSCR(r13)
cmpd cr4,r5,r4
bge cr4,pnv_wakeup_tb_loss /* returns to caller */
diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
index 443d5ca..99a760e 100644
--- a/arch/powerpc/platforms/powernv/idle.c
+++ b/arch/powerpc/platforms/powernv/idle.c
@@ -24,6 +24,7 @@
#include <asm/code-patching.h>
#include <asm/smp.h>
#include <asm/runlatch.h>
+#include <asm/dbell.h>
#include "powernv.h"
#include "subcore.h"
@@ -387,6 +388,86 @@ void power9_idle(void)
power9_idle_type(pnv_default_stop_val, pnv_default_stop_mask);
}
+#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
+/*
+ * This is used in working around bugs in thread reconfiguration
+ * on POWER9 (at least up to Nimbus DD2.2) relating to transactional
+ * memory and the way that XER[SO] is checkpointed.
+ * This function forces the core into SMT4 in order by asking
+ * all other threads not to stop, and sending a message to any
+ * that are in a stop state.
+ * Must be called with preemption disabled.
+ *
+ * DO NOT call this unless cpu_has_feature(CPU_FTR_P9_TM_XER_SO_BUG) is
+ * true; otherwise this function will hang the system, due to the
+ * optimization in power9_idle_stop.
+ */
+void pnv_power9_force_smt4_catch(void)
+{
+ int cpu, cpu0, thr;
+ struct paca_struct *tpaca;
+ int awake_threads = 1; /* this thread is awake */
+ int poke_threads = 0;
+ int need_awake = threads_per_core;
+
+ cpu = smp_processor_id();
+ cpu0 = cpu & ~(threads_per_core - 1);
+ tpaca = &paca[cpu0];
+ for (thr = 0; thr < threads_per_core; ++thr) {
+ if (cpu != cpu0 + thr)
+ atomic_inc(&tpaca[thr].dont_stop);
+ }
+ /* order setting dont_stop vs testing requested_psscr */
+ mb();
+ for (thr = 0; thr < threads_per_core; ++thr) {
+ if (!tpaca[thr].requested_psscr)
+ ++awake_threads;
+ else
+ poke_threads |= (1 << thr);
+ }
+
+ /* If at least 3 threads are awake, the core is in SMT4 already */
+ if (awake_threads < need_awake) {
+ /* We have to wake some threads; we'll use msgsnd */
+ for (thr = 0; thr < threads_per_core; ++thr) {
+ if (poke_threads & (1 << thr)) {
+ ppc_msgsnd_sync();
+ ppc_msgsnd(PPC_DBELL_MSGTYPE, 0,
+ tpaca[thr].hw_cpu_id);
+ }
+ }
+ /* now spin until at least 3 threads are awake */
+ do {
+ for (thr = 0; thr < threads_per_core; ++thr) {
+ if ((poke_threads & (1 << thr)) &&
+ !tpaca[thr].requested_psscr) {
+ ++awake_threads;
+ poke_threads &= ~(1 << thr);
+ }
+ }
+ } while (awake_threads < need_awake);
+ }
+}
+EXPORT_SYMBOL_GPL(pnv_power9_force_smt4_catch);
+
+void pnv_power9_force_smt4_release(void)
+{
+ int cpu, cpu0, thr;
+ struct paca_struct *tpaca;
+
+ cpu = smp_processor_id();
+ cpu0 = cpu & ~(threads_per_core - 1);
+ tpaca = &paca[cpu0];
+
+ /* clear all the dont_stop flags */
+ for (thr = 0; thr < threads_per_core; ++thr) {
+ if (cpu != cpu0 + thr)
+ atomic_dec(&tpaca[thr].dont_stop);
+ }
+}
+EXPORT_SYMBOL_GPL(pnv_power9_force_smt4_release);
+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
+
#ifdef CONFIG_HOTPLUG_CPU
static void pnv_program_cpu_hotplug_lpcr(unsigned int cpu, u64 lpcr_val)
{
--
2.7.4
^ permalink raw reply related
* [PATCH 3/5] KVM: PPC: Book3S HV: Work around transactional memory bugs in POWER9
From: Paul Mackerras @ 2018-03-21 10:24 UTC (permalink / raw)
To: kvm, linuxppc-dev; +Cc: kvm-ppc
In-Reply-To: <1521627901-13547-1-git-send-email-paulus@ozlabs.org>
POWER9 has hardware bugs relating to transactional memory and thread
reconfiguration (changes to hardware SMT mode). Specifically, the core
does not have enough storage to store a complete checkpoint of all the
architected state for all four threads. The DD2.2 version of POWER9
includes hardware modifications designed to allow hypervisor software
to implement workarounds for these problems. This patch implements
those workarounds in KVM code so that KVM guests see a full, working
transactional memory implementation.
The problems center around the use of TM suspended state, where the
CPU has a checkpointed state but execution is not transactional. The
workaround is to implement a "fake suspend" state, which looks to the
guest like suspended state but the CPU does not store a checkpoint.
In this state, any instruction that would cause a transition to
transactional state (rfid, rfebb, mtmsrd, tresume) or would use the
checkpointed state (treclaim) causes a "soft patch" interrupt (vector
0x1500) to the hypervisor so that it can be emulated. The trechkpt
instruction also causes a soft patch interrupt.
On POWER9 DD2.2, we avoid returning to the guest in any state which
would require a checkpoint to be present. The trechkpt in the guest
entry path which would normally create that checkpoint is replaced by
either a transition to fake suspend state, if the guest is in suspend
state, or a rollback to the pre-transactional state if the guest is in
transactional state. Fake suspend state is indicated by a flag in the
PACA plus a new bit in the PSSCR. The new PSSCR bit is write-only and
reads back as 0.
On exit from the guest, if the guest is in fake suspend state, we still
do the treclaim instruction as we would in real suspend state, in order
to get into non-transactional state, but we do not save the resulting
register state since there was no checkpoint.
Emulation of the instructions that cause a softpatch interrupt is
handled in two paths. If the guest is in real suspend mode, we call
kvmhv_p9_tm_emulation_early() to handle the cases where the guest is
transitioning to transactional state. This is called before we do the
treclaim in the guest exit path; because we haven't done treclaim, we
can get back to the guest with the transaction still active. If the
instruction is a case that kvmhv_p9_tm_emulation_early() doesn't
handle, or if the guest is in fake suspend state, then we proceed to
do the complete guest exit path and subsequently call
kvmhv_p9_tm_emulation() in host context with the MMU on. This handles
all the cases including the cases that generate program interrupts
(illegal instruction or TM Bad Thing) and facility unavailable
interrupts.
The emulation is reasonably straightforward and is mostly concerned
with checking for exception conditions and updating the state of
registers such as MSR and CR0. The treclaim emulation takes care to
ensure that the TEXASR register gets updated as if it were the guest
treclaim instruction that had done failure recording, not the treclaim
done in hypervisor state in the guest exit path.
With this, the KVM_CAP_PPC_HTM capability returns true (1) even if
transactional memory is not available to host userspace.
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
---
arch/powerpc/include/asm/kvm_asm.h | 2 +
arch/powerpc/include/asm/kvm_book3s.h | 4 +
arch/powerpc/include/asm/kvm_book3s_64.h | 43 ++++++
arch/powerpc/include/asm/kvm_book3s_asm.h | 1 +
arch/powerpc/include/asm/kvm_host.h | 1 +
arch/powerpc/include/asm/ppc-opcode.h | 4 +
arch/powerpc/include/asm/reg.h | 7 +
arch/powerpc/kernel/asm-offsets.c | 2 +
arch/powerpc/kernel/cputable.c | 1 -
arch/powerpc/kernel/exceptions-64s.S | 4 +-
arch/powerpc/kvm/Makefile | 7 +
arch/powerpc/kvm/book3s_hv.c | 18 ++-
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 143 +++++++++++++++++++-
arch/powerpc/kvm/book3s_hv_tm.c | 216 ++++++++++++++++++++++++++++++
arch/powerpc/kvm/book3s_hv_tm_builtin.c | 109 +++++++++++++++
arch/powerpc/kvm/powerpc.c | 5 +-
16 files changed, 557 insertions(+), 10 deletions(-)
create mode 100644 arch/powerpc/kvm/book3s_hv_tm.c
create mode 100644 arch/powerpc/kvm/book3s_hv_tm_builtin.c
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
index 09a802b..a790d5c 100644
--- a/arch/powerpc/include/asm/kvm_asm.h
+++ b/arch/powerpc/include/asm/kvm_asm.h
@@ -108,6 +108,8 @@
/* book3s_hv */
+#define BOOK3S_INTERRUPT_HV_SOFTPATCH 0x1500
+
/*
* Special trap used to indicate to host that this is a
* passthrough interrupt that could not be handled
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 376ae80..4c02a73 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -241,6 +241,10 @@ extern void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr,
unsigned long mask);
extern void kvmppc_set_fscr(struct kvm_vcpu *vcpu, u64 fscr);
+extern int kvmhv_p9_tm_emulation_early(struct kvm_vcpu *vcpu);
+extern int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu);
+extern void kvmhv_emulate_tm_rollback(struct kvm_vcpu *vcpu);
+
extern void kvmppc_entry_trampoline(void);
extern void kvmppc_hv_entry_trampoline(void);
extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst);
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index 998f7b7..c424e44 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -472,6 +472,49 @@ static inline void set_dirty_bits_atomic(unsigned long *map, unsigned long i,
set_bit_le(i, map);
}
+static inline u64 sanitize_msr(u64 msr)
+{
+ msr &= ~MSR_HV;
+ msr |= MSR_ME;
+ return msr;
+}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static inline void copy_from_checkpoint(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.cr = vcpu->arch.cr_tm;
+ vcpu->arch.xer = vcpu->arch.xer_tm;
+ vcpu->arch.lr = vcpu->arch.lr_tm;
+ vcpu->arch.ctr = vcpu->arch.ctr_tm;
+ vcpu->arch.amr = vcpu->arch.amr_tm;
+ vcpu->arch.ppr = vcpu->arch.ppr_tm;
+ vcpu->arch.dscr = vcpu->arch.dscr_tm;
+ vcpu->arch.tar = vcpu->arch.tar_tm;
+ memcpy(vcpu->arch.gpr, vcpu->arch.gpr_tm,
+ sizeof(vcpu->arch.gpr));
+ vcpu->arch.fp = vcpu->arch.fp_tm;
+ vcpu->arch.vr = vcpu->arch.vr_tm;
+ vcpu->arch.vrsave = vcpu->arch.vrsave_tm;
+}
+
+static inline void copy_to_checkpoint(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.cr_tm = vcpu->arch.cr;
+ vcpu->arch.xer_tm = vcpu->arch.xer;
+ vcpu->arch.lr_tm = vcpu->arch.lr;
+ vcpu->arch.ctr_tm = vcpu->arch.ctr;
+ vcpu->arch.amr_tm = vcpu->arch.amr;
+ vcpu->arch.ppr_tm = vcpu->arch.ppr;
+ vcpu->arch.dscr_tm = vcpu->arch.dscr;
+ vcpu->arch.tar_tm = vcpu->arch.tar;
+ memcpy(vcpu->arch.gpr_tm, vcpu->arch.gpr,
+ sizeof(vcpu->arch.gpr));
+ vcpu->arch.fp_tm = vcpu->arch.fp;
+ vcpu->arch.vr_tm = vcpu->arch.vr;
+ vcpu->arch.vrsave_tm = vcpu->arch.vrsave;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
#endif /* __ASM_KVM_BOOK3S_64_H__ */
diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h
index ab386af..d978fdf 100644
--- a/arch/powerpc/include/asm/kvm_book3s_asm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
@@ -119,6 +119,7 @@ struct kvmppc_host_state {
u8 host_ipi;
u8 ptid; /* thread number within subcore when split */
u8 tid; /* thread number within whole core */
+ u8 fake_suspend;
struct kvm_vcpu *kvm_vcpu;
struct kvmppc_vcore *kvm_vcore;
void __iomem *xics_phys;
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 1f53b56..deb5429 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -610,6 +610,7 @@ struct kvm_vcpu_arch {
u64 tfhar;
u64 texasr;
u64 tfiar;
+ u64 orig_texasr;
u32 cr_tm;
u64 xer_tm;
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index f1083bc..772eff7 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -232,6 +232,7 @@
#define PPC_INST_MSGSYNC 0x7c0006ec
#define PPC_INST_MSGSNDP 0x7c00011c
#define PPC_INST_MSGCLRP 0x7c00015c
+#define PPC_INST_MTMSRD 0x7c000164
#define PPC_INST_MTTMR 0x7c0003dc
#define PPC_INST_NOP 0x60000000
#define PPC_INST_PASTE 0x7c20070d
@@ -239,8 +240,10 @@
#define PPC_INST_POPCNTB_MASK 0xfc0007fe
#define PPC_INST_POPCNTD 0x7c0003f4
#define PPC_INST_POPCNTW 0x7c0002f4
+#define PPC_INST_RFEBB 0x4c000124
#define PPC_INST_RFCI 0x4c000066
#define PPC_INST_RFDI 0x4c00004e
+#define PPC_INST_RFID 0x4c000024
#define PPC_INST_RFMCI 0x4c00004c
#define PPC_INST_MFSPR 0x7c0002a6
#define PPC_INST_MFSPR_DSCR 0x7c1102a6
@@ -277,6 +280,7 @@
#define PPC_INST_TRECHKPT 0x7c0007dd
#define PPC_INST_TRECLAIM 0x7c00075d
#define PPC_INST_TABORT 0x7c00071d
+#define PPC_INST_TSR 0x7c0005dd
#define PPC_INST_NAP 0x4c000364
#define PPC_INST_SLEEP 0x4c0003a4
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index e6c7ead..cb0f272 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -156,6 +156,8 @@
#define PSSCR_SD 0x00400000 /* Status Disable */
#define PSSCR_PLS 0xf000000000000000 /* Power-saving Level Status */
#define PSSCR_GUEST_VIS 0xf0000000000003ff /* Guest-visible PSSCR fields */
+#define PSSCR_FAKE_SUSPEND 0x00000400 /* Fake-suspend bit (P9 DD2.2) */
+#define PSSCR_FAKE_SUSPEND_LG 10 /* Fake-suspend bit position */
/* Floating Point Status and Control Register (FPSCR) Fields */
#define FPSCR_FX 0x80000000 /* FPU exception summary */
@@ -237,7 +239,12 @@
#define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */
#define SPRN_TEXASR 0x82 /* Transaction EXception & Summary */
#define SPRN_TEXASRU 0x83 /* '' '' '' Upper 32 */
+#define TEXASR_ABORT __MASK(63-31) /* terminated by tabort or treclaim */
+#define TEXASR_SUSP __MASK(63-32) /* tx failed in suspended state */
+#define TEXASR_HV __MASK(63-34) /* MSR[HV] when failure occurred */
+#define TEXASR_PR __MASK(63-35) /* MSR[PR] when failure occurred */
#define TEXASR_FS __MASK(63-36) /* TEXASR Failure Summary */
+#define TEXASR_EXACT __MASK(63-37) /* TFIAR value is exact */
#define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */
#define SPRN_TIDR 144 /* Thread ID register */
#define SPRN_CTRLF 0x088
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index dbefe30..daf809a 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -568,6 +568,7 @@ int main(void)
OFFSET(VCPU_TFHAR, kvm_vcpu, arch.tfhar);
OFFSET(VCPU_TFIAR, kvm_vcpu, arch.tfiar);
OFFSET(VCPU_TEXASR, kvm_vcpu, arch.texasr);
+ OFFSET(VCPU_ORIG_TEXASR, kvm_vcpu, arch.orig_texasr);
OFFSET(VCPU_GPR_TM, kvm_vcpu, arch.gpr_tm);
OFFSET(VCPU_FPRS_TM, kvm_vcpu, arch.fp_tm.fpr);
OFFSET(VCPU_VRS_TM, kvm_vcpu, arch.vr_tm.vr);
@@ -650,6 +651,7 @@ int main(void)
HSTATE_FIELD(HSTATE_HOST_IPI, host_ipi);
HSTATE_FIELD(HSTATE_PTID, ptid);
HSTATE_FIELD(HSTATE_TID, tid);
+ HSTATE_FIELD(HSTATE_FAKE_SUSPEND, fake_suspend);
HSTATE_FIELD(HSTATE_MMCR0, host_mmcr[0]);
HSTATE_FIELD(HSTATE_MMCR1, host_mmcr[1]);
HSTATE_FIELD(HSTATE_MMCRA, host_mmcr[2]);
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 68052ea..b3de017 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -569,7 +569,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_INVALID,
.cpu_setup = __setup_cpu_power9,
.cpu_restore = __restore_cpu_power9,
- .flush_tlb = __flush_tlb_power9,
.machine_check_early = __machine_check_early_realmode_p9,
.platform = "power9",
},
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 3ac87e5..a19fbaa 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1273,7 +1273,7 @@ EXC_REAL_BEGIN(denorm_exception_hv, 0x1500, 0x100)
bne+ denorm_assist
#endif
- KVMTEST_PR(0x1500)
+ KVMTEST_HV(0x1500)
EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV)
EXC_REAL_END(denorm_exception_hv, 0x1500, 0x100)
@@ -1285,7 +1285,7 @@ EXC_VIRT_END(denorm_exception, 0x5500, 0x100)
EXC_VIRT_NONE(0x5500, 0x100)
#endif
-TRAMP_KVM_SKIP(PACA_EXGEN, 0x1500)
+TRAMP_KVM_HV(PACA_EXGEN, 0x1500)
#ifdef CONFIG_PPC_DENORMALISATION
TRAMP_REAL_BEGIN(denorm_assist)
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 85ba80d..4b19da8 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -74,9 +74,15 @@ kvm-hv-y += \
book3s_64_mmu_hv.o \
book3s_64_mmu_radix.o
+kvm-hv-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
+ book3s_hv_tm.o
+
kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \
book3s_hv_rm_xics.o book3s_hv_rm_xive.o
+kvm-book3s_64-builtin-tm-objs-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
+ book3s_hv_tm_builtin.o
+
ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
book3s_hv_hmi.o \
@@ -84,6 +90,7 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
book3s_hv_rm_mmu.o \
book3s_hv_ras.o \
book3s_hv_builtin.o \
+ $(kvm-book3s_64-builtin-tm-objs-y) \
$(kvm-book3s_64-builtin-xics-objs-y)
endif
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 8970735..a043bde 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -1206,6 +1206,19 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
r = RESUME_GUEST;
}
break;
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ case BOOK3S_INTERRUPT_HV_SOFTPATCH:
+ /*
+ * This occurs for various TM-related instructions that
+ * we need to emulate on POWER9 DD2.2. We have already
+ * handled the cases where the guest was in real-suspend
+ * mode and was transitioning to transactional state.
+ */
+ r = kvmhv_p9_tm_emulation(vcpu);
+ break;
+#endif
+
case BOOK3S_INTERRUPT_HV_RM_HARD:
r = RESUME_PASSTHROUGH;
break;
@@ -1978,7 +1991,9 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
* turn off the HFSCR bit, which causes those instructions to trap.
*/
vcpu->arch.hfscr = mfspr(SPRN_HFSCR);
- if (!cpu_has_feature(CPU_FTR_TM))
+ if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST))
+ vcpu->arch.hfscr |= HFSCR_TM;
+ else if (!cpu_has_feature(CPU_FTR_TM_COMP))
vcpu->arch.hfscr &= ~HFSCR_TM;
if (cpu_has_feature(CPU_FTR_ARCH_300))
vcpu->arch.hfscr &= ~HFSCR_MSGP;
@@ -2242,6 +2257,7 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc)
tpaca = &paca[cpu];
tpaca->kvm_hstate.kvm_vcpu = vcpu;
tpaca->kvm_hstate.ptid = cpu - vc->pcpu;
+ tpaca->kvm_hstate.fake_suspend = 0;
/* Order stores to hstate.kvm_vcpu etc. before store to kvm_vcore */
smp_wmb();
tpaca->kvm_hstate.kvm_vcore = vc;
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index f31f357..5af6174 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -787,12 +787,18 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Branch around the call if both CPU_FTR_TM and
+ * CPU_FTR_P9_TM_HV_ASSIST are off.
+ */
BEGIN_FTR_SECTION
+ b 91f
+END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
/*
* NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
*/
bl kvmppc_restore_tm
-END_FTR_SECTION_IFSET(CPU_FTR_TM)
+91:
#endif
/* Load guest PMU registers */
@@ -915,11 +921,14 @@ BEGIN_FTR_SECTION
mtspr SPRN_ACOP, r6
mtspr SPRN_CSIGR, r7
mtspr SPRN_TACR, r8
+ nop
FTR_SECTION_ELSE
/* POWER9-only registers */
ld r5, VCPU_TID(r4)
ld r6, VCPU_PSSCR(r4)
+ lbz r8, HSTATE_FAKE_SUSPEND(r13)
oris r6, r6, PSSCR_EC@h /* This makes stop trap to HV */
+ rldimi r6, r8, PSSCR_FAKE_SUSPEND_LG, 63 - PSSCR_FAKE_SUSPEND_LG
ld r7, VCPU_HFSCR(r4)
mtspr SPRN_TIDR, r5
mtspr SPRN_PSSCR, r6
@@ -1370,6 +1379,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
std r3, VCPU_CTR(r9)
std r4, VCPU_XER(r9)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* For softpatch interrupt, go off and do TM instruction emulation */
+ cmpwi r12, BOOK3S_INTERRUPT_HV_SOFTPATCH
+ beq kvmppc_tm_emul
+#endif
+
/* If this is a page table miss then see if it's theirs or ours */
cmpwi r12, BOOK3S_INTERRUPT_H_DATA_STORAGE
beq kvmppc_hdsi
@@ -1729,12 +1744,18 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
bl kvmppc_save_fp
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Branch around the call if both CPU_FTR_TM and
+ * CPU_FTR_P9_TM_HV_ASSIST are off.
+ */
BEGIN_FTR_SECTION
+ b 91f
+END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
/*
* NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
*/
bl kvmppc_save_tm
-END_FTR_SECTION_IFSET(CPU_FTR_TM)
+91:
#endif
/* Increment yield count if they have a VPA */
@@ -2054,6 +2075,42 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
mtlr r0
blr
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Softpatch interrupt for transactional memory emulation cases
+ * on POWER9 DD2.2. This is early in the guest exit path - we
+ * haven't saved registers or done a treclaim yet.
+ */
+kvmppc_tm_emul:
+ /* Save instruction image in HEIR */
+ mfspr r3, SPRN_HEIR
+ stw r3, VCPU_HEIR(r9)
+
+ /*
+ * The cases we want to handle here are those where the guest
+ * is in real suspend mode and is trying to transition to
+ * transactional mode.
+ */
+ lbz r0, HSTATE_FAKE_SUSPEND(r13)
+ cmpwi r0, 0 /* keep exiting guest if in fake suspend */
+ bne guest_exit_cont
+ rldicl r3, r11, 64 - MSR_TS_S_LG, 62
+ cmpwi r3, 1 /* or if not in suspend state */
+ bne guest_exit_cont
+
+ /* Call C code to do the emulation */
+ mr r3, r9
+ bl kvmhv_p9_tm_emulation_early
+ nop
+ ld r9, HSTATE_KVM_VCPU(r13)
+ li r12, BOOK3S_INTERRUPT_HV_SOFTPATCH
+ cmpwi r3, 0
+ beq guest_exit_cont /* continue exiting if not handled */
+ ld r10, VCPU_PC(r9)
+ ld r11, VCPU_MSR(r9)
+ b fast_interrupt_c_return /* go back to guest if handled */
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
/*
* Check whether an HDSI is an HPTE not found fault or something else.
* If it is an HPTE not found fault that is due to the guest accessing
@@ -2587,13 +2644,19 @@ _GLOBAL(kvmppc_h_cede) /* r3 = vcpu pointer, r11 = msr, r13 = paca */
bl kvmppc_save_fp
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Branch around the call if both CPU_FTR_TM and
+ * CPU_FTR_P9_TM_HV_ASSIST are off.
+ */
BEGIN_FTR_SECTION
+ b 91f
+END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
/*
* NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
*/
ld r9, HSTATE_KVM_VCPU(r13)
bl kvmppc_save_tm
-END_FTR_SECTION_IFSET(CPU_FTR_TM)
+91:
#endif
/*
@@ -2700,12 +2763,18 @@ kvm_end_cede:
#endif
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Branch around the call if both CPU_FTR_TM and
+ * CPU_FTR_P9_TM_HV_ASSIST are off.
+ */
BEGIN_FTR_SECTION
+ b 91f
+END_FTR_SECTION(CPU_FTR_TM | CPU_FTR_P9_TM_HV_ASSIST, 0)
/*
* NOTE THAT THIS TRASHES ALL NON-VOLATILE REGISTERS INCLUDING CR
*/
bl kvmppc_restore_tm
-END_FTR_SECTION_IFSET(CPU_FTR_TM)
+91:
#endif
/* load up FP state */
@@ -3046,6 +3115,15 @@ kvmppc_save_tm:
std r1, HSTATE_HOST_R1(r13)
li r3, TM_CAUSE_KVM_RESCHED
+BEGIN_FTR_SECTION
+ /* Emulation of the treclaim instruction needs TEXASR before treclaim */
+ mfspr r6, SPRN_TEXASR
+ std r6, VCPU_ORIG_TEXASR(r9)
+
+ rldicl. r8, r8, 64 - MSR_TS_S_LG, 62
+ beq 3f
+END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
+
/* Clear the MSR RI since r1, r13 are all going to be foobar. */
li r5, 0
mtmsrd r5, 1
@@ -3057,6 +3135,38 @@ kvmppc_save_tm:
SET_SCRATCH0(r13)
GET_PACA(r13)
std r9, PACATMSCRATCH(r13)
+
+ /* If doing TM emulation on POWER9 DD2.2, check for fake suspend mode */
+BEGIN_FTR_SECTION
+3:
+ lbz r9, HSTATE_FAKE_SUSPEND(r13)
+ cmpwi r9, 0
+ beq 2f
+ /*
+ * We were in fake suspend, so we are not going to save the
+ * register state as the guest checkpointed state (since
+ * we already have it), therefore we can now use any volatile GPR.
+ */
+ /* Reload stack pointer and TOC. */
+ ld r1, HSTATE_HOST_R1(r13)
+ ld r2, PACATOC(r13)
+ li r5, MSR_RI
+ mtmsrd r5, 1
+ HMT_MEDIUM
+ ld r6, HSTATE_DSCR(r13)
+ mtspr SPRN_DSCR, r6
+ li r0, 0
+ stb r0, HSTATE_FAKE_SUSPEND(r13)
+ mfspr r3, SPRN_PSSCR
+ /* PSSCR_FAKE_SUSPEND is a write-only bit, but clear it anyway */
+ li r0, PSSCR_FAKE_SUSPEND
+ andc r3, r3, r0
+ mtspr SPRN_PSSCR, r3
+ ld r9, HSTATE_KVM_VCPU(r13)
+ b 1f
+2:
+END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
+
ld r9, HSTATE_KVM_VCPU(r13)
/* Get a few more GPRs free. */
@@ -3182,6 +3292,15 @@ kvmppc_restore_tm:
mtspr SPRN_TEXASR, r7
/*
+ * If we are doing TM emulation for the guest on a POWER9 DD2,
+ * then we don't actually do a trechkpt -- we either set up
+ * fake-suspend mode, or emulate a TM rollback.
+ */
+BEGIN_FTR_SECTION
+ b .Ldo_tm_fake_load
+END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
+
+ /*
* We need to load up the checkpointed state for the guest.
* We need to do this early as it will blow away any GPRs, VSRs and
* some SPRs.
@@ -3253,10 +3372,24 @@ kvmppc_restore_tm:
/* Set the MSR RI since we have our registers back. */
li r5, MSR_RI
mtmsrd r5, 1
-
+9:
ld r0, PPC_LR_STKOFF(r1)
mtlr r0
blr
+
+.Ldo_tm_fake_load:
+ cmpwi r5, 1 /* check for suspended state */
+ bgt 10f
+ stb r5, HSTATE_FAKE_SUSPEND(r13)
+ b 9b /* and return */
+10: stdu r1, -PPC_MIN_STKFRM(r1)
+ /* guest is in transactional state, so simulate rollback */
+ mr r3, r4
+ bl kvmhv_emulate_tm_rollback
+ nop
+ ld r4, HSTATE_KVM_VCPU(r13) /* our vcpu pointer has been trashed */
+ addi r1, r1, PPC_MIN_STKFRM
+ b 9b
#endif
/*
diff --git a/arch/powerpc/kvm/book3s_hv_tm.c b/arch/powerpc/kvm/book3s_hv_tm.c
new file mode 100644
index 0000000..bf710ad
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_tm.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2017 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_book3s_64.h>
+#include <asm/reg.h>
+#include <asm/ppc-opcode.h>
+
+static void emulate_tx_failure(struct kvm_vcpu *vcpu, u64 failure_cause)
+{
+ u64 texasr, tfiar;
+ u64 msr = vcpu->arch.shregs.msr;
+
+ tfiar = vcpu->arch.pc & ~0x3ull;
+ texasr = (failure_cause << 56) | TEXASR_ABORT | TEXASR_FS | TEXASR_EXACT;
+ if (MSR_TM_SUSPENDED(vcpu->arch.shregs.msr))
+ texasr |= TEXASR_SUSP;
+ if (msr & MSR_PR) {
+ texasr |= TEXASR_PR;
+ tfiar |= 1;
+ }
+ vcpu->arch.tfiar = tfiar;
+ /* Preserve ROT and TL fields of existing TEXASR */
+ vcpu->arch.texasr = (vcpu->arch.texasr & 0x3ffffff) | texasr;
+}
+
+/*
+ * This gets called on a softpatch interrupt on POWER9 DD2.2 processors.
+ * We expect to find a TM-related instruction to be emulated. The
+ * instruction image is in vcpu->arch.emul_inst. If the guest was in
+ * TM suspended or transactional state, the checkpointed state has been
+ * reclaimed and is in the vcpu struct. The CPU is in virtual mode in
+ * host context.
+ */
+int kvmhv_p9_tm_emulation(struct kvm_vcpu *vcpu)
+{
+ u32 instr = vcpu->arch.emul_inst;
+ u64 msr = vcpu->arch.shregs.msr;
+ u64 newmsr, bescr;
+ int ra, rs;
+
+ switch (instr & 0xfc0007ff) {
+ case PPC_INST_RFID:
+ /* XXX do we need to check for PR=0 here? */
+ newmsr = vcpu->arch.shregs.srr1;
+ /* should only get here for Sx -> T1 transition */
+ WARN_ON_ONCE(!(MSR_TM_SUSPENDED(msr) &&
+ MSR_TM_TRANSACTIONAL(newmsr) &&
+ (newmsr & MSR_TM)));
+ newmsr = sanitize_msr(newmsr);
+ vcpu->arch.shregs.msr = newmsr;
+ vcpu->arch.cfar = vcpu->arch.pc - 4;
+ vcpu->arch.pc = vcpu->arch.shregs.srr0;
+ return RESUME_GUEST;
+
+ case PPC_INST_RFEBB:
+ if ((msr & MSR_PR) && (vcpu->arch.vcore->pcr & PCR_ARCH_206)) {
+ /* generate an illegal instruction interrupt */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ return RESUME_GUEST;
+ }
+ /* check EBB facility is available */
+ if (!(vcpu->arch.hfscr & HFSCR_EBB)) {
+ /* generate an illegal instruction interrupt */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ return RESUME_GUEST;
+ }
+ if ((msr & MSR_PR) && !(vcpu->arch.fscr & FSCR_EBB)) {
+ /* generate a facility unavailable interrupt */
+ vcpu->arch.fscr = (vcpu->arch.fscr & ~(0xffull << 56)) |
+ ((u64)FSCR_EBB_LG << 56);
+ kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FAC_UNAVAIL);
+ return RESUME_GUEST;
+ }
+ bescr = vcpu->arch.bescr;
+ /* expect to see a S->T transition requested */
+ WARN_ON_ONCE(!(MSR_TM_SUSPENDED(msr) &&
+ ((bescr >> 30) & 3) == 2));
+ bescr &= ~BESCR_GE;
+ if (instr & (1 << 11))
+ bescr |= BESCR_GE;
+ vcpu->arch.bescr = bescr;
+ msr = (msr & ~MSR_TS_MASK) | MSR_TS_T;
+ vcpu->arch.shregs.msr = msr;
+ vcpu->arch.cfar = vcpu->arch.pc - 4;
+ vcpu->arch.pc = vcpu->arch.ebbrr;
+ return RESUME_GUEST;
+
+ case PPC_INST_MTMSRD:
+ /* XXX do we need to check for PR=0 here? */
+ rs = (instr >> 21) & 0x1f;
+ newmsr = kvmppc_get_gpr(vcpu, rs);
+ /* check this is a Sx -> T1 transition */
+ WARN_ON_ONCE(!(MSR_TM_SUSPENDED(msr) &&
+ MSR_TM_TRANSACTIONAL(newmsr) &&
+ (newmsr & MSR_TM)));
+ /* mtmsrd doesn't change LE */
+ newmsr = (newmsr & ~MSR_LE) | (msr & MSR_LE);
+ newmsr = sanitize_msr(newmsr);
+ vcpu->arch.shregs.msr = newmsr;
+ return RESUME_GUEST;
+
+ case PPC_INST_TSR:
+ /* check for PR=1 and arch 2.06 bit set in PCR */
+ if ((msr & MSR_PR) && (vcpu->arch.vcore->pcr & PCR_ARCH_206)) {
+ /* generate an illegal instruction interrupt */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ return RESUME_GUEST;
+ }
+ /* check for TM disabled in the HFSCR or MSR */
+ if (!(vcpu->arch.hfscr & HFSCR_TM)) {
+ /* generate an illegal instruction interrupt */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ return RESUME_GUEST;
+ }
+ if (!(msr & MSR_TM)) {
+ /* generate a facility unavailable interrupt */
+ vcpu->arch.fscr = (vcpu->arch.fscr & ~(0xffull << 56)) |
+ ((u64)FSCR_TM_LG << 56);
+ kvmppc_book3s_queue_irqprio(vcpu,
+ BOOK3S_INTERRUPT_FAC_UNAVAIL);
+ return RESUME_GUEST;
+ }
+ /* Set CR0 to indicate previous transactional state */
+ vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) |
+ (((msr & MSR_TS_MASK) >> MSR_TS_S_LG) << 28);
+ /* L=1 => tresume, L=0 => tsuspend */
+ if (instr & (1 << 21)) {
+ if (MSR_TM_SUSPENDED(msr))
+ msr = (msr & ~MSR_TS_MASK) | MSR_TS_T;
+ } else {
+ if (MSR_TM_TRANSACTIONAL(msr))
+ msr = (msr & ~MSR_TS_MASK) | MSR_TS_S;
+ }
+ vcpu->arch.shregs.msr = msr;
+ return RESUME_GUEST;
+
+ case PPC_INST_TRECLAIM:
+ /* check for TM disabled in the HFSCR or MSR */
+ if (!(vcpu->arch.hfscr & HFSCR_TM)) {
+ /* generate an illegal instruction interrupt */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ return RESUME_GUEST;
+ }
+ if (!(msr & MSR_TM)) {
+ /* generate a facility unavailable interrupt */
+ vcpu->arch.fscr = (vcpu->arch.fscr & ~(0xffull << 56)) |
+ ((u64)FSCR_TM_LG << 56);
+ kvmppc_book3s_queue_irqprio(vcpu,
+ BOOK3S_INTERRUPT_FAC_UNAVAIL);
+ return RESUME_GUEST;
+ }
+ /* If no transaction active, generate TM bad thing */
+ if (!MSR_TM_ACTIVE(msr)) {
+ kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+ return RESUME_GUEST;
+ }
+ /* If failure was not previously recorded, recompute TEXASR */
+ if (!(vcpu->arch.orig_texasr & TEXASR_FS)) {
+ ra = (instr >> 16) & 0x1f;
+ if (ra)
+ ra = kvmppc_get_gpr(vcpu, ra) & 0xff;
+ emulate_tx_failure(vcpu, ra);
+ }
+
+ copy_from_checkpoint(vcpu);
+
+ /* Set CR0 to indicate previous transactional state */
+ vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) |
+ (((msr & MSR_TS_MASK) >> MSR_TS_S_LG) << 28);
+ vcpu->arch.shregs.msr &= ~MSR_TS_MASK;
+ return RESUME_GUEST;
+
+ case PPC_INST_TRECHKPT:
+ /* XXX do we need to check for PR=0 here? */
+ /* check for TM disabled in the HFSCR or MSR */
+ if (!(vcpu->arch.hfscr & HFSCR_TM)) {
+ /* generate an illegal instruction interrupt */
+ kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+ return RESUME_GUEST;
+ }
+ if (!(msr & MSR_TM)) {
+ /* generate a facility unavailable interrupt */
+ vcpu->arch.fscr = (vcpu->arch.fscr & ~(0xffull << 56)) |
+ ((u64)FSCR_TM_LG << 56);
+ kvmppc_book3s_queue_irqprio(vcpu,
+ BOOK3S_INTERRUPT_FAC_UNAVAIL);
+ return RESUME_GUEST;
+ }
+ /* If transaction active or TEXASR[FS] = 0, bad thing */
+ if (MSR_TM_ACTIVE(msr) || !(vcpu->arch.texasr & TEXASR_FS)) {
+ kvmppc_core_queue_program(vcpu, SRR1_PROGTM);
+ return RESUME_GUEST;
+ }
+
+ copy_to_checkpoint(vcpu);
+
+ /* Set CR0 to indicate previous transactional state */
+ vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) |
+ (((msr & MSR_TS_MASK) >> MSR_TS_S_LG) << 28);
+ vcpu->arch.shregs.msr = msr | MSR_TS_S;
+ return RESUME_GUEST;
+ }
+
+ /* What should we do here? We didn't recognize the instruction */
+ WARN_ON_ONCE(1);
+ return RESUME_GUEST;
+}
diff --git a/arch/powerpc/kvm/book3s_hv_tm_builtin.c b/arch/powerpc/kvm/book3s_hv_tm_builtin.c
new file mode 100644
index 0000000..d98ccfd
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_tm_builtin.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_ppc.h>
+#include <asm/kvm_book3s.h>
+#include <asm/kvm_book3s_64.h>
+#include <asm/reg.h>
+#include <asm/ppc-opcode.h>
+
+/*
+ * This handles the cases where the guest is in real suspend mode
+ * and we want to get back to the guest without dooming the transaction.
+ * The caller has checked that the guest is in real-suspend mode
+ * (MSR[TS] = S and the fake-suspend flag is not set).
+ */
+int kvmhv_p9_tm_emulation_early(struct kvm_vcpu *vcpu)
+{
+ u32 instr = vcpu->arch.emul_inst;
+ u64 newmsr, msr, bescr;
+ int rs;
+
+ switch (instr & 0xfc0007ff) {
+ case PPC_INST_RFID:
+ /* XXX do we need to check for PR=0 here? */
+ newmsr = vcpu->arch.shregs.srr1;
+ /* should only get here for Sx -> T1 transition */
+ if (!(MSR_TM_TRANSACTIONAL(newmsr) && (newmsr & MSR_TM)))
+ return 0;
+ newmsr = sanitize_msr(newmsr);
+ vcpu->arch.shregs.msr = newmsr;
+ vcpu->arch.cfar = vcpu->arch.pc - 4;
+ vcpu->arch.pc = vcpu->arch.shregs.srr0;
+ return 1;
+
+ case PPC_INST_RFEBB:
+ /* check for PR=1 and arch 2.06 bit set in PCR */
+ msr = vcpu->arch.shregs.msr;
+ if ((msr & MSR_PR) && (vcpu->arch.vcore->pcr & PCR_ARCH_206))
+ return 0;
+ /* check EBB facility is available */
+ if (!(vcpu->arch.hfscr & HFSCR_EBB) ||
+ ((msr & MSR_PR) && !(mfspr(SPRN_FSCR) & FSCR_EBB)))
+ return 0;
+ bescr = mfspr(SPRN_BESCR);
+ /* expect to see a S->T transition requested */
+ if (((bescr >> 30) & 3) != 2)
+ return 0;
+ bescr &= ~BESCR_GE;
+ if (instr & (1 << 11))
+ bescr |= BESCR_GE;
+ mtspr(SPRN_BESCR, bescr);
+ msr = (msr & ~MSR_TS_MASK) | MSR_TS_T;
+ vcpu->arch.shregs.msr = msr;
+ vcpu->arch.cfar = vcpu->arch.pc - 4;
+ vcpu->arch.pc = mfspr(SPRN_EBBRR);
+ return 1;
+
+ case PPC_INST_MTMSRD:
+ /* XXX do we need to check for PR=0 here? */
+ rs = (instr >> 21) & 0x1f;
+ newmsr = kvmppc_get_gpr(vcpu, rs);
+ msr = vcpu->arch.shregs.msr;
+ /* check this is a Sx -> T1 transition */
+ if (!(MSR_TM_TRANSACTIONAL(newmsr) && (newmsr & MSR_TM)))
+ return 0;
+ /* mtmsrd doesn't change LE */
+ newmsr = (newmsr & ~MSR_LE) | (msr & MSR_LE);
+ newmsr = sanitize_msr(newmsr);
+ vcpu->arch.shregs.msr = newmsr;
+ return 1;
+
+ case PPC_INST_TSR:
+ /* we know the MSR has the TS field = S (0b01) here */
+ msr = vcpu->arch.shregs.msr;
+ /* check for PR=1 and arch 2.06 bit set in PCR */
+ if ((msr & MSR_PR) && (vcpu->arch.vcore->pcr & PCR_ARCH_206))
+ return 0;
+ /* check for TM disabled in the HFSCR or MSR */
+ if (!(vcpu->arch.hfscr & HFSCR_TM) || !(msr & MSR_TM))
+ return 0;
+ /* L=1 => tresume => set TS to T (0b10) */
+ if (instr & (1 << 21))
+ vcpu->arch.shregs.msr = (msr & ~MSR_TS_MASK) | MSR_TS_T;
+ /* Set CR0 to 0b0010 */
+ vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | 0x20000000;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * This is called when we are returning to a guest in TM transactional
+ * state. We roll the guest state back to the checkpointed state.
+ */
+void kvmhv_emulate_tm_rollback(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.shregs.msr &= ~MSR_TS_MASK; /* go to N state */
+ vcpu->arch.pc = vcpu->arch.tfhar;
+ copy_from_checkpoint(vcpu);
+ vcpu->arch.cr = (vcpu->arch.cr & 0x0fffffff) | 0xa0000000;
+}
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 52c2053..4e38764 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -646,10 +646,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = hv_enabled;
break;
#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
case KVM_CAP_PPC_HTM:
r = hv_enabled &&
- (cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM_COMP);
+ (!!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM) ||
+ cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST));
break;
+#endif
default:
r = 0;
break;
--
2.7.4
^ permalink raw reply related
* [PATCH 4/5] KVM: PPC: Book3S HV: Work around XER[SO] bug in fake suspend mode
From: Paul Mackerras @ 2018-03-21 10:25 UTC (permalink / raw)
To: kvm, linuxppc-dev; +Cc: kvm-ppc
In-Reply-To: <1521627901-13547-1-git-send-email-paulus@ozlabs.org>
From: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
This works around a hardware bug in "Nimbus" POWER9 DD2.2 processors,
where a treclaim performed in fake suspend mode can cause subsequent
reads from the XER register to return inconsistent values for the SO
(summary overflow) bit. The inconsistent SO bit state can potentially
be observed on any thread in the core. We have to do the treclaim
because that is the only way to get the thread out of suspend state
(fake or real) and into non-transactional state.
The workaround for the bug is to force the core into SMT4 mode before
doing the treclaim. This patch adds the code to do that, conditional
on the CPU_FTR_P9_TM_XER_SO_BUG feature bit.
Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
---
arch/powerpc/kvm/book3s_hv_rmhandlers.S | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 5af6174..11396c0 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -3101,6 +3101,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
kvmppc_save_tm:
mflr r0
std r0, PPC_LR_STKOFF(r1)
+ stdu r1, -PPC_MIN_STKFRM(r1)
/* Turn on TM. */
mfmsr r8
@@ -3120,8 +3121,16 @@ BEGIN_FTR_SECTION
mfspr r6, SPRN_TEXASR
std r6, VCPU_ORIG_TEXASR(r9)
- rldicl. r8, r8, 64 - MSR_TS_S_LG, 62
+ lbz r0, HSTATE_FAKE_SUSPEND(r13) /* Were we fake suspended? */
+ cmpwi r0, 0
beq 3f
+ rldicl. r8, r8, 64 - MSR_TS_S_LG, 62 /* Did we actually hrfid? */
+ beq 4f
+BEGIN_FTR_SECTION_NESTED(96)
+ bl pnv_power9_force_smt4_catch
+END_FTR_SECTION_NESTED(CPU_FTR_P9_TM_XER_SO_BUG, CPU_FTR_P9_TM_XER_SO_BUG, 96)
+ nop
+3:
END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
/* Clear the MSR RI since r1, r13 are all going to be foobar. */
@@ -3138,7 +3147,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
/* If doing TM emulation on POWER9 DD2.2, check for fake suspend mode */
BEGIN_FTR_SECTION
-3:
lbz r9, HSTATE_FAKE_SUSPEND(r13)
cmpwi r9, 0
beq 2f
@@ -3150,13 +3158,18 @@ BEGIN_FTR_SECTION
/* Reload stack pointer and TOC. */
ld r1, HSTATE_HOST_R1(r13)
ld r2, PACATOC(r13)
+ /* Set MSR RI now we have r1 and r13 back. */
li r5, MSR_RI
mtmsrd r5, 1
HMT_MEDIUM
ld r6, HSTATE_DSCR(r13)
mtspr SPRN_DSCR, r6
- li r0, 0
- stb r0, HSTATE_FAKE_SUSPEND(r13)
+BEGIN_FTR_SECTION_NESTED(96)
+ bl pnv_power9_force_smt4_release
+END_FTR_SECTION_NESTED(CPU_FTR_P9_TM_XER_SO_BUG, CPU_FTR_P9_TM_XER_SO_BUG, 96)
+ nop
+
+4:
mfspr r3, SPRN_PSSCR
/* PSSCR_FAKE_SUSPEND is a write-only bit, but clear it anyway */
li r0, PSSCR_FAKE_SUSPEND
@@ -3244,6 +3257,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_P9_TM_HV_ASSIST)
std r6, VCPU_TFIAR(r9)
std r7, VCPU_TEXASR(r9)
+ addi r1, r1, PPC_MIN_STKFRM
ld r0, PPC_LR_STKOFF(r1)
mtlr r0
blr
@@ -3278,6 +3292,8 @@ kvmppc_restore_tm:
mtspr SPRN_TFIAR, r6
mtspr SPRN_TEXASR, r7
+ li r0, 0
+ stb r0, HSTATE_FAKE_SUSPEND(r13)
ld r5, VCPU_MSR(r4)
rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
beqlr /* TM not active in guest */
--
2.7.4
^ 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