* Re: [PATCH] cpuidle/powernv: Populate cpuidle state details by querying the device-tree
From: Lorenzo Pieralisi @ 2014-10-24 14:30 UTC (permalink / raw)
To: Preeti U Murthy
Cc: linux-pm@vger.kernel.org, rjw@rjwysocki.net,
shreyas@linux.vnet.ibm.com, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20141014075259.11810.50996.stgit@preeti.in.ibm.com>
On Tue, Oct 14, 2014 at 08:53:00AM +0100, Preeti U Murthy wrote:
> We hard code the metrics relevant for cpuidle states in the kernel today.
> Instead pick them up from the device tree so that they remain relevant
> and updated for the system that the kernel is running on.
>
> Cc: linux-pm@vger.kernel.org
> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> Cc: devicetree@vger.kernel.org
> Cc: linuxppc-dev@lists.ozlabs.org
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Signed-off-by: Preeti U. Murthy <preeti@linux.vnet.ibm.com>
> Signed-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com>
> ---
>
> drivers/cpuidle/cpuidle-powernv.c | 27 ++++++++++++++++++++++-----
> 1 file changed, 22 insertions(+), 5 deletions(-)
Device tree properties should be documented, and these bindings are
getting very similar to the ones I have just completed for ARM,
I wonder whether we should take the generic bits out of ARM bindings (ie
exit_latency) and make those available to other architectures.
Thanks,
Lorenzo
>
> diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
> index fa79392..b57681d 100644
> --- a/drivers/cpuidle/cpuidle-powernv.c
> +++ b/drivers/cpuidle/cpuidle-powernv.c
> @@ -165,7 +165,8 @@ static int powernv_add_idle_states(void)
> int nr_idle_states = 1; /* Snooze */
> int dt_idle_states;
> const __be32 *idle_state_flags;
> - u32 len_flags, flags;
> + const __be32 *idle_state_latency;
> + u32 len_flags, flags, latency_ns;
> int i;
>
> /* Currently we have snooze statically defined */
> @@ -182,18 +183,32 @@ static int powernv_add_idle_states(void)
> return nr_idle_states;
> }
>
> + idle_state_latency = of_get_property(power_mgt,
> + "ibm,cpu-idle-state-latencies-ns", NULL);
> + if (!idle_state_latency) {
> + pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-latencies-ns\n");
> + return nr_idle_states;
> + }
> +
> dt_idle_states = len_flags / sizeof(u32);
>
> for (i = 0; i < dt_idle_states; i++) {
>
> flags = be32_to_cpu(idle_state_flags[i]);
> +
> + /* Cpuidle accepts exit_latency in us and we estimate
> + * target residency to be 10x exit_latency
> + */
> + latency_ns = be32_to_cpu(idle_state_latency[i]);
> if (flags & IDLE_USE_INST_NAP) {
> /* Add NAP state */
> strcpy(powernv_states[nr_idle_states].name, "Nap");
> strcpy(powernv_states[nr_idle_states].desc, "Nap");
> powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
> - powernv_states[nr_idle_states].exit_latency = 10;
> - powernv_states[nr_idle_states].target_residency = 100;
> + powernv_states[nr_idle_states].exit_latency =
> + ((unsigned int)latency_ns) / 1000;
> + powernv_states[nr_idle_states].target_residency =
> + ((unsigned int)latency_ns / 100);
> powernv_states[nr_idle_states].enter = &nap_loop;
> nr_idle_states++;
> }
> @@ -204,8 +219,10 @@ static int powernv_add_idle_states(void)
> strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
> powernv_states[nr_idle_states].flags =
> CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
> - powernv_states[nr_idle_states].exit_latency = 300;
> - powernv_states[nr_idle_states].target_residency = 1000000;
> + powernv_states[nr_idle_states].exit_latency =
> + ((unsigned int)latency_ns) / 1000;
> + powernv_states[nr_idle_states].target_residency =
> + ((unsigned int)latency_ns / 100);
> powernv_states[nr_idle_states].enter = &fastsleep_loop;
> nr_idle_states++;
> }
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH v2 08/47] kernel: Move pm_power_off to common code
From: Guenter Roeck @ 2014-10-24 15:53 UTC (permalink / raw)
To: James Hogan
Cc: linux-mips, linux-m68k, linux-ia64, linux-sh, linux, sparclinux,
linux-s390, linux-am33-list, linux-c6x-dev, linux-hexagon, x86,
xen-devel, linux-xtensa, user-mode-linux-devel, linux-pm,
adi-buildroot-devel, user-mode-linux-user, linux-metag,
linux-arm-kernel, linux-parisc, linux-cris-kernel, linux-kernel,
linux-alpha, linux390, linuxppc-dev
In-Reply-To: <544A2017.7020804@imgtec.com>
On Fri, Oct 24, 2014 at 10:47:03AM +0100, James Hogan wrote:
> Hi Guenter,
>
> On 21/10/14 05:12, Guenter Roeck wrote:
> > pm_power_off is defined for all architectures. Move it to common code.
> >
> > Have all architectures call do_kernel_power_off instead of pm_power_off.
> > Some architectures point pm_power_off to machine_power_off. For those,
> > call do_kernel_power_off from machine_power_off instead.
> >
> > Acked-by: David Vrabel <david.vrabel@citrix.com>
> > Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
> > Acked-by: Hirokazu Takata <takata@linux-m32r.org>
> > Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
> > Acked-by: Max Filippov <jcmvbkbc@gmail.com>
> > Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net>
> > Acked-by: Richard Weinberger <richard@nod.at>
> > Acked-by: Xuetao Guan <gxt@mprc.pku.edu.cn>
>
> For metag:
> Acked-by: James Hogan <james.hogan@imgtec.com>
>
Thanks!
Guenter
^ permalink raw reply
* Re: [PATCH V2 1/2] mm: Update generic gup implementation to handle hugepage directory
From: James Bottomley @ 2014-10-24 16:22 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: aarcange, linux-arch, steve.capper, linux-kernel, linux-mm,
aneesh.kumar, hannes, akpm, linuxppc-dev, David Miller
In-Reply-To: <1414107635.364.91.camel@pasglop>
On Fri, 2014-10-24 at 10:40 +1100, Benjamin Herrenschmidt wrote:
> On Thu, 2014-10-23 at 18:40 -0400, David Miller wrote:
> > Hey guys, was looking over the generic GUP while working on a sparc64
> > issue and I noticed that you guys do speculative page gets, and after
> > talking with Johannes Weiner (CC:'d) about this we don't see how it
> > could be necessary.
> >
> > If interrupts are disabled during the page table scan (which they
> > are), no IPI tlb flushes can arrive. Therefore any removal from the
> > page tables is guarded by interrupts being re-enabled. And as a
> > result, page counts of pages we see in the page tables must always
> > have a count > 0.
> >
> > x86 does direct atomic_add() on &page->_count because of this
> > invariant and I would rather see the generic version do this too.
>
> This is of course only true of archs who use IPIs for TLB flushes, so if
> we are going down the path of not being speculative, powerpc would have
> to go back to doing its own since our broadcast TLB flush means we
> aren't protected (we are only protected vs. the page tables themselves
> being freed since we do that via sched RCU).
>
> AFAIK, ARM also broadcasts TLB flushes...
Parisc does this. As soon as one CPU issues a TLB purge, it's broadcast
to all the CPUs on the inter-CPU bus. The next instruction isn't
executed until they respond.
But this is only for our CPU TLB. There's no other external
consequence, so removal from the page tables isn't effected by this TLB
flush, therefore the theory on which Dave bases the change to
atomic_add() should work for us (of course, atomic_add is lock add
unlock on our CPU, so it's not going to be of much benefit).
James
> Another option would be to make the generic code use something defined
> by the arch to decide whether to use speculative get or
> not. I like the idea of keeping the bulk of that code generic...
>
> Cheers,
> Ben.
>
> > --
> > To unsubscribe, send a message with 'unsubscribe linux-mm' in
> > the body to majordomo@kvack.org. For more info on Linux MM,
> > see: http://www.linux-mm.org/ .
> > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
>
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@kvack.org. For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
>
^ permalink raw reply
* [PATCH 0/2] ASoC: fsl: Use dynamic slot width for ESAI.
From: Nicolin Chen @ 2014-10-24 23:48 UTC (permalink / raw)
To: broonie, b02247
Cc: alsa-devel, timur, lgirdwood, linux-kernel, Li.Xiubo,
linuxppc-dev
This series of patches add the support of dynamic slot width for
ESAI driver. To do this, the PATCH-1 removes the fixed width. In
order not to break those platforms that use fixed width, there
comes the PATCH-2 to apply an override of slot_width.
@Shengjiu,
Will you be available to test this series on Sabre Auto for both
Master and Slave cases? I'd like to wait for your Test-by. Thanks.
Nicolin Chen (2):
ASoC: fsl_esai: Use dynamic slot width as default
ASoC: fsl-asoc-card: Add slot_width setting for cpu-dai
sound/soc/fsl/fsl-asoc-card.c | 12 ++++++++++++
sound/soc/fsl/fsl_esai.c | 12 +++++++-----
2 files changed, 19 insertions(+), 5 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH] ASoC: fsl-asoc-card: Don't bypass settings if cpu-dai is Master
From: Nicolin Chen @ 2014-10-24 23:48 UTC (permalink / raw)
To: broonie, b02247
Cc: alsa-devel, timur, lgirdwood, linux-kernel, Li.Xiubo,
linuxppc-dev
In-Reply-To: <cover.1414193668.git.nicoleotsuka@gmail.com>
When cpu-dai is the DAI Master (CBM_CFx), it may need some configurations,
set_sysclk() call for eample, for cpu-dai side in the hw_params(), even if
the set_bias_level() has already taken care of the codec-dai side.
So this patch just simply adds an additional condition.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl-asoc-card.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 007c772..14572e6 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -125,7 +125,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
priv->sample_rate = params_rate(params);
priv->sample_format = params_format(params);
- if (priv->card.set_bias_level)
+ /*
+ * If codec-dai is DAI Master and all configurations are already in the
+ * set_bias_level(), bypass the remaining settings in hw_params().
+ * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS.
+ */
+ if (priv->card.set_bias_level && priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM)
return 0;
/* Specific configurations of DAIs starts from here */
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] ASoC: fsl_esai: Use dynamic slot width as default
From: Nicolin Chen @ 2014-10-24 23:48 UTC (permalink / raw)
To: broonie, b02247
Cc: alsa-devel, timur, lgirdwood, linux-kernel, Li.Xiubo,
linuxppc-dev
In-Reply-To: <cover.1414193668.git.nicoleotsuka@gmail.com>
The driver previously used 32-bit fixed slot width as default.
In result, ESAI might use 32-bit length to capture 16-bit width
audio slot from CODEC side when ESAI is running as DAI slave.
So this patch just removes the default slot_width so as to use
dynamic slot width. If there comes a specific situation that
needs a fixed width, the machine driver shall set slot_width
via set_tdm_slot() so as to let the ESAI driver replace the
dynamic width policy with the fixed value.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_esai.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index a645e29..ca319d5 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -513,10 +513,15 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
u32 width = snd_pcm_format_width(params_format(params));
u32 channels = params_channels(params);
u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
+ u32 slot_width = width;
u32 bclk, mask, val;
int ret;
- bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots;
+ /* Override slot_width if being specifially set */
+ if (esai_priv->slot_width)
+ slot_width = esai_priv->slot_width;
+
+ bclk = params_rate(params) * slot_width * esai_priv->slots;
ret = fsl_esai_set_bclk(dai, tx, bclk);
if (ret)
@@ -538,7 +543,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
- val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
+ val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
@@ -780,9 +785,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
return ret;
}
- /* Set a default slot size */
- esai_priv->slot_width = 32;
-
/* Set a default slot number */
esai_priv->slots = 2;
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] ASoC: fsl-asoc-card: Add slot_width setting for cpu-dai
From: Nicolin Chen @ 2014-10-24 23:48 UTC (permalink / raw)
To: broonie, b02247
Cc: alsa-devel, timur, lgirdwood, linux-kernel, Li.Xiubo,
linuxppc-dev
In-Reply-To: <cover.1414193668.git.nicoleotsuka@gmail.com>
ESAI may need to use fixed slot width to comply with external
CODEC. So this set_tdm_slot() call will allow the ESAI driver
to override its default dynamic slot width policy.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl-asoc-card.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 14572e6..3f6959c 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -51,6 +51,7 @@ struct codec_priv {
* @sysclk_freq[2]: SYSCLK rates for set_sysclk()
* @sysclk_dir[2]: SYSCLK directions for set_sysclk()
* @sysclk_id[2]: SYSCLK ids for set_sysclk()
+ * @slot_width: Slot width of each frame
*
* Note: [1] for tx and [0] for rx
*/
@@ -58,6 +59,7 @@ struct cpu_priv {
unsigned long sysclk_freq[2];
u32 sysclk_dir[2];
u32 sysclk_id[2];
+ u32 slot_width;
};
/**
@@ -142,6 +144,15 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (cpu_priv->slot_width) {
+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2,
+ cpu_priv->slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set TDM slot for cpu dai\n");
+ return ret;
+ }
+ }
+
return 0;
}
@@ -453,6 +464,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
+ priv->cpu_priv.slot_width = 32;
priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
--
1.9.1
^ permalink raw reply related
* [PATCH] ASoC: fsl_asrc: Add reg_defaults for regmap to fix kernel dump
From: Nicolin Chen @ 2014-10-25 2:03 UTC (permalink / raw)
To: broonie; +Cc: alsa-devel, linuxppc-dev, linux-kernel
Kernel dump (WARN_ON) ocurred during system boot-up inside regmap_write():
------------[ cut here ]------------
WARNING: CPU: 0 PID: 47 at kernel/locking/lockdep.c:2744 lockdep_trace_alloc+0xe8/0x108()
DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags))
Modules linked in:
CPU: 0 PID: 47 Comm: kworker/u2:2 Not tainted 3.18.0-rc1-10245-gb75d289-dirty #56
Workqueue: deferwq deferred_probe_work_func
Backtrace:
[<80012294>] (dump_backtrace) from [<80012578>] (show_stack+0x18/0x1c)
r6:8097c73c r5:8097c73c r4:00000000 r3:be33ba80
[<80012560>] (show_stack) from [<806aac48>] (dump_stack+0x8c/0xa4)
[<806aabbc>] (dump_stack) from [<8002a694>] (warn_slowpath_common+0x70/0x94)
r6:80062838 r5:00000009 r4:bd827b30 r3:be33ba80
[<8002a624>] (warn_slowpath_common) from [<8002a6f0>] (warn_slowpath_fmt+0x38/0x40)
r8:00000004 r7:00000001 r6:000080d0 r5:60000193 r4:bd826010
[<8002a6bc>] (warn_slowpath_fmt) from [<80062838>] (lockdep_trace_alloc+0xe8/0x108)
r3:80831590 r2:8082e160
[<80062750>] (lockdep_trace_alloc) from [<800ea5dc>] (kmem_cache_alloc+0x28/0x134)
r5:000080d0 r4:be001f00
[<800ea5b4>] (kmem_cache_alloc) from [<8038d72c>] (regcache_rbtree_write+0x15c/0x648)
r10:00000000 r9:0000001c r8:00000004 r7:00000001 r6:00000000 r5:bd819a00
r4:00000000 r3:811aea88
[<8038d5d0>] (regcache_rbtree_write) from [<8038c4d8>] (regcache_write+0x5c/0x64)
r10:be3f9f88 r9:00000000 r8:00000004 r7:00000001 r6:00000000 r5:00000001
r4:bd819a00
[<8038c47c>] (regcache_write) from [<8038b0dc>] (_regmap_raw_write+0x134/0x5f4)
r6:be3f9f84 r5:00000001 r4:bd819a00 r3:00000001
[<8038afa8>] (_regmap_raw_write) from [<8038b610>] (_regmap_bus_raw_write+0x74/0x94)
r10:00000000 r9:00000001 r8:be3fb080 r7:bd819a00 r6:00000001 r5:00000000
r4:bd819a00
[<8038b59c>] (_regmap_bus_raw_write) from [<8038a8b4>] (_regmap_write+0x60/0x9c)
r6:00000001 r5:00000000 r4:bd819a00 r3:8038b59c
[<8038a854>] (_regmap_write) from [<8038ba24>] (regmap_write+0x48/0x68)
r7:bd81ad80 r6:00000001 r5:00000000 r4:bd819a00
[<8038b9dc>] (regmap_write) from [<80528f30>] (fsl_asrc_dai_probe+0x34/0x104)
r6:bd888628 r5:be3fb080 r4:be3b4410 r3:be3b442c
------------[ dump end ]------------
=============================================================================
2741 /*
2742 * Oi! Can't be having __GFP_FS allocations with IRQs disabled.
2743 */
2744 if (DEBUG_LOCKS_WARN_ON(irqs_disabled_flags(flags)))
2745 return;
=============================================================================
By looking at 2744 line, we can get that it's because regcache_rbtree_write()
would call kmalloc() with GFP flag if it couldn't find an existing block to
insert nodes while this kmalloc() call is inside a spin_lock_irq_save pair,
i.e. IRQs disabled.
Even though this may be a bug that should be fixed, I still try to send this
patch as a quick fix (work around) since it does no harm to assign default
values of every registers when using regcache.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
sound/soc/fsl/fsl_asrc.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index f2d8652..817d304 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -684,12 +684,38 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg)
}
}
+static struct reg_default fsl_asrc_reg[] = {
+ { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 },
+ { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 },
+ { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 },
+ { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 },
+ { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 },
+ { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 },
+ { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 },
+ { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 },
+ { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 },
+ { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 },
+ { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 },
+ { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 },
+ { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 },
+ { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 },
+ { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 },
+ { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 },
+ { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 },
+ { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 },
+ { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 },
+ { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 },
+ { REG_ASRMCR1C, 0x0000 },
+};
+
static const struct regmap_config fsl_asrc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = REG_ASRMCR1C,
+ .reg_defaults = fsl_asrc_reg,
+ .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg),
.readable_reg = fsl_asrc_readable_reg,
.volatile_reg = fsl_asrc_volatile_reg,
.writeable_reg = fsl_asrc_writeable_reg,
--
1.9.1
^ permalink raw reply related
* Re: [PATCH V2 1/2] mm: Update generic gup implementation to handle hugepage directory
From: Aneesh Kumar K.V @ 2014-10-25 10:30 UTC (permalink / raw)
To: David Miller, akpm
Cc: aarcange, linux-arch, steve.capper, hannes, linux-kernel,
linux-mm, linuxppc-dev
In-Reply-To: <20141023.184035.388557314666522484.davem@davemloft.net>
David Miller <davem@davemloft.net> writes:
> Hey guys, was looking over the generic GUP while working on a sparc64
> issue and I noticed that you guys do speculative page gets, and after
> talking with Johannes Weiner (CC:'d) about this we don't see how it
> could be necessary.
>
> If interrupts are disabled during the page table scan (which they
> are), no IPI tlb flushes can arrive. Therefore any removal from the
> page tables is guarded by interrupts being re-enabled. And as a
> result, page counts of pages we see in the page tables must always
> have a count > 0.
>
> x86 does direct atomic_add() on &page->_count because of this
> invariant and I would rather see the generic version do this too.
But that won't work with RCU GUP. For example on powerpc the tlb flush
doesn't involve an IPI and we can essentially find page count 0.
-aneesh
^ permalink raw reply
* [PATCH V3 1/2] mm: Update generic gup implementation to handle hugepage directory
From: Aneesh Kumar K.V @ 2014-10-25 10:44 UTC (permalink / raw)
To: akpm, Steve Capper, Andrea Arcangeli, benh, mpe
Cc: linux-arch, linux-mm, linuxppc-dev, linux-kernel,
Aneesh Kumar K.V
Update generic gup implementation with powerpc specific details.
On powerpc at pmd level we can have hugepte, normal pmd pointer
or a pointer to the hugepage directory.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
Changes from V3:
* Explain pgd_huge, also move the definition to linux/hugetlb.h.
Both pgd_huge and is_hugepd are related to hugepages and hugetlb.h
is the right header
arch/arm/include/asm/pgtable.h | 2 +
arch/arm64/include/asm/pgtable.h | 2 +
arch/powerpc/include/asm/page.h | 1 +
include/linux/hugetlb.h | 30 +++++++++++
include/linux/mm.h | 7 +++
mm/gup.c | 113 +++++++++++++++++++--------------------
6 files changed, 96 insertions(+), 59 deletions(-)
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 3b30062..c52d261 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -181,6 +181,8 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
+#define pgd_huge(pgd) (0)
+
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_present(pmd) (pmd_val(pmd))
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 41a43bf..f532a14 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -464,6 +464,8 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
+#define pgd_huge(pgd) (0)
+
/*
* Encode and decode a swap entry:
* bits 0-1: present (must be zero)
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 26fe1ae..f973fce 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -380,6 +380,7 @@ static inline int hugepd_ok(hugepd_t hpd)
#endif
#define is_hugepd(pdep) (hugepd_ok(*((hugepd_t *)(pdep))))
+#define pgd_huge pgd_huge
int pgd_huge(pgd_t pgd);
#else /* CONFIG_HUGETLB_PAGE */
#define is_hugepd(pdep) 0
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 6e6d338..de63dbc 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -175,6 +175,36 @@ static inline void __unmap_hugepage_range(struct mmu_gather *tlb,
}
#endif /* !CONFIG_HUGETLB_PAGE */
+/*
+ * hugepages at page global directory. If arch support
+ * hugepages at pgd level, they need to define this.
+ */
+#ifndef pgd_huge
+#define pgd_huge(x) 0
+#endif
+
+#ifndef is_hugepd
+/*
+ * Some architectures requires a hugepage directory format that is
+ * required to support multiple hugepage sizes. For example
+ * a4fe3ce7699bfe1bd88f816b55d42d8fe1dac655 introduced the same
+ * on powerpc. This allows for a more flexible hugepage pagetable
+ * layout.
+ */
+typedef struct { unsigned long pd; } hugepd_t;
+#define is_hugepd(hugepd) (0)
+#define __hugepd(x) ((hugepd_t) { (x) })
+static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
+ unsigned pdshift, unsigned long end,
+ int write, struct page **pages, int *nr)
+{
+ return 0;
+}
+#else
+extern int gup_huge_pd(hugepd_t hugepd, unsigned long addr,
+ unsigned pdshift, unsigned long end,
+ int write, struct page **pages, int *nr);
+#endif
#define HUGETLB_ANON_FILE "anon_hugepage"
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 02d11ee..31d7fac 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1219,6 +1219,13 @@ long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
struct vm_area_struct **vmas);
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages);
+
+#ifdef CONFIG_HAVE_GENERIC_RCU_GUP
+extern int gup_huge_pte(pte_t orig, pte_t *ptep, unsigned long addr,
+ unsigned long sz, unsigned long end, int write,
+ struct page **pages, int *nr);
+#endif
+
struct kvec;
int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
struct page **pages);
diff --git a/mm/gup.c b/mm/gup.c
index cd62c8c..30773f3 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -786,65 +786,31 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
}
#endif /* __HAVE_ARCH_PTE_SPECIAL */
-static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr,
- unsigned long end, int write, struct page **pages, int *nr)
+int gup_huge_pte(pte_t orig, pte_t *ptep, unsigned long addr,
+ unsigned long sz, unsigned long end, int write,
+ struct page **pages, int *nr)
{
- struct page *head, *page, *tail;
int refs;
+ unsigned long pte_end;
+ struct page *head, *page, *tail;
- if (write && !pmd_write(orig))
- return 0;
-
- refs = 0;
- head = pmd_page(orig);
- page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
- tail = page;
- do {
- VM_BUG_ON_PAGE(compound_head(page) != head, page);
- pages[*nr] = page;
- (*nr)++;
- page++;
- refs++;
- } while (addr += PAGE_SIZE, addr != end);
- if (!page_cache_add_speculative(head, refs)) {
- *nr -= refs;
+ if (write && !pte_write(orig))
return 0;
- }
- if (unlikely(pmd_val(orig) != pmd_val(*pmdp))) {
- *nr -= refs;
- while (refs--)
- put_page(head);
+ if (!pte_present(orig))
return 0;
- }
- /*
- * Any tail pages need their mapcount reference taken before we
- * return. (This allows the THP code to bump their ref count when
- * they are split into base pages).
- */
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
- return 1;
-}
-
-static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
- unsigned long end, int write, struct page **pages, int *nr)
-{
- struct page *head, *page, *tail;
- int refs;
+ pte_end = (addr + sz) & ~(sz-1);
+ if (pte_end < end)
+ end = pte_end;
- if (write && !pud_write(orig))
- return 0;
+ /* hugepages are never "special" */
+ VM_BUG_ON(!pfn_valid(pte_pfn(orig)));
refs = 0;
- head = pud_page(orig);
- page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
+ head = pte_page(orig);
+ page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
tail = page;
do {
VM_BUG_ON_PAGE(compound_head(page) != head, page);
@@ -859,13 +825,18 @@ static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr,
return 0;
}
- if (unlikely(pud_val(orig) != pud_val(*pudp))) {
+ if (unlikely(pte_val(orig) != pte_val(*ptep))) {
*nr -= refs;
while (refs--)
put_page(head);
return 0;
}
+ /*
+ * Any tail pages need their mapcount reference taken before we
+ * return. (This allows the THP code to bump their ref count when
+ * they are split into base pages).
+ */
while (refs--) {
if (PageTail(tail))
get_huge_page_tail(tail);
@@ -898,10 +869,19 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
if (pmd_numa(pmd))
return 0;
- if (!gup_huge_pmd(pmd, pmdp, addr, next, write,
- pages, nr))
+ if (!gup_huge_pte(__pte(pmd_val(pmd)), (pte_t *)pmdp,
+ addr, PMD_SIZE, next,
+ write, pages, nr))
return 0;
+ } else if (unlikely(is_hugepd(__hugepd(pmd_val(pmd))))) {
+ /*
+ * architecture have different format for hugetlbfs
+ * pmd format and THP pmd format
+ */
+ if (!gup_huge_pd(__hugepd(pmd_val(pmd)), addr,
+ PMD_SHIFT, next, write, pages, nr))
+ return 0;
} else if (!gup_pte_range(pmd, addr, next, write, pages, nr))
return 0;
} while (pmdp++, addr = next, addr != end);
@@ -909,22 +889,27 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
return 1;
}
-static int gup_pud_range(pgd_t *pgdp, unsigned long addr, unsigned long end,
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
int write, struct page **pages, int *nr)
{
unsigned long next;
pud_t *pudp;
- pudp = pud_offset(pgdp, addr);
+ pudp = pud_offset(&pgd, addr);
do {
pud_t pud = ACCESS_ONCE(*pudp);
next = pud_addr_end(addr, end);
if (pud_none(pud))
return 0;
- if (pud_huge(pud)) {
- if (!gup_huge_pud(pud, pudp, addr, next, write,
- pages, nr))
+ if (unlikely(pud_huge(pud))) {
+ if (!gup_huge_pte(__pte(pud_val(pud)), (pte_t *)pudp,
+ addr, PUD_SIZE, next,
+ write, pages, nr))
+ return 0;
+ } else if (unlikely(is_hugepd(__hugepd(pud_val(pud))))) {
+ if (!gup_huge_pd(__hugepd(pud_val(pud)), addr,
+ PUD_SHIFT, next, write, pages, nr))
return 0;
} else if (!gup_pmd_range(pud, addr, next, write, pages, nr))
return 0;
@@ -970,10 +955,21 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
local_irq_save(flags);
pgdp = pgd_offset(mm, addr);
do {
+ pgd_t pgd = ACCESS_ONCE(*pgdp);
+
next = pgd_addr_end(addr, end);
- if (pgd_none(*pgdp))
+ if (pgd_none(pgd))
break;
- else if (!gup_pud_range(pgdp, addr, next, write, pages, &nr))
+ if (unlikely(pgd_huge(pgd))) {
+ if (!gup_huge_pte(__pte(pgd_val(pgd)), (pte_t *)pgdp,
+ addr, PGDIR_SIZE, next,
+ write, pages, &nr))
+ break;
+ } else if (unlikely(is_hugepd(__hugepd(pgd_val(pgd))))) {
+ if (!gup_huge_pd(__hugepd(pgd_val(pgd)), addr,
+ PGDIR_SHIFT, next, write, pages, &nr))
+ break;
+ } else if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
break;
} while (pgdp++, addr = next, addr != end);
local_irq_restore(flags);
@@ -1028,5 +1024,4 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
return ret;
}
-
#endif /* CONFIG_HAVE_GENERIC_RCU_GUP */
--
2.1.0
^ permalink raw reply related
* [PATCH V3 2/2] arch/powerpc: Switch to generic RCU get_user_pages_fast
From: Aneesh Kumar K.V @ 2014-10-25 10:44 UTC (permalink / raw)
To: akpm, Steve Capper, Andrea Arcangeli, benh, mpe
Cc: linux-arch, linux-mm, linuxppc-dev, linux-kernel,
Aneesh Kumar K.V
In-Reply-To: <1414233860-7683-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>
This patch switch the ppc arch to use the generic RCU based
gup implementation.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/hugetlb.h | 8 +-
arch/powerpc/include/asm/page.h | 3 +-
arch/powerpc/include/asm/pgtable-ppc64.h | 1 -
arch/powerpc/include/asm/pgtable.h | 5 -
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/gup.c | 235 -------------------------------
arch/powerpc/mm/hugetlbpage.c | 27 ++--
8 files changed, 21 insertions(+), 261 deletions(-)
delete mode 100644 arch/powerpc/mm/gup.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 88eace4..7af887d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -148,6 +148,7 @@ config PPC
select HAVE_ARCH_AUDITSYSCALL
select ARCH_SUPPORTS_ATOMIC_RMW
select DCACHE_WORD_ACCESS if PPC64 && CPU_LITTLE_ENDIAN
+ select HAVE_GENERIC_RCU_GUP
config GENERIC_CSUM
def_bool CPU_LITTLE_ENDIAN
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index 766b77d..1d53a65 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -48,7 +48,7 @@ static inline unsigned int hugepd_shift(hugepd_t hpd)
#endif /* CONFIG_PPC_BOOK3S_64 */
-static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr,
+static inline pte_t *hugepte_offset(hugepd_t hpd, unsigned long addr,
unsigned pdshift)
{
/*
@@ -58,9 +58,9 @@ static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr,
*/
unsigned long idx = 0;
- pte_t *dir = hugepd_page(*hpdp);
+ pte_t *dir = hugepd_page(hpd);
#ifndef CONFIG_PPC_FSL_BOOK3E
- idx = (addr & ((1UL << pdshift) - 1)) >> hugepd_shift(*hpdp);
+ idx = (addr & ((1UL << pdshift) - 1)) >> hugepd_shift(hpd);
#endif
return dir + idx;
@@ -193,7 +193,7 @@ static inline void flush_hugetlb_page(struct vm_area_struct *vma,
}
#define hugepd_shift(x) 0
-static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr,
+static inline pte_t *hugepte_offset(hugepd_t hpd, unsigned long addr,
unsigned pdshift)
{
return 0;
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index f973fce..69c0598 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -379,13 +379,14 @@ static inline int hugepd_ok(hugepd_t hpd)
}
#endif
-#define is_hugepd(pdep) (hugepd_ok(*((hugepd_t *)(pdep))))
+#define is_hugepd(hpd) (hugepd_ok(hpd))
#define pgd_huge pgd_huge
int pgd_huge(pgd_t pgd);
#else /* CONFIG_HUGETLB_PAGE */
#define is_hugepd(pdep) 0
#define pgd_huge(pgd) 0
#endif /* CONFIG_HUGETLB_PAGE */
+#define __hugepd(x) ((hugepd_t) { (x) })
struct page;
extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index ae153c4..29c3624 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -575,6 +575,5 @@ static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
*/
return true;
}
-
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 316f9a5..4a67c1d 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -274,11 +274,6 @@ extern void paging_init(void);
*/
extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
-extern int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, unsigned long addr,
- unsigned long end, int write, struct page **pages, int *nr);
-
-extern int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
- unsigned long end, int write, struct page **pages, int *nr);
#ifndef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_large(pmd) 0
#define has_transparent_hugepage() 0
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 325e861..438dcd3 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -6,7 +6,7 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
-obj-y := fault.o mem.o pgtable.o gup.o mmap.o \
+obj-y := fault.o mem.o pgtable.o mmap.o \
init_$(CONFIG_WORD_SIZE).o \
pgtable_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
deleted file mode 100644
index d874668..0000000
--- a/arch/powerpc/mm/gup.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Lockless get_user_pages_fast for powerpc
- *
- * Copyright (C) 2008 Nick Piggin
- * Copyright (C) 2008 Novell Inc.
- */
-#undef DEBUG
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/hugetlb.h>
-#include <linux/vmstat.h>
-#include <linux/pagemap.h>
-#include <linux/rwsem.h>
-#include <asm/pgtable.h>
-
-#ifdef __HAVE_ARCH_PTE_SPECIAL
-
-/*
- * The performance critical leaf functions are made noinline otherwise gcc
- * inlines everything into a single function which results in too much
- * register pressure.
- */
-static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
- unsigned long end, int write, struct page **pages, int *nr)
-{
- unsigned long mask, result;
- pte_t *ptep;
-
- result = _PAGE_PRESENT|_PAGE_USER;
- if (write)
- result |= _PAGE_RW;
- mask = result | _PAGE_SPECIAL;
-
- ptep = pte_offset_kernel(&pmd, addr);
- do {
- pte_t pte = ACCESS_ONCE(*ptep);
- struct page *page;
- /*
- * Similar to the PMD case, NUMA hinting must take slow path
- */
- if (pte_numa(pte))
- return 0;
-
- if ((pte_val(pte) & mask) != result)
- return 0;
- VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
- page = pte_page(pte);
- if (!page_cache_get_speculative(page))
- return 0;
- if (unlikely(pte_val(pte) != pte_val(*ptep))) {
- put_page(page);
- return 0;
- }
- pages[*nr] = page;
- (*nr)++;
-
- } while (ptep++, addr += PAGE_SIZE, addr != end);
-
- return 1;
-}
-
-static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
- int write, struct page **pages, int *nr)
-{
- unsigned long next;
- pmd_t *pmdp;
-
- pmdp = pmd_offset(&pud, addr);
- do {
- pmd_t pmd = ACCESS_ONCE(*pmdp);
-
- next = pmd_addr_end(addr, end);
- /*
- * If we find a splitting transparent hugepage we
- * return zero. That will result in taking the slow
- * path which will call wait_split_huge_page()
- * if the pmd is still in splitting state
- */
- if (pmd_none(pmd) || pmd_trans_splitting(pmd))
- return 0;
- if (pmd_huge(pmd) || pmd_large(pmd)) {
- /*
- * NUMA hinting faults need to be handled in the GUP
- * slowpath for accounting purposes and so that they
- * can be serialised against THP migration.
- */
- if (pmd_numa(pmd))
- return 0;
-
- if (!gup_hugepte((pte_t *)pmdp, PMD_SIZE, addr, next,
- write, pages, nr))
- return 0;
- } else if (is_hugepd(pmdp)) {
- if (!gup_hugepd((hugepd_t *)pmdp, PMD_SHIFT,
- addr, next, write, pages, nr))
- return 0;
- } else if (!gup_pte_range(pmd, addr, next, write, pages, nr))
- return 0;
- } while (pmdp++, addr = next, addr != end);
-
- return 1;
-}
-
-static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
- int write, struct page **pages, int *nr)
-{
- unsigned long next;
- pud_t *pudp;
-
- pudp = pud_offset(&pgd, addr);
- do {
- pud_t pud = ACCESS_ONCE(*pudp);
-
- next = pud_addr_end(addr, end);
- if (pud_none(pud))
- return 0;
- if (pud_huge(pud)) {
- if (!gup_hugepte((pte_t *)pudp, PUD_SIZE, addr, next,
- write, pages, nr))
- return 0;
- } else if (is_hugepd(pudp)) {
- if (!gup_hugepd((hugepd_t *)pudp, PUD_SHIFT,
- addr, next, write, pages, nr))
- return 0;
- } else if (!gup_pmd_range(pud, addr, next, write, pages, nr))
- return 0;
- } while (pudp++, addr = next, addr != end);
-
- return 1;
-}
-
-int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
- struct page **pages)
-{
- struct mm_struct *mm = current->mm;
- unsigned long addr, len, end;
- unsigned long next;
- unsigned long flags;
- pgd_t *pgdp;
- int nr = 0;
-
- pr_devel("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
-
- start &= PAGE_MASK;
- addr = start;
- len = (unsigned long) nr_pages << PAGE_SHIFT;
- end = start + len;
-
- if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
- start, len)))
- return 0;
-
- pr_devel(" aligned: %lx .. %lx\n", start, end);
-
- /*
- * XXX: batch / limit 'nr', to avoid large irq off latency
- * needs some instrumenting to determine the common sizes used by
- * important workloads (eg. DB2), and whether limiting the batch size
- * will decrease performance.
- *
- * It seems like we're in the clear for the moment. Direct-IO is
- * the main guy that batches up lots of get_user_pages, and even
- * they are limited to 64-at-a-time which is not so many.
- */
- /*
- * This doesn't prevent pagetable teardown, but does prevent
- * the pagetables from being freed on powerpc.
- *
- * So long as we atomically load page table pointers versus teardown,
- * we can follow the address down to the the page and take a ref on it.
- */
- local_irq_save(flags);
-
- pgdp = pgd_offset(mm, addr);
- do {
- pgd_t pgd = ACCESS_ONCE(*pgdp);
-
- pr_devel(" %016lx: normal pgd %p\n", addr,
- (void *)pgd_val(pgd));
- next = pgd_addr_end(addr, end);
- if (pgd_none(pgd))
- break;
- if (pgd_huge(pgd)) {
- if (!gup_hugepte((pte_t *)pgdp, PGDIR_SIZE, addr, next,
- write, pages, &nr))
- break;
- } else if (is_hugepd(pgdp)) {
- if (!gup_hugepd((hugepd_t *)pgdp, PGDIR_SHIFT,
- addr, next, write, pages, &nr))
- break;
- } else if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
- break;
- } while (pgdp++, addr = next, addr != end);
-
- local_irq_restore(flags);
-
- return nr;
-}
-
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
- struct page **pages)
-{
- struct mm_struct *mm = current->mm;
- int nr, ret;
-
- start &= PAGE_MASK;
- nr = __get_user_pages_fast(start, nr_pages, write, pages);
- ret = nr;
-
- if (nr < nr_pages) {
- pr_devel(" slow path ! nr = %d\n", nr);
-
- /* Try to get the remaining pages with get_user_pages */
- start += nr << PAGE_SHIFT;
- pages += nr;
-
- down_read(&mm->mmap_sem);
- ret = get_user_pages(current, mm, start,
- nr_pages - nr, write, 0, pages, NULL);
- up_read(&mm->mmap_sem);
-
- /* Have to be a bit careful with return values */
- if (nr > 0) {
- if (ret < 0)
- ret = nr;
- else
- ret += nr;
- }
- }
-
- return ret;
-}
-
-#endif /* __HAVE_ARCH_PTE_SPECIAL */
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 7e70ae9..03342df 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -230,7 +230,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz
if (hugepd_none(*hpdp) && __hugepte_alloc(mm, hpdp, addr, pdshift, pshift))
return NULL;
- return hugepte_offset(hpdp, addr, pdshift);
+ return hugepte_offset(*hpdp, addr, pdshift);
}
#else
@@ -270,7 +270,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz
if (hugepd_none(*hpdp) && __hugepte_alloc(mm, hpdp, addr, pdshift, pshift))
return NULL;
- return hugepte_offset(hpdp, addr, pdshift);
+ return hugepte_offset(*hpdp, addr, pdshift);
}
#endif
@@ -538,7 +538,7 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
do {
pmd = pmd_offset(pud, addr);
next = pmd_addr_end(addr, end);
- if (!is_hugepd(pmd)) {
+ if (!is_hugepd(__hugepd(pmd_val(*pmd)))) {
/*
* if it is not hugepd pointer, we should already find
* it cleared.
@@ -587,7 +587,7 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
do {
pud = pud_offset(pgd, addr);
next = pud_addr_end(addr, end);
- if (!is_hugepd(pud)) {
+ if (!is_hugepd(__hugepd(pud_val(*pud)))) {
if (pud_none_or_clear_bad(pud))
continue;
hugetlb_free_pmd_range(tlb, pud, addr, next, floor,
@@ -653,7 +653,7 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
do {
next = pgd_addr_end(addr, end);
pgd = pgd_offset(tlb->mm, addr);
- if (!is_hugepd(pgd)) {
+ if (!is_hugepd(__hugepd(pgd_val(*pgd)))) {
if (pgd_none_or_clear_bad(pgd))
continue;
hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
@@ -713,18 +713,17 @@ static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end,
return (__boundary - 1 < end - 1) ? __boundary : end;
}
-int gup_hugepd(hugepd_t *hugepd, unsigned pdshift,
- unsigned long addr, unsigned long end,
- int write, struct page **pages, int *nr)
+int gup_huge_pd(hugepd_t hugepd, unsigned long addr, unsigned pdshift,
+ unsigned long end, int write, struct page **pages, int *nr)
{
pte_t *ptep;
- unsigned long sz = 1UL << hugepd_shift(*hugepd);
+ unsigned long sz = 1UL << hugepd_shift(hugepd);
unsigned long next;
ptep = hugepte_offset(hugepd, addr, pdshift);
do {
next = hugepte_addr_end(addr, end, sz);
- if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr))
+ if (!gup_huge_pte(*ptep, ptep, addr, sz, end, write, pages, nr))
return 0;
} while (ptep++, addr = next, addr != end);
@@ -961,7 +960,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
else if (pgd_huge(pgd)) {
ret_pte = (pte_t *) pgdp;
goto out;
- } else if (is_hugepd(&pgd))
+ } else if (is_hugepd(__hugepd(pgd_val(pgd))))
hpdp = (hugepd_t *)&pgd;
else {
/*
@@ -978,7 +977,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
else if (pud_huge(pud)) {
ret_pte = (pte_t *) pudp;
goto out;
- } else if (is_hugepd(&pud))
+ } else if (is_hugepd(__hugepd(pud_val(pud))))
hpdp = (hugepd_t *)&pud;
else {
pdshift = PMD_SHIFT;
@@ -999,7 +998,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
if (pmd_huge(pmd) || pmd_large(pmd)) {
ret_pte = (pte_t *) pmdp;
goto out;
- } else if (is_hugepd(&pmd))
+ } else if (is_hugepd(__hugepd(pmd_val(pmd))))
hpdp = (hugepd_t *)&pmd;
else
return pte_offset_kernel(&pmd, ea);
@@ -1008,7 +1007,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
if (!hpdp)
return NULL;
- ret_pte = hugepte_offset(hpdp, ea, pdshift);
+ ret_pte = hugepte_offset(*hpdp, ea, pdshift);
pdshift = hugepd_shift(*hpdp);
out:
if (shift)
--
2.1.0
^ permalink raw reply related
* Re: [PATCH v3 16/27] Mips/MSI: Save msi chip in pci sysdata
From: Ralf Baechle @ 2014-10-25 13:04 UTC (permalink / raw)
To: Yijing Wang
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, Thierry Reding,
sparclinux, linux-arch, linux-s390, Russell King, Joerg Roedel,
x86, Sebastian Ott, xen-devel, arnab.basu, Liviu Dudau,
Arnd Bergmann, Konrad Rzeszutek Wilk, Chris Metcalf,
Bjorn Helgaas, Thomas Gleixner, linux-arm-kernel,
Thomas Petazzoni, Xinwei Hu, Tony Luck, Sergei Shtylyov,
linux-kernel, iommu, David Vrabel, Wuyun, linuxppc-dev,
David S. Miller, Lucas Stach
In-Reply-To: <1413342435-7876-17-git-send-email-wangyijing@huawei.com>
On Wed, Oct 15, 2014 at 11:07:04AM +0800, Yijing Wang wrote:
> +static inline struct msi_chip *pci_msi_chip(struct pci_bus *bus)
> +{
> + struct pci_controller *control = (struct pci_controller *)bus->sysdata;
bus->sysdata is void * so this cast is unnecessary.
Ralf
^ permalink raw reply
* Re: [PATCH v3 18/27] MIPS/Xlp: Remove the dead function destroy_irq() to fix build error
From: Ralf Baechle @ 2014-10-25 13:11 UTC (permalink / raw)
To: Yijing Wang
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, Thierry Reding,
sparclinux, linux-arch, linux-s390, Russell King, Joerg Roedel,
x86, Sebastian Ott, xen-devel, arnab.basu, Liviu Dudau,
Arnd Bergmann, Konrad Rzeszutek Wilk, Chris Metcalf,
Bjorn Helgaas, Thomas Gleixner, linux-arm-kernel,
Thomas Petazzoni, Xinwei Hu, Tony Luck, Sergei Shtylyov,
linux-kernel, iommu, David Vrabel, Wuyun, linuxppc-dev,
David S. Miller, Lucas Stach
In-Reply-To: <1413342435-7876-19-git-send-email-wangyijing@huawei.com>
Applied, thanks.
Ralf
^ permalink raw reply
* [PATCH] PPC: bpf_jit_comp: add SKF_AD_PKTTYPE instruction
From: Denis Kirjanov @ 2014-10-26 19:23 UTC (permalink / raw)
To: netdev; +Cc: linuxppc-dev, Denis Kirjanov, Matt Evans
Cc: Matt Evans <matt@ozlabs.org>
Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
---
arch/powerpc/include/asm/ppc-opcode.h | 1 +
arch/powerpc/net/bpf_jit.h | 7 +++++++
arch/powerpc/net/bpf_jit_comp.c | 5 +++++
3 files changed, 13 insertions(+)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 6f85362..1a52877 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -204,6 +204,7 @@
#define PPC_INST_ERATSX_DOT 0x7c000127
/* Misc instructions for BPF compiler */
+#define PPC_INST_LBZ 0x88000000
#define PPC_INST_LD 0xe8000000
#define PPC_INST_LHZ 0xa0000000
#define PPC_INST_LHBRX 0x7c00062c
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index 9aee27c..c406aa9 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -87,6 +87,9 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
#define PPC_STD(r, base, i) EMIT(PPC_INST_STD | ___PPC_RS(r) | \
___PPC_RA(base) | ((i) & 0xfffc))
+
+#define PPC_LBZ(r, base, i) EMIT(PPC_INST_LBZ | ___PPC_RT(r) | \
+ ___PPC_RA(base) | IMM_L(i))
#define PPC_LD(r, base, i) EMIT(PPC_INST_LD | ___PPC_RT(r) | \
___PPC_RA(base) | IMM_L(i))
#define PPC_LWZ(r, base, i) EMIT(PPC_INST_LWZ | ___PPC_RT(r) | \
@@ -96,6 +99,10 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
#define PPC_LHBRX(r, base, b) EMIT(PPC_INST_LHBRX | ___PPC_RT(r) | \
___PPC_RA(base) | ___PPC_RB(b))
/* Convenience helpers for the above with 'far' offsets: */
+#define PPC_LBZ_OFFS(r, base, i) do { if ((i) < 32768) PPC_LBZ(r, base, i); \
+ else { PPC_ADDIS(r, base, IMM_HA(i)); \
+ PPC_LBZ(r, r, IMM_L(i)); } } while(0)
+
#define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \
else { PPC_ADDIS(r, base, IMM_HA(i)); \
PPC_LD(r, r, IMM_L(i)); } } while(0)
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index cbae2df..d110e28 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -407,6 +407,11 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
queue_mapping));
break;
+ case BPF_ANC | SKF_AD_PKTTYPE:
+ PPC_LBZ_OFFS(r_A, r_skb, PKT_TYPE_OFFSET());
+ PPC_ANDI(r_A, r_A, PKT_TYPE_MAX);
+ PPC_SRWI(r_A, r_A, 5);
+ break;
case BPF_ANC | SKF_AD_CPU:
#ifdef CONFIG_SMP
/*
--
2.1.0
^ permalink raw reply related
* Re: [PATCH V2 1/2] mm: Update generic gup implementation to handle hugepage directory
From: Benjamin Herrenschmidt @ 2014-10-26 20:50 UTC (permalink / raw)
To: James Bottomley
Cc: aarcange, linux-arch, steve.capper, linux-kernel, linux-mm,
aneesh.kumar, hannes, akpm, linuxppc-dev, David Miller
In-Reply-To: <1414167761.19984.17.camel@jarvis.lan>
On Fri, 2014-10-24 at 09:22 -0700, James Bottomley wrote:
> Parisc does this. As soon as one CPU issues a TLB purge, it's broadcast
> to all the CPUs on the inter-CPU bus. The next instruction isn't
> executed until they respond.
>
> But this is only for our CPU TLB. There's no other external
> consequence, so removal from the page tables isn't effected by this TLB
> flush, therefore the theory on which Dave bases the change to
> atomic_add() should work for us (of course, atomic_add is lock add
> unlock on our CPU, so it's not going to be of much benefit).
I'm not sure I follow you here.
Do you or do you now perform an IPI to do TLB flushes ? If you don't
(for example because you have HW broadcast), then you need the
speculative get_page(). If you do (and can read a PTE atomically), you
can get away with atomic_add().
The reason is that if you remember how zap_pte_range works, we perform
the flush before we get rid of the page.
So if your using IPIs for the flush, the fact that gup_fast has
interrupts disabled will delay the IPI response and thus effectively
prevent the pages from being actually freed, allowing us to simply do
the atomic_add() on x86.
But if we don't use IPIs because we have HW broadcast of TLB
invalidations, then we don't have that synchronization. atomic_add won't
work, we need get_page_speculative() because the page could be
concurrently being freed.
Cheers,
Ben.
> James
>
> > Another option would be to make the generic code use something defined
> > by the arch to decide whether to use speculative get or
> > not. I like the idea of keeping the bulk of that code generic...
> >
> > Cheers,
> > Ben.
> >
> > > --
> > > To unsubscribe, send a message with 'unsubscribe linux-mm' in
> > > the body to majordomo@kvack.org. For more info on Linux MM,
> > > see: http://www.linux-mm.org/ .
> > > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
> >
> >
> > --
> > To unsubscribe, send a message with 'unsubscribe linux-mm' in
> > the body to majordomo@kvack.org. For more info on Linux MM,
> > see: http://www.linux-mm.org/ .
> > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
> >
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH V2 1/2] mm: Update generic gup implementation to handle hugepage directory
From: Andrea Arcangeli @ 2014-10-27 0:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linux-arch, steve.capper, linux-kernel, James Bottomley, linux-mm,
aneesh.kumar, hannes, akpm, linuxppc-dev, David Miller
In-Reply-To: <1414356641.364.142.camel@pasglop>
Hello,
On Mon, Oct 27, 2014 at 07:50:41AM +1100, Benjamin Herrenschmidt wrote:
> On Fri, 2014-10-24 at 09:22 -0700, James Bottomley wrote:
>
> > Parisc does this. As soon as one CPU issues a TLB purge, it's broadcast
> > to all the CPUs on the inter-CPU bus. The next instruction isn't
> > executed until they respond.
> >
> > But this is only for our CPU TLB. There's no other external
> > consequence, so removal from the page tables isn't effected by this TLB
> > flush, therefore the theory on which Dave bases the change to
> > atomic_add() should work for us (of course, atomic_add is lock add
> > unlock on our CPU, so it's not going to be of much benefit).
>
> I'm not sure I follow you here.
>
> Do you or do you now perform an IPI to do TLB flushes ? If you don't
> (for example because you have HW broadcast), then you need the
> speculative get_page(). If you do (and can read a PTE atomically), you
> can get away with atomic_add().
>
> The reason is that if you remember how zap_pte_range works, we perform
> the flush before we get rid of the page.
>
> So if your using IPIs for the flush, the fact that gup_fast has
> interrupts disabled will delay the IPI response and thus effectively
> prevent the pages from being actually freed, allowing us to simply do
> the atomic_add() on x86.
>
> But if we don't use IPIs because we have HW broadcast of TLB
> invalidations, then we don't have that synchronization. atomic_add won't
> work, we need get_page_speculative() because the page could be
> concurrently being freed.
I looked at how this works more closely and I agree
get_page_unless_zero is always necessary if the TLB flush doesn't
always wait for IPIs to all CPUs where a gup_fast may be running onto.
To summarize, the pagetables are freed with RCU (arch sets
HAVE_RCU_TABLE_FREE) and that allows to walk them lockless with RCU.
After we can walk the pagetables lockless with RCU, we get to the page
lockless, but the pages themself can still be freed at any time from
under us (hence the need for get_page_unless_zero).
The additional trick gup_fast RCU does is to recheck the pte after
elevating the page count with get_page_unless_zero. Rechecking the
pte/hugepmd to be sure it didn't change from under us is critical to
be sure get_page_unless_zero didn't run after the page was freed and
reallocated which would otherwise lead to a security problem too
(i.e. it protects against get_page_unless_zero false positives).
The last bit required is to still disable irqs like on x86 to
serialize against THP splits combined with pmdp_splitting_flush always
delivering IPIs (pmdp_splitting_flush must wait all gup_fast to
complete before proceeding in mangling the page struct of the compound
page).
Preventing the irq disable while taking a gup_fast pin using
compound_lock isn't as "easy" as it is to do for put_page. put_page
(non-compound) fastest path remains THP agnostic because
collapse_huge_page is inhibited by any existing gup pin, but here
we're exactly taking it, so we can't depend on it to already exist to
avoid the race with collapse_huge_page. It's not just split_huge_page
we need to protect against.
So while thinking the above summary, I noticed this patch misses a IPI
in mm/huge_memory.c that must be delivered after pmdp_clear_flush
below to be safe against collapse_huge_page for the same reasons it
sends it within pmdp_splitting_flush. Without this IPI what can happen
is that the GUP pin protection in __collapse_huge_page_isolate races
against gup_fast-RCU.
If gup_fast reads the pte on one CPU before pmdp_clear_flush, and on
the other CPU __collapse_huge_page_isolate succeeds, then gup_fast
could recheck the pte that hasn't been zapped yet by
__collapse_huge_page_copy. gup_fast would succeed because the pte
wasn't zapped yet, but then __collapse_huge_page_copy would run
replacing the pte with a transhuge pmd, making gup_fast return the old
page, while the process got the copy as part of the collapsed hugepage.
/*
* After this gup_fast can't run anymore. This also removes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> invariant broken by gup_fast-RCU
* any huge TLB entry from the CPU so we won't allow
* huge and small TLB entries for the same virtual address
* to avoid the risk of CPU bugs in that area.
*/
_pmd = pmdp_clear_flush(vma, address, pmd);
spin_unlock(pmd_ptl);
mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
spin_lock(pte_ptl);
isolated = __collapse_huge_page_isolate(vma, address, pte);
spin_unlock(pte_ptl);
CPU0 CPU1
--------- -------------
gup_fast-RCU
local_irq_disable()
pte = pte_offset_map(pmd, address)
pmdp_clear_flush (not sending IPI -> bug)
__collapse_huge_page_isolate -> succeeds
(page_count != 1 gup-pin check of
__collapse_huge_page_isolate
didn't fire)
page = vm_normal_page(pte)
get_page_unless_zero() -> succeeds
recheck pte -> succeeds
local_irq_enable()
return page
collapse_huge_page thought
no gup_fast could run after
pmdp_clear_flush returned
__collapse_huge_page_copy (zap
pte too late, gup_fast already
returned on the other CPU)
set_pmd_at(mm, address, pmd, _pmd);
virtual memory backed by THP
gup_fast went out of sync with virtual memory
It could be solved also without IPI, for example by adding a failure
path to __collapse_huge_page_copy and by adding a second gup-pin check
(page_count != 1) after pte_clear(vma->vm_mm, address, _pte) (with a
smp_mb() in between) and returning a failure if the check
triggers. However then we need to store the 512 pte pointers in a
temporary page to roll all of them back if we raced.
Comments what is preferable between IPI and a gup-pin check after
zapping the pte in __collapse_huge_page_copy welcome. If a
modification to __collapse_huge_page_copy is preferable the temporary
pte allocation (for rollback in the gup-pin check trigger case) should
still be skipped on x86.
Thanks,
Andrea
^ permalink raw reply
* Re: [PATCH v3 16/27] Mips/MSI: Save msi chip in pci sysdata
From: Yijing Wang @ 2014-10-27 1:06 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, linux-ia64, linux-pci, Bharat.Bhushan, Thierry Reding,
sparclinux, linux-arch, linux-s390, Russell King, Joerg Roedel,
x86, Sebastian Ott, xen-devel, arnab.basu, Liviu Dudau,
Arnd Bergmann, Konrad Rzeszutek Wilk, Chris Metcalf,
Bjorn Helgaas, Thomas Gleixner, linux-arm-kernel,
Thomas Petazzoni, Xinwei Hu, Tony Luck, Sergei Shtylyov,
linux-kernel, iommu, David Vrabel, Wuyun, linuxppc-dev,
David S. Miller, Lucas Stach
In-Reply-To: <20141025130428.GD16738@linux-mips.org>
On 2014/10/25 21:04, Ralf Baechle wrote:
> On Wed, Oct 15, 2014 at 11:07:04AM +0800, Yijing Wang wrote:
>
>> +static inline struct msi_chip *pci_msi_chip(struct pci_bus *bus)
>> +{
>> + struct pci_controller *control = (struct pci_controller *)bus->sysdata;
>
> bus->sysdata is void * so this cast is unnecessary.
Yes, will update it, thanks!
>
> Ralf
>
> .
>
--
Thanks!
Yijing
^ permalink raw reply
* Re: [PATCH] cpuidle/powernv: Populate cpuidle state details by querying the device-tree
From: Michael Ellerman @ 2014-10-27 3:34 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: linux-pm@vger.kernel.org, rjw@rjwysocki.net,
shreyas@linux.vnet.ibm.com, Preeti U Murthy,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20141024143030.GA25966@red-moon>
On Fri, 2014-10-24 at 15:30 +0100, Lorenzo Pieralisi wrote:
> On Tue, Oct 14, 2014 at 08:53:00AM +0100, Preeti U Murthy wrote:
> > We hard code the metrics relevant for cpuidle states in the kernel today.
> > Instead pick them up from the device tree so that they remain relevant
> > and updated for the system that the kernel is running on.
>
> Device tree properties should be documented, and these bindings are
> getting very similar to the ones I have just completed for ARM,
> I wonder whether we should take the generic bits out of ARM bindings (ie
> exit_latency) and make those available to other architectures.
The firmware that emits those properties is already in the field, so it would
have been nice to use a generic binding but it's too late now.
cheers
^ permalink raw reply
* RE: [PATCH] cpufreq: qoriq: Make the driver usable on all QorIQ platforms
From: Yuantian Tang @ 2014-10-27 3:39 UTC (permalink / raw)
To: Viresh Kumar
Cc: linuxppc-dev@ozlabs.org, Rafael J. Wysocki,
Linux Kernel Mailing List, linux-pm@vger.kernel.org
In-Reply-To: <CAKohpokSuKOwZ3-OWFtU0z7E1fsMg4tyPiUoFUfw26pD9Py=MA@mail.gmail.com>
DQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IFZpcmVzaCBLdW1hciBbbWFp
bHRvOnZpcmVzaC5rdW1hckBsaW5hcm8ub3JnXQ0KPiBTZW50OiBUdWVzZGF5LCBPY3RvYmVyIDIx
LCAyMDE0IDU6MDQgUE0NCj4gVG86IFRhbmcgWXVhbnRpYW4tQjI5OTgzDQo+IENjOiBSYWZhZWwg
Si4gV3lzb2NraTsgTGludXggS2VybmVsIE1haWxpbmcgTGlzdDsgbGludXgtcG1Admdlci5rZXJu
ZWwub3JnOw0KPiBsaW51eHBwYy1kZXZAb3psYWJzLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENI
XSBjcHVmcmVxOiBxb3JpcTogTWFrZSB0aGUgZHJpdmVyIHVzYWJsZSBvbiBhbGwgUW9ySVENCj4g
cGxhdGZvcm1zDQo+IA0KPiBPbiAyMSBPY3RvYmVyIDIwMTQgMTQ6MjksIFl1YW50aWFuIFRhbmcg
PFl1YW50aWFuLlRhbmdAZnJlZXNjYWxlLmNvbT4NCj4gd3JvdGU6DQo+ID4gSWYgSSBkbyBzbywg
bWVudWNvbmZpZyB3aWxsIGRpc3BsYXkgbGlrZSB0aGlzKG9uIFBQQyk6DQo+ID4gICAgICAgICBQ
b3dlclBDIENQVSBmcmVxdWVuY3kgc2NhbGluZyBkcml2ZXJzICAtLS0tDQo+ID4gICAgIFFvcklR
IENQVSBGcmVxdWVuY3kgc2NhbGluZyAgLS0tPg0KPiA+ICAgICAgICAgICAgICAgICA8Kj4gQ1BV
IGZyZXF1ZW5jeSBzY2FsaW5nIGRyaXZlciBmb3IgRnJlZXNjYWxlIFFvcklRDQo+ID4gU29DcyBP
biBBUk0sIHRoZXJlIHNob3VsZCBiZSBhIHNpbWlsYXIgcHJvYmxlbS4NCj4gPiBJc24ndCB3ZWly
ZD8NCj4gDQo+IFNpbWlsYXIgaXMgdHJ1ZSBmb3IgY3B1ZnJlcS1jcHUwIGRyaXZlciBhcyB3ZWxs
Li4gTWF5YmUgd2UgY2FuIGNyZWF0ZSBhDQo+IEtjb25maWcuZHJpdmVycyBjb25maWd1cmF0aW9u
IGFuZCBpbmNsdWRlIGl0IGZyb20gYWxsIGFyY2hpdGVjdHVyZSBzcGVjaWZpYyBvbmVzID8NCj4g
DQo+IEAgUmFmYWVsID8NCg0KRG8gd2UgaGF2ZSBhIGNvbmNsdXNpb24geWV0Pw0KDQpSZWdhcmRz
LA0KWXVhbnRpYW4NCg==
^ permalink raw reply
* Re: [RFC 03/11] powerpc: kvm: add interface to control kvm function on a core
From: Preeti U Murthy @ 2014-10-27 4:04 UTC (permalink / raw)
To: kernelfans, linuxppc-dev, kvm-ppc; +Cc: Paul Mackerras, Alexander Graf
In-Reply-To: <1413487800-7162-4-git-send-email-kernelfans@gmail.com>
Hi Liu,
On 10/17/2014 12:59 AM, kernelfans@gmail.com wrote:
> When kvm is enabled on a core, we migrate all external irq to primary
> thread. Since currently, the kvmirq logic is handled by the primary
> hwthread.
>
> Todo: this patch lacks re-enable of irqbalance when kvm is disable on
> the core
Why is a sysfs file introduced to trigger irq migration? Why is it not
done during kvm module insert ? And similarly spread interrupts when the
module is removed? Isn't this a saner way ?
>
> Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
> ---
> arch/powerpc/kernel/sysfs.c | 39 ++++++++++++++++++++++++++++++++++
> arch/powerpc/sysdev/xics/xics-common.c | 12 +++++++++++
> 2 files changed, 51 insertions(+)
>
> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
> index 67fd2fd..a2595dd 100644
> --- a/arch/powerpc/kernel/sysfs.c
> +++ b/arch/powerpc/kernel/sysfs.c
> @@ -552,6 +552,45 @@ static void sysfs_create_dscr_default(void)
> if (cpu_has_feature(CPU_FTR_DSCR))
> err = device_create_file(cpu_subsys.dev_root, &dev_attr_dscr_default);
> }
> +
> +#ifdef CONFIG_KVMPPC_ENABLE_SECONDARY
> +#define NR_CORES (CONFIG_NR_CPUS/threads_per_core)
> +static DECLARE_BITMAP(kvm_on_core, NR_CORES) __read_mostly
> +
> +static ssize_t show_kvm_enable(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> +}
> +
> +static ssize_t __used store_kvm_enable(struct device *dev,
> + struct device_attribute *attr, const char *buf,
> + size_t count)
> +{
> + struct cpumask stop_cpus;
> + unsigned long core, thr;
> +
> + sscanf(buf, "%lx", &core);
> + if (core > NR_CORES)
> + return -1;
> + if (!test_bit(core, &kvm_on_core))
> + for (thr = 1; thr< threads_per_core; thr++)
> + if (cpu_online(thr * threads_per_core + thr))
> + cpumask_set_cpu(thr * threads_per_core + thr, &stop_cpus);
What is the above logic trying to do? Did you mean
cpu_online(threads_per_core * core + thr) ?
> +
> + stop_machine(xics_migrate_irqs_away_secondary, NULL, &stop_cpus);
> + set_bit(core, &kvm_on_core);
> + return count;
> +}
> +
> +static DEVICE_ATTR(kvm_enable, 0600,
> + show_kvm_enable, store_kvm_enable);
> +
> +static void sysfs_create_kvm_enable(void)
> +{
> + device_create_file(cpu_subsys.dev_root, &dev_attr_kvm_enable);
> +}
> +#endif
> +
> #endif /* CONFIG_PPC64 */
>
> #ifdef HAS_PPC_PMC_PA6T
> diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
> index fe0cca4..68b33d8 100644
> --- a/arch/powerpc/sysdev/xics/xics-common.c
> +++ b/arch/powerpc/sysdev/xics/xics-common.c
> @@ -258,6 +258,18 @@ unlock:
> raw_spin_unlock_irqrestore(&desc->lock, flags);
> }
> }
> +
> +int xics_migrate_irqs_away_secondary(void *data)
> +{
> + int cpu = smp_processor_id();
> + if(cpu%thread_per_core != 0) {
> + WARN(condition, format...);
> + return 0;
> + }
> + /* In fact, if we can migrate the primary, it will be more fine */
> + xics_migrate_irqs_away();
Isn't the aim of the patch to migrate irqs away from the secondary onto
the primary? But from above it looks like we are returning when we find
out that we are secondary threads, isn't it?
> + return 0;
> +}
> #endif /* CONFIG_HOTPLUG_CPU */
Note that xics_migrate_irqs_away() is defined under CONFIG_CPU_HOTPLUG.
But we will need this option on PowerKVM even when hotplug is not
configured in.
Regards
Preeti U Murthy
> #ifdef CONFIG_SMP
>
^ permalink raw reply
* [PATCH] CXL: Fix PSL error due to duplicate segment table entries
From: Ian Munsie @ 2014-10-27 4:24 UTC (permalink / raw)
To: mpe
Cc: cbe-oss-dev, mikey, arnd, Aneesh Kumar K.V, greg, linux-kernel,
linuxppc-dev, anton, imunsie, jk
From: Ian Munsie <imunsie@au1.ibm.com>
In certain circumstances the PSL can send an interrupt for a segment
miss that the kernel has already handled. This can happen if multiple
translations for the same segment are queued in the PSL before the
kernel has restarted the first translation.
The CXL driver did not expect this situation and did not check if a
segment had already been handled. This could cause a duplicate segment
table entry which in turn caused a PSL error taking down the card.
This patch fixes the issue by checking for existing entries in the
segment table that match the segment it is trying to insert to avoid
inserting duplicate entries.
Some of the code has been refactored to simplify it - the segment table
hash has been moved from cxl_load_segment to find_free_sste where it is
used and we have disabled the secondary hash in the segment table to
reduce the number of entries that need to be tested from 16 to 8. Due to
the large segment sizes we use it is extremely unlikely that the
secondary hash would ever have been used in practice, so this should not
have any negative impacts and may even improve performance.
copro_calculate_slb will now mask the ESID by the correct mask for 1T vs
256M segments. This has no effect by itself as the extra bits were
ignored, but it makes debugging the segment table entries easier and
means that we can directly compare the ESID values for duplicates
without needing to worry about masking in the comparison.
Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
---
arch/powerpc/mm/copro_fault.c | 3 +-
drivers/misc/cxl/fault.c | 73 ++++++++++++++++++++++---------------------
drivers/misc/cxl/native.c | 4 +--
3 files changed, 41 insertions(+), 39 deletions(-)
diff --git a/arch/powerpc/mm/copro_fault.c b/arch/powerpc/mm/copro_fault.c
index 0f9939e..5a236f0 100644
--- a/arch/powerpc/mm/copro_fault.c
+++ b/arch/powerpc/mm/copro_fault.c
@@ -99,8 +99,6 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
u64 vsid;
int psize, ssize;
- slb->esid = (ea & ESID_MASK) | SLB_ESID_V;
-
switch (REGION_ID(ea)) {
case USER_REGION_ID:
pr_devel("%s: 0x%llx -- USER_REGION_ID\n", __func__, ea);
@@ -133,6 +131,7 @@ int copro_calculate_slb(struct mm_struct *mm, u64 ea, struct copro_slb *slb)
vsid |= mmu_psize_defs[psize].sllp |
((ssize == MMU_SEGSIZE_1T) ? SLB_VSID_B_1T : 0);
+ slb->esid = (ea & (ssize == MMU_SEGSIZE_1T ? ESID_MASK_1T : ESID_MASK)) | SLB_ESID_V;
slb->vsid = vsid;
return 0;
diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c
index 69506eb..421cfd6 100644
--- a/drivers/misc/cxl/fault.c
+++ b/drivers/misc/cxl/fault.c
@@ -21,60 +21,63 @@
#include "cxl.h"
-static struct cxl_sste* find_free_sste(struct cxl_sste *primary_group,
- bool sec_hash,
- struct cxl_sste *secondary_group,
- unsigned int *lru)
+static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb)
{
- unsigned int i, entry;
- struct cxl_sste *sste, *group = primary_group;
-
- for (i = 0; i < 2; i++) {
- for (entry = 0; entry < 8; entry++) {
- sste = group + entry;
- if (!(be64_to_cpu(sste->esid_data) & SLB_ESID_V))
- return sste;
- }
- if (!sec_hash)
- break;
- group = secondary_group;
+ return ((sste->vsid_data == cpu_to_be64(slb->vsid)) &&
+ (sste->esid_data == cpu_to_be64(slb->esid)));
+}
+
+/* This finds a free SSTE and checks to see if it's already in table */
+static struct cxl_sste* find_free_sste(struct cxl_context *ctx,
+ struct copro_slb *slb)
+{
+ struct cxl_sste *primary, *sste, *ret = NULL;
+ unsigned int mask = (ctx->sst_size >> 7) - 1; /* SSTP0[SegTableSize] */
+ unsigned int entry;
+ unsigned int hash;
+
+ if (slb->vsid & SLB_VSID_B_1T)
+ hash = (slb->esid >> SID_SHIFT_1T) & mask;
+ else /* 256M */
+ hash = (slb->esid >> SID_SHIFT) & mask;
+
+ primary = ctx->sstp + (hash << 3);
+ sste = primary;
+
+ for (entry = 0; entry < 8; entry++) {
+ if (!ret && !(be64_to_cpu(sste->esid_data) & SLB_ESID_V))
+ ret = sste;
+ if (sste_matches(sste, slb))
+ return NULL;
+ sste++;
}
+ if (ret)
+ return ret;
+
/* Nothing free, select an entry to cast out */
- if (sec_hash && (*lru & 0x8))
- sste = secondary_group + (*lru & 0x7);
- else
- sste = primary_group + (*lru & 0x7);
- *lru = (*lru + 1) & 0xf;
+ ret = primary + ctx->sst_lru;
+ ctx->sst_lru = (ctx->sst_lru + 1) & 0x7;
- return sste;
+ return ret;
}
static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb)
{
/* mask is the group index, we search primary and secondary here. */
- unsigned int mask = (ctx->sst_size >> 7)-1; /* SSTP0[SegTableSize] */
- bool sec_hash = 1;
struct cxl_sste *sste;
- unsigned int hash;
unsigned long flags;
-
- sec_hash = !!(cxl_p1n_read(ctx->afu, CXL_PSL_SR_An) & CXL_PSL_SR_An_SC);
-
- if (slb->vsid & SLB_VSID_B_1T)
- hash = (slb->esid >> SID_SHIFT_1T) & mask;
- else /* 256M */
- hash = (slb->esid >> SID_SHIFT) & mask;
-
spin_lock_irqsave(&ctx->sste_lock, flags);
- sste = find_free_sste(ctx->sstp + (hash << 3), sec_hash,
- ctx->sstp + ((~hash & mask) << 3), &ctx->sst_lru);
+ sste = find_free_sste(ctx, slb);
+ if (!sste)
+ goto out_unlock;
pr_devel("CXL Populating SST[%li]: %#llx %#llx\n",
sste - ctx->sstp, slb->vsid, slb->esid);
sste->vsid_data = cpu_to_be64(slb->vsid);
sste->esid_data = cpu_to_be64(slb->esid);
+out_unlock:
spin_unlock_irqrestore(&ctx->sste_lock, flags);
}
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
index 623286a..d47532e 100644
--- a/drivers/misc/cxl/native.c
+++ b/drivers/misc/cxl/native.c
@@ -417,7 +417,7 @@ static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr)
ctx->elem->haurp = 0; /* disable */
ctx->elem->sdr = cpu_to_be64(mfspr(SPRN_SDR1));
- sr = CXL_PSL_SR_An_SC;
+ sr = 0;
if (ctx->master)
sr |= CXL_PSL_SR_An_MP;
if (mfspr(SPRN_LPCR) & LPCR_TC)
@@ -508,7 +508,7 @@ static int attach_dedicated(struct cxl_context *ctx, u64 wed, u64 amr)
u64 sr;
int rc;
- sr = CXL_PSL_SR_An_SC;
+ sr = 0;
set_endian(sr);
if (ctx->master)
sr |= CXL_PSL_SR_An_MP;
--
2.1.1
^ permalink raw reply related
* Re: [RFC 04/11] powerpc: kvm: introduce a kthread on primary thread to anti tickless
From: Preeti U Murthy @ 2014-10-27 4:45 UTC (permalink / raw)
To: kernelfans, linuxppc-dev, kvm-ppc; +Cc: Paul Mackerras, Alexander Graf
In-Reply-To: <1413487800-7162-5-git-send-email-kernelfans@gmail.com>
On 10/17/2014 12:59 AM, kernelfans@gmail.com wrote:
> (This patch is a place holder.)
>
> If there is only one vcpu thread is ready(the other vcpu thread can
> wait for it to execute), the primary thread can enter tickless mode,
We do not configure NOHZ_FULL to y by default. Hence no thread would
enter tickless mode.
> which causes the primary keeps running, so the secondary has no
> opportunity to exit to host, even they have other tsk on them.
The secondary threads can still get scheduling ticks. The decrementer of
the secondary threads is still active. So as long as secondary threads
are busy, scheduling ticks will fire and try to schedule a new task on them.
Regards
Preeti U Murthy
>
> Introduce a kthread (anti_tickless) on primary, so when there is only
> one vcpu thread on primary, the secondary can resort to anti_tickless
> to keep the primary out of tickless mode.
> (I thought that anti_tickless thread can goto NAP, so we can let the
> secondary run).
>
> Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
> ---
> arch/powerpc/kernel/sysfs.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
> index a2595dd..f0b110e 100644
> --- a/arch/powerpc/kernel/sysfs.c
> +++ b/arch/powerpc/kernel/sysfs.c
> @@ -575,9 +575,11 @@ static ssize_t __used store_kvm_enable(struct device *dev,
> if (!test_bit(core, &kvm_on_core))
> for (thr = 1; thr< threads_per_core; thr++)
> if (cpu_online(thr * threads_per_core + thr))
> - cpumask_set_cpu(thr * threads_per_core + thr, &stop_cpus);
> + cpumask_set_cpu(core * threads_per_core + thr, &stop_cpus);
>
> stop_machine(xics_migrate_irqs_away_secondary, NULL, &stop_cpus);
> + /* fixme, create a kthread on primary hwthread to handle tickless mode */
> + //kthread_create_on_cpu(prevent_tickless, NULL, core * threads_per_core, "ppckvm_prevent_tickless");
> set_bit(core, &kvm_on_core);
> return count;
> }
>
^ permalink raw reply
* Re: [RFC 06/11] powerpc: kvm: introduce online in paca to indicate whether cpu is needed by host
From: Preeti U Murthy @ 2014-10-27 5:32 UTC (permalink / raw)
To: kernelfans, linuxppc-dev, kvm-ppc; +Cc: Paul Mackerras, Alexander Graf
In-Reply-To: <1413487800-7162-7-git-send-email-kernelfans@gmail.com>
Hi Liu,
On 10/17/2014 12:59 AM, kernelfans@gmail.com wrote:
> Nowadays, powerKVM runs with secondary hwthread offline. Although
> we can make all secondary hwthread online later, we still preserve
> this behavior for dedicated KVM env. Achieve this by setting
> paca->online as false.
>
> Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/paca.h | 3 +++
> arch/powerpc/kernel/asm-offsets.c | 3 +++
> arch/powerpc/kernel/smp.c | 3 +++
> arch/powerpc/kvm/book3s_hv_rmhandlers.S | 12 ++++++++++++
> 4 files changed, 21 insertions(+)
>
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index a5139ea..67c2500 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -84,6 +84,9 @@ struct paca_struct {
> u8 cpu_start; /* At startup, processor spins until */
> /* this becomes non-zero. */
> u8 kexec_state; /* set when kexec down has irqs off */
> +#ifdef CONFIG_KVMPPC_ENABLE_SECONDARY
> + u8 online;
> +#endif
> #ifdef CONFIG_PPC_STD_MMU_64
> struct slb_shadow *slb_shadow_ptr;
> struct dtl_entry *dispatch_log;
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index 9d7dede..0faa8fe 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -182,6 +182,9 @@ int main(void)
> DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc));
> DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase));
> DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
> +#ifdef CONFIG_KVMPPC_ENABLE_SECONDARY
> + DEFINE(PACAONLINE, offsetof(struct paca_struct, online));
> +#endif
> DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
> DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened));
> DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
> diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
> index a0738af..4c3843e 100644
> --- a/arch/powerpc/kernel/smp.c
> +++ b/arch/powerpc/kernel/smp.c
> @@ -736,6 +736,9 @@ void start_secondary(void *unused)
>
> cpu_startup_entry(CPUHP_ONLINE);
>
> +#ifdef CONFIG_KVMPPC_ENABLE_SECONDARY
> + get_paca()->online = true;
> +#endif
> BUG();
> }
>
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index f0c4db7..d5594b0 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -322,6 +322,13 @@ kvm_no_guest:
> li r0, KVM_HWTHREAD_IN_NAP
> stb r0, HSTATE_HWTHREAD_STATE(r13)
> kvm_do_nap:
> +#ifdef PPCKVM_ENABLE_SECONDARY
> + /* check the cpu is needed by host or not */
> + ld r2, PACAONLINE(r13)
> + ld r3, 0
> + cmp r2, r3
> + bne kvm_secondary_exit_trampoline
> +#endif
> /* Clear the runlatch bit before napping */
> mfspr r2, SPRN_CTRLF
> clrrdi r2, r2, 1
> @@ -340,6 +347,11 @@ kvm_do_nap:
> nap
> b .
>
> +#ifdef PPCKVM_ENABLE_SECONDARY
> +kvm_secondary_exit_trampoline:
> + b .
Uh? When we have no vcpu to run, we loop here instead of doing a nap?
What are we achieving?
If I understand the intention of the patch well, we are looking to
provide a knob whereby the host can indicate if it needs the secondaries
at all.
Today the host does boot with all threads online. There are some init
scripts which take the secondaries down. So today the host does not have
a say in preventing this, compile time or runtime. So lets see how we
can switch between the two behaviors if we don't have the init script,
which looks like a saner thing to do.
We should set the paca->online flag to false by default. If
KVM_PPC_ENABLE_SECONDARY is configured, we need to set this flag to
true. So at compile time, we resolve the flag.
While booting, we look at the flag and decide whether to get the
secondaries online. So we get the current behavior if we have not
configured KVM_PPC_ENABLE_SECONDARY. Will this achieve the purpose of
this patch?
Regards
Preeti U Murthy
^ permalink raw reply
* Re: [RFC 07/11] powerpc: kvm: the stopper func to cease secondary hwthread
From: Preeti U Murthy @ 2014-10-27 6:07 UTC (permalink / raw)
To: kernelfans, linuxppc-dev, kvm-ppc; +Cc: Paul Mackerras, Alexander Graf
In-Reply-To: <1413487800-7162-8-git-send-email-kernelfans@gmail.com>
On 10/17/2014 12:59 AM, kernelfans@gmail.com wrote:
> To enter guest, primary hwtherad schedules the stopper func on
> secondary threads and force them into NAP mode.
> When exit to host,secondary threads hardcode to restore the stack,
> then switch back to the stopper func, i.e host.
>
> Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
> ---
> arch/powerpc/kvm/book3s_hv.c | 15 +++++++++++++++
> arch/powerpc/kvm/book3s_hv_rmhandlers.S | 34 +++++++++++++++++++++++++++++++++
> 2 files changed, 49 insertions(+)
>
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index ba258c8..4348abd 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -1486,6 +1486,21 @@ static void kvmppc_remove_runnable(struct kvmppc_vcore *vc,
> list_del(&vcpu->arch.run_list);
> }
>
> +#ifdef KVMPPC_ENABLE_SECONDARY
> +
> +extern void kvmppc_secondary_stopper_enter();
> +
> +static int kvmppc_secondary_stopper(void *data)
> +{
> + int cpu =smp_processor_id();
> + struct paca_struct *lpaca = get_paca();
> + BUG_ON(!(cpu%thread_per_core));
> +
> + kvmppc_secondary_stopper_enter();
> +}
> +
> +#endif
> +
> static int kvmppc_grab_hwthread(int cpu)
> {
> struct paca_struct *tpaca;
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index d5594b0..254038b 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -349,7 +349,41 @@ kvm_do_nap:
>
> #ifdef PPCKVM_ENABLE_SECONDARY
> kvm_secondary_exit_trampoline:
> +
> + /* all register is free to use, later kvmppc_secondary_stopper_exit set up them*/
> + //loop-wait for the primary to signal that host env is ready
> +
> + LOAD_REG_ADDR(r5, kvmppc_secondary_stopper_exit)
> + /* fixme, load msr from lpaca stack */
> + li r6, MSR_IR | MSR_DR
> + mtsrr0 r5
> + mtsrr1 r6
> + RFI
> +
> +_GLOBAL_TOC(kvmppc_secondary_stopper_enter)
> + mflr r0
> + std r0, PPC_LR_STKOFF(r1)
> + stdu r1, -112(r1)
> +
> + /* fixme: store other register such as msr */
> +
> + /* prevent us to enter kernel */
> + li r0, 1
> + stb r0, HSTATE_HWTHREAD_REQ(r13)
> + /* tell the primary that we are ready */
> + li r0,KVM_HWTHREAD_IN_KERNEL
> + stb r0,HSTATE_HWTHREAD_STATE(r13)
> + nap
> b .
I see a fundamental issues with this design. Note that the secondaries
are still capable of getting IPIs, timer interrupts and scheduler
interrupts in nap. Scheduling ticks do not get stopped just because we
nap. So the primary thread cannot assume that the secondaries will wait
in nap until it has switched to guest context. There will definitely be
race conditions here between primary switching context and the secondary
handling some interrupt in virtual mode.
So your answer to above could be that we are preventing the secondaries
from entering the kernel by setting the HSTATE_HWTHREAD_REQ above. But
we cannot do this because the secondary thread is as alive and kicking
as the primary thread on the host. There can be hrtimers queued, there
may be an IPI from a thread in another core. We cannot ignore handling
them while we wait for the primary thread to switch context.
There is also a bug as far as I can see with having a b . after nap. I
mentioned that in one of my earlier replies to this patch.
Regards
Preeti U Murthy
> +
> +/* enter with vmode */
> +kvmppc_secondary_stopper_exit:
> + /* fixme, restore the stack which we store on lpaca */
> +
> + ld r0, 112+PPC_LR_STKOFF(r1)
> + addi r1, r1, 112
> + mtlr r0
> + blr
> #endif
>
> /******************************************************************************
>
^ permalink raw reply
* Re: [PATCH V3] powerpc, xmon: Enable HW instruction breakpoint on POWER8
From: Anshuman Khandual @ 2014-10-27 6:20 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Michael Ellerman
In-Reply-To: <1412855321-21276-1-git-send-email-khandual@linux.vnet.ibm.com>
On 10/09/2014 05:18 PM, Anshuman Khandual wrote:
> This patch enables support for hardware instruction breakpoints
> on POWER8 with the help of a new register CIABR (Completed
> Instruction Address Breakpoint Register). With this patch, single
> hardware instruction breakpoint can be added and cleared during
> any active xmon debug session. This hardware based instruction
> breakpoint mechanism works correctly along with the existing TRAP
> based instruction breakpoints available on xmon.
Hey Michael,
Any updates on this patch ?
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox