* Re: [PATCH 15/17] powerpc: Add config option for transactional memory
From: Michael Neuling @ 2013-02-14 1:52 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Matt Evans
In-Reply-To: <2AEBB52F-9DB5-4211-9DA7-B1D271F1D6E8@kernel.crashing.org>
Kumar Gala <galak@kernel.crashing.org> wrote:
>
> On Feb 12, 2013, at 10:31 PM, Michael Neuling wrote:
>
> > Kconfig option for transactional memory on powerpc.
> >
> > Signed-off-by: Matt Evans <matt@ozlabs.org>
> > Signed-off-by: Michael Neuling <mikey@neuling.org>
> > ---
> > arch/powerpc/Kconfig | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> > index 4b27edb..fbeb6d2 100644
> > --- a/arch/powerpc/Kconfig
> > +++ b/arch/powerpc/Kconfig
> > @@ -313,6 +313,14 @@ config MATH_EMULATION
> > unit, which will allow programs that use floating-point
> > instructions to run.
> >
> > +config PPC_TRANSACTIONAL_MEM
> > + bool "Transactional Memory support for POWERPC"
> > + depends on PPC64
>
> Should this really depend on PPC_BOOK3S_64 ?
OK, thanks.
Mikey
^ permalink raw reply
* Re: [PATCH] powerpc: Apply early paca fixups to boot_paca and the boot cpu's paca
From: Geoff Levand @ 2013-02-14 0:57 UTC (permalink / raw)
To: Michael Ellerman; +Cc: phileas-fogg, linuxppc-dev, stable
In-Reply-To: <1360716290-15985-1-git-send-email-michael@ellerman.id.au>
On Wed, 2013-02-13 at 11:44 +1100, Michael Ellerman wrote:
> In commit 466921c we added a hack to set the paca data_offset to zero so
> that per-cpu accesses would work on the boot cpu prior to per-cpu areas
> being setup. This fixed a problem with lockdep touching per-cpu areas
> very early in boot.
>
> However if we combine CONFIG_LOCK_STAT=y with any of the PPC_EARLY_DEBUG
> options, we can hit the same problem in udbg_early_init(). To avoid that
> we need to set the data_offset of the boot_paca also. So factor out the
> fixup logic and call it for both the boot_paca, and "the paca of the
> boot cpu".
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Tested-by: Geoff Levand <geoff@infradead.org>
This fixes a boot hang on the PS3 with ps3_defconfig builds of
linux-3.7.
Please consider applying for linux-3.7.x stable.
-Geoff
^ permalink raw reply
* [PATCH] powerpc: Mark low level irq handlers NO_THREAD
From: Thomas Gleixner @ 2013-02-13 22:38 UTC (permalink / raw)
To: linuxppc-dev; +Cc: leroy christophe
These low level handlers cannot be threaded. Mark them NO_THREAD
Reported-by: leroy christophe <christophe.leroy@c-s.fr>
Tested-by: leroy christophe <christophe.leroy@c-s.fr>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
arch/powerpc/platforms/8xx/m8xx_setup.c | 1 +
arch/powerpc/sysdev/cpm1.c | 1 +
2 files changed, 2 insertions(+)
Index: linux-stable/arch/powerpc/platforms/8xx/m8xx_setup.c
===================================================================
--- linux-stable.orig/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ linux-stable/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -43,6 +43,7 @@ static irqreturn_t timebase_interrupt(in
static struct irqaction tbint_irqaction = {
.handler = timebase_interrupt,
+ .flags = IRQF_NO_THREAD,
.name = "tbint",
};
Index: linux-stable/arch/powerpc/sysdev/cpm1.c
===================================================================
--- linux-stable.orig/arch/powerpc/sysdev/cpm1.c
+++ linux-stable/arch/powerpc/sysdev/cpm1.c
@@ -120,6 +120,7 @@ static irqreturn_t cpm_error_interrupt(i
static struct irqaction cpm_error_irqaction = {
.handler = cpm_error_interrupt,
+ .flags = IRQF_NO_THREAD,
.name = "error",
};
^ permalink raw reply
* Re: PS3 platform is broken on Linux 3.7.0
From: Michael Ellerman @ 2013-02-13 22:37 UTC (permalink / raw)
To: Geoff Levand; +Cc: Phileas Fogg, cbe-oss-dev, linuxppc-dev
In-Reply-To: <1360740779.28936.20.camel@clam>
On Tue, Feb 12, 2013 at 11:32:59PM -0800, Geoff Levand wrote:
> Hi,
>
> On Fri, 2012-12-14 at 16:35 +0400, Phileas Fogg wrote:
> > I wanted to bring to your attention the fact that the PS3 platform is broken on Linux 3.7.0.
>
> > So i cloned the Linux powerpc GIT repository and tried to find out which commits broke the PS3 platform.
>
> > ---------------------------------------------------------------------------------------------
> >
> > commit 407821a34fce89b4f0b031dbab5cec7d059f46bc
> > Author: Michael Ellerman <michael@ellerman.id.au>
> > Date: Fri Sep 7 15:31:44 2012 +0000
> >
> > powerpc: Initialise paca.data_offset with poison
>
> I did a little more work on this, and it seems the change below
> will fix the problem introduced by Michael's change. I can only
> guess we need to use udbg_printf() here. I'll look at it some more
> as I have time.
Have you tried with the patch I posted yesterday?
cheers
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: Make context bits depend on virtual addr size.
From: Geoff Levand @ 2013-02-13 20:09 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: phileas-fogg, linuxppc-dev, paulus
In-Reply-To: <87pq04jvb4.fsf@linux.vnet.ibm.com>
Hi Aneesh,
On Wed, 2013-02-13 at 17:10 +0530, Aneesh Kumar K.V wrote:
> Ok. How about the below patch. This is based on the suggestion from
> Paulus. I still have to take care of few comments in the code.
>
> Phileas and Geoff,
>
> Can we check whether this fix the PS3 boot hang ?
I did a quick build and boot test, and this one seems to work OK.
-Geoff
^ permalink raw reply
* Re[2]: [PATCH 2/2] powerpc: Make context bits depend on virtual addr size.
From: Phileas Fogg @ 2013-02-13 18:13 UTC (permalink / raw)
To: Aneesh Kumar K.V; +Cc: geoff, linuxppc-dev, paulus
In-Reply-To: <87pq04jvb4.fsf@linux.vnet.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 481 bytes --]
>
>Ok. How about the below patch. This is based on the suggestion from
>Paulus. I still have to take care of few comments in the code.
>
>We now split the proto-vsid range differently.
> User: 0 to [2^(CONTEXT_BITS) - 4 + 2^(USER_ESID_BITS)]
> kernel: [2^(CONTEXT_BITS) - 4 + 2^(USER_ESID_BITS)] to 2^(VSID_BITS) - 1
>
>Phileas and Geoff,
>
>Can we check whether this fix the PS3 boot hang ?
Tested the new patch with Linux 3.8.0-rc7, it seems to be working well.
regards
[-- Attachment #2: Type: text/html, Size: 890 bytes --]
^ permalink raw reply
* RE: [PATCH 2/2] powerpc: Make context bits depend on virtual addr size.
From: Aneesh Kumar K.V @ 2013-02-13 18:07 UTC (permalink / raw)
To: David Laight, Benjamin Herrenschmidt, phileas-fogg, geoff
Cc: paulus, linuxppc-dev
In-Reply-To: <87mwv8jnmj.fsf@linux.vnet.ibm.com>
"Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> writes:
> David Laight <David.Laight@aculab.com> writes:
>
>>> +#define CONTEXT_BITS 19
>>> +#define USER_ESID_BITS 18
>>> +#define USER_ESID_BITS_1T 6
>>> +
>>> +/*
>>> + * 256MB segment
>>> + * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments
>>> + * available for user + kernel mapping. The top 4 contexts are used for
>>> + * kernel mapping. Each segment contains 2^28 bytes. Each
>>> + * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts
>>> + * (19 == 37 + 28 - 46).
>>> + */
>>
>> I can't help feeling this would be easier to understand if a full
>> 64? 80? bit address was shown with the various bit ranges identified.
>>
>> Given the comment, I'd have expected CONTEXT_BITS to be calculated
>> from three other named constants - rather than being set to 19.
>>
>
> May be the comments were misleading. We build proto vsid using a
> combination of context and ea bits.
>
> Current code does the below:
>
> for kernel:
> proto_vsid = ea >> SID_SHIFT;
> proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS));
> for user:
> proto_vsid = ea >> SID_SHIFT
> proto_vsid |= context << USER_ESID_BITS
>
> context range is 0 - (2^19 -1)
>
> With this patch we _don't_ give kernel half the proto vsid range.
> Instead, we reduce the proto vsid range and then the kernel is given
> top 4 context. ie, kernel proto vsid is now
>
> for kenel:
> proto_vsid = ea >> SID_SHIFT;
> context = (MAX_CONTEXT - 4) + ((effective address >> 60) - 0xc);
> proto_vsid |= context << USER_ESID_BITS
>
Hmm that may be an issue, considering ESID for kernel is 36 bits.
We have overlapping bits between shifted value of context and kernel
ESID.
-aneesh
^ permalink raw reply
* Re: BOOKE KVM calling load_up_fpu from C?
From: Scott Wood @ 2013-02-13 17:37 UTC (permalink / raw)
To: Bhushan Bharat-R65777
Cc: Wood Scott-B07421, Michael Neuling, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <6A3DF150A5B70D4F9B66A25E3F7C888D065A3511@039-SN2MPN1-023.039d.mgd.msft.net>
On 02/12/2013 10:17:00 PM, Bhushan Bharat-R65777 wrote:
>=20
>=20
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Wednesday, February 13, 2013 6:53 AM
> > To: Bhushan Bharat-R65777
> > Cc: Wood Scott-B07421; Michael Neuling; =20
> linuxppc-dev@lists.ozlabs.org
> > Subject: Re: BOOKE KVM calling load_up_fpu from C?
> >
> > On 02/12/2013 07:18:14 PM, Bhushan Bharat-R65777 wrote:
> > >
> > >
> > > > -----Original Message-----
> > > > From: Wood Scott-B07421
> > > > Sent: Wednesday, February 13, 2013 12:03 AM
> > > > To: Bhushan Bharat-R65777
> > > > Cc: Michael Neuling; Wood Scott-B07421;
> > > linuxppc-dev@lists.ozlabs.org
> > > > Subject: Re: BOOKE KVM calling load_up_fpu from C?
> > > >
> > > > On 64-bit, though, there's a store to the caller's stack frame
> > > > (yuck) which the kvm/booke.h caller is not prepared for.
> > >
> > > So if caller is using r12 then it can lead to come corruption, =20
> right ?
> >
> > No, r12 is a volatile register in the ABI, as is r9. The issue is =20
> that the
> > stack can be corrupted.
>=20
> What do you mean by stack is corrupted?
load_up_fpu() makes assumptions about the caller's stack frame that =20
aren't true when called from C code.
> My understanding is that when calling the assembly function from C =20
> function then stack frame will not be pushed and assembly function =20
> uses the caller stack frame.
Huh? Assembly functions obey the same ABI as C functions (at least, =20
asm functions meant to be callable from C do). If the above were true, =20
how would C code know that it's calling an asm function, and how would =20
it know how much stack to create and which portions would be clobbered?
The issue with load_up_fpu() is that it was apparently not meant to be =20
called directly from C code.
-Scott=
^ permalink raw reply
* Re: [PATCH v3 1/1] powerpc/85xx: Board support for ppa8548
From: Timur Tabi @ 2013-02-13 17:29 UTC (permalink / raw)
To: Stef van Os
Cc: scottwood@freescale.com, Paul Mackerras,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1360764540-4185-1-git-send-email-stef.van.os@prodrive.nl>
On 02/13/2013 08:09 AM, Stef van Os wrote:
> Initial board support for the Prodrive PPA8548 AMC module. Board
> is an MPC8548 AMC platform used in RapidIO systems. This module is
> also used to test/work on mainline linux RapidIO software.
>
> PPA8548 overview:
> - 1.3 GHz Freescale PowerQUICC III MPC8548 processor
> - 1 GB DDR2 @ 266 MHz
> - 8 MB NOR flash
> - Serial RapidIO 1.2
> - 1 x 10/100/1000 BASE-T front ethernet
> - 1 x 1000 BASE-BX ethernet on AMC connector
>
> Signed-off-by: Stef van Os <stef.van.os@prodrive.nl>
Acked-by: Timur Tabi <timur@tabi.org>
^ permalink raw reply
* [PATCH] Enhanced support for MPC8xx/8xxx watchdog
From: Christophe Leroy @ 2013-02-13 15:19 UTC (permalink / raw)
To: Wim Van Sebroeck; +Cc: linuxppc-dev, linux-kernel, linux-watchdog
This patch modifies the behaviour of the MPC8xx/8xxx watchdog. On the MPC8xx,
at 133Mhz, the maximum timeout of the watchdog timer is 1s, which means it must
be pinged twice a second. This is not in line with the Linux watchdog concept
which is based on a default watchdog timeout around 60s.
This patch introduces an intermediate layer between the CPU and the userspace.
The kernel pings the watchdog at the required frequency at the condition that
userspace tools refresh it regularly.
The new parameter 'heartbeat' allows to set up the userspace timeout.
The driver also implements the WDIOC_SETTIMEOUT ioctl.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
diff -ur linux-3.7.7/drivers/watchdog/mpc8xxx_wdt.c linux/drivers/watchdog/mpc8xxx_wdt.c
--- linux-3.7.7/drivers/watchdog/mpc8xxx_wdt.c 2013-02-11 18:05:09.000000000 +0100
+++ linux/drivers/watchdog/mpc8xxx_wdt.c 2013-02-13 15:55:22.000000000 +0100
@@ -52,10 +52,17 @@
static struct mpc8xxx_wdt __iomem *wd_base;
static int mpc8xxx_wdt_init_late(void);
+#define WD_TIMO 10 /* Default heartbeat = 10 seconds */
+
+static int heartbeat = WD_TIMO;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog SW heartbeat in seconds. (0 < heartbeat < 65536s, default="
+ __MODULE_STRING(WD_TIMO) "s)");
static u16 timeout = 0xffff;
module_param(timeout, ushort, 0);
MODULE_PARM_DESC(timeout,
- "Watchdog timeout in ticks. (0<timeout<65536, default=65535)");
+ "Watchdog HW timeout in ticks. (0<timeout<65536, default=65535)");
static bool reset = 1;
module_param(reset, bool, 0);
@@ -74,8 +81,10 @@
static int prescale = 1;
static unsigned int timeout_sec;
+static int wdt_auto = 1;
static unsigned long wdt_is_open;
static DEFINE_SPINLOCK(wdt_spinlock);
+static unsigned long wdt_last_ping;
static void mpc8xxx_wdt_keepalive(void)
{
@@ -91,9 +100,20 @@
static void mpc8xxx_wdt_timer_ping(unsigned long arg)
{
- mpc8xxx_wdt_keepalive();
- /* We're pinging it twice faster than needed, just to be sure. */
- mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
+ if (wdt_auto)
+ wdt_last_ping = jiffies;
+
+ if (jiffies - wdt_last_ping <= heartbeat * HZ) {
+ mpc8xxx_wdt_keepalive();
+ /* We're pinging it twice faster than needed, to be sure. */
+ mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
+ }
+}
+
+static void mpc8xxx_wdt_sw_keepalive(void)
+{
+ wdt_last_ping = jiffies;
+ mpc8xxx_wdt_timer_ping(0);
}
static void mpc8xxx_wdt_pr_warn(const char *msg)
@@ -106,7 +126,7 @@
size_t count, loff_t *ppos)
{
if (count)
- mpc8xxx_wdt_keepalive();
+ mpc8xxx_wdt_sw_keepalive();
return count;
}
@@ -130,7 +150,7 @@
out_be32(&wd_base->swcrr, tmp);
- del_timer_sync(&wdt_timer);
+ wdt_auto = 0;
return nonseekable_open(inode, file);
}
@@ -138,7 +158,8 @@
static int mpc8xxx_wdt_release(struct inode *inode, struct file *file)
{
if (!nowayout)
- mpc8xxx_wdt_timer_ping(0);
+ wdt_auto = 1;
+
else
mpc8xxx_wdt_pr_warn("watchdog closed");
clear_bit(0, &wdt_is_open);
@@ -163,10 +184,12 @@
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
- mpc8xxx_wdt_keepalive();
+ mpc8xxx_wdt_sw_keepalive();
return 0;
case WDIOC_GETTIMEOUT:
- return put_user(timeout_sec, p);
+ return put_user(heartbeat, p);
+ case WDIOC_SETTIMEOUT:
+ return get_user(heartbeat, p);
default:
return -ENOTTY;
}
@@ -215,6 +238,8 @@
ret = -ENOSYS;
goto err_unmap;
}
+ if (enabled)
+ timeout = in_be32(&wd_base->swcrr) >> 16;
/* Calculate the timeout in seconds */
if (prescale)
@@ -273,6 +298,7 @@
.compatible = "fsl,mpc823-wdt",
.data = &(struct mpc8xxx_wdt_type) {
.prescaler = 0x800,
+ .hw_enabled = true,
},
},
{},
^ permalink raw reply
* RE: [PATCH 2/2] powerpc: Make context bits depend on virtual addr size.
From: Aneesh Kumar K.V @ 2013-02-13 14:26 UTC (permalink / raw)
To: David Laight, Benjamin Herrenschmidt, phileas-fogg, geoff
Cc: paulus, linuxppc-dev
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6026B7148@saturn3.aculab.com>
David Laight <David.Laight@aculab.com> writes:
>> +#define CONTEXT_BITS 19
>> +#define USER_ESID_BITS 18
>> +#define USER_ESID_BITS_1T 6
>> +
>> +/*
>> + * 256MB segment
>> + * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments
>> + * available for user + kernel mapping. The top 4 contexts are used for
>> + * kernel mapping. Each segment contains 2^28 bytes. Each
>> + * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts
>> + * (19 == 37 + 28 - 46).
>> + */
>
> I can't help feeling this would be easier to understand if a full
> 64? 80? bit address was shown with the various bit ranges identified.
>
> Given the comment, I'd have expected CONTEXT_BITS to be calculated
> from three other named constants - rather than being set to 19.
>
May be the comments were misleading. We build proto vsid using a
combination of context and ea bits.
Current code does the below:
for kernel:
proto_vsid = ea >> SID_SHIFT;
proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS));
for user:
proto_vsid = ea >> SID_SHIFT
proto_vsid |= context << USER_ESID_BITS
context range is 0 - (2^19 -1)
With this patch we _don't_ give kernel half the proto vsid range.
Instead, we reduce the proto vsid range and then the kernel is given
top 4 context. ie, kernel proto vsid is now
for kenel:
proto_vsid = ea >> SID_SHIFT;
context = (MAX_CONTEXT - 4) + ((effective address >> 60) - 0xc);
proto_vsid |= context << USER_ESID_BITS
-aneesh
^ permalink raw reply
* [PATCH v3 1/1] powerpc/85xx: Board support for ppa8548
From: Stef van Os @ 2013-02-13 14:09 UTC (permalink / raw)
To: Kumar Gala, linuxppc-dev
Cc: scottwood, Paul Mackerras, timur.tabi, Stef van Os
Initial board support for the Prodrive PPA8548 AMC module. Board
is an MPC8548 AMC platform used in RapidIO systems. This module is
also used to test/work on mainline linux RapidIO software.
PPA8548 overview:
- 1.3 GHz Freescale PowerQUICC III MPC8548 processor
- 1 GB DDR2 @ 266 MHz
- 8 MB NOR flash
- Serial RapidIO 1.2
- 1 x 10/100/1000 BASE-T front ethernet
- 1 x 1000 BASE-BX ethernet on AMC connector
Signed-off-by: Stef van Os <stef.van.os@prodrive.nl>
---
arch/powerpc/boot/dts/ppa8548.dts | 166 +++++++++++++++++++++++++++
arch/powerpc/configs/85xx/ppa8548_defconfig | 65 +++++++++++
arch/powerpc/platforms/85xx/Kconfig | 7 +
arch/powerpc/platforms/85xx/Makefile | 1 +
arch/powerpc/platforms/85xx/ppa8548.c | 98 ++++++++++++++++
5 files changed, 337 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/boot/dts/ppa8548.dts
create mode 100644 arch/powerpc/configs/85xx/ppa8548_defconfig
create mode 100644 arch/powerpc/platforms/85xx/ppa8548.c
diff --git a/arch/powerpc/boot/dts/ppa8548.dts b/arch/powerpc/boot/dts/ppa8548.dts
new file mode 100644
index 0000000..f97ecee
--- /dev/null
+++ b/arch/powerpc/boot/dts/ppa8548.dts
@@ -0,0 +1,166 @@
+/*
+ * PPA8548 Device Tree Source (36-bit address map)
+ * Copyright 2013 Prodrive B.V.
+ *
+ * Based on:
+ * MPC8548 CDS Device Tree Source (36-bit address map)
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/include/ "fsl/mpc8548si-pre.dtsi"
+
+/ {
+ model = "ppa8548";
+ compatible = "ppa8548";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&mpic>;
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 0x0 0x40000000>;
+ };
+
+ lbc: localbus@fe0005000 {
+ reg = <0xf 0xe0005000 0 0x1000>;
+ ranges = <0x0 0x0 0xf 0xff800000 0x00800000>;
+ };
+
+ soc: soc8548@fe0000000 {
+ ranges = <0 0xf 0xe0000000 0x100000>;
+ };
+
+ pci0: pci@fe0008000 {
+ /* ppa8548 board doesn't support PCI */
+ status = "disabled";
+ };
+
+ pci1: pci@fe0009000 {
+ /* ppa8548 board doesn't support PCI */
+ status = "disabled";
+ };
+
+ pci2: pcie@fe000a000 {
+ /* ppa8548 board doesn't support PCI */
+ status = "disabled";
+ };
+
+ rio: rapidio@fe00c0000 {
+ reg = <0xf 0xe00c0000 0x0 0x11000>;
+ port1 {
+ ranges = <0x0 0x0 0x0 0x80000000 0x0 0x40000000>;
+ };
+ };
+};
+
+&lbc {
+ nor@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x00800000>;
+ bank-width = <2>;
+ device-width = <2>;
+
+ partition@0 {
+ reg = <0x0 0x7A0000>;
+ label = "user";
+ };
+
+ partition@7A0000 {
+ reg = <0x7A0000 0x20000>;
+ label = "env";
+ read-only;
+ };
+
+ partition@7C0000 {
+ reg = <0x7C0000 0x40000>;
+ label = "u-boot";
+ read-only;
+ };
+ };
+};
+
+&soc {
+ i2c@3000 {
+ rtc@6f {
+ compatible = "intersil,isl1208";
+ reg = <0x6f>;
+ };
+ };
+
+ i2c@3100 {
+ };
+
+ /*
+ * Only ethernet controller @25000 and @26000 are used.
+ * Use alias enet2 and enet3 for the remainig controllers,
+ * to stay compatible with mpc8548si-pre.dtsi.
+ */
+ enet2: ethernet@24000 {
+ status = "disabled";
+ };
+
+ mdio@24520 {
+ phy0: ethernet-phy@0 {
+ interrupts = <7 1 0 0>;
+ reg = <0x0>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy@1 {
+ interrupts = <8 1 0 0>;
+ reg = <0x1>;
+ device_type = "ethernet-phy";
+ };
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet0: ethernet@25000 {
+ tbi-handle = <&tbi1>;
+ phy-handle = <&phy0>;
+ };
+
+ mdio@25520 {
+ tbi1: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet1: ethernet@26000 {
+ tbi-handle = <&tbi2>;
+ phy-handle = <&phy1>;
+ };
+
+ mdio@26520 {
+ tbi2: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet3: ethernet@27000 {
+ status = "disabled";
+ };
+
+ mdio@27520 {
+ tbi3: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ crypto@30000 {
+ status = "disabled";
+ };
+};
+
+/include/ "fsl/mpc8548si-post.dtsi"
diff --git a/arch/powerpc/configs/85xx/ppa8548_defconfig b/arch/powerpc/configs/85xx/ppa8548_defconfig
new file mode 100644
index 0000000..a11337d
--- /dev/null
+++ b/arch/powerpc/configs/85xx/ppa8548_defconfig
@@ -0,0 +1,65 @@
+CONFIG_PPC_85xx=y
+CONFIG_PPA8548=y
+CONFIG_DTC=y
+CONFIG_DEFAULT_UIMAGE=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_PCI is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_LOWMEM_SIZE_BOOL=y
+CONFIG_LOWMEM_SIZE=0x40000000
+CONFIG_LOWMEM_CAM_NUM_BOOL=y
+CONFIG_LOWMEM_CAM_NUM=4
+CONFIG_PAGE_OFFSET_BOOL=y
+CONFIG_PAGE_OFFSET=0xb0000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0xb0000000
+# CONFIG_PHYSICAL_START_BOOL is not set
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYSICAL_ALIGN=0x04000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0xb0000000
+
+CONFIG_FSL_LBC=y
+CONFIG_FSL_DMA=y
+CONFIG_FSL_RIO=y
+
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_DMA_ENGINE=y
+CONFIG_RAPIDIO_TSI57X=y
+CONFIG_RAPIDIO_TSI568=y
+CONFIG_RAPIDIO_CPS_XX=y
+CONFIG_RAPIDIO_CPS_GEN2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_PROC_DEVICETREE=y
+
+CONFIG_MTD=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_PHYSMAP_OF=y
+
+CONFIG_I2C=y
+CONFIG_I2C_MPC=y
+CONFIG_I2C_CHARDEV
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_DRV_ISL1208=y
+
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_GIANFAR=y
+CONFIG_MARVELL_PHY=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 02d02a0..803bfed 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -191,6 +191,13 @@ config SBC8548
help
This option enables support for the Wind River SBC8548 board
+config PPA8548
+ bool "Prodrive PPA8548"
+ help
+ This option enables support for the Prodrive PPA8548 board.
+ select DEFAULT_UIMAGE
+ select HAS_RAPIDIO
+
config GE_IMP3A
bool "GE Intelligent Platforms IMP3A"
select DEFAULT_UIMAGE
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 76f679c..d5f4195 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_P5040_DS) += p5040_ds.o corenet_ds.o
obj-$(CONFIG_STX_GP3) += stx_gp3.o
obj-$(CONFIG_TQM85xx) += tqm85xx.o
obj-$(CONFIG_SBC8548) += sbc8548.o
+obj-$(CONFIG_PPA8548) += ppa8548.o
obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o
obj-$(CONFIG_KSI8560) += ksi8560.o
obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o
diff --git a/arch/powerpc/platforms/85xx/ppa8548.c b/arch/powerpc/platforms/85xx/ppa8548.c
new file mode 100644
index 0000000..6a7704b
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/ppa8548.c
@@ -0,0 +1,98 @@
+/*
+ * ppa8548 setup and early boot code.
+ *
+ * Copyright 2009 Prodrive B.V..
+ *
+ * By Stef van Os (see MAINTAINERS for contact information)
+ *
+ * Based on the SBC8548 support - Copyright 2007 Wind River Systems Inc.
+ * Based on the MPC8548CDS support - Copyright 2005 Freescale Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/seq_file.h>
+#include <linux/of_platform.h>
+
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+
+static void __init ppa8548_pic_init(void)
+{
+ struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN,
+ 0, 256, " OpenPIC ");
+ BUG_ON(mpic == NULL);
+ mpic_init(mpic);
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init ppa8548_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("ppa8548_setup_arch()", 0);
+}
+
+static void ppa8548_show_cpuinfo(struct seq_file *m)
+{
+ uint32_t svid, phid1;
+
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Prodrive B.V.\n");
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+ /* Display cpu Pll setting */
+ phid1 = mfspr(SPRN_HID1);
+ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+}
+
+static struct of_device_id __initdata of_bus_ids[] = {
+ { .name = "soc", },
+ { .type = "soc", },
+ { .compatible = "simple-bus", },
+ { .compatible = "gianfar", },
+ { .compatible = "fsl,srio", },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+ return 0;
+}
+machine_device_initcall(ppa8548, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init ppa8548_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "ppa8548");
+}
+
+define_machine(ppa8548) {
+ .name = "ppa8548",
+ .probe = ppa8548_probe,
+ .setup_arch = ppa8548_setup_arch,
+ .init_IRQ = ppa8548_pic_init,
+ .show_cpuinfo = ppa8548_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = fsl_rstcr_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
--
1.7.2.5
^ permalink raw reply related
* Re: [PATCH v2 1/1] powerpc/85xx: Board support for ppa8548
From: Stef van Os @ 2013-02-13 14:03 UTC (permalink / raw)
To: Kumar Gala
Cc: Scott Wood, Paul Mackerras, linuxppc-dev@lists.ozlabs.org,
Timur Tabi
In-Reply-To: <8D4EF5B0-BEC6-4114-88CF-166EB3A70A53@kernel.crashing.org>
On 02/12/2013 09:09 PM, Kumar Gala wrote:
>
> On Feb 4, 2013, at 9:30 AM, Timur Tabi wrote:
>
>> On 02/03/2013 01:39 PM, Stef van Os wrote:
>>
>>> + pci0: pci@fe0008000 {
>>> + status = "disabled";
>>> + };
>>> +
>>> + pci1: pci@fe0009000 {
>>> + status = "disabled";
>>> + };
>>> +
>>> + pci2: pcie@fe000a000 {
>>> + status = "disabled";
>>> + };
>>
>> I was hoping you'd follow my example and include a comment indicating why the PCI devices are all disabled.
>>
>>> +static void ppa8548_show_cpuinfo(struct seq_file *m)
>>> +{
>>> + uint svid, phid1;
>>
>> Please don't used unsized integers for hardware registers.
>>
>> uint32_t svid, phid1;
>
>
> Stef,
>
> If you'd like this included for 3.9, please make the minor updates.
>
> thanks
>
> - k
Patches are on their way. Thanks!
Stef.
^ permalink raw reply
* Re: [PATCH 15/17] powerpc: Add config option for transactional memory
From: Kumar Gala @ 2013-02-13 14:02 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-16-git-send-email-mikey@neuling.org>
On Feb 12, 2013, at 10:31 PM, Michael Neuling wrote:
> Kconfig option for transactional memory on powerpc.
>
> Signed-off-by: Matt Evans <matt@ozlabs.org>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> ---
> arch/powerpc/Kconfig | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 4b27edb..fbeb6d2 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -313,6 +313,14 @@ config MATH_EMULATION
> unit, which will allow programs that use floating-point
> instructions to run.
>
> +config PPC_TRANSACTIONAL_MEM
> + bool "Transactional Memory support for POWERPC"
> + depends on PPC64
Should this really depend on PPC_BOOK3S_64 ?
> + depends on SMP
> + default n
> + ---help---
> + Support user-mode Transactional Memory on POWERPC.
> +
> config 8XX_MINIMAL_FPEMU
> bool "Minimal math emulation for 8xx"
> depends on 8xx && !MATH_EMULATION
> --
> 1.7.10.4
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 08/17] powerpc: Add FP/VSX and VMX register load functions for transactional memory
From: Kumar Gala @ 2013-02-13 13:54 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-9-git-send-email-mikey@neuling.org>
On Feb 12, 2013, at 10:31 PM, Michael Neuling wrote:
> This adds functions to restore the state of the FP/VSX registers from
> what's stored in the thread_struct. Two version for FP/VSX are =
required
> since one restores them from transactional/checkpoint side of the
> thread_struct and the other from the speculated side.
>=20
> Similar functions are added for VMX registers.
>=20
> Signed-off-by: Matt Evans <matt@ozlabs.org>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> ---
> arch/powerpc/kernel/fpu.S | 54 =
++++++++++++++++++++++++++++++++++++++++++
> arch/powerpc/kernel/vector.S | 51 =
+++++++++++++++++++++++++++++++++++++++
> 2 files changed, 105 insertions(+)
>=20
> diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
> index adb1551..0441ba6 100644
> --- a/arch/powerpc/kernel/fpu.S
> +++ b/arch/powerpc/kernel/fpu.S
> @@ -62,6 +62,60 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); =
\
> __REST_32FPVSRS_TRANSACT(n,__REG_##c,__REG_##base)
> #define SAVE_32FPVSRS(n,c,base) =
__SAVE_32FPVSRS(n,__REG_##c,__REG_##base)
>=20
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> +/*
> + * Wrapper to call load_up_fpu from C.
> + * void do_load_up_fpu(struct pt_regs *regs);
> + */
> +_GLOBAL(do_load_up_fpu)
> + mflr r0
> + std r0, 16(r1)
> + stdu r1, -112(r1)
> +
> + subi r6, r3, STACK_FRAME_OVERHEAD
> + /* load_up_fpu expects r12=3DMSR, r13=3DPACA, and returns
> + * with r12 =3D new MSR.
> + */
> + ld r12,_MSR(r6)
> + GET_PACA(r13)
> +
> + bl load_up_fpu
> + std r12,_MSR(r6)
> +
> + ld r0, 112+16(r1)
> + addi r1, r1, 112
> + mtlr r0
> + blr
> +
> +
> +/* void do_load_up_fpu(struct thread_struct *thread)
Comment is wrong, should be void do_load_up_transact_fpu(...)
> + *
> + * This is similar to load_up_fpu but for the transactional version =
of the FP
> + * register set. It doesn't mess with the task MSR or valid flags.
> + * Furthermore, we don't do lazy FP with TM currently.
> + */
> +_GLOBAL(do_load_up_transact_fpu)
> + mfmsr r6
> + ori r5,r6,MSR_FP
> +#ifdef CONFIG_VSX
> +BEGIN_FTR_SECTION
> + oris r5,r5,MSR_VSX@h
> +END_FTR_SECTION_IFSET(CPU_FTR_VSX)
> +#endif
> + SYNC
> + MTMSRD(r5)
> +
> + lfd fr0,THREAD_TRANSACT_FPSCR(r3)
> + MTFSF_L(fr0)
> + REST_32FPVSRS_TRANSACT(0, R4, R3)
> +
> + /* FP/VSX off again */
> + MTMSRD(r6)
> + SYNC
> +
> + blr
> +#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
> +
> /*
> * This task wants to use the FPU now.
> * On UP, disable FP for the task which had the FPU previously,
> diff --git a/arch/powerpc/kernel/vector.S =
b/arch/powerpc/kernel/vector.S
> index e830289..7112a24 100644
> --- a/arch/powerpc/kernel/vector.S
> +++ b/arch/powerpc/kernel/vector.S
> @@ -7,6 +7,57 @@
> #include <asm/page.h>
> #include <asm/ptrace.h>
>=20
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> +/*
> + * Wrapper to call load_up_altivec from C.
> + * void do_load_up_altivec(struct pt_regs *regs);
> + */
> +_GLOBAL(do_load_up_altivec)
> + mflr r0
> + std r0, 16(r1)
> + stdu r1, -112(r1)
> +
> + subi r6, r3, STACK_FRAME_OVERHEAD
> + /* load_up_altivec expects r12=3DMSR, r13=3DPACA, and returns
> + * with r12 =3D new MSR.
> + */
> + ld r12,_MSR(r6)
> + GET_PACA(r13)
> + bl load_up_altivec
> + std r12,_MSR(r6)
> +
> + ld r0, 112+16(r1)
> + addi r1, r1, 112
> + mtlr r0
> + blr
> +
> +/* void do_load_up_altivec(struct thread_struct *thread)
comment wrong.
> + *
> + * This is similar to load_up_altivec but for the transactional =
version of the
> + * vector regs. It doesn't mess with the task MSR or valid flags.
> + * Furthermore, VEC laziness is not supported with TM currently.
> + */
> +_GLOBAL(do_load_up_transact_altivec)
> + mfmsr r6
> + oris r5,r6,MSR_VEC@h
> + MTMSRD(r5)
> + isync
> +
> + li r4,1
> + stw r4,THREAD_USED_VR(r3)
> +
> + li r10,THREAD_TRANSACT_VSCR
> + lvx vr0,r10,r3
> + mtvscr vr0
> + REST_32VRS_TRANSACT(0,r4,r3)
> +
> + /* Disable VEC again. */
> + MTMSRD(r6)
> + isync
> +
> + blr
> +#endif
> +
> /*
> * load_up_altivec(unused, unused, tsk)
> * Disable VMX for the task which had it previously,
> --=20
> 1.7.10.4
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 06/17] powerpc: Add transactional memory paca scratch register to show_regs
From: Kumar Gala @ 2013-02-13 13:52 UTC (permalink / raw)
To: Michael Neuling; +Cc: linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-7-git-send-email-mikey@neuling.org>
On Feb 12, 2013, at 10:31 PM, Michael Neuling wrote:
> Add transactional memory paca scratch register to show_regs. This is =
useful
> for debugging.
>=20
> Signed-off-by: Matt Evans <matt@ozlabs.org>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> ---
> arch/powerpc/include/asm/paca.h | 1 +
> arch/powerpc/kernel/asm-offsets.c | 1 +
> arch/powerpc/kernel/entry_64.S | 4 ++++
> arch/powerpc/kernel/process.c | 3 +++
> 4 files changed, 9 insertions(+)
>=20
> diff --git a/arch/powerpc/include/asm/paca.h =
b/arch/powerpc/include/asm/paca.h
> index c47d687..07e9851 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -137,6 +137,7 @@ struct paca_struct {
> u8 irq_work_pending; /* IRQ_WORK interrupt while =
soft-disable */
> u8 nap_state_lost; /* NV GPR values lost in =
power7_idle */
> u64 sprg3; /* Saved user-visible sprg */
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> + u64 tm_scratch; /* TM scratch area for reclaim =
*/
#endif
>=20
> #ifdef CONFIG_PPC_POWERNV
> /* Pointer to OPAL machine check event structure set by the
> diff --git a/arch/powerpc/kernel/asm-offsets.c =
b/arch/powerpc/kernel/asm-offsets.c
> index b67e4c3..f9654b6 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -126,6 +126,7 @@ int main(void)
> DEFINE(THREAD_TAR, offsetof(struct thread_struct, tar));
> #endif
> #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> + DEFINE(PACATMSCRATCH, offsetof(struct paca_struct, tm_scratch));
> DEFINE(THREAD_TM_TFHAR, offsetof(struct thread_struct, =
tm_tfhar));
> DEFINE(THREAD_TM_TEXASR, offsetof(struct thread_struct, =
tm_texasr));
> DEFINE(THREAD_TM_TFIAR, offsetof(struct thread_struct, =
tm_tfiar));
> diff --git a/arch/powerpc/kernel/entry_64.S =
b/arch/powerpc/kernel/entry_64.S
> index 9ae8451..612ea13 100644
> --- a/arch/powerpc/kernel/entry_64.S
> +++ b/arch/powerpc/kernel/entry_64.S
> @@ -785,6 +785,10 @@ fast_exception_return:
> andc r4,r4,r0 /* r0 contains MSR_RI here */
> mtmsrd r4,1
>=20
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> + /* TM debug */
> + std r3, PACATMSCRATCH(r13) /* Stash returned-to MSR */
> +#endif
> /*
> * r13 is our per cpu area, only restore it if we are returning =
to
> * userspace the value stored in the stack frame may belong to
> diff --git a/arch/powerpc/kernel/process.c =
b/arch/powerpc/kernel/process.c
> index b0a0321..1cc4053 100644
> --- a/arch/powerpc/kernel/process.c
> +++ b/arch/powerpc/kernel/process.c
> @@ -754,6 +754,9 @@ void show_regs(struct pt_regs * regs)
> printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip);
> printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link);
> #endif
> +#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
> + printk("PACATMSCRATCH [%llx]\n", get_paca()->tm_scratch);
> +#endif
> show_stack(current, (unsigned long *) regs->gpr[1]);
> if (!user_mode(regs))
> show_instructions(regs);
> --=20
> 1.7.10.4
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* RE: [PATCH 2/2] powerpc: Make context bits depend on virtual addr size.
From: David Laight @ 2013-02-13 13:27 UTC (permalink / raw)
To: Aneesh Kumar K.V, Benjamin Herrenschmidt, phileas-fogg, geoff
Cc: paulus, linuxppc-dev
In-Reply-To: <87pq04jvb4.fsf@linux.vnet.ibm.com>
> +#define CONTEXT_BITS 19
> +#define USER_ESID_BITS 18
> +#define USER_ESID_BITS_1T 6
> +
> +/*
> + * 256MB segment
> + * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 =
segments
> + * available for user + kernel mapping. The top 4 contexts are used =
for
> + * kernel mapping. Each segment contains 2^28 bytes. Each
> + * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts
> + * (19 =3D=3D 37 + 28 - 46).
> + */
I can't help feeling this would be easier to understand if a full
64? 80? bit address was shown with the various bit ranges identified.
Given the comment, I'd have expected CONTEXT_BITS to be calculated
from three other named constants - rather than being set to 19.
David
^ permalink raw reply
* Re: [PATCH 2/2] powerpc: Make context bits depend on virtual addr size.
From: Aneesh Kumar K.V @ 2013-02-13 11:40 UTC (permalink / raw)
To: Benjamin Herrenschmidt, phileas-fogg, geoff; +Cc: linuxppc-dev, paulus
In-Reply-To: <1360727211.2035.30.camel@pasglop>
Benjamin Herrenschmidt <benh@kernel.crashing.org> writes:
> On Wed, 2013-02-13 at 08:54 +0530, Aneesh Kumar K.V wrote:
>> > A compile option ? Really ? Ugh...
>>
>> I actually wanted that to be done in Kconfig.cputype, but haven't found
>> a nice way to do it. Considering we are switching between only two
>> values, I was thinking an #ifdef would work.
>
> No, we want to support all those processor types from a single kernel image.
Ok. How about the below patch. This is based on the suggestion from
Paulus. I still have to take care of few comments in the code.
We now split the proto-vsid range differently.
User: 0 to [2^(CONTEXT_BITS) - 4 + 2^(USER_ESID_BITS)]
kernel: [2^(CONTEXT_BITS) - 4 + 2^(USER_ESID_BITS)] to 2^(VSID_BITS) - 1
Phileas and Geoff,
Can we check whether this fix the PS3 boot hang ?
-aneesh
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 2fdb47a..1e65a01 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -381,21 +381,33 @@ extern void slb_set_size(u16 size);
* hash collisions.
*/
+#define CONTEXT_BITS 19
+#define USER_ESID_BITS 18
+#define USER_ESID_BITS_1T 6
+
+/*
+ * 256MB segment
+ * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments
+ * available for user + kernel mapping. The top 4 contexts are used for
+ * kernel mapping. Each segment contains 2^28 bytes. Each
+ * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts
+ * (19 == 37 + 28 - 46).
+ */
+#define MAX_CONTEXT ((ASM_CONST(1) << CONTEXT_BITS) - 1)
+
+
/*
* This should be computed such that protovosid * vsid_mulitplier
* doesn't overflow 64 bits. It should also be co-prime to vsid_modulus
*/
#define VSID_MULTIPLIER_256M ASM_CONST(12538073) /* 24-bit prime */
-#define VSID_BITS_256M 38
+#define VSID_BITS_256M (CONTEXT_BITS + USER_ESID_BITS)
#define VSID_MODULUS_256M ((1UL<<VSID_BITS_256M)-1)
#define VSID_MULTIPLIER_1T ASM_CONST(12538073) /* 24-bit prime */
-#define VSID_BITS_1T 26
+#define VSID_BITS_1T (CONTEXT_BITS + USER_ESID_BITS_1T)
#define VSID_MODULUS_1T ((1UL<<VSID_BITS_1T)-1)
-#define CONTEXT_BITS 19
-#define USER_ESID_BITS 18
-#define USER_ESID_BITS_1T 6
#define USER_VSID_RANGE (1UL << (USER_ESID_BITS + SID_SHIFT))
@@ -513,34 +525,6 @@ typedef struct {
})
#endif /* 1 */
-/*
- * This is only valid for addresses >= PAGE_OFFSET
- * The proto-VSID space is divided into two class
- * User: 0 to 2^(CONTEXT_BITS + USER_ESID_BITS) -1
- * kernel: 2^(CONTEXT_BITS + USER_ESID_BITS) to 2^(VSID_BITS) - 1
- *
- * With KERNEL_START at 0xc000000000000000, the proto vsid for
- * the kernel ends up with 0xc00000000 (36 bits). With 64TB
- * support we need to have kernel proto-VSID in the
- * [2^37 to 2^38 - 1] range due to the increased USER_ESID_BITS.
- */
-static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize)
-{
- unsigned long proto_vsid;
- /*
- * We need to make sure proto_vsid for the kernel is
- * >= 2^(CONTEXT_BITS + USER_ESID_BITS[_1T])
- */
- if (ssize == MMU_SEGSIZE_256M) {
- proto_vsid = ea >> SID_SHIFT;
- proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS));
- return vsid_scramble(proto_vsid, 256M);
- }
- proto_vsid = ea >> SID_SHIFT_1T;
- proto_vsid |= (1UL << (CONTEXT_BITS + USER_ESID_BITS_1T));
- return vsid_scramble(proto_vsid, 1T);
-}
-
/* Returns the segment size indicator for a user address */
static inline int user_segment_size(unsigned long addr)
{
@@ -561,6 +545,26 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea,
| (ea >> SID_SHIFT_1T), 1T);
}
+/*
+ * This is only valid for addresses >= PAGE_OFFSET
+ * The proto-VSID space is divided into two class
+ * User: 0 to 2^(CONTEXT_BITS) - 4 + 2^(USER_ESID_BITS)
+ * kernel: 2^(CONTEXT_BITS) - 4 + 2^(USER_ESID_BITS) to 2^(VSID_BITS) - 1
+ *
+ * With KERNEL_START at 0xc000000000000000, the proto vsid for
+ * the kernel ends up with 0xc00000000 (36 bits). We use one context
+ * for 0xc, 0xd, 0xe and 0xf.
+ *
+ */
+static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize)
+{
+ unsigned long context;
+ /*
+ * kernel take the top 4 context from the available range
+ */
+ context = (MAX_CONTEXT - 4) + ((ea >> 60) - 0xc);
+ return get_vsid(context, ea, ssize);
+}
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_MMU_HASH64_H_ */
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 4665e82..78c6d0b 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1269,16 +1269,23 @@ _GLOBAL(do_stab_bolted)
stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */
+ mfspr r11,SPRN_DAR
+ srdi r9,r11,60 /* ea >> 60 */
+ srdi r11,r11,SID_SHIFT
+
+ /* Calculate VSID:
+ * This is the kernel vsid, we take the top for context from
+ * the range. context = (MAX_CONTEXT - 4) + ((ea >> 60) - 0xc)
+ */
+ subi r9,r9,(0xc + 4 + 1)
+ lis r10,8
+ add r9,r9,r10
+
/* Hash to the primary group */
ld r10,PACASTABVIRT(r13)
- mfspr r11,SPRN_DAR
- srdi r11,r11,28
rldimi r10,r11,7,52 /* r10 = first ste of the group */
+ rldimi r11,r9,USER_ESID_BITS,0 /* proto vsid */
- /* Calculate VSID */
- /* This is a kernel address, so protovsid = ESID | 1 << 37 */
- li r9,0x1
- rldimi r11,r9,(CONTEXT_BITS + USER_ESID_BITS),0
ASM_VSID_SCRAMBLE(r11, r9, 256M)
rldic r9,r11,12,16 /* r9 = vsid << 12 */
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 40bc5b0..9c84b16 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -29,15 +29,6 @@
static DEFINE_SPINLOCK(mmu_context_lock);
static DEFINE_IDA(mmu_context_ida);
-/*
- * 256MB segment
- * The proto-VSID space has 2^(CONTEX_BITS + USER_ESID_BITS) - 1 segments
- * available for user mappings. Each segment contains 2^28 bytes. Each
- * context maps 2^46 bytes (64TB) so we can support 2^19-1 contexts
- * (19 == 37 + 28 - 46).
- */
-#define MAX_CONTEXT ((1UL << CONTEXT_BITS) - 1)
-
int __init_new_context(void)
{
int index;
@@ -56,7 +47,7 @@ again:
else if (err)
return err;
- if (index > MAX_CONTEXT) {
+ if (index > (MAX_CONTEXT - 4)) {
spin_lock(&mmu_context_lock);
ida_remove(&mmu_context_ida, index);
spin_unlock(&mmu_context_lock);
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 1a16ca2..487f998 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -56,12 +56,19 @@ _GLOBAL(slb_allocate_realmode)
*/
_GLOBAL(slb_miss_kernel_load_linear)
li r11,0
- li r9,0x1
+ /*
+ * context = (MAX_CONTEXT - 4) + ((ea >> 60) - 0xc)
+ */
+ srdi r9,r3,60
+ subi r9,r9,(0xc + 4 + 1)
+ lis r10, 8
+ add r9,r9,r10
+ srdi r10,r3,28 /* FIXME!! doing it twice */
/*
* for 1T we shift 12 bits more. slb_finish_load_1T will do
* the necessary adjustment
*/
- rldimi r10,r9,(CONTEXT_BITS + USER_ESID_BITS),0
+ rldimi r10,r9,USER_ESID_BITS,0
BEGIN_FTR_SECTION
b slb_finish_load
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
@@ -91,12 +98,19 @@ _GLOBAL(slb_miss_kernel_load_vmemmap)
_GLOBAL(slb_miss_kernel_load_io)
li r11,0
6:
- li r9,0x1
+ /*
+ * context = (MAX_CONTEXT - 4) + ((ea >> 60) - 0xc)
+ */
+ srdi r9,r3,60
+ subi r9,r9,(0xc + 4 + 1)
+ lis r10,8
+ add r9,r9,r10
+ srdi r10,r3,28 /* FIXME!! doing it twice */
/*
* for 1T we shift 12 bits more. slb_finish_load_1T will do
* the necessary adjustment
*/
- rldimi r10,r9,(CONTEXT_BITS + USER_ESID_BITS),0
+ rldimi r10,r9,USER_ESID_BITS,0
BEGIN_FTR_SECTION
b slb_finish_load
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
^ permalink raw reply related
* Re: PS3 platform is broken on Linux 3.7.0
From: Geoff Levand @ 2013-02-13 7:32 UTC (permalink / raw)
To: Phileas Fogg, Michael Ellerman; +Cc: cbe-oss-dev, linuxppc-dev
In-Reply-To: <1355488506.55692113@f147.mail.ru>
Hi,
On Fri, 2012-12-14 at 16:35 +0400, Phileas Fogg wrote:
> I wanted to bring to your attention the fact that the PS3 platform is broken on Linux 3.7.0.
> So i cloned the Linux powerpc GIT repository and tried to find out which commits broke the PS3 platform.
> ---------------------------------------------------------------------------------------------
>
> commit 407821a34fce89b4f0b031dbab5cec7d059f46bc
> Author: Michael Ellerman <michael@ellerman.id.au>
> Date: Fri Sep 7 15:31:44 2012 +0000
>
> powerpc: Initialise paca.data_offset with poison
I did a little more work on this, and it seems the change below
will fix the problem introduced by Michael's change. I can only
guess we need to use udbg_printf() here. I'll look at it some more
as I have time.
-Geoff
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 5c56834..6b4f613 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -184,8 +185,8 @@ void __init allocate_pacas(void)
paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit));
memset(paca, 0, paca_size);
- printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
- paca_size, nr_cpu_ids, paca);
+// printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
+// paca_size, nr_cpu_ids, paca);
allocate_lppacas(nr_cpu_ids, limit);
>
^ permalink raw reply related
* [PATCH 17/17] powerpc: Documentation for transactional memory on powerpc
From: Michael Neuling @ 2013-02-13 4:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-1-git-send-email-mikey@neuling.org>
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
Documentation/powerpc/transactional_memory.txt | 175 ++++++++++++++++++++++++
1 file changed, 175 insertions(+)
create mode 100644 Documentation/powerpc/transactional_memory.txt
diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt
new file mode 100644
index 0000000..c907be4
--- /dev/null
+++ b/Documentation/powerpc/transactional_memory.txt
@@ -0,0 +1,175 @@
+Transactional Memory support
+============================
+
+POWER kernel support for this feature is currently limited to supporting
+its use by user programs. It is not currently used by the kernel itself.
+
+This file aims to sum up how it is supported by Linux and what behaviour you
+can expect from your user programs.
+
+
+Basic overview
+==============
+
+Hardware Transactional Memory is supported on POWER8 processors, and is a
+feature that enables a different form of atomic memory access. Several new
+instructions are presented to delimit transactions; transactions are
+guaranteed to either complete atomically or roll back and undo any partial
+changes.
+
+A simple transaction looks like this:
+
+begin_move_money:
+ tbegin
+ beq abort_handler
+
+ ld r4, SAVINGS_ACCT(r3)
+ ld r5, CURRENT_ACCT(r3)
+ subi r5, r5, 1
+ addi r4, r4, 1
+ std r4, SAVINGS_ACCT(r3)
+ std r5, CURRENT_ACCT(r3)
+
+ tend
+
+ b continue
+
+abort_handler:
+ ... test for odd failures ...
+
+ /* Retry the transaction if it failed because it conflicted with
+ * someone else: */
+ b begin_move_money
+
+
+The 'tbegin' instruction denotes the start point, and 'tend' the end point.
+Between these points the processor is in 'Transactional' state; any memory
+references will complete in one go if there are no conflicts with other
+transactional or non-transactional accesses within the system. In this
+example, the transaction completes as though it were normal straight-line code
+IF no other processor has touched SAVINGS_ACCT(r3) or CURRENT_ACCT(r3); an
+atomic move of money from the current account to the savings account has been
+performed. Even though the normal ld/std instructions are used (note no
+lwarx/stwcx), either *both* SAVINGS_ACCT(r3) and CURRENT_ACCT(r3) will be
+updated, or neither will be updated.
+
+If, in the meantime, there is a conflict with the locations accessed by the
+transaction, the transaction will be aborted by the CPU. Register and memory
+state will roll back to that at the 'tbegin', and control will continue from
+'tbegin+4'. The branch to abort_handler will be taken this second time; the
+abort handler can check the cause of the failure, and retry.
+
+Checkpointed registers include all GPRs, FPRs, VRs/VSRs, LR, CCR/CR, CTR, FPCSR
+and a few other status/flag regs; see the ISA for details.
+
+Causes of transaction aborts
+============================
+
+- Conflicts with cache lines used by other processors
+- Signals
+- Context switches
+- See the ISA for full documentation of everything that will abort transactions.
+
+
+Syscalls
+========
+
+Performing syscalls from within transaction is not recommended, and can lead
+to unpredictable results.
+
+Syscalls do not by design abort transactions, but beware: The kernel code will
+not be running in transactional state. The effect of syscalls will always
+remain visible, but depending on the call they may abort your transaction as a
+side-effect, read soon-to-be-aborted transactional data that should not remain
+invisible, etc. If you constantly retry a transaction that constantly aborts
+itself by calling a syscall, you'll have a livelock & make no progress.
+
+Simple syscalls (e.g. sigprocmask()) "could" be OK. Even things like write()
+from, say, printf() should be OK as long as the kernel does not access any
+memory that was accessed transactionally.
+
+Consider any syscalls that happen to work as debug-only -- not recommended for
+production use. Best to queue them up till after the transaction is over.
+
+
+Signals
+=======
+
+Delivery of signals (both sync and async) during transactions provides a second
+thread state (ucontext/mcontext) to represent the second transactional register
+state. Signal delivery 'treclaim's to capture both register states, so signals
+abort transactions. The usual ucontext_t passed to the signal handler
+represents the checkpointed/original register state; the signal appears to have
+arisen at 'tbegin+4'.
+
+If the sighandler ucontext has uc_link set, a second ucontext has been
+delivered. For future compatibility the MSR.TS field should be checked to
+determine the transactional state -- if so, the second ucontext in uc->uc_link
+represents the active transactional registers at the point of the signal.
+
+For 64-bit processes, uc->uc_mcontext.regs->msr is a full 64-bit MSR and its TS
+field shows the transactional mode.
+
+For 32-bit processes, the mcontext's MSR register is only 32 bits; the top 32
+bits are stored in the MSR of the second ucontext, i.e. in
+uc->uc_link->uc_mcontext.regs->msr. The top word contains the transactional
+state TS.
+
+However, basic signal handlers don't need to be aware of transactions
+and simply returning from the handler will deal with things correctly:
+
+Transaction-aware signal handlers can read the transactional register state
+from the second ucontext. This will be necessary for crash handlers to
+determine, for example, the address of the instruction causing the SIGSEGV.
+
+Example signal handler:
+
+ void crash_handler(int sig, siginfo_t *si, void *uc)
+ {
+ ucontext_t *ucp = uc;
+ ucontext_t *transactional_ucp = ucp->uc_link;
+
+ if (ucp_link) {
+ u64 msr = ucp->uc_mcontext.regs->msr;
+ /* May have transactional ucontext! */
+#ifndef __powerpc64__
+ msr |= ((u64)transactional_ucp->uc_mcontext.regs->msr) << 32;
+#endif
+ if (MSR_TM_ACTIVE(msr)) {
+ /* Yes, we crashed during a transaction. Oops. */
+ fprintf(stderr, "Transaction to be restarted at 0x%llx, but "
+ "crashy instruction was at 0x%llx\n",
+ ucp->uc_mcontext.regs->nip,
+ transactional_ucp->uc_mcontext.regs->nip);
+ }
+ }
+
+ fix_the_problem(ucp->dar);
+ }
+
+
+Failure cause codes used by kernel
+==================================
+
+These are defined in <asm/reg.h>, and distinguish different reasons why the
+kernel aborted a transaction:
+
+ TM_CAUSE_RESCHED Thread was rescheduled.
+ TM_CAUSE_FAC_UNAV FP/VEC/VSX unavailable trap.
+ TM_CAUSE_SYSCALL Currently unused; future syscalls that must abort
+ transactions for consistency will use this.
+ TM_CAUSE_SIGNAL Signal delivered.
+ TM_CAUSE_MISC Currently unused.
+
+These can be checked by the user program's abort handler as TEXASR[0:7].
+
+
+GDB
+===
+
+GDB and ptrace are not currently TM-aware. If one stops during a transaction,
+it looks like the transaction has just started (the checkpointed state is
+presented). The transaction cannot then be continued and will take the failure
+handler route. Furthermore, the transactional 2nd register state will be
+inaccessible. GDB can currently be used on programs using TM, but not sensibly
+in parts within transactions.
--
1.7.10.4
^ permalink raw reply related
* [PATCH 16/17] powerpc: Add transactional memory to pseries and ppc64 defconfigs
From: Michael Neuling @ 2013-02-13 4:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-1-git-send-email-mikey@neuling.org>
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/configs/ppc64_defconfig | 2 ++
arch/powerpc/configs/pseries_defconfig | 2 ++
2 files changed, 4 insertions(+)
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 6cbdeb4..aef3f71 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -49,6 +49,8 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_PMAC64=y
CONFIG_HZ_100=y
CONFIG_BINFMT_MISC=m
+CONFIG_PPC_TRANSACTIONAL_MEM=y
+CONFIG_HOTPLUG_CPU=y
CONFIG_KEXEC=y
CONFIG_IRQ_ALL_CPUS=y
CONFIG_MEMORY_HOTREMOVE=y
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 04fa7f2..c4dfbaf 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -43,6 +43,8 @@ CONFIG_RTAS_FLASH=m
CONFIG_IBMEBUS=y
CONFIG_HZ_100=y
CONFIG_BINFMT_MISC=m
+CONFIG_PPC_TRANSACTIONAL_MEM=y
+CONFIG_HOTPLUG_CPU=y
CONFIG_KEXEC=y
CONFIG_IRQ_ALL_CPUS=y
CONFIG_MEMORY_HOTPLUG=y
--
1.7.10.4
^ permalink raw reply related
* [PATCH 15/17] powerpc: Add config option for transactional memory
From: Michael Neuling @ 2013-02-13 4:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-1-git-send-email-mikey@neuling.org>
Kconfig option for transactional memory on powerpc.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/Kconfig | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 4b27edb..fbeb6d2 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -313,6 +313,14 @@ config MATH_EMULATION
unit, which will allow programs that use floating-point
instructions to run.
+config PPC_TRANSACTIONAL_MEM
+ bool "Transactional Memory support for POWERPC"
+ depends on PPC64
+ depends on SMP
+ default n
+ ---help---
+ Support user-mode Transactional Memory on POWERPC.
+
config 8XX_MINIMAL_FPEMU
bool "Minimal math emulation for 8xx"
depends on 8xx && !MATH_EMULATION
--
1.7.10.4
^ permalink raw reply related
* [PATCH 14/17] powerpc: Add transactional memory to POWER8 cpu features
From: Michael Neuling @ 2013-02-13 4:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-1-git-send-email-mikey@neuling.org>
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/cputable.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 3636081..fb3245e 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -421,7 +421,8 @@ extern const char *powerpc_base_platform;
CPU_FTR_DSCR | CPU_FTR_SAO | \
CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
- CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | CPU_FTR_BCTAR)
+ CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | CPU_FTR_BCTAR | \
+ CPU_FTR_TM_COMP)
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
--
1.7.10.4
^ permalink raw reply related
* [PATCH 13/17] powerpc: Add new transactional memory state to the signal context
From: Michael Neuling @ 2013-02-13 4:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-1-git-send-email-mikey@neuling.org>
This adds the new transactional memory archtected state to the signal context
in both 32 and 64 bit.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/reg.h | 1 +
arch/powerpc/kernel/signal.h | 8 +
arch/powerpc/kernel/signal_32.c | 500 ++++++++++++++++++++++++++++++++++++++-
arch/powerpc/kernel/signal_64.c | 337 +++++++++++++++++++++++++-
4 files changed, 830 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index eee2a60..7035e60 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -120,6 +120,7 @@
#define TM_CAUSE_FAC_UNAV 0xfa
#define TM_CAUSE_SYSCALL 0xf9 /* Persistent */
#define TM_CAUSE_MISC 0xf6
+#define TM_CAUSE_SIGNAL 0xf4
#if defined(CONFIG_PPC_BOOK3S_64)
#define MSR_64BIT MSR_SF
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
index e00acb4..ec84c90 100644
--- a/arch/powerpc/kernel/signal.h
+++ b/arch/powerpc/kernel/signal.h
@@ -25,13 +25,21 @@ extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
extern unsigned long copy_fpr_to_user(void __user *to,
struct task_struct *task);
+extern unsigned long copy_transact_fpr_to_user(void __user *to,
+ struct task_struct *task);
extern unsigned long copy_fpr_from_user(struct task_struct *task,
void __user *from);
+extern unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+ void __user *from);
#ifdef CONFIG_VSX
extern unsigned long copy_vsx_to_user(void __user *to,
struct task_struct *task);
+extern unsigned long copy_transact_vsx_to_user(void __user *to,
+ struct task_struct *task);
extern unsigned long copy_vsx_from_user(struct task_struct *task,
void __user *from);
+extern unsigned long copy_transact_vsx_from_user(struct task_struct *task,
+ void __user *from);
#endif
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 804e323..e4a88d3 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -43,6 +43,7 @@
#include <asm/sigcontext.h>
#include <asm/vdso.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#ifdef CONFIG_PPC64
#include "ppc32.h"
#include <asm/unistd.h>
@@ -293,6 +294,10 @@ long sys_sigaction(int sig, struct old_sigaction __user *act,
struct sigframe {
struct sigcontext sctx; /* the sigcontext */
struct mcontext mctx; /* all the register values */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct sigcontext sctx_transact;
+ struct mcontext mctx_transact;
+#endif
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
@@ -321,6 +326,9 @@ struct rt_sigframe {
struct siginfo info;
#endif
struct ucontext uc;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct ucontext uc_transact;
+#endif
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
@@ -381,6 +389,61 @@ unsigned long copy_vsx_from_user(struct task_struct *task,
task->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return 0;
}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+unsigned long copy_transact_fpr_to_user(void __user *to,
+ struct task_struct *task)
+{
+ double buf[ELF_NFPREG];
+ int i;
+
+ /* save FPR copy to local buffer then write to the thread_struct */
+ for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+ buf[i] = task->thread.TS_TRANS_FPR(i);
+ memcpy(&buf[i], &task->thread.transact_fpscr, sizeof(double));
+ return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double));
+}
+
+unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+ void __user *from)
+{
+ double buf[ELF_NFPREG];
+ int i;
+
+ if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double)))
+ return 1;
+ for (i = 0; i < (ELF_NFPREG - 1) ; i++)
+ task->thread.TS_TRANS_FPR(i) = buf[i];
+ memcpy(&task->thread.transact_fpscr, &buf[i], sizeof(double));
+
+ return 0;
+}
+
+unsigned long copy_transact_vsx_to_user(void __user *to,
+ struct task_struct *task)
+{
+ double buf[ELF_NVSRHALFREG];
+ int i;
+
+ /* save FPR copy to local buffer then write to the thread_struct */
+ for (i = 0; i < ELF_NVSRHALFREG; i++)
+ buf[i] = task->thread.transact_fpr[i][TS_VSRLOWOFFSET];
+ return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double));
+}
+
+unsigned long copy_transact_vsx_from_user(struct task_struct *task,
+ void __user *from)
+{
+ double buf[ELF_NVSRHALFREG];
+ int i;
+
+ if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double)))
+ return 1;
+ for (i = 0; i < ELF_NVSRHALFREG ; i++)
+ task->thread.transact_fpr[i][TS_VSRLOWOFFSET] = buf[i];
+ return 0;
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#else
inline unsigned long copy_fpr_to_user(void __user *to,
struct task_struct *task)
@@ -395,6 +458,22 @@ inline unsigned long copy_fpr_from_user(struct task_struct *task,
return __copy_from_user(task->thread.fpr, from,
ELF_NFPREG * sizeof(double));
}
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+inline unsigned long copy_transact_fpr_to_user(void __user *to,
+ struct task_struct *task)
+{
+ return __copy_to_user(to, task->thread.transact_fpr,
+ ELF_NFPREG * sizeof(double));
+}
+
+inline unsigned long copy_transact_fpr_from_user(struct task_struct *task,
+ void __user *from)
+{
+ return __copy_from_user(task->thread.transact_fpr, from,
+ ELF_NFPREG * sizeof(double));
+}
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#endif
/*
@@ -483,6 +562,156 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
return 0;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Save the current user registers on the user stack.
+ * We only save the altivec/spe registers if the process has used
+ * altivec/spe instructions at some point.
+ * We also save the transactional registers to a second ucontext in the
+ * frame.
+ *
+ * See save_user_regs() and signal_64.c:setup_tm_sigcontexts().
+ */
+static int save_tm_user_regs(struct pt_regs *regs,
+ struct mcontext __user *frame,
+ struct mcontext __user *tm_frame, int sigret)
+{
+ unsigned long msr = regs->msr;
+
+ /* tm_reclaim rolls back all reg states, updating thread.ckpt_regs,
+ * thread.transact_fpr[], thread.transact_vr[], etc.
+ */
+ tm_enable();
+ tm_reclaim(¤t->thread, msr, TM_CAUSE_SIGNAL);
+
+ /* Make sure floating point registers are stored in regs */
+ flush_fp_to_thread(current);
+
+ /* Save both sets of general registers */
+ if (save_general_regs(¤t->thread.ckpt_regs, frame)
+ || save_general_regs(regs, tm_frame))
+ return 1;
+
+ /* Stash the top half of the 64bit MSR into the 32bit MSR word
+ * of the transactional mcontext. This way we have a backward-compatible
+ * MSR in the 'normal' (checkpointed) mcontext and additionally one can
+ * also look at what type of transaction (T or S) was active at the
+ * time of the signal.
+ */
+ if (__put_user((msr >> 32), &tm_frame->mc_gregs[PT_MSR]))
+ return 1;
+
+#ifdef CONFIG_ALTIVEC
+ /* save altivec registers */
+ if (current->thread.used_vr) {
+ flush_altivec_to_thread(current);
+ if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
+ ELF_NVRREG * sizeof(vector128)))
+ return 1;
+ if (msr & MSR_VEC) {
+ if (__copy_to_user(&tm_frame->mc_vregs,
+ current->thread.transact_vr,
+ ELF_NVRREG * sizeof(vector128)))
+ return 1;
+ } else {
+ if (__copy_to_user(&tm_frame->mc_vregs,
+ current->thread.vr,
+ ELF_NVRREG * sizeof(vector128)))
+ return 1;
+ }
+
+ /* set MSR_VEC in the saved MSR value to indicate that
+ * frame->mc_vregs contains valid data
+ */
+ msr |= MSR_VEC;
+ }
+
+ /* We always copy to/from vrsave, it's 0 if we don't have or don't
+ * use altivec. Since VSCR only contains 32 bits saved in the least
+ * significant bits of a vector, we "cheat" and stuff VRSAVE in the
+ * most significant bits of that same vector. --BenH
+ */
+ if (__put_user(current->thread.vrsave,
+ (u32 __user *)&frame->mc_vregs[32]))
+ return 1;
+ if (msr & MSR_VEC) {
+ if (__put_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_frame->mc_vregs[32]))
+ return 1;
+ } else {
+ if (__put_user(current->thread.vrsave,
+ (u32 __user *)&tm_frame->mc_vregs[32]))
+ return 1;
+ }
+#endif /* CONFIG_ALTIVEC */
+
+ if (copy_fpr_to_user(&frame->mc_fregs, current))
+ return 1;
+ if (msr & MSR_FP) {
+ if (copy_transact_fpr_to_user(&tm_frame->mc_fregs, current))
+ return 1;
+ } else {
+ if (copy_fpr_to_user(&tm_frame->mc_fregs, current))
+ return 1;
+ }
+
+#ifdef CONFIG_VSX
+ /*
+ * Copy VSR 0-31 upper half from thread_struct to local
+ * buffer, then write that to userspace. Also set MSR_VSX in
+ * the saved MSR value to indicate that frame->mc_vregs
+ * contains valid data
+ */
+ if (current->thread.used_vsr) {
+ __giveup_vsx(current);
+ if (copy_vsx_to_user(&frame->mc_vsregs, current))
+ return 1;
+ if (msr & MSR_VSX) {
+ if (copy_transact_vsx_to_user(&tm_frame->mc_vsregs,
+ current))
+ return 1;
+ } else {
+ if (copy_vsx_to_user(&tm_frame->mc_vsregs, current))
+ return 1;
+ }
+
+ msr |= MSR_VSX;
+ }
+#endif /* CONFIG_VSX */
+#ifdef CONFIG_SPE
+ /* SPE regs are not checkpointed with TM, so this section is
+ * simply the same as in save_user_regs().
+ */
+ if (current->thread.used_spe) {
+ flush_spe_to_thread(current);
+ if (__copy_to_user(&frame->mc_vregs, current->thread.evr,
+ ELF_NEVRREG * sizeof(u32)))
+ return 1;
+ /* set MSR_SPE in the saved MSR value to indicate that
+ * frame->mc_vregs contains valid data */
+ msr |= MSR_SPE;
+ }
+
+ /* We always copy to/from spefscr */
+ if (__put_user(current->thread.spefscr, (u32 __user *)&frame->mc_vregs + ELF_NEVRREG))
+ return 1;
+#endif /* CONFIG_SPE */
+
+ if (__put_user(msr, &frame->mc_gregs[PT_MSR]))
+ return 1;
+ if (sigret) {
+ /* Set up the sigreturn trampoline: li r0,sigret; sc */
+ if (__put_user(0x38000000UL + sigret, &frame->tramp[0])
+ || __put_user(0x44000002UL, &frame->tramp[1]))
+ return 1;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+ (unsigned long) &frame->tramp[2]);
+ }
+
+ return 0;
+}
+#endif
+
/*
* Restore the current user register values from the user stack,
* (except for MSR).
@@ -588,6 +817,139 @@ static long restore_user_regs(struct pt_regs *regs,
return 0;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Restore the current user register values from the user stack, except for
+ * MSR, and recheckpoint the original checkpointed register state for processes
+ * in transactions.
+ */
+static long restore_tm_user_regs(struct pt_regs *regs,
+ struct mcontext __user *sr,
+ struct mcontext __user *tm_sr)
+{
+ long err;
+ unsigned long msr;
+#ifdef CONFIG_VSX
+ int i;
+#endif
+
+ /*
+ * restore general registers but not including MSR or SOFTE. Also
+ * take care of keeping r2 (TLS) intact if not a signal.
+ * See comment in signal_64.c:restore_tm_sigcontexts();
+ * TFHAR is restored from the checkpointed NIP; TEXASR and TFIAR
+ * were set by the signal delivery.
+ */
+ err = restore_general_regs(regs, tm_sr);
+ err |= restore_general_regs(¤t->thread.ckpt_regs, sr);
+
+ err |= __get_user(current->thread.tm_tfhar, &sr->mc_gregs[PT_NIP]);
+
+ err |= __get_user(msr, &sr->mc_gregs[PT_MSR]);
+ if (err)
+ return 1;
+
+ /* Restore the previous little-endian mode */
+ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
+
+ /*
+ * Do this before updating the thread state in
+ * current->thread.fpr/vr/evr. That way, if we get preempted
+ * and another task grabs the FPU/Altivec/SPE, it won't be
+ * tempted to save the current CPU state into the thread_struct
+ * and corrupt what we are writing there.
+ */
+ discard_lazy_cpu_state();
+
+#ifdef CONFIG_ALTIVEC
+ regs->msr &= ~MSR_VEC;
+ if (msr & MSR_VEC) {
+ /* restore altivec registers from the stack */
+ if (__copy_from_user(current->thread.vr, &sr->mc_vregs,
+ sizeof(sr->mc_vregs)) ||
+ __copy_from_user(current->thread.transact_vr,
+ &tm_sr->mc_vregs,
+ sizeof(sr->mc_vregs)))
+ return 1;
+ } else if (current->thread.used_vr) {
+ memset(current->thread.vr, 0, ELF_NVRREG * sizeof(vector128));
+ memset(current->thread.transact_vr, 0,
+ ELF_NVRREG * sizeof(vector128));
+ }
+
+ /* Always get VRSAVE back */
+ if (__get_user(current->thread.vrsave,
+ (u32 __user *)&sr->mc_vregs[32]) ||
+ __get_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_sr->mc_vregs[32]))
+ return 1;
+#endif /* CONFIG_ALTIVEC */
+
+ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+
+ if (copy_fpr_from_user(current, &sr->mc_fregs) ||
+ copy_transact_fpr_from_user(current, &tm_sr->mc_fregs))
+ return 1;
+
+#ifdef CONFIG_VSX
+ regs->msr &= ~MSR_VSX;
+ if (msr & MSR_VSX) {
+ /*
+ * Restore altivec registers from the stack to a local
+ * buffer, then write this out to the thread_struct
+ */
+ if (copy_vsx_from_user(current, &sr->mc_vsregs) ||
+ copy_transact_vsx_from_user(current, &tm_sr->mc_vsregs))
+ return 1;
+ } else if (current->thread.used_vsr)
+ for (i = 0; i < 32 ; i++) {
+ current->thread.fpr[i][TS_VSRLOWOFFSET] = 0;
+ current->thread.transact_fpr[i][TS_VSRLOWOFFSET] = 0;
+ }
+#endif /* CONFIG_VSX */
+
+#ifdef CONFIG_SPE
+ /* SPE regs are not checkpointed with TM, so this section is
+ * simply the same as in restore_user_regs().
+ */
+ regs->msr &= ~MSR_SPE;
+ if (msr & MSR_SPE) {
+ if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
+ ELF_NEVRREG * sizeof(u32)))
+ return 1;
+ } else if (current->thread.used_spe)
+ memset(current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
+
+ /* Always get SPEFSCR back */
+ if (__get_user(current->thread.spefscr, (u32 __user *)&sr->mc_vregs
+ + ELF_NEVRREG))
+ return 1;
+#endif /* CONFIG_SPE */
+
+ /* Now, recheckpoint. This loads up all of the checkpointed (older)
+ * registers, including FP and V[S]Rs. After recheckpointing, the
+ * transactional versions should be loaded.
+ */
+ tm_enable();
+ /* This loads the checkpointed FP/VEC state, if used */
+ tm_recheckpoint(¤t->thread, msr);
+ /* The task has moved into TM state S, so ensure MSR reflects this */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | MSR_TS_S;
+
+ /* This loads the speculative FP/VEC state, if used */
+ if (msr & MSR_FP) {
+ do_load_up_transact_fpu(¤t->thread);
+ regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+ }
+ if (msr & MSR_VEC) {
+ do_load_up_transact_altivec(¤t->thread);
+ regs->msr |= MSR_VEC;
+ }
+
+ return 0;
+}
+#endif
+
#ifdef CONFIG_PPC64
long compat_sys_rt_sigaction(int sig, const struct sigaction32 __user *act,
struct sigaction32 __user *oact, size_t sigsetsize)
@@ -827,6 +1189,8 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
struct mcontext __user *frame;
void __user *addr;
unsigned long newsp = 0;
+ int sigret;
+ unsigned long tramp;
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
@@ -838,7 +1202,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
/* Put the siginfo & fill in most of the ucontext */
if (copy_siginfo_to_user(&rt_sf->info, info)
|| __put_user(0, &rt_sf->uc.uc_flags)
- || __put_user(0, &rt_sf->uc.uc_link)
|| __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
|| __put_user(sas_ss_flags(regs->gpr[1]),
&rt_sf->uc.uc_stack.ss_flags)
@@ -852,14 +1215,37 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
frame = &rt_sf->uc.uc_mcontext;
addr = frame;
if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
- if (save_user_regs(regs, frame, 0, 1))
- goto badframe;
- regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp;
+ sigret = 0;
+ tramp = current->mm->context.vdso_base + vdso32_rt_sigtramp;
} else {
- if (save_user_regs(regs, frame, __NR_rt_sigreturn, 1))
+ sigret = __NR_rt_sigreturn;
+ tramp = (unsigned long) frame->tramp;
+ }
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ if (save_tm_user_regs(regs, &rt_sf->uc.uc_mcontext,
+ &rt_sf->uc_transact.uc_mcontext, sigret))
goto badframe;
- regs->link = (unsigned long) frame->tramp;
}
+ else
+#endif
+ if (save_user_regs(regs, frame, sigret, 1))
+ goto badframe;
+ regs->link = tramp;
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ if (__put_user((unsigned long)&rt_sf->uc_transact,
+ &rt_sf->uc.uc_link)
+ || __put_user(to_user_ptr(&rt_sf->uc_transact.uc_mcontext),
+ &rt_sf->uc_transact.uc_regs))
+ goto badframe;
+ }
+ else
+#endif
+ if (__put_user(0, &rt_sf->uc.uc_link))
+ goto badframe;
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
@@ -878,6 +1264,13 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
regs->nip = (unsigned long) ka->sa.sa_handler;
/* enter the signal handler in big-endian mode */
regs->msr &= ~MSR_LE;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Remove TM bits from thread's MSR. The MSR in the sigcontext
+ * just indicates to userland that we were doing a transaction, but we
+ * don't want to return in transactional state:
+ */
+ regs->msr &= ~MSR_TS_MASK;
+#endif
return 1;
badframe:
@@ -925,6 +1318,35 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int
return 0;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static int do_setcontext_tm(struct ucontext __user *ucp,
+ struct ucontext __user *tm_ucp,
+ struct pt_regs *regs)
+{
+ sigset_t set;
+ struct mcontext __user *mcp;
+ struct mcontext __user *tm_mcp;
+ u32 cmcp;
+ u32 tm_cmcp;
+
+ if (get_sigset_t(&set, &ucp->uc_sigmask))
+ return -EFAULT;
+
+ if (__get_user(cmcp, &ucp->uc_regs) ||
+ __get_user(tm_cmcp, &tm_ucp->uc_regs))
+ return -EFAULT;
+ mcp = (struct mcontext __user *)(u64)cmcp;
+ tm_mcp = (struct mcontext __user *)(u64)tm_cmcp;
+ /* no need to check access_ok(mcp), since mcp < 4GB */
+
+ set_current_blocked(&set);
+ if (restore_tm_user_regs(regs, mcp, tm_mcp))
+ return -EFAULT;
+
+ return 0;
+}
+#endif
+
long sys_swapcontext(struct ucontext __user *old_ctx,
struct ucontext __user *new_ctx,
int ctx_size, int r6, int r7, int r8, struct pt_regs *regs)
@@ -1020,7 +1442,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
struct pt_regs *regs)
{
struct rt_sigframe __user *rt_sf;
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct ucontext __user *uc_transact;
+ unsigned long msr_hi;
+ unsigned long tmp;
+ int tm_restore = 0;
+#endif
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -1028,6 +1455,34 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);
if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf)))
goto bad;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (__get_user(tmp, &rt_sf->uc.uc_link))
+ goto bad;
+ uc_transact = (struct ucontext __user *)(uintptr_t)tmp;
+ if (uc_transact) {
+ u32 cmcp;
+ struct mcontext __user *mcp;
+
+ if (__get_user(cmcp, &uc_transact->uc_regs))
+ return -EFAULT;
+ mcp = (struct mcontext __user *)(u64)cmcp;
+ /* The top 32 bits of the MSR are stashed in the transactional
+ * ucontext. */
+ if (__get_user(msr_hi, &mcp->mc_gregs[PT_MSR]))
+ goto bad;
+
+ if (MSR_TM_SUSPENDED(msr_hi<<32)) {
+ /* We only recheckpoint on return if we're
+ * transaction.
+ */
+ tm_restore = 1;
+ if (do_setcontext_tm(&rt_sf->uc, uc_transact, regs))
+ goto bad;
+ }
+ }
+ if (!tm_restore)
+ /* Fall through, for non-TM restore */
+#endif
if (do_setcontext(&rt_sf->uc, regs, 1))
goto bad;
@@ -1179,6 +1634,8 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
struct sigcontext __user *sc;
struct sigframe __user *frame;
unsigned long newsp = 0;
+ int sigret;
+ unsigned long tramp;
/* Set up Signal Frame */
frame = get_sigframe(ka, regs, sizeof(*frame), 1);
@@ -1201,14 +1658,25 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
goto badframe;
if (vdso32_sigtramp && current->mm->context.vdso_base) {
- if (save_user_regs(regs, &frame->mctx, 0, 1))
- goto badframe;
- regs->link = current->mm->context.vdso_base + vdso32_sigtramp;
+ sigret = 0;
+ tramp = current->mm->context.vdso_base + vdso32_sigtramp;
} else {
- if (save_user_regs(regs, &frame->mctx, __NR_sigreturn, 1))
+ sigret = __NR_sigreturn;
+ tramp = (unsigned long) frame->mctx.tramp;
+ }
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ if (save_tm_user_regs(regs, &frame->mctx, &frame->mctx_transact,
+ sigret))
goto badframe;
- regs->link = (unsigned long) frame->mctx.tramp;
}
+ else
+#endif
+ if (save_user_regs(regs, &frame->mctx, sigret, 1))
+ goto badframe;
+
+ regs->link = tramp;
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
@@ -1223,7 +1691,13 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
regs->nip = (unsigned long) ka->sa.sa_handler;
/* enter the signal handler in big-endian mode */
regs->msr &= ~MSR_LE;
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Remove TM bits from thread's MSR. The MSR in the sigcontext
+ * just indicates to userland that we were doing a transaction, but we
+ * don't want to return in transactional state:
+ */
+ regs->msr &= ~MSR_TS_MASK;
+#endif
return 1;
badframe:
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 1ca045d..7a76ee4 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -34,6 +34,7 @@
#include <asm/syscalls.h>
#include <asm/vdso.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#include "signal.h"
@@ -56,6 +57,9 @@
struct rt_sigframe {
/* sys_rt_sigreturn requires the ucontext be the first field */
struct ucontext uc;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct ucontext uc_transact;
+#endif
unsigned long _unused[2];
unsigned int tramp[TRAMP_SIZE];
struct siginfo __user *pinfo;
@@ -145,6 +149,145 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
return err;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * As above, but Transactional Memory is in use, so deliver sigcontexts
+ * containing checkpointed and transactional register states.
+ *
+ * To do this, we treclaim to gather both sets of registers and set up the
+ * 'normal' sigcontext registers with rolled-back register values such that a
+ * simple signal handler sees a correct checkpointed register state.
+ * If interested, a TM-aware sighandler can examine the transactional registers
+ * in the 2nd sigcontext to determine the real origin of the signal.
+ */
+static long setup_tm_sigcontexts(struct sigcontext __user *sc,
+ struct sigcontext __user *tm_sc,
+ struct pt_regs *regs,
+ int signr, sigset_t *set, unsigned long handler)
+{
+ /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the
+ * process never used altivec yet (MSR_VEC is zero in pt_regs of
+ * the context). This is very important because we must ensure we
+ * don't lose the VRSAVE content that may have been set prior to
+ * the process doing its first vector operation
+ * Userland shall check AT_HWCAP to know wether it can rely on the
+ * v_regs pointer or not.
+ */
+#ifdef CONFIG_ALTIVEC
+ elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)
+ (((unsigned long)sc->vmx_reserve + 15) & ~0xful);
+ elf_vrreg_t __user *tm_v_regs = (elf_vrreg_t __user *)
+ (((unsigned long)tm_sc->vmx_reserve + 15) & ~0xful);
+#endif
+ unsigned long msr = regs->msr;
+ long err = 0;
+
+ BUG_ON(!MSR_TM_ACTIVE(regs->msr));
+
+ /* tm_reclaim rolls back all reg states, saving checkpointed (older)
+ * GPRs to thread.ckpt_regs and (if used) FPRs to (newer)
+ * thread.transact_fp and/or VRs to (newer) thread.transact_vr.
+ * THEN we save out FP/VRs, if necessary, to the checkpointed (older)
+ * thread.fr[]/vr[]s. The transactional (newer) GPRs are on the
+ * stack, in *regs.
+ */
+ tm_enable();
+ tm_reclaim(¤t->thread, msr, TM_CAUSE_SIGNAL);
+
+ flush_fp_to_thread(current);
+
+#ifdef CONFIG_ALTIVEC
+ err |= __put_user(v_regs, &sc->v_regs);
+ err |= __put_user(tm_v_regs, &tm_sc->v_regs);
+
+ /* save altivec registers */
+ if (current->thread.used_vr) {
+ flush_altivec_to_thread(current);
+ /* Copy 33 vec registers (vr0..31 and vscr) to the stack */
+ err |= __copy_to_user(v_regs, current->thread.vr,
+ 33 * sizeof(vector128));
+ /* If VEC was enabled there are transactional VRs valid too,
+ * else they're a copy of the checkpointed VRs.
+ */
+ if (msr & MSR_VEC)
+ err |= __copy_to_user(tm_v_regs,
+ current->thread.transact_vr,
+ 33 * sizeof(vector128));
+ else
+ err |= __copy_to_user(tm_v_regs,
+ current->thread.vr,
+ 33 * sizeof(vector128));
+
+ /* set MSR_VEC in the MSR value in the frame to indicate
+ * that sc->v_reg contains valid data.
+ */
+ msr |= MSR_VEC;
+ }
+ /* We always copy to/from vrsave, it's 0 if we don't have or don't
+ * use altivec.
+ */
+ err |= __put_user(current->thread.vrsave, (u32 __user *)&v_regs[33]);
+ if (msr & MSR_VEC)
+ err |= __put_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_v_regs[33]);
+ else
+ err |= __put_user(current->thread.vrsave,
+ (u32 __user *)&tm_v_regs[33]);
+
+#else /* CONFIG_ALTIVEC */
+ err |= __put_user(0, &sc->v_regs);
+ err |= __put_user(0, &tm_sc->v_regs);
+#endif /* CONFIG_ALTIVEC */
+
+ /* copy fpr regs and fpscr */
+ err |= copy_fpr_to_user(&sc->fp_regs, current);
+ if (msr & MSR_FP)
+ err |= copy_transact_fpr_to_user(&tm_sc->fp_regs, current);
+ else
+ err |= copy_fpr_to_user(&tm_sc->fp_regs, current);
+
+#ifdef CONFIG_VSX
+ /*
+ * Copy VSX low doubleword to local buffer for formatting,
+ * then out to userspace. Update v_regs to point after the
+ * VMX data.
+ */
+ if (current->thread.used_vsr) {
+ __giveup_vsx(current);
+ v_regs += ELF_NVRREG;
+ tm_v_regs += ELF_NVRREG;
+
+ err |= copy_vsx_to_user(v_regs, current);
+
+ if (msr & MSR_VSX)
+ err |= copy_transact_vsx_to_user(tm_v_regs, current);
+ else
+ err |= copy_vsx_to_user(tm_v_regs, current);
+
+ /* set MSR_VSX in the MSR value in the frame to
+ * indicate that sc->vs_reg) contains valid data.
+ */
+ msr |= MSR_VSX;
+ }
+#endif /* CONFIG_VSX */
+
+ err |= __put_user(&sc->gp_regs, &sc->regs);
+ err |= __put_user(&tm_sc->gp_regs, &tm_sc->regs);
+ WARN_ON(!FULL_REGS(regs));
+ err |= __copy_to_user(&tm_sc->gp_regs, regs, GP_REGS_SIZE);
+ err |= __copy_to_user(&sc->gp_regs,
+ ¤t->thread.ckpt_regs, GP_REGS_SIZE);
+ err |= __put_user(msr, &tm_sc->gp_regs[PT_MSR]);
+ err |= __put_user(msr, &sc->gp_regs[PT_MSR]);
+ err |= __put_user(signr, &sc->signal);
+ err |= __put_user(handler, &sc->handler);
+ if (set != NULL)
+ err |= __put_user(set->sig[0], &sc->oldmask);
+
+ return err;
+}
+#endif
+
/*
* Restore the sigcontext from the signal frame.
*/
@@ -241,6 +384,153 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
return err;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+/*
+ * Restore the two sigcontexts from the frame of a transactional processes.
+ */
+
+static long restore_tm_sigcontexts(struct pt_regs *regs,
+ struct sigcontext __user *sc,
+ struct sigcontext __user *tm_sc)
+{
+#ifdef CONFIG_ALTIVEC
+ elf_vrreg_t __user *v_regs, *tm_v_regs;
+#endif
+ unsigned long err = 0;
+ unsigned long msr;
+#ifdef CONFIG_VSX
+ int i;
+#endif
+ /* copy the GPRs */
+ err |= __copy_from_user(regs->gpr, tm_sc->gp_regs, sizeof(regs->gpr));
+ err |= __copy_from_user(¤t->thread.ckpt_regs, sc->gp_regs,
+ sizeof(regs->gpr));
+
+ /*
+ * TFHAR is restored from the checkpointed 'wound-back' ucontext's NIP.
+ * TEXASR was set by the signal delivery reclaim, as was TFIAR.
+ * Users doing anything abhorrent like thread-switching w/ signals for
+ * TM-Suspended code will have to back TEXASR/TFIAR up themselves.
+ * For the case of getting a signal and simply returning from it,
+ * we don't need to re-copy them here.
+ */
+ err |= __get_user(regs->nip, &tm_sc->gp_regs[PT_NIP]);
+ err |= __get_user(current->thread.tm_tfhar, &sc->gp_regs[PT_NIP]);
+
+ /* get MSR separately, transfer the LE bit if doing signal return */
+ err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+ regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
+
+ /* The following non-GPR non-FPR non-VR state is also checkpointed: */
+ err |= __get_user(regs->ctr, &tm_sc->gp_regs[PT_CTR]);
+ err |= __get_user(regs->link, &tm_sc->gp_regs[PT_LNK]);
+ err |= __get_user(regs->xer, &tm_sc->gp_regs[PT_XER]);
+ err |= __get_user(regs->ccr, &tm_sc->gp_regs[PT_CCR]);
+ err |= __get_user(current->thread.ckpt_regs.ctr,
+ &sc->gp_regs[PT_CTR]);
+ err |= __get_user(current->thread.ckpt_regs.link,
+ &sc->gp_regs[PT_LNK]);
+ err |= __get_user(current->thread.ckpt_regs.xer,
+ &sc->gp_regs[PT_XER]);
+ err |= __get_user(current->thread.ckpt_regs.ccr,
+ &sc->gp_regs[PT_CCR]);
+
+ /* These regs are not checkpointed; they can go in 'regs'. */
+ err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]);
+ err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]);
+ err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]);
+ err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]);
+
+ /*
+ * Do this before updating the thread state in
+ * current->thread.fpr/vr. That way, if we get preempted
+ * and another task grabs the FPU/Altivec, it won't be
+ * tempted to save the current CPU state into the thread_struct
+ * and corrupt what we are writing there.
+ */
+ discard_lazy_cpu_state();
+
+ /*
+ * Force reload of FP/VEC.
+ * This has to be done before copying stuff into current->thread.fpr/vr
+ * for the reasons explained in the previous comment.
+ */
+ regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX);
+
+#ifdef CONFIG_ALTIVEC
+ err |= __get_user(v_regs, &sc->v_regs);
+ err |= __get_user(tm_v_regs, &tm_sc->v_regs);
+ if (err)
+ return err;
+ if (v_regs && !access_ok(VERIFY_READ, v_regs, 34 * sizeof(vector128)))
+ return -EFAULT;
+ if (tm_v_regs && !access_ok(VERIFY_READ,
+ tm_v_regs, 34 * sizeof(vector128)))
+ return -EFAULT;
+ /* Copy 33 vec registers (vr0..31 and vscr) from the stack */
+ if (v_regs != 0 && tm_v_regs != 0 && (msr & MSR_VEC) != 0) {
+ err |= __copy_from_user(current->thread.vr, v_regs,
+ 33 * sizeof(vector128));
+ err |= __copy_from_user(current->thread.transact_vr, tm_v_regs,
+ 33 * sizeof(vector128));
+ }
+ else if (current->thread.used_vr) {
+ memset(current->thread.vr, 0, 33 * sizeof(vector128));
+ memset(current->thread.transact_vr, 0, 33 * sizeof(vector128));
+ }
+ /* Always get VRSAVE back */
+ if (v_regs != 0 && tm_v_regs != 0) {
+ err |= __get_user(current->thread.vrsave,
+ (u32 __user *)&v_regs[33]);
+ err |= __get_user(current->thread.transact_vrsave,
+ (u32 __user *)&tm_v_regs[33]);
+ }
+ else {
+ current->thread.vrsave = 0;
+ current->thread.transact_vrsave = 0;
+ }
+#endif /* CONFIG_ALTIVEC */
+ /* restore floating point */
+ err |= copy_fpr_from_user(current, &sc->fp_regs);
+ err |= copy_transact_fpr_from_user(current, &tm_sc->fp_regs);
+#ifdef CONFIG_VSX
+ /*
+ * Get additional VSX data. Update v_regs to point after the
+ * VMX data. Copy VSX low doubleword from userspace to local
+ * buffer for formatting, then into the taskstruct.
+ */
+ if (v_regs && ((msr & MSR_VSX) != 0)) {
+ v_regs += ELF_NVRREG;
+ tm_v_regs += ELF_NVRREG;
+ err |= copy_vsx_from_user(current, v_regs);
+ err |= copy_transact_vsx_from_user(current, tm_v_regs);
+ } else {
+ for (i = 0; i < 32 ; i++) {
+ current->thread.fpr[i][TS_VSRLOWOFFSET] = 0;
+ current->thread.transact_fpr[i][TS_VSRLOWOFFSET] = 0;
+ }
+ }
+#endif
+ tm_enable();
+ /* This loads the checkpointed FP/VEC state, if used */
+ tm_recheckpoint(¤t->thread, msr);
+ /* The task has moved into TM state S, so ensure MSR reflects this: */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | __MASK(33);
+
+ /* This loads the speculative FP/VEC state, if used */
+ if (msr & MSR_FP) {
+ do_load_up_transact_fpu(¤t->thread);
+ regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+ }
+ if (msr & MSR_VEC) {
+ do_load_up_transact_altivec(¤t->thread);
+ regs->msr |= MSR_VEC;
+ }
+
+ return err;
+}
+#endif
+
/*
* Setup the trampoline code on the stack
*/
@@ -355,6 +645,9 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
{
struct ucontext __user *uc = (struct ucontext __user *)regs->gpr[1];
sigset_t set;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ unsigned long msr;
+#endif
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -365,6 +658,21 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
goto badframe;
set_current_blocked(&set);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (__get_user(msr, &uc->uc_mcontext.gp_regs[PT_MSR]))
+ goto badframe;
+ if (MSR_TM_SUSPENDED(msr)) {
+ /* We recheckpoint on return. */
+ struct ucontext __user *uc_transact;
+ if (__get_user(uc_transact, &uc->uc_link))
+ goto badframe;
+ if (restore_tm_sigcontexts(regs, &uc->uc_mcontext,
+ &uc_transact->uc_mcontext))
+ goto badframe;
+ }
+ else
+ /* Fall through, for non-TM restore */
+#endif
if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext))
goto badframe;
@@ -415,19 +723,42 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->gpr[1]),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
- (unsigned long)ka->sa.sa_handler, 1);
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (MSR_TM_ACTIVE(regs->msr)) {
+ /* The ucontext_t passed to userland points to the second
+ * ucontext_t (for transactional state) with its uc_link ptr.
+ */
+ err |= __put_user(&frame->uc_transact, &frame->uc.uc_link);
+ err |= setup_tm_sigcontexts(&frame->uc.uc_mcontext,
+ &frame->uc_transact.uc_mcontext,
+ regs, signr,
+ NULL,
+ (unsigned long)ka->sa.sa_handler);
+ } else
+#endif
+ {
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr,
+ NULL, (unsigned long)ka->sa.sa_handler,
+ 1);
+ }
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto badframe;
/* Make sure signal handler doesn't get spurious FP exceptions */
current->thread.fpscr.val = 0;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Remove TM bits from thread's MSR. The MSR in the sigcontext
+ * just indicates to userland that we were doing a transaction, but we
+ * don't want to return in transactional state:
+ */
+ regs->msr &= ~MSR_TS_MASK;
+#endif
/* Set up to return from userspace. */
if (vdso64_rt_sigtramp && current->mm->context.vdso_base) {
--
1.7.10.4
^ permalink raw reply related
* [PATCH 12/17] powerpc: Hook in new transactional memory code
From: Michael Neuling @ 2013-02-13 4:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1360729895-304-1-git-send-email-mikey@neuling.org>
This hooks the new transactional memory code into context switching, FP/VMX/VMX
unavailable and exception return.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/kernel/exceptions-64s.S | 56 ++++++++++++++++++++++++++++++++--
arch/powerpc/kernel/process.c | 15 +++++++--
arch/powerpc/kernel/traps.c | 32 +++++++++++++++++++
arch/powerpc/mm/hash_utils_64.c | 16 ++++++++++
4 files changed, 115 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index d0cc657..85b923c 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1147,9 +1147,26 @@ fp_unavailable_common:
addi r3,r1,STACK_FRAME_OVERHEAD
bl .kernel_fp_unavailable_exception
BUG_OPCODE
-1: bl .load_up_fpu
+1:
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+ bl .load_up_fpu
b fast_exception_return
-
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .fp_unavailable_tm
+ b .ret_from_except
+#endif
.align 7
.globl altivec_unavailable_common
altivec_unavailable_common:
@@ -1157,8 +1174,25 @@ altivec_unavailable_common:
#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
beq 1f
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
bl .load_up_altivec
b fast_exception_return
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .altivec_unavailable_tm
+ b .ret_from_except
+#endif
1:
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
@@ -1175,7 +1209,24 @@ vsx_unavailable_common:
#ifdef CONFIG_VSX
BEGIN_FTR_SECTION
beq 1f
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ /* Test if 2 TM state bits are zero. If non-zero (ie. userspace was in
+ * transaction), go do TM stuff
+ */
+ rldicl. r0, r12, (64-MSR_TS_LG), (64-2)
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
b .load_up_vsx
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ DISABLE_INTS
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .vsx_unavailable_tm
+ b .ret_from_except
+#endif
1:
END_FTR_SECTION_IFSET(CPU_FTR_VSX)
#endif
@@ -1190,6 +1241,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
tm_unavailable_common:
EXCEPTION_PROLOG_COMMON(0xf60, PACA_EXGEN)
bl .save_nvgprs
+ DISABLE_INTS
addi r3,r1,STACK_FRAME_OVERHEAD
bl .tm_unavailable_exception
b .ret_from_except
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 48a9875..59dd545 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -515,7 +515,7 @@ out_and_saveregs:
tm_save_sprs(thr);
}
-static inline void __maybe_unused tm_recheckpoint_new_task(struct task_struct *new)
+static inline void tm_recheckpoint_new_task(struct task_struct *new)
{
unsigned long msr;
@@ -590,6 +590,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
struct ppc64_tlb_batch *batch;
#endif
+ __switch_to_tm(prev);
+
#ifdef CONFIG_SMP
/* avoid complexity of lazy save/restore of fpu
* by just saving it every time we switch out if
@@ -705,6 +707,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
* of sync. Hard disable here.
*/
hard_irq_disable();
+
+ tm_recheckpoint_new_task(new);
+
last = _switch(old_thread, new_thread);
#ifdef CONFIG_PPC_BOOK3S_64
@@ -1080,7 +1085,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
regs->msr = MSR_USER32;
}
#endif
-
discard_lazy_cpu_state();
#ifdef CONFIG_VSX
current->thread.used_vsr = 0;
@@ -1100,6 +1104,13 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
current->thread.spefscr = 0;
current->thread.used_spe = 0;
#endif /* CONFIG_SPE */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (cpu_has_feature(CPU_FTR_TM))
+ regs->msr |= MSR_TM;
+ current->thread.tm_tfhar = 0;
+ current->thread.tm_texasr = 0;
+ current->thread.tm_tfiar = 0;
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
}
#define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 5c30469..f9b751b 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1029,6 +1029,38 @@ void __kprobes program_check_exception(struct pt_regs *regs)
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
return;
}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ if (reason & REASON_TM) {
+ /* This is a TM "Bad Thing Exception" program check.
+ * This occurs when:
+ * - An rfid/hrfid/mtmsrd attempts to cause an illegal
+ * transition in TM states.
+ * - A trechkpt is attempted when transactional.
+ * - A treclaim is attempted when non transactional.
+ * - A tend is illegally attempted.
+ * - writing a TM SPR when transactional.
+ */
+ if (!user_mode(regs) &&
+ report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
+ regs->nip += 4;
+ return;
+ }
+ /* If usermode caused this, it's done something illegal and
+ * gets a SIGILL slap on the wrist. We call it an illegal
+ * operand to distinguish from the instruction just being bad
+ * (e.g. executing a 'tend' on a CPU without TM!); it's an
+ * illegal /placement/ of a valid instruction.
+ */
+ if (user_mode(regs)) {
+ _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
+ return;
+ } else {
+ printk(KERN_EMERG "Unexpected TM Bad Thing exception "
+ "at %lx (msr 0x%x)\n", regs->nip, reason);
+ die("Unrecoverable exception", regs, SIGABRT);
+ }
+ }
+#endif
/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 3a292be..1b6e127 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -55,6 +55,7 @@
#include <asm/code-patching.h>
#include <asm/fadump.h>
#include <asm/firmware.h>
+#include <asm/tm.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -1171,6 +1172,21 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx);
ppc_md.hpte_invalidate(slot, vpn, psize, ssize, local);
} pte_iterate_hashed_end();
+
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ /* Transactions are not aborted by tlbiel, only tlbie.
+ * Without, syncing a page back to a block device w/ PIO could pick up
+ * transactional data (bad!) so we force an abort here. Before the
+ * sync the page will be made read-only, which will flush_hash_page.
+ * BIG ISSUE here: if the kernel uses a page from userspace without
+ * unmapping it first, it may see the speculated version.
+ */
+ if (local && cpu_has_feature(CPU_FTR_TM) &&
+ MSR_TM_ACTIVE(current->thread.regs->msr)) {
+ tm_enable();
+ tm_abort(TM_CAUSE_TLBI);
+ }
+#endif
}
void flush_hash_range(unsigned long number, int local)
--
1.7.10.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