LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag
From: Nicolin Chen @ 2014-03-27 11:06 UTC (permalink / raw)
  To: broonie, Li.Xiubo
  Cc: alsa-devel, David.Laight, linuxppc-dev, linux-kernel, timur

It's quite cricial to clear error flags because SAI might hang if getting
FIFO underrun during playback (I haven't confirmed the same issue on Rx
overflow though).

So this patch enables those irq and adds isr() to clear the flags so as to
keep playback entirely safe.

Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---

Changelog
v2:
 * Mask the active flags only for the following handler.
 * Reset FIFO for FIFO underrun/overflow cases.
 * Enable two error flags only as default.
 * Use dev_warn for two error flags.
 * Only clear those W1C bits.

 sound/soc/fsl/fsl_sai.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++--
 sound/soc/fsl/fsl_sai.h | 15 +++++++++
 2 files changed, 97 insertions(+), 3 deletions(-)

diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index c4a4231..0bc98bb 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -23,6 +23,71 @@
 
 #include "fsl_sai.h"
 
+#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
+		       FSL_SAI_CSR_FEIE)
+
+static irqreturn_t fsl_sai_isr(int irq, void *devid)
+{
+	struct fsl_sai *sai = (struct fsl_sai *)devid;
+	struct device *dev = &sai->pdev->dev;
+	u32 xcsr, mask;
+
+	/* Only handle those what we enabled */
+	mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
+
+	/* Tx IRQ */
+	regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
+	xcsr &= mask;
+
+	if (xcsr & FSL_SAI_CSR_WSF)
+		dev_dbg(dev, "isr: Start of Tx word detected\n");
+
+	if (xcsr & FSL_SAI_CSR_SEF)
+		dev_warn(dev, "isr: Tx Frame sync error detected\n");
+
+	if (xcsr & FSL_SAI_CSR_FEF) {
+		dev_warn(dev, "isr: Transmit underrun detected\n");
+		/* FIFO reset for safety */
+		xcsr |= FSL_SAI_CSR_FR;
+	}
+
+	if (xcsr & FSL_SAI_CSR_FWF)
+		dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
+
+	if (xcsr & FSL_SAI_CSR_FRF)
+		dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
+
+	regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+			   FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+
+	/* Rx IRQ */
+	regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
+	xcsr &= mask;
+
+	if (xcsr & FSL_SAI_CSR_WSF)
+		dev_dbg(dev, "isr: Start of Rx word detected\n");
+
+	if (xcsr & FSL_SAI_CSR_SEF)
+		dev_warn(dev, "isr: Rx Frame sync error detected\n");
+
+	if (xcsr & FSL_SAI_CSR_FEF) {
+		dev_warn(dev, "isr: Receive overflow detected\n");
+		/* FIFO reset for safety */
+		xcsr |= FSL_SAI_CSR_FR;
+	}
+
+	if (xcsr & FSL_SAI_CSR_FWF)
+		dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
+
+	if (xcsr & FSL_SAI_CSR_FRF)
+		dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
+
+	regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+			   FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+
+	return IRQ_HANDLED;
+}
+
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
 		int clk_id, unsigned int freq, int fsl_dir)
 {
@@ -373,8 +438,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
 	struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-	regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
-	regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+	regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
+	regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
 	regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
 			   FSL_SAI_MAXBURST_TX * 2);
 	regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -490,12 +555,14 @@ static int fsl_sai_probe(struct platform_device *pdev)
 	struct fsl_sai *sai;
 	struct resource *res;
 	void __iomem *base;
-	int ret;
+	int irq, ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
+	sai->pdev = pdev;
+
 	sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
 	if (sai->big_endian_regs)
 		fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -514,6 +581,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
 		return PTR_ERR(sai->regmap);
 	}
 
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+		return ret;
+	}
+
 	sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
 	sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
 	sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index e432260..a264185 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -37,7 +37,21 @@
 
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE	BIT(31)
+#define FSL_SAI_CSR_FR		BIT(25)
+#define FSL_SAI_CSR_xF_SHIFT	16
+#define FSL_SAI_CSR_xF_W_SHIFT	18
+#define FSL_SAI_CSR_xF_MASK	(0x1f << FSL_SAI_CSR_xF_SHIFT)
+#define FSL_SAI_CSR_xF_W_MASK	(0x7 << FSL_SAI_CSR_xF_W_SHIFT)
+#define FSL_SAI_CSR_WSF		BIT(20)
+#define FSL_SAI_CSR_SEF		BIT(19)
+#define FSL_SAI_CSR_FEF		BIT(18)
 #define FSL_SAI_CSR_FWF		BIT(17)
+#define FSL_SAI_CSR_FRF		BIT(16)
+#define FSL_SAI_CSR_xIE_SHIFT	8
+#define FSL_SAI_CSR_WSIE	BIT(12)
+#define FSL_SAI_CSR_SEIE	BIT(11)
+#define FSL_SAI_CSR_FEIE	BIT(10)
+#define FSL_SAI_CSR_FWIE	BIT(9)
 #define FSL_SAI_CSR_FRIE	BIT(8)
 #define FSL_SAI_CSR_FRDE	BIT(0)
 
@@ -99,6 +113,7 @@
 #define FSL_SAI_MAXBURST_RX 6
 
 struct fsl_sai {
+	struct platform_device *pdev;
 	struct regmap *regmap;
 
 	bool big_endian_regs;
-- 
1.8.4

^ permalink raw reply related

* Re: [PATCH v4] powernv, cpufreq: cpufreq driver for powernv platform
From: Benjamin Herrenschmidt @ 2014-03-27 11:12 UTC (permalink / raw)
  To: ego
  Cc: Linux PM list, Viresh Kumar, Rafael J. Wysocki,
	linuxppc-dev@ozlabs.org, Anton Blanchard, Srivatsa S. Bhat
In-Reply-To: <20140327093050.GA27777@in.ibm.com>

On Thu, 2014-03-27 at 15:00 +0530, Gautham R Shenoy wrote:
> > > --- a/arch/powerpc/configs/pseries_le_defconfig
> > > +++ b/arch/powerpc/configs/pseries_le_defconfig
> > > @@ -350,3 +350,4 @@ CONFIG_CRYPTO_LZO=m
> > >  # CONFIG_CRYPTO_ANSI_CPRNG is not set
> > >  CONFIG_CRYPTO_DEV_NX=y
> > >  CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
> > > +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
> > 
> > don't know how Rafael want this, but probably this part could have
> gone
> > through ppc tree..
> > 
> 
> That would mean multiple patches :-)

We can always fix the defconfig later but I am also find if Rafael
carries that bit.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH v4] powernv, cpufreq: cpufreq driver for powernv platform
From: Gautham R Shenoy @ 2014-03-27 11:20 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: ego@linux.vnet.ibm.com, Linux PM list, Rafael J. Wysocki,
	linuxppc-dev@ozlabs.org, Anton Blanchard, Srivatsa S. Bhat
In-Reply-To: <CAKohponOe9Au+pe5u9FpddW3+f5pegZB953+5fmYBDusE9j0HA@mail.gmail.com>

On Thu, Mar 27, 2014 at 03:29:36PM +0530, Viresh Kumar wrote:
> On 27 March 2014 15:00, Gautham R Shenoy <ego@linux.vnet.ibm.com> wrote:
> > As of now, I prefer this patch be based on code that is in the -next
> > tree. I'll get rid of the per-core locking once the serialization
> > patch of the core is accepted.
> 
> Okay.. Then divide this patch into two parts, second one doing all
> the serialization stuff and I will review only the first one from V5 :)
> 
> Maybe mention that in Patch2 as well, that once serialization patches
> are accepted, its not required.

Sure. This would be a good idea.

> 
> >> don't know how Rafael want this, but probably this part could have gone
> >> through ppc tree..
> >
> > That would mean multiple patches :-)
> 
> I wasn't opposed to multiple patches at all, but multiple patches for
> basic functionality of same driver file. Otherwise separating things
> into patches is the best receipe.

Fair enough!

> 
> >> > +#define pr_fmt(fmt)    "powernv-cpufreq: " fmt
> >> > +
> >> > +#include <linux/module.h>
> >> > +#include <linux/cpufreq.h>
> >> > +#include <linux/smp.h>
> >> > +#include <linux/of.h>
> >> > +#include <asm/cputhreads.h>
> >>
> >> I thought I gave a comment on missing headers here?
> >
> > Ok, so these seem to be the missing ones.
> >
> > #include <linux/kernel.h>
> > #include <linux/percpu-defs.h>
> > #include <linux/mutex.h>
> 
> This may shift to Patch 2 ..

Ok.

> 
> > #include <linux/sysfs.h>
> > #include <linux/cpumask.h>
> >
> > #include <asm/reg.h>
> >
> > Have I missed anything else ?
> 
> Not sure :) .. I will see if I can find anymore..
>

Cool.
 
> >> > +static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
> >> > +static int powernv_pstate_ids[POWERNV_MAX_PSTATES+1];
> >>
> >> I though we don't need this anymore? Either Rafael will take my patch as
> >> is for the BOOST fixup or we will end up creating .isboost field in
> >> struct cpufreq_frequency_table and so you could have used .driver_data here.
> >>
> >
> > I mentioned in my reply to your BOOST fixup patch that we would like
> > pstate_ids to be of the type "signed int", while the .driver_data is
> > an "unsigned int". If we end up using .driver_data, we would have to
> > be careful and not use it directly but reassign it to a signed int (or
> > typecast it) before using it.
> 
> Probably many people would want it to be unsigned it, so that they
> can put some strange hex values there..
> 
> Which part of your code conflicts with this right now? I can see only
> this line in powernv_set_freq()

I am not denying the advantage of storing pstate_ids in .driver_data
since we will then have all the information in one place.
(That said, in the future if we want to export additional
information, say pertaining to the voltage, we will have to keep a
separate array anyway :-) )

However, as of now, I am wary about reusing a variable provided by
the core, whose type is fixed (which is not the type I am interested
in) and whose interpretation is ambiguous (since it is also being used
as a BOOST indicator).

When we have a .is_boost field, or a flags field in the cpufreq_table,
and once the .driver_data field is completely opaque, I would be
comfortable making use of .driver_data to store the pstate_ids. So
I'll send out those patches once the fixes are present in the
core. For now, let this code stay as it is. I think we should be ok
with the additional overhead of 1kb as of now.

> 
> freq_data.pstate_id = powernv_pstate_ids[new_index];
> 
> And I don't think we will have side effects here.
> 
> > Not just that, the pr_debugs in the core which are printed during
> > frequency transitions will then end up printing large positive values
> > (since it will interpret negative pstate_ids as unsigned int) in the
> > place of pstate_ids, which would not be particularly useful.
> 
> I have checked it again, those prints shouldn't have used that field.
> Will fix them.
> 
> And so you can use that field in your code and I will get core fixed
> for you..

Like I said earlier, once the core is fixed, I'll be comfortable using
the .driver_data field for the purpose I need. Not until then :-)

> 
> >> Why do you need to get these from DT? And not find that yourself here instead?
> >
> > Well, I think we can obtain a more accurate value from the DT which
> > would have already computed it. But I'll let vaidy answer this.
> 
> Can we simply refer to frequency values here for finding min and max
> pstates? If yes, then probably this is the better place as there can be
> human errors in DT.. Also those binding are just not required then.
> And obviously less headache for you as well when you are changing
> pstate tables.
> 
> >> > +       freq_data = (struct powernv_smp_call_data *)arg;
> >>
> >> don't need casting here ?
> >
> > Doesn't harm having it there. Just like the #includes :-)
> 
> Do you ever have these typecasts while you do kmalloc? It also
> returns void *.. That's the same..
> 
> CodingStyle: Chapter 14: Allocating memory:
> 
> Casting the return value which is a void pointer is redundant. The conversion
> from void pointer to any other pointer type is guaranteed by the C programming
> language.

Thanks. I shall keep this in mind in the future.

> 
> >> > +       pr_debug("cpu %d pmsr %lx pstate_id %d frequency %d kHz \n",
> >> > +               smp_processor_id(), pmspr_val, freq_data->pstate_id,
> >>
> >> s/smp_processor_id/raw_smp_processor_id ?
> >
> > No. This function is called via smp_call_function(). So we have
> > preempt_disable on and it is safe to use smp_processor_id.
> 
> My question wasn't about being safe, but avoiding the complexity
> of debug_smp_processor_id(). raw_smp_processor_id() can execute
> very quickly.

Well, in the scenarios that we're interested in, it is highly unlikely
that CONFIG_PREMPT is set. Hence we'll default to
raw_smp_processor_id() anyway. So, I think we can retain
smp_processor_id(). 

> 
> > You mean s/clock/core ?
> 
> Oops!! yes.
> 
> > Thanks for a detailed review again.
> 
> Its my job :)
> 
> > I'll send out the updated patch today incorporating the comments. It
> > shouldn't be hard since most of the comments do not affect the
> > functionality.
> 
> Probably they do now ? :)

Not really.

> 
--
Thanks and Regards
gautham.

^ permalink raw reply

* Re: [PATCH v4] powernv, cpufreq: cpufreq driver for powernv platform
From: Viresh Kumar @ 2014-03-27 11:29 UTC (permalink / raw)
  To: ego@linux.vnet.ibm.com
  Cc: Linux PM list, Rafael J. Wysocki, linuxppc-dev@ozlabs.org,
	Anton Blanchard, Srivatsa S. Bhat
In-Reply-To: <20140327112031.GC27777@in.ibm.com>

On 27 March 2014 16:50, Gautham R Shenoy <ego@linux.vnet.ibm.com> wrote:
> (That said, in the future if we want to export additional
> information, say pertaining to the voltage, we will have to keep a
> separate array anyway :-) )

Lets handle that once it comes.

> However, as of now, I am wary about reusing a variable provided by
> the core, whose type is fixed (which is not the type I am interested
> in) and whose interpretation is ambiguous (since it is also being used
> as a BOOST indicator).

I understand that..

> When we have a .is_boost field, or a flags field in the cpufreq_table,

Probably we might keep it as is and take the patch which I already
sent. In that case as well your stuff will continue to work..

> and once the .driver_data field is completely opaque, I would be
> comfortable making use of .driver_data to store the pstate_ids. So
> I'll send out those patches once the fixes are present in the
> core. For now, let this code stay as it is. I think we should be ok
> with the additional overhead of 1kb as of now.

Chances are more that all my changes would make it before this
driver and then you would be required to update this driver
before submission.

^ permalink raw reply

* Re: [PATCH] phy/at8031: enable at8031 to work on interrupt mode
From: Sergei Shtylyov @ 2014-03-27 11:52 UTC (permalink / raw)
  To: Zhao Qiang, linuxppc-dev, netdev, B07421
  Cc: mugunthanvnm, linux-kernel, helmut.schaa, zonque, R63061, davem
In-Reply-To: <1395901116-16034-1-git-send-email-B45475@freescale.com>

Hello.

On 27-03-2014 10:18, Zhao Qiang wrote:

> The at8031 can work on polling mode and interrupt mode.
> Add ack_interrupt and config intr funcs to enable
> interrupt mode for it.

> Signed-off-by: Zhao Qiang <B45475@freescale.com>
> ---
>   drivers/net/phy/at803x.c | 30 ++++++++++++++++++++++++++++++
>   1 file changed, 30 insertions(+)

> diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
> index bc71947..d034ef5 100644
> --- a/drivers/net/phy/at803x.c
> +++ b/drivers/net/phy/at803x.c
[...]
> @@ -191,6 +194,31 @@ static int at803x_config_init(struct phy_device *phydev)
>   	return 0;
>   }
>
> +static int at803x_ack_interrupt(struct phy_device *phydev)
> +{
> +	int err;
> +
> +	err = phy_read(phydev, AT803X_INSR);

    Could make this an initializer...

> +
> +	return (err < 0) ? err : 0;
> +}
> +
> +static int at803x_config_intr(struct phy_device *phydev)
> +{
> +	int err;
> +	int value;
> +
> +	value = phy_read(phydev, AT803X_INER);
> +
> +	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
> +		err = phy_write(phydev, AT803X_INER,
> +				(value | AT803X_INER_INIT));

    Inner parens not needed.

> +	else
> +		err = phy_write(phydev, AT803X_INER, value);

    Why are you not clearing the bits here? Why write back what has been read 
at all?

WBR, Sergei

^ permalink raw reply

* [PATCH] ALSA: snd-aoa: Add another layout entry for PowerBook6,5
From: Adam Smith @ 2014-03-27 11:52 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: stefang

Either one or a combination of commits
3a3dd0186f619b74e61e6f29dddcaf59af7d3cac "Improve detection of devices
from device-tree" and 26b0d14106954ae46d2f4f7eec3481828a210f7d "Adapt
to new i2c probing scheme" broke the snd-powermac module for my
PowerBook6,5 machine (12" iBook late 2004).  As I understand things,
these machines should be moving over to use snd-aoa.

The attached patch (against a 3.13.0 kernel) creates a new snd-aoa
layout entry for PowerBook6,5 machines.  I've tested it on my iBook and
sound now appears to be fully working.  The module snd-aoa-i2sbus needs
to be added to /etc/modules to ensure all the necessary snd-aoa modules
are loaded. 
 

Signed-off-by: Adam Smith <adogcalledsummer@gmail.com>

diff -uprN a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
--- a/sound/aoa/fabrics/layout.c	2014-01-20 02:40:07.000000000 +0000
+++ b/sound/aoa/fabrics/layout.c	2014-03-05 18:31:11.748445177 +0000
@@ -113,6 +113,7 @@ MODULE_ALIAS("sound-layout-100");
 MODULE_ALIAS("aoa-device-id-14");
 MODULE_ALIAS("aoa-device-id-22");
 MODULE_ALIAS("aoa-device-id-35");
+MODULE_ALIAS("aoa-device-id-38");
 MODULE_ALIAS("aoa-device-id-44");
 
 /* onyx with all but microphone connected */
@@ -363,6 +364,12 @@ static struct layout layouts[] = {
 	  },
 	},
 	/* PowerBook6,5 */
+	{ .device_id = 38,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_noline,
+	  },
+	},
 	{ .device_id = 44,
 	  .codecs[0] = {
 		.name = "tas",
diff -uprN a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
--- a/sound/aoa/soundbus/i2sbus/core.c	2014-01-20 02:40:07.000000000 +0000
+++ b/sound/aoa/soundbus/i2sbus/core.c	2014-03-05 18:32:41.184445303 +0000
@@ -203,7 +203,7 @@ static int i2sbus_add_dev(struct macio_d
 			 * so restrict to those we do handle for now.
 			 */
 			if (id && (*id == 22 || *id == 14 || *id == 35 ||
-				   *id == 44)) {
+				   *id == 38 || *id == 44)) {
 				snprintf(dev->sound.modalias, 32,
 					 "aoa-device-id-%d", *id);
 				ok = 1;

^ permalink raw reply

* [PATCH 1/2] video/fsl: Fix the sleep function for FSL DIU module
From: Jason Jin @ 2014-03-27 11:37 UTC (permalink / raw)
  To: b07421, timur
  Cc: linux-fbdev, linuxppc-dev, r58472, jason.jin, Wang Dongsheng

For deep sleep, the diu module will power off, when wake up from the deep
sleep, more registers need to be reinitialized.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Jason Jin <Jason.Jin@freescale.com>
---
V2: Coding style clean up based on Timur's comments.

 drivers/video/fsl-diu-fb.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index e8758b9..4bc4730 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1628,9 +1628,15 @@ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
 static int fsl_diu_resume(struct platform_device *ofdev)
 {
 	struct fsl_diu_data *data;
+	unsigned int i;
 
 	data = dev_get_drvdata(&ofdev->dev);
-	enable_lcdc(data->fsl_diu_info);
+	fsl_diu_enable_interrupts(data);
+	update_lcdc(data->fsl_diu_info);
+	for (i = 0; i < NUM_AOIS; i++) {
+		if (data->mfb[i].count)
+			fsl_diu_enable_panel(&data->fsl_diu_info[i]);
+	}
 
 	return 0;
 }
-- 
1.8.0

^ permalink raw reply related

* [PATCH 2/2] Make the diu driver work without board level initilization
From: Jason Jin @ 2014-03-27 11:38 UTC (permalink / raw)
  To: b07421, timur; +Cc: linux-fbdev, linuxppc-dev, r58472, jason.jin

So far the DIU driver does not have a mechanism to do the
board specific initialization. So on some platforms,
such as P1022, 8610 and 5121, The board specific initialization
is implmented in the platform file such p10222_ds.

Actually, the DIU is already intialized in the u-boot, the pin sharing
and the signal routing are also set in u-boot. So we can leverage that
in kernel driver to avoid board sepecific initialization, especially
for the corenet platform, which is the abstraction for serveral
platfroms.

The potential problem is that when the system wakeup from the deep
sleep, some platform settings may need to be re-initialized. The CPLD
and FPGA settings will be kept, but the pixel clock register which
usually locate at the global utility space need to be reinitialized.

Generally, the pixel clock setting was implemented in the platform
file, But the pixel clock register itself should be part of the DIU
module, And for P1022,8610 and T1040, the pixel clock register have the
same structure, So we can consider to move the pixel clock setting
from the platform to the diu driver. This patch provide the options
set the pixel clock in the diu driver. But the original platform pixel
clock setting stil can be used for P1022,8610 and 512x without any
update. To implement the pixel clock setting in the diu driver. the
following update in the diu dts node was needed.
display:display@180000 {
	compatible = "fsl,t1040-diu", "fsl,diu";
-	reg = <0x180000 1000>;
+	reg = <0x180000 1000 0xfc028 4>;
+	pixclk = <0 255 0>;
 	interrupts = <74 2 0 0>;
}
The 0xfc028 is the offset for pixel clock register. the 3 segment of
the pixclk stand for the PXCKDLYDIR, the max of PXCK and the PXCKDLY
which will be used by the pixel clock register setting.

This was tested on T1040 platform. For other platform, the original
node together with the platform settings still can work.

Signed-off-by: Jason Jin <Jason.Jin@freescale.com>
---
V2: Remove the pixel clock register saving for suspend.
add the pixel clock setting in driver.

 drivers/video/fsl-diu-fb.c | 61 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 4bc4730..792038f 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -50,6 +50,7 @@
 #define INT_PARERR	0x08	/* Display parameters error interrupt */
 #define INT_LS_BF_VS	0x10	/* Lines before vsync. interrupt */
 
+#define PIXCLKCR_PXCKEN 0x80000000
 /*
  * List of supported video modes
  *
@@ -372,6 +373,8 @@ struct fsl_diu_data {
 	unsigned int irq;
 	enum fsl_diu_monitor_port monitor_port;
 	struct diu __iomem *diu_reg;
+	void __iomem *pixelclk_reg;
+	u32 pixclkcr[3];
 	spinlock_t reg_lock;
 	u8 dummy_aoi[4 * 4 * 4];
 	struct diu_ad dummy_ad __aligned(8);
@@ -479,7 +482,10 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
 			port = FSL_DIU_PORT_DLVDS;
 	}
 
-	return diu_ops.valid_monitor_port(port);
+	if (diu_ops.valid_monitor_port)
+		return diu_ops.valid_monitor_port(port);
+	else
+		return port;
 }
 
 /*
@@ -798,6 +804,35 @@ static void set_fix(struct fb_info *info)
 	fix->ypanstep = 1;
 }
 
+static void set_pixel_clock(struct fsl_diu_data *data, unsigned int pixclock)
+{
+	unsigned long freq;
+	u64 temp;
+	u32 pxclk;
+	u32 pxclkdl_dir, pxckmax, pxclk_delay;
+
+	/* Convert pixclock from a wavelength to a frequency */
+	temp = 1000000000000ULL;
+	do_div(temp, pixclock);
+	freq = temp;
+
+	pxclkdl_dir = data->pixclkcr[0] << 30;
+	pxckmax =  data->pixclkcr[1];
+	pxclk_delay = data->pixclkcr[2] << 8;
+
+	/*
+	 * 'pxclk' is the ratio of the platform clock to the pixel clock.
+	 * This number is programmed into the PIXCLKCR register, and the valid
+	 * range of values is 2- pxckmax.
+	 */
+	pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+	pxclk = clamp_t(u32, pxclk, 2, pxckmax);
+
+	out_be32(data->pixelclk_reg, 0);
+	out_be32(data->pixelclk_reg, PIXCLKCR_PXCKEN
+			| pxclkdl_dir | (pxclk << 16) | pxclk_delay);
+}
+
 static void update_lcdc(struct fb_info *info)
 {
 	struct fb_var_screeninfo *var = &info->var;
@@ -846,7 +881,13 @@ static void update_lcdc(struct fb_info *info)
 
 	out_be32(&hw->vsyn_para, temp);
 
-	diu_ops.set_pixel_clock(var->pixclock);
+	/* If the pixel clock setting function can not be used on the platform,
+	 * then use the platform one.
+	 */
+	if (diu_ops.set_pixel_clock)
+		diu_ops.set_pixel_clock(var->pixclock);
+	else
+		set_pixel_clock(data, var->pixclock);
 
 #ifndef CONFIG_PPC_MPC512x
 	/*
@@ -1752,6 +1793,22 @@ static int fsl_diu_probe(struct platform_device *pdev)
 		goto error;
 	}
 
+	if (!diu_ops.set_pixel_clock) {
+		data->pixelclk_reg = of_iomap(np, 1);
+		if (!data->pixelclk_reg) {
+			dev_err(&pdev->dev, "Cannot map pixelclk registers, please \
+				provide the diu_ops for pixclk setting instead.\n");
+			ret = -EFAULT;
+			goto error;
+		}
+		/*Get the pixclkcr settings: PXCKDLYDIR; MAXPXCK, PXCKDLY*/
+		ret = of_property_read_u32_array(np, "pixclk", data->pixclkcr, 3);
+		if (ret) {
+			dev_err(&pdev->dev, "Cannot get pixelclk registers information.\n");
+			goto error;
+		}
+	}
+
 	/* Get the IRQ of the DIU */
 	data->irq = irq_of_parse_and_map(np, 0);
 
-- 
1.8.0

^ permalink raw reply related

* Re: [PATCH v4] powernv, cpufreq: cpufreq driver for powernv platform
From: Benjamin Herrenschmidt @ 2014-03-27 12:56 UTC (permalink / raw)
  To: ego
  Cc: Linux PM list, Viresh Kumar, Rafael J. Wysocki,
	linuxppc-dev@ozlabs.org, Anton Blanchard, Srivatsa S. Bhat
In-Reply-To: <20140327112031.GC27777@in.ibm.com>

On Thu, 2014-03-27 at 16:50 +0530, Gautham R Shenoy wrote:
> 
> Well, in the scenarios that we're interested in, it is highly unlikely
> that CONFIG_PREMPT is set. Hence we'll default to
> raw_smp_processor_id() anyway. So, I think we can retain
> smp_processor_id(). 

We don't know that. Some people are interested in running preempt
on these things. If raw is ok to call here, please use it.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] ASoC: fsl_sai: Add isr to deal with error flag
From: Mark Brown @ 2014-03-27 13:05 UTC (permalink / raw)
  To: David Laight
  Cc: alsa-devel@alsa-project.org, Li.Xiubo@freescale.com,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	'Nicolin Chen'
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D0F6EA538@AcuExch.aculab.com>

[-- Attachment #1: Type: text/plain, Size: 1155 bytes --]

On Thu, Mar 27, 2014 at 09:41:20AM +0000, David Laight wrote:
> From: Mark Brown

> > The trace is already conditional?  I'd also expect to see the driver
> > only acknowledging sources it knows about and only reporting that the
> > interrupt was handled if it saw one of them - right now all interrupts
> > are unconditionally acknowleged.

> The traces are separately conditional on their own bits.
> That is a lot of checks that will normally be false.

Oh, I see what you mean.  I'm not sure that level of optimisation is
worth it, the overhead of taking an interrupt in the first place is
going to dwarf the optimisation and the indentation probably won't help
writing clear messages.

> Also the driver may need to clear all the active interrupt
> bits in order to make the IRQ go away.
> It should trace that bits it doesn't expect to be set though.

The interrupt core will eventually take care of it if the interrupt is
left screaming with nothing handling it (and provide diagnostics).  I
would *hope* that this is only happening for unmasked interrupt sources
we explicitly unmask anyway, we really don't want interrupts on FIFO
level changes.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2] ASoC: fsl_sai: Add isr to deal with error flag
From: Mark Brown @ 2014-03-27 13:26 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: alsa-devel, linux-kernel, timur, Li.Xiubo, David.Laight,
	linuxppc-dev
In-Reply-To: <1395918419-20739-1-git-send-email-Guangyu.Chen@freescale.com>

[-- Attachment #1: Type: text/plain, Size: 1157 bytes --]

On Thu, Mar 27, 2014 at 07:06:59PM +0800, Nicolin Chen wrote:
> It's quite cricial to clear error flags because SAI might hang if getting
> FIFO underrun during playback (I haven't confirmed the same issue on Rx
> overflow though).
> 
> So this patch enables those irq and adds isr() to clear the flags so as to
> keep playback entirely safe.

So, I've applied this since we're (hopefully!) very near the merge
window opening and it seems like it should be an improvement overall.
However a few things below:

> +	/* Only handle those what we enabled */
> +	mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;

The shifting here could use a comment.

> +	regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
> +			   FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);

Using update_bits() is going to do an extra read, better to do this as:

	if (xcsr)
		regmap_write(sai->regmap, FSL_SAI_RCSR, xcsr);

otherwise we might be ignoring any of the bits that are actually clear
on read (it seems like there are some?).

> +	return IRQ_HANDLED;

I'd expect to see IRQ_NONE if we didn't actually see an interrupt
source.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: Bug in reclaim logic with exhausted nodes?
From: Nishanth Aravamudan @ 2014-03-27 20:33 UTC (permalink / raw)
  To: Christoph Lameter; +Cc: linux-mm, mgorman, linuxppc-dev, anton, rientjes
In-Reply-To: <alpine.DEB.2.10.1403251323030.26744@nuc>

Hi Christoph,

On 25.03.2014 [13:25:30 -0500], Christoph Lameter wrote:
> On Tue, 25 Mar 2014, Nishanth Aravamudan wrote:
> 
> > On power, very early, we find the 16G pages (gpages in the powerpc arch
> > code) in the device-tree:
> >
> > early_setup ->
> > 	early_init_mmu ->
> > 		htab_initialize ->
> > 			htab_init_page_sizes ->
> > 				htab_dt_scan_hugepage_blocks ->
> > 					memblock_reserve
> > 						which marks the memory
> > 						as reserved
> > 					add_gpage
> > 						which saves the address
> > 						off so future calls for
> > 						alloc_bootmem_huge_page()
> >
> > hugetlb_init ->
> > 		hugetlb_init_hstates ->
> > 			hugetlb_hstate_alloc_pages ->
> > 				alloc_bootmem_huge_page
> >
> > > Not sure if I understand that correctly.
> >
> > Basically this is present memory that is "reserved" for the 16GB usage
> > per the LPAR configuration. We honor that configuration in Linux based
> > upon the contents of the device-tree. It just so happens in the
> > configuration from my original e-mail that a consequence of this is that
> > a NUMA node has memory (topologically), but none of that memory is free,
> > nor will it ever be free.
> 
> Well dont do that
> 
> > Perhaps, in this case, we could just remove that node from the N_MEMORY
> > mask? Memory allocations will never succeed from the node, and we can
> > never free these 16GB pages. It is really not any different than a
> > memoryless node *except* when you are using the 16GB pages.
> 
> That looks to be the correct way to handle things. Maybe mark the node as
> offline or somehow not present so that the kernel ignores it.

This is a SLUB condition:

mm/slub.c::early_kmem_cache_node_alloc():
...
        page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
...
        if (page_to_nid(page) != node) {
                printk(KERN_ERR "SLUB: Unable to allocate memory from "
                                "node %d\n", node);
                printk(KERN_ERR "SLUB: Allocating a useless per node structure "
                                "in order to be able to continue\n");
        }
...

Since this is quite early, and we have not set up the nodemasks yet,
does it make sense to perhaps have a temporary init-time nodemask that
we set bits in here, and "fix-up" those nodes when we setup the
nodemasks?

Thanks,
Nish

^ permalink raw reply

* Re: [PATCH 4/4] powerpc/powernv: Fix little endian issues OPAL error log code
From: Anton Blanchard @ 2014-03-27 22:04 UTC (permalink / raw)
  To: Stewart Smith; +Cc: paulus, linuxppc-dev
In-Reply-To: <87ob0supw1.fsf@river.i-did-not-set--mail-host-address--so-tickle-me>


Hi Stewart,

> Do we also need any magic for the getting of error logs themselves?
> 
> You may want to check the md5 of the logs themselves on be and le.

Good idea. An md5 of the logs in LE and BE on this box checks out, so I
think we are good.

Anton

^ permalink raw reply

* [PATCH 1/2] powerpc/powernv: Fix endian issues with OPAL async code
From: Anton Blanchard @ 2014-03-27 22:17 UTC (permalink / raw)
  To: benh, paulus, neelegup, sbhat; +Cc: linuxppc-dev


Byteswap struct opal_msg in one place instead of requiring all the
callers to do it.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

Index: b/arch/powerpc/include/asm/opal.h
===================================================================
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -421,6 +421,12 @@ enum OpalSysparamPerm {
 	OPAL_SYSPARAM_RW        = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE),
 };
 
+struct raw_opal_msg {
+	__be32 msg_type;
+	__be32 reserved;
+	__be64 params[8];
+};
+
 struct opal_msg {
 	uint32_t msg_type;
 	uint32_t reserved;
Index: b/arch/powerpc/platforms/powernv/opal.c
===================================================================
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -288,9 +288,11 @@ static void opal_handle_message(void)
 	 * TODO: pre-allocate a message buffer depending on opal-msg-size
 	 * value in /proc/device-tree.
 	 */
+	static struct raw_opal_msg raw_msg;
 	static struct opal_msg msg;
+	int i;
 
-	ret = opal_get_msg(__pa(&msg), sizeof(msg));
+	ret = opal_get_msg(__pa(&raw_msg), sizeof(raw_msg));
 	/* No opal message pending. */
 	if (ret == OPAL_RESOURCE)
 		return;
@@ -302,6 +304,11 @@ static void opal_handle_message(void)
 		return;
 	}
 
+	msg.msg_type = be32_to_cpu(raw_msg.msg_type);
+	msg.reserved = be32_to_cpu(raw_msg.reserved);
+	for (i = 0; i < ARRAY_SIZE(raw_msg.params); i++)
+		msg.params[i] = be64_to_cpu(raw_msg.params[i]);
+
 	/* Sanity check */
 	if (msg.msg_type > OPAL_MSG_TYPE_MAX) {
 		pr_warning("%s: Unknown message type: %u\n",

^ permalink raw reply

* [PATCH 2/2] powerpc/powernv: Fix endian issues with sensor code
From: Anton Blanchard @ 2014-03-27 22:18 UTC (permalink / raw)
  To: benh, paulus, neelegup, sbhat; +Cc: linuxppc-dev
In-Reply-To: <20140328091737.6cb02f7d@kryten>


One OPAL call and one device tree property needed byte swapping.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

Index: b/arch/powerpc/platforms/powernv/opal-sensor.c
===================================================================
--- a/arch/powerpc/platforms/powernv/opal-sensor.c
+++ b/arch/powerpc/platforms/powernv/opal-sensor.c
@@ -33,6 +33,7 @@ int opal_get_sensor_data(u32 sensor_hndl
 {
 	int ret, token;
 	struct opal_msg msg;
+	__be32 data;
 
 	token = opal_async_get_token_interruptible();
 	if (token < 0) {
@@ -42,7 +43,7 @@ int opal_get_sensor_data(u32 sensor_hndl
 	}
 
 	mutex_lock(&opal_sensor_mutex);
-	ret = opal_sensor_read(sensor_hndl, token, sensor_data);
+	ret = opal_sensor_read(sensor_hndl, token, &data);
 	if (ret != OPAL_ASYNC_COMPLETION)
 		goto out_token;
 
@@ -53,6 +54,7 @@ int opal_get_sensor_data(u32 sensor_hndl
 		goto out_token;
 	}
 
+	*sensor_data = be32_to_cpu(data);
 	ret = msg.params[1];
 
 out_token:
Index: b/arch/powerpc/include/asm/opal.h
===================================================================
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -886,8 +886,7 @@ int64_t opal_get_param(uint64_t token, u
 		uint64_t length);
 int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
 		uint64_t length);
-int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
-		uint32_t *sensor_data);
+int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
Index: b/drivers/hwmon/ibmpowernv.c
===================================================================
--- a/drivers/hwmon/ibmpowernv.c
+++ b/drivers/hwmon/ibmpowernv.c
@@ -471,7 +471,7 @@ static int __init powernv_hwmon_init(voi
 	struct device_node *opal, *np = NULL;
 	enum attributes attr_type;
 	enum sensors type;
-	const u32 *sensor_id;
+	u32 sensor_id;
 	u32 sensor_index;
 	int err;
 
@@ -497,14 +497,13 @@ static int __init powernv_hwmon_init(voi
 				&sensor_index))
 			continue;
 
-		sensor_id = of_get_property(np, "sensor-id", NULL);
-		if (!sensor_id) {
+		if (of_property_read_u32(np, "sensor-id", &sensor_id)) {
 			pr_info("%s: %s doesn't have sensor-id\n", __func__,
 					np->name);
 			continue;
 		}
 
-		err = powernv_sensor_init(*sensor_id, np, type, attr_type,
+		err = powernv_sensor_init(sensor_id, np, type, attr_type,
 				sensor_index);
 		if (err) {
 			of_node_put(opal);

^ permalink raw reply

* Re: [PATCH 1/2] powerpc/powernv: Fix endian issues with OPAL async code
From: Benjamin Herrenschmidt @ 2014-03-27 22:27 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: neelegup, sbhat, paulus, linuxppc-dev
In-Reply-To: <20140328091737.6cb02f7d@kryten>

On Fri, 2014-03-28 at 09:17 +1100, Anton Blanchard wrote:
> Byteswap struct opal_msg in one place instead of requiring all the
> callers to do it.

This will clash with us making opal.h something clean and identical
between OPAL and clients.

Can you rename the converted version instead ? (yeah I know, it suck
to find a good name ...)

Cheers,
Ben.

> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> 
> Index: b/arch/powerpc/include/asm/opal.h
> ===================================================================
> --- a/arch/powerpc/include/asm/opal.h
> +++ b/arch/powerpc/include/asm/opal.h
> @@ -421,6 +421,12 @@ enum OpalSysparamPerm {
>  	OPAL_SYSPARAM_RW        = (OPAL_SYSPARAM_READ | OPAL_SYSPARAM_WRITE),
>  };
>  
> +struct raw_opal_msg {
> +	__be32 msg_type;
> +	__be32 reserved;
> +	__be64 params[8];
> +};
> +
>  struct opal_msg {
>  	uint32_t msg_type;
>  	uint32_t reserved;
> Index: b/arch/powerpc/platforms/powernv/opal.c
> ===================================================================
> --- a/arch/powerpc/platforms/powernv/opal.c
> +++ b/arch/powerpc/platforms/powernv/opal.c
> @@ -288,9 +288,11 @@ static void opal_handle_message(void)
>  	 * TODO: pre-allocate a message buffer depending on opal-msg-size
>  	 * value in /proc/device-tree.
>  	 */
> +	static struct raw_opal_msg raw_msg;
>  	static struct opal_msg msg;
> +	int i;
>  
> -	ret = opal_get_msg(__pa(&msg), sizeof(msg));
> +	ret = opal_get_msg(__pa(&raw_msg), sizeof(raw_msg));
>  	/* No opal message pending. */
>  	if (ret == OPAL_RESOURCE)
>  		return;
> @@ -302,6 +304,11 @@ static void opal_handle_message(void)
>  		return;
>  	}
>  
> +	msg.msg_type = be32_to_cpu(raw_msg.msg_type);
> +	msg.reserved = be32_to_cpu(raw_msg.reserved);
> +	for (i = 0; i < ARRAY_SIZE(raw_msg.params); i++)
> +		msg.params[i] = be64_to_cpu(raw_msg.params[i]);
> +
>  	/* Sanity check */
>  	if (msg.msg_type > OPAL_MSG_TYPE_MAX) {
>  		pr_warning("%s: Unknown message type: %u\n",

^ permalink raw reply

* [PATCH 0/2] OPAL message log interface
From: Joel Stanley @ 2014-03-27 23:50 UTC (permalink / raw)
  To: benh, paulus, anton, shangw, hegdevasant, michael, stewart; +Cc: linuxppc-dev

These two patches add support for the message log, and expose a new OPAL call
called opal_invalid that allow me to cause OPAL to inject messages into the
log.

The naming is a bit mixed, as our device tree node is opal-memcons and I
retained the naming of the header structure 'struct memcons', but all other
references are to the OPAL message log.

They have been tested on a POWER7+ machine running some recent firmware.

Joel Stanley (2):
  powerpc/powernv: Add OPAL message log interface
  powerpc/powernv: Add invalid OPAL call

 arch/powerpc/include/asm/opal.h                |  6 ++
 arch/powerpc/platforms/powernv/Makefile        |  1 +
 arch/powerpc/platforms/powernv/opal-messages.c | 97 ++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |  1 +
 arch/powerpc/platforms/powernv/opal.c          |  6 +-
 5 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-messages.c

-- 
1.9.1

^ permalink raw reply

* [PATCH 1/2] powerpc/powernv: Add OPAL message log interface
From: Joel Stanley @ 2014-03-27 23:50 UTC (permalink / raw)
  To: benh, paulus, anton, shangw, hegdevasant, michael, stewart; +Cc: linuxppc-dev
In-Reply-To: <1395964240-8305-1-git-send-email-joel@jms.id.au>

OPAL provides an in-memory circular buffer containing a message log
populated with various runtime messages produced by the firmware.

Provide a sysfs interface /sys/firmware/opal/messages for userspace to
view the messages.

Signed-off-by: Joel Stanley <joel@jms.id.au>
---
 arch/powerpc/include/asm/opal.h                |  4 ++
 arch/powerpc/platforms/powernv/Makefile        |  1 +
 arch/powerpc/platforms/powernv/opal-messages.c | 97 ++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal.c          |  4 +-
 4 files changed, 105 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-messages.c

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ffafab0..6aa757e 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -729,6 +729,9 @@ typedef struct oppanel_line {
 /* /sys/firmware/opal */
 extern struct kobject *opal_kobj;
 
+/* /ibm,opal */
+extern struct device_node *opal_node;
+
 /* API functions */
 int64_t opal_console_write(int64_t term_number, __be64 *length,
 			   const uint8_t *buffer);
@@ -918,6 +921,7 @@ extern void opal_flash_init(void);
 extern int opal_elog_init(void);
 extern void opal_platform_dump_init(void);
 extern void opal_sys_param_init(void);
+extern void opal_messages_init(void);
 
 extern int opal_machine_check(struct pt_regs *regs);
 extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index f324ea0..e2ba418 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,6 +1,7 @@
 obj-y			+= setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
+obj-y			+= opal-messages.o
 
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_PCI)	+= pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/opal-messages.c b/arch/powerpc/platforms/powernv/opal-messages.c
new file mode 100644
index 0000000..3a863e8
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-messages.c
@@ -0,0 +1,97 @@
+/*
+ * PowerNV OPAL in-memory console interface
+ *
+ * Copyright 2014 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/io.h>
+#include <asm/opal.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/types.h>
+
+/* OPAL in-memory console. Defined in OPAL source at core/console.c */
+struct memcons {
+	__be64 magic;
+#define MEMCONS_MAGIC	0x6630696567726173L
+	__be64 obuf_phys;
+	__be64 ibuf_phys;
+	__be32 obuf_size;
+	__be32 ibuf_size;
+	__be32 out_pos;
+#define MEMCONS_OUT_POS_WRAP	0x80000000u
+#define MEMCONS_OUT_POS_MASK	0x00ffffffu
+	__be32 in_prod;
+	__be32 in_cons;
+};
+
+static ssize_t opal_messages_read(struct file *file, struct kobject *kobj,
+	struct bin_attribute *bin_attr, char *to, loff_t pos, size_t count)
+{
+	struct memcons *mc = bin_attr->private;
+	const char *conbuf;
+	bool wrapped;
+	size_t num_read;
+	int out_pos;
+
+	if (!mc)
+		return -ENODEV;
+
+	conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys));
+	wrapped = be32_to_cpu(mc->out_pos) & MEMCONS_OUT_POS_WRAP;
+	out_pos = be32_to_cpu(mc->out_pos) & MEMCONS_OUT_POS_MASK;
+
+	if (!wrapped) {
+		num_read = memory_read_from_buffer(to, count, &pos, conbuf,
+				out_pos);
+	} else {
+		num_read = memory_read_from_buffer(to, count, &pos,
+				conbuf + out_pos,
+				be32_to_cpu(mc->obuf_size) - out_pos);
+
+		if (num_read < 0)
+			goto out;
+
+		num_read += memory_read_from_buffer(to + num_read,
+				count - num_read, &pos, conbuf, out_pos);
+	}
+out:
+	return num_read;
+}
+
+static struct bin_attribute messages_attr = {
+	.attr = {.name = "messages", .mode = 0444},
+	.read = opal_messages_read
+};
+
+void __init opal_messages_init(void)
+{
+	u64 mcaddr;
+	struct memcons *mc;
+
+	if (of_property_read_u64(opal_node, "ibm,opal-memcons", &mcaddr)) {
+		pr_warn("OPAL: Property ibm,opal-memcons not found, no message log\n");
+		return;
+	}
+
+	mc = phys_to_virt(mcaddr);
+	if (!mc) {
+		pr_warn("OPAL: memory console address is invalid\n");
+		return;
+	}
+
+	if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
+		pr_warn("OPAL: memory console version is invalid\n");
+		return;
+	}
+
+	messages_attr.private = mc;
+
+	if (sysfs_create_bin_file(opal_kobj, &messages_attr) != 0)
+		pr_warn("OPAL: sysfs file creation failed\n");
+}
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index e92f2f6..2bc032a 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -46,7 +46,7 @@ struct mcheck_recoverable_range {
 static struct mcheck_recoverable_range *mc_recoverable_range;
 static int mc_recoverable_range_len;
 
-static struct device_node *opal_node;
+struct device_node *opal_node;
 static DEFINE_SPINLOCK(opal_write_lock);
 extern u64 opal_mc_secondary_handler[];
 static unsigned int *opal_irqs;
@@ -574,6 +574,8 @@ static int __init opal_init(void)
 		opal_platform_dump_init();
 		/* Setup system parameters interface */
 		opal_sys_param_init();
+		/* Setup message log interface. */
+		opal_messages_init();
 	}
 
 	return 0;
-- 
1.9.1

^ permalink raw reply related

* [PATCH 2/2] powerpc/powernv: Add invalid OPAL call
From: Joel Stanley @ 2014-03-27 23:50 UTC (permalink / raw)
  To: benh, paulus, anton, shangw, hegdevasant, michael, stewart; +Cc: linuxppc-dev
In-Reply-To: <1395964240-8305-1-git-send-email-joel@jms.id.au>

This call will not be understood by OPAL, and cause it to add an error
to it's log. Among other things, this is useful for testing the
behaviour of the log as it fills up.

Signed-off-by: Joel Stanley <joel@jms.id.au>
---
 arch/powerpc/include/asm/opal.h                | 2 ++
 arch/powerpc/platforms/powernv/opal-wrappers.S | 1 +
 arch/powerpc/platforms/powernv/opal.c          | 2 ++
 3 files changed, 5 insertions(+)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 6aa757e..7f480a4 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -87,6 +87,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_ASYNC_COMPLETION	-15
 
 /* API Tokens (in r0) */
+#define OPAL_INVALID				-1
 #define OPAL_CONSOLE_WRITE			1
 #define OPAL_CONSOLE_READ			2
 #define OPAL_RTC_READ				3
@@ -853,6 +854,7 @@ int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 int64_t opal_lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
 		      uint32_t addr, __be32 *data, uint32_t sz);
 
+int64_t opal_invalid(void);
 int64_t opal_read_elog(uint64_t buffer, size_t size, uint64_t log_id);
 int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
 int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 75c89df..69657dc 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -143,3 +143,4 @@ OPAL_CALL(opal_sync_host_reboot,		OPAL_SYNC_HOST_REBOOT);
 OPAL_CALL(opal_sensor_read,			OPAL_SENSOR_READ);
 OPAL_CALL(opal_get_param,			OPAL_GET_PARAM);
 OPAL_CALL(opal_set_param,			OPAL_SET_PARAM);
+OPAL_CALL(opal_invalid,				OPAL_INVALID);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 2bc032a..f58a3c7 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -43,6 +43,8 @@ struct mcheck_recoverable_range {
 	u64 recover_addr;
 };
 
+EXPORT_SYMBOL_GPL(opal_invalid);
+
 static struct mcheck_recoverable_range *mc_recoverable_range;
 static int mc_recoverable_range_len;
 
-- 
1.9.1

^ permalink raw reply related

* Re: MPC8641 based custom board Kernel stuck at 1000Mhz core clock
From: Valdis.Kletnieks @ 2014-03-27 16:31 UTC (permalink / raw)
  To: Ashish; +Cc: scottwood, linuxppc-dev, kernelnewbies
In-Reply-To: <5333FEBD.3050704@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 556 bytes --]

On Thu, 27 Mar 2014 16:04:37 +0530, Ashish said:
> Hi,
>
>   I am using MPC8641-HPCN based custom board and able to boot linux at
> MPX clock 400Mhz and core clock 800mhz. When I am increasing core
> frequency ie MPX clock at 400Mhz and core at 1Ghz, kernel stuck.

Step 0:  Prove to us that your core actually runs reliable and stably at 1Ghz.

Step 1: Figure out *where* it gets stuck.  If you have earlyprintk working on
your board, adding 'initcall_debug ignore_loglevel' to the kernel cmdline often
helps track down where a kernel hangs during boot.


[-- Attachment #2: Type: application/pgp-signature, Size: 848 bytes --]

^ permalink raw reply

* [PATCH 2/7] powerpc: Make boot_cpuid common between 32 and 64-bit
From: Benjamin Herrenschmidt @ 2014-03-28  2:36 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1395974192-820-1-git-send-email-benh@kernel.crashing.org>

Move the definition to setup-common.c and set the init value
to -1 on both 32 and 64-bit (it was 0 on 64-bit).

Additionally add a check to prom.c to garantee that the init
value has been udpated after the DT scan.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/kernel/prom.c         | 4 ++++
 arch/powerpc/kernel/setup-common.c | 3 +++
 arch/powerpc/kernel/setup_32.c     | 2 --
 arch/powerpc/kernel/setup_64.c     | 1 -
 4 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 0fc55b5..f1002b1 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -744,6 +744,10 @@ void __init early_init_devtree(void *params)
 	 * (altivec support, boot CPU ID, ...)
 	 */
 	of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
+	if (boot_cpuid < 0) {
+		printk("Failed to indentify boot CPU !\n");
+		BUG();
+	}
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PPC64)
 	/* We'll later wait for secondaries to check in; there are
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index bc76cc6..79b7612 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -76,6 +76,9 @@ EXPORT_SYMBOL(ppc_md);
 struct machdep_calls *machine_id;
 EXPORT_SYMBOL(machine_id);
 
+int boot_cpuid = -1;
+EXPORT_SYMBOL_GPL(boot_cpuid);
+
 unsigned long klimit = (unsigned long) _end;
 
 char cmd_line[COMMAND_LINE_SIZE];
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 04cc4fc..ea4fda6 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -44,8 +44,6 @@
 
 extern void bootx_init(unsigned long r4, unsigned long phys);
 
-int boot_cpuid = -1;
-EXPORT_SYMBOL_GPL(boot_cpuid);
 int boot_cpuid_phys;
 EXPORT_SYMBOL_GPL(boot_cpuid_phys);
 
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 4933909..d8aabbd 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -74,7 +74,6 @@
 #define DBG(fmt...)
 #endif
 
-int boot_cpuid = 0;
 int spinning_secondaries;
 u64 ppc64_pft_size;
 
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 3/7] powerpc/prom: early_init_dt_scan_cpus() updates cpu features only once
From: Benjamin Herrenschmidt @ 2014-03-28  2:36 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1395974192-820-1-git-send-email-benh@kernel.crashing.org>

All our cpu feature updates were done for every CPU in the device-tree,
thus overwriting the cputable bits over and over again. Instead do them
only for the boot CPU.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/kernel/prom.c | 52 +++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index f1002b1..7270ca1 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -346,33 +346,34 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 #endif
 	}
 
-	if (found >= 0) {
-		DBG("boot cpu: logical %d physical %d\n", found,
-			be32_to_cpu(intserv[found_thread]));
-		boot_cpuid = found;
-		set_hard_smp_processor_id(found,
-			be32_to_cpu(intserv[found_thread]));
+	/* Not the boot CPU */
+	if (found < 0)
+		return 0;
 
-		/*
-		 * PAPR defines "logical" PVR values for cpus that
-		 * meet various levels of the architecture:
-		 * 0x0f000001	Architecture version 2.04
-		 * 0x0f000002	Architecture version 2.05
-		 * If the cpu-version property in the cpu node contains
-		 * such a value, we call identify_cpu again with the
-		 * logical PVR value in order to use the cpu feature
-		 * bits appropriate for the architecture level.
-		 *
-		 * A POWER6 partition in "POWER6 architected" mode
-		 * uses the 0x0f000002 PVR value; in POWER5+ mode
-		 * it uses 0x0f000001.
-		 */
-		prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
-		if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000)
-			identify_cpu(0, be32_to_cpup(prop));
+	DBG("boot cpu: logical %d physical %d\n", found,
+	    be32_to_cpu(intserv[found_thread]));
+	boot_cpuid = found;
+	set_hard_smp_processor_id(found, be32_to_cpu(intserv[found_thread]));
 
-		identical_pvr_fixup(node);
-	}
+	/*
+	 * PAPR defines "logical" PVR values for cpus that
+	 * meet various levels of the architecture:
+	 * 0x0f000001	Architecture version 2.04
+	 * 0x0f000002	Architecture version 2.05
+	 * If the cpu-version property in the cpu node contains
+	 * such a value, we call identify_cpu again with the
+	 * logical PVR value in order to use the cpu feature
+	 * bits appropriate for the architecture level.
+	 *
+	 * A POWER6 partition in "POWER6 architected" mode
+	 * uses the 0x0f000002 PVR value; in POWER5+ mode
+	 * it uses 0x0f000001.
+	 */
+	prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
+	if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000)
+		identify_cpu(0, be32_to_cpup(prop));
+
+	identical_pvr_fixup(node);
 
 	check_cpu_feature_properties(node);
 	check_cpu_pa_features(node);
@@ -384,7 +385,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 	else
 		cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
 #endif
-
 	return 0;
 }
 
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 4/7] powerpc/ppc64: Gracefully handle early interrupts
From: Benjamin Herrenschmidt @ 2014-03-28  2:36 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1395974192-820-1-git-send-email-benh@kernel.crashing.org>

If we take an interrupt such as a trap caused by a BUG_ON before the
MMU has been setup, the interrupt handlers try to enable virutal mode
and cause a recursive crash, making the original problem very hard
to debug.

This fixes it by adjusting the "kernel_msr" value in the PACA so that
it only has MSR_IR and MSR_DR (translation for instruction and data)
set after the MMU has been initialized for the processor.

We may still not have a console yet but at least we don't get into
a recursive fault (and early debug console or memory dump via JTAG
of the kernel buffer *will* give us the proper error).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/kernel/paca.c     |  3 ++-
 arch/powerpc/kernel/setup_64.c | 15 +++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index bf0aada..ad302f8 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -152,7 +152,8 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
 	new_paca->paca_index = cpu;
 	new_paca->kernel_toc = kernel_toc;
 	new_paca->kernelbase = (unsigned long) _stext;
-	new_paca->kernel_msr = MSR_KERNEL;
+	/* Only set MSR:IR/DR when MMU is initialized */
+	new_paca->kernel_msr = MSR_KERNEL & ~(MSR_IR | MSR_DR);
 	new_paca->hw_cpu_id = 0xffff;
 	new_paca->kexec_state = KEXEC_STATE_NONE;
 	new_paca->__current = &init_task;
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index d8aabbd..1d33e81 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -261,6 +261,14 @@ void __init early_setup(unsigned long dt_ptr)
 	/* Initialize the hash table or TLB handling */
 	early_init_mmu();
 
+	/*
+	 * At this point, we can let interrupts switch to virtual mode
+	 * (the MMU has been setup), so adjust the MSR in the PACA to
+	 * have IR and DR set.
+	 */
+	get_paca()->kernel_msr = MSR_KERNEL;
+
+	/* Reserve large chunks of memory for use by CMA for KVM */
 	kvm_cma_reserve();
 
 	/*
@@ -293,6 +301,13 @@ void early_setup_secondary(void)
 
 	/* Initialize the hash table or TLB handling */
 	early_init_mmu_secondary();
+
+	/*
+	 * At this point, we can let interrupts switch to virtual mode
+	 * (the MMU has been setup), so adjust the MSR in the PACA to
+	 * have IR and DR set.
+	 */
+	get_paca()->kernel_msr = MSR_KERNEL;
 }
 
 #endif /* CONFIG_SMP */
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 1/7] powerpc: Adjust CPU_FTR_SMT on all platforms
From: Benjamin Herrenschmidt @ 2014-03-28  2:36 UTC (permalink / raw)
  To: linuxppc-dev

For historical reasons that code was under #ifdef CONFIG_PPC_PSERIES
but it applies equally to all 64-bit platforms.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/kernel/prom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index d711b7e..0fc55b5 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -378,7 +378,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 	check_cpu_pa_features(node);
 	check_cpu_slb_size(node);
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC64
 	if (nthreads > 1)
 		cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
 	else
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 6/7] powerpc/powernv: Add opal_notifier_unregister() and export to modules
From: Benjamin Herrenschmidt @ 2014-03-28  2:36 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <1395974192-820-1-git-send-email-benh@kernel.crashing.org>

opal_notifier_register() is missing a pending "unregister" variant
and should be exposed to modules.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/opal.h       |  2 ++
 arch/powerpc/platforms/powernv/opal.c | 14 ++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ffafab0..1dd3f9b 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -891,6 +891,8 @@ extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
 				   int depth, void *data);
 
 extern int opal_notifier_register(struct notifier_block *nb);
+extern int opal_notifier_unregister(struct notifier_block *nb);
+
 extern int opal_message_notifier_register(enum OpalMessageType msg_type,
 						struct notifier_block *nb);
 extern void opal_notifier_enable(void);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index e92f2f6..7835d5b 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -180,6 +180,20 @@ int opal_notifier_register(struct notifier_block *nb)
 	atomic_notifier_chain_register(&opal_notifier_head, nb);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(opal_notifier_register);
+
+int opal_notifier_unregister(struct notifier_block *nb)
+{
+	if (!nb) {
+		pr_warning("%s: Invalid argument (%p)\n",
+			   __func__, nb);
+		return -EINVAL;
+	}
+
+	atomic_notifier_chain_unregister(&opal_notifier_head, nb);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(opal_notifier_unregister);
 
 static void opal_do_notifier(uint64_t events)
 {
-- 
1.8.3.2

^ 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