Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 2/2] drm: dw-hdmi: gate audio clock from the I2S enablement callbacks
From: Archit Taneja @ 2017-04-19  4:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170414083113.4255-3-romain.perier@collabora.com>



On 04/14/2017 02:01 PM, Romain Perier wrote:
> Currently, the audio sampler clock is enabled from dw_hdmi_setup() at
> step E. and is kept enabled for later use. This clock should be enabled
> and disabled along with the actual audio stream and not always on (that
> is bad for PM). Futhermore, as described by the datasheet, the I2S

s/Futhermore/Furthermore

> variant need to gate/ungate the clock when the stream is

s/need/needs

> enabled/disabled.
>
> This commit adds a parameter to hdmi_audio_enable_clk() that controls
> when the audio sample clock must be enabled or disabled. Then, it adds
> the call to this function from dw_hdmi_i2s_audio_enable() and
> dw_hdmi_i2s_audio_disable().
>
> Signed-off-by: Romain Perier <romain.perier@collabora.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 20 ++++++++++++++------
>  1 file changed, 14 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 5b328c0..a6da634 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -544,6 +544,12 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
>  }
>  EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate);
>
> +static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable)
> +{
> +	hdmi_modb(hdmi, enable ? 0 : HDMI_MC_CLKDIS_AUDCLK_DISABLE,
> +		  HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
> +}
> +
>  void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
>  {
>  	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> @@ -557,6 +563,12 @@ void dw_hdmi_ahb_audio_disable(struct dw_hdmi *hdmi)
>  void dw_hdmi_i2s_audio_enable(struct dw_hdmi *hdmi)
>  {
>  	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> +	hdmi_enable_audio_clk(hdmi, true);
> +}
> +
> +void dw_hdmi_i2s_audio_disable(struct dw_hdmi *hdmi)
> +{
> +	hdmi_enable_audio_clk(hdmi, false);
>  }

This should be static too.

If you're okay with the suggestions, I can fix these myself and push. Let
me know if that's okay.

Thanks,
Archit

>
>  void dw_hdmi_audio_enable(struct dw_hdmi *hdmi)
> @@ -1592,11 +1604,6 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
>  			    HDMI_MC_FLOWCTRL);
>  }
>
> -static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
> -{
> -	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
> -}
> -
>  /* Workaround to clear the overflow condition */
>  static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
>  {
> @@ -1710,7 +1717,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
>
>  		/* HDMI Initialization Step E - Configure audio */
>  		hdmi_clk_regenerator_update_pixel_clock(hdmi);
> -		hdmi_enable_audio_clk(hdmi);
> +		hdmi_enable_audio_clk(hdmi, true);
>  	}
>
>  	/* not for DVI mode */
> @@ -2438,6 +2445,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		audio.write	= hdmi_writeb;
>  		audio.read	= hdmi_readb;
>  		hdmi->enable_audio = dw_hdmi_i2s_audio_enable;
> +		hdmi->disable_audio = dw_hdmi_i2s_audio_disable;
>
>  		pdevinfo.name = "dw-hdmi-i2s-audio";
>  		pdevinfo.data = &audio;
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v2 1/2] drm: dw-hdmi: add specific I2S and AHB functions for stream handling
From: Archit Taneja @ 2017-04-19  4:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170414083113.4255-2-romain.perier@collabora.com>



On 04/14/2017 02:01 PM, Romain Perier wrote:
> Currently, CTS+N is forced to zero as a workaround of the IP block for
> i.MX platforms. This is requested in the datasheet of the corresponding
> IP for AHB mode only. However, we have seen that it introduces glitches
> or delays when playing a sound on HDMI for I2S mode. This proves that we
> cannot keep the current functions for handling audio stream as-is if
> these contain workaround that are specific to a mode.
>
> This commit introduces two callbacks, one for each variant.
> dw_hdmi_setup defines the right function depending on the detected
> variant. Then, the exported functions dw_hdmi_audio_enable and
> dw_hdmi_audio_disable calls the corresponding callbacks
>
> Signed-off-by: Romain Perier <romain.perier@collabora.com>
> ---
>  drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 26 ++++++++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 4b6f216..5b328c0 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -173,6 +173,8 @@ struct dw_hdmi {
>
>  	unsigned int reg_shift;
>  	struct regmap *regm;
> +	void (*enable_audio)(struct dw_hdmi *hdmi);
> +	void (*disable_audio)(struct dw_hdmi *hdmi);
>  };
>
>  #define HDMI_IH_PHY_STAT0_RX_SENSE \
> @@ -542,13 +544,29 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
>  }
>  EXPORT_SYMBOL_GPL(dw_hdmi_set_sample_rate);
>
> +void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi)
> +{
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> +}
> +
> +void dw_hdmi_ahb_audio_disable(struct dw_hdmi *hdmi)
> +{
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
> +}
> +
> +void dw_hdmi_i2s_audio_enable(struct dw_hdmi *hdmi)
> +{
> +	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> +}
> +

I get some sparse warnings asking for the above 3 to be static.

Thanks,
Archit

>  void dw_hdmi_audio_enable(struct dw_hdmi *hdmi)
>  {
>  	unsigned long flags;
>
>  	spin_lock_irqsave(&hdmi->audio_lock, flags);
>  	hdmi->audio_enable = true;
> -	hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n);
> +	if (hdmi->enable_audio)
> +		hdmi->enable_audio(hdmi);
>  	spin_unlock_irqrestore(&hdmi->audio_lock, flags);
>  }
>  EXPORT_SYMBOL_GPL(dw_hdmi_audio_enable);
> @@ -559,7 +577,8 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi)
>
>  	spin_lock_irqsave(&hdmi->audio_lock, flags);
>  	hdmi->audio_enable = false;
> -	hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0);
> +	if (hdmi->disable_audio)
> +		hdmi->disable_audio(hdmi);
>  	spin_unlock_irqrestore(&hdmi->audio_lock, flags);
>  }
>  EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable);
> @@ -2404,6 +2423,8 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		audio.irq = irq;
>  		audio.hdmi = hdmi;
>  		audio.eld = hdmi->connector.eld;
> +		hdmi->enable_audio = dw_hdmi_ahb_audio_enable;
> +		hdmi->disable_audio = dw_hdmi_ahb_audio_disable;
>
>  		pdevinfo.name = "dw-hdmi-ahb-audio";
>  		pdevinfo.data = &audio;
> @@ -2416,6 +2437,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
>  		audio.hdmi	= hdmi;
>  		audio.write	= hdmi_writeb;
>  		audio.read	= hdmi_readb;
> +		hdmi->enable_audio = dw_hdmi_i2s_audio_enable;
>
>  		pdevinfo.name = "dw-hdmi-i2s-audio";
>  		pdevinfo.data = &audio;
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [arm64] OOPS when using /proc/kcore to disassemble the kernel symbols in "perf top"
From: Pratyush Anand @ 2017-04-19  4:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <58F1DE6A.7050307@huawei.com>

Hi tan,

On Saturday 15 April 2017 02:18 PM, Tan Xiaojun wrote:
> Hi,
>
> My test server is Hisilicon D03/D05 (arm64).
> Kernel source code is 4.11-rc6 (up to date) and config (as an attachment in the end) is generated by defconfig.
> (Old version does not seem to have this problem. Linux-4.1 is fine and other versions I have not tested yet.)

I tested with mustang(ARM64) and 4.11-rc6 and could not reproduce it.

>
> When I do "perf top" and annotate a random kernel symbol (like vsnprintf or others), the system report an OOPS below:
> (The probability of occurrence is very high, almost every time.)
>
> $ perf top
>
> Annotate vsnprintf               ---- choose it
> Zoom into perf(7066) thread
> Zoom into the Kernel DSO
> Browse map details
> Run scripts for samples of thread [perf]
> Run scripts for samples of symbol [vsnprintf]
> Run scripts for all samples
> Exit
>
> log:
> Apr 17 05:03:59 EulerOS kernel: [  339.913498] Unable to handle kernel paging request at virtual address ffffdb16aa14028c
> Apr 17 05:03:59 EulerOS kernel: [  339.913502] pgd = ffff803f70b29000
> Apr 17 05:03:59 EulerOS kernel: [  339.913506] [ffffdb16aa14028c] *pgd=0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913511] Internal error: Oops: 96000004 [#1] PREEMPT SMP
> Apr 17 05:03:59 EulerOS kernel: [  339.913514] Modules linked in:
> Apr 17 05:03:59 EulerOS kernel: [  339.913520] CPU: 6 PID: 9703 Comm: perf Not tainted 4.11.0-rc6-00029-gb9b3322 #3
> Apr 17 05:03:59 EulerOS kernel: [  339.913523] Hardware name: Huawei Taishan 2180 /BC11SPCC, BIOS 1.31 06/23/2016
> Apr 17 05:03:59 EulerOS kernel: [  339.913526] task: ffff803f6ff99a00 task.stack: ffff803f4c104000
> Apr 17 05:03:59 EulerOS kernel: [  339.913531] PC is at __memcpy+0x38/0x180
> Apr 17 05:03:59 EulerOS kernel: [  339.913535] LR is at vread+0x148/0x284
> Apr 17 05:03:59 EulerOS kernel: [  339.913538] pc : [<ffff0000083926b8>] lr : [<ffff0000081ba2a0>] pstate: 00000145
> Apr 17 05:03:59 EulerOS kernel: [  339.913540] sp : ffff803f4c107c70
> Apr 17 05:03:59 EulerOS kernel: [  339.913542] x29: ffff803f4c107c70 x28: ffff803f5ef73000
> Apr 17 05:03:59 EulerOS kernel: [  339.913548] x27: 000000000000032c x26: ffff803f6ff99a00
> Apr 17 05:03:59 EulerOS kernel: [  339.913552] x25: ffff00000839d28c x24: ffff803f7f801380
> Apr 17 05:03:59 EulerOS kernel: [  339.913557] x23: 000000000000032c x22: ffff803f5ef73000
> Apr 17 05:03:59 EulerOS kernel: [  339.913561] x21: 000000000000028c x20: ffff00000839d28c
> Apr 17 05:03:59 EulerOS kernel: [  339.913565] x19: 000000000000032c x18: 0000ffffaa6cc2d0
> Apr 17 05:03:59 EulerOS kernel: [  339.913569] x17: 0000ffffab9dc350 x16: ffff0000081f5f04
> Apr 17 05:03:59 EulerOS kernel: [  339.913573] x15: 0000317ba8000000 x14: 001c19d1d0000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913577] x13: 00000003e8000000 x12: 0000000000000006
> Apr 17 05:03:59 EulerOS kernel: [  339.913581] x11: 0000000000000007 x10: 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913586] x9 : 0000000000000000 x8 : ffff000008e6d3d8
> Apr 17 05:03:59 EulerOS kernel: [  339.913590] x7 : 00005b16aa140000 x6 : ffff803f5ef73000
> Apr 17 05:03:59 EulerOS kernel: [  339.913594] x5 : 0000000000000d74 x4 : 0000000000000004
> Apr 17 05:03:59 EulerOS kernel: [  339.913598] x3 : 0000000000000000 x2 : 0000000000000328
> Apr 17 05:03:59 EulerOS kernel: [  339.913602] x1 : ffffdb16aa14028c x0 : ffff803f5ef73000

So, source pointer for the memcpy(2nd arg) seems wrong. (Unable to handle 
kernel paging request at virtual address ffffdb16aa14028c, and x1 is 
ffffdb16aa14028c).

I tried to look into code around source pointer,and they seem to be correct.

in read_kcore(): start is source pointer.
         start = kc_offset_to_vaddr(*fpos - elf_buflen);
	vread(buf, (char *)start, tsz);

in vread() -> aligned_vread(): addr is source pointer.
offset = offset_in_page(addr);
p = vmalloc_to_page(addr);
*map = kmap_atomic(p);
memcpy(buf, map + offset, length);

They all look fine and should work. Since, it always works with 4.1 on your 
platform, can you please try a git bisect to see which commit is causing 
trouble for you.

~Pratyush

> Apr 17 05:03:59 EulerOS kernel: [  339.913606]
> Apr 17 05:03:59 EulerOS kernel: [  339.913609] Process perf (pid: 9703, stack limit = 0xffff803f4c104000)
> Apr 17 05:03:59 EulerOS kernel: [  339.913612] Stack: (0xffff803f4c107c70 to 0xffff803f4c108000)
> Apr 17 05:03:59 EulerOS kernel: [  339.913615] 7c60:                                   ffff803f4c107d00 ffff000008267a18
> Apr 17 05:03:59 EulerOS kernel: [  339.913619] 7c80: 000000000000032c 0000000036dd9c10 ffff000008f75160 ffff803f4c107eb8
> Apr 17 05:03:59 EulerOS kernel: [  339.913622] 7ca0: 0000000000000000 ffff803f6ff99a00 ffff803f5ef73000 ffff000008e6d3d8
> Apr 17 05:03:59 EulerOS kernel: [  339.913625] 7cc0: ffff00000839d28c 000000000000032c 0000000000000024 ffff803f5ef73000
> Apr 17 05:03:59 EulerOS kernel: [  339.913629] 7ce0: 000000000000032c 000000000000032c ffff803f6ff99a00 ffff000008e684a0
> Apr 17 05:03:59 EulerOS kernel: [  339.913632] 7d00: ffff803f4c107d90 ffff000008259d00 ffff803f720c3d00 fffffffffffffffb
> Apr 17 05:03:59 EulerOS kernel: [  339.913635] 7d20: 0000000036dd9c10 ffff803f4c107eb8 0000000080000000 0000000000000015
> Apr 17 05:03:59 EulerOS kernel: [  339.913638] 7d40: 0000000000000124 000000000000003f ffff000008942000 ffff803f6ff99a00
> Apr 17 05:03:59 EulerOS kernel: [  339.913641] 7d60: ffff803f6ff08310 ffff803f6ff99a00 ffff803f6ff99a00 ffff803f6ff99a00
> Apr 17 05:03:59 EulerOS kernel: [  339.913644] 7d80: 0000000d00000124 0000000000002000 ffff803f4c107db0 ffff0000081f3810
> Apr 17 05:03:59 EulerOS kernel: [  339.913647] 7da0: ffff803f6ff08300 ffff803f4c107eb8 ffff803f4c107e30 ffff0000081f4ab0
> Apr 17 05:03:59 EulerOS kernel: [  339.913650] 7dc0: 000000000000032c ffff803f6ff08300 0000000000000000 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913653] 7de0: ffff803f4c107e10 ffff0000081f49ac ffff803f6ff08300 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913656] 7e00: 0000000036dd9c10 ffff803f4c107eb8 ffff803f4c107e30 ffff0000081f4a8c
> Apr 17 05:03:59 EulerOS kernel: [  339.913659] 7e20: 000000000000032c ffff803f6ff08300 ffff803f4c107e70 ffff0000081f5f48
> Apr 17 05:03:59 EulerOS kernel: [  339.913662] 7e40: ffff803f6ff08303 ffff803f6ff08300 ffffffffffffffff 0000ffffab9dc37c
> Apr 17 05:03:59 EulerOS kernel: [  339.913664] 7e60: 0000000000000200 0000ffffab9dcbdc 0000000000000000 ffff000008082f8c
> Apr 17 05:03:59 EulerOS kernel: [  339.913667] 7e80: 0000000000000200 0000803ff70f9000 ffffffffffffffff ffff000008082f5c
> Apr 17 05:03:59 EulerOS kernel: [  339.913670] 7ea0: 0000000036dd9c10 000000000000032c ffffffffffffffff 000000000839f28c
> Apr 17 05:03:59 EulerOS kernel: [  339.913673] 7ec0: 000000000000002a 0000000036dd9c10 000000000000032c 0000ffffaa6d42c8
> Apr 17 05:03:59 EulerOS kernel: [  339.913676] 7ee0: 0000ffffaa6cc49c 0000ffffaa6d41c0 0000ffffaa6d48b0 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913679] 7f00: 000000000000003f 0000000000000003 0000000000000020 0000000000000007
> Apr 17 05:03:59 EulerOS kernel: [  339.913682] 7f20: 0000000000000006 00000003e8000000 001c19d1d0000000 0000317ba8000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913685] 7f40: 0000000000000000 0000ffffab9dc350 0000ffffaa6cc2d0 0000000000622000
> Apr 17 05:03:59 EulerOS kernel: [  339.913688] 7f60: 0000000000001000 0000000036dd9c10 000000000000032c 00000000006f1038
> Apr 17 05:03:59 EulerOS kernel: [  339.913691] 7f80: 000000000000002b 000000000000002a 000000000839f28c 0000000000000001
> Apr 17 05:03:59 EulerOS kernel: [  339.913694] 7fa0: 0000ffffaa6d3990 0000ffffaa6cc4e0 0000ffffab9dc368 0000ffffaa6cc4a0
> Apr 17 05:03:59 EulerOS kernel: [  339.913697] 7fc0: 0000ffffab9dc37c 0000000080000000 000000000000002a 000000000000003f
> Apr 17 05:03:59 EulerOS kernel: [  339.913700] 7fe0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913702] Call trace:
> Apr 17 05:03:59 EulerOS kernel: [  339.913705] Exception stack(0xffff803f4c107aa0 to 0xffff803f4c107bd0)
> Apr 17 05:03:59 EulerOS kernel: [  339.913708] 7aa0: 000000000000032c 0001000000000000 ffff803f4c107c70 ffff0000083926b8
> Apr 17 05:03:59 EulerOS kernel: [  339.913712] 7ac0: 00000000014200ca 0000000000000000 ffff803f71b1ec38 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913715] 7ae0: ffff803f6ff99a00 0000000036dda000 0000000000000000 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913718] 7b00: 000000000000000c ffff000008f6c610 ffff803f4c107b60 ffff0000082c0ae0
> Apr 17 05:03:59 EulerOS kernel: [  339.913721] 7b20: ffff803f7047a030 ffff000008f76000 0000000000000000 ffff803f7200a800
> Apr 17 05:03:59 EulerOS kernel: [  339.913724] 7b40: ffff803f5ef73000 ffffdb16aa14028c 0000000000000328 0000000000000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913727] 7b60: 0000000000000004 0000000000000d74 ffff803f5ef73000 00005b16aa140000
> Apr 17 05:03:59 EulerOS kernel: [  339.913729] 7b80: ffff000008e6d3d8 0000000000000000 0000000000000000 0000000000000007
> Apr 17 05:03:59 EulerOS kernel: [  339.913732] 7ba0: 0000000000000006 00000003e8000000 001c19d1d0000000 0000317ba8000000
> Apr 17 05:03:59 EulerOS kernel: [  339.913735] 7bc0: ffff0000081f5f04 0000ffffab9dc350
> Apr 17 05:03:59 EulerOS kernel: [  339.913739] [<ffff0000083926b8>] __memcpy+0x38/0x180
> Apr 17 05:03:59 EulerOS kernel: [  339.913743] [<ffff000008267a18>] read_kcore+0x230/0x3b0
> Apr 17 05:03:59 EulerOS kernel: [  339.913747] [<ffff000008259d00>] proc_reg_read+0x64/0x90
> Apr 17 05:03:59 EulerOS kernel: [  339.913751] [<ffff0000081f3810>] __vfs_read+0x28/0x108
> Apr 17 05:03:59 EulerOS kernel: [  339.913754] [<ffff0000081f4ab0>] vfs_read+0x80/0x13c
> Apr 17 05:03:59 EulerOS kernel: [  339.913757] [<ffff0000081f5f48>] SyS_read+0x44/0xa0
> Apr 17 05:03:59 EulerOS kernel: [  339.913761] [<ffff000008082f8c>] __sys_trace_return+0x0/0x4
> Apr 17 05:03:59 EulerOS kernel: [  339.913765] Code: 36080064 78402423 780024c3 36100064 (b8404423)
> Apr 17 05:03:59 EulerOS kernel: [  339.913768] ---[ end trace 6710f03ffe50aedc ]---
> Apr 17 05:03:59 EulerOS kernel: [  339.913772] note: perf[9703] exited with preempt_count 2
>
> Call relationship:
> read_kcore -> vread -> aligned_vread -> memcpy -> __memcpy
>
> Maybe you can give me some ideas.
>
> Thanks a lot.
>
> Xiaojun.
>
>
>
>

^ permalink raw reply

* [PATCH v2 8/9] staging: fsl-dpaa2/eth: Add TODO file
From: Stuart Yoder @ 2017-04-19  3:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170412162538.25302-9-ruxandra.radulescu@nxp.com>

On Wed, Apr 12, 2017 at 11:25 AM, Ioana Radulescu
<ruxandra.radulescu@nxp.com> wrote:
> Add a list of TODO items for the Ethernet driver
>
> Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
> ---
> v2: Add note
>
>  drivers/staging/fsl-dpaa2/ethernet/TODO | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
>  create mode 100644 drivers/staging/fsl-dpaa2/ethernet/TODO
>
> diff --git a/drivers/staging/fsl-dpaa2/ethernet/TODO b/drivers/staging/fsl-dpaa2/ethernet/TODO
> new file mode 100644
> index 000000000000..110e66d44b42
> --- /dev/null
> +++ b/drivers/staging/fsl-dpaa2/ethernet/TODO
> @@ -0,0 +1,14 @@
> +* Add a DPAA2 MAC kernel driver in order to allow PHY management; currently
> +  the DPMAC objects and their link to DPNIs are handled by MC internally
> +  and all PHYs are seen as fixed-link
> +* add more debug support: decide how to expose detailed debug statistics,
> +  add ingress error queue support
> +* MC firmware uprev; the DPAA2 objects used by the Ethernet driver need to
> +  be kept in sync with binary interface changes in MC
> +* refine README file
> +* cleanup
> +
> +NOTE: None of the above is must-have before getting the DPAA2 Ethernet driver
> +out of staging. The main requirement for that is to have the drivers it
> +depends on, fsl-mc bus and DPIO driver, moved to drivers/bus and drivers/soc
> +respectively.

The TODO file should have contact info (I think)...look at other
drivers/staging TODO
for examples.

Stuart

^ permalink raw reply

* [PATCH v3 7/8] arm64: exception: handle asynchronous SError interrupt
From: Xiongfeng Wang @ 2017-04-19  2:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <58F5EFC6.5070601@arm.com>

Hi James,

Thanks for your reply.

On 2017/4/18 18:51, James Morse wrote:
> Hi Wang Xiongfeng,
> 
> On 18/04/17 02:09, Xiongfeng Wang wrote:
>> I have some confusion about the RAS feature when VHE is enabled. Does RAS spec support
>> the situation when VHE is enabled. When VHE is disabled, the hyperviosr delegates the error
>> exception to EL1 by setting HCR_EL2.VSE to 1, and this will inject a virtual SEI into OS.
> 
> (The ARM-ARM also requires the HCR_EL2.AMO to be set so that physical SError
>  Interrupts are taken to EL2, meaning EL1 can never receive a physical SError)
> 
> 
>> My understanding is that HCR_EL2.VSE is only used to inject a virtual SEI into EL1.
> 
> ... mine too ...
> 
>> But when VHE is enabled, the host OS will run at EL2. We can't inject a virtual SEI into
>> host OS. I don't know if RAS spec can handle this situation.
> 
> The host expects to receive physical SError Interrupts. The ARM-ARM doesn't
> describe a way to inject these as they are generated by the CPU.
> 
> Am I right in thinking you want this to use SError Interrupts as an APEI
> notification? (This isn't a CPU thing so the RAS spec doesn't cover this use)

Yes, using sei as an APEI notification is one part of my consideration. Another use is for ESB.
RAS spec 6.5.3 'Example software sequences: Variant: asynchronous External Abort with ESB'
describes the SEI recovery process when ESB is implemented.

In this situation, SEI is routed to EL3 (SCR_EL3.EA = 1). When an SEI occurs in EL0 and not been taken immediately,
and then an ESB instruction at SVC entry is executed, SEI is taken to EL3. The ESB at SVC entry is
used for preventing the error propagating from user space to kernel space. The EL3 SEI handler collects
the errors and fills in the APEI table, and then jump to EL2 SEI handler. EL2 SEI handler inject
an vSEI into EL1 by setting HCR_EL2.VSE = 1, so that when returned to OS, an SEI is pending.
Then ESB is executed again, and DISR_EL1.A is set by hardware (2.4.4 ESB and virtual errors), so that
the following process can be executed.

So we want to inject a vSEI into OS, when control is returned from EL3/2 to OS, no matter whether
it is on host OS or guest OS. I don't know if my understanding is right here.
> 
> This is straightforward for the hyper-visor to implement using Virtual SError.
> I don't think its not always feasible for the host as Physical SError is routed
> to EL3 by SCR_EL3.EA, meaning there is no hardware generated SError that can
> reach EL2. Another APEI notification mechanism may be more appropriate.

> 
> EL3 may be able to 'fake' an SError by returning into the appropriate EL2 vector
> if the exception came from EL{0,1}, or from EL2 and PSTATE.A is clear.
> If the SError came from EL2 and the ESR_EL3.IESB bit is set, we can write an
> appropriate ESR into DISR.

Yes, this can work. When VHE is enabled, we can set DISR.A by software, and 'fake'
an SError by returning into the EL2 SEI vector.

> You cant use SError to cover all the possible RAS exceptions. We already have
> this problem using SEI if PSTATE.A was set and the exception was an imprecise
> abort from EL2. We can't return to the interrupted context and we can't deliver
> an SError to EL2 either.

SEI came from EL2 and PSTATE.A is set. Is it the situation where VHE is enabled and CPU is running
in kernel space. If SEI occurs in kernel space, can we just panic or shutdown.
> 
> Setting SCR_EL3.EA allows firmware to handle these ugly corner cases. Notifying
> the OS is a separate problem where APEI's SEI may not always be the best choice.
> 
> 
> Thanks,
> 
> James
> 
> .
> 
Thanks,
Wang Xiongfeng

^ permalink raw reply

* [PATCH] ARM: dts: rockchip: reuse firefly dtsi
From: Eddie Cai @ 2017-04-19  0:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <746291609.ssvjv54Vin@phil>

2017-04-19 6:20 GMT+08:00 Heiko Stuebner <heiko@sntech.de>:
> Hi Eddie,
>
> Am Dienstag, 18. April 2017, 20:15:27 CEST schrieb Eddie Cai:
>> firefly reload is very similar with firefly board, so reuse firefly dtsi
>>
>> Signed-off-by: Eddie Cai <eddie.cai.linux@gmail.com>
>> ---
>>  arch/arm/boot/dts/rk3288-firefly-reload-core.dtsi | 310 ------------------
>>  arch/arm/boot/dts/rk3288-firefly-reload.dts       | 368 ++--------------------
>
> I would disagree and remember having a similar discussion when the reload-
> support was initially submitted. Please keep in mind that the firefly-
> reload is a som+baseboard combination, so somebody could (or maybe
> already has) create a completely different baseboard for the som that
> does not have any similarities with the original firefly.
> The previous firefly being a real single board.
>
> We also don't combine rock2 and firefly and other boards following the
> general rk3288 design guidelines :-) and the original firefly and reload are
> very different boards if you look at them.
OK, i think the real similar part is the core board and firefly. how
about reuse the
firefly code in the core board?
>
>
> Heiko
>

^ permalink raw reply

* [PATCH 2/2] hwmon: (brcmstb) Add driver for Broadcom STB DPFE
From: Florian Fainelli @ 2017-04-19  0:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CANEuBv5uTBurgpoXBh143T0sB+GCj8oymDxh5+2CqXk5A4dYqw@mail.gmail.com>

On 04/18/2017 05:15 PM, Markus Mayer wrote:
> On 18 April 2017 at 15:47, Guenter Roeck <linux@roeck-us.net> wrote:
>> Hi Florian,
>>
>> On Tue, Apr 18, 2017 at 03:29:55PM -0700, Florian Fainelli wrote:
>>> Hey Guenter,
>>>
>>> On 04/18/2017 01:58 PM, Guenter Roeck wrote:
>>>> Hi Markus,
>>>>
>>>> On Tue, Apr 18, 2017 at 01:17:02PM -0700, Markus Mayer wrote:
>>>>> From: Markus Mayer <mmayer@broadcom.com>
>>>>>
>>>>> This driver allows access to DRAM properties, such as the refresh rate,
>>>>> via the Broadcom STB DDR PHY Front End (DPFE). The refresh rate can be
>>>>> used as indirect indicator of the DRAM temperature.
>>>>>
>>>>> The driver also allows setting of the sampling interval.
>>>>>
>>>>> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>>>>> ---
>>>> [ ... ]
>>>>
>>>>> +
>>>>> +static SENSOR_DEVICE_ATTR(dpfe_info, 0444, show_info, NULL, 1000);
>>>>> +static SENSOR_DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh,
>>>>> +                    1000);
>>>>> +static SENSOR_DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL, 1000);
>>>>> +static struct attribute *dpfe_attrs[] = {
>>>>> +  &sensor_dev_attr_dpfe_info.dev_attr.attr,
>>>>> +  &sensor_dev_attr_dpfe_refresh.dev_attr.attr,
>>>>> +  &sensor_dev_attr_dpfe_vendor.dev_attr.attr,
>>>>> +  NULL
>>>>> +};
>>>>> +ATTRIBUTE_GROUPS(dpfe);
>>>>> +
>>>>
>>>> There is not a single standard hwmon attribute. I don't know how
>>>> to classify this driver, and where it should reside, but it is not
>>>> a hwmon driver.
>>>
>>> This is a driver that talks to an embedded CPU running firmware which is
>>> capable of giving various informations about the DRAM chip being
>>> populated, including a temperature trend (hotter or cooler). We thought
>>> initially we would be able to expose the actual temperature, but this in
>>> turn required a lot more knowledge about the DRAM chip that we wish we
>>> knew about. That is sort of where and why this driver was proposed for
>>> hwmon.
>>>
>>> Which subsystem do you think would be best for this driver drivers/misc/
>>> or drivers/soc/bcm/brcmstb/ maybe?
>>
>> Both should work. I would probably try misc first and let Greg tell me
>> which way to go ;-).
> 
> Thanks for the tip. As Florian said, it was not the idea to submit a
> completely non-standard hwmon driver. I was sure I would be able to
> report at least some standard hwmon data also.

Good thing with drivers/soc/bcm/brcmstb/ is that I can take such patches
directly through ARM SoC pull requests, and since this is inherently
Broadcom STB specific, that sounds like the most ideal location IMHO.
-- 
Florian

^ permalink raw reply

* [PATCH v6 6/8] coresight: add support for CPU debug module
From: Leo Yan @ 2017-04-19  0:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170418174050.GC22806@linaro.org>

On Tue, Apr 18, 2017 at 11:40:50AM -0600, Mathieu Poirier wrote:
> On Thu, Apr 06, 2017 at 09:30:59PM +0800, Leo Yan wrote:
> > Coresight includes debug module and usually the module connects with CPU
> > debug logic. ARMv8 architecture reference manual (ARM DDI 0487A.k) has
> > description for related info in "Part H: External Debug".
> > 
> > Chapter H7 "The Sample-based Profiling Extension" introduces several
> > sampling registers, e.g. we can check program counter value with
> > combined CPU exception level, secure state, etc. So this is helpful for
> > analysis CPU lockup scenarios, e.g. if one CPU has run into infinite
> > loop with IRQ disabled. In this case the CPU cannot switch context and
> > handle any interrupt (including IPIs), as the result it cannot handle
> > SMP call for stack dump.
> > 
> > This patch is to enable coresight debug module, so firstly this driver
> > is to bind apb clock for debug module and this is to ensure the debug
> > module can be accessed from program or external debugger. And the driver
> > uses sample-based registers for debug purpose, e.g. when system triggers
> > panic, the driver will dump program counter and combined context
> > registers (EDCIDSR, EDVIDSR); by parsing context registers so can
> > quickly get to know CPU secure state, exception level, etc.
> > 
> > Some of the debug module registers are located in CPU power domain, so
> > this requires the CPU power domain stays on when access related debug
> > registers, but the power management for CPU power domain is quite
> > dependent on SoC integration for power management. For the platforms
> > which with sane power controller implementations, this driver follows
> > the method to set EDPRCR to try to pull the CPU out of low power state
> > and then set 'no power down request' bit so the CPU has no chance to
> > lose power.
> > 
> > If the SoC has not followed up this design well for power management
> > controller, the user should use the command line parameter or sysfs
> > to constrain all or partial idle states to ensure the CPU power
> > domain is enabled and access coresight CPU debug component safely.
> > 
> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> 
> This is coming along well - a few comment below.  In your next revision please
> add GKH to the 'To' list.  

Sure. Will send out in this week and add Greg in 'To' list.

> > ---
> >  drivers/hwtracing/coresight/Kconfig               |  14 +
> >  drivers/hwtracing/coresight/Makefile              |   1 +
> >  drivers/hwtracing/coresight/coresight-cpu-debug.c | 667 ++++++++++++++++++++++
> >  3 files changed, 682 insertions(+)
> >  create mode 100644 drivers/hwtracing/coresight/coresight-cpu-debug.c
> > 
> > diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
> > index 130cb21..8d55d6d 100644
> > --- a/drivers/hwtracing/coresight/Kconfig
> > +++ b/drivers/hwtracing/coresight/Kconfig
> > @@ -89,4 +89,18 @@ config CORESIGHT_STM
> >  	  logging useful software events or data coming from various entities
> >  	  in the system, possibly running different OSs
> >  
> > +config CORESIGHT_CPU_DEBUG
> > +	tristate "CoreSight CPU Debug driver"
> > +	depends on ARM || ARM64
> > +	depends on DEBUG_FS
> > +	help
> > +	  This driver provides support for coresight debugging module. This
> > +	  is primarily used to dump sample-based profiling registers when
> > +	  system triggers panic, the driver will parse context registers so
> > +	  can quickly get to know program counter (PC), secure state,
> > +	  exception level, etc. Before use debugging functionality, platform
> > +	  needs to ensure the clock domain and power domain are enabled
> > +	  properly, please refer Documentation/trace/coresight-cpu-debug.txt
> > +	  for detailed description and the example for usage.
> > +
> >  endif
> > diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
> > index af480d9..433d590 100644
> > --- a/drivers/hwtracing/coresight/Makefile
> > +++ b/drivers/hwtracing/coresight/Makefile
> > @@ -16,3 +16,4 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \
> >  					coresight-etm4x-sysfs.o
> >  obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
> >  obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
> > +obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o
> > diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c
> > new file mode 100644
> > index 0000000..8470e31
> > --- /dev/null
> > +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c
> > @@ -0,0 +1,667 @@
> > +/*
> > + * Copyright (c) 2017 Linaro Limited. All rights reserved.
> > + *
> > + * Author: Leo Yan <leo.yan@linaro.org>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms of the GNU General Public License version 2 as published by
> > + * the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + *
> > + */
> > +#include <linux/amba/bus.h>
> > +#include <linux/coresight.h>
> > +#include <linux/cpu.h>
> > +#include <linux/debugfs.h>
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/err.h>
> > +#include <linux/init.h>
> > +#include <linux/io.h>
> > +#include <linux/iopoll.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/moduleparam.h>
> > +#include <linux/pm_qos.h>
> > +#include <linux/slab.h>
> > +#include <linux/smp.h>
> > +#include <linux/types.h>
> > +#include <linux/uaccess.h>
> > +
> > +#include "coresight-priv.h"
> > +
> > +#define EDPCSR				0x0A0
> > +#define EDCIDSR				0x0A4
> > +#define EDVIDSR				0x0A8
> > +#define EDPCSR_HI			0x0AC
> > +#define EDOSLAR				0x300
> > +#define EDPRCR				0x310
> > +#define EDPRSR				0x314
> > +#define EDDEVID1			0xFC4
> > +#define EDDEVID				0xFC8
> > +
> > +#define EDPCSR_PROHIBITED		0xFFFFFFFF
> > +
> > +/* bits definition for EDPCSR */
> > +#define EDPCSR_THUMB			BIT(0)
> > +#define EDPCSR_ARM_INST_MASK		GENMASK(31, 2)
> > +#define EDPCSR_THUMB_INST_MASK		GENMASK(31, 1)
> > +
> > +/* bits definition for EDPRCR */
> > +#define EDPRCR_COREPURQ			BIT(3)
> > +#define EDPRCR_CORENPDRQ		BIT(0)
> > +
> > +/* bits definition for EDPRSR */
> > +#define EDPRSR_DLK			BIT(6)
> > +#define EDPRSR_PU			BIT(0)
> > +
> > +/* bits definition for EDVIDSR */
> > +#define EDVIDSR_NS			BIT(31)
> > +#define EDVIDSR_E2			BIT(30)
> > +#define EDVIDSR_E3			BIT(29)
> > +#define EDVIDSR_HV			BIT(28)
> > +#define EDVIDSR_VMID			GENMASK(7, 0)
> > +
> > +/*
> > + * bits definition for EDDEVID1:PSCROffset
> > + *
> > + * NOTE: armv8 and armv7 have different definition for the register,
> > + * so consolidate the bits definition as below:
> > + *
> > + * 0b0000 - Sample offset applies based on the instruction state, we
> > + *          rely on EDDEVID to check if EDPCSR is implemented or not
> > + * 0b0001 - No offset applies.
> > + * 0b0010 - No offset applies, but do not use in AArch32 mode
> > + *
> > + */
> > +#define EDDEVID1_PCSR_OFFSET_MASK	GENMASK(3, 0)
> > +#define EDDEVID1_PCSR_OFFSET_INS_SET	(0x0)
> > +#define EDDEVID1_PCSR_NO_OFFSET_DIS_AARCH32	(0x2)
> > +
> > +/* bits definition for EDDEVID */
> > +#define EDDEVID_PCSAMPLE_MODE		GENMASK(3, 0)
> > +#define EDDEVID_IMPL_EDPCSR		(0x1)
> > +#define EDDEVID_IMPL_EDPCSR_EDCIDSR	(0x2)
> > +#define EDDEVID_IMPL_FULL		(0x3)
> > +
> > +#define DEBUG_WAIT_SLEEP		1000
> > +#define DEBUG_WAIT_TIMEOUT		32000
> > +
> > +struct debug_drvdata {
> > +	void __iomem	*base;
> > e	struct device	*dev;
> > +	int		cpu;
> > +
> > +	bool		edpcsr_present;
> > +	bool		edcidsr_present;
> > +	bool		edvidsr_present;
> > +	bool		pc_has_offset;
> > +
> > +	u32		edpcsr;
> > +	u32		edpcsr_hi;
> > +	u32		edprsr;
> > +	u32		edvidsr;
> > +	u32		edcidsr;
> > +};
> > +
> > +static DEFINE_MUTEX(debug_lock);
> > +static DEFINE_PER_CPU(struct debug_drvdata *, debug_drvdata);
> > +static int debug_count;
> > +static struct dentry *debug_debugfs_dir;
> > +
> > +static bool debug_enable;
> > +module_param_named(enable, debug_enable, bool, 0600);
> > +MODULE_PARM_DESC(enable, "Knob to enable debug functionality "
> > +		 "(default is 0, which means is disabled by default)");
> 
> For this driver we have a debugFS interface so I question the validity of a
> kernel module parameter.  Other than adding complexity to the code it offers no
> real added value.  If a user is to insmod a module, it is just as easy to switch
> on the functionality using debugFS in a second step.

This module parameter can be used for kernel command line, so
it's useful when user wants to dynamically turn on/off the
functionality at boot up time.

Does this make sense for you? Removing this parameter is okay for
me, but this means users need to decide if use it by Kernel config
with static building in. This is a bit contradictory with before's
discussion.

> > +static void debug_os_unlock(struct debug_drvdata *drvdata)
> > +{
> > +	/* Unlocks the debug registers */
> > +	writel_relaxed(0x0, drvdata->base + EDOSLAR);
> 
> Here the wmb is to make sure reordering (either at compile time or in the CPU)
> doesn't happend.  You need a comment here otherwise checkpatch will complain.
> Speaking of which, did you run this through checkpatch?

Right. Everytime I run checkpatch before sending patch and it has
complain for this. Will add comment. Sorry for imprecise working.

> > +	wmb();
> > +}
> > +
> > +/*
> > + * According to ARM DDI 0487A.k, before access external debug
> > + * registers should firstly check the access permission; if any
> > + * below condition has been met then cannot access debug
> > + * registers to avoid lockup issue:
> > + *
> > + * - CPU power domain is powered off;
> > + * - The OS Double Lock is locked;
> > + *
> > + * By checking EDPRSR can get to know if meet these conditions.
> > + */
> > +static bool debug_access_permitted(struct debug_drvdata *drvdata)
> > +{
> > +	/* CPU is powered off */
> > +	if (!(drvdata->edprsr & EDPRSR_PU))
> > +		return false;
> > +
> > +	/* The OS Double Lock is locked */
> > +	if (drvdata->edprsr & EDPRSR_DLK)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> > +static void debug_force_cpu_powered_up(struct debug_drvdata *drvdata)
> > +{
> > +	bool retried = false;
> > +	u32 edprcr;
> > +
> > +try_again:
> > +
> > +	/*
> > +	 * Send request to power management controller and assert
> > +	 * DBGPWRUPREQ signal; if power management controller has
> > +	 * sane implementation, it should enable CPU power domain
> > +	 * in case CPU is in low power state.
> > +	 */
> > +	edprcr = readl_relaxed(drvdata->base + EDPRCR);
> > +	edprcr |= EDPRCR_COREPURQ;
> > +	writel_relaxed(edprcr, drvdata->base + EDPRCR);
> > +
> > +	/* Wait for CPU to be powered up (timeout~=32ms) */
> > +	if (readx_poll_timeout_atomic(readl_relaxed, drvdata->base + EDPRSR,
> > +			drvdata->edprsr, (drvdata->edprsr & EDPRSR_PU),
> > +			DEBUG_WAIT_SLEEP, DEBUG_WAIT_TIMEOUT)) {
> > +		/*
> > +		 * Unfortunately the CPU cannot be powered up, so return
> > +		 * back and later has no permission to access other
> > +		 * registers. For this case, should disable CPU low power
> > +		 * states to ensure CPU power domain is enabled!
> > +		 */
> > +		pr_err("%s: power up request for CPU%d failed\n",
> > +			__func__, drvdata->cpu);
> > +		return;
> > +	}
> > +
> > +	/*
> > +	 * At this point the CPU is powered up, so set the no powerdown
> > +	 * request bit so we don't lose power and emulate power down.
> > +	 */
> > +	edprcr = readl_relaxed(drvdata->base + EDPRCR);
> > +	edprcr |= EDPRCR_COREPURQ | EDPRCR_CORENPDRQ;
> > +	writel_relaxed(edprcr, drvdata->base + EDPRCR);
> > +
> > +	drvdata->edprsr = readl_relaxed(drvdata->base + EDPRSR);
> > +
> > +	/* Bail out if CPU is powered up */
> > +	if (likely(drvdata->edprsr & EDPRSR_PU))
> > +		return;
> 
>         /* The core power domain got switched off on use, try again */
>         if (unlikely(!drvdata->edprsr & EDPRSR_PU))
>                 goto try_again;
> 
> I understand you don't want to introduce a infinite loop but if that happens
> here, something else has gone very wrong.  The above readx_poll_timeout_atomic
> loop should take care of bailing out in case of problems.  That way you also get
> to rid of the retried variable and the code is more simple.

Okay. I will follow your method. Thinking the duration of CPU power
on/off is not same magnitude with this piece code, the infinite loop
will not happen.

> > +
> > +	/*
> > +	 * Handle race condition if CPU has been waken up but it sleeps
> > +	 * again if EDPRCR_CORENPDRQ has been flipped, so try to run
> > +	 * waken flow one more time.
> > +	 */
> > +	if (!retried) {
> > +		retried = true;
> > +		goto try_again;
> > +	}
> > +}
> > +
> > +static void debug_read_regs(struct debug_drvdata *drvdata)
> > +{
> > +	u32 save_edprcr;
> > +
> > +	CS_UNLOCK(drvdata->base);
> > +
> > +	/* Unlock os lock */
> > +	debug_os_unlock(drvdata);
> > +
> > +	/* Save EDPRCR register */
> > +	save_edprcr = readl_relaxed(drvdata->base + EDPRCR);
> > +
> > +	/*
> > +	 * Ensure CPU power domain is enabled to let registers
> > +	 * are accessiable.
> > +	 */
> > +	debug_force_cpu_powered_up(drvdata);
> > +
> > +	if (!debug_access_permitted(drvdata))
> > +		goto out;
> > +
> > +	drvdata->edpcsr = readl_relaxed(drvdata->base + EDPCSR);
> > +
> > +	/*
> > +	 * As described in ARM DDI 0487A.k, if the processing
> > +	 * element (PE) is in debug state, or sample-based
> > +	 * profiling is prohibited, EDPCSR reads as 0xFFFFFFFF;
> > +	 * EDCIDSR, EDVIDSR and EDPCSR_HI registers also become
> > +	 * UNKNOWN state. So directly bail out for this case.
> > +	 */
> > +	if (drvdata->edpcsr == EDPCSR_PROHIBITED)
> > +		goto out;
> > +
> > +	/*
> > +	 * A read of the EDPCSR normally has the side-effect of
> > +	 * indirectly writing to EDCIDSR, EDVIDSR and EDPCSR_HI;
> > +	 * at this point it's safe to read value from them.
> > +	 */
> > +	if (IS_ENABLED(CONFIG_64BIT))
> > +		drvdata->edpcsr_hi = readl_relaxed(drvdata->base + EDPCSR_HI);
> > +
> > +	if (drvdata->edcidsr_present)
> > +		drvdata->edcidsr = readl_relaxed(drvdata->base + EDCIDSR);
> > +
> > +	if (drvdata->edvidsr_present)
> > +		drvdata->edvidsr = readl_relaxed(drvdata->base + EDVIDSR);
> > +
> > +out:
> > +	/* Restore EDPRCR register */
> > +	writel_relaxed(save_edprcr, drvdata->base + EDPRCR);
> > +
> > +	CS_LOCK(drvdata->base);
> > +}
> > +
> > +static unsigned long debug_adjust_pc(struct debug_drvdata *drvdata)
> > +{
> > +	unsigned long arm_inst_offset = 0, thumb_inst_offset = 0;
> > +	unsigned long pc;
> > +
> > +	if (IS_ENABLED(CONFIG_64BIT))
> > +		return (unsigned long)drvdata->edpcsr_hi << 32 |
> > +		       (unsigned long)drvdata->edpcsr;
> > +
> > +	pc = (unsigned long)drvdata->edpcsr;
> > +
> > +	if (drvdata->pc_has_offset) {
> > +		arm_inst_offset = 8;
> > +		thumb_inst_offset = 4;
> > +	}
> > +
> > +	/* Handle thumb instruction */
> > +	if (pc & EDPCSR_THUMB) {
> > +		pc = (pc & EDPCSR_THUMB_INST_MASK) - thumb_inst_offset;
> > +		return pc;
> > +	}
> > +
> > +	/*
> > +	 * Handle arm instruction offset, if the arm instruction
> > +	 * is not 4 byte alignment then it's possible the case
> > +	 * for implementation defined; keep original value for this
> > +	 * case and print info for notice.
> > +	 */
> > +	if (pc & BIT(1))
> > +		pr_emerg("Instruction offset is implementation defined\n");
> > +	else
> > +		pc = (pc & EDPCSR_ARM_INST_MASK) - arm_inst_offset;
> > +
> > +	return pc;
> > +}
> > +
> > +static void debug_dump_regs(struct debug_drvdata *drvdata)
> > +{
> > +	unsigned long pc;
> > +
> > +	pr_emerg("\tEDPRSR:  %08x (Power:%s DLK:%s)\n", drvdata->edprsr,
> > +		 drvdata->edprsr & EDPRSR_PU ? "On" : "Off",
> > +		 drvdata->edprsr & EDPRSR_DLK ? "Lock" : "Unlock");
> > +
> > +	if (!debug_access_permitted(drvdata)) {
> > +		pr_emerg("No permission to access debug registers!\n");
> > +		return;
> > +	}
> > +
> > +	if (drvdata->edpcsr == EDPCSR_PROHIBITED) {
> > +		pr_emerg("CPU is in Debug state or profiling is prohibited!\n");
> > +		return;
> > +	}
> > +
> > +	pc = debug_adjust_pc(drvdata);
> > +	pr_emerg("\tEDPCSR:  [<%p>] %pS\n", (void *)pc, (void *)pc);
> > +
> > +	if (drvdata->edcidsr_present)
> > +		pr_emerg("\tEDCIDSR: %08x\n", drvdata->edcidsr);
> > +
> > +	if (drvdata->edvidsr_present)
> > +		pr_emerg("\tEDVIDSR: %08x (State:%s Mode:%s Width:%dbits VMID:%x)\n",
> > +			 drvdata->edvidsr,
> > +			 drvdata->edvidsr & EDVIDSR_NS ? "Non-secure" : "Secure",
> > +			 drvdata->edvidsr & EDVIDSR_E3 ? "EL3" :
> > +				(drvdata->edvidsr & EDVIDSR_E2 ? "EL2" : "EL1/0"),
> > +			 drvdata->edvidsr & EDVIDSR_HV ? 64 : 32,
> > +			 drvdata->edvidsr & (u32)EDVIDSR_VMID);
> > +}
> > +
> > +static void debug_init_arch_data(void *info)
> > +{
> > +	struct debug_drvdata *drvdata = info;
> > +	u32 mode, pcsr_offset;
> > +	u32 eddevid, eddevid1;
> > +
> > +	CS_UNLOCK(drvdata->base);
> > +
> > +	/* Read device info */
> > +	eddevid  = readl_relaxed(drvdata->base + EDDEVID);
> > +	eddevid1 = readl_relaxed(drvdata->base + EDDEVID1);
> > +
> > +	CS_LOCK(drvdata->base);
> > +
> > +	/* Parse implementation feature */
> > +	mode = eddevid & EDDEVID_PCSAMPLE_MODE;
> > +	pcsr_offset = eddevid1 & EDDEVID1_PCSR_OFFSET_MASK;
> > +
> > +	drvdata->edpcsr_present  = false;
> > +	drvdata->edcidsr_present = false;
> > +	drvdata->edvidsr_present = false;
> > +	drvdata->pc_has_offset   = false;
> > +
> > +	switch (mode) {
> > +	case EDDEVID_IMPL_FULL:
> > +		drvdata->edvidsr_present = true;
> > +		/* Fall through */
> > +	case EDDEVID_IMPL_EDPCSR_EDCIDSR:
> > +		drvdata->edcidsr_present = true;
> > +		/* Fall through */
> > +	case EDDEVID_IMPL_EDPCSR:
> > +		/*
> > +		 * In ARM DDI 0487A.k, the EDDEVID1.PCSROffset is used to
> > +		 * define if has the offset for PC sampling value; if read
> > +		 * back EDDEVID1.PCSROffset == 0x2, then this means the debug
> > +		 * module does not sample the instruction set state when
> > +		 * armv8 CPU in AArch32 state.
> > +		 */
> > +		drvdata->edpcsr_present = (IS_ENABLED(CONFIG_64BIT) ||
> > +			(pcsr_offset != EDDEVID1_PCSR_NO_OFFSET_DIS_AARCH32));
> > +
> > +		drvdata->pc_has_offset =
> > +			(pcsr_offset == EDDEVID1_PCSR_OFFSET_INS_SET);
> > +		break;
> > +	default:
> > +		break;
> > +	}
> > +}
> > +
> > +/*
> > + * Dump out information on panic.
> > + */
> > +static int debug_notifier_call(struct notifier_block *self,
> > +			       unsigned long v, void *p)
> > +{
> > +	int cpu;
> > +	struct debug_drvdata *drvdata;
> > +
> > +	pr_emerg("ARM external debug module:\n");
> > +
> > +	for_each_possible_cpu(cpu) {
> > +		drvdata = per_cpu(debug_drvdata, cpu);
> > +		if (!drvdata)
> > +			continue;
> > +
> > +		pr_emerg("CPU[%d]:\n", drvdata->cpu);
> > +
> > +		debug_read_regs(drvdata);
> > +		debug_dump_regs(drvdata);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static struct notifier_block debug_notifier = {
> > +	.notifier_call = debug_notifier_call,
> > +};
> > +
> > +static int debug_enable_func(void)
> > +{
> > +	struct debug_drvdata *drvdata;
> > +	int cpu;
> > +
> > +	for_each_possible_cpu(cpu) {
> > +		drvdata = per_cpu(debug_drvdata, cpu);
> > +		if (!drvdata)
> > +			continue;
> > +
> > +		pm_runtime_get_sync(drvdata->dev);
> > +	}
> > +
> > +	return atomic_notifier_chain_register(&panic_notifier_list,
> > +					      &debug_notifier);
> > +}
> > +
> > +static int debug_disable_func(void)
> > +{
> > +	struct debug_drvdata *drvdata;
> > +	int cpu;
> > +
> > +	for_each_possible_cpu(cpu) {
> > +		drvdata = per_cpu(debug_drvdata, cpu);
> > +		if (!drvdata)
> > +			continue;
> > +
> > +		pm_runtime_put(drvdata->dev);
> > +	}
> > +
> > +	return atomic_notifier_chain_unregister(&panic_notifier_list,
> > +						&debug_notifier);
> > +}
> > +
> > +static ssize_t debug_func_knob_write(struct file *f,
> > +		const char __user *buf, size_t count, loff_t *ppos)
> > +{
> > +	u8 val;
> > +	int ret;
> > +
> > +	ret = kstrtou8_from_user(buf, count, 2, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	mutex_lock(&debug_lock);
> > +
> > +	if (val == debug_enable)
> > +		goto out;
> > +
> > +	if (val)
> > +		ret = debug_enable_func();
> > +	else
> > +		ret = debug_disable_func();
> 
> I don't think you need to install the handler every time the functionality is
> switched on/off.  I suggest to install the handler at boot time (or module
> insertion time) and in the notifier handler, check the debug_enable flag before
> moving on with the output.

Will do.

> > +
> > +	if (ret) {
> > +		pr_err("%s: unable to %s debug function: %d\n",
> > +		       __func__, val ? "enable" : "disable", ret);
> > +		goto err;
> > +	}
> > +
> > +	debug_enable = val;
> 
> Using a true/false value is probably better here.  That way you don't end up
> with miscellaneous values in debugFS.

>From my testing here will not assign other values rather than 0 or 1.
This is controlled by function kstrtou8_from_user(), the 3rd parameter
'2' is to define the value range [0..1], so other values will report
error after return back from kstrtou8_from_user().

> > +out:
> > +	ret = count;
> > +err:
> > +	mutex_unlock(&debug_lock);
> > +	return ret;
> > +}
> > +
> > +static ssize_t debug_func_knob_read(struct file *f,
> > +		char __user *ubuf, size_t count, loff_t *ppos)
> > +{
> > +	ssize_t ret;
> > +	char buf[2];
> > +
> > +	mutex_lock(&debug_lock);
> > +
> > +	buf[0] = '0' + debug_enable;
> > +	buf[1] = '\n';
> 
>         snprintf()

Will fix.

> > +	ret = simple_read_from_buffer(ubuf, count, ppos, buf, sizeof(buf));
> > +
> > +	mutex_unlock(&debug_lock);
> > +	return ret;
> > +}
> > +
> > +static const struct file_operations debug_func_knob_fops = {
> > +	.open	= simple_open,
> > +	.read	= debug_func_knob_read,
> > +	.write	= debug_func_knob_write,
> > +};
> > +
> > +static int debug_func_init(void)
> > +{
> > +	struct dentry *file;
> > +	int ret;
> > +
> > +	/* Create debugfs node */
> > +	debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL);
> > +	if (!debug_debugfs_dir) {
> > +		pr_err("%s: unable to create debugfs directory\n", __func__);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	file = debugfs_create_file("enable", S_IRUGO | S_IWUSR,
> > +			debug_debugfs_dir, NULL, &debug_func_knob_fops);
> 
> Please align this properly.

Will fix. Thanks a lot for detailed reviewing.

[...]

Thanks,
Leo Yan

^ permalink raw reply

* [PATCH 2/2] hwmon: (brcmstb) Add driver for Broadcom STB DPFE
From: Markus Mayer @ 2017-04-19  0:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170418224739.GA24376@roeck-us.net>

On 18 April 2017 at 15:47, Guenter Roeck <linux@roeck-us.net> wrote:
> Hi Florian,
>
> On Tue, Apr 18, 2017 at 03:29:55PM -0700, Florian Fainelli wrote:
>> Hey Guenter,
>>
>> On 04/18/2017 01:58 PM, Guenter Roeck wrote:
>> > Hi Markus,
>> >
>> > On Tue, Apr 18, 2017 at 01:17:02PM -0700, Markus Mayer wrote:
>> >> From: Markus Mayer <mmayer@broadcom.com>
>> >>
>> >> This driver allows access to DRAM properties, such as the refresh rate,
>> >> via the Broadcom STB DDR PHY Front End (DPFE). The refresh rate can be
>> >> used as indirect indicator of the DRAM temperature.
>> >>
>> >> The driver also allows setting of the sampling interval.
>> >>
>> >> Signed-off-by: Markus Mayer <mmayer@broadcom.com>
>> >> ---
>> > [ ... ]
>> >
>> >> +
>> >> +static SENSOR_DEVICE_ATTR(dpfe_info, 0444, show_info, NULL, 1000);
>> >> +static SENSOR_DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh,
>> >> +                    1000);
>> >> +static SENSOR_DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL, 1000);
>> >> +static struct attribute *dpfe_attrs[] = {
>> >> +  &sensor_dev_attr_dpfe_info.dev_attr.attr,
>> >> +  &sensor_dev_attr_dpfe_refresh.dev_attr.attr,
>> >> +  &sensor_dev_attr_dpfe_vendor.dev_attr.attr,
>> >> +  NULL
>> >> +};
>> >> +ATTRIBUTE_GROUPS(dpfe);
>> >> +
>> >
>> > There is not a single standard hwmon attribute. I don't know how
>> > to classify this driver, and where it should reside, but it is not
>> > a hwmon driver.
>>
>> This is a driver that talks to an embedded CPU running firmware which is
>> capable of giving various informations about the DRAM chip being
>> populated, including a temperature trend (hotter or cooler). We thought
>> initially we would be able to expose the actual temperature, but this in
>> turn required a lot more knowledge about the DRAM chip that we wish we
>> knew about. That is sort of where and why this driver was proposed for
>> hwmon.
>>
>> Which subsystem do you think would be best for this driver drivers/misc/
>> or drivers/soc/bcm/brcmstb/ maybe?
>
> Both should work. I would probably try misc first and let Greg tell me
> which way to go ;-).

Thanks for the tip. As Florian said, it was not the idea to submit a
completely non-standard hwmon driver. I was sure I would be able to
report at least some standard hwmon data also.

Regards,
-Markus

^ permalink raw reply

* [v4.9-rt PATCH] ARM: mm: remove tasklist locking from update_sections_early()
From: Kees Cook @ 2017-04-19  0:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170418204815.9001-1-grygorii.strashko@ti.com>

On Tue, Apr 18, 2017 at 1:48 PM, Grygorii Strashko
<grygorii.strashko@ti.com> wrote:
> The below backtrace can be observed on -rt kernel with CONFIG_DEBUG_RODATA
> option enabled:
>
>  BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:993
>  in_atomic(): 1, irqs_disabled(): 128, pid: 14, name: migration/0
>  1 lock held by migration/0/14:
>   #0:  (tasklist_lock){+.+...}, at: [<c01183e8>] update_sections_early+0x24/0xdc
>  irq event stamp: 38
>  hardirqs last  enabled at (37): [<c08f6f7c>] _raw_spin_unlock_irq+0x24/0x68
>  hardirqs last disabled at (38): [<c01fdfe8>] multi_cpu_stop+0xd8/0x138
>  softirqs last  enabled at (0): [<c01303ec>] copy_process.part.5+0x238/0x1b64
>  softirqs last disabled at (0): [<  (null)>]   (null)
>  Preemption disabled at: [<c01fe244>] cpu_stopper_thread+0x80/0x10c
>  CPU: 0 PID: 14 Comm: migration/0 Not tainted 4.9.21-rt16-02220-g49e319c #15
>  Hardware name: Generic DRA74X (Flattened Device Tree)
>  [<c0112014>] (unwind_backtrace) from [<c010d370>] (show_stack+0x10/0x14)
>  [<c010d370>] (show_stack) from [<c049beb8>] (dump_stack+0xa8/0xd4)
>  [<c049beb8>] (dump_stack) from [<c01631a0>] (___might_sleep+0x1bc/0x2ac)
>  [<c01631a0>] (___might_sleep) from [<c08f7244>] (__rt_spin_lock+0x1c/0x30)
>  [<c08f7244>] (__rt_spin_lock) from [<c08f77a4>] (rt_read_lock+0x54/0x68)
>  [<c08f77a4>] (rt_read_lock) from [<c01183e8>] (update_sections_early+0x24/0xdc)
>  [<c01183e8>] (update_sections_early) from [<c01184b0>] (__fix_kernmem_perms+0x10/0x1c)
>  [<c01184b0>] (__fix_kernmem_perms) from [<c01fe010>] (multi_cpu_stop+0x100/0x138)
>  [<c01fe010>] (multi_cpu_stop) from [<c01fe24c>] (cpu_stopper_thread+0x88/0x10c)
>  [<c01fe24c>] (cpu_stopper_thread) from [<c015edc4>] (smpboot_thread_fn+0x174/0x31c)
>  [<c015edc4>] (smpboot_thread_fn) from [<c015a988>] (kthread+0xf0/0x108)
>  [<c015a988>] (kthread) from [<c0108818>] (ret_from_fork+0x14/0x3c)
>  Freeing unused kernel memory: 1024K (c0d00000 - c0e00000)
>
> The stop_machine() is called with cpus = NULL from fix_kernmem_perms() and
> mark_rodata_ro() which means only one CPU will execute
> update_sections_early() while all other CPUs will spin and wait. Hence,
> it's safe to remove tasklist locking from update_sections_early(). As part of
> this change also mark functions which are local to this module as static
> to simplify code analize in the future.

Hm, yes, good point. It's only every called while other CPUs are stopped.

>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Laura Abbott <labbott@redhat.com>
> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> ---
>  arch/arm/mm/init.c | 8 +++-----
>  1 file changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 370581a..a77953a 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -693,30 +693,28 @@ static void update_sections_early(struct section_perm perms[], int n)

Maybe this should be renamed update_sections_stopped()? Or at least
comments added to help see why it's safe.

>  {
>         struct task_struct *t, *s;
>
> -       read_lock(&tasklist_lock);
>         for_each_process(t) {
>                 if (t->flags & PF_KTHREAD)
>                         continue;
>                 for_each_thread(t, s)
>                         set_section_perms(perms, n, true, s->mm);
>         }
> -       read_unlock(&tasklist_lock);
>         set_section_perms(perms, n, true, current->active_mm);
>         set_section_perms(perms, n, true, &init_mm);
>  }
>
> -int __fix_kernmem_perms(void *unused)
> +static int __fix_kernmem_perms(void *unused)
>  {
>         update_sections_early(nx_perms, ARRAY_SIZE(nx_perms));
>         return 0;
>  }
>
> -void fix_kernmem_perms(void)
> +static void fix_kernmem_perms(void)
>  {
>         stop_machine(__fix_kernmem_perms, NULL, NULL);
>  }
>
> -int __mark_rodata_ro(void *unused)
> +static int __mark_rodata_ro(void *unused)
>  {
>         update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
>         return 0;

Yeah, the static marks are all correct, thanks for fixing these!

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply

* [PATCH] ARM: dts: bcm-cygnus: Add 911360's V3D device.
From: Eric Anholt @ 2017-04-18 23:32 UTC (permalink / raw)
  To: linux-arm-kernel

This loads the VC4 driver on the 911360_entphn platform (with the
corresponding series sent to dri-devel), which is supported by master
of the Mesa tree.

Signed-off-by: Eric Anholt <eric@anholt.net>
---
 arch/arm/boot/dts/bcm-cygnus.dtsi      | 13 +++++++++++++
 arch/arm/boot/dts/bcm911360_entphn.dts |  8 ++++++++
 2 files changed, 21 insertions(+)

diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
index f52750c6d3ed..907a5e843364 100644
--- a/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -406,6 +406,19 @@
 			status = "disabled";
 		};
 
+		v3d: v3d at 180a2000 {
+			compatible = "brcm,cygnus-v3d";
+			reg = <0x180a2000 0x1000>;
+			clocks = <&mipipll BCM_CYGNUS_MIPIPLL_CH2_V3D>;
+			clock-names = "v3d_clk";
+			interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
+		vc4: gpu {
+			compatible = "brcm,cygnus-vc4";
+		};
+
 		adc: adc at 180a6000 {
 			compatible = "brcm,iproc-static-adc";
 			#io-channel-cells = <1>;
diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts
index 8b3800f46288..037621c13290 100644
--- a/arch/arm/boot/dts/bcm911360_entphn.dts
+++ b/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -57,6 +57,14 @@
 	};
 };
 
+&v3d {
+	assigned-clocks =
+		<&mipipll BCM_CYGNUS_MIPIPLL>,
+		<&mipipll BCM_CYGNUS_MIPIPLL_CH2_V3D>;
+	assigned-clock-rates = <525000000>, <300000000>;
+	status = "okay";
+};
+
 &uart3 {
 	status = "okay";
 };
-- 
2.11.0

^ permalink raw reply related

* [PATCH 4/4] mmc: pxamci: Fix race condition between pxamci_dma_irq() and pxamci_irq()
From: Petr Cvek @ 2017-04-18 23:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1492492523.git.petr.cvek@tul.cz>

The data write requests may require an FIFO flush when the DMA transaction
ends. This is handled by a DMA callback pxamci_dma_irq(). After flushing
the FIFO the MCI controller generates the DATA_TRAN_DONE interrupt.

Problem is the DATA_TRAN_DONE interrupt will be generated when the write
data length is divisible by the FIFO size (no flush is required). And in
this case the DMA callback can be called long time after the
DATA_TRAN_DONE interrupt (as the DMA callback is realised by a tasklet,
it can even stack). When the DMA callback is finally called there can
already be a different type of the transaction (another data read or write
request).

The dmaengine_tx_status() will be called for a wrong DMA transaction and
in some case it returns DMA_IN_PROGRESS, which the code recognize as
an error and ends a running DMA and halts the MCI controller.

The problem presents itself under heavy (interrupt) load with a high MCI
traffic with this message:

	mmc0: DMA error on tx channel

The fix must obey these situations:
 - Any command will erase the FIFO
 - Data writes divisible by the FIFO size will (probably) automatically
   generate a DATA_TRAN_DONE interrupt
 - Data writes with a nonzero FIFO remainder must be flushed and then MCI
   generates a DATA_TRAN_DONE interrupt
 - Data reads do not require a flush but they will generate
   a DATA_TRAN_DONE interrupt

The fix changes the DATA_TRAN_DONE interrupt enable from read/write
requests to read requests. The DATA_TRAN_DONE interrupt for a write
request is enabled in the DMA callback, this assures  a DATA_TRAN_DONE
interrupt will be always called after a callback (with or without an FIFO
flush).

Signed-off-by: Petr Cvek <petr.cvek@tul.cz>
---
 drivers/mmc/host/pxamci.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 570735a10127..08713bb6c716 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -335,7 +335,9 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
 
 	pxamci_disable_irq(host, END_CMD_RES);
 	if (host->data && !cmd->error) {
-		pxamci_enable_irq(host, DATA_TRAN_DONE);
+		if (host->data->flags & MMC_DATA_READ)
+			pxamci_enable_irq(host, DATA_TRAN_DONE);
+
 		/*
 		 * workaround for erratum #91, if doing write
 		 * enable DMA late
@@ -585,6 +587,9 @@ static void pxamci_dma_irq(void *param)
 
 	if (likely(status == DMA_COMPLETE)) {
 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
+
+		/* NOTICE pxamci_irq() is dependent on pxamci_dma_irq() */
+		pxamci_enable_irq(host, DATA_TRAN_DONE);
 	} else {
 		pr_err("%s: Invalid DMA status %i\n", mmc_hostname(host->mmc),
 			status);
-- 
2.11.0

^ permalink raw reply related

* [PATCH 3/4] mmc: pxamci: Disable DATA_TRAN_DONE interrupt sooner
From: Petr Cvek @ 2017-04-18 23:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1492492523.git.petr.cvek@tul.cz>

Disable the DATA_TRAN_DONE interrupt as soon as possible in the handler.

Signed-off-by: Petr Cvek <petr.cvek@tul.cz>
---
 drivers/mmc/host/pxamci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 48c26d848e9f..570735a10127 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -354,6 +354,8 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
 	struct mmc_data *data = host->data;
 	struct dma_chan *chan;
 
+	pxamci_disable_irq(host, DATA_TRAN_DONE);
+
 	if (!data) {
 		pr_err("%s: Missing data structure\n",
 			mmc_hostname(host->mmc));
@@ -389,8 +391,6 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
 	else
 		data->bytes_xfered = 0;
 
-	pxamci_disable_irq(host, DATA_TRAN_DONE);
-
 	host->data = NULL;
 	if (host->mrq->stop) {
 		pxamci_stop_clock(host);
-- 
2.11.0

^ permalink raw reply related

* [PATCH 2/4] mmc: pxamci: Enhance error checking
From: Petr Cvek @ 2017-04-18 23:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1492492523.git.petr.cvek@tul.cz>

The pxamci_dma_irq() and pxamci_data_done() should print errors if they
obtains invalid parameters. Make the pxamci_dma_irq() call with
the MMC_DATA_READ flag a fault as the DMA callback is used only for write.

Signed-off-by: Petr Cvek <petr.cvek@tul.cz>
---
 drivers/mmc/host/pxamci.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 80bc8065b50f..48c26d848e9f 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -354,13 +354,22 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
 	struct mmc_data *data = host->data;
 	struct dma_chan *chan;
 
-	if (!data)
+	if (!data) {
+		pr_err("%s: Missing data structure\n",
+			mmc_hostname(host->mmc));
 		return 0;
+	}
 
 	if (data->flags & MMC_DATA_READ)
 		chan = host->dma_chan_rx;
-	else
+	else if (data->flags & MMC_DATA_WRITE)
 		chan = host->dma_chan_tx;
+	else {
+		pr_err("%s: Unknown data direction, flags=%08x\n",
+			mmc_hostname(host->mmc), data->flags);
+		return 0;
+	}
+
 	dma_unmap_sg(chan->device->dev,
 		     data->sg, data->sg_len, host->dma_dir);
 
@@ -558,21 +567,27 @@ static void pxamci_dma_irq(void *param)
 
 	spin_lock_irqsave(&host->lock, flags);
 
-	if (!host->data)
+	if (!host->data) {
+		pr_err("%s: Missing data structure\n",
+			mmc_hostname(host->mmc));
 		goto out_unlock;
+	}
 
-	if (host->data->flags & MMC_DATA_READ)
-		chan = host->dma_chan_rx;
-	else
-		chan = host->dma_chan_tx;
+	if (!(host->data->flags & MMC_DATA_WRITE)) {
+		pr_err("%s: DMA callback is only for tx channel, flags=%x\n",
+			mmc_hostname(host->mmc), host->data->flags);
+		goto out_unlock;
+	}
+
+	chan = host->dma_chan_tx;
 
 	status = dmaengine_tx_status(chan, host->dma_cookie, &state);
 
 	if (likely(status == DMA_COMPLETE)) {
 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
 	} else {
-		pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc),
-			host->data->flags & MMC_DATA_READ ? "rx" : "tx");
+		pr_err("%s: Invalid DMA status %i\n", mmc_hostname(host->mmc),
+			status);
 		host->data->error = -EIO;
 		pxamci_data_done(host, 0);
 	}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 1/4] mmc: pxamci: Use the right flags for DMA callback init
From: Petr Cvek @ 2017-04-18 23:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.1492492523.git.petr.cvek@tul.cz>

The MMC_DATA_READ and the MMC_DATA_WRITE flags for the mmc request are not
mutually exclusive (two different bits). Change the callback initialization
code to use the proper one.

Signed-off-by: Petr Cvek <petr.cvek@tul.cz>
---
 drivers/mmc/host/pxamci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index c763b404510f..80bc8065b50f 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -235,7 +235,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 		return;
 	}
 
-	if (!(data->flags & MMC_DATA_READ)) {
+	if (data->flags & MMC_DATA_WRITE) {
 		tx->callback = pxamci_dma_irq;
 		tx->callback_param = host;
 	}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 0/4] mmc: pxamci: better error handling + fix a race condition
From: Petr Cvek @ 2017-04-18 23:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This patchset deals with a very rare race condition [1] in the PXA MCI
driver which was introduced by using the DMA callback tasklet after
converting the driver for the usage of the kernel DMA engine. The consequent
(and not strictly relevant) changes in the driver v4.7-v4.10 caused the bug
to manifest, but only under a heavy load.

The PXA27x SoC is a little bit weird because when a DMA fills the write FIFO
you must manually flush it. This is done in the callback of the DMA. After
the flush a MCI interrupt is generated and the code continues.

The problem is the read FIFO and the writes of the data sizes divisible by 32
the MCI interrupt is generated immediately after end of the DMA. The driver
trusted the DMA callback to spinlock the IRQ before MCI interrupt handler is
called but it is not a valid solution as the DMA callback is using a tasklet
which can be delayed for a very long time (during testing there was a few
cases of a multiple tasklet scheduling before finally the tasklet started).

The patchset makes the MCI interrupt dependent on the callback in a way that
the interrupt is enabled only in the callback. The read path interrupt enable
stays at the same place (before starting the DMA), it has been only restricted
for the data read path.

The patchset clarifies the code a little and adds a few error reports.

The fix should not make the operation slower as the only slowdown may be
in the case of write && weird length of data && heavy load (when the tasklet
is delayed anyway).

The patchset has been tested on the HTC Magician (PXA27x). I suggest a test
on a different SoC (driver seems to be compatible with PXA300+). Any
incompatibility can be probably fixed by something like cpu_is_pxa300().

References:

[1] "[BUG] dmaengine: pxa_dma: + mmc: pxamci: race condition with DMA error
    on tx channel"
    https://www.spinics.net/lists/linux-mmc/msg42899.html

Thanks,

Petr Cvek (4):
  mmc: pxamci: Use the right flags for DMA callback init
  mmc: pxamci: Enhance error checking
  mmc: pxamci: Disable DATA_TRAN_DONE interrupt sooner
  mmc: pxamci: Fix race condition between pxamci_dma_irq() and
    pxamci_irq()

 drivers/mmc/host/pxamci.c | 46 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 13 deletions(-)

-- 
2.11.0

^ permalink raw reply

* [PATCH v6 5/8] coresight: use const for device_node structures
From: Leo Yan @ 2017-04-18 23:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170418152447.GB22806@linaro.org>

Hi Mathieu,

On Tue, Apr 18, 2017 at 09:24:47AM -0600, Mathieu Poirier wrote:
> On Thu, Apr 06, 2017 at 09:30:58PM +0800, Leo Yan wrote:
> > Almost low level functions from open firmware have used const to
> > qualify device_node structures, so add const for device_node
> > parameters in of_coresight related functions.
> > 
> > Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> 
> I agree with these changes but the patch needs to be split up - please see
> below.
> 
> > ---
> >  drivers/hwtracing/coresight/of_coresight.c | 6 +++---
> >  include/linux/coresight.h                  | 8 ++++----
> >  2 files changed, 7 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
> > index 78d2399..46eec0f 100644
> > --- a/drivers/hwtracing/coresight/of_coresight.c
> > +++ b/drivers/hwtracing/coresight/of_coresight.c
> > @@ -52,7 +52,7 @@ of_coresight_get_endpoint_device(struct device_node *endpoint)
> >  			       endpoint, of_dev_node_match);
> >  }
> >  
> > -static void of_coresight_get_ports(struct device_node *node,
> > +static void of_coresight_get_ports(const struct device_node *node,
> >  				   int *nr_inport, int *nr_outport)
> 
> Move this to a patch by itself as it is not related to this driver.
> 
> >  {
> >  	struct device_node *ep = NULL;
> > @@ -101,7 +101,7 @@ static int of_coresight_alloc_memory(struct device *dev,
> >  	return 0;
> >  }
> >  
> > -int of_coresight_get_cpu(struct device_node *node)
> > +int of_coresight_get_cpu(const struct device_node *node)
> 
> Move this to the previous patch in this set.  There is not need to undo what you
> just did there.
> 
> >  {
> >  	int cpu;
> >  	bool found;
> > @@ -128,7 +128,7 @@ int of_coresight_get_cpu(struct device_node *node)
> >  EXPORT_SYMBOL_GPL(of_coresight_get_cpu);
> >  
> >  struct coresight_platform_data *of_get_coresight_platform_data(
> > -				struct device *dev, struct device_node *node)
> > +			struct device *dev, const struct device_node *node)
> 
> Same here, move this to a new patch (the same one as of_coresight_get_ports()).

Yeah, this is better than my form. Will change.

Thanks,
Leo Yan

^ permalink raw reply

* [PATCH V15 11/11] arm/arm64: KVM: add guest SEA support
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

Currently external aborts are unsupported by the guest abort
handling. Add handling for SEAs so that the host kernel reports
SEAs which occur in the guest kernel.

When an SEA occurs in the guest kernel, the guest exits and is
routed to kvm_handle_guest_abort(). Prior to this patch, a print
message of an unsupported FSC would be printed and nothing else
would happen. With this patch, the code gets routed to the APEI
handling of SEAs in the host kernel to report the SEA information.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>
---
 arch/arm/include/asm/kvm_arm.h       | 10 ++++++++++
 arch/arm/include/asm/system_misc.h   |  5 +++++
 arch/arm/kvm/mmu.c                   | 35 ++++++++++++++++++++++++++++++++---
 arch/arm64/include/asm/kvm_arm.h     | 10 ++++++++++
 arch/arm64/include/asm/system_misc.h |  2 ++
 arch/arm64/mm/fault.c                | 23 +++++++++++++++++++++--
 drivers/acpi/apei/ghes.c             | 13 +++++++------
 include/acpi/ghes.h                  |  2 +-
 8 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index a3f0b3d..ebf020b 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -187,6 +187,16 @@
 #define FSC_FAULT	(0x04)
 #define FSC_ACCESS	(0x08)
 #define FSC_PERM	(0x0c)
+#define FSC_SEA		(0x10)
+#define FSC_SEA_TTW0	(0x14)
+#define FSC_SEA_TTW1	(0x15)
+#define FSC_SEA_TTW2	(0x16)
+#define FSC_SEA_TTW3	(0x17)
+#define FSC_SECC	(0x18)
+#define FSC_SECC_TTW0	(0x1c)
+#define FSC_SECC_TTW1	(0x1d)
+#define FSC_SECC_TTW2	(0x1e)
+#define FSC_SECC_TTW3	(0x1f)
 
 /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
 #define HPFAR_MASK	(~0xf)
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index a3d61ad..8c4a89f 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -22,6 +22,11 @@
 
 extern unsigned int user_debug;
 
+static inline int handle_guest_sea(phys_addr_t addr, unsigned int esr)
+{
+	return -1;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_ARM_SYSTEM_MISC_H */
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 582a972..fd11855 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -29,6 +29,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/virt.h>
+#include <asm/system_misc.h>
 
 #include "trace.h"
 
@@ -1418,6 +1419,24 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
 		kvm_set_pfn_accessed(pfn);
 }
 
+static bool is_abort_sea(unsigned long fault_status) {
+	switch (fault_status) {
+	case FSC_SEA:
+	case FSC_SEA_TTW0:
+	case FSC_SEA_TTW1:
+	case FSC_SEA_TTW2:
+	case FSC_SEA_TTW3:
+	case FSC_SECC:
+	case FSC_SECC_TTW0:
+	case FSC_SECC_TTW1:
+	case FSC_SECC_TTW2:
+	case FSC_SECC_TTW3:
+		return true;
+	default:
+		return false;
+	}
+}
+
 /**
  * kvm_handle_guest_abort - handles all 2nd stage aborts
  * @vcpu:	the VCPU pointer
@@ -1440,19 +1459,29 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	gfn_t gfn;
 	int ret, idx;
 
+	fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
+
+	fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
+
+	/*
+	 * The host kernel will handle the synchronous external abort. There
+	 * is no need to pass the error into the guest.
+	 */
+	if (is_abort_sea(fault_status)) {
+		if (!handle_guest_sea(fault_ipa, kvm_vcpu_get_hsr(vcpu)))
+			return 1;
+	}
+
 	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
 	if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
 		kvm_inject_vabt(vcpu);
 		return 1;
 	}
 
-	fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
-
 	trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu),
 			      kvm_vcpu_get_hfar(vcpu), fault_ipa);
 
 	/* Check the stage-2 fault is trans. fault or write fault */
