Re: [PATCH] cpufreq: powernv: Add support of frequency domain

2017-12-13 Thread Viresh Kumar
+ Gautham,

@Gautham: Can you please help reviewing this one ?

On 13-12-17, 13:49, Abhishek Goel wrote:
> @@ -693,6 +746,8 @@ static int powernv_cpufreq_target_index(struct 
> cpufreq_policy *policy,
>  {
>   struct powernv_smp_call_data freq_data;
>   unsigned int cur_msec, gpstate_idx;
> + cpumask_t temp;
> + u32 cpu;
>   struct global_pstate_info *gpstates = policy->driver_data;
>  
>   if (unlikely(rebooting) && new_index != get_nominal_index())
> @@ -761,24 +816,48 @@ static int powernv_cpufreq_target_index(struct 
> cpufreq_policy *policy,
>   spin_unlock(&gpstates->gpstate_lock);
>  
>   /*
> -  * Use smp_call_function to send IPI and execute the
> -  * mtspr on target CPU.  We could do that without IPI
> -  * if current CPU is within policy->cpus (core)
> +  * Use smp_call_function to send IPI and execute the mtspr on CPU.
> +  * This needs to be done on every core of the policy

Why on each CPU ?

>*/
> - smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1);
> + cpumask_copy(&temp, policy->cpus);
> +
> + while (!cpumask_empty(&temp)) {
> + cpu = cpumask_first(&temp);
> + smp_call_function_any(cpu_sibling_mask(cpu),
> + set_pstate, &freq_data, 1);
> + cpumask_andnot(&temp, &temp, cpu_sibling_mask(cpu));
> + }
> +
>   return 0;
>  }

-- 
viresh


Re: [PATCH 2/2] powernv/kdump: Fix cases where the kdump kernel can get HMI's

2017-12-13 Thread Nicholas Piggin
On Thu, 14 Dec 2017 11:12:13 +1100
Balbir Singh  wrote:

> On Wed, 13 Dec 2017 20:51:01 +1000
> Nicholas Piggin  wrote:
> 
> > This is looking pretty nice now...
> > 
> > On Wed, 13 Dec 2017 19:08:28 +1100
> > Balbir Singh  wrote:
> >   
> > > @@ -543,7 +543,25 @@ void smp_send_debugger_break(void)
> > >  #ifdef CONFIG_KEXEC_CORE
> > >  void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
> > >  {
> > > + int cpu;
> > > +
> > >   smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_ipi_callback, 100);
> > > + if (kdump_in_progress() && crash_wake_offline) {
> > > + for_each_present_cpu(cpu) {
> > > + if (cpu_online(cpu))
> > > + continue;
> > > + /*
> > > +  * crash_ipi_callback will wait for
> > > +  * all cpus, including offline CPUs.
> > > +  * We don't care about nmi_ipi_function.
> > > +  * Offline cpus will jump straight into
> > > +  * crash_ipi_callback, we can skip the
> > > +  * entire NMI dance and waiting for
> > > +  * cpus to clear pending mask, etc.
> > > +  */
> > > + do_smp_send_nmi_ipi(cpu);
> > 
> > Still a little bit concerned about using NMI IPI for this.
> >  
> 
> OK -- for offline CPUs you mean?

Yes.

> > If you take an NMI IPI from stop, the idle code should do the
> > right thing and we would just return the system reset wakeup
> > reason in SRR1 here (which does not need to be cleared).
> > 
> > If you take the system reset anywhere else in the loop, it's
> > going to go out via system_reset_exception. I guess that
> > would end up doing the right thing, it probably gets to
> > crash_ipi_callback from crash_kexec_secondary?  
> 
> You mean like if we are online at the time of NMI'ing? If so
> the original loop will NMI us back into crash_ipi_callback
> anyway. We don't expect this to occur for offline CPUs

No, if the offline CPU is executing any instruction except for
stop when the crash occurs.

> 
> > 
> > It's just going to be a very untested code path :( What we
> > gain I suppose is better ability to handle a CPU that's locked
> > up somewhere in the cpu offline path. Assuming the uncommon
> > case works...
> > 
> > Actually, if you *always* go via the system reset exception
> > handler, then code paths will be shared. That might be the
> > way to go. So I would check for system reset wakeup SRR1 reason
> > and call replay_system_reset() for it. What do you think?
> >   
> 
> We could do that, but that would call pnv_system_reset_exception
> and try to call the NMI function, but we've not used that path
> to initiate the NMI, so it should call the stale nmi_ipi_function
> which is crash_ipi_callback and not go via the crash_kexec path.

It shouldn't, if the CPU is not set in the NMI bitmask, I think
it should go back out and do the rest of the system_reset_exception
handler.

Anyway we have to get this case right, because it can already hit
as I said if the offline CPU takes the NMI when it is not stopped.
This is why I want to try to use a unified code path.

> I can't call smp_send_nmi_ipi due to the nmi_ipi_busy_count and
> I'm worried about calling a stale nmi_ipi_function via the
> system_reset_exception path, if we are OK with it, I can revisit
> the code path

You shouldn't get a stale one, that would also be a bug -- we
have to cope with NMIs coming in at any time that are triggered
externally (not by smp_send_nmi_ipi), so if you see any bugs
there those need to be fixed separately.

Thanks,
Nick


[PATCH v2] powerpc/npu: Cleanup MMIO ATSD flushing

2017-12-13 Thread Balbir Singh
While reviewing the code I found that the flush assumes all
pages are of mmu_linear_psize, which is not correct. The patch
uses find_linux_pte to find the right page size and uses that
for launching the ATSD invalidation. A new helper is added
to abstract the invalidation from the various notifiers.

The patch also cleans up a bit by removing AP size from PID
flushes.

Signed-off-by: Balbir Singh 
---

Changelog:
  Refactor the handling of return values from find_linux_pte
  as suggested by Aneesh

 arch/powerpc/platforms/powernv/npu-dma.c | 55 ++--
 1 file changed, 38 insertions(+), 17 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/npu-dma.c 
b/arch/powerpc/platforms/powernv/npu-dma.c
index f6cbc1a71472..e8caa3e2019d 100644
--- a/arch/powerpc/platforms/powernv/npu-dma.c
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -27,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "powernv.h"
 #include "pci.h"
@@ -460,9 +462,6 @@ static int mmio_invalidate_pid(struct npu *npu, unsigned 
long pid, bool flush)
/* PRS set to process-scoped */
launch |= PPC_BIT(13);
 
-   /* AP */
-   launch |= (u64) mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17);
-
/* PID */
launch |= pid << PPC_BITLSHIFT(38);
 
@@ -474,7 +473,8 @@ static int mmio_invalidate_pid(struct npu *npu, unsigned 
long pid, bool flush)
 }
 
 static int mmio_invalidate_va(struct npu *npu, unsigned long va,
-   unsigned long pid, bool flush)
+   unsigned long pid, bool flush,
+   unsigned int shift)
 {
unsigned long launch;
 
@@ -485,9 +485,8 @@ static int mmio_invalidate_va(struct npu *npu, unsigned 
long va,
launch |= PPC_BIT(13);
 
/* AP */
-   launch |= (u64) mmu_get_ap(mmu_virtual_psize) << PPC_BITLSHIFT(17);
+   launch |= (u64) mmu_get_ap(shift) << PPC_BITLSHIFT(17);
 
-   /* PID */
launch |= pid << PPC_BITLSHIFT(38);
 
/* No flush */
@@ -504,7 +503,8 @@ struct mmio_atsd_reg {
 };
 
 static void mmio_invalidate_wait(
-   struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], bool flush)
+   struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS], bool flush,
+   unsigned int shift)
 {
struct npu *npu;
int i, reg;
@@ -537,7 +537,8 @@ static void mmio_invalidate_wait(
  * the value of va.
  */
 static void mmio_invalidate(struct npu_context *npu_context, int va,
-   unsigned long address, bool flush)
+   unsigned long address, bool flush,
+   unsigned int shift)
 {
int i, j;
struct npu *npu;
@@ -572,7 +573,7 @@ static void mmio_invalidate(struct npu_context 
*npu_context, int va,
if (va)
mmio_atsd_reg[i].reg =
mmio_invalidate_va(npu, address, pid,
-   flush);
+   flush, shift);
else
mmio_atsd_reg[i].reg =
mmio_invalidate_pid(npu, pid, flush);
@@ -585,10 +586,32 @@ static void mmio_invalidate(struct npu_context 
*npu_context, int va,
}
}
 
-   mmio_invalidate_wait(mmio_atsd_reg, flush);
+   mmio_invalidate_wait(mmio_atsd_reg, flush, shift);
if (flush)
/* Wait for the flush to complete */
-   mmio_invalidate_wait(mmio_atsd_reg, false);
+   mmio_invalidate_wait(mmio_atsd_reg, false, shift);
+}
+
+static void pnv_npu2_invalidate_helper(struct npu_context *npu_context,
+   struct mm_struct *mm, unsigned long start,
+   unsigned long end, bool flush)
+{
+   unsigned long address;
+   unsigned int hshift = 0, shift;
+
+   address = start;
+   do {
+   local_irq_disable();
+   find_linux_pte(mm->pgd, address, NULL, &hshift);
+   if (hshift)
+   shift = hshift;
+   else
+   shift = PAGE_SHIFT;
+   mmio_invalidate(npu_context, address > 0, address, flush,
+   shift);
+   local_irq_enable();
+   address += (1ull << shift);
+   } while (address < end);
 }
 
 static void pnv_npu2_mn_release(struct mmu_notifier *mn,
@@ -604,7 +627,7 @@ static void pnv_npu2_mn_release(struct mmu_notifier *mn,
 * There should be no more translation requests for this PID, but we
 * need to ensure any entries for it are removed from the TLB.
 */
-   mmio_invalidate(npu_context, 0, 0, true);
+   pnv_npu2_invalidate_helper(npu_context, mm, 0, PAGE_SIZE, true);
 }
 
 static void pnv_npu2_mn_change_pte(struct mmu_notifier 

Re: [PATCH 2/2] powernv/kdump: Fix cases where the kdump kernel can get HMI's

2017-12-13 Thread Balbir Singh
On Wed, 13 Dec 2017 20:51:01 +1000
Nicholas Piggin  wrote:

> This is looking pretty nice now...
> 
> On Wed, 13 Dec 2017 19:08:28 +1100
> Balbir Singh  wrote:
> 
> > @@ -543,7 +543,25 @@ void smp_send_debugger_break(void)
> >  #ifdef CONFIG_KEXEC_CORE
> >  void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
> >  {
> > +   int cpu;
> > +
> > smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_ipi_callback, 100);
> > +   if (kdump_in_progress() && crash_wake_offline) {
> > +   for_each_present_cpu(cpu) {
> > +   if (cpu_online(cpu))
> > +   continue;
> > +   /*
> > +* crash_ipi_callback will wait for
> > +* all cpus, including offline CPUs.
> > +* We don't care about nmi_ipi_function.
> > +* Offline cpus will jump straight into
> > +* crash_ipi_callback, we can skip the
> > +* entire NMI dance and waiting for
> > +* cpus to clear pending mask, etc.
> > +*/
> > +   do_smp_send_nmi_ipi(cpu);  
> 
> Still a little bit concerned about using NMI IPI for this.
>

OK -- for offline CPUs you mean?

> If you take an NMI IPI from stop, the idle code should do the
> right thing and we would just return the system reset wakeup
> reason in SRR1 here (which does not need to be cleared).
> 
> If you take the system reset anywhere else in the loop, it's
> going to go out via system_reset_exception. I guess that
> would end up doing the right thing, it probably gets to
> crash_ipi_callback from crash_kexec_secondary?

You mean like if we are online at the time of NMI'ing? If so
the original loop will NMI us back into crash_ipi_callback
anyway. We don't expect this to occur for offline CPUs

> 
> It's just going to be a very untested code path :( What we
> gain I suppose is better ability to handle a CPU that's locked
> up somewhere in the cpu offline path. Assuming the uncommon
> case works...
> 
> Actually, if you *always* go via the system reset exception
> handler, then code paths will be shared. That might be the
> way to go. So I would check for system reset wakeup SRR1 reason
> and call replay_system_reset() for it. What do you think?
> 

We could do that, but that would call pnv_system_reset_exception
and try to call the NMI function, but we've not used that path
to initiate the NMI, so it should call the stale nmi_ipi_function
which is crash_ipi_callback and not go via the crash_kexec path.


I can't call smp_send_nmi_ipi due to the nmi_ipi_busy_count and
I'm worried about calling a stale nmi_ipi_function via the
system_reset_exception path, if we are OK with it, I can revisit
the code path

Thanks,
Balbir Singh.


[PATCH v3 11/11] ASoC: fsl_ssi: Define ternary macros to simplify code

2017-12-13 Thread Nicolin Chen
Some regmap code looks redudant. So simplify it.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 27 +++
 sound/soc/fsl/fsl_ssi.h |  4 
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 4a2438c..578870f 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -405,13 +405,10 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool 
enable)
  */
 static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx)
 {
-   if (is_rx) {
-   regmap_update_bits(ssi->regs, REG_SSI_SOR,
-  SSI_SOR_RX_CLR, SSI_SOR_RX_CLR);
-   } else {
-   regmap_update_bits(ssi->regs, REG_SSI_SOR,
-  SSI_SOR_TX_CLR, SSI_SOR_TX_CLR);
-   }
+   bool tx = !is_rx;
+
+   regmap_update_bits(ssi->regs, REG_SSI_SOR,
+  SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx));
 }
 
 /**
@@ -666,6 +663,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
struct snd_soc_dai *dai,
struct snd_pcm_hw_params *hw_params)
 {
+   bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
struct regmap *regs = ssi->regs;
int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret;
@@ -753,10 +751,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
(psr ? SSI_SxCCR_PSR : 0);
mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR;
 
-   if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || synchronous)
-   regmap_update_bits(regs, REG_SSI_STCCR, mask, stccr);
-   else
-   regmap_update_bits(regs, REG_SSI_SRCCR, mask, stccr);
+   /* STCCR is used for RX in synchronous mode */
+   tx2 = tx || synchronous;
+   regmap_update_bits(regs, REG_SSI_SxCCR(tx2), mask, stccr);
 
if (!baudclk_is_used) {
ret = clk_set_rate(ssi->baudclk, baudrate);
@@ -784,6 +781,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
*substream,
 struct snd_pcm_hw_params *hw_params,
 struct snd_soc_dai *dai)
 {
+   bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
struct regmap *regs = ssi->regs;
unsigned int channels = params_channels(hw_params);
@@ -834,11 +832,8 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
*substream,
}
 
/* In synchronous mode, the SSI uses STCCR for capture */
-   if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
-   ssi->cpu_dai_drv.symmetric_rates)
-   regmap_update_bits(regs, REG_SSI_STCCR, SSI_SxCCR_WL_MASK, wl);
-   else
-   regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_WL_MASK, wl);
+   tx2 = tx || ssi->cpu_dai_drv.symmetric_rates;
+   regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl);
 
return 0;
 }
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index b610087..de2fdc5 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -35,10 +35,12 @@
 #define REG_SSI_STCR   0x1c
 /* SSI Receive Configuration Register */
 #define REG_SSI_SRCR   0x20
+#define REG_SSI_SxCR(tx)   ((tx) ? REG_SSI_STCR : REG_SSI_SRCR)
 /* SSI Transmit Clock Control Register */
 #define REG_SSI_STCCR  0x24
 /* SSI Receive Clock Control Register */
 #define REG_SSI_SRCCR  0x28
