LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [RFC PATCH 3/4] powerpc: refactor of_get_cpu_node to support other architectures
From: Benjamin Herrenschmidt @ 2013-08-16 12:32 UTC (permalink / raw)
  To: Sudeep KarkadaNagesha
  Cc: Jonas Bonn, devicetree@vger.kernel.org, Michal Simek,
	linux-pm@vger.kernel.org, microblaze-uclinux@itee.uq.edu.au,
	linux@openrisc.net, linux-kernel@vger.kernel.org,
	rob.herring@calxeda.com, Rafael J. Wysocki,
	grant.likely@linaro.org, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <520DE753.8090601@arm.com>

On Fri, 2013-08-16 at 09:48 +0100, Sudeep KarkadaNagesha wrote:

> > Naming is a bit gross. You might want to make it clearer that
> > we are talking about CPU IDs in the device-tree here.
> > 
> Any particular preference to the name or just a note is sufficient.
> Also unlike PPC, in ARM we don't set hard processor id value based
> values read from device tree. DT must contain the values matching to the
> hardware ID registers.

This is exactly the same on ppc. We don't "set" HW values. The
device-tree content matches the HW internals. Some processors have a
"PIR" register as well which contains the HW value, in this case the
device-tree must contain the same value as the PIR on that processor.

> >> +static bool __of_find_n_match_cpu_property(struct device_node *cpun,
> >> +			const char *prop_name, int cpu, unsigned int *thread)
> >> +{
> >> +	const __be32 *cell;
> >> +	int ac, prop_len, tid;
> >> +	u64 hwid;
> >> +
> >> +	ac = of_n_addr_cells(cpun);
> >> +	cell = of_get_property(cpun, prop_name, &prop_len);
> >> +	if (!cell)
> >> +		return false;
> >> +	prop_len /= sizeof(*cell);
> >> +	for (tid = 0; tid < prop_len; tid++) {
> >> +		hwid = of_read_number(cell, ac);
> >> +		if (arch_match_cpu_phys_id(cpu, hwid)) {
> >> +			if (thread)
> >> +				*thread = tid;
> >> +			return true;
> >> +		}
> > 
> > Missing:          cell += ac;
> Ah, missed it while refactoring, will fix it. Thanks

Ben.

> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: Critical Interrupt Input
From: Kumar Gala @ 2013-08-16 11:04 UTC (permalink / raw)
  To: hbausley; +Cc: linuxppc-dev
In-Reply-To: <4724f96e$5f998126$5fb2b995$@deltatau.com>


On Aug 15, 2013, at 11:57 PM, Henry Bausley wrote:

>=20
> Is there any reason that a Critical Input Interrupt will not work =
reliably on a 44x powerpc?
>=20
> I am using an AMCC now Applied Micro AMCC460EX=20
>=20
> and changed
>=20
> CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception)
> to
> CRITICAL_EXCEPTION(0x0100, CriticalInput, do_MyCritIntr)
>=20
> The code for the handler is trivial
> ie.
> int crintrcount;
>=20
> void do_MyCritIntr(void)
> {
>   crintrcount++;
> }
>=20
> The code runs for a while but eventually I get panic messages and  the =
system hangs.  Is there something I must alter in the kernel to do this =
reliably?

The 44x low level code needs to handle exception stacks properly for =
this to work.  Since its possible to have a critical exception occur =
while in a normal exception level, you have to have proper saving of =
additional register state and a stack frame for the critical exception, =
etc.  I'm not sure if that was ever done for 44x.

- k

^ permalink raw reply

* Re: [PATCH 1/2] powerpc/85xx: add hardware automatically enter altivec idle state
From: Kumar Gala @ 2013-08-16 11:02 UTC (permalink / raw)
  To: Dongsheng Wang; +Cc: scottwood, linuxppc-dev
In-Reply-To: <1376637789-27330-1-git-send-email-dongsheng.wang@freescale.com>


On Aug 16, 2013, at 2:23 AM, Dongsheng Wang wrote:

> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>=20
> Each core's AltiVec unit may be placed into a power savings mode
> by turning off power to the unit. Core hardware will automatically
> power down the AltiVec unit after no AltiVec instructions have
> executed in N cycles. The AltiVec power-control is triggered by =
hardware.
>=20
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>

Why treat this as a idle HW governor vs just some one time setup at boot =
of the time delay?

- k=

^ permalink raw reply

* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Nicolin Chen @ 2013-08-16 10:16 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
	pawel.moll, swarren, festevam, Tomasz Figa, rob.herring, timur,
	broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816101151.GQ26614@pengutronix.de>

On Fri, Aug 16, 2013 at 12:11:51PM +0200, Sascha Hauer wrote:
> > Some clocks are not from CCM and we haven't defined in imx6q-clk.txt,
> > so in most cases we can't provide a phandle for them, eg: spdif_ext.
> > I think it's a bit hard to force it to be 'required'. An 'optional'
> > looks more flexible to me and a default one is ensured even if it's
> > missing.
> 
> <&clks 0> is the dummy clock. This can be used for all input clocks not
> defined by the SoC.

That's feasible, thank you.

> spdif_ext would be a fixed clock on boards which provide it, but wiring
> this up would be the job of the board maintainer.

Understood.

> Look, it's really simple. Define the binding in a way that describes the
> hardware. Then use some sensible default in the driver for which clock
> to use. This doesn't have to cover all possible usecases, it only has
> to work. This is all that is necessary to get this driver mainline and
> will make most users happy. Then, later, someone might come along who
> needs more fine grained control over the clocks, but this guy is then
> able to justify *why* more control is needed.
> 
> This is not about getting a full featured driver into mainline. Get
> a basic driver into mainline and improve it later. You'll make it
> easier for us all.

Thank you for explain all these to the despicable me.
I'll try to make myself more comfortable with rules here.

Best regards,
Nicolin Chen

^ permalink raw reply

* Re: [PATCH 2/2] powerpc/iommu: check dev->iommu_group before remove a device from iommu_group
From: Alexey Kardashevskiy @ 2013-08-16 10:15 UTC (permalink / raw)
  To: Wei Yang; +Cc: paulus, benh, linuxppc-dev, linux-kernel
In-Reply-To: <1376647687-20550-3-git-send-email-weiyang@linux.vnet.ibm.com>

On 08/16/2013 08:08 PM, Wei Yang wrote:
> ---
>  arch/powerpc/kernel/iommu.c |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
> index b20ff17..5abf7c3 100644
> --- a/arch/powerpc/kernel/iommu.c
> +++ b/arch/powerpc/kernel/iommu.c
> @@ -1149,7 +1149,8 @@ static int iommu_bus_notifier(struct notifier_block *nb,
>  	case BUS_NOTIFY_ADD_DEVICE:
>  		return iommu_add_device(dev);
>  	case BUS_NOTIFY_DEL_DEVICE:
> -		iommu_del_device(dev);
> +		if (dev->iommu_group)
> +			iommu_del_device(dev);
>  		return 0;
>  	default:
>  		return 0;
> 

This one seems redundant, no?


-- 
Alexey

^ permalink raw reply

* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Sascha Hauer @ 2013-08-16 10:11 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
	pawel.moll, swarren, festevam, Tomasz Figa, rob.herring, timur,
	broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816095357.GA4694@MrMyself>

On Fri, Aug 16, 2013 at 05:53:58PM +0800, Nicolin Chen wrote:
> On Fri, Aug 16, 2013 at 10:56:32AM +0200, Sascha Hauer wrote:
> > > "tx<0-8>"	Optional	Tx clock source for spdif playback.
> > > 				If absent, will use core clock.
> > > 				The index from 0 to 8 is identical
> > > 				to the clock source list described
> > > 				in TxClk_Source bit of register STC.
> > > 				Multiple clock source are allowed
> > > 				for this tx clock source. The driver
> > > 				will select one source from them for
> > > 				each supported sample rate according
> > > 				to the clock rates of these provided
> > > 				clock sources.
> > 
> > You mean tx<0-7>
> 
> Yes. Thank you.
> 
> > Also I would make this option required. Use a dummy clock for mux inputs
> > that are grounded for a specific SoC.
> 
> Some clocks are not from CCM and we haven't defined in imx6q-clk.txt,
> so in most cases we can't provide a phandle for them, eg: spdif_ext.
> I think it's a bit hard to force it to be 'required'. An 'optional'
> looks more flexible to me and a default one is ensured even if it's
> missing.

<&clks 0> is the dummy clock. This can be used for all input clocks not
defined by the SoC.

spdif_ext would be a fixed clock on boards which provide it, but wiring
this up would be the job of the board maintainer.

> > Again, describe the input clocks *to* *the* *S/PDIF* *core* in the
> > devicetree. Nothing more, nothing less. We've already been at the point
> > where we realized that half of the above clocks only describe the
> > 'PDLL locked' condition. Also the tx clocks are from what I see identical
> > to the rx clocks. The following are the clocks:
> > 
> > clock-names: "core", "rxtx<0-7>" Required. The S/PDIF core has a core
> > clock and 8 clocks which are muxed internally to provide input/output
> > sample clocks.
> 
> I know the reason why you suggest to combine two into 'rxtx<0-7>'
> is because the clock mux is defined so. And the previous suggestion
> 'the option required' is also because of it. But actually the rxclk 
> itself, can be not only routed from the clock mux but also derived
> from DPLL of SPDIF Rx BLOCK as well. So, IMHO, it's more likely to
> be a fact that rxclk actually has 9 clock source, 8 from mux and
> 1 from DPLL. But why we here have to exclude it?

Because this is configuration, not hardware description.

> 
> WELL anyway, I know my opinion might not be concerned so much. So
> I would like to follow the suggestion as an expediency because I
> still wish this patch could be finally applied and merged into
> mainline :(
> 
> But I still don't get why we need to be so obsessed to make this
> impenetrable rule of devicetree that we here have to sacrifice
> something we could have reasonably done.

Look, it's really simple. Define the binding in a way that describes the
hardware. Then use some sensible default in the driver for which clock
to use. This doesn't have to cover all possible usecases, it only has
to work. This is all that is necessary to get this driver mainline and
will make most users happy. Then, later, someone might come along who
needs more fine grained control over the clocks, but this guy is then
able to justify *why* more control is needed.

This is not about getting a full featured driver into mainline. Get
a basic driver into mainline and improve it later. You'll make it
easier for us all.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH 0/2] powerpc/iommu: check dev->iommu_group before remove it
From: Wei Yang @ 2013-08-16 10:08 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel; +Cc: aik, paulus, benh, Wei Yang

Had a talk with Alexey, who suggest me to send this for comments.

On powernv platform, the P7IOC provide limited range of DMA space. For
example, there are only 8 DMA segments on each PHB. When there are more 
than 8 PEs, some of PE's tce32_table is not initialized.

In the normal case, 8 PE is enough. If VF is enabled, 8 is not enough. This
lead to some pci_dev's iommu_table_base is NULL. Which results this device
couldn't be added to any iommu_group, and finally dev->iommu_group is left NULL.
When this VF is removed from the system, this will case kernel crash.

These two patches add the check to guard the kernel. Comments are welcome for
which place is better.

One more comment from Alexey is where we allow these non-DMA capable device
exist in the system. Maybe we should not allow to create a pci_dev for those
who can't get proper DMA space. Your comments are welcome :-)

Thanks in advance.

Wei Yang (2):
  iommu: Don't remove device when no iommu_group associated
  powerpc/iommu: check dev->iommu_group before remove a device from
    iommu_group

 arch/powerpc/kernel/iommu.c |    3 ++-
 drivers/iommu/iommu.c       |    3 +++
 2 files changed, 5 insertions(+), 1 deletions(-)

-- 
1.7.5.4

^ permalink raw reply

* [PATCH 1/2] iommu: Don't remove device when no iommu_group associated
From: Wei Yang @ 2013-08-16 10:08 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel; +Cc: aik, paulus, benh, Wei Yang
In-Reply-To: <1376647687-20550-1-git-send-email-weiyang@linux.vnet.ibm.com>

In some cases, one device may not associated with any iommu_group.
For example, not enough DMA address space.

For those devices, kernel will crash when try to remove it from an iommu_group.

This patch do the check before remove it.

Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
---
 drivers/iommu/iommu.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index fbe9ca7..fe41946 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -379,6 +379,9 @@ void iommu_group_remove_device(struct device *dev)
 	struct iommu_group *group = dev->iommu_group;
 	struct iommu_device *tmp_device, *device = NULL;
 
+	if (!group)
+		return;
+
 	/* Pre-notify listeners that a device is being removed. */
 	blocking_notifier_call_chain(&group->notifier,
 				     IOMMU_GROUP_NOTIFY_DEL_DEVICE, dev);
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 2/2] powerpc/iommu: check dev->iommu_group before remove a device from iommu_group
From: Wei Yang @ 2013-08-16 10:08 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel; +Cc: aik, paulus, benh, Wei Yang
In-Reply-To: <1376647687-20550-1-git-send-email-weiyang@linux.vnet.ibm.com>

---
 arch/powerpc/kernel/iommu.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index b20ff17..5abf7c3 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -1149,7 +1149,8 @@ static int iommu_bus_notifier(struct notifier_block *nb,
 	case BUS_NOTIFY_ADD_DEVICE:
 		return iommu_add_device(dev);
 	case BUS_NOTIFY_DEL_DEVICE:
-		iommu_del_device(dev);
+		if (dev->iommu_group)
+			iommu_del_device(dev);
 		return 0;
 	default:
 		return 0;
-- 
1.7.5.4

^ permalink raw reply related

* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Nicolin Chen @ 2013-08-16  9:53 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
	pawel.moll, swarren, festevam, Tomasz Figa, rob.herring, timur,
	broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816085632.GO26614@pengutronix.de>

On Fri, Aug 16, 2013 at 10:56:32AM +0200, Sascha Hauer wrote:
> > "tx<0-8>"	Optional	Tx clock source for spdif playback.
> > 				If absent, will use core clock.
> > 				The index from 0 to 8 is identical
> > 				to the clock source list described
> > 				in TxClk_Source bit of register STC.
> > 				Multiple clock source are allowed
> > 				for this tx clock source. The driver
> > 				will select one source from them for
> > 				each supported sample rate according
> > 				to the clock rates of these provided
> > 				clock sources.
> 
> You mean tx<0-7>

Yes. Thank you.

> Also I would make this option required. Use a dummy clock for mux inputs
> that are grounded for a specific SoC.

Some clocks are not from CCM and we haven't defined in imx6q-clk.txt,
so in most cases we can't provide a phandle for them, eg: spdif_ext.
I think it's a bit hard to force it to be 'required'. An 'optional'
looks more flexible to me and a default one is ensured even if it's
missing.

> > "rx<0-16>"	Optional	Rx clock source for spdif record.
> > 				If absent, will use core clock.
> > 				The index from 0 to 16 is identical
> > 				to the clock source list described
> > 				in ClkSrc_Sel bit of register SRPC.
> > 				If the index provided contains an
> > 				"if (DPLL Locked)" condition in its
> > 				source, the correspond clock phandle
> > 				should be the one in "else" path.
> > 				Only one rx clock source should be
> > 				defined here.
> 
> Again, describe the input clocks *to* *the* *S/PDIF* *core* in the
> devicetree. Nothing more, nothing less. We've already been at the point
> where we realized that half of the above clocks only describe the
> 'PDLL locked' condition. Also the tx clocks are from what I see identical
> to the rx clocks. The following are the clocks:
> 
> clock-names: "core", "rxtx<0-7>" Required. The S/PDIF core has a core
> clock and 8 clocks which are muxed internally to provide input/output
> sample clocks.

I know the reason why you suggest to combine two into 'rxtx<0-7>'
is because the clock mux is defined so. And the previous suggestion
'the option required' is also because of it. But actually the rxclk 
itself, can be not only routed from the clock mux but also derived
from DPLL of SPDIF Rx BLOCK as well. So, IMHO, it's more likely to
be a fact that rxclk actually has 9 clock source, 8 from mux and
1 from DPLL. But why we here have to exclude it?


WELL anyway, I know my opinion might not be concerned so much. So
I would like to follow the suggestion as an expediency because I
still wish this patch could be finally applied and merged into
mainline :(

But I still don't get why we need to be so obsessed to make this
impenetrable rule of devicetree that we here have to sacrifice
something we could have reasonably done.

And thank you for the comments again, Sascha.
Nicolin Chen

^ permalink raw reply

* Re: [RFC PATCH 2/4] openrisc: remove undefined of_get_cpu_node declaration
From: Sudeep KarkadaNagesha @ 2013-08-16  9:41 UTC (permalink / raw)
  To: Jonas Bonn
  Cc: devicetree@vger.kernel.org, Michal Simek,
	linux-pm@vger.kernel.org, Sudeep KarkadaNagesha,
	linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
	Rafael J. Wysocki, grant.likely@linaro.org,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1376586580-5409-3-git-send-email-Sudeep.KarkadaNagesha@arm.com>

On 15/08/13 18:09, Sudeep KarkadaNagesha wrote:
> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>=20
> This patch removes the declaration of the function 'of_get_cpu_node'
> which is not defined for openrisc. This is in preparation to move
> it's definition from PPC to DT common code.
>=20
> Again it could be there as it was originally copied from powerpc.
>=20
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
> Cc: Jonas Bonn <jonas@southpole.se>
Hi Jonas,

Since both microblaze and openrisc have moderated lists which I am not
member of, these patches were blocked. Michal Simek agreed to remove
this for microblaze. Do you see any concern with this patch for openrisc
? Can I have you ACK if it looks fine ?

Regards,
Sudeep
> ---
>  arch/openrisc/include/asm/prom.h | 3 ---
>  1 file changed, 3 deletions(-)
>=20
> diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm=
/prom.h
> index bbb34e5..eb59bfe 100644
> --- a/arch/openrisc/include/asm/prom.h
> +++ b/arch/openrisc/include/asm/prom.h
> @@ -44,9 +44,6 @@ void of_parse_dma_window(struct device_node *dn, const =
void *dma_window_prop,
> =20
>  extern void kdump_move_device_tree(void);
> =20
> -/* CPU OF node matching */
> -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
> -
>  /* Get the MAC address */
>  extern const void *of_get_mac_address(struct device_node *np);
> =20
>=20

^ permalink raw reply

* Re: [RFC PATCH v2 02/10] powerpc/book3s: Introduce exclusive emergency stack for machine check exception.
From: Mahesh Jagannath Salgaonkar @ 2013-08-16  9:05 UTC (permalink / raw)
  To: Madhavan Srinivasan
  Cc: linuxppc-dev, Paul Mackerras, Jeremy Kerr, Anton Blanchard
In-Reply-To: <520DE9D4.5050402@linux.vnet.ibm.com>

On 08/16/2013 02:29 PM, Madhavan Srinivasan wrote:
> On Friday 16 August 2013 01:34 PM, Mahesh J Salgaonkar wrote:
>> From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
>>
>> This patch introduces exclusive emergency stack for machine check exception.
>> We use emergency stack to handle machine check exception so that we can save
>> MCE information (srr1, srr0, dar and dsisr) before turning on ME bit and be
>> ready for re-entrancy. This helps us to prevent clobbering of MCE information
>> in case of nested machine checks.
>>
>> The reason for using emergency stack over normal kernel stack is that the
>> machine check might occur in the middle of setting up a stack frame which may
>> result into improper use of kernel stack.
>>
>> Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
>> ---
>>  arch/powerpc/include/asm/paca.h |    9 +++++++++
>>  arch/powerpc/kernel/setup_64.c  |    8 +++++++-
>>  arch/powerpc/xmon/xmon.c        |    2 ++
>>  3 files changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
>> index 77c91e7..b4ca4e9 100644
>> --- a/arch/powerpc/include/asm/paca.h
>> +++ b/arch/powerpc/include/asm/paca.h
>> @@ -147,6 +147,15 @@ struct paca_struct {
>>  	 */
>>  	struct opal_machine_check_event *opal_mc_evt;
>>  #endif
>> +#ifdef CONFIG_PPC_BOOK3S_64
>> +	/* Exclusive emergency stack pointer for machine check exception. */
>> +	void *mc_emergency_sp;
>> +	/*
>> +	 * Flag to check whether we are in machine check early handler
>> +	 * and already using emergency stack.
>> +	 */
>> +	u16 in_mce;
>> +#endif
>>
>>  	/* Stuff for accurate time accounting */
>>  	u64 user_time;			/* accumulated usermode TB ticks */
>> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
>> index 389fb807..3fdbdb0 100644
>> --- a/arch/powerpc/kernel/setup_64.c
>> +++ b/arch/powerpc/kernel/setup_64.c
>> @@ -529,7 +529,8 @@ static void __init exc_lvl_early_init(void)
>>
>>  /*
>>   * Stack space used when we detect a bad kernel stack pointer, and
>> - * early in SMP boots before relocation is enabled.
>> + * early in SMP boots before relocation is enabled. Exclusive emergency
>> + * stack for machine checks.
>>   */
>>  static void __init emergency_stack_init(void)
>>  {
>> @@ -552,6 +553,11 @@ static void __init emergency_stack_init(void)
>>  		sp  = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
>>  		sp += THREAD_SIZE;
>>  		paca[i].emergency_sp = __va(sp);
>> +
>> +		/* emergency stack for machine check exception handling. */
>> +		sp  = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
>> +		sp += THREAD_SIZE;
>> +		paca[i].mc_emergency_sp = __va(sp);
>>  	}
>>  }
>>
> Just a concern, kindly ignore it if it is irrelevant.
> you have defined mc_emergency_sp under CONFIG_PPC_BOOK3S_64, but
> assigning memory in a common code. This may break build for other
> configs such as like ppc64e_defconfig.

Nice catch. Will fix it in next spin.

Thanks,
-Mahesh.

^ permalink raw reply

* Re: [RFC PATCH v2 02/10] powerpc/book3s: Introduce exclusive emergency stack for machine check exception.
From: Madhavan Srinivasan @ 2013-08-16  8:59 UTC (permalink / raw)
  To: Mahesh J Salgaonkar
  Cc: linuxppc-dev, Paul Mackerras, Jeremy Kerr, Anton Blanchard
In-Reply-To: <20130816080410.680.46919.stgit@mars.in.ibm.com>

On Friday 16 August 2013 01:34 PM, Mahesh J Salgaonkar wrote:
> From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
> 
> This patch introduces exclusive emergency stack for machine check exception.
> We use emergency stack to handle machine check exception so that we can save
> MCE information (srr1, srr0, dar and dsisr) before turning on ME bit and be
> ready for re-entrancy. This helps us to prevent clobbering of MCE information
> in case of nested machine checks.
> 
> The reason for using emergency stack over normal kernel stack is that the
> machine check might occur in the middle of setting up a stack frame which may
> result into improper use of kernel stack.
> 
> Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
> ---
>  arch/powerpc/include/asm/paca.h |    9 +++++++++
>  arch/powerpc/kernel/setup_64.c  |    8 +++++++-
>  arch/powerpc/xmon/xmon.c        |    2 ++
>  3 files changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index 77c91e7..b4ca4e9 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -147,6 +147,15 @@ struct paca_struct {
>  	 */
>  	struct opal_machine_check_event *opal_mc_evt;
>  #endif
> +#ifdef CONFIG_PPC_BOOK3S_64
> +	/* Exclusive emergency stack pointer for machine check exception. */
> +	void *mc_emergency_sp;
> +	/*
> +	 * Flag to check whether we are in machine check early handler
> +	 * and already using emergency stack.
> +	 */
> +	u16 in_mce;
> +#endif
> 
>  	/* Stuff for accurate time accounting */
>  	u64 user_time;			/* accumulated usermode TB ticks */
> diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
> index 389fb807..3fdbdb0 100644
> --- a/arch/powerpc/kernel/setup_64.c
> +++ b/arch/powerpc/kernel/setup_64.c
> @@ -529,7 +529,8 @@ static void __init exc_lvl_early_init(void)
> 
>  /*
>   * Stack space used when we detect a bad kernel stack pointer, and
> - * early in SMP boots before relocation is enabled.
> + * early in SMP boots before relocation is enabled. Exclusive emergency
> + * stack for machine checks.
>   */
>  static void __init emergency_stack_init(void)
>  {
> @@ -552,6 +553,11 @@ static void __init emergency_stack_init(void)
>  		sp  = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
>  		sp += THREAD_SIZE;
>  		paca[i].emergency_sp = __va(sp);
> +
> +		/* emergency stack for machine check exception handling. */
> +		sp  = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
> +		sp += THREAD_SIZE;
> +		paca[i].mc_emergency_sp = __va(sp);
>  	}
>  }
> 
Just a concern, kindly ignore it if it is irrelevant.
you have defined mc_emergency_sp under CONFIG_PPC_BOOK3S_64, but
assigning memory in a common code. This may break build for other
configs such as like ppc64e_defconfig.

> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
> index 96bf5bd..147a5e98 100644
> --- a/arch/powerpc/xmon/xmon.c
> +++ b/arch/powerpc/xmon/xmon.c
> @@ -2044,6 +2044,8 @@ static void dump_one_paca(int cpu)
>  	DUMP(p, stab_addr, "lx");
>  #endif
>  	DUMP(p, emergency_sp, "p");
> +	DUMP(p, mc_emergency_sp, "p");
> +	DUMP(p, in_mce, "x");
>  	DUMP(p, data_offset, "lx");
>  	DUMP(p, hw_cpu_id, "x");
>  	DUMP(p, cpu_start, "x");
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 

^ permalink raw reply

* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Sascha Hauer @ 2013-08-16  8:56 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: mark.rutland, devicetree, alsa-devel, lars, ian.campbell,
	pawel.moll, swarren, festevam, Tomasz Figa, rob.herring, timur,
	broonie, p.zabel, galak, shawn.guo, linuxppc-dev
In-Reply-To: <20130816080124.GE1846@MrMyself>

On Fri, Aug 16, 2013 at 04:01:25PM +0800, Nicolin Chen wrote:
> Hi Sascha,
> 
>    Thank you for the detailed comments.
> 
> On Fri, Aug 16, 2013 at 09:08:18AM +0200, Sascha Hauer wrote:
> > Which of them the driver should use is configuration and thus normally
> > should *not* be described in the devicetree. However, there may be no
> > good way for the driver to know which clock to use in which case. There
> > may be additional board requirements which are unknown to the driver. So
> > in this case it might be valid to put the information which clock to use
> > into the devicetree. But be aware that from the moment you put this
> > information into the devicetree the driver is no longer free to chose
> > the best clock, even if in future we find a good way to automatically
> > guess the best clock. Do you have some insights in which case I would
> > use which input clock? Is this only about which clock has the best
> > suitable input frequency or is this also about synchronization of the
> > audio signal with some other unit?
> 
> I understand. What I'm thinking now is to let the driver find the best
> clock source for tx clock and a correspond divisor like this:
> 
> "tx<0-8>"	Optional	Tx clock source for spdif playback.
> 				If absent, will use core clock.
> 				The index from 0 to 8 is identical
> 				to the clock source list described
> 				in TxClk_Source bit of register STC.
> 				Multiple clock source are allowed
> 				for this tx clock source. The driver
> 				will select one source from them for
> 				each supported sample rate according
> 				to the clock rates of these provided
> 				clock sources.

You mean tx<0-7>.

Also I would make this option required. Use a dummy clock for mux inputs
that are grounded for a specific SoC.

> 
> Please review this idea.
> 
> 
> And likewise for rx:
> 
> "rx<0-16>"	Optional	Rx clock source for spdif record.
> 				If absent, will use core clock.
> 				The index from 0 to 16 is identical
> 				to the clock source list described
> 				in ClkSrc_Sel bit of register SRPC.
> 				If the index provided contains an
> 				"if (DPLL Locked)" condition in its
> 				source, the correspond clock phandle
> 				should be the one in "else" path.
> 				Only one rx clock source should be
> 				defined here.

Again, describe the input clocks *to* *the* *S/PDIF* *core* in the
devicetree. Nothing more, nothing less. We've already been at the point
where we realized that half of the above clocks only describe the
'PDLL locked' condition. Also the tx clocks are from what I see identical
to the rx clocks. The following are the clocks:

clock-names: "core", "rxtx<0-7>" Required. The S/PDIF core has a core
clock and 8 clocks which are muxed internally to provide input/output
sample clocks.

This is all binding that is needed for now.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* Re: [RFC PATCH 3/4] powerpc: refactor of_get_cpu_node to support other architectures
From: Sudeep KarkadaNagesha @ 2013-08-16  8:48 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Jonas Bonn, devicetree@vger.kernel.org, Michal Simek,
	linux-pm@vger.kernel.org, Sudeep KarkadaNagesha,
	microblaze-uclinux@itee.uq.edu.au, linux@openrisc.net,
	linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
	Rafael J. Wysocki, grant.likely@linaro.org,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1376628563.4255.137.camel@pasglop>

On 16/08/13 05:49, Benjamin Herrenschmidt wrote:
> On Thu, 2013-08-15 at 18:09 +0100, Sudeep KarkadaNagesha wrote:
>> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>>
>> Currently different drivers requiring to access cpu device node are
>> parsing the device tree themselves. Since the ordering in the DT need
>> not match the logical cpu ordering, the parsing logic needs to consider
>> that. However, this has resulted in lots of code duplication and in some
>> cases even incorrect logic.
>=20
>  .../...
>=20
>> =20
>> +bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
>> +{
>> +=09return (int)phys_id =3D=3D get_hard_smp_processor_id(cpu);
>> +}
>=20
> Naming is a bit gross. You might want to make it clearer that
> we are talking about CPU IDs in the device-tree here.
>=20
Any particular preference to the name or just a note is sufficient.
Also unlike PPC, in ARM we don't set hard processor id value based
values read from device tree. DT must contain the values matching to the
hardware ID registers.

>> +static bool __of_find_n_match_cpu_property(struct device_node *cpun,
>> +=09=09=09const char *prop_name, int cpu, unsigned int *thread)
>> +{
>> +=09const __be32 *cell;
>> +=09int ac, prop_len, tid;
>> +=09u64 hwid;
>> +
>> +=09ac =3D of_n_addr_cells(cpun);
>> +=09cell =3D of_get_property(cpun, prop_name, &prop_len);
>> +=09if (!cell)
>> +=09=09return false;
>> +=09prop_len /=3D sizeof(*cell);
>> +=09for (tid =3D 0; tid < prop_len; tid++) {
>> +=09=09hwid =3D of_read_number(cell, ac);
>> +=09=09if (arch_match_cpu_phys_id(cpu, hwid)) {
>> +=09=09=09if (thread)
>> +=09=09=09=09*thread =3D tid;
>> +=09=09=09return true;
>> +=09=09}
>=20
> Missing:          cell +=3D ac;
Ah, missed it while refactoring, will fix it. Thanks

Regards,
Sudeep

^ permalink raw reply

* Re: [RFC PATCH 3/4] powerpc: refactor of_get_cpu_node to support other architectures
From: Sudeep KarkadaNagesha @ 2013-08-16  8:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Jonas Bonn, devicetree@vger.kernel.org, Michal Simek,
	linux-pm@vger.kernel.org, Sudeep KarkadaNagesha,
	microblaze-uclinux@itee.uq.edu.au, linux@openrisc.net,
	linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
	Rafael J. Wysocki, grant.likely@linaro.org,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <1376628601.4255.138.camel@pasglop>

On 16/08/13 05:50, Benjamin Herrenschmidt wrote:
> On Thu, 2013-08-15 at 18:09 +0100, Sudeep KarkadaNagesha wrote:
>>                /* Check for ibm,ppc-interrupt-server#s. If it doesn't ex=
ist
>>                  * fallback to "reg" property and assume no threads
>>                  */
>> -
>=20
> Oh and I forgot ... that comment is now wrong, since your code handles
> threads in the "reg" case...
>=20
I have fixed it in the next patch while adding the documentation to
these function. I wanted changes in this patch minimal. I can fix it
here too if you insist on it.

Regards,
Sudeep

^ permalink raw reply

* [PATCH 2/2] powerpc/85xx: add hardware automatically enter pw20 state
From: Dongsheng Wang @ 2013-08-16  7:23 UTC (permalink / raw)
  To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng
In-Reply-To: <1376637789-27330-1-git-send-email-dongsheng.wang@freescale.com>

From: Wang Dongsheng <dongsheng.wang@freescale.com>

Using hardware features make core automatically enter PW20 state.
Set a TB count to hardware, the effective count begins when PW10
is entered. When the effective period has expired, the core will
proceed from PW10 to PW20 if no exit conditions have occurred during
the period.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>

diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index c047e08..3c81a88 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -219,6 +219,7 @@
 
 /* Bit definitions for PWRMGTCR0. */
 #define PWRMGTCR0_ALTIVEC_IDLE	(1 << 22) /* Altivec idle enable */
+#define PWRMGTCR0_PW20_WAIT	(1 << 14) /* PW20 state enable bit */
 
 /* Bit definitions for the MCSR. */
 #define MCSR_MCS	0x80000000 /* Machine Check Summary */
diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
index dbbbc24..a208d52 100644
--- a/arch/powerpc/platforms/85xx/common.c
+++ b/arch/powerpc/platforms/85xx/common.c
@@ -17,12 +17,22 @@
 
 #define ALTIVEC_COUNT_OFFSET		16
 #define ALTIVEC_IDLE_COUNT_MASK		0x003f0000
+#define PW20_COUNT_OFFSET		8
+#define PW20_IDLE_COUNT_MASK		0x00003f00
 
 /*
  * FIXME - We don't know the AltiVec application scenarios.
  */
 #define ALTIVEC_IDLE_TIME	1000 /* 1ms */
 
+/*
+ * FIXME - We don't know, what time should we let the core into PW20 state.
+ * because we don't know the current state of the cpu load. And threads are
+ * independent, so we can not know the state of different thread has been
+ * idle.
+ */
+#define	PW20_IDLE_TIME		1000 /* 1ms */
+
 static struct of_device_id __initdata mpc85xx_common_ids[] = {
 	{ .type = "soc", },
 	{ .compatible = "soc", },
@@ -145,9 +155,33 @@ static void setup_altivec_idle(void *unused)
 	mtspr(SPRN_PWRMGTCR0, altivec_idle);
 }
 
+static void setup_pw20_idle(void *unused)
+{
+	u32 pw20_idle, bit;
+
+	if (!has_pw20_altivec_idle())
+		return;
+
+	pw20_idle = mfspr(SPRN_PWRMGTCR0);
+
+	/* set PW20_WAIT bit, enable pw20 */
+	pw20_idle |= PWRMGTCR0_PW20_WAIT;
+
+	/* Set Automatic PW20 Core Idle Count */
+	/* clear count */
+	pw20_idle &= ~PW20_IDLE_COUNT_MASK;
+
+	/* set count */
+	bit = get_idle_ticks_bit(PW20_IDLE_TIME);
+	pw20_idle |= ((MAX_BIT - bit) << PW20_COUNT_OFFSET);
+
+	mtspr(SPRN_PWRMGTCR0, pw20_idle);
+}
+
 static int __init setup_idle_hw_governor(void)
 {
 	on_each_cpu(setup_altivec_idle, NULL, 1);
+	on_each_cpu(setup_pw20_idle, NULL, 1);
 
 	return 0;
 }
-- 
1.8.0

^ permalink raw reply related

* [PATCH 1/2] powerpc/85xx: add hardware automatically enter altivec idle state
From: Dongsheng Wang @ 2013-08-16  7:23 UTC (permalink / raw)
  To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng

From: Wang Dongsheng <dongsheng.wang@freescale.com>

Each core's AltiVec unit may be placed into a power savings mode
by turning off power to the unit. Core hardware will automatically
power down the AltiVec unit after no AltiVec instructions have
executed in N cycles. The AltiVec power-control is triggered by hardware.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 5d7d9c2..5c7a7ba 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1053,6 +1053,8 @@
 #define PVR_8560	0x80200000
 #define PVR_VER_E500V1	0x8020
 #define PVR_VER_E500V2	0x8021
+#define PVR_VER_E6500	0x8040
+
 /*
  * For the 8xx processors, all of them report the same PVR family for
  * the PowerPC core. The various versions of these processors must be
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index b417de3..c047e08 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -170,6 +170,7 @@
 #define SPRN_L2CSR1	0x3FA	/* L2 Data Cache Control and Status Register 1 */
 #define SPRN_DCCR	0x3FA	/* Data Cache Cacheability Register */
 #define SPRN_ICCR	0x3FB	/* Instruction Cache Cacheability Register */
+#define SPRN_PWRMGTCR0	0x3FB	/* Power management control register 0 */
 #define SPRN_SVR	0x3FF	/* System Version Register */
 
 /*
@@ -216,6 +217,9 @@
 #define	CCR1_DPC	0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
 #define	CCR1_TCS	0x00000080 /* Timer Clock Select */
 
+/* Bit definitions for PWRMGTCR0. */
+#define PWRMGTCR0_ALTIVEC_IDLE	(1 << 22) /* Altivec idle enable */
+
 /* Bit definitions for the MCSR. */
 #define MCSR_MCS	0x80000000 /* Machine Check Summary */
 #define MCSR_IB		0x40000000 /* Instruction PLB Error */
diff --git a/arch/powerpc/platforms/85xx/common.c b/arch/powerpc/platforms/85xx/common.c
index d0861a0..dbbbc24 100644
--- a/arch/powerpc/platforms/85xx/common.c
+++ b/arch/powerpc/platforms/85xx/common.c
@@ -7,10 +7,22 @@
  */
 #include <linux/of_platform.h>
 
+#include <asm/time.h>
+
 #include <sysdev/cpm2_pic.h>
 
 #include "mpc85xx.h"
 
+#define MAX_BIT				64
+
+#define ALTIVEC_COUNT_OFFSET		16
+#define ALTIVEC_IDLE_COUNT_MASK		0x003f0000
+
+/*
+ * FIXME - We don't know the AltiVec application scenarios.
+ */
+#define ALTIVEC_IDLE_TIME	1000 /* 1ms */
+
 static struct of_device_id __initdata mpc85xx_common_ids[] = {
 	{ .type = "soc", },
 	{ .compatible = "soc", },
@@ -80,3 +92,63 @@ void __init mpc85xx_cpm2_pic_init(void)
 	irq_set_chained_handler(irq, cpm2_cascade);
 }
 #endif
+
+static bool has_pw20_altivec_idle(void)
+{
+	u32 pvr;
+
+	pvr = mfspr(SPRN_PVR);
+
+	/* PW20 & AltiVec idle feature only exists for E6500 */
+	if (PVR_VER(pvr) != PVR_VER_E6500)
+		return false;
+
+	/* Fix erratum, e6500 rev1 does not support PW20 & AltiVec idle */
+	if (PVR_REV(pvr) < 0x20)
+		return false;
+
+	return true;
+}
+
+static unsigned int get_idle_ticks_bit(unsigned int us)
+{
+	unsigned int cycle;
+
+	/*
+	 * The time control by TB turn over bit, so we need
+	 * to be divided by 2.
+	 */
+	cycle = (us / 2) * tb_ticks_per_usec;
+
+	return ilog2(cycle) + 1;
+}
+
+static void setup_altivec_idle(void *unused)
+{
+	u32 altivec_idle, bit;
+
+	if (!has_pw20_altivec_idle())
+		return;
+
+	/* Enable Altivec Idle */
+	altivec_idle = mfspr(SPRN_PWRMGTCR0);
+	altivec_idle |= PWRMGTCR0_ALTIVEC_IDLE;
+
+	/* Set Automatic AltiVec Idle Count */
+	/* clear count */
+	altivec_idle &= ~ALTIVEC_IDLE_COUNT_MASK;
+
+	/* set count */
+	bit = get_idle_ticks_bit(ALTIVEC_IDLE_TIME);
+	altivec_idle |= ((MAX_BIT - bit) << ALTIVEC_COUNT_OFFSET);
+
+	mtspr(SPRN_PWRMGTCR0, altivec_idle);
+}
+
+static int __init setup_idle_hw_governor(void)
+{
+	on_each_cpu(setup_altivec_idle, NULL, 1);
+
+	return 0;
+}
+late_initcall(setup_idle_hw_governor);
-- 
1.8.0

^ permalink raw reply related

* [RFC PATCH v2 10/10] powerpc/powernv: Machine check exception handling.
From: Mahesh J Salgaonkar @ 2013-08-16  8:05 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

Add basic error handling in machine check exception handler.

- If MSR_RI isn't set, we can not recover.
- Check if disposition set to OpalMCE_DISPOSITION_RECOVERED.
- Check if address at fault is inside kernel address space, if not then send
  SIGBUS to process if we hit exception when in userspace.
- If address at fault is not provided then and if we get a synchronous machine
  check while in userspace then kill the task.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/mce.h        |    1 +
 arch/powerpc/kernel/mce.c             |   27 +++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal.c |   43 ++++++++++++++++++++++++++++++++-
 3 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index d319161..3ff1208 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -190,5 +190,6 @@ extern void save_mce_event(struct pt_regs *regs, long handled,
 			   struct mce_error_info *mce_err, uint64_t addr);
 extern int get_mce_event(struct machine_check_event *mce, bool release);
 extern void release_mce_event(void);
+extern uint64_t get_mce_fault_addr(struct machine_check_event *evt);
 
 #endif /* __ASM_PPC64_MCE_H__ */
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index aeecdf1..659778e 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -162,3 +162,30 @@ void release_mce_event(void)
 {
 	get_mce_event(NULL, true);
 }
+
+uint64_t get_mce_fault_addr(struct machine_check_event *evt)
+{
+	switch (evt->error_type) {
+	case MCE_ERROR_TYPE_UE:
+		if (evt->u.ue_error.effective_address_provided)
+			return evt->u.ue_error.effective_address;
+		break;
+	case MCE_ERROR_TYPE_SLB:
+		if (evt->u.slb_error.effective_address_provided)
+			return evt->u.slb_error.effective_address;
+		break;
+	case MCE_ERROR_TYPE_ERAT:
+		if (evt->u.erat_error.effective_address_provided)
+			return evt->u.erat_error.effective_address;
+		break;
+	case MCE_ERROR_TYPE_TLB:
+		if (evt->u.tlb_error.effective_address_provided)
+			return evt->u.tlb_error.effective_address;
+		break;
+	default:
+	case MCE_ERROR_TYPE_UNKNOWN:
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(get_mce_fault_addr);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 8545b33..7af3b12 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include <asm/opal.h>
 #include <asm/firmware.h>
 #include <asm/mce.h>
@@ -240,6 +241,44 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
 	return written;
 }
 
+static int opal_recover_mce(struct pt_regs *regs,
+					struct machine_check_event *evt)
+{
+	int recovered = 0;
+	uint64_t ea = get_mce_fault_addr(evt);
+
+	if (!(regs->msr & MSR_RI)) {
+		/* If MSR_RI isn't set, we cannot recover */
+		recovered = 0;
+	} else if (evt->disposition == MCE_DISPOSITION_RECOVERED) {
+		/* Platform corrected itself */
+		recovered = 1;
+	} else if (ea && !is_kernel_addr(ea)) {
+		/*
+		 * Faulting address is not in kernel text. We should be fine.
+		 * We need to find which process uses this address.
+		 * For now, kill the task if we have received exception when
+		 * in userspace.
+		 *
+		 * TODO: Queue up this address for hwpoisioning later.
+		 */
+		if (user_mode(regs) && !is_global_init(current)) {
+			_exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
+			recovered = 1;
+		} else
+			recovered = 0;
+	} else if (user_mode(regs) && !is_global_init(current) &&
+		evt->severity == MCE_SEV_ERROR_SYNC) {
+		/*
+		 * If we have received a synchronous error when in userspace
+		 * kill the task.
+		 */
+		_exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
+		recovered = 1;
+	}
+	return recovered;
+}
+
 int opal_machine_check(struct pt_regs *regs)
 {
 	struct machine_check_event evt;
@@ -350,7 +389,9 @@ int opal_machine_check(struct pt_regs *regs)
 		printk("%s  Error type: Unknown\n", level);
 		break;
 	}
-	return evt.severity == MCE_SEV_FATAL ? 0 : 1;
+	if (opal_recover_mce(regs, &evt))
+		return 1;
+	return 0;
 }
 
 static irqreturn_t opal_interrupt(int irq, void *data)

^ permalink raw reply related

* [RFC PATCH v2 09/10] powerpc/powernv: Remove machine check handling in OPAL.
From: Mahesh J Salgaonkar @ 2013-08-16  8:05 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

Now that we are ready to handle machine check directly in linux, do not
register with firmware to handle machine check exception.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/opal.c |    8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index bcbbcdc..8545b33 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -83,14 +83,10 @@ static int __init opal_register_exception_handlers(void)
 	if (!(powerpc_firmware_features & FW_FEATURE_OPAL))
 		return -ENODEV;
 
-	/* Hookup some exception handlers. We use the fwnmi area at 0x7000
-	 * to provide the glue space to OPAL
+	/* Hookup some exception handlers except machine check. We use the
+	 * fwnmi area at 0x7000 to provide the glue space to OPAL
 	 */
 	glue = 0x7000;
-	opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER,
-					__pa(opal_mc_secondary_handler[0]),
-					glue);
-	glue += 128;
 	opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER,
 					0, glue);
 	glue += 128;

^ permalink raw reply related

* [RFC PATCH v2 08/10] powerpc/book3s: Decode and save machine check event.
From: Mahesh J Salgaonkar @ 2013-08-16  8:05 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

Now that we handle machine check in linux, the MCE decoding should also
take place in linux host. This info is crucial to log before we go down
in case we can not handle the machine check errors. This patch decodes
and populates a machine check event which contain high level meaning full
MCE information.

We do this in real mode C code with ME bit on. The MCE information is still
available on emergency stack (in pt_regs structure format). Even if we take
another exception at this point the MCE early handler will allocate a new
stack frame on top of current one. So when we return back here we still have
our MCE information safe on current stack.

We use per cpu buffer to save high level MCE information. Each per cpu buffer
is an array of machine check event structure indexed by per cpu counter
mce_nest_count. The mce_nest_count is incremented every time we enter
machine check early handler in real mode to get the current free slot
(index = mce_nest_count - 1). The mce_nest_count is decremented once the
MCE info is consumed by virtual mode machine exception handler.

This patch provides save_mce_event(), get_mce_event() and release_mce_event()
generic routines that can be used by machine check handlers to populate and
retrieve the event. The routine release_mce_event() will free the event slot so
that it can be reused. Caller can invoke get_mce_event() with a release flag
either to release the event slot immediately OR keep it so that it can be
fetched again. The event slot can be also released anytime by invoking
release_mce_event().

This patch also updates kvm code to invoke get_mce_event to retrieve generic
mce event rather than paca->opal_mce_evt.

The KVM code always calls get_mce_event() with release flags set to false so
that event is available for linus host machine

If machine check occurs while we are in guest, KVM tries to handle the error.
If KVM is able to handle MC error successfully, it enters the guest and
delivers the machine check to guest. If KVM is not able to handle MC error, it
exists the guest and passes the control to linux host machine check handler
which then logs MC event and decides how to handle it in linux host. In failure
case, KVM needs to make sure that the MC event is available for linux host to
consume. Hence KVM always calls get_mce_event() with release flags set to false
and later it invokes release_mce_event() only if it succeeds to handle error.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/mce.h        |  124 +++++++++++++++++++++++++
 arch/powerpc/kernel/Makefile          |    2 
 arch/powerpc/kernel/mce.c             |  164 +++++++++++++++++++++++++++++++++
 arch/powerpc/kernel/mce_power.c       |  116 ++++++++++++++++++++++-
 arch/powerpc/kvm/book3s_hv_ras.c      |   32 ++++--
 arch/powerpc/platforms/powernv/opal.c |   35 +++----
 6 files changed, 434 insertions(+), 39 deletions(-)
 create mode 100644 arch/powerpc/kernel/mce.c

diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 6866062..d319161 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -66,5 +66,129 @@
 
 #define P8_DSISR_MC_SLB_ERRORS		(P7_DSISR_MC_SLB_ERRORS | \
 					 P8_DSISR_MC_ERAT_MULTIHIT_SEC)
+enum MCE_Version {
+	MCE_V1 = 1,
+};
+
+enum MCE_Severity {
+	MCE_SEV_NO_ERROR = 0,
+	MCE_SEV_WARNING = 1,
+	MCE_SEV_ERROR_SYNC = 2,
+	MCE_SEV_FATAL = 3,
+};
+
+enum MCE_Disposition {
+	MCE_DISPOSITION_RECOVERED = 0,
+	MCE_DISPOSITION_NOT_RECOVERED = 1,
+};
+
+enum MCE_Initiator {
+	MCE_INITIATOR_UNKNOWN = 0,
+	MCE_INITIATOR_CPU = 1,
+};
+
+enum MCE_ErrorType {
+	MCE_ERROR_TYPE_UNKNOWN = 0,
+	MCE_ERROR_TYPE_UE = 1,
+	MCE_ERROR_TYPE_SLB = 2,
+	MCE_ERROR_TYPE_ERAT = 3,
+	MCE_ERROR_TYPE_TLB = 4,
+};
+
+enum MCE_UeErrorType {
+	MCE_UE_ERROR_INDETERMINATE = 0,
+	MCE_UE_ERROR_IFETCH = 1,
+	MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2,
+	MCE_UE_ERROR_LOAD_STORE = 3,
+	MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4,
+};
+
+enum MCE_SlbErrorType {
+	MCE_SLB_ERROR_INDETERMINATE = 0,
+	MCE_SLB_ERROR_PARITY = 1,
+	MCE_SLB_ERROR_MULTIHIT = 2,
+};
+
+enum MCE_EratErrorType {
+	MCE_ERAT_ERROR_INDETERMINATE = 0,
+	MCE_ERAT_ERROR_PARITY = 1,
+	MCE_ERAT_ERROR_MULTIHIT = 2,
+};
+
+enum MCE_TlbErrorType {
+	MCE_TLB_ERROR_INDETERMINATE = 0,
+	MCE_TLB_ERROR_PARITY = 1,
+	MCE_TLB_ERROR_MULTIHIT = 2,
+};
+
+struct machine_check_event {
+	enum MCE_Version	version:8;	/* 0x00 */
+	uint8_t			in_use;		/* 0x01 */
+	enum MCE_Severity	severity:8;	/* 0x02 */
+	enum MCE_Initiator	initiator:8;	/* 0x03 */
+	enum MCE_ErrorType	error_type:8;	/* 0x04 */
+	enum MCE_Disposition	disposition:8;	/* 0x05 */
+	uint8_t			reserved_1[2];	/* 0x06 */
+	uint64_t		gpr3;		/* 0x08 */
+	uint64_t		srr0;		/* 0x10 */
+	uint64_t		srr1;		/* 0x18 */
+	union {					/* 0x20 */
+		struct {
+			enum MCE_UeErrorType ue_error_type:8;
+			uint8_t		effective_address_provided;
+			uint8_t		physical_address_provided;
+			uint8_t		reserved_1[5];
+			uint64_t	effective_address;
+			uint64_t	physical_address;
+			uint8_t		reserved_2[8];
+		} ue_error;
+
+		struct {
+			enum MCE_SlbErrorType slb_error_type:8;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} slb_error;
+
+		struct {
+			enum MCE_EratErrorType erat_error_type:8;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} erat_error;
+
+		struct {
+			enum MCE_TlbErrorType tlb_error_type:8;
+			uint8_t		effective_address_provided;
+			uint8_t		reserved_1[6];
+			uint64_t	effective_address;
+			uint8_t		reserved_2[16];
+		} tlb_error;
+	} u;
+};
+
+struct mce_error_info {
+	enum MCE_ErrorType error_type:8;
+	union {
+		enum MCE_UeErrorType ue_error_type:8;
+		enum MCE_SlbErrorType slb_error_type:8;
+		enum MCE_EratErrorType erat_error_type:8;
+		enum MCE_TlbErrorType tlb_error_type:8;
+	} u;
+	uint8_t		reserved[2];
+};
+
+#define MAX_MC_EVT	100
+
+/* Release flags for get_mce_event() */
+#define MCE_EVENT_RELEASE	true
+#define MCE_EVENT_DONTRELEASE	false
+
+extern void save_mce_event(struct pt_regs *regs, long handled,
+			   struct mce_error_info *mce_err, uint64_t addr);
+extern int get_mce_event(struct machine_check_event *mce, bool release);
+extern void release_mce_event(void);
 
 #endif /* __ASM_PPC64_MCE_H__ */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index a1aba53..c3ae108 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_PPC64)		+= setup_64.o sys_ppc32.o \
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_power.o
-obj-$(CONFIG_PPC_BOOK3S_64)	+= mce_power.o
+obj-$(CONFIG_PPC_BOOK3S_64)	+= mce.o mce_power.o
 obj64-$(CONFIG_RELOCATABLE)	+= reloc_64.o
 obj-$(CONFIG_PPC_BOOK3E_64)	+= exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC_A2)		+= cpu_setup_a2.o
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
new file mode 100644
index 0000000..aeecdf1
--- /dev/null
+++ b/arch/powerpc/kernel/mce.c
@@ -0,0 +1,164 @@
+/*
+ * Machine check exception handling.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "mce: " fmt
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/percpu.h>
+#include <linux/export.h>
+#include <asm/mce.h>
+
+static DEFINE_PER_CPU(int, mce_nest_count);
+static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event);
+
+static void mce_set_error_info(struct machine_check_event *mce,
+			       struct mce_error_info *mce_err)
+{
+	mce->error_type = mce_err->error_type;
+	switch (mce_err->error_type) {
+	case MCE_ERROR_TYPE_UE:
+		mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type;
+		break;
+	case MCE_ERROR_TYPE_SLB:
+		mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type;
+		break;
+	case MCE_ERROR_TYPE_ERAT:
+		mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type;
+		break;
+	case MCE_ERROR_TYPE_TLB:
+		mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
+		break;
+	case MCE_ERROR_TYPE_UNKNOWN:
+	default:
+		break;
+	}
+}
+
+/*
+ * Decode and save high level MCE information into per cpu buffer which
+ * is an array of machine_check_event structure.
+ */
+void save_mce_event(struct pt_regs *regs, long handled,
+		    struct mce_error_info *mce_err,
+		    uint64_t addr)
+{
+	uint64_t srr1;
+	int index = __get_cpu_var(mce_nest_count)++;
+	struct machine_check_event *mce = &__get_cpu_var(mce_event[index]);
+
+	/*
+	 * Return if we don't have enough space to log mce event.
+	 * mce_nest_count may go beyond MAX_MC_EVT but that's ok,
+	 * the check below will stop buffer overrun.
+	 */
+	if (index >= MAX_MC_EVT)
+		return;
+
+	/* Populate generic machine check info */
+	mce->version = MCE_V1;
+	mce->srr0 = regs->nip;
+	mce->srr1 = regs->msr;
+	mce->gpr3 = regs->gpr[3];
+	mce->in_use = 1;
+
+	mce->initiator = MCE_INITIATOR_CPU;
+	if (handled)
+		mce->disposition = MCE_DISPOSITION_RECOVERED;
+	else
+		mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
+	mce->severity = MCE_SEV_ERROR_SYNC;
+
+	srr1 = regs->msr;
+
+	/*
+	 * Populate the mce error_type and type-specific error_type.
+	 */
+	mce_set_error_info(mce, mce_err);
+
+	if (!addr)
+		return;
+
+	if (mce->error_type == MCE_ERROR_TYPE_TLB) {
+		mce->u.tlb_error.effective_address_provided = true;
+		mce->u.tlb_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_SLB) {
+		mce->u.slb_error.effective_address_provided = true;
+		mce->u.slb_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
+		mce->u.erat_error.effective_address_provided = true;
+		mce->u.erat_error.effective_address = addr;
+	} else if (mce->error_type == MCE_ERROR_TYPE_UE) {
+		mce->u.ue_error.effective_address_provided = true;
+		mce->u.ue_error.effective_address = addr;
+	}
+	return;
+}
+
+/*
+ * get_mce_event:
+ *	mce	Pointer to machine_check_event structure to be filled.
+ *	release Flag to indicate whether to free the event slot or not.
+ *		0 <= do not release the mce event. Caller will invoke
+ *		     release_mce_event() once event has been consumed.
+ *		1 <= release the slot.
+ *
+ *	return	1 = success
+ *		0 = failure
+ *
+ * get_mce_event() will be called by platform specific machine check
+ * handle routine and in KVM.
+ * When we call get_mce_event(), we are still in interrupt context and
+ * preemption will not be scheduled until ret_from_expect() routine
+ * is called.
+ */
+int get_mce_event(struct machine_check_event *mce, bool release)
+{
+	int index = __get_cpu_var(mce_nest_count) - 1;
+	struct machine_check_event *mc_evt;
+	int ret = 0;
+
+	/* Sanity check */
+	if (index < 0)
+		return ret;
+
+	/* Check if we have MCE info to process. */
+	if (index < MAX_MC_EVT) {
+		mc_evt = &__get_cpu_var(mce_event[index]);
+		/* Copy the event structure and release the original */
+		if (mce)
+			*mce = *mc_evt;
+		if (release)
+			mc_evt->in_use = 0;
+		ret = 1;
+	}
+	/* Decrement the count to free the slot. */
+	if (release)
+		__get_cpu_var(mce_nest_count)--;
+
+	return ret;
+}
+
+void release_mce_event(void)
+{
+	get_mce_event(NULL, true);
+}
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 949d102..c153d9c 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -136,22 +136,116 @@ static long mce_handle_ierror_p7(uint64_t srr1)
 	return handled;
 }
 
+static void mce_get_common_ierror(struct mce_error_info *mce_err, uint64_t srr1)
+{
+	switch (P7_SRR1_MC_IFETCH(srr1)) {
+	case P7_SRR1_MC_IFETCH_SLB_PARITY:
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
+		break;
+	case P7_SRR1_MC_IFETCH_SLB_MULTIHIT:
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
+		break;
+	case P7_SRR1_MC_IFETCH_TLB_MULTIHIT:
+		mce_err->error_type = MCE_ERROR_TYPE_TLB;
+		mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
+		break;
+	case P7_SRR1_MC_IFETCH_UE:
+	case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL:
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH;
+		break;
+	case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD:
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type =
+				MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH;
+		break;
+	}
+}
+
+static void mce_get_ierror_p7(struct mce_error_info *mce_err, uint64_t srr1)
+{
+	mce_get_common_ierror(mce_err, srr1);
+	if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) {
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE;
+	}
+}
+
+static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr)
+{
+	if (dsisr & P7_DSISR_MC_UE) {
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE;
+	} else if (dsisr & P7_DSISR_MC_UE_TABLEWALK) {
+		mce_err->error_type = MCE_ERROR_TYPE_UE;
+		mce_err->u.ue_error_type =
+				MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
+	} else if (dsisr & P7_DSISR_MC_ERAT_MULTIHIT) {
+		mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+		mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+	} else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT) {
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
+	} else if (dsisr & P7_DSISR_MC_SLB_PARITY_MFSLB) {
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
+	} else if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) {
+		mce_err->error_type = MCE_ERROR_TYPE_TLB;
+		mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
+	} else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT_PARITY) {
+		mce_err->error_type = MCE_ERROR_TYPE_SLB;
+		mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE;
+	}
+}
+
 long __machine_check_early_realmode_p7(struct pt_regs *regs)
 {
-	uint64_t srr1;
+	uint64_t srr1, addr;
 	long handled = 1;
+	struct mce_error_info mce_error_info = { 0 };
 
 	srr1 = regs->msr;
 
-	if (P7_SRR1_MC_LOADSTORE(srr1))
+	/*
+	 * Handle memory errors depending whether this was a load/store or
+	 * ifetch exception. Also, populate the mce error_type and
+	 * type-specific error_type from either SRR1 or DSISR, depending
+	 * whether this was a load/store or ifetch exception
+	 */
+	if (P7_SRR1_MC_LOADSTORE(srr1)) {
 		handled = mce_handle_derror_p7(regs->dsisr);
-	else
+		mce_get_derror_p7(&mce_error_info, regs->dsisr);
+		addr = regs->dar;
+	} else {
 		handled = mce_handle_ierror_p7(srr1);
+		mce_get_ierror_p7(&mce_error_info, srr1);
+		addr = regs->nip;
+	}
 
-	/* TODO: Decode machine check reason. */
+	save_mce_event(regs, handled, &mce_error_info, addr);
 	return handled;
 }
 
+static void mce_get_ierror_p8(struct mce_error_info *mce_err, uint64_t srr1)
+{
+	mce_get_common_ierror(mce_err, srr1);
+	if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) {
+		mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+		mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+	}
+}
+
+static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr)
+{
+	mce_get_derror_p7(mce_err, dsisr);
+	if (dsisr & P8_DSISR_MC_ERAT_MULTIHIT_SEC) {
+		mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+		mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+	}
+}
+
 static long mce_handle_ierror_p8(uint64_t srr1)
 {
 	long handled = 0;
@@ -172,16 +266,22 @@ static long mce_handle_derror_p8(uint64_t dsisr)
 
 long __machine_check_early_realmode_p8(struct pt_regs *regs)
 {
-	uint64_t srr1;
+	uint64_t srr1, addr;
 	long handled = 1;
+	struct mce_error_info mce_error_info = { 0 };
 
 	srr1 = regs->msr;
 
-	if (P7_SRR1_MC_LOADSTORE(srr1))
+	if (P7_SRR1_MC_LOADSTORE(srr1)) {
 		handled = mce_handle_derror_p8(regs->dsisr);
-	else
+		mce_get_derror_p8(&mce_error_info, regs->dsisr);
+		addr = regs->dar;
+	} else {
 		handled = mce_handle_ierror_p8(srr1);
+		mce_get_ierror_p8(&mce_error_info, srr1);
+		addr = regs->nip;
+	}
 
-	/* TODO: Decode machine check reason. */
+	save_mce_event(regs, handled, &mce_error_info, addr);
 	return handled;
 }
diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c
index 5c427b4..768a9f9 100644
--- a/arch/powerpc/kvm/book3s_hv_ras.c
+++ b/arch/powerpc/kvm/book3s_hv_ras.c
@@ -12,6 +12,7 @@
 #include <linux/kvm_host.h>
 #include <linux/kernel.h>
 #include <asm/opal.h>
+#include <asm/mce.h>
 
 /* SRR1 bits for machine check on POWER7 */
 #define SRR1_MC_LDSTERR		(1ul << (63-42))
@@ -67,9 +68,7 @@ static void reload_slb(struct kvm_vcpu *vcpu)
 static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 {
 	unsigned long srr1 = vcpu->arch.shregs.msr;
-#ifdef CONFIG_PPC_POWERNV
-	struct opal_machine_check_event *opal_evt;
-#endif
+	struct machine_check_event mce_evt;
 	long handled = 1;
 
 	if (srr1 & SRR1_MC_LDSTERR) {
@@ -109,22 +108,31 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 		handled = 0;
 	}
 
-#ifdef CONFIG_PPC_POWERNV
 	/*
-	 * See if OPAL has already handled the condition.
-	 * We assume that if the condition is recovered then OPAL
+	 * See if we have already handled the condition in the linux host.
+	 * We assume that if the condition is recovered then linux host
 	 * will have generated an error log event that we will pick
 	 * up and log later.
+	 * Don't release mce event now. In case if condition is not
+	 * recovered we do guest exit and go back to linux host machine
+	 * check handler. Hence we need make sure that current mce event
+	 * is available for linux host to consume.
 	 */
-	opal_evt = local_paca->opal_mc_evt;
-	if (opal_evt->version == OpalMCE_V1 &&
-	    (opal_evt->severity == OpalMCE_SEV_NO_ERROR ||
-	     opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED))
+	if (!get_mce_event(&mce_evt, MCE_EVENT_DONTRELEASE))
+		goto out;
+
+	if (mce_evt.version == MCE_V1 &&
+	    (mce_evt.severity == MCE_SEV_NO_ERROR ||
+	     mce_evt.disposition == MCE_DISPOSITION_RECOVERED))
 		handled = 1;
 
+out:
+	/*
+	 * If we have handled the error, then release the mce event because
+	 * we will be delivering machine check to guest.
+	 */
 	if (handled)
-		opal_evt->in_use = 0;
-#endif
+		release_mce_event();
 
 	return handled;
 }
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 106301f..bcbbcdc 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <asm/opal.h>
 #include <asm/firmware.h>
+#include <asm/mce.h>
 
 #include "powernv.h"
 
@@ -245,8 +246,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
 
 int opal_machine_check(struct pt_regs *regs)
 {
-	struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt;
-	struct opal_machine_check_event evt;
+	struct machine_check_event evt;
 	const char *level, *sevstr, *subtype;
 	static const char *opal_mc_ue_types[] = {
 		"Indeterminate",
@@ -271,30 +271,29 @@ int opal_machine_check(struct pt_regs *regs)
 		"Multihit",
 	};
 
-	/* Copy the event structure and release the original */
-	evt = *opal_evt;
-	opal_evt->in_use = 0;
+	if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
+		return 0;
 
 	/* Print things out */
-	if (evt.version != OpalMCE_V1) {
+	if (evt.version != MCE_V1) {
 		pr_err("Machine Check Exception, Unknown event version %d !\n",
 		       evt.version);
 		return 0;
 	}
 	switch(evt.severity) {
-	case OpalMCE_SEV_NO_ERROR:
+	case MCE_SEV_NO_ERROR:
 		level = KERN_INFO;
 		sevstr = "Harmless";
 		break;
-	case OpalMCE_SEV_WARNING:
+	case MCE_SEV_WARNING:
 		level = KERN_WARNING;
 		sevstr = "";
 		break;
-	case OpalMCE_SEV_ERROR_SYNC:
+	case MCE_SEV_ERROR_SYNC:
 		level = KERN_ERR;
 		sevstr = "Severe";
 		break;
-	case OpalMCE_SEV_FATAL:
+	case MCE_SEV_FATAL:
 	default:
 		level = KERN_ERR;
 		sevstr = "Fatal";
@@ -302,12 +301,12 @@ int opal_machine_check(struct pt_regs *regs)
 	}
 
 	printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
-	       evt.disposition == OpalMCE_DISPOSITION_RECOVERED ?
+	       evt.disposition == MCE_DISPOSITION_RECOVERED ?
 	       "Recovered" : "[Not recovered");
 	printk("%s  Initiator: %s\n", level,
-	       evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown");
+	       evt.initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown");
 	switch(evt.error_type) {
-	case OpalMCE_ERROR_TYPE_UE:
+	case MCE_ERROR_TYPE_UE:
 		subtype = evt.u.ue_error.ue_error_type <
 			ARRAY_SIZE(opal_mc_ue_types) ?
 			opal_mc_ue_types[evt.u.ue_error.ue_error_type]
@@ -320,7 +319,7 @@ int opal_machine_check(struct pt_regs *regs)
 			printk("%s      Physial address: %016llx\n",
 			       level, evt.u.ue_error.physical_address);
 		break;
-	case OpalMCE_ERROR_TYPE_SLB:
+	case MCE_ERROR_TYPE_SLB:
 		subtype = evt.u.slb_error.slb_error_type <
 			ARRAY_SIZE(opal_mc_slb_types) ?
 			opal_mc_slb_types[evt.u.slb_error.slb_error_type]
@@ -330,7 +329,7 @@ int opal_machine_check(struct pt_regs *regs)
 			printk("%s    Effective address: %016llx\n",
 			       level, evt.u.slb_error.effective_address);
 		break;
-	case OpalMCE_ERROR_TYPE_ERAT:
+	case MCE_ERROR_TYPE_ERAT:
 		subtype = evt.u.erat_error.erat_error_type <
 			ARRAY_SIZE(opal_mc_erat_types) ?
 			opal_mc_erat_types[evt.u.erat_error.erat_error_type]
@@ -340,7 +339,7 @@ int opal_machine_check(struct pt_regs *regs)
 			printk("%s    Effective address: %016llx\n",
 			       level, evt.u.erat_error.effective_address);
 		break;
-	case OpalMCE_ERROR_TYPE_TLB:
+	case MCE_ERROR_TYPE_TLB:
 		subtype = evt.u.tlb_error.tlb_error_type <
 			ARRAY_SIZE(opal_mc_tlb_types) ?
 			opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type]
@@ -351,11 +350,11 @@ int opal_machine_check(struct pt_regs *regs)
 			       level, evt.u.tlb_error.effective_address);
 		break;
 	default:
-	case OpalMCE_ERROR_TYPE_UNKNOWN:
+	case MCE_ERROR_TYPE_UNKNOWN:
 		printk("%s  Error type: Unknown\n", level);
 		break;
 	}
-	return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1;
+	return evt.severity == MCE_SEV_FATAL ? 0 : 1;
 }
 
 static irqreturn_t opal_interrupt(int irq, void *data)

^ permalink raw reply related

* [RFC PATCH v2 07/10] powerpc/book3s: Flush SLB/TLBs if we get SLB/TLB machine check errors on power8.
From: Mahesh J Salgaonkar @ 2013-08-16  8:04 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

This patch handles the memory errors on power8. If we get a machine check
exception due to SLB or TLB errors, then flush SLBs/TLBs and reload SLBs to
recover.

I do not have access to power8 box, hence this patch haven't been tested
yet.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/mce.h  |    3 +++
 arch/powerpc/kernel/cputable.c  |    4 ++++
 arch/powerpc/kernel/mce_power.c |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+)

diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index ba19073..6866062 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -64,4 +64,7 @@
 					 P7_DSISR_MC_SLB_MULTIHIT | \
 					 P7_DSISR_MC_SLB_MULTIHIT_PARITY)
 
+#define P8_DSISR_MC_SLB_ERRORS		(P7_DSISR_MC_SLB_ERRORS | \
+					 P8_DSISR_MC_ERAT_MULTIHIT_SEC)
+
 #endif /* __ASM_PPC64_MCE_H__ */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index c28cc2c..0195358 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -74,6 +74,7 @@ extern void __restore_cpu_a2(void);
 extern void __flush_tlb_power7(unsigned long inval_selector);
 extern void __flush_tlb_power8(unsigned long inval_selector);
 extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
+extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
 extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -462,6 +463,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_power8,
 		.cpu_restore		= __restore_cpu_power8,
 		.flush_tlb		= __flush_tlb_power8,
+		.machine_check_early	= __machine_check_early_realmode_p8,
 		.platform		= "power8",
 	},
 	{	/* Power7 */
@@ -521,6 +523,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_power8,
 		.cpu_restore		= __restore_cpu_power8,
 		.flush_tlb		= __flush_tlb_power8,
+		.machine_check_early	= __machine_check_early_realmode_p8,
 		.platform		= "power8",
 	},
 	{	/* Power8 */
@@ -540,6 +543,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_power8,
 		.cpu_restore		= __restore_cpu_power8,
 		.flush_tlb		= __flush_tlb_power8,
+		.machine_check_early	= __machine_check_early_realmode_p8,
 		.platform		= "power8",
 	},
 	{	/* Cell Broadband Engine */
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 645d722..949d102 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -151,3 +151,37 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)
 	/* TODO: Decode machine check reason. */
 	return handled;
 }
+
+static long mce_handle_ierror_p8(uint64_t srr1)
+{
+	long handled = 0;
+
+	handled = mce_handle_common_ierror(srr1);
+
+	if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) {
+		flush_and_reload_slb();
+		handled = 1;
+	}
+	return handled;
+}
+
+static long mce_handle_derror_p8(uint64_t dsisr)
+{
+	return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS);
+}
+
+long __machine_check_early_realmode_p8(struct pt_regs *regs)
+{
+	uint64_t srr1;
+	long handled = 1;
+
+	srr1 = regs->msr;
+
+	if (P7_SRR1_MC_LOADSTORE(srr1))
+		handled = mce_handle_derror_p8(regs->dsisr);
+	else
+		handled = mce_handle_ierror_p8(srr1);
+
+	/* TODO: Decode machine check reason. */
+	return handled;
+}