-	fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
 	if (fault_status != FSC_FAULT && fault_status != FSC_PERM &&
 	    fault_status != FSC_ACCESS) {
 		kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 6e99978..61d694c 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -204,6 +204,16 @@
 #define FSC_FAULT	ESR_ELx_FSC_FAULT
 #define FSC_ACCESS	ESR_ELx_FSC_ACCESS
 #define FSC_PERM	ESR_ELx_FSC_PERM
+#define FSC_SEA		ESR_ELx_FSC_EXTABT
+#define FSC_SEA_TTW0	(0x14)
+#define FSC_SEA_TTW1	(0x15)
+#define FSC_SEA_TTW2	(0x16)
+#define FSC_SEA_TTW3	(0x17)
+#define FSC_SECC	(0x18)
+#define FSC_SECC_TTW0	(0x1c)
+#define FSC_SECC_TTW1	(0x1d)
+#define FSC_SECC_TTW2	(0x1e)
+#define FSC_SECC_TTW3	(0x1f)
 
 /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
 #define HPFAR_MASK	(~UL(0xf))
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index bc81243..95aa442 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -56,6 +56,8 @@ void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
 	__show_ratelimited;						\
 })
 
+int handle_guest_sea(phys_addr_t addr, unsigned int esr);
+
 #endif	/* __ASSEMBLY__ */
 
 #endif	/* __ASM_SYSTEM_MISC_H */
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 10013ff..a8c5d11 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -515,6 +515,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 {
 	struct siginfo info;
 	const struct fault_info *inf;
+	int ret = 0;
 
 	inf = esr_to_fault_info(esr);
 	pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n",
@@ -527,7 +528,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 	 */
 	if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
 		nmi_enter();
-		ghes_notify_sea();
+		ret = ghes_notify_sea();
 		nmi_exit();
 	}
 