+#define REG_SSI_SxCCR(tx)  ((tx) ? REG_SSI_STCCR : REG_SSI_SRCCR)
 /* SSI FIFO Control/Status Register */
 #define REG_SSI_SFCSR  0x2c
 /*
@@ -67,6 +69,7 @@
 #define REG_SSI_STMSK  0x48
 /* SSI  Receive Time Slot Mask Register */
 #define REG_SSI_SRMSK  0x4c
+#define REG_SSI_SxMSK(tx)  ((tx) ? REG_SSI_STMSK : REG_SSI_SRMSK)
 /*
  * SSI AC97 Channel Status Register
  *
@@ -249,6 +252,7 @@
 #define SSI_SOR_CLKOFF 0x0040
 #define SSI_SOR_RX_CLR 0x0020
 #define SSI_SOR_TX_CLR 0x0010
+#define SSI_SOR_xX_CLR(tx) ((tx) ? SSI_SOR_TX_CLR : SSI_SOR_RX_CLR)
 #define SSI_SOR_INIT   0x0008
 #define SSI_SOR_WAIT_SHIFT 1
 #define SSI_SOR_WAIT_MASK  0x0006
-- 
2.1.4



[PATCH v3 10/11] ASoC: fsl_ssi: Rename i2smode to i2s_net

2017-12-13 Thread Nicolin Chen
Since this i2smode also includes the setting of Network mode, it
should have it in the name. This patch also adds its MASK define.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 24 
 sound/soc/fsl/fsl_ssi.h |  1 +
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 1cdc62a..4a2438c 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -201,7 +201,7 @@ struct fsl_ssi_soc_data {
  * @cpu_dai_drv: CPU DAI driver for this device
  *
  * @dai_fmt: DAI configuration this device is currently used with
- * @i2s_mode: I2S and Network mode configuration of SCR register
+ * @i2s_net: I2S and Network mode configurations of SCR register
  * @use_dma: DMA is used or FIQ with stream filter
  * @use_dual_fifo: DMA with support for dual FIFO mode
  * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree
@@ -245,7 +245,7 @@ struct fsl_ssi {
struct snd_soc_dai_driver cpu_dai_drv;
 
unsigned int dai_fmt;
-   u8 i2s_mode;
+   u8 i2s_net;
bool use_dma;
bool use_dual_fifo;
bool has_ipg_clk_name;
@@ -821,16 +821,16 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
*substream,
}
 
if (!fsl_ssi_is_ac97(ssi)) {
-   u8 i2smode;
+   u8 i2s_net;
/* Normal + Network mode to send 16-bit data in 32-bit frames */
if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16)
-   i2smode = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET;
+   i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET;
else
-   i2smode = ssi->i2s_mode;
+   i2s_net = ssi->i2s_net;
 
regmap_update_bits(regs, REG_SSI_SCR,
-  SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK,
-  channels == 1 ? 0 : i2smode);
+  SSI_SCR_I2S_NET_MASK,
+  channels == 1 ? 0 : i2s_net);
}
 
/* In synchronous mode, the SSI uses STCCR for capture */
@@ -887,7 +887,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
srcr &= ~mask;
 
/* Use Network mode as default */
-   ssi->i2s_mode = SSI_SCR_NET;
+   ssi->i2s_net = SSI_SCR_NET;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
regmap_update_bits(regs, REG_SSI_STCCR,
@@ -897,10 +897,10 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFS:
-   ssi->i2s_mode |= SSI_SCR_I2S_MODE_MASTER;
+   ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFM:
-   ssi->i2s_mode |= SSI_SCR_I2S_MODE_SLAVE;
+   ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE;
break;
default:
return -EINVAL;
@@ -925,12 +925,12 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
break;
case SND_SOC_DAIFMT_AC97:
/* Data on falling edge of bclk, frame high, 1clk before data */
-   ssi->i2s_mode |= SSI_SCR_I2S_MODE_NORMAL;
+   ssi->i2s_net |= SSI_SCR_I2S_MODE_NORMAL;
break;
default:
return -EINVAL;
}
-   scr |= ssi->i2s_mode;
+   scr |= ssi->i2s_net;
 
/* DAI clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 52b88f1..b610087 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -95,6 +95,7 @@
 #define SSI_SCR_I2S_MODE_SLAVE 0x0040
 #define SSI_SCR_SYN0x0010
 #define SSI_SCR_NET0x0008
+#define SSI_SCR_I2S_NET_MASK   (SSI_SCR_NET | SSI_SCR_I2S_MODE_MASK)
 #define SSI_SCR_RE 0x0004
 #define SSI_SCR_TE 0x0002
 #define SSI_SCR_SSIEN  0x0001
-- 
2.1.4



[PATCH v3 09/11] ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals

2017-12-13 Thread Nicolin Chen
The name fsl_ssi_rxtx_reg_val is too long to read comfortably.
So this patch shortens it by using an array (fsl_ssi_regvals,
renamed from fsl_ssi_reg_val). To do that, it also introduces
two macros (TX and RX) to replace the wrapper structure. This
will also help further cleanups.

Meanwhile, it unifies all local variable with the name "vals"
to get rid of the name "reg" -- could be confusing with "regs"
in the private struct for regmap.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 79 +++--
 sound/soc/fsl/fsl_ssi.h |  3 ++
 2 files changed, 40 insertions(+), 42 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 08258c4..1cdc62a 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -106,18 +106,13 @@ enum fsl_ssi_type {
FSL_SSI_MX51,
 };
 
-struct fsl_ssi_reg_val {
+struct fsl_ssi_regvals {
u32 sier;
u32 srcr;
u32 stcr;
u32 scr;
 };
 
-struct fsl_ssi_rxtx_reg_val {
-   struct fsl_ssi_reg_val rx;
-   struct fsl_ssi_reg_val tx;
-};
-
 static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
 {
switch (reg) {
@@ -213,7 +208,7 @@ struct fsl_ssi_soc_data {
  * @fifo_depth: Depth of the SSI FIFOs
  * @slot_width: Width of each DAI slot
  * @slots: Number of slots
- * @rxtx_reg_val: Specific RX/TX register settings
+ * @regvals: Specific RX/TX register settings
  *
  * @clk: Clock source to access register
  * @baudclk: Clock source to generate bit and frame-sync clocks
@@ -257,7 +252,7 @@ struct fsl_ssi {
unsigned int fifo_depth;
unsigned int slot_width;
unsigned int slots;
-   struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
+   struct fsl_ssi_regvals regvals[2];
 
struct clk *clk;
struct clk *baudclk;
@@ -383,25 +378,25 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable)
 {
struct regmap *regs = ssi->regs;
-   struct fsl_ssi_rxtx_reg_val *vals = &ssi->rxtx_reg_val;
+   struct fsl_ssi_regvals *vals = ssi->regvals;
 
if (enable) {
regmap_update_bits(regs, REG_SSI_SIER,
-  vals->rx.sier | vals->tx.sier,
-  vals->rx.sier | vals->tx.sier);
+  vals[RX].sier | vals[TX].sier,
+  vals[RX].sier | vals[TX].sier);
regmap_update_bits(regs, REG_SSI_SRCR,
-  vals->rx.srcr | vals->tx.srcr,
-  vals->rx.srcr | vals->tx.srcr);
+  vals[RX].srcr | vals[TX].srcr,
+  vals[RX].srcr | vals[TX].srcr);
regmap_update_bits(regs, REG_SSI_STCR,
-  vals->rx.stcr | vals->tx.stcr,
-  vals->rx.stcr | vals->tx.stcr);
+  vals[RX].stcr | vals[TX].stcr,
+  vals[RX].stcr | vals[TX].stcr);
} else {
regmap_update_bits(regs, REG_SSI_SRCR,
-  vals->rx.srcr | vals->tx.srcr, 0);
+  vals[RX].srcr | vals[TX].srcr, 0);
regmap_update_bits(regs, REG_SSI_STCR,
-  vals->rx.stcr | vals->tx.stcr, 0);
+  vals[RX].stcr | vals[TX].stcr, 0);
regmap_update_bits(regs, REG_SSI_SIER,
-  vals->rx.sier | vals->tx.sier, 0);
+  vals[RX].sier | vals[TX].sier, 0);
}
 }
 
@@ -443,10 +438,10 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool 
is_rx)
  * Enable or disable SSI configuration.
  */
 static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,
-  struct fsl_ssi_reg_val *vals)
+  struct fsl_ssi_regvals *vals)
 {
struct regmap *regs = ssi->regs;
-   struct fsl_ssi_reg_val *avals;
+   struct fsl_ssi_regvals *avals;
int nr_active_streams;
u32 scr;
int keep_active;
@@ -461,10 +456,10 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool 
enable,
keep_active = 0;
 
/* Get the opposite direction to keep its values untouched */
-   if (&ssi->rxtx_reg_val.rx == vals)
-   avals = &ssi->rxtx_reg_val.tx;
+   if (&ssi->regvals[RX] == vals)
+   avals = &ssi->regvals[TX];
else
-   avals = &ssi->rxtx_reg_val.rx;
+   avals = &ssi->regvals[RX];
 
if (!enable) {
/* Exclude necessary bits for the opposite stream */
@@ -543,7 +538,7 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,
 
 static void fsl_ssi_rx_config(struct

[PATCH v3 08/11] ASoC: fsl_ssi: Rename scr_val to scr

2017-12-13 Thread Nicolin Chen
Simplify the variable name. This reduces one over-80-character line.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 83d6e3d..08258c4 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -448,12 +448,12 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool 
enable,
struct regmap *regs = ssi->regs;
struct fsl_ssi_reg_val *avals;
int nr_active_streams;
-   u32 scr_val;
+   u32 scr;
int keep_active;
 
-   regmap_read(regs, REG_SSI_SCR, &scr_val);
+   regmap_read(regs, REG_SSI_SCR, &scr);
 
-   nr_active_streams = !!(scr_val & SSI_SCR_TE) + !!(scr_val & SSI_SCR_RE);
+   nr_active_streams = !!(scr & SSI_SCR_TE) + !!(scr & SSI_SCR_RE);
 
if (nr_active_streams - 1 > 0)
keep_active = 1;
@@ -795,11 +795,11 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
*substream,
unsigned int sample_size = params_width(hw_params);
u32 wl = SSI_SxCCR_WL(sample_size);
int ret;
-   u32 scr_val;
+   u32 scr;
int enabled;
 
-   regmap_read(regs, REG_SSI_SCR, &scr_val);
-   enabled = scr_val & SSI_SCR_SSIEN;
+   regmap_read(regs, REG_SSI_SCR, &scr);
+   enabled = scr & SSI_SCR_SSIEN;
 
/*
 * SSI is properly configured if it is enabled and running in
-- 
2.1.4



[PATCH v3 07/11] ASoC: fsl_ssi: Rename cpu_dai parameter to dai

2017-12-13 Thread Nicolin Chen
Shortens the variable name to save space, useful for dev_err outputs.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 32 
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 7b6aedd..83d6e3d 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -668,10 +668,10 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream 
*substream,
  *   (In 2-channel I2S Master mode, slot_width is fixed 32)
  */
 static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
-   struct snd_soc_dai *cpu_dai,
+   struct snd_soc_dai *dai,
struct snd_pcm_hw_params *hw_params)
 {
-   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
struct regmap *regs = ssi->regs;
int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret;
u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
@@ -701,7 +701,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
 * never greater than 1/5 IPG clock rate
 */
if (freq * 5 > clk_get_rate(ssi->clk)) {
-   dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n");
+   dev_err(dai->dev, "bitclk > ipgclk / 5\n");
return -EINVAL;
}
 
@@ -750,7 +750,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
 
/* No proper pm found if it is still remaining the initial value */
if (pm == 999) {
-   dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
+   dev_err(dai->dev, "failed to handle the required sysclk\n");
return -EINVAL;
}
 
@@ -766,7 +766,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
if (!baudclk_is_used) {
ret = clk_set_rate(ssi->baudclk, baudrate);
if (ret) {
-   dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
+   dev_err(dai->dev, "failed to set baudclk rate\n");
return -EINVAL;
}
}
@@ -787,9 +787,9 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
  */
 static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
 struct snd_pcm_hw_params *hw_params,
-struct snd_soc_dai *cpu_dai)
+struct snd_soc_dai *dai)
 {
-   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
struct regmap *regs = ssi->regs;
unsigned int channels = params_channels(hw_params);
unsigned int sample_size = params_width(hw_params);
@@ -811,7 +811,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
*substream,
return 0;
 
if (fsl_ssi_is_i2s_master(ssi)) {
-   ret = fsl_ssi_set_bclk(substream, cpu_dai, hw_params);
+   ret = fsl_ssi_set_bclk(substream, dai, hw_params);
if (ret)
return ret;
 
@@ -849,7 +849,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
*substream,
 }
 
 static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
-  struct snd_soc_dai *cpu_dai)
+  struct snd_soc_dai *dai)
 {
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai);
@@ -1018,30 +1018,30 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
 /**
  * Configure Digital Audio Interface (DAI) Format
  */
-static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
 
/* AC97 configured DAIFMT earlier in the probe() */
if (fsl_ssi_is_ac97(ssi))
return 0;
 
-   return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi, fmt);
+   return _fsl_ssi_set_dai_fmt(dai->dev, ssi, fmt);
 }
 
 /**
  * Set TDM slot number and slot width
  */
-static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
u32 rx_mask, int slots, int slot_width)
 {
-   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
+   struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai);
struct regmap *regs = ssi->regs;
u32 val;
 