^ permalink raw reply related

* [RFC PATCH v2 06/10] powerpc/book3s: Flush SLB/TLBs if we get SLB/TLB machine check errors on power7.
From: Mahesh J Salgaonkar @ 2013-08-16  8:04 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

If we get a machine check exception due to SLB or TLB errors, then flush
SLBs/TLBs and reload SLBs to recover. We do this in real mode before turning
on MMU. Otherwise we would run into nested machine checks.

If we get a machine check when we are in guest, then just flush the
SLBs and continue. This patch handles errors for power7. The next
patch will handle errors for power8

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/bitops.h |    5 +
 arch/powerpc/include/asm/mce.h    |   67 ++++++++++++++++
 arch/powerpc/kernel/Makefile      |    1 
 arch/powerpc/kernel/cputable.c    |    4 +
 arch/powerpc/kernel/mce_power.c   |  153 +++++++++++++++++++++++++++++++++++++
 5 files changed, 230 insertions(+)
 create mode 100644 arch/powerpc/include/asm/mce.h
 create mode 100644 arch/powerpc/kernel/mce_power.c

diff --git a/arch/powerpc/include/asm/bitops.h b/arch/powerpc/include/asm/bitops.h
index 910194e..a57f4bc 100644
--- a/arch/powerpc/include/asm/bitops.h
+++ b/arch/powerpc/include/asm/bitops.h
@@ -46,6 +46,11 @@
 #include <asm/asm-compat.h>
 #include <asm/synch.h>
 