@@ -540,7 +541,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 		info.si_addr  = (void __user *)addr;
 	arm64_notify_die("", regs, &info, esr);
 
-	return 0;
+	return ret;
 }
 
 static const struct fault_info fault_info[] = {
@@ -611,6 +612,24 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 };
 
 /*
+ * Handle Synchronous External Aborts that occur in a guest kernel.
+ *
+ * The return value will be zero if the SEA was successfully handled
+ * and non-zero if there was an error processing the error or there was
+ * no error to process.
+ */
+int handle_guest_sea(phys_addr_t addr, unsigned int esr)
+{
+	int ret = -ENOENT;
+
+	if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
+		ret = ghes_notify_sea();
+	}
+
+	return ret;
+}
+
+/*
  * Dispatch a data abort to the relevant handler.
  */
 asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 612deb3..d286248 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -812,17 +812,18 @@ static int ghes_notify_sci(struct notifier_block *this,
 #ifdef CONFIG_ACPI_APEI_SEA
 static LIST_HEAD(ghes_sea);
 
-void ghes_notify_sea(void)
+int ghes_notify_sea(void)
 {
 	struct ghes *ghes;
+	int ret = -ENOENT;
 
-	/*
-	 * synchronize_rcu() will wait for nmi_exit(), so no need to
-	 * rcu_read_lock().
-	 */
+	rcu_read_lock();
 	list_for_each_entry_rcu(ghes, &ghes_sea, list) {
-		ghes_proc(ghes);
+		if(!ghes_proc(ghes))
+			ret = 0;
 	}
+	rcu_read_unlock();
+	return ret;
 }
 
 static void ghes_sea_add(struct ghes *ghes)
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index ef0040893..09e0b65 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -99,6 +99,6 @@ static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
 	return gdata + 1;
 }
 
-void ghes_notify_sea(void);
+int ghes_notify_sea(void);
 
 #endif /* GHES_H */
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 10/11] trace, ras: add ARM processor error trace event
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

Currently there are trace events for the various RAS
errors with the exception of ARM processor type errors.
Add a new trace event for such errors so that the user
will know when they occur. These trace events are
consistent with the ARM processor error section type
defined in UEFI 2.6 spec section N.2.4.4.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Reviewed-by: Xie XiuQi <xiexiuqi@huawei.com>
---
 drivers/acpi/apei/ghes.c    |  8 +++++++-
 drivers/firmware/efi/cper.c |  1 +
 drivers/ras/ras.c           |  1 +
 include/ras/ras_event.h     | 45 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 3d9f63b..612deb3 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -518,7 +518,13 @@ static void ghes_do_proc(struct ghes *ghes,
 		}
 #endif
 #ifdef CONFIG_RAS
-		else if (trace_unknown_sec_event_enabled()) {
+		else if (!uuid_le_cmp(sec_type, CPER_SEC_PROC_ARM) &&
+			 trace_arm_event_enabled()) {
+			struct cper_sec_proc_arm *arm_err;
+
+			arm_err = acpi_hest_get_payload(gdata);
+			trace_arm_event(arm_err);
+		} else if (trace_unknown_sec_event_enabled()) {
 			void *unknown_err = acpi_hest_get_payload(gdata);
 
 			trace_unknown_sec_event(&sec_type,
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 610d31a..650e0f6 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -35,6 +35,7 @@
 #include <linux/printk.h>
 #include <linux/bcd.h>
 #include <acpi/ghes.h>
+#include <ras/ras_event.h>
 
 #define INDENT_SP	" "
 
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index fb2500b..8ba5a94 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -28,3 +28,4 @@ static int __init ras_init(void)
 #endif
 EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event);
 EXPORT_TRACEPOINT_SYMBOL_GPL(unknown_sec_event);
+EXPORT_TRACEPOINT_SYMBOL_GPL(arm_event);
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index 5861b6f..13befad 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -162,6 +162,51 @@
 );
 
 /*
+ * ARM Processor Events Report
+ *
+ * This event is generated when hardware detects an ARM processor error
+ * has occurred. UEFI 2.6 spec section N.2.4.4.
+ */
+TRACE_EVENT(arm_event,
+
+	TP_PROTO(const struct cper_sec_proc_arm *proc),
+
+	TP_ARGS(proc),
+
+	TP_STRUCT__entry(
+		__field(u64, mpidr)
+		__field(u64, midr)
+		__field(u32, running_state)
+		__field(u32, psci_state)
+		__field(u8, affinity)
+	),
+
+	TP_fast_assign(
+		if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
+			__entry->affinity = proc->affinity_level;
+		else
+			__entry->affinity = ~0;
+		if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
+			__entry->mpidr = proc->mpidr;
+		else
+			__entry->mpidr = 0ULL;
+		__entry->midr = proc->midr;
+		if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
+			__entry->running_state = proc->running_state;
+			__entry->psci_state = proc->psci_state;
+		} else {
+			__entry->running_state = ~0;
+			__entry->psci_state = ~0;
+		}
+	),
+
+	TP_printk("affinity level: %d; MPIDR: %016llx; MIDR: %016llx; "
+		  "running state: %d; PSCI state: %d",
+		  __entry->affinity, __entry->mpidr, __entry->midr,
+		  __entry->running_state, __entry->psci_state)
+);
+
+/*
  * Unknown Section Report
  *
  * This event is generated when hardware detected a hardware
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 09/11] ras: acpi / apei: generate trace event for unrecognized CPER section
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

UEFI spec allows for non-standard section in Common Platform Error
Record. This is defined in section N.2.3 of UEFI version 2.5.

Currently if the CPER section's type (UUID) does not match with
any section type that the kernel knows how to parse, trace event
is not generated for such section. And thus user is not able to know
happening of such hardware error, including error record of
non-standard section.

This commit generates a trace event which contains raw error data
for unrecognized CPER section.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Tested-by: Shiju Jose <shiju.jose@huawei.com>
---
 drivers/acpi/apei/ghes.c | 27 +++++++++++++++++++++++----
 drivers/ras/ras.c        |  1 +
 include/ras/ras_event.h  | 45 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index b91123f..3d9f63b 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -45,11 +45,13 @@
 #include <linux/aer.h>
 #include <linux/nmi.h>
 #include <linux/sched/clock.h>
+#include <linux/uuid.h>
 
 #include <acpi/actbl1.h>
 #include <acpi/ghes.h>
 #include <acpi/apei.h>
 #include <asm/tlbflush.h>
+#include <ras/ras_event.h>
 
 #include "apei-internal.h"
 
@@ -461,12 +463,21 @@ static void ghes_do_proc(struct ghes *ghes,
 {
 	int sev, sec_sev;
 	struct acpi_hest_generic_data *gdata;
+	uuid_le sec_type;
+	uuid_le *fru_id = &NULL_UUID_LE;
+	char *fru_text = "";
 
 	sev = ghes_severity(estatus->error_severity);
 	apei_estatus_for_each_section(estatus, gdata) {
 		sec_sev = ghes_severity(gdata->error_severity);
-		if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
-				 CPER_SEC_PLATFORM_MEM)) {
+		sec_type = *(uuid_le *)gdata->section_type;
+
+		if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+			fru_id = (uuid_le *)gdata->fru_id;
+		if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+			fru_text = gdata->fru_text;
+
+		if (!uuid_le_cmp(sec_type, CPER_SEC_PLATFORM_MEM)) {
 			struct cper_sec_mem_err *mem_err;
 			mem_err = acpi_hest_get_payload(gdata);
 			ghes_edac_report_mem_error(ghes, sev, mem_err);
@@ -475,8 +486,7 @@ static void ghes_do_proc(struct ghes *ghes,
 			ghes_handle_memory_failure(gdata, sev);
 		}
 #ifdef CONFIG_ACPI_APEI_PCIEAER
-		else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
-				      CPER_SEC_PCIE)) {
+		else if (!uuid_le_cmp(sec_type, CPER_SEC_PCIE)) {
 			struct cper_sec_pcie *pcie_err;
 			pcie_err = acpi_hest_get_payload(gdata);
 			if (sev == GHES_SEV_RECOVERABLE &&
@@ -507,6 +517,15 @@ static void ghes_do_proc(struct ghes *ghes,
 
 		}
 #endif
+#ifdef CONFIG_RAS
+		else if (trace_unknown_sec_event_enabled()) {
+			void *unknown_err = acpi_hest_get_payload(gdata);
+
+			trace_unknown_sec_event(&sec_type,
+					fru_id, fru_text, sec_sev,
+					unknown_err, gdata->error_data_length);
+		}
+#endif
 	}
 }
 
diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c
index b67dd36..fb2500b 100644
--- a/drivers/ras/ras.c
+++ b/drivers/ras/ras.c
@@ -27,3 +27,4 @@ static int __init ras_init(void)
 EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event);
 #endif
 EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event);
+EXPORT_TRACEPOINT_SYMBOL_GPL(unknown_sec_event);
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index 1791a12..5861b6f 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -162,6 +162,51 @@
 );
 
 /*
+ * Unknown Section Report
+ *
+ * This event is generated when hardware detected a hardware
+ * error event, which may be of non-standard section as defined
+ * in UEFI spec appendix "Common Platform Error Record", or may
+ * be of sections for which TRACE_EVENT is not defined.
+ *
+ */
+TRACE_EVENT(unknown_sec_event,
+
+	TP_PROTO(const uuid_le *sec_type,
+		 const uuid_le *fru_id,
+		 const char *fru_text,
+		 const u8 sev,
+		 const u8 *err,
+		 const u32 len),
+
+	TP_ARGS(sec_type, fru_id, fru_text, sev, err, len),
+
+	TP_STRUCT__entry(
+		__array(char, sec_type, 16)
+		__array(char, fru_id, 16)
+		__string(fru_text, fru_text)
+		__field(u8, sev)
+		__field(u32, len)
+		__dynamic_array(u8, buf, len)
+	),
+
+	TP_fast_assign(
+		memcpy(__entry->sec_type, sec_type, sizeof(uuid_le));
+		memcpy(__entry->fru_id, fru_id, sizeof(uuid_le));
+		__assign_str(fru_text, fru_text);
+		__entry->sev = sev;
+		__entry->len = len;
+		memcpy(__get_dynamic_array(buf), err, len);
+	),
+
+	TP_printk("severity: %d; sec type:%pU; FRU: %pU %s; data len:%d; raw data:%s",
+		  __entry->sev, __entry->sec_type,
+		  __entry->fru_id, __get_str(fru_text),
+		  __entry->len,
+		  __print_hex(__get_dynamic_array(buf), __entry->len))
+);
+
+/*
  * PCIe AER Trace event
  *
  * These events are generated when hardware detects a corrected or
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 08/11] efi: print unrecognized CPER section
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

UEFI spec allows for non-standard section in Common Platform Error
Record. This is defined in section N.2.3 of UEFI version 2.5.

Currently if the CPER section's type (UUID) does not match with
one of the section types that the kernel knows how to parse, the
section is skipped. Therefore, user is not able to see
such CPER data, for instance, error record of non-standard section.

For above mentioned case, this change prints out the raw data in
hex in dmesg buffer. Data length is taken from Error Data length
field of Generic Error Data Entry.

The following is a sample output from dmesg:
[  140.739180] {1}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 2
[  140.739182] {1}[Hardware Error]: It has been corrected by h/w and requires no further action
[  140.739191] {1}[Hardware Error]: event severity: corrected
[  140.739196] {1}[Hardware Error]:  time: precise 2017-03-15 20:37:35
[  140.739197] {1}[Hardware Error]:  Error 0, type: corrected
[  140.739203] {1}[Hardware Error]:   section type: unknown, d2e2621c-f936-468d-0d84-15a4ed015c8b
[  140.739205] {1}[Hardware Error]:   section length: 568 (0x238)
[  140.739210] {1}[Hardware Error]:   00000000: 4d415201 4d492031 453a4d45 435f4343  .RAM1 IMEM:ECC_C
[  140.739214] {1}[Hardware Error]:   00000010: 53515f45 44525f42 00000000 00000000  E_QSB_RD........
[  140.739217] {1}[Hardware Error]:   00000020: 00000000 00000000 00000000 00000000  ................
[  140.739220] {1}[Hardware Error]:   00000030: 00000000 00000000 01010000 01010000  ................
[  140.739223] {1}[Hardware Error]:   00000040: 00000000 00000000 00000005 00000000  ................
[  140.739226] {1}[Hardware Error]:   00000050: 01010000 00000000 00000001 00dddd00  ................
...

The raw data from the error can then be decoded using vendor
specific tools.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Reviewed-by: James Morse <james.morse@arm.com>
---
 drivers/firmware/efi/cper.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index f959185..610d31a 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -596,8 +596,16 @@ static void cper_estatus_timestamp(const char *pfx,
 			cper_print_proc_arm(newpfx, arm_err);
 		else
 			goto err_section_too_small;
-	} else
-		printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);
+	} else {
+		const void *unknown_err;
+
+		unknown_err = acpi_hest_get_payload(gdata);
+		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
+		printk("%ssection length: %d (%#x)\n", newpfx,
+		       gdata->error_data_length, gdata->error_data_length);
+		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
+			       unknown_err, gdata->error_data_length, true);
+	}
 
 	return;
 
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 07/11] acpi: apei: panic OS with fatal error status block
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

From: "Jonathan (Zhixiong) Zhang" <zjzhang@codeaurora.org>

Even if an error status block's severity is fatal, the kernel does not
honor the severity level and panic.

With the firmware first model, the platform could inform the OS about a
fatal hardware error through the non-NMI GHES notification type. The OS
should panic when a hardware error record is received with this
severity.

Call panic() after CPER data in error status block is printed if
severity is fatal, before each error section is handled.

Signed-off-by: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
Reviewed-by: James Morse <james.morse@arm.com>
---
 drivers/acpi/apei/ghes.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 2d387f8..b91123f 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -134,6 +134,8 @@
 static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
 static atomic_t ghes_estatus_cache_alloced;
 
+static int ghes_panic_timeout __read_mostly = 30;
+
 static int ghes_ioremap_init(void)
 {
 	ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
@@ -692,6 +694,13 @@ static int ghes_ack_error(struct acpi_hest_generic_v2 *generic_v2)
 	return apei_write(val, &generic_v2->read_ack_register);
 }
 
+static void __ghes_call_panic(void)
+{
+	if (panic_timeout == 0)
+		panic_timeout = ghes_panic_timeout;
+	panic("Fatal hardware error!");
+}
+
 static int ghes_proc(struct ghes *ghes)
 {
 	int rc;
@@ -699,6 +708,10 @@ static int ghes_proc(struct ghes *ghes)
 	rc = ghes_read_estatus(ghes, 0);
 	if (rc)
 		goto out;
+	if (ghes_severity(ghes->estatus->error_severity) >= GHES_SEV_PANIC) {
+		__ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
+		__ghes_call_panic();
+	}
 	if (!ghes_estatus_cached(ghes->estatus)) {
 		if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus))
 			ghes_estatus_cache_add(ghes->generic, ghes->estatus);
@@ -835,8 +848,6 @@ static inline void ghes_sea_remove(struct ghes *ghes)
 
 static LIST_HEAD(ghes_nmi);
 
-static int ghes_panic_timeout	__read_mostly = 30;
-
 static void ghes_proc_in_irq(struct irq_work *irq_work)
 {
 	struct llist_node *llnode, *next;
@@ -929,9 +940,7 @@ static void __ghes_panic(struct ghes *ghes)
 	__ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
 
 	/* reboot to log the error! */
-	if (panic_timeout == 0)
-		panic_timeout = ghes_panic_timeout;
-	panic("Fatal hardware error!");
+	__ghes_call_panic();
 }
 
 static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 06/11] acpi: apei: handle SEA notification type for ARMv8
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

ARM APEI extension proposal added SEA (Synchronous External Abort)
notification type for ARMv8.
Add a new GHES error source handling function for SEA. If an error
source's notification type is SEA, then this function can be registered
into the SEA exception handler. That way GHES will parse and report
SEA exceptions when they occur.
An SEA can interrupt code that had interrupts masked and is treated as
an NMI. To aid this the page of address space for mapping APEI buffers
while in_nmi() is always reserved, and ghes_ioremap_pfn_nmi() is
changed to use the helper methods to find the prot_t to map with in
the same way as ghes_ioremap_pfn_irq().

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Reviewed-by: James Morse <james.morse@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm64/Kconfig        |  2 ++
 arch/arm64/mm/fault.c     | 13 +++++++++
 drivers/acpi/apei/Kconfig | 15 ++++++++++
 drivers/acpi/apei/ghes.c  | 70 +++++++++++++++++++++++++++++++++++++++++++----
 include/acpi/ghes.h       |  7 +++++
 5 files changed, 101 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3741859..36226c2 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -18,6 +18,7 @@ config ARM64
 	select ARCH_HAS_STRICT_KERNEL_RWX
 	select ARCH_HAS_STRICT_MODULE_RWX
 	select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
+	select ARCH_HAVE_NMI_SAFE_CMPXCHG if ACPI_APEI_SEA
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select ARCH_SUPPORTS_ATOMIC_RMW
 	select ARCH_SUPPORTS_NUMA_BALANCING
@@ -92,6 +93,7 @@ config ARM64
 	select HAVE_IRQ_TIME_ACCOUNTING
 	select HAVE_MEMBLOCK
 	select HAVE_MEMBLOCK_NODE_MAP if NUMA
+	select HAVE_NMI if ACPI_APEI_SEA
 	select HAVE_PATA_PLATFORM
 	select HAVE_PERF_EVENTS
 	select HAVE_PERF_REGS
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index b74d8b7..10013ff 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -42,6 +42,8 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
+#include <acpi/ghes.h>
+
 struct fault_info {
 	int	(*fn)(unsigned long addr, unsigned int esr,
 		      struct pt_regs *regs);
@@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 	pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n",
 		inf->name, esr, addr);
 
+	/*
+	 * Synchronous aborts may interrupt code which had interrupts masked.
+	 * Before calling out into the wider kernel tell the interested
+	 * subsystems.
+	 */
+	if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
+		nmi_enter();
+		ghes_notify_sea();
+		nmi_exit();
+	}
+
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code  = 0;
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index b0140c8..de14d49 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -39,6 +39,21 @@ config ACPI_APEI_PCIEAER
 	  PCIe AER errors may be reported via APEI firmware first mode.
 	  Turn on this option to enable the corresponding support.
 
+config ACPI_APEI_SEA
+	bool "APEI Synchronous External Abort logging/recovering support"
+	depends on ARM64 && ACPI_APEI_GHES
+	default y
+	help
+	  This option should be enabled if the system supports
+	  firmware first handling of SEA (Synchronous External Abort).
+	  SEA happens with certain faults of data abort or instruction
+	  abort synchronous exceptions on ARMv8 systems. If a system
+	  supports firmware first handling of SEA, the platform analyzes
+	  and handles hardware error notifications from SEA, and it may then
+	  form a HW error record for the OS to parse and handle. This
+	  option allows the OS to look for such hardware error record, and
+	  take appropriate action.
+
 config ACPI_APEI_MEMORY_FAILURE
 	bool "APEI memory error recovering support"
 	depends on ACPI_APEI && MEMORY_FAILURE
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index dfb7dd2..2d387f8 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -115,11 +115,7 @@
  * Two virtual pages are used, one for IRQ/PROCESS context, the other for
  * NMI context (optionally).
  */
-#ifdef CONFIG_HAVE_ACPI_APEI_NMI
 #define GHES_IOREMAP_PAGES           2
-#else
-#define GHES_IOREMAP_PAGES           1
-#endif
 #define GHES_IOREMAP_IRQ_PAGE(base)	(base)
 #define GHES_IOREMAP_NMI_PAGE(base)	((base) + PAGE_SIZE)
 
@@ -158,10 +154,14 @@ static void ghes_ioremap_exit(void)
 static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
 {
 	unsigned long vaddr;
+	phys_addr_t paddr;
+	pgprot_t prot;
 
 	vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
-	ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
-			   pfn << PAGE_SHIFT, PAGE_KERNEL);
+
+	paddr = pfn << PAGE_SHIFT;
+	prot = arch_apei_get_mem_attribute(paddr);
+	ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
 
 	return (void __iomem *)vaddr;
 }
@@ -771,6 +771,50 @@ static int ghes_notify_sci(struct notifier_block *this,
 	.notifier_call = ghes_notify_sci,
 };
 
+#ifdef CONFIG_ACPI_APEI_SEA
+static LIST_HEAD(ghes_sea);
+
+void ghes_notify_sea(void)
+{
+	struct ghes *ghes;
+
+	/*
+	 * synchronize_rcu() will wait for nmi_exit(), so no need to
+	 * rcu_read_lock().
+	 */
+	list_for_each_entry_rcu(ghes, &ghes_sea, list) {
+		ghes_proc(ghes);
+	}
+}
+
+static void ghes_sea_add(struct ghes *ghes)
+{
+	mutex_lock(&ghes_list_mutex);
+	list_add_rcu(&ghes->list, &ghes_sea);
+	mutex_unlock(&ghes_list_mutex);
+}
+
+static void ghes_sea_remove(struct ghes *ghes)
+{
+	mutex_lock(&ghes_list_mutex);
+	list_del_rcu(&ghes->list);
+	mutex_unlock(&ghes_list_mutex);
+	synchronize_rcu();
+}
+#else /* CONFIG_ACPI_APEI_SEA */
+static inline void ghes_sea_add(struct ghes *ghes)
+{
+	pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
+	       ghes->generic->header.source_id);
+}
+
+static inline void ghes_sea_remove(struct ghes *ghes)
+{
+	pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
+	       ghes->generic->header.source_id);
+}
+#endif /* CONFIG_ACPI_APEI_SEA */
+
 #ifdef CONFIG_HAVE_ACPI_APEI_NMI
 /*
  * printk is not safe in NMI context.  So in NMI handler, we allocate
@@ -1016,6 +1060,14 @@ static int ghes_probe(struct platform_device *ghes_dev)
 	case ACPI_HEST_NOTIFY_EXTERNAL:
 	case ACPI_HEST_NOTIFY_SCI:
 		break;
+	case ACPI_HEST_NOTIFY_SEA:
+		if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
+			pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n",
+				generic->header.source_id);
+			rc = -ENOTSUPP;
+			goto err;
+		}
+		break;
 	case ACPI_HEST_NOTIFY_NMI:
 		if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
 			pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
@@ -1081,6 +1133,9 @@ static int ghes_probe(struct platform_device *ghes_dev)
 		list_add_rcu(&ghes->list, &ghes_sci);
 		mutex_unlock(&ghes_list_mutex);
 		break;
+	case ACPI_HEST_NOTIFY_SEA:
+		ghes_sea_add(ghes);
+		break;
 	case ACPI_HEST_NOTIFY_NMI:
 		ghes_nmi_add(ghes);
 		break;
@@ -1124,6 +1179,9 @@ static int ghes_remove(struct platform_device *ghes_dev)
 		mutex_unlock(&ghes_list_mutex);
 		synchronize_rcu();
 		break;
+	case ACPI_HEST_NOTIFY_SEA:
+		ghes_sea_remove(ghes);
+		break;
 	case ACPI_HEST_NOTIFY_NMI:
 		ghes_nmi_remove(ghes);
 		break;
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index b89361a..ef0040893 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -1,3 +1,6 @@
+#ifndef GHES_H
+#define GHES_H
+
 #include <acpi/apei.h>
 #include <acpi/hed.h>
 
@@ -95,3 +98,7 @@ static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
 
 	return gdata + 1;
 }
+
+void ghes_notify_sea(void);
+
+#endif /* GHES_H */
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 05/11] arm64: exception: handle Synchronous External Abort
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

SEA exceptions are often caused by an uncorrected hardware
error, and are handled when data abort and instruction abort
exception classes have specific values for their Fault Status
Code.
When SEA occurs, before killing the process, report the error
in the kernel logs.
Update fault_info[] with specific SEA faults so that the
new SEA handler is used.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Reviewed-by: James Morse <james.morse@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm64/include/asm/esr.h |  1 +
 arch/arm64/mm/fault.c        | 45 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index d14c478..f20c64a 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -83,6 +83,7 @@
 #define ESR_ELx_WNR		(UL(1) << 6)
 
 /* Shared ISS field definitions for Data/Instruction aborts */
+#define ESR_ELx_FnV		(UL(1) << 10)
 #define ESR_ELx_EA		(UL(1) << 9)
 #define ESR_ELx_S1PTW		(UL(1) << 7)
 
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 1b35b8bd..b74d8b7 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -505,6 +505,31 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 	return 1;
 }
 
+/*
+ * This abort handler deals with Synchronous External Abort.
+ * It calls notifiers, and then returns "fault".
+ */
+static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
+{
+	struct siginfo info;
+	const struct fault_info *inf;
+
+	inf = esr_to_fault_info(esr);
+	pr_err("Synchronous External Abort: %s (0x%08x)@0x%016lx\n",
+		inf->name, esr, addr);
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code  = 0;
+	if (esr & ESR_ELx_FnV)
+		info.si_addr = 0;
+	else
+		info.si_addr  = (void __user *)addr;
+	arm64_notify_die("", regs, &info, esr);
+
+	return 0;
+}
+
 static const struct fault_info fault_info[] = {
 	{ do_bad,		SIGBUS,  0,		"ttbr address size fault"	},
 	{ do_bad,		SIGBUS,  0,		"level 1 address size fault"	},
@@ -522,22 +547,22 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
 	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 1 permission fault"	},
 	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 2 permission fault"	},
 	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 3 permission fault"	},
-	{ do_bad,		SIGBUS,  0,		"synchronous external abort"	},
+	{ do_sea,		SIGBUS,  0,		"synchronous external abort"	},
 	{ do_bad,		SIGBUS,  0,		"unknown 17"			},
 	{ do_bad,		SIGBUS,  0,		"unknown 18"			},
 	{ do_bad,		SIGBUS,  0,		"unknown 19"			},
-	{ do_bad,		SIGBUS,  0,		"synchronous external abort (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous external abort (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous external abort (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous external abort (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous parity error"	},
+	{ do_sea,		SIGBUS,  0,		"level 0 (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"level 1 (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"level 2 (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"level 3 (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"synchronous parity or ECC error" },
 	{ do_bad,		SIGBUS,  0,		"unknown 25"			},
 	{ do_bad,		SIGBUS,  0,		"unknown 26"			},
 	{ do_bad,		SIGBUS,  0,		"unknown 27"			},
-	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk)" },
-	{ do_bad,		SIGBUS,  0,		"synchronous parity error (translation table walk)" },
+	{ do_sea,		SIGBUS,  0,		"level 0 synchronous parity error (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"level 1 synchronous parity error (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"level 2 synchronous parity error (translation table walk)"	},
+	{ do_sea,		SIGBUS,  0,		"level 3 synchronous parity error (translation table walk)"	},
 	{ do_bad,		SIGBUS,  0,		"unknown 32"			},
 	{ do_alignment_fault,	SIGBUS,  BUS_ADRALN,	"alignment fault"		},
 	{ do_bad,		SIGBUS,  0,		"unknown 34"			},
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related

* [PATCH V15 04/11] efi: parse ARM processor error
From: Tyler Baicar @ 2017-04-18 23:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1492556723-9189-1-git-send-email-tbaicar@codeaurora.org>

Add support for ARM Common Platform Error Record (CPER).
UEFI 2.6 specification adds support for ARM specific
processor error information to be reported as part of the
CPER records. This provides more detail on for processor error logs.

Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org>
CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org>
Reviewed-by: James Morse <james.morse@arm.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 drivers/firmware/efi/cper.c | 135 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/cper.h        |  54 ++++++++++++++++++
 2 files changed, 189 insertions(+)

diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 46585f9..f959185 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -110,12 +110,15 @@ void cper_print_bits(const char *pfx, unsigned int bits,
 static const char * const proc_type_strs[] = {
 	"IA32/X64",
 	"IA64",
+	"ARM",
 };
 
 static const char * const proc_isa_strs[] = {
 	"IA32",
 	"IA64",
 	"X64",
+	"ARM A32/T32",
+	"ARM A64",
 };
 
 static const char * const proc_error_type_strs[] = {
@@ -184,6 +187,128 @@ static void cper_print_proc_generic(const char *pfx,
 		printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
 }
 
+#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+static const char * const arm_reg_ctx_strs[] = {
+	"AArch32 general purpose registers",
+	"AArch32 EL1 context registers",
+	"AArch32 EL2 context registers",
+	"AArch32 secure context registers",
+	"AArch64 general purpose registers",
+	"AArch64 EL1 context registers",
+	"AArch64 EL2 context registers",
+	"AArch64 EL3 context registers",
+	"Misc. system register structure",
+};
+
+static void cper_print_proc_arm(const char *pfx,
+				const struct cper_sec_proc_arm *proc)
+{
+	int i, len, max_ctx_type;
+	struct cper_arm_err_info *err_info;
+	struct cper_arm_ctx_info *ctx_info;
+	char newpfx[64];
+
+	printk("%ssection length: %d\n", pfx, proc->section_length);
+	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
+
+	len = proc->section_length - (sizeof(*proc) +
+		proc->err_info_num * (sizeof(*err_info)));
+	if (len < 0) {
+		printk("%ssection length is too small\n", pfx);
+		printk("%sfirmware-generated error record is incorrect\n", pfx);
+		printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
+		return;
+	}
+
+	if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
+		printk("%sMPIDR: 0x%016llx\n", pfx, proc->mpidr);
+	if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
+		printk("%serror affinity level: %d\n", pfx,
+			proc->affinity_level);
+	if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
+		printk("%srunning state: 0x%x\n", pfx, proc->running_state);
+		printk("%sPSCI state: %d\n", pfx, proc->psci_state);
+	}
+
+	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
+
+	err_info = (struct cper_arm_err_info *)(proc + 1);
+	for (i = 0; i < proc->err_info_num; i++) {
+		printk("%sError info structure %d:\n", pfx, i);
+		printk("%sversion:%d\n", newpfx, err_info->version);
+		printk("%slength:%d\n", newpfx, err_info->length);
+		if (err_info->validation_bits &
+		    CPER_ARM_INFO_VALID_MULTI_ERR) {
+			if (err_info->multiple_error == 0)
+				printk("%ssingle error\n", newpfx);
+			else if (err_info->multiple_error == 1)
+				printk("%smultiple errors\n", newpfx);
+			else
+				printk("%smultiple errors count:%u\n",
+				newpfx, err_info->multiple_error);
+		}
+		if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
+			if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
+				printk("%sfirst error captured\n", newpfx);
+			if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
+				printk("%slast error captured\n", newpfx);
+			if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
+				printk("%spropagated error captured\n",
+				       newpfx);
+			if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
+				printk("%soverflow occurred, error info is incomplete\n",
+				       newpfx);
+		}
+		printk("%serror_type: %d, %s\n", newpfx, err_info->type,
+			err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
+			proc_error_type_strs[err_info->type] : "unknown");
+		if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO)
+			printk("%serror_info: 0x%016llx\n", newpfx,
+			       err_info->error_info);
+		if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
+			printk("%svirtual fault address: 0x%016llx\n",
+				newpfx, err_info->virt_fault_addr);
+		if (err_info->validation_bits &
+		    CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
+			printk("%sphysical fault address: 0x%016llx\n",
+				newpfx, err_info->physical_fault_addr);
+		err_info += 1;
+	}
+	ctx_info = (struct cper_arm_ctx_info *)err_info;
+	max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
+	for (i = 0; i < proc->context_info_num; i++) {
+		int size = sizeof(*ctx_info) + ctx_info->size;
+
+		printk("%sContext info structure %d:\n", pfx, i);
+		if (len < size) {
+			printk("%ssection length is too small\n", newpfx);
+			printk("%sfirmware-generated error record is incorrect\n", pfx);
+			return;
+		}
+		if (ctx_info->type > max_ctx_type) {
+			printk("%sInvalid context type: %d\n", newpfx,
+							ctx_info->type);
+			printk("%sMax context type: %d\n", newpfx,
+							max_ctx_type);
+			return;
+		}
+		printk("%sregister context type %d: %s\n", newpfx,
+			ctx_info->type, arm_reg_ctx_strs[ctx_info->type]);
+		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
+				(ctx_info + 1), ctx_info->size, 0);
+		len -= size;
+		ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
+	}
+
+	if (len > 0) {
+		printk("%sVendor specific error info has %u bytes:\n", pfx,
+		       len);
+		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
+				len, true);
+	}
+}
+#endif
+
 static const char * const mem_err_type_strs[] = {
 	"unknown",
 	"no error",
@@ -461,6 +586,16 @@ static void cper_estatus_timestamp(const char *pfx,
 			cper_print_pcie(newpfx, pcie, gdata);
 		else
 			goto err_section_too_small;
+	} else if ((IS_ENABLED(CONFIG_ARM64) || IS_ENABLED(CONFIG_ARM)) &&
+		   !uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
+		struct cper_sec_proc_arm *arm_err;
+
+		arm_err = acpi_hest_get_payload(gdata);
+		printk("%ssection_type: ARM processor error\n", newpfx);
+		if (gdata->error_data_length >= sizeof(*arm_err))
+			cper_print_proc_arm(newpfx, arm_err);
+		else
+			goto err_section_too_small;
 	} else
 		printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);
 
diff --git a/include/linux/cper.h b/include/linux/cper.h
index dcacb1a..85450f3 100644
--- a/include/linux/cper.h
+++ b/include/linux/cper.h
@@ -180,6 +180,10 @@ enum {
 #define CPER_SEC_PROC_IPF						\
 	UUID_LE(0xE429FAF1, 0x3CB7, 0x11D4, 0x0B, 0xCA, 0x07, 0x00,	\
 		0x80, 0xC7, 0x3C, 0x88, 0x81)
+/* Processor Specific: ARM */
+#define CPER_SEC_PROC_ARM						\
+	UUID_LE(0xE19E3D16, 0xBC11, 0x11E4, 0x9C, 0xAA, 0xC2, 0x05,	\
+		0x1D, 0x5D, 0x46, 0xB0)
 /* Platform Memory */
 #define CPER_SEC_PLATFORM_MEM						\
 	UUID_LE(0xA5BC1114, 0x6F64, 0x4EDE, 0xB8, 0x63, 0x3E, 0x83,	\
@@ -255,6 +259,22 @@ enum {
 
 #define CPER_PCIE_SLOT_SHIFT			3
 
+#define CPER_ARM_VALID_MPIDR			0x00000001
+#define CPER_ARM_VALID_AFFINITY_LEVEL		0x00000002
+#define CPER_ARM_VALID_RUNNING_STATE		0x00000004
+#define CPER_ARM_VALID_VENDOR_INFO		0x00000008
+
+#define CPER_ARM_INFO_VALID_MULTI_ERR		0x0001
+#define CPER_ARM_INFO_VALID_FLAGS		0x0002
+#define CPER_ARM_INFO_VALID_ERR_INFO		0x0004
+#define CPER_ARM_INFO_VALID_VIRT_ADDR		0x0008
+#define CPER_ARM_INFO_VALID_PHYSICAL_ADDR	0x0010
+
+#define CPER_ARM_INFO_FLAGS_FIRST		0x0001
+#define CPER_ARM_INFO_FLAGS_LAST		0x0002
+#define CPER_ARM_INFO_FLAGS_PROPAGATED		0x0004
+#define CPER_ARM_INFO_FLAGS_OVERFLOW		0x0008
+
 /*
  * All tables and structs must be byte-packed to match CPER
  * specification, since the tables are provided by the system BIOS
@@ -340,6 +360,40 @@ struct cper_ia_proc_ctx {
 	__u64	mm_reg_addr;
 };
 
+/* ARM Processor Error Section */
+struct cper_sec_proc_arm {
+	__u32	validation_bits;
+	__u16	err_info_num; /* Number of Processor Error Info */
+	__u16	context_info_num; /* Number of Processor Context Info Records*/
+	__u32	section_length;
+	__u8	affinity_level;
+	__u8	reserved[3];	/* must be zero */
+	__u64	mpidr;
+	__u64	midr;
+	__u32	running_state; /* Bit 0 set - Processor running. PSCI = 0 */
+	__u32	psci_state;
+};
+
+/* ARM Processor Error Information Structure */
+struct cper_arm_err_info {
+	__u8	version;
+	__u8	length;
+	__u16	validation_bits;
+	__u8	type;
+	__u16	multiple_error;
+	__u8	flags;
+	__u64	error_info;
+	__u64	virt_fault_addr;
+	__u64	physical_fault_addr;
+};
+
+/* ARM Processor Context Information Structure */
+struct cper_arm_ctx_info {
+	__u16	version;
+	__u16	type;
+	__u32	size;
+};
+
 /* Old Memory Error Section UEFI 2.1, 2.2 */
 struct cper_sec_mem_err_old {
 	__u64	validation_bits;
-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

^ permalink raw reply related


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