/* The word length should be 8, 10, 12, 16, 18, 20, 22 or 24 */
if (slot_width & 1 || slot_width < 8 || slot_width > 24) {
-   dev_err(cp

[PATCH v3 05/11] ASoC: fsl_ssi: Refine indentations and wrappings

2017-12-13 Thread Nicolin Chen
This patch just simply unifies the coding style.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 239 +---
 sound/soc/fsl/fsl_ssi.h |   2 +-
 sound/soc/fsl/fsl_ssi_dbg.c |   3 +-
 3 files changed, 118 insertions(+), 126 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index ce6c945..a3b9116 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -69,21 +69,35 @@
  * samples will be written to STX properly.
  */
 #ifdef __BIG_ENDIAN
-#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
-SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
-SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
+#define FSLSSI_I2S_FORMATS \
+   (SNDRV_PCM_FMTBIT_S8 | \
+SNDRV_PCM_FMTBIT_S16_BE | \
+SNDRV_PCM_FMTBIT_S18_3BE | \
+SNDRV_PCM_FMTBIT_S20_3BE | \
+SNDRV_PCM_FMTBIT_S24_3BE | \
+SNDRV_PCM_FMTBIT_S24_BE)
 #else
-#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
-SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
-SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+#define FSLSSI_I2S_FORMATS \
+   (SNDRV_PCM_FMTBIT_S8 | \
+SNDRV_PCM_FMTBIT_S16_LE | \
+SNDRV_PCM_FMTBIT_S18_3LE | \
+SNDRV_PCM_FMTBIT_S20_3LE | \
+SNDRV_PCM_FMTBIT_S24_3LE | \
+SNDRV_PCM_FMTBIT_S24_LE)
 #endif
 
-#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \
-   SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \
-   SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN)
-#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \
-   SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \
-   SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN)
+#define FSLSSI_SIER_DBG_RX_FLAGS \
+   (SSI_SIER_RFF0_EN | \
+SSI_SIER_RLS_EN | \
+SSI_SIER_RFS_EN | \
+SSI_SIER_ROE0_EN | \
+SSI_SIER_RFRC_EN)
+#define FSLSSI_SIER_DBG_TX_FLAGS \
+   (SSI_SIER_TFE0_EN | \
+SSI_SIER_TLS_EN | \
+SSI_SIER_TFS_EN | \
+SSI_SIER_TUE0_EN | \
+SSI_SIER_TFRC_EN)
 
 enum fsl_ssi_type {
FSL_SSI_MCP8610,
@@ -291,8 +305,8 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = {
.imx = false,
.offline_config = true,
.sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC |
-   SSI_SISR_ROE0 | SSI_SISR_ROE1 |
-   SSI_SISR_TUE0 | SSI_SISR_TUE1,
+  SSI_SISR_ROE0 | SSI_SISR_ROE1 |
+  SSI_SISR_TUE0 | SSI_SISR_TUE1,
 };
 
 static struct fsl_ssi_soc_data fsl_ssi_imx21 = {
@@ -306,15 +320,15 @@ static struct fsl_ssi_soc_data fsl_ssi_imx35 = {
.imx = true,
.offline_config = true,
.sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC |
-   SSI_SISR_ROE0 | SSI_SISR_ROE1 |
-   SSI_SISR_TUE0 | SSI_SISR_TUE1,
+  SSI_SISR_ROE0 | SSI_SISR_ROE1 |
+  SSI_SISR_TUE0 | SSI_SISR_TUE1,
 };
 
 static struct fsl_ssi_soc_data fsl_ssi_imx51 = {
.imx = true,
.offline_config = false,
.sisr_write_mask = SSI_SISR_ROE0 | SSI_SISR_ROE1 |
-   SSI_SISR_TUE0 | SSI_SISR_TUE1,
+  SSI_SISR_TUE0 | SSI_SISR_TUE1,
 };
 
 static const struct of_device_id fsl_ssi_ids[] = {
@@ -373,21 +387,21 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool 
enable)
 
if (enable) {
regmap_update_bits(regs, REG_SSI_SIER,
-   vals->rx.sier | vals->tx.sier,
-   vals->rx.sier | vals->tx.sier);
+  vals->rx.sier | vals->tx.sier,
+  vals->rx.sier | vals->tx.sier);
regmap_update_bits(regs, REG_SSI_SRCR,
-   vals->rx.srcr | vals->tx.srcr,
-   vals->rx.srcr | vals->tx.srcr);
+  vals->rx.srcr | vals->tx.srcr,
+  vals->rx.srcr | vals->tx.srcr);
regmap_update_bits(regs, REG_SSI_STCR,
-   vals->rx.stcr | vals->tx.stcr,
-   vals->rx.stcr | vals->tx.stcr);
+  vals->rx.stcr | vals->tx.stcr,
+  vals->rx.stcr | vals->tx.stcr);
} else {
regmap_update_bits(regs, REG_SSI_SRCR,
-   vals->rx.srcr | vals->tx.srcr, 0);
+  vals->rx.srcr | vals->tx.srcr, 0);
regmap_update_bits(regs, REG_SSI_STCR,
-   vals->rx.stcr | vals->tx.stcr, 0);
+  vals->rx.stcr | vals->tx.stcr, 0);
regmap_update_bits(regs, REG_SSI_SIER,
-  

[PATCH v3 06/11] ASoC: fsl_ssi: Refine printk outputs

2017-12-13 Thread Nicolin Chen
This patches unifies the error message in the "failed to " format.

It also reduces the length of one line and adds spaces to an operator.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index a3b9116..7b6aedd 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -701,7 +701,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream 
*substream,
 * never greater than 1/5 IPG clock rate
 */
if (freq * 5 > clk_get_rate(ssi->clk)) {
-   dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n");
+   dev_err(cpu_dai->dev, "bitclk > ipgclk / 5\n");
return -EINVAL;
}
 
@@ -873,7 +873,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
ssi->dai_fmt = fmt;
 
if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) {
-   dev_err(dev, "baudclk is missing which is necessary for master 
mode\n");
+   dev_err(dev, "missing baudclk for master mode\n");
return -EINVAL;
}
 
@@ -1289,7 +1289,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
ssi->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ssi->clk)) {
ret = PTR_ERR(ssi->clk);
-   dev_err(dev, "could not get clock: %d\n", ret);
+   dev_err(dev, "failed to get clock: %d\n", ret);
return ret;
}
 
@@ -1305,7 +1305,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
/* Do not error out for slave cases that live without a baud clock */
ssi->baudclk = devm_clk_get(dev, "baud");
if (IS_ERR(ssi->baudclk))
-   dev_dbg(dev, "could not get baud clock: %ld\n",
+   dev_dbg(dev, "failed to get baud clock: %ld\n",
 PTR_ERR(ssi->baudclk));
 
ssi->dma_params_tx.maxburst = ssi->dma_maxburst;
@@ -1426,7 +1426,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
  ®config);
}
if (IS_ERR(ssi->regs)) {
-   dev_err(dev, "Failed to init register map\n");
+   dev_err(dev, "failed to init register map\n");
return PTR_ERR(ssi->regs);
}
 
@@ -1485,7 +1485,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
mutex_init(&ssi->ac97_reg_lock);
ret = snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
if (ret) {
-   dev_err(dev, "could not set AC'97 ops\n");
+   dev_err(dev, "failed to set AC'97 ops\n");
goto error_ac97_ops;
}
}
@@ -1501,7 +1501,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, ssi->irq, fsl_ssi_isr, 0,
   dev_name(dev), ssi);
if (ret < 0) {
-   dev_err(dev, "could not claim irq %u\n", ssi->irq);
+   dev_err(dev, "failed to claim irq %u\n", ssi->irq);
goto error_asoc_register;
}
}
@@ -1543,7 +1543,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
ret = of_property_read_u32(np, "cell-index", &ssi_idx);
if (ret) {
-   dev_err(dev, "cannot get SSI index property\n");
+   dev_err(dev, "failed to get SSI index property\n");
goto error_sound_card;
}
 
-- 
2.1.4



[PATCH v3 04/11] ASoC: fsl_ssi: Rename registers and fields macros

2017-12-13 Thread Nicolin Chen
This patch renames CCSR_SSI_xxx to REG_SSI_xxx and SSI_xxx_yyy style.
It also slightly reduces the length of them to save some space.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 374 +--
 sound/soc/fsl/fsl_ssi.h | 376 ++--
 sound/soc/fsl/fsl_ssi_dbg.c |  44 +++---
 3 files changed, 397 insertions(+), 397 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index fe11a23..ce6c945 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -78,12 +78,12 @@
 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
 #endif
 
-#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \
-   CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \
-   CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN)
-#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
-   CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
-   CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
+#define FSLSSI_SIER_DBG_RX_FLAGS (SSI_SIER_RFF0_EN | \
+   SSI_SIER_RLS_EN | SSI_SIER_RFS_EN | \
+   SSI_SIER_ROE0_EN | SSI_SIER_RFRC_EN)
+#define FSLSSI_SIER_DBG_TX_FLAGS (SSI_SIER_TFE0_EN | \
+   SSI_SIER_TLS_EN | SSI_SIER_TFS_EN | \
+   SSI_SIER_TUE0_EN | SSI_SIER_TFRC_EN)
 
 enum fsl_ssi_type {
FSL_SSI_MCP8610,
@@ -107,8 +107,8 @@ struct fsl_ssi_rxtx_reg_val {
 static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
 {
switch (reg) {
-   case CCSR_SSI_SACCEN:
-   case CCSR_SSI_SACCDIS:
+   case REG_SSI_SACCEN:
+   case REG_SSI_SACCDIS:
return false;
default:
return true;
@@ -118,18 +118,18 @@ static bool fsl_ssi_readable_reg(struct device *dev, 
unsigned int reg)
 static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg)
 {
switch (reg) {
-   case CCSR_SSI_STX0:
-   case CCSR_SSI_STX1:
-   case CCSR_SSI_SRX0:
-   case CCSR_SSI_SRX1:
-   case CCSR_SSI_SISR:
-   case CCSR_SSI_SFCSR:
-   case CCSR_SSI_SACNT:
-   case CCSR_SSI_SACADD:
-   case CCSR_SSI_SACDAT:
-   case CCSR_SSI_SATAG:
-   case CCSR_SSI_SACCST:
-   case CCSR_SSI_SOR:
+   case REG_SSI_STX0:
+   case REG_SSI_STX1:
+   case REG_SSI_SRX0:
+   case REG_SSI_SRX1:
+   case REG_SSI_SISR:
+   case REG_SSI_SFCSR:
+   case REG_SSI_SACNT:
+   case REG_SSI_SACADD:
+   case REG_SSI_SACDAT:
+   case REG_SSI_SATAG:
+   case REG_SSI_SACCST:
+   case REG_SSI_SOR:
return true;
default:
return false;
@@ -139,12 +139,12 @@ static bool fsl_ssi_volatile_reg(struct device *dev, 
unsigned int reg)
 static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg)
 {
switch (reg) {
-   case CCSR_SSI_SRX0:
-   case CCSR_SSI_SRX1:
-   case CCSR_SSI_SISR:
-   case CCSR_SSI_SACADD:
-   case CCSR_SSI_SACDAT:
-   case CCSR_SSI_SATAG:
+   case REG_SSI_SRX0:
+   case REG_SSI_SRX1:
+   case REG_SSI_SISR:
+   case REG_SSI_SACADD:
+   case REG_SSI_SACDAT:
+   case REG_SSI_SATAG:
return true;
default:
return false;
@@ -154,9 +154,9 @@ static bool fsl_ssi_precious_reg(struct device *dev, 
unsigned int reg)
 static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg)
 {
switch (reg) {
-   case CCSR_SSI_SRX0:
-   case CCSR_SSI_SRX1:
-   case CCSR_SSI_SACCST:
+   case REG_SSI_SRX0:
+   case REG_SSI_SRX1:
+   case REG_SSI_SACCST:
return false;
default:
return true;
@@ -164,12 +164,12 @@ static bool fsl_ssi_writeable_reg(struct device *dev, 
unsigned int reg)
 }
 
 static const struct regmap_config fsl_ssi_regconfig = {
-   .max_register = CCSR_SSI_SACCDIS,
+   .max_register = REG_SSI_SACCDIS,
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
-   .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1,
+   .num_reg_defaults_raw = REG_SSI_SACCDIS / sizeof(uint32_t) + 1,
.readable_reg = fsl_ssi_readable_reg,
.volatile_reg = fsl_ssi_volatile_reg,
.precious_reg = fsl_ssi_precious_reg,
@@ -290,9 +290,9 @@ struct fsl_ssi {
 static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = {
.imx = false,
.offline_config = true,
-   .sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC |
-   CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
-   CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1,
+   .sisr_write_mask = SSI_SISR_RFRC | SSI_SISR_TFRC |
+   SSI_SISR_ROE0 | SSI_SISR_ROE1 |
+   SSI_SISR_TUE0 | SSI_SISR_TUE1,
 };
 
 static struct fs

[PATCH v3 03/11] ASoC: fsl_ssi: Refine all comments

2017-12-13 Thread Nicolin Chen
This patch refines the comments by:
1) Removing all out-of-date comments
2) Removing all not-so-useful comments
3) Unifying the styles of all comments
4) Simplifying over-descriptive comments
5) Adding comments to improve code readablity
6) Moving all register related comments to fsl_ssi.h
7) Adding comments to all register and field defines

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---

Changelog
v2->v3
 * Revised a comment in hw_params() by taking Maciej's advice
v1->v2
 * Added some new comments at "SoC specific data" to be more precise
 * Revised one comment in fsl_ssi_config()
 * Revised the comment of fsl_ssi_setup_reg_vals()
 * Added one comment for AC97 in fsl_ssi_setup_reg_vals()
 * Revised the comment of fsl_ssi_hw_params() to be more precise
 * Added some comments in _fsl_ssi_set_dai_fmt() to help understand
   the formats
 * Added one comment in fsl_ssi_set_dai_fmt() to explain why AC97
   needs to bypass it
 * Revised comments in fsl_ssi_set_dai_tdm_slot() to be more precise
 * Revised comments around dual FIFO code in fsl_ssi_imx_probe() to
   be more precise

 sound/soc/fsl/fsl_ssi.c | 377 +++-
 sound/soc/fsl/fsl_ssi.h |  67 +++-
 sound/soc/fsl/fsl_ssi_dbg.c |  12 +-
 3 files changed, 191 insertions(+), 265 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index e903c92..fe11a23 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -187,42 +187,48 @@ struct fsl_ssi_soc_data {
 /**
  * fsl_ssi: per-SSI private data
  *
- * @reg: Pointer to the regmap registers
+ * @regs: Pointer to the regmap registers
  * @irq: IRQ of this SSI
  * @cpu_dai_drv: CPU DAI driver for this device
  *
  * @dai_fmt: DAI configuration this device is currently used with
- * @i2s_mode: i2s and network mode configuration of the device. Is used to
- * switch between normal and i2s/network mode
- * mode depending on the number of channels
+ * @i2s_mode: I2S and Network mode configuration of SCR register
  * @use_dma: DMA is used or FIQ with stream filter
- * @use_dual_fifo: DMA with support for both FIFOs used
- * @fifo_deph: Depth of the SSI FIFOs
- * @slot_width: width of each DAI slot
- * @slots: number of slots
- * @rxtx_reg_val: Specific register settings for receive/transmit configuration
+ * @use_dual_fifo: DMA with support for dual FIFO mode
+ * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree
+ * @fifo_depth: Depth of the SSI FIFOs
+ * @slot_width: Width of each DAI slot
+ * @slots: Number of slots
+ * @rxtx_reg_val: Specific RX/TX register settings
  *
- * @clk: SSI clock
- * @baudclk: SSI baud clock for master mode
+ * @clk: Clock source to access register
+ * @baudclk: Clock source to generate bit and frame-sync clocks
  * @baudclk_streams: Active streams that are using baudclk
  *
+ * @regcache_sfcsr: Cache sfcsr register value during suspend and resume
+ * @regcache_sacnt: Cache sacnt register value during suspend and resume
+ *
  * @dma_params_tx: DMA transmit parameters
  * @dma_params_rx: DMA receive parameters
  * @ssi_phys: physical address of the SSI registers
  *
  * @fiq_params: FIQ stream filtering parameters
  *
- * @pdev: Pointer to pdev used for deprecated fsl-ssi sound card
+ * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only)
+ *TODO: Should be replaced with simple-sound-card
  *
  * @dbg_stats: Debugging statistics
  *
  * @soc: SoC specific data
+ * @dev: Pointer to &pdev->dev
+ *
+ * @fifo_watermark: The FIFO watermark setting. Notifies DMA when there are
+ *  @fifo_watermark or fewer words in TX fifo or
+ *  @fifo_watermark or more empty words in RX fifo.
+ * @dma_maxburst: Max number of words to transfer in one go. So far,
+ *this is always the same as fifo_watermark.
  *
- * @fifo_watermark: the FIFO watermark setting.  Notifies DMA when
- * there are @fifo_watermark or fewer words in TX fifo or
- * @fifo_watermark or more empty words in RX fifo.
- * @dma_maxburst: max number of words to transfer in one go.  So far,
- * this is always the same as fifo_watermark.
+ * @ac97_reg_lock: Mutex lock to serialize AC97 register access operations
  */
 struct fsl_ssi {
struct regmap *regs;
@@ -243,20 +249,15 @@ struct fsl_ssi {
struct clk *baudclk;
unsigned int baudclk_streams;
 
-   /* regcache for volatile regs */
u32 regcache_sfcsr;
u32 regcache_sacnt;
 
-   /* DMA params */
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
dma_addr_t ssi_phys;
 
-   /* params for non-dma FIQ stream filtered mode */
struct imx_pcm_fiq_params fiq_params;
 
-   /* Used when using fsl-ssi as sound-card. This is only used by ppc and
-* should be replaced with simple-sound-card. */
struct platf

[PATCH v3 02/11] ASoC: fsl_ssi: Cache pdev->dev pointer

2017-12-13 Thread Nicolin Chen
There should be no trouble to understand dev = pdev->dev.
This can save some space to have more print info or save
some wrapped lines.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 64 -
 1 file changed, 31 insertions(+), 33 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 84d2f7e..e903c92 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1379,23 +1379,24 @@ static int fsl_ssi_imx_probe(struct platform_device 
*pdev,
struct fsl_ssi *ssi, void __iomem *iomem)
 {
struct device_node *np = pdev->dev.of_node;
+   struct device *dev = &pdev->dev;
u32 dmas[4];
int ret;
 
if (ssi->has_ipg_clk_name)
-   ssi->clk = devm_clk_get(&pdev->dev, "ipg");
+   ssi->clk = devm_clk_get(dev, "ipg");
else
-   ssi->clk = devm_clk_get(&pdev->dev, NULL);
+   ssi->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ssi->clk)) {
ret = PTR_ERR(ssi->clk);
-   dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+   dev_err(dev, "could not get clock: %d\n", ret);
return ret;
}
 
if (!ssi->has_ipg_clk_name) {
ret = clk_prepare_enable(ssi->clk);
if (ret) {
-   dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", 
ret);
+   dev_err(dev, "clk_prepare_enable failed: %d\n", ret);
return ret;
}
}
@@ -1403,9 +1404,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
/* For those SLAVE implementations, we ignore non-baudclk cases
 * and, instead, abandon MASTER mode that needs baud clock.
 */
-   ssi->baudclk = devm_clk_get(&pdev->dev, "baud");
+   ssi->baudclk = devm_clk_get(dev, "baud");
if (IS_ERR(ssi->baudclk))
-   dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
+   dev_dbg(dev, "could not get baud clock: %ld\n",
 PTR_ERR(ssi->baudclk));
 
ssi->dma_params_tx.maxburst = ssi->dma_maxburst;
@@ -1469,6 +1470,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
struct fsl_ssi *ssi;
int ret = 0;
struct device_node *np = pdev->dev.of_node;
+   struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
const char *p, *sprop;
const uint32_t *iprop;
@@ -1477,17 +1479,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
char name[64];
struct regmap_config regconfig = fsl_ssi_regconfig;
 
-   of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
+   of_id = of_match_device(fsl_ssi_ids, dev);
if (!of_id || !of_id->data)
return -EINVAL;
 
-   ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi),
-   GFP_KERNEL);
+   ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL);
if (!ssi)
return -ENOMEM;
 
ssi->soc = of_id->data;
-   ssi->dev = &pdev->dev;
+   ssi->dev = dev;
 
sprop = of_get_property(np, "fsl,mode", NULL);
if (sprop) {
@@ -1507,10 +1508,10 @@ static int fsl_ssi_probe(struct platform_device *pdev)
memcpy(&ssi->cpu_dai_drv, &fsl_ssi_dai_template,
   sizeof(fsl_ssi_dai_template));
}
-   ssi->cpu_dai_drv.name = dev_name(&pdev->dev);
+   ssi->cpu_dai_drv.name = dev_name(dev);
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-   iomem = devm_ioremap_resource(&pdev->dev, res);
+   iomem = devm_ioremap_resource(dev, res);
if (IS_ERR(iomem))
return PTR_ERR(iomem);
ssi->ssi_phys = res->start;
@@ -1528,21 +1529,20 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ret = of_property_match_string(np, "clock-names", "ipg");
if (ret < 0) {
ssi->has_ipg_clk_name = false;
-   ssi->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
-   ®config);
+   ssi->regs = devm_regmap_init_mmio(dev, iomem, ®config);
} else {
ssi->has_ipg_clk_name = true;
-   ssi->regs = devm_regmap_init_mmio_clk(&pdev->dev,
-   "ipg", iomem, ®config);
+   ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem,
+ ®config);
}
if (IS_ERR(ssi->regs)) {
-   dev_err(&pdev->dev, "Failed to init register map\n");
+   dev_err(dev, "Failed to init register map\n");
return PTR_ERR(ssi->regs);
}
 
ssi->irq = platform_get_irq(pdev, 0);
if (ssi->irq < 0) {
-   dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+   dev_err(

[PATCH v3 01/11] ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi

2017-12-13 Thread Nicolin Chen
Shorten the private data structure to save some wrapped lines.

Signed-off-by: Nicolin Chen 
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 
---
 sound/soc/fsl/fsl_ssi.c | 456 +++-
 1 file changed, 220 insertions(+), 236 deletions(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index c350117..84d2f7e 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -185,7 +185,7 @@ struct fsl_ssi_soc_data {
 };
 
 /**
- * fsl_ssi_private: per-SSI private data
+ * fsl_ssi: per-SSI private data
  *
  * @reg: Pointer to the regmap registers
  * @irq: IRQ of this SSI
@@ -224,7 +224,7 @@ struct fsl_ssi_soc_data {
  * @dma_maxburst: max number of words to transfer in one go.  So far,
  * this is always the same as fifo_watermark.
  */
-struct fsl_ssi_private {
+struct fsl_ssi {
struct regmap *regs;
int irq;
struct snd_soc_dai_driver cpu_dai_drv;
@@ -325,21 +325,21 @@ static const struct of_device_id fsl_ssi_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
 
-static bool fsl_ssi_is_ac97(struct fsl_ssi_private *ssi_private)
+static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi)
 {
-   return (ssi_private->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
+   return (ssi->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) ==
SND_SOC_DAIFMT_AC97;
 }
 
-static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
+static bool fsl_ssi_is_i2s_master(struct fsl_ssi *ssi)
 {
-   return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+   return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
SND_SOC_DAIFMT_CBS_CFS;
 }
 
-static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
+static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi)
 {
-   return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+   return (ssi->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
SND_SOC_DAIFMT_CBM_CFS;
 }
 /**
@@ -352,12 +352,12 @@ static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private 
*ssi_private)
  * This interrupt handler is used only to gather statistics.
  *
  * @irq: IRQ of the SSI device
- * @dev_id: pointer to the ssi_private structure for this SSI device
+ * @dev_id: pointer to the fsl_ssi structure for this SSI device
  */
 static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 {
-   struct fsl_ssi_private *ssi_private = dev_id;
-   struct regmap *regs = ssi_private->regs;
+   struct fsl_ssi *ssi = dev_id;
+   struct regmap *regs = ssi->regs;
__be32 sisr;
__be32 sisr2;
 
@@ -367,12 +367,12 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 */
regmap_read(regs, CCSR_SSI_SISR, &sisr);
 
-   sisr2 = sisr & ssi_private->soc->sisr_write_mask;
+   sisr2 = sisr & ssi->soc->sisr_write_mask;
/* Clear the bits that we set */
if (sisr2)
regmap_write(regs, CCSR_SSI_SISR, sisr2);
 
-   fsl_ssi_dbg_isr(&ssi_private->dbg_stats, sisr);
+   fsl_ssi_dbg_isr(&ssi->dbg_stats, sisr);
 
return IRQ_HANDLED;
 }
@@ -380,11 +380,10 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
 /*
  * Enable/Disable all rx/tx config flags at once.
  */
-static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
-   bool enable)
+static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable)
 {
-   struct regmap *regs = ssi_private->regs;
-   struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
+   struct regmap *regs = ssi->regs;
+   struct fsl_ssi_rxtx_reg_val *vals = &ssi->rxtx_reg_val;
 
if (enable) {
regmap_update_bits(regs, CCSR_SSI_SIER,
@@ -414,14 +413,13 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private 
*ssi_private,
  * Note: The SOR is not documented in recent IMX datasheet, but
  * is described in IMX51 reference manual at section 56.3.3.15.
  */
-static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private,
-   bool is_rx)
+static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx)
 {
if (is_rx) {
-   regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR,
+   regmap_update_bits(ssi->regs, CCSR_SSI_SOR,
CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR);
} else {
-   regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR,
+   regmap_update_bits(ssi->regs, CCSR_SSI_SOR,
CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR);
}
 }
@@ -448,12 +446,12 @@ static void fsl_ssi_fifo_clear(struct fsl_ssi_private 
*ssi_private,
 
 /*
  * Enable/Disable a ssi configuration. You have to pass either
- * ssi_private->rxtx_reg_val.rx or tx as vals parameter.
+ * ssi->rxtx_reg_val.rx or tx as vals parameter.
  */
-static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
+static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable,
 

[PATCH v3 00/11] ASoC: fsl_ssi: Clean up - coding style level

2017-12-13 Thread Nicolin Chen
==Changelog==
v2->v3
 * Added Tested-by and Reviewed-by from Maciej
 * Revised PATCH-03 "Refine all comments" by adding Maciej advice
 * Revised PATCH-05 "Refine indentations and wrappings"
v1->v2
 * Dropped one patch to remove "struct device"
 * Revised PATCH-03 "Refine all comments"
 * Revised PATCH-05 "Refine indentations and wrappings"
 * Rebased all other patches
 * Added PATCH-10 "Rename i2smode to i2s_net"
 * Added PATCH-11 "Define ternary macros to simplify code"

 # Detialed changes are described in each updated patch.

==Background==
The fsl_ssi driver was designed for PPC originally and then it has
been updated to support different modes for i.MX Series, including
SDMA, I2S Master mode, AC97 and older i.MXs with FIQ, by different
contributors for different use cases in different coding styles.

Additionally, in order to fix/work-around hardware bugs and design
flaws, the driver made a lot of compromise so now its program flow
looks very complicated and it's getting hard to maintain or update.

So I am going to clean up the driver on both coding style level and
program flow level.

==Introduction==
This series of patches is the first set to clean up fsl_ssi driver
in the coding style level. Any patch here is not supposed to change
the program flow.

==Verification==
Theoretically, since these patches do not change program flow, they
only need code review, build or sanity tests. I have done build and
sanity tests on an i.MX6SoloX with WM8962 using imx_v6_v7_defconfig
and playback/record tests in I2S Master/Slave modes.

Nicolin Chen (11):
  ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi
  ASoC: fsl_ssi: Cache pdev->dev pointer
  ASoC: fsl_ssi: Refine all comments
  ASoC: fsl_ssi: Rename registers and fields macros
  ASoC: fsl_ssi: Refine indentations and wrappings
  ASoC: fsl_ssi: Refine printk outputs
  ASoC: fsl_ssi: Rename cpu_dai parameter to dai
  ASoC: fsl_ssi: Rename scr_val to scr
  ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals
  ASoC: fsl_ssi: Rename i2smode to i2s_net
  ASoC: fsl_ssi: Define ternary macros to simplify code

 sound/soc/fsl/fsl_ssi.c | 1374 +++
 sound/soc/fsl/fsl_ssi.h |  427 --
 sound/soc/fsl/fsl_ssi_dbg.c |   59 +-
 3 files changed, 879 insertions(+), 981 deletions(-)

-- 
2.1.4



Re: [PATCH v2 00/11] ASoC: fsl_ssi: Clean up - coding style level

2017-12-13 Thread Maciej S. Szmigiero
On 13.12.2017 07:34, Nicolin Chen wrote:
> ==Changelog==
> v1->v2
>  * Dropped one patch to remove "struct device"
>  * Revised PATCH-03 "Refine all comments"
>  * Revised PATCH-05 "Refine indentations and wrappings"
>  * Rebased all other patches
>  * Added PATCH-10 "Rename i2smode to i2s_net"
>  * Added PATCH-11 "Define ternary macros to simplify code"
> 
>  # Detialed changes are described in each updated patch.
> 
> ==Background==
> The fsl_ssi driver was designed for PPC originally and then it has
> been updated to support different modes for i.MX Series, including
> SDMA, I2S Master mode, AC97 and older i.MXs with FIQ, by different
> contributors for different use cases in different coding styles.
> 
> Additionally, in order to fix/work-around hardware bugs and design
> flaws, the driver made a lot of compromise so now its program flow
> looks very complicated and it's getting hard to maintain or update.
> 
> So I am going to clean up the driver on both coding style level and
> program flow level.
> 
> ==Introduction==
> This series of patches is the first set to clean up fsl_ssi driver
> in the coding style level. Any patch here is not supposed to change
> the program flow.
> 
> ==Verification==
> Theoretically, since these patches do not change program flow, they
> only need code review, build or sanity tests. I have done build and
> sanity tests on an i.MX6SoloX with WM8962 using imx_v6_v7_defconfig
> and playback/record tests in I2S Master/Slave modes.
> 
> Nicolin Chen (11):
>   ASoC: fsl_ssi: Rename fsl_ssi_private to fsl_ssi
>   ASoC: fsl_ssi: Cache pdev->dev pointer
>   ASoC: fsl_ssi: Refine all comments
>   ASoC: fsl_ssi: Rename registers and fields macros
>   ASoC: fsl_ssi: Refine indentations and wrappings
>   ASoC: fsl_ssi: Refine printk outputs
>   ASoC: fsl_ssi: Rename cpu_dai parameter to dai
>   ASoC: fsl_ssi: Rename scr_val to scr
>   ASoC: fsl_ssi: Replace fsl_ssi_rxtx_reg_val with fsl_ssi_regvals
>   ASoC: fsl_ssi: Rename i2smode to i2s_net
>   ASoC: fsl_ssi: Define ternary macros to simplify code
> 
>  sound/soc/fsl/fsl_ssi.c | 1373 
> +++
>  sound/soc/fsl/fsl_ssi.h |  427 --
>  sound/soc/fsl/fsl_ssi_dbg.c |   59 +-
>  3 files changed, 876 insertions(+), 983 deletions(-)
> 

For the whole series:
Tested-by: Maciej S. Szmigiero 
Reviewed-by: Maciej S. Szmigiero 

Thanks.


Re: [PATCH v2 03/11] ASoC: fsl_ssi: Refine all comments

2017-12-13 Thread Nicolin Chen
On Wed, Dec 13, 2017 at 11:28:51PM +0100, Maciej S. Szmigiero wrote:

> > -   /*
> > -* If we're in synchronous mode, and the SSI is already enabled,
> > -* then STCCR is already set properly.
> > -*/
> > +   /* To support simultaneous TX and RX, bypass it if SSI is enabled */
> > if (enabled && ssi->cpu_dai_drv.symmetric_rates)
> > return 0;
> >  
> 
> I would say that the old comment described better what is happening -
> since in synchronous (& non-AC'97) mode STCCR controls both TX and RX
> the first direction that is started (either playback or capture) is the
> only direction that needs to configure SSI in hw_params().

There is also an SCR register configuration in this hw_params(),
so the old comment has to be updated. But I would take it into
consideration and revise a bit.

Thanks.


Re: [PATCH v2 05/11] ASoC: fsl_ssi: Refine indentations and wrappings

2017-12-13 Thread Nicolin Chen
On Wed, Dec 13, 2017 at 11:30:31PM +0100, Maciej S. Szmigiero wrote:
> On 13.12.2017 07:34, Nicolin Chen wrote:
> > This patch just simply unifies the coding style.
> > 
> > Signed-off-by: Nicolin Chen 
> > ---
> > 
> > Changelog
> > v1->v2
> >  * Added two missing indentation changes
> >  * Removed two extra blank lines.
> > 
> >  sound/soc/fsl/fsl_ssi.c | 239 
> > +---
> >  sound/soc/fsl/fsl_ssi.h |   2 +-
> >  sound/soc/fsl/fsl_ssi_dbg.c |   3 +-
> >  3 files changed, 118 insertions(+), 126 deletions(-)
> > 
> > diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
> > index 8b5407d..9a3db08 100644
> > --- a/sound/soc/fsl/fsl_ssi.c
> > +++ b/sound/soc/fsl/fsl_ssi.c
> (..)
> > @@ -916,12 +917,11 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
> > case SND_SOC_DAIFMT_DSP_A:
> > /* Data on rising edge of bclk, frame high, 1clk before data */
> > strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |
> > -   SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
> > +SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
> > break;
> > case SND_SOC_DAIFMT_DSP_B:
> > /* Data on rising edge of bclk, frame high */
> > -   strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |
> > -   SSI_STCR_TXBIT0;
> > +   strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |  SSI_STCR_TXBIT0;
> 
> It looks like an extra space got here  ^.

Good catch.

Thanks


Re: [PATCH v2 05/11] ASoC: fsl_ssi: Refine indentations and wrappings

2017-12-13 Thread Maciej S. Szmigiero
On 13.12.2017 07:34, Nicolin Chen wrote:
> This patch just simply unifies the coding style.
> 
> Signed-off-by: Nicolin Chen 
> ---
> 
> Changelog
> v1->v2
>  * Added two missing indentation changes
>  * Removed two extra blank lines.
> 
>  sound/soc/fsl/fsl_ssi.c | 239 
> +---
>  sound/soc/fsl/fsl_ssi.h |   2 +-
>  sound/soc/fsl/fsl_ssi_dbg.c |   3 +-
>  3 files changed, 118 insertions(+), 126 deletions(-)
> 
> diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
> index 8b5407d..9a3db08 100644
> --- a/sound/soc/fsl/fsl_ssi.c
> +++ b/sound/soc/fsl/fsl_ssi.c
(..)
> @@ -916,12 +917,11 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
>   case SND_SOC_DAIFMT_DSP_A:
>   /* Data on rising edge of bclk, frame high, 1clk before data */
>   strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |
> - SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
> +  SSI_STCR_TXBIT0 | SSI_STCR_TEFS;
>   break;
>   case SND_SOC_DAIFMT_DSP_B:
>   /* Data on rising edge of bclk, frame high */
> - strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |
> - SSI_STCR_TXBIT0;
> + strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP |  SSI_STCR_TXBIT0;

It looks like an extra space got here^.

Maciej


Re: [PATCH v2 03/11] ASoC: fsl_ssi: Refine all comments

2017-12-13 Thread Maciej S. Szmigiero
On 13.12.2017 07:34, Nicolin Chen wrote:
> This patch refines the comments by:
> 1) Removing all out-of-date comments
> 2) Removing all not-so-useful comments
> 3) Unifying the styles of all comments
> 4) Simplifying over-descriptive comments
> 5) Adding comments to improve code readablity
> 6) Moving all register related comments to fsl_ssi.h
> 7) Adding comments to all register and field defines
> 
> Signed-off-by: Nicolin Chen 
> ---
> 
> Changelog
> v1->v2
>  * Added some new comments at "SoC specific data" to be more precise.
>  * Revised one comment in fsl_ssi_config().
>  * Revised the comment of fsl_ssi_setup_reg_vals().
>  * Added one comment for AC97 in fsl_ssi_setup_reg_vals().
>  * Revised the comment of fsl_ssi_hw_params() to be more precise.
>  * Added some comments in _fsl_ssi_set_dai_fmt() to help understand the 
> formats.
>  * Added one comment in fsl_ssi_set_dai_fmt() to state why AC97 needs to 
> bypass it.
>  * Revised comments in fsl_ssi_set_dai_tdm_slot() to be more precise.
>  * Revised comments around dual FIFO code in fsl_ssi_imx_probe() to be more 
> precise.
> 
>  sound/soc/fsl/fsl_ssi.c | 376 
> ++--
>  sound/soc/fsl/fsl_ssi.h |  67 +++-
>  sound/soc/fsl/fsl_ssi_dbg.c |  12 +-
>  3 files changed, 188 insertions(+), 267 deletions(-)
> 
> diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
> index e903c92..796a7ea 100644
> --- a/sound/soc/fsl/fsl_ssi.c
> +++ b/sound/soc/fsl/fsl_ssi.c
(..)
> @@ -878,10 +794,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream 
> *substream,
>   regmap_read(regs, CCSR_SSI_SCR, &scr_val);
>   enabled = scr_val & CCSR_SSI_SCR_SSIEN;
>  
> - /*
> -  * If we're in synchronous mode, and the SSI is already enabled,
> -  * then STCCR is already set properly.
> -  */
> + /* To support simultaneous TX and RX, bypass it if SSI is enabled */
>   if (enabled && ssi->cpu_dai_drv.symmetric_rates)
>   return 0;
>  

I would say that the old comment described better what is happening -
since in synchronous (& non-AC'97) mode STCCR controls both TX and RX
the first direction that is started (either playback or capture) is the
only direction that needs to configure SSI in hw_params().

When the opposite direction enters hw_params() (while the first one is
still running) there is no need to do anything and we can exit early.

Maciej


[PATCH 3/3] soc/fsl/qe: Use common error handling code in ucc_fast_init()

2017-12-13 Thread SF Markus Elfring
From: Markus Elfring 
Date: Wed, 13 Dec 2017 18:18:56 +0100

Add jump targets so that a bit of exception handling can be better reused
at the end of this function.

Signed-off-by: Markus Elfring 
---
 drivers/soc/fsl/qe/ucc_fast.c | 32 
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 2092bfdcf1bc..268dfc5dc89b 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -269,8 +269,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n",
__func__);
uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
-   ucc_fast_free(uccf);
-   return -ENOMEM;
+   goto free_nomem;
}
 
/* Allocate memory for Rx Virtual Fifo */
@@ -282,8 +281,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n",
__func__);
uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
-   ucc_fast_free(uccf);
-   return -ENOMEM;
+   goto free_nomem;
}
 
/* Set Virtual Fifo registers */
@@ -312,8 +310,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
COMM_DIR_RX)) {
printk(KERN_ERR "%s: illegal value for RX clock\n",
   __func__);
-   ucc_fast_free(uccf);
-   return -EINVAL;
+   goto free_inval;
}
/* Tx clock routing */
if ((uf_info->tx_clock != QE_CLK_NONE) &&
@@ -321,8 +318,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
COMM_DIR_TX)) {
printk(KERN_ERR "%s: illegal value for TX clock\n",
   __func__);
-   ucc_fast_free(uccf);
-   return -EINVAL;
+   goto free_inval;
}
} else {
/* tdm Rx clock routing */
@@ -330,8 +326,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->rx_clock,
 COMM_DIR_RX)) {
pr_err("%s: illegal value for RX clock", __func__);
-   ucc_fast_free(uccf);
-   return -EINVAL;
+   goto free_inval;
}
 
/* tdm Tx clock routing */
@@ -339,8 +334,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->tx_clock,
 COMM_DIR_TX)) {
pr_err("%s: illegal value for TX clock", __func__);
-   ucc_fast_free(uccf);
-   return -EINVAL;
+   goto free_inval;
}
 
/* tdm Rx sync clock routing */
@@ -348,8 +342,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->rx_sync,
  COMM_DIR_RX)) {
pr_err("%s: illegal value for RX clock", __func__);
-   ucc_fast_free(uccf);
-   return -EINVAL;
+   goto free_inval;
}
 
/* tdm Tx sync clock routing */
@@ -357,8 +350,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->tx_sync,
  COMM_DIR_TX)) {
pr_err("%s: illegal value for TX clock", __func__);
-   ucc_fast_free(uccf);
-   return -EINVAL;
+   goto free_inval;
}
}
 
@@ -374,6 +366,14 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
 
*uccf_ret = uccf;
return 0;
+
+free_nomem:
+   ucc_fast_free(uccf);
+   return -ENOMEM;
+
+free_inval:
+   ucc_fast_free(uccf);
+   return -EINVAL;
 }
 EXPORT_SYMBOL(ucc_fast_init);
 
-- 
2.15.1



[PATCH 2/3] soc/fsl/qe: Improve a size determination in two functions

2017-12-13 Thread SF Markus Elfring
From: Markus Elfring 
Date: Wed, 13 Dec 2017 17:51:21 +0100

Replace the specification of data structures by pointer dereferences
as the parameter for the operator "sizeof" to make the corresponding size
determination a bit safer according to the Linux coding style convention.

This issue was detected by using the Coccinelle software.

Signed-off-by: Markus Elfring 
---
 drivers/soc/fsl/qe/ucc_fast.c | 2 +-
 drivers/soc/fsl/qe/ucc_slow.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 59b68bf4aebb..2092bfdcf1bc 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -194,7 +194,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
return -EINVAL;
}
 
-   uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
+   uccf = kzalloc(sizeof(*uccf), GFP_KERNEL);
if (!uccf)
return -ENOMEM;
 
diff --git a/drivers/soc/fsl/qe/ucc_slow.c b/drivers/soc/fsl/qe/ucc_slow.c
index fc91412e2300..c21a42c11080 100644
--- a/drivers/soc/fsl/qe/ucc_slow.c
+++ b/drivers/soc/fsl/qe/ucc_slow.c
@@ -152,7 +152,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct 
ucc_slow_private ** ucc
return -EINVAL;
}
 
-   uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
+   uccs = kzalloc(sizeof(*uccs), GFP_KERNEL);
if (!uccs)
return -ENOMEM;
 
-- 
2.15.1



[PATCH 1/3] soc/fsl/qe: Delete an error message for a failed memory allocation in three functions

2017-12-13 Thread SF Markus Elfring
From: Markus Elfring 
Date: Wed, 13 Dec 2017 17:45:23 +0100

Omit an extra message for a memory allocation failure in these functions.

This issue was detected by using the Coccinelle software.

Signed-off-by: Markus Elfring 
---
 drivers/soc/fsl/qe/gpio.c | 4 +---
 drivers/soc/fsl/qe/ucc_fast.c | 5 +
 drivers/soc/fsl/qe/ucc_slow.c | 5 +
 3 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 3b27075c21a7..9239cf176e67 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -143,10 +143,8 @@ struct qe_pin *qe_pin_request(struct device_node *np, int 
index)
unsigned long flags;
 
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
-   if (!qe_pin) {
-   pr_debug("%s: can't allocate memory\n", __func__);
+   if (!qe_pin)
return ERR_PTR(-ENOMEM);
-   }
 
err = of_get_gpio(np, index);
if (err < 0)
diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c
index 83d8d16e3a69..59b68bf4aebb 100644
--- a/drivers/soc/fsl/qe/ucc_fast.c
+++ b/drivers/soc/fsl/qe/ucc_fast.c
@@ -195,11 +195,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct 
ucc_fast_private ** ucc
}
 
uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
-   if (!uccf) {
-   printk(KERN_ERR "%s: Cannot allocate private data\n",
-   __func__);
+   if (!uccf)
return -ENOMEM;
-   }
 
/* Fill fast UCC structure */
uccf->uf_info = uf_info;
diff --git a/drivers/soc/fsl/qe/ucc_slow.c b/drivers/soc/fsl/qe/ucc_slow.c
index 9334bdbd9b30..fc91412e2300 100644
--- a/drivers/soc/fsl/qe/ucc_slow.c
+++ b/drivers/soc/fsl/qe/ucc_slow.c
@@ -153,11 +153,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct 
ucc_slow_private ** ucc
}
 
uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
-   if (!uccs) {
-   printk(KERN_ERR "%s: Cannot allocate private data\n",
-   __func__);
+   if (!uccs)
return -ENOMEM;
-   }
 
/* Fill slow UCC structure */
uccs->us_info = us_info;
-- 
2.15.1



[PATCH 0/3] SoC/FSL/QE: Adjustments for three function implementations

2017-12-13 Thread SF Markus Elfring
From: Markus Elfring 
Date: Wed, 13 Dec 2017 18:28:38 +0100

Three update suggestions were taken into account
from static source code analysis.

Markus Elfring (3):
  Delete an error message for a failed memory allocation in three functions
  Improve a size determination in two functions
  Use common error handling code in ucc_fast_init()

 drivers/soc/fsl/qe/gpio.c |  4 +---
 drivers/soc/fsl/qe/ucc_fast.c | 39 ++-
 drivers/soc/fsl/qe/ucc_slow.c |  7 ++-
 3 files changed, 21 insertions(+), 29 deletions(-)

-- 
2.15.1



[PATCH V3] cxl: Add support for ASB_Notify on POWER9

2017-12-13 Thread Christophe Lombard
The POWER9 core supports a new feature: ASB_Notify which requires the
support of the Special Purpose Register: TIDR.

The ASB_Notify command, generated by the AFU, will attempt to
wake-up the host thread identified by the particular LPID:PID:TID.

This patch assign a unique TIDR (thread id) for the current thread which
will be used in the process element entry.

A next patch will handle a new kind of "compatible" property in the
device-tree (PHB DT node) indicating which version of CAPI and which
features are supported, instead of handling PVR values.

Signed-off-by: Christophe Lombard 
Reviewed-by: Philippe Bergheaud 

---
Changelog[v3]
 - Rebased to latest upstream.
 - Updated attr->tid field in cxllib_get_PE_attributes().

Changelog[v2]
 - Rebased to latest upstream.
 - Updated the ioctl interface.
 - Added a checking to allow updating the TIDR if a P9 chip is present.
---
 arch/powerpc/kernel/process.c |  2 ++
 drivers/misc/cxl/api.c|  9 +
 drivers/misc/cxl/context.c| 26 ++
 drivers/misc/cxl/cxl.h|  4 
 drivers/misc/cxl/cxllib.c |  3 ++-
 drivers/misc/cxl/file.c   | 24 
 drivers/misc/cxl/native.c |  2 +-
 include/uapi/misc/cxl.h   | 17 -
 8 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 5acb5a1..22a17c1 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1744,6 +1744,7 @@ int copy_thread(unsigned long clone_flags, unsigned long 
usp,
kregs->nip = ppc_function_entry(f);
return 0;
 }
+EXPORT_SYMBOL_GPL(clear_thread_tidr);
 
 /*
  * Set up a thread for executing a new program
@@ -1919,6 +1920,7 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int 
val)
| tsk->thread.fpexc_mode;
return 0;
 }
+EXPORT_SYMBOL_GPL(set_thread_tidr);
 
 int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
 {
diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c
index 7c11bad..605272c 100644
--- a/drivers/misc/cxl/api.c
+++ b/drivers/misc/cxl/api.c
@@ -684,3 +684,12 @@ void _cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev)
}
 }
 /* Exported via cxl_base */
+
+int cxl_thread_tidr(struct cxl_context *ctx, u64 flags)
+{
+   if (!ctx)
+   return -EINVAL;
+
+   return cxl_context_thread_tidr(ctx, flags);
+}
+EXPORT_SYMBOL_GPL(cxl_thread_tidr);
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c
index 12a41b2..14e1a51 100644
--- a/drivers/misc/cxl/context.c
+++ b/drivers/misc/cxl/context.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "cxl.h"
 
@@ -42,6 +43,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu 
*afu, bool master)
 
ctx->afu = afu;
ctx->master = master;
+   ctx->tid = 0;
ctx->pid = NULL; /* Set in start work ioctl */
mutex_init(&ctx->mapping_lock);
ctx->mapping = NULL;
@@ -362,3 +364,27 @@ void cxl_context_mm_count_put(struct cxl_context *ctx)
if (ctx->mm)
mmdrop(ctx->mm);
 }