+/* PPC bit number conversion */
+#define PPC_BIT(bit)		(0x8000000000000000UL >> (bit))
+#define PPC_BITLSHIFT(be)	(63 - (be))
+#define PPC_BITMASK(bs, be)	((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+
 /*
  * clear_bit doesn't imply a memory barrier
  */
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
new file mode 100644
index 0000000..ba19073
--- /dev/null
+++ b/arch/powerpc/include/asm/mce.h
@@ -0,0 +1,67 @@
+/*
+ * Machine check exception header file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __ASM_PPC64_MCE_H__
+#define __ASM_PPC64_MCE_H__
+
+#include <linux/bitops.h>
+
+/*
+ * Machine Check bits on power7 and power8
+ */
+#define P7_SRR1_MC_LOADSTORE(srr1)	((srr1) & PPC_BIT(42)) /* P8 too */
+
+/* SRR1 bits for machine check (On Power7 and Power8) */
+#define P7_SRR1_MC_IFETCH(srr1)	((srr1) & PPC_BITMASK(43, 45)) /* P8 too */
+
+#define P7_SRR1_MC_IFETCH_UE		(0x1 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_SLB_PARITY	(0x2 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT	(0x3 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_SLB_BOTH	(0x4 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT	(0x5 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD	(0x6 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL	(0x7 << PPC_BITLSHIFT(45))
+
+/* SRR1 bits for machine check (On Power8) */
+#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT	(0x4 << PPC_BITLSHIFT(45))
+
+/* DSISR bits for machine check (On Power7 and Power8) */
+#define P7_DSISR_MC_UE			(PPC_BIT(48))	/* P8 too */
+#define P7_DSISR_MC_UE_TABLEWALK	(PPC_BIT(49))	/* P8 too */
+#define P7_DSISR_MC_ERAT_MULTIHIT	(PPC_BIT(52))	/* P8 too */
+#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB	(PPC_BIT(53))	/* P8 too */
+#define P7_DSISR_MC_SLB_PARITY_MFSLB	(PPC_BIT(55))	/* P8 too */
+#define P7_DSISR_MC_SLB_MULTIHIT	(PPC_BIT(56))	/* P8 too */
+#define P7_DSISR_MC_SLB_MULTIHIT_PARITY	(PPC_BIT(57))	/* P8 too */
+
+/*
+ * DSISR bits for machine check (Power8) in addition to above.
+ * Secondary DERAT Multihit
+ */
+#define P8_DSISR_MC_ERAT_MULTIHIT_SEC	(PPC_BIT(54))
+
+/* SLB error bits */
+#define P7_DSISR_MC_SLB_ERRORS		(P7_DSISR_MC_ERAT_MULTIHIT | \
+					 P7_DSISR_MC_SLB_PARITY_MFSLB | \
+					 P7_DSISR_MC_SLB_MULTIHIT | \
+					 P7_DSISR_MC_SLB_MULTIHIT_PARITY)
+
+#endif /* __ASM_PPC64_MCE_H__ */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index a8619bf..a1aba53 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_PPC64)		+= setup_64.o sys_ppc32.o \
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)	+= cpu_setup_power.o
+obj-$(CONFIG_PPC_BOOK3S_64)	+= mce_power.o
 obj64-$(CONFIG_RELOCATABLE)	+= reloc_64.o
 obj-$(CONFIG_PPC_BOOK3E_64)	+= exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC_A2)		+= cpu_setup_a2.o
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index cdbe115..c28cc2c 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -73,6 +73,7 @@ extern void __restore_cpu_power8(void);
 extern void __restore_cpu_a2(void);
 extern void __flush_tlb_power7(unsigned long inval_selector);
 extern void __flush_tlb_power8(unsigned long inval_selector);
+extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
 extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -443,6 +444,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_power7,
 		.cpu_restore		= __restore_cpu_power7,
 		.flush_tlb		= __flush_tlb_power7,
+		.machine_check_early	= __machine_check_early_realmode_p7,
 		.platform		= "power7",
 	},
 	{	/* 2.07-compliant processor, i.e. Power8 "architected" mode */
@@ -479,6 +481,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_power7,
 		.cpu_restore		= __restore_cpu_power7,
 		.flush_tlb		= __flush_tlb_power7,
+		.machine_check_early	= __machine_check_early_realmode_p7,
 		.platform		= "power7",
 	},
 	{	/* Power7+ */
@@ -498,6 +501,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.cpu_setup		= __setup_cpu_power7,
 		.cpu_restore		= __restore_cpu_power7,
 		.flush_tlb		= __flush_tlb_power7,
+		.machine_check_early	= __machine_check_early_realmode_p7,
 		.platform		= "power7+",
 	},
 	{	/* Power8E */
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
new file mode 100644
index 0000000..645d722
--- /dev/null
+++ b/arch/powerpc/kernel/mce_power.c
@@ -0,0 +1,153 @@
+/*
+ * Machine check exception handling CPU-side for power7 and power8
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "mce_power: " fmt
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <asm/mmu.h>
+#include <asm/mce.h>
+
+/* flush SLBs and reload */
+static void flush_and_reload_slb(void)
+{
+	struct slb_shadow *slb;
+	unsigned long i, n;
+
+	if (!mmu_has_feature(MMU_FTR_SLB))
+		return;
+
+	/* Invalidate all SLBs */
+	asm volatile("slbmte %0,%0; slbia" : : "r" (0));
+
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
+	/*
+	 * If machine check is hit when in guest or in transition, we will
+	 * only flush the SLBs and continue.
+	 */
+	if (get_paca()->kvm_hstate.in_guest)
+		return;
+#endif
+
+	/* For host kernel, reload the SLBs from shadow SLB buffer. */
+	slb = get_slb_shadow();
+	if (!slb)
+		return;
+
+	n = min_t(u32, slb->persistent, SLB_MIN_SIZE);
+
+	/* Load up the SLB entries from shadow SLB */
+	for (i = 0; i < n; i++) {
+		unsigned long rb = slb->save_area[i].esid;
+		unsigned long rs = slb->save_area[i].vsid;
+
+		rb = (rb & ~0xFFFul) | i;
+		asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb));
+	}
+}
+
+static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits)
+{
+	long handled = 1;
+
+	/*
+	 * flush and reload SLBs for SLB errors and flush TLBs for TLB errors.
+	 * reset the error bits whenever we handle them so that at the end
+	 * we can check whether we handled all of them or not.
+	 * */
+	if (dsisr & slb_error_bits) {
+		flush_and_reload_slb();
+		/* reset error bits */
+		dsisr &= ~(slb_error_bits);
+	}
+	if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) {
+		if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
+			cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE);
+		/* reset error bits */
+		dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB;
+	}
+	/* Any other errors we don't understand? */
+	if (dsisr & 0xffffffffUL)
+		handled = 0;
+
+	return handled;
+}
+
+static long mce_handle_derror_p7(uint64_t dsisr)
+{
+	return mce_handle_derror(dsisr, P7_DSISR_MC_SLB_ERRORS);
+}
+
+static long mce_handle_common_ierror(uint64_t srr1)
+{
+	long handled = 0;
+
+	switch (P7_SRR1_MC_IFETCH(srr1)) {
+	case 0:
+		break;
+	case P7_SRR1_MC_IFETCH_SLB_PARITY:
+	case P7_SRR1_MC_IFETCH_SLB_MULTIHIT:
+		/* flush and reload SLBs for SLB errors. */
+		flush_and_reload_slb();
+		handled = 1;
+		break;
+	case P7_SRR1_MC_IFETCH_TLB_MULTIHIT:
+		if (cur_cpu_spec && cur_cpu_spec->flush_tlb) {
+			cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE);
+			handled = 1;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return handled;
+}
+
+static long mce_handle_ierror_p7(uint64_t srr1)
+{
+	long handled = 0;
+
+	handled = mce_handle_common_ierror(srr1);
+
+	if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) {
+		flush_and_reload_slb();
+		handled = 1;
+	}
+	return handled;
+}
+
+long __machine_check_early_realmode_p7(struct pt_regs *regs)
+{
+	uint64_t srr1;
+	long handled = 1;
+
+	srr1 = regs->msr;
+
+	if (P7_SRR1_MC_LOADSTORE(srr1))
+		handled = mce_handle_derror_p7(regs->dsisr);
+	else
+		handled = mce_handle_ierror_p7(srr1);
+
+	/* TODO: Decode machine check reason. */
+	return handled;
+}