+
+int cxl_context_thread_tidr(struct cxl_context *ctx, u64 flags)
+{
+   int rc = 0;
+
+   if (!cxl_is_power9())
+   return -ENODEV;
+
+   /* Clear any TIDR value assigned to the current thread */
+   if (flags == CXL_THREAD_TID_CLEAN) {
+   clear_thread_tidr(current);
+   ctx->tid = 0;
+   }
+
+   /* Assign a unique TIDR (thread id) for the current thread */
+   if (flags == CXL_THREAD_TID_ASSIGN) {
+   rc = set_thread_tidr(current);
+   if (!rc)
+   ctx->tid = current->thread.tidr;
+   }
+   pr_devel("%s: current tidr: %d\n", __func__, ctx->tid);
+
+   return rc;
+}
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index e46a406..e372291 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -561,6 +561,7 @@ struct cxl_context {
unsigned int sst_size, sst_lru;
 
wait_queue_head_t wq;
+   u32 tid;
/* use mm context associated with this pid for ds faults */
struct pid *pid;
spinlock_t lock; /* Protects pending_irq_mask, pending_fault and 
fault_addr */
@@ -1169,4 +1170,7 @@ void cxl_context_mm_count_get(struct cxl_context *ctx);
 /* Decrements the reference count to "struct mm_struct" */
 void cxl_context_mm_count_put(struct cxl_context *ctx);
 
+/* Handles an unique TIDR (thread id) for the current thread */
+int cxl_context_thread_tidr(struct cxl_context *ctx, u64 flags);
+
 #endif
diff --git a/drivers/misc/cxl/cxllib.c b/drivers/misc/cxl/cxllib.c
index dc9bc18..30ccba4 100644
--- a/drivers/misc/cxl/cxllib.c
+++ b/drivers/misc/cxl/cxllib.c
@@ -199,10 +199,11 @@ int cxllib_get_PE_attributes(struct task_struct *task,
 */
attr->pid = mm->context.id;
mmput(mm);
+  

[PATCH v1 2/7] powerpc/kernel: Add uevents in EEH error/resume

2017-12-13 Thread Bryant G. Ly
Devices can go offline when EEH is reported. This patch adds
a change to the kernel object and lets udev know of error.
When device resumes a change is also set reporting device as
online. Therefore, EEH events are better propagated to user
space for devices in powerpc arch.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/kernel/eeh_driver.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 3c0fa99c5533..c61bf770282b 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -204,6 +204,7 @@ static void *eeh_report_error(void *data, void *userdata)
struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
enum pci_ers_result rc, *res = userdata;
struct pci_driver *driver;
+   char *envp[] = {"EVENT=EEH_ERROR", "ONLINE=0", NULL};
 
if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe))
return NULL;
@@ -228,6 +229,7 @@ static void *eeh_report_error(void *data, void *userdata)
 
edev->in_error = true;
eeh_pcid_put(dev);
+   kobject_uevent_env(&dev->dev.kobj, KOBJ_CHANGE, envp);
return NULL;
 }
 
@@ -358,6 +360,7 @@ static void *eeh_report_resume(void *data, void *userdata)
struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
bool was_in_error;
struct pci_driver *driver;
+   char *envp[] = {"EVENT=EEH_RESUME", "ONLINE=1", NULL};
 
if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe))
return NULL;
@@ -379,8 +382,8 @@ static void *eeh_report_resume(void *data, void *userdata)
}
 
driver->err_handler->resume(dev);
-
eeh_pcid_put(dev);
+   kobject_uevent_env(&dev->dev.kobj, KOBJ_CHANGE, envp);
return NULL;
 }
 
-- 
2.14.3 (Apple Git-98)



[PATCH v1 6/7] pseries/pci: Associate PEs to VFs in configure SR-IOV

2017-12-13 Thread Bryant G. Ly
After initial validation of SR-IOV resources, firmware will
associate PEs to the dynamic VFs created within this call. This
patch adds the association of PEs to the PF array of PE numbers
indexed by VF.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/platforms/pseries/pci.c | 156 ++-
 1 file changed, 153 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/pci.c 
b/arch/powerpc/platforms/pseries/pci.c
index 48d3af026f90..c90e7d1247a8 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -57,18 +57,168 @@ void pcibios_name_device(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device);
 #endif
-
 #ifdef CONFIG_PCI_IOV
+#define MAX_VFS_FOR_MAP_PE 256
+struct pe_map_bar_entry {
+   __be64 bar;   ///< Input:  Virtual Function BAR
+   __be16 rid;   ///< Input:  Virtual Function Router ID
+   __be16 pe_num;///< Output: Virtual Function PE Number
+   __be32 reserved;  ///< Reserved Space
+};
+
+int pseries_send_map_pe(struct pci_dev *pdev,
+   u16 num_vfs,
+   struct pe_map_bar_entry *vf_pe_array)
+{
+   struct pci_dn *pdn;
+   int   rc;
+   unsigned long buid, addr;
+   int ibm_map_pes = rtas_token("ibm,open-sriov-map-pe-number");
+
+   if (ibm_map_pes == RTAS_UNKNOWN_SERVICE)
+   return -EINVAL;
+
+   pdn = pci_get_pdn(pdev);
+   addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+   buid = pdn->phb->buid;
+   spin_lock(&rtas_data_buf_lock);
+   memcpy(rtas_data_buf, vf_pe_array,
+  RTAS_DATA_BUF_SIZE);
+   rc = rtas_call(ibm_map_pes, 5, 1, NULL, addr,
+  BUID_HI(buid), BUID_LO(buid),
+  rtas_data_buf,
+  num_vfs * sizeof(struct pe_map_bar_entry));
+   memcpy(vf_pe_array, rtas_data_buf,
+  RTAS_DATA_BUF_SIZE);
+   spin_unlock(&rtas_data_buf_lock);
+
+   if (rc)
+   dev_err(&pdev->dev,
+   "%s: Failed to associate pes PE#%lx, rc=%x\n",
+   __func__,  addr, rc);
+
+   return rc;
+}
+
+void pseries_set_pe_num(struct pci_dev *pdev,
+   u16 vf_index, __be16 pe_num)
+{
+   struct pci_dn *pdn;
+
+   pdn = pci_get_pdn(pdev);
+   pdn->pe_num_map[vf_index] = be16_to_cpu(pe_num);
+   dev_dbg(&pdev->dev, "VF %04x:%02x:%02x.%x associated with PE#%x\n",
+   pci_domain_nr(pdev->bus),
+   pdev->bus->number,
+   PCI_SLOT(pci_iov_virtfn_devfn(pdev, vf_index)),
+   PCI_FUNC(pci_iov_virtfn_devfn(pdev, vf_index)),
+   pdn->pe_num_map[vf_index]);
+}
+
+int pseries_associate_pes(struct pci_dev *pdev, u16 num_vfs)
+{
+   struct pci_dn *pdn;
+   int i,  rc,  vf_index;
+   struct pe_map_bar_entry *vf_pe_array;
+   struct resource *res;
+   u64 size;
+
+   vf_pe_array = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+   if (!vf_pe_array)
+   return -ENOMEM;
+
+   memset(vf_pe_array, 0, RTAS_DATA_BUF_SIZE);
+   pdn = pci_get_pdn(pdev);
+   /* create firmware structure to associate pes */
+   for (vf_index = 0; vf_index < num_vfs && vf_index < MAX_VFS_FOR_MAP_PE;
+vf_index++) {
+   pdn->pe_num_map[vf_index] = IODA_INVALID_PE;
+   for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+   res = &pdev->resource[i + PCI_IOV_RESOURCES];
+   if (!res->parent)
+   continue;
+   size = pcibios_iov_resource_alignment(pdev, i +
+ PCI_IOV_RESOURCES
+ );
+   vf_pe_array[vf_index].bar =
+   be64_to_cpu(res->start + size * vf_index);
+   vf_pe_array[vf_index].rid =
+   be16_to_cpu((pci_iov_virtfn_bus(pdev, vf_index)
+   << 8) | pci_iov_virtfn_devfn(pdev,
+   vf_index));
+   vf_pe_array[vf_index].pe_num =
+   be16_to_cpu(IODA_INVALID_PE);
+   }
+   }
+
+   rc = pseries_send_map_pe(pdev, num_vfs, vf_pe_array);
+   /* Only zero is success */
+   if (!rc)
+   for (vf_index = 0; vf_index < num_vfs && vf_index <
+MAX_VFS_FOR_MAP_PE; vf_index++)
+   pseries_set_pe_num(pdev, vf_index,
+  vf_pe_array[vf_index].pe_num);
+
+   kfree(vf_pe_array);
+   return rc;
+}
+
+int pseries_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
+{
+   struct pci_dn *pdn;
+   int 

[PATCH v1 7/7] pseries/setup: Add Initialization of VF Bars

2017-12-13 Thread Bryant G. Ly
When enabling SR-IOV in pseries platform,
the VF bar properties for a PF are reported on
the device node in the device tree.

This patch adds the IOV Bar resources to Linux
structures from the device tree for later use
when configuring SR-IOV by PF driver.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/include/asm/pci.h |   2 +
 arch/powerpc/kernel/pci_of_scan.c  |   2 +-
 arch/powerpc/platforms/pseries/setup.c | 183 +
 3 files changed, 186 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 8dc32eacc97c..d82802ff5088 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -121,6 +121,8 @@ extern int remove_phb_dynamic(struct pci_controller *phb);
 extern struct pci_dev *of_create_pci_dev(struct device_node *node,
struct pci_bus *bus, int devfn);
 
+extern unsigned int pci_parse_of_flags(u32 addr0, int bridge);
+
 extern void of_scan_pci_bridge(struct pci_dev *dev);
 
 extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
diff --git a/arch/powerpc/kernel/pci_of_scan.c 
b/arch/powerpc/kernel/pci_of_scan.c
index 0d790f8432d2..20ceec4a5f5e 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -38,7 +38,7 @@ static u32 get_int_prop(struct device_node *np, const char 
*name, u32 def)
  * @addr0: value of 1st cell of a device tree PCI address.
  * @bridge: Set this flag if the address is from a bridge 'ranges' property
  */
-static unsigned int pci_parse_of_flags(u32 addr0, int bridge)
+unsigned int pci_parse_of_flags(u32 addr0, int bridge)
 {
unsigned int flags = 0;
 
diff --git a/arch/powerpc/platforms/pseries/setup.c 
b/arch/powerpc/platforms/pseries/setup.c
index 5f1beb8367ac..ce28882cbde8 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -459,6 +459,181 @@ static void __init find_and_init_phbs(void)
of_pci_check_probe_only();
 }
 
+#ifdef CONFIG_PCI_IOV
+enum rtas_iov_fw_value_map {
+   NUM_RES_PROPERTY  = 0, ///< Number of Resources
+   LOW_INT   = 1, ///< Lowest 32 bits of Address
+   START_OF_ENTRIES  = 2, ///< Always start of entry
+   APERTURE_PROPERTY = 2, ///< Start of entry+ to  Aperture Size
+   WDW_SIZE_PROPERTY = 4, ///< Start of entry+ to Window Size
+   NEXT_ENTRY= 7  ///< Go to next entry on array
+};
+
+enum get_iov_fw_value_index {
+   BAR_ADDRS = 1,///<  Get Bar Address
+   APERTURE_SIZE = 2,///<  Get Aperture Size
+   WDW_SIZE  = 3 ///<  Get Window Size
+};
+
+resource_size_t pseries_get_iov_fw_values(struct pci_dev *dev, int resno,
+ enum get_iov_fw_value_index value)
+{
+   struct vf_bar_wdw {
+   __be64  addr;
+   __be64  aperture_size;
+   __be64  wdw_size;
+   };
+
+   struct vf_bar_wdw window_avail[PCI_SRIOV_NUM_BARS];
+   const int *indexes;
+   struct device_node *dn = pci_device_to_OF_node(dev);
+   int i, r, num_res;
+   resource_size_t return_value;
+
+   indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL);
+   if (!indexes)
+   return  0;
+
+   memset(window_avail,
+  0, sizeof(struct vf_bar_wdw) * PCI_SRIOV_NUM_BARS);
+   return_value = 0;
+   /*
+* First element in the array is the number of Bars
+* returned.  Search through the list to find the matching
+* bar
+*/
+   num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1);
+   for (i = START_OF_ENTRIES, r = 0; r < num_res && r < PCI_SRIOV_NUM_BARS;
+i += NEXT_ENTRY, r++) {
+   window_avail[r].addr = of_read_number(&indexes[i], 2);
+   window_avail[r].aperture_size =
+   of_read_number(&indexes[i + APERTURE_PROPERTY], 2);
+   window_avail[r].wdw_size =
+   of_read_number(&indexes[i + WDW_SIZE_PROPERTY], 2);
+   }
+
+   switch (value) {
+   case BAR_ADDRS:
+   return_value = window_avail[resno].addr;
+   break;
+   case APERTURE_SIZE:
+   return_value = window_avail[resno].aperture_size;
+   break;
+   case WDW_SIZE:
+   return_value = window_avail[resno].wdw_size;
+   break;
+   default:
+   break;
+   }
+   return  return_value;
+}
+
+void of_pci_parse_vf_bar_size(struct pci_dev *dev, const int *indexes)
+{
+   struct resource *res;
+   resource_size_t base, size;
+   int i, r, num_res;
+
+   num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1);
+   for (i = START_OF_ENTRIES, r = 0; r < num_res && r < PCI_SRIOV_NUM_BARS;
+i += NEXT_ENTRY, r++) {
+   res = &dev->resource[r + PCI_IOV_RESOURC

[PATCH v1 4/7] powerpc/kernel Add EEH operations to notify resume

2017-12-13 Thread Bryant G. Ly
When pseries SR-IOV is enabled and after a PF driver
has resumed from EEH, platform has to be notified
of the event so the child VFs can be allowed to
resume their normal recovery path.

This patch makes the EEH operation allow unfreeze
platform dependent code and adds the call to
pseries EEH code.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/include/asm/eeh.h   |   1 +
 arch/powerpc/kernel/eeh_driver.c |   4 ++
 arch/powerpc/platforms/powernv/eeh-powernv.c |   3 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c | 100 ++-
 4 files changed, 106 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 5161c37dd039..12d52a0cd447 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -214,6 +214,7 @@ struct eeh_ops {
int (*write_config)(struct pci_dn *pdn, int where, int size, u32 val);
int (*next_error)(struct eeh_pe **pe);
int (*restore_config)(struct pci_dn *pdn);
+   int (*notify_resume)(struct pci_dn *pdn);
 };
 
 extern int eeh_subsystem_flags;
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index c61bf770282b..dbda0cda559b 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -361,6 +361,7 @@ static void *eeh_report_resume(void *data, void *userdata)
bool was_in_error;
struct pci_driver *driver;
char *envp[] = {"EVENT=EEH_RESUME", "ONLINE=1", NULL};
+   struct pci_dn *pdn = eeh_dev_to_pdn(edev);
 
if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe))
return NULL;
@@ -384,6 +385,9 @@ static void *eeh_report_resume(void *data, void *userdata)
driver->err_handler->resume(dev);
eeh_pcid_put(dev);
kobject_uevent_env(&dev->dev.kobj, KOBJ_CHANGE, envp);
+#ifdef CONFIG_PCI_IOV
+   eeh_ops->notify_resume(pdn);
+#endif
return NULL;
 }
 
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c 
b/arch/powerpc/platforms/powernv/eeh-powernv.c
index 961e64115d92..8575b3a29e7c 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -1763,7 +1763,8 @@ static struct eeh_ops pnv_eeh_ops = {
.read_config= pnv_eeh_read_config,
.write_config   = pnv_eeh_write_config,
.next_error = pnv_eeh_next_error,
-   .restore_config = pnv_eeh_restore_config
+   .restore_config = pnv_eeh_restore_config,
+   .notify_resume  = NULL
 };
 
 #ifdef CONFIG_PCI_IOV
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c 
b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 5bdd1678a9ff..2b36fbf4ce74 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -798,6 +798,103 @@ static int pseries_eeh_restore_config(struct pci_dn *pdn)
return 0;
 }
 
+#ifdef CONFIG_PCI_IOV
+int pseries_send_allow_unfreeze(struct eeh_pe *pe,
+   u16 *vf_pe_array, int cur_vfs)
+{
+   int  rc, config_addr;
+   int ibm_allow_unfreeze = rtas_token("ibm,open-sriov-allow-unfreeze");
+
+   config_addr = pe->config_addr;
+   spin_lock(&rtas_data_buf_lock);
+   memcpy(rtas_data_buf, vf_pe_array, RTAS_DATA_BUF_SIZE);
+   rc = rtas_call(ibm_allow_unfreeze, 5, 1, NULL,
+  config_addr,
+  BUID_HI(pe->phb->buid),
+  BUID_LO(pe->phb->buid),
+  rtas_data_buf, cur_vfs * sizeof(u16));
+   spin_unlock(&rtas_data_buf_lock);
+   if (rc)
+   pr_warn("%s: Failed to allow unfreeze for PHB#%x-PE#%x, 
rc=%x\n",
+   __func__,
+   pe->phb->global_number,
+   pe->config_addr, rc);
+   return rc;
+}
+
+static int pseries_call_allow_unfreeze(struct eeh_dev *edev)
+{
+   struct eeh_pe *pe;
+   struct pci_dn *pdn, *tmp, *parent, *physfn_pdn;
+   int cur_vfs, rc, vf_index;
+   u16 *vf_pe_array;
+
+   vf_pe_array = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+   if (!vf_pe_array)
+   return -ENOMEM;
+
+   memset(vf_pe_array, 0, RTAS_DATA_BUF_SIZE);
+   cur_vfs = 0;
+   rc = 0;
+   if (edev->pdev->is_physfn) {
+   pe = eeh_dev_to_pe(edev);
+   cur_vfs = pci_num_vf(edev->pdev);
+   pdn = eeh_dev_to_pdn(edev);
+   parent  = pdn->parent;
+   /* For each of its VF
+* call allow unfreeze
+*/
+   for (vf_index = 0; vf_index < cur_vfs; vf_index++)
+   vf_pe_array[vf_index] =
+   be16_to_cpu(pdn->pe_num_map[vf_index]);
+
+   rc = pseries_send_allow_unfreeze(pe, vf_pe_array, cur_vfs);
+   pdn->last_allow_rc = rc;
+  

[PATCH v1 5/7] powerpc/kernel: Add EEH notify resume sysfs

2017-12-13 Thread Bryant G. Ly
Introduce a method for notify resume to be
called from sysfs. In this patch one can
now call notify resume from sysfs when
is supported by platform.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/kernel/eeh_sysfs.c | 46 -
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c
index 797549289798..344e7607f2e0 100644
--- a/arch/powerpc/kernel/eeh_sysfs.c
+++ b/arch/powerpc/kernel/eeh_sysfs.c
@@ -90,6 +90,38 @@ static ssize_t eeh_pe_state_store(struct device *dev,
 
 static DEVICE_ATTR_RW(eeh_pe_state);
 
+#ifdef CONFIG_PCI_IOV
+static ssize_t eeh_notify_resume_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+   struct pci_dev *pdev = to_pci_dev(dev);
+   struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
+   struct pci_dn *pdn = pci_get_pdn(pdev);
+
+   if (!edev || !edev->pe)
+   return -ENODEV;
+
+   pdn = pci_get_pdn(pdev);
+   return sprintf(buf, "%d\n", pdn->last_allow_rc);
+}
+
+static ssize_t eeh_notify_resume_store(struct device *dev,
+  struct device_attribute *attr,
+  const char *buf, size_t count)
+{
+   struct pci_dev *pdev = to_pci_dev(dev);
+   struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
+
+   if (!edev || !edev->pe)
+   return -ENODEV;
+
+   if (eeh_ops->notify_resume(pci_get_pdn(pdev)))
+   return -EIO;
+   return count;
+}
+static DEVICE_ATTR_RW(eeh_notify_resume);
+#endif
+
 void eeh_sysfs_add_device(struct pci_dev *pdev)
 {
struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
@@ -104,7 +136,13 @@ void eeh_sysfs_add_device(struct pci_dev *pdev)
rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_state);
-
+#ifdef CONFIG_PCI_IOV
+   if (of_get_property(pci_device_to_OF_node
+   ((pdev->is_physfn ? pdev : pdev->physfn)),
+   "ibm,is-open-sriov-pf", NULL))
+   rc += device_create_file(&pdev->dev,
+&dev_attr_eeh_notify_resume);
+#endif
if (rc)
pr_warn("EEH: Unable to create sysfs entries\n");
else if (edev)
@@ -128,6 +166,12 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev)
device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
device_remove_file(&pdev->dev, &dev_attr_eeh_pe_state);
+#ifdef CONFIG_PCI_IOV
+   if (of_get_property(pci_device_to_OF_node
+   ((pdev->is_physfn ? pdev : pdev->physfn)),
+   "ibm,is-open-sriov-pf", NULL))
+   device_remove_file(&pdev->dev, &dev_attr_eeh_notify_resume);
+#endif
 
if (edev)
edev->mode &= ~EEH_DEV_SYSFS;
-- 
2.14.3 (Apple Git-98)



[PATCH v1 3/7] platforms/pseries: Set eeh_pe of EEH_PE_VF type

2017-12-13 Thread Bryant G. Ly
To correctly use EEH code one has to make
sure that the EEH_PE_VF is set for dynamic created
VFs. Therefore this patch allocates an eeh_pe of
eeh type EEH_PE_VF and associates PE with parent.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/include/asm/pci-bridge.h| 5 -
 arch/powerpc/platforms/pseries/eeh_pseries.c | 9 -
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/pci-bridge.h 
b/arch/powerpc/include/asm/pci-bridge.h
index 9f66ddebb799..c30c7cba4c30 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -211,7 +211,10 @@ struct pci_dn {
unsigned int *pe_num_map;   /* PE# for the first VF PE or array */
boolm64_single_mode;/* Use M64 BAR in Single Mode */
 #define IODA_INVALID_M64(-1)
-   int (*m64_map)[PCI_SRIOV_NUM_BARS];
+   union {
+   int (*m64_map)[PCI_SRIOV_NUM_BARS];
+   int last_allow_rc;
+   };
 #endif /* CONFIG_PCI_IOV */
int mps;/* Maximum Payload Size */
struct list_head child_list;
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c 
b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 1a9a6fa91151..5bdd1678a9ff 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -58,6 +58,8 @@ static int ibm_configure_pe;
 void pseries_pcibios_bus_add_device(struct pci_dev *pdev)
 {
struct pci_dn *pdn = pci_get_pdn(pdev);
+   struct pci_dn *physfn_pdn;
+   struct eeh_dev *edev;
 
if (!pdev->is_virtfn)
return;
@@ -65,6 +67,10 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev)
pdn->device_id  =  pdev->device;
pdn->vendor_id  =  pdev->vendor;
pdn->class_code =  pdev->class;
+   pdn->last_allow_rc =  0;
+   physfn_pdn  =  pci_get_pdn(pdev->physfn);
+   pdn->pe_number  =  physfn_pdn->pe_num_map[pdn->vf_index];
+   edev = pdn_to_eeh_dev(pdn);
 
/*
 * The following operations will fail if VF's sysfs files
@@ -72,8 +78,9 @@ void pseries_pcibios_bus_add_device(struct pci_dev *pdev)
 */
eeh_add_device_early(pdn);
eeh_add_device_late(pdev);
+   edev->pe_config_addr =  (pdn->busno << 16) | (pdn->devfn << 8);
+   eeh_add_to_parent_pe(edev);
eeh_sysfs_add_device(pdev);
-
 }
 
 /*
-- 
2.14.3 (Apple Git-98)



[PATCH v1 1/7] platform/pseries: Update VF config space after EEH

2017-12-13 Thread Bryant G. Ly
Add EEH platform operations for pseries to update VF
config space. With this change after EEH, the VF
will have updated config space for pseries platform.

Signed-off-by: Bryant G. Ly 
Signed-off-by: Juan J. Alvarez 
---
 arch/powerpc/platforms/pseries/eeh_pseries.c | 85 +++-
 1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c 
b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 2295f117e2d3..1a9a6fa91151 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -708,6 +708,89 @@ static int pseries_eeh_write_config(struct pci_dn *pdn, 
int where, int size, u32
return rtas_write_config(pdn, where, size, val);
 }
 
+static int pseries_eeh_restore_vf_config(struct pci_dn *pdn)
+{
+   struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
+   u32 devctl, cmd, cap2, aer_capctl;
+   int old_mps;
+
+   if (edev->pcie_cap) {
+   /* Restore MPS */
+   old_mps = (ffs(pdn->mps) - 8) << 5;
+   eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
+2, &devctl);
+   devctl &= ~PCI_EXP_DEVCTL_PAYLOAD;
+   devctl |= old_mps;
+   eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
+ 2, devctl);
+
+   /* Disable Completion Timeout */
+   eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCAP2,
+4, &cap2);
+   if (cap2 & 0x10) {
+   eeh_ops->read_config(pdn,
+edev->pcie_cap + PCI_EXP_DEVCTL2,
+4, &cap2);
+   cap2 |= 0x10;
+   eeh_ops->write_config(pdn,
+ edev->pcie_cap + PCI_EXP_DEVCTL2,
+ 4, cap2);
+   }
+   }
+
+   /* Enable SERR and parity checking */
+   eeh_ops->read_config(pdn, PCI_COMMAND, 2, &cmd);
+   cmd |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+   eeh_ops->write_config(pdn, PCI_COMMAND, 2, cmd);
+
+   /* Enable report various errors */
+   if (edev->pcie_cap) {
+   eeh_ops->read_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
+2, &devctl);
+   devctl &= ~PCI_EXP_DEVCTL_CERE;
+   devctl |= (PCI_EXP_DEVCTL_NFERE |
+  PCI_EXP_DEVCTL_FERE |
+  PCI_EXP_DEVCTL_URRE);
+   eeh_ops->write_config(pdn, edev->pcie_cap + PCI_EXP_DEVCTL,
+ 2, devctl);
+   }
+
+   /* Enable ECRC generation and check */
+   if (edev->pcie_cap && edev->aer_cap) {
+   eeh_ops->read_config(pdn, edev->aer_cap + PCI_ERR_CAP,
+4, &aer_capctl);
+   aer_capctl |= (PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
+   eeh_ops->write_config(pdn, edev->aer_cap + PCI_ERR_CAP,
+ 4, aer_capctl);
+   }
+
+   return 0;
+}
+
+static int pseries_eeh_restore_config(struct pci_dn *pdn)
+{
+   struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
+   s64 ret;
+
+   if (!edev)
+   return -EEXIST;
+
+   /*
+* FIXME: The MPS, error routing rules, timeout setting are worthy
+* to be exported by firmware in extendible way.
+*/
+   if (edev->physfn)
+   ret = pseries_eeh_restore_vf_config(pdn);
+
+   if (ret) {
+   pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n",
+   __func__, edev->pe_config_addr, ret);
+   return -EIO;
+   }
+
+   return 0;
+}
+
 static struct eeh_ops pseries_eeh_ops = {
.name   = "pseries",
.init   = pseries_eeh_init,
@@ -723,7 +806,7 @@ static struct eeh_ops pseries_eeh_ops = {
.read_config= pseries_eeh_read_config,
.write_config   = pseries_eeh_write_config,
.next_error = NULL,
-   .restore_config = NULL
+   .restore_config = pseries_eeh_restore_config
 };
 
 /**
-- 
2.14.3 (Apple Git-98)



[PATCH v1 0/7] SR-IOV Enablement on PowerVM

2017-12-13 Thread Bryant G. Ly
This patch series will enable SR-IOV on PowerVM. A specific set of
lids for PFW/PHYP is required. They are planned to release with
920 at the moment.

For IBM internal testers let me know of a system you want to test on
and we can put on the lids required or we can provide a system to run
the tests.

This patch depends on the three patches:
988fc3ba5653278a8c14d6ccf687371775930d2b
dae7253f9f78a731755ca20c66b2d2c40b86baea
608c0d8804ef3ca4cda8ec6ad914e47deb283d7b

Bryant G. Ly (7):
  platform/pseries: Update VF config space after EEH
  powerpc/kernel: Add uevents in EEH error/resume
  platforms/pseries: Set eeh_pe of EEH_PE_VF type
  powerpc/kernel Add EEH operations to notify resume
  powerpc/kernel: Add EEH notify resume sysfs
  pseries/pci: Associate PEs to VFs in configure SR-IOV
  pseries/setup: Add Initialization of VF Bars

 arch/powerpc/include/asm/eeh.h   |   1 +
 arch/powerpc/include/asm/pci-bridge.h|   5 +-
 arch/powerpc/include/asm/pci.h   |   2 +
 arch/powerpc/kernel/eeh_driver.c |   9 +-
 arch/powerpc/kernel/eeh_sysfs.c  |  46 ++-
 arch/powerpc/kernel/pci_of_scan.c|   2 +-
 arch/powerpc/platforms/powernv/eeh-powernv.c |   3 +-
 arch/powerpc/platforms/pseries/eeh_pseries.c | 192 ++-
 arch/powerpc/platforms/pseries/pci.c | 156 +-
 arch/powerpc/platforms/pseries/setup.c   | 183 +
 10 files changed, 589 insertions(+), 10 deletions(-)

-- 
2.14.3 (Apple Git-98)



[PATCH] cpufreq: powernv: Add support of frequency domain

2017-12-13 Thread Abhishek Goel
Frequency-domain indicates group of CPUs that would share same frequency.
It is detected using device-tree node "frequency-domain-indicator".
frequency-domain-indicator is a bitmask which will have different value
depending upon the generation of the processor.

CPUs of the same chip for which the result of a bitwise AND between
their PIR and the frequency-domain-indicator is the same share the same
frequency.

In this patch, we define hash-table indexed by the aforementioned
bitwise ANDed value to store the cpumask of the CPUs sharing the same
frequency domain. Further, the cpufreq policy will be created per
frequency-domain

So for POWER9, a cpufreq policy is created per quad while for POWER8 it
is created per core. Governor decides frequency for each policy but
multiple cores may come under same policy. In such case frequency needs
to be set on each core sharing that policy.

Signed-off-by: Abhishek Goel 
---
 drivers/cpufreq/powernv-cpufreq.c | 95 +++
 1 file changed, 87 insertions(+), 8 deletions(-)

diff --git a/drivers/cpufreq/powernv-cpufreq.c 
b/drivers/cpufreq/powernv-cpufreq.c
index b6d7c4c..9384110 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -37,6 +37,7 @@
 #include  /* Required for cpu_sibling_mask() in UP configs */
 #include 
 #include 
+#include 
 
 #define POWERNV_MAX_PSTATES256
 #define PMSR_PSAFE_ENABLE  (1UL << 30)
@@ -130,6 +131,8 @@ static struct chip {
 static int nr_chips;
 static DEFINE_PER_CPU(struct chip *, chip_info);
 
+static u32 freq_domain_indicator;
+
 /*
  * Note:
  * The set of pstates consists of contiguous integers.
@@ -194,6 +197,38 @@ static inline void reset_gpstates(struct cpufreq_policy 
*policy)
gpstates->last_gpstate_idx = 0;
 }
 
+#define SIZE NR_CPUS
+#define ORDER_FREQ_MAP ilog2(SIZE)
+
+static DEFINE_HASHTABLE(freq_domain_map, ORDER_FREQ_MAP);
+
+struct hashmap {
+   cpumask_t mask;
+   int chip_id;
+   u32 pir_key;
+   struct hlist_node hash_node;
+};
+
+static void insert(u32 key, int cpu)
+{
+   struct hashmap *data;
+
+   hash_for_each_possible(freq_domain_map, data, hash_node, key%SIZE) {
+   if (data->chip_id == cpu_to_chip_id(cpu) &&
+   data->pir_key == key) {
+   cpumask_set_cpu(cpu, &data->mask);
+   return;
+   }
+   }
+
+   data = kzalloc(sizeof(*data), GFP_KERNEL);
+   hash_add(freq_domain_map, &data->hash_node, key%SIZE);
+   cpumask_set_cpu(cpu, &data->mask);
+   data->chip_id = cpu_to_chip_id(cpu);
+   data->pir_key = key;
+
+}
+
 /*
  * Initialize the freq table based on data obtained
  * from the firmware passed via device-tree
@@ -206,6 +241,7 @@ static int init_powernv_pstates(void)
u32 len_ids, len_freqs;
u32 pstate_min, pstate_max, pstate_nominal;
u32 pstate_turbo, pstate_ultra_turbo;
+   u32 key;
 
power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
if (!power_mgt) {
@@ -229,6 +265,13 @@ static int init_powernv_pstates(void)
return -ENODEV;
}
 
+   if (of_device_is_compatible(power_mgt, "freq-domain-v1") &&
+   of_property_read_u32(power_mgt, "ibm,freq-domain-indicator",
+&freq_domain_indicator)) {
+   pr_warn("ibm,freq-domain-indicator not found\n");
+   freq_domain_indicator = 0;
+   }
+
if (of_property_read_u32(power_mgt, "ibm,pstate-ultra-turbo",
 &pstate_ultra_turbo)) {
powernv_pstate_info.wof_enabled = false;
@@ -249,6 +292,7 @@ static int init_powernv_pstates(void)
 next:
pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min,
pstate_nominal, pstate_max);
+   pr_info("frequency domain indicator %d", freq_domain_indicator);
pr_info("Workload Optimized Frequency is %s in the platform\n",
(powernv_pstate_info.wof_enabled) ? "enabled" : "disabled");
 
@@ -276,6 +320,15 @@ static int init_powernv_pstates(void)
return -ENODEV;
}
 
+   if (freq_domain_indicator) {
+   hash_init(freq_domain_map);
+   for_each_possible_cpu(i) {
+   key = ((u32) get_hard_smp_processor_id(i) &
+   freq_domain_indicator);
+   insert(key, i);
+   }
+   }
+
powernv_pstate_info.nr_pstates = nr_pstates;
pr_debug("NR PStates %d\n", nr_pstates);
for (i = 0; i < nr_pstates; i++) {
@@ -693,6 +746,8 @@ static int powernv_cpufreq_target_index(struct 
cpufreq_policy *policy,
 {
struct powernv_smp_call_data freq_data;
unsigned int cur_msec, gpstate_idx;
+   cpumask_t temp;
+   u32 cpu;
struct global_pstate_info *gpstates = policy->driver_data;
 
if (unlikely(rebooting) && new_index != ge

[PATCH] powerpc/sysdev: change CPM GPIO to platform_device

2017-12-13 Thread Christophe Leroy
Since commit 9427ecbed46cc ("gpio: Rework of_gpiochip_set_names()
to use device property accessors"), gpio chips have to have a
parent, otherwise devprop_gpiochip_set_names() prematurely exists
with message "GPIO chip parent is NULL" and doesn't proceed
'gpio-line-names' DT property.

This patch wraps the CPM GPIO into a platform driver to allow
assignment of the parent device.

Signed-off-by: Christophe Leroy 
---
 arch/powerpc/include/asm/cpm.h   |  2 +-
 arch/powerpc/include/asm/cpm1.h  |  2 +
 arch/powerpc/sysdev/Makefile |  3 +-
 arch/powerpc/sysdev/cpm1.c   | 33 -
 arch/powerpc/sysdev/cpm2.c   | 11 --
 arch/powerpc/sysdev/cpm_common.c |  5 ++-
 arch/powerpc/sysdev/cpm_gpio.c   | 80 
 7 files changed, 97 insertions(+), 39 deletions(-)
 create mode 100644 arch/powerpc/sysdev/cpm_gpio.c

diff --git a/arch/powerpc/include/asm/cpm.h b/arch/powerpc/include/asm/cpm.h
index b925df1b87d0..4c24ea8209bb 100644
--- a/arch/powerpc/include/asm/cpm.h
+++ b/arch/powerpc/include/asm/cpm.h
@@ -166,6 +166,6 @@ static inline int cpm_command(u32 command, u8 opcode)
 }
 #endif /* CONFIG_CPM */
 
-int cpm2_gpiochip_add32(struct device_node *np);
+int cpm2_gpiochip_add32(struct device *dev);
 
 #endif
diff --git a/arch/powerpc/include/asm/cpm1.h b/arch/powerpc/include/asm/cpm1.h
index 3db821876d48..a116fe931789 100644
--- a/arch/powerpc/include/asm/cpm1.h
+++ b/arch/powerpc/include/asm/cpm1.h
@@ -605,5 +605,7 @@ enum cpm_clk {
 };
 
 int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode);
+int cpm1_gpiochip_add16(struct device *dev);
+int cpm1_gpiochip_add32(struct device *dev);
 
 #endif /* __CPM1__ */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 0baba21404dc..fc31a271830b 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -43,7 +43,8 @@ obj-$(CONFIG_OF_RTC)  += of_rtc.o
 
 obj-$(CONFIG_CPM)  += cpm_common.o
 obj-$(CONFIG_CPM1) += cpm1.o
-obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o
+obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o cpm_gpio.o
+obj-$(CONFIG_8xx_GPIO) += cpm_gpio.o
 obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o
 obj-$(CONFIG_PPC_DCR)  += dcr.o
 obj-$(CONFIG_UCODE_PATCH)  += micropatch.o
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index f5544c6fbd18..e6ec2b1263b1 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -635,8 +635,9 @@ static int cpm1_gpio16_dir_in(struct gpio_chip *gc, 
unsigned int gpio)
return 0;
 }
 
-int cpm1_gpiochip_add16(struct device_node *np)
+int cpm1_gpiochip_add16(struct device *dev)
 {
+   struct device_node *np = dev->of_node;
struct cpm1_gpio16_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
struct gpio_chip *gc;
@@ -666,6 +667,8 @@ int cpm1_gpiochip_add16(struct device_node *np)
gc->get = cpm1_gpio16_get;
gc->set = cpm1_gpio16_set;
gc->to_irq = cpm1_gpio16_to_irq;
+   gc->parent = dev;
+   gc->owner = THIS_MODULE;
 
return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
 }
@@ -761,8 +764,9 @@ static int cpm1_gpio32_dir_in(struct gpio_chip *gc, 
unsigned int gpio)
return 0;
 }
 
-int cpm1_gpiochip_add32(struct device_node *np)
+int cpm1_gpiochip_add32(struct device *dev)
 {
+   struct device_node *np = dev->of_node;
struct cpm1_gpio32_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
struct gpio_chip *gc;
@@ -782,31 +786,10 @@ int cpm1_gpiochip_add32(struct device_node *np)
gc->direction_output = cpm1_gpio32_dir_out;
gc->get = cpm1_gpio32_get;
gc->set = cpm1_gpio32_set;
+   gc->parent = dev;
+   gc->owner = THIS_MODULE;
 
return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
 }
 
-static int cpm_init_par_io(void)
-{
-   struct device_node *np;
-
-   for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a")
-   cpm1_gpiochip_add16(np);
-
-   for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b")
-   cpm1_gpiochip_add32(np);
-
-   for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c")
-   cpm1_gpiochip_add16(np);
-
-   for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d")
-   cpm1_gpiochip_add16(np);
-
-   /* Port E uses CPM2 layout */
-   for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e")
-   cpm2_gpiochip_add32(np);
-   return 0;
-}
-arch_initcall(cpm_init_par_io);
-
 #endif /* CONFIG_8xx_GPIO */
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c
index f78ff841652c..07718b9a2c99 100644
--- a/arch/powerpc/sysdev/cpm2.c
+++ b/arch/powerpc/sysdev/cpm2.c
@@ -354,14 +354,3 @@ void cpm2_set_pin(int port, int pin, int flags)
else
clrbits32(&iop[port].odr, pin);
 }
-
-static int cpm_init_par_io(void)
-{
-   struct device_node *np;
-
-

Re: [PATCH 2/2] powernv/kdump: Fix cases where the kdump kernel can get HMI's

2017-12-13 Thread Nicholas Piggin
This is looking pretty nice now...

On Wed, 13 Dec 2017 19:08:28 +1100
Balbir Singh  wrote:

> @@ -543,7 +543,25 @@ void smp_send_debugger_break(void)
>  #ifdef CONFIG_KEXEC_CORE
>  void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
>  {
> + int cpu;
> +
>   smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_ipi_callback, 100);
> + if (kdump_in_progress() && crash_wake_offline) {
> + for_each_present_cpu(cpu) {
> + if (cpu_online(cpu))
> + continue;
> + /*
> +  * crash_ipi_callback will wait for
> +  * all cpus, including offline CPUs.
> +  * We don't care about nmi_ipi_function.
> +  * Offline cpus will jump straight into
> +  * crash_ipi_callback, we can skip the
> +  * entire NMI dance and waiting for
> +  * cpus to clear pending mask, etc.
> +  */
> + do_smp_send_nmi_ipi(cpu);

Still a little bit concerned about using NMI IPI for this.

If you take an NMI IPI from stop, the idle code should do the
right thing and we would just return the system reset wakeup
reason in SRR1 here (which does not need to be cleared).

If you take the system reset anywhere else in the loop, it's
going to go out via system_reset_exception. I guess that
would end up doing the right thing, it probably gets to
crash_ipi_callback from crash_kexec_secondary?

It's just going to be a very untested code path :( What we
gain I suppose is better ability to handle a CPU that's locked
up somewhere in the cpu offline path. Assuming the uncommon
case works...

Actually, if you *always* go via the system reset exception
handler, then code paths will be shared. That might be the
way to go. So I would check for system reset wakeup SRR1 reason
and call replay_system_reset() for it. What do you think?

Thanks,
Nick


[PATCH 2/2] powernv/kdump: Fix cases where the kdump kernel can get HMI's

2017-12-13 Thread Balbir Singh
Certain HMI's such as malfunction error propagate through
all threads/core on the system. If a thread was offline
prior to us crashing the system and jumping to the kdump
kernel, bad things happen when it wakes up due to an HMI
in the kdump kernel.

There are several possible ways to solve this problem

1. Put the offline cores in a state such that they are
not woken up for machine check and HMI errors. This
does not work, since we might need to wake up offline
threads to handle TB errors
2. Ignore HMI errors, setup HMEER to mask HMI errors,
but this still leads the window open for any MCEs
and masking them for the duration of the dump might
be a concern
3. Wake up offline CPUs, as in send them to
crash_ipi_callback (not wake them up as in mark them
online as seen by the hotplug). kexec does a
wake_online_cpus() call, this patch does something
similar, but instead sends an IPI and forces them to
crash_ipi_callback()

This patch takes approach #3.

Care is taken to enable this only for powenv platforms
via crash_wake_offline (a global value set at setup
time). The crash code sends out IPI's to all CPU's
which then move to crash_ipi_callback and kexec_smp_wait().

Signed-off-by: Balbir Singh 
---

Changelog
 - Michael Ellerman recommended refactoring
   the code so as to not modify major portions of the
   NMI handling/IPI code.

 arch/powerpc/include/asm/kexec.h |  2 ++
 arch/powerpc/kernel/crash.c  | 13 -
 arch/powerpc/kernel/smp.c| 18 ++
 arch/powerpc/platforms/powernv/smp.c | 17 +
 4 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index 4419d435639a..9dcbfa6bbb91 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -73,6 +73,8 @@ extern void kexec_smp_wait(void); /* get and clear naca 
physid, wait for
  master to copy new code to 0 */
 extern int crashing_cpu;
 extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+extern void crash_ipi_callback(struct pt_regs *);
+extern int crash_wake_offline;
 
 struct kimage;
 struct pt_regs;
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 29c56ca2ddfd..00b215125d3e 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -44,6 +44,14 @@
 #define REAL_MODE_TIMEOUT  1
 
 static int time_to_dump;
+/*
+ * crash_wake_offline should be set to 1 by platforms that intend to wake
+ * up offline cpus prior to jumping to a kdump kernel. Currently powernv
+ * sets it to 1, since we want to avoid things from happening when an
+ * offline CPU wakes up due to something like an HMI (malfunction error),
+ * which propagates to all threads.
+ */
+int crash_wake_offline;
 
 #define CRASH_HANDLER_MAX 3
 /* List of shutdown handles */
@@ -63,7 +71,7 @@ static int handle_fault(struct pt_regs *regs)
 #ifdef CONFIG_SMP
 
 static atomic_t cpus_in_crash;
-static void crash_ipi_callback(struct pt_regs *regs)
+void crash_ipi_callback(struct pt_regs *regs)
 {
static cpumask_t cpus_state_saved = CPU_MASK_NONE;
 
@@ -106,6 +114,9 @@ static void crash_kexec_prepare_cpus(int cpu)
 
printk(KERN_EMERG "Sending IPI to other CPUs\n");
 
+   if (crash_wake_offline)
+   ncpus = num_present_cpus() - 1;
+
crash_send_ipi(crash_ipi_callback);
smp_wmb();
 
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index e0a4c1f82e25..bbe7634b3a43 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -543,7 +543,25 @@ void smp_send_debugger_break(void)
 #ifdef CONFIG_KEXEC_CORE
 void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
 {
+   int cpu;
+
smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_ipi_callback, 100);
+   if (kdump_in_progress() && crash_wake_offline) {
+   for_each_present_cpu(cpu) {
+   if (cpu_online(cpu))
+   continue;
+   /*
+* crash_ipi_callback will wait for
+* all cpus, including offline CPUs.
+* We don't care about nmi_ipi_function.
+* Offline cpus will jump straight into
+* crash_ipi_callback, we can skip the
+* entire NMI dance and waiting for
+* cpus to clear pending mask, etc.
+*/
+   do_smp_send_nmi_ipi(cpu);
+   }
+   }
 }
 #endif
 
diff --git a/arch/powerpc/platforms/powernv/smp.c 
b/arch/powerpc/platforms/powernv/smp.c
index ba030669eca1..49a23f9db5f0 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -37,6 +37,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include "powernv.h"
 
@@ -212,6 +214,18 @@ static void pn

[PATCH 1/2] powerpc/crash: Remove the test for cpu_online in the IPI callback

2017-12-13 Thread Balbir Singh
Our check was extra cautious, we've audited crash_send_ipi
and it sends an IPI only to online CPU's. Removal of this
check should have not functional impact on crash kdump.

Signed-off-by: Balbir Singh 
---
 arch/powerpc/kernel/crash.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index cbabb5adccd9..29c56ca2ddfd 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -69,9 +69,6 @@ static void crash_ipi_callback(struct pt_regs *regs)
 
int cpu = smp_processor_id();
 
-   if (!cpu_online(cpu))
-   return;
-
hard_irq_disable();
if (!cpumask_test_cpu(cpu, &cpus_state_saved)) {
crash_save_cpu(regs, cpu);
-- 
2.13.6