^ permalink raw reply related

* [RFC PATCH v2 05/10] powerpc/book3s: Add flush_tlb operation in cpu_spec.
From: Mahesh J Salgaonkar @ 2013-08-16  8:04 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

This patch introduces flush_tlb operation in cpu_spec structure. This will
help us to invoke appropriate CPU-side flush tlb routine. This patch
adds the foundation to invoke CPU specific flush routine for respective
architectures. Currently this patch introduce flush_tlb for p7 and p8.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/cputable.h   |    5 ++++
 arch/powerpc/kernel/cpu_setup_power.S |   38 +++++++++++++++++++++++----------
 arch/powerpc/kernel/cputable.c        |    8 +++++++
 arch/powerpc/kvm/book3s_hv_ras.c      |   18 +++-------------
 4 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index d8c098e..d76e47b 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -97,6 +97,11 @@ struct cpu_spec {
 	 */
 	long		(*machine_check_early)(struct pt_regs *regs);
 
+	/*
+	 * Processor specific routine to flush tlbs.
+	 */
+	void		(*flush_tlb)(unsigned long inval_selector);
+
 };
 
 extern struct cpu_spec		*cur_cpu_spec;
diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S
index 18b5b9c..37d1bb0 100644
--- a/arch/powerpc/kernel/cpu_setup_power.S
+++ b/arch/powerpc/kernel/cpu_setup_power.S
@@ -29,7 +29,7 @@ _GLOBAL(__setup_cpu_power7)
 	mtspr	SPRN_LPID,r0
 	mfspr	r3,SPRN_LPCR
 	bl	__init_LPCR
-	bl	__init_TLB
+	bl	__init_tlb_power7
 	mtlr	r11
 	blr
 
@@ -42,7 +42,7 @@ _GLOBAL(__restore_cpu_power7)
 	mtspr	SPRN_LPID,r0
 	mfspr	r3,SPRN_LPCR
 	bl	__init_LPCR
-	bl	__init_TLB
+	bl	__init_tlb_power7
 	mtlr	r11
 	blr
 
@@ -59,7 +59,7 @@ _GLOBAL(__setup_cpu_power8)
 	oris	r3, r3, LPCR_AIL_3@h
 	bl	__init_LPCR
 	bl	__init_HFSCR
-	bl	__init_TLB
+	bl	__init_tlb_power8
 	bl	__init_PMU_HV
 	mtlr	r11
 	blr
@@ -78,7 +78,7 @@ _GLOBAL(__restore_cpu_power8)
 	oris	r3, r3, LPCR_AIL_3@h
 	bl	__init_LPCR
 	bl	__init_HFSCR
-	bl	__init_TLB
+	bl	__init_tlb_power8
 	bl	__init_PMU_HV
 	mtlr	r11
 	blr
@@ -134,15 +134,31 @@ __init_HFSCR:
 	mtspr	SPRN_HFSCR,r3
 	blr
 
-__init_TLB:
-	/*
-	 * Clear the TLB using the "IS 3" form of tlbiel instruction
-	 * (invalidate by congruence class). P7 has 128 CCs, P8 has 512
-	 * so we just always do 512
-	 */
+/*
+ * Clear the TLB using the specified IS form of tlbiel instruction
+ * (invalidate by congruence class). P7 has 128 CCs., P8 has 512.
+ *
+ * r3 = IS field
+ */
+__init_tlb_power7:
+	li	r3,0xc00	/* IS field = 0b11 */
+_GLOBAL(__flush_tlb_power7)
+	li	r6,128
+	mtctr	r6
+	mr	r7,r3		/* IS field */
+	ptesync
+2:	tlbiel	r7
+	addi	r7,r7,0x1000
+	bdnz	2b
+	ptesync
+1:	blr
+
+__init_tlb_power8:
+	li	r3,0xc00	/* IS field = 0b11 */
+_GLOBAL(__flush_tlb_power8)
 	li	r6,512
 	mtctr	r6
-	li	r7,0xc00	/* IS field = 0b11 */
+	mr	r7,r3		/* IS field */
 	ptesync
 2:	tlbiel	r7
 	addi	r7,r7,0x1000
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 22973a7..cdbe115 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -71,6 +71,8 @@ extern void __restore_cpu_power7(void);
 extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power8(void);
 extern void __restore_cpu_a2(void);
+extern void __flush_tlb_power7(unsigned long inval_selector);
+extern void __flush_tlb_power8(unsigned long inval_selector);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
 extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -440,6 +442,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_cpu_type	= "ppc64/ibm-compat-v1",
 		.cpu_setup		= __setup_cpu_power7,
 		.cpu_restore		= __restore_cpu_power7,
+		.flush_tlb		= __flush_tlb_power7,
 		.platform		= "power7",
 	},
 	{	/* 2.07-compliant processor, i.e. Power8 "architected" mode */
@@ -456,6 +459,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_cpu_type	= "ppc64/ibm-compat-v1",
 		.cpu_setup		= __setup_cpu_power8,
 		.cpu_restore		= __restore_cpu_power8,
+		.flush_tlb		= __flush_tlb_power8,
 		.platform		= "power8",
 	},
 	{	/* Power7 */
@@ -474,6 +478,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_type		= PPC_OPROFILE_POWER4,
 		.cpu_setup		= __setup_cpu_power7,
 		.cpu_restore		= __restore_cpu_power7,
+		.flush_tlb		= __flush_tlb_power7,
 		.platform		= "power7",
 	},
 	{	/* Power7+ */
@@ -492,6 +497,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_type		= PPC_OPROFILE_POWER4,
 		.cpu_setup		= __setup_cpu_power7,
 		.cpu_restore		= __restore_cpu_power7,
+		.flush_tlb		= __flush_tlb_power7,
 		.platform		= "power7+",
 	},
 	{	/* Power8E */
@@ -510,6 +516,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_type		= PPC_OPROFILE_INVALID,
 		.cpu_setup		= __setup_cpu_power8,
 		.cpu_restore		= __restore_cpu_power8,
+		.flush_tlb		= __flush_tlb_power8,
 		.platform		= "power8",
 	},
 	{	/* Power8 */
@@ -528,6 +535,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 		.oprofile_type		= PPC_OPROFILE_INVALID,
 		.cpu_setup		= __setup_cpu_power8,
 		.cpu_restore		= __restore_cpu_power8,
+		.flush_tlb		= __flush_tlb_power8,
 		.platform		= "power8",
 	},
 	{	/* Cell Broadband Engine */
diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c
index a353c48..5c427b4 100644
--- a/arch/powerpc/kvm/book3s_hv_ras.c
+++ b/arch/powerpc/kvm/book3s_hv_ras.c
@@ -58,18 +58,6 @@ static void reload_slb(struct kvm_vcpu *vcpu)
 	}
 }
 
-/* POWER7 TLB flush */
-static void flush_tlb_power7(struct kvm_vcpu *vcpu)
-{
-	unsigned long i, rb;
-
-	rb = TLBIEL_INVAL_SET_LPID;
-	for (i = 0; i < POWER7_TLB_SETS; ++i) {
-		asm volatile("tlbiel %0" : : "r" (rb));
-		rb += 1 << TLBIEL_INVAL_SET_SHIFT;
-	}
-}
-
 /*
  * On POWER7, see if we can handle a machine check that occurred inside
  * the guest in real mode, without switching to the host partition.
@@ -96,7 +84,8 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 				   DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI);
 		}
 		if (dsisr & DSISR_MC_TLB_MULTI) {
-			flush_tlb_power7(vcpu);
+			if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
+				cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID);
 			dsisr &= ~DSISR_MC_TLB_MULTI;
 		}
 		/* Any other errors we don't understand? */
@@ -113,7 +102,8 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 		reload_slb(vcpu);
 		break;
 	case SRR1_MC_IFETCH_TLBMULTI:
-		flush_tlb_power7(vcpu);
+		if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
+			cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID);
 		break;
 	default:
 		handled = 0;

^ permalink raw reply related

* [RFC PATCH v2 04/10] powerpc/book3s: Introduce a early machine check hook in cpu_spec.
From: Mahesh J Salgaonkar @ 2013-08-16  8:04 UTC (permalink / raw)
  To: linuxppc-dev, Benjamin Herrenschmidt
  Cc: Jeremy Kerr, Paul Mackerras, Anton Blanchard
In-Reply-To: <20130816080213.680.50794.stgit@mars.in.ibm.com>

From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

This patch adds the early machine check function pointer in cputable for
CPU specific early machine check handling. The early machine handle routine
will be called in real mode to handle SLB and TLB errors. This patch just
sets up a mechanism invoke CPU specific handler. The subsequent patches
will populate the function pointer.

Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/cputable.h |    7 +++++++
 arch/powerpc/kernel/traps.c         |    7 +++++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 6f3887d..d8c098e 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -90,6 +90,13 @@ struct cpu_spec {
 	 * if the error is fatal, 1 if it was fully recovered and 0 to
 	 * pass up (not CPU originated) */
 	int		(*machine_check)(struct pt_regs *regs);
+
+	/*
+	 * Processor specific early machine check handler which is
+	 * called in real mode to handle SLB and TLB errors.
+	 */
+	long		(*machine_check_early)(struct pt_regs *regs);
+
 };
 
 extern struct cpu_spec		*cur_cpu_spec;
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 1720e08..07331b7 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -294,8 +294,11 @@ void system_reset_exception(struct pt_regs *regs)
  */
 long machine_check_early(struct pt_regs *regs)
 {
-	/* TODO: handle/decode machine check reason */
-	return 0;
+	long handled = 0;
+
+	if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
+		handled = cur_cpu_spec->machine_check_early(regs);
+	return handled;
 }
 
 #endif

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox