Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v3 2/2] drm/panel: Add support for Chunghwa CLAA070WP03XG panel
From: Randy Li @ 2016-09-19 19:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474311771-23321-1-git-send-email-ayaka@soulik.info>

The Chunghwa CLAA070WP03XG is a 7" 1280x800 panel, which can be
supported by the simple panel driver.

Signed-off-by: Randy Li <ayaka@soulik.info>
---
 .../display/panel/chunghwa,claa070wp03xg.txt       |  7 ++++++
 drivers/gpu/drm/panel/panel-simple.c               | 27 ++++++++++++++++++++++
 2 files changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt

diff --git a/Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt b/Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt
new file mode 100644
index 0000000..dd22685
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt
@@ -0,0 +1,7 @@
+Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "chunghwa,claa070wp03xg"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index f178998..3204e6b 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -583,6 +583,30 @@ static const struct panel_desc avic_tm070ddh03 = {
 	},
 };
 
+static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
+	.clock = 66770,
+	.hdisplay = 800,
+	.hsync_start = 800 + 49,
+	.hsync_end = 800 + 49 + 33,
+	.htotal = 800 + 49 + 33 + 17,
+	.vdisplay = 1280,
+	.vsync_start = 1280 + 1,
+	.vsync_end = 1280 + 1 + 7,
+	.vtotal = 1280 + 1 + 7 + 15,
+	.vrefresh = 60,
+	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc chunghwa_claa070wp03xg = {
+	.modes = &chunghwa_claa070wp03xg_mode,
+	.num_modes = 1,
+	.bpc = 6,
+	.size = {
+		.width = 94,
+		.height = 150,
+	},
+};
+
 static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
 	.clock = 72070,
 	.hdisplay = 1366,
@@ -1544,6 +1568,9 @@ static const struct of_device_id platform_of_match[] = {
 		.compatible = "avic,tm070ddh03",
 		.data = &avic_tm070ddh03,
 	}, {
+		.compatible = "chunghwa,claa070wp03xg",
+		.data = &chunghwa_claa070wp03xg,
+	}, {
 		.compatible = "chunghwa,claa101wa01a",
 		.data = &chunghwa_claa101wa01a
 	}, {
-- 
2.7.4

^ permalink raw reply related

* [RFC PATCH v3 1/2] ARM: dts: samsung: add rga-lvds panel in itop elite
From: Randy Li @ 2016-09-19 19:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474311771-23321-1-git-send-email-ayaka@soulik.info>

It is actually a lvds panel connected through a rga-lvds bridge.
The touchscreen is communicated with i2c bus but the driver is not
support now.

Signed-off-by: Randy Li <ayaka@soulik.info>
---
 arch/arm/boot/dts/exynos4412-itop-elite.dts | 54 +++++++++++++++++++++++++++--
 1 file changed, 52 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/exynos4412-itop-elite.dts b/arch/arm/boot/dts/exynos4412-itop-elite.dts
index b08705e..5153522 100644
--- a/arch/arm/boot/dts/exynos4412-itop-elite.dts
+++ b/arch/arm/boot/dts/exynos4412-itop-elite.dts
@@ -138,6 +138,36 @@
 		assigned-clocks = <&clock CLK_MOUT_CAM0>;
 		assigned-clock-parents = <&clock CLK_XUSBXTI>;
 	};
+
+	vcc_sys_lcd: sys-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpl0 4 GPIO_ACTIVE_HIGH>;
+	};
+
+	panel: panel at 0 {
+		compatible = "chunghwa,claa070wp03xg";
+
+		power-supply = <&vcc_sys_lcd>;
+		enable-gpios = <&gpl0 2 GPIO_ACTIVE_HIGH>;
+		backlight = <&bl>;
+
+		port {
+			lcd_ep: endpoint {
+				remote-endpoint = <&rga_lvds>;
+			};
+		};
+	};
+
+	bl: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm 1 5000000 PWM_POLARITY_INVERTED>;
+		brightness-levels = <0 5 12 16 32 64 128 255>;
+		default-brightness-level = <5>;
+		power-supply = <&vcc_sys_lcd>;
+	};
 };
 
 &adc {
@@ -171,11 +201,31 @@
 	assigned-clock-rates = <0>, <176000000>;
 };
 
+&fimd {
+	pinctrl-0 = <&lcd_clk &lcd_data24>;
+	pinctrl-names = "default";
+	status = "okay";
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		port at 3 {
+			reg = <3>;
+			rga_lvds: endpoint {
+				remote-endpoint = <&lcd_ep>;
+			};
+		};
+	};
+};
+
 &hsotg {
 	dr_mode = "peripheral";
 	status = "okay";
 };
 
+&i2c_3 {
+	status = "okay";
+};
+
 &i2c_4 {
 	samsung,i2c-sda-delay = <100>;
 	samsung,i2c-slave-addr = <0x10>;
@@ -215,9 +265,9 @@
 
 &pwm {
 	status = "okay";
-	pinctrl-0 = <&pwm0_out>;
+	pinctrl-0 = <&pwm0_out &pwm1_out>;
 	pinctrl-names = "default";
-	samsung,pwm-outputs = <0>;
+	samsung,pwm-outputs = <0>, <1>;
 };
 
 &sdhci_2 {
-- 
2.7.4

^ permalink raw reply related

* [RFC PATCH v3 0/2] adding panel claa070wp03xg support for exynos
From: Randy Li @ 2016-09-19 19:02 UTC (permalink / raw)
  To: linux-arm-kernel

The timings issue is still here, this version is just some modifications
in dts file.

Randy Li (2):
  ARM: dts: samsung: add rga-lvds panel in itop elite
  drm/panel: Add support for Chunghwa CLAA070WP03XG panel

 .../display/panel/chunghwa,claa070wp03xg.txt       |  7 +++
 arch/arm/boot/dts/exynos4412-itop-elite.dts        | 54 +++++++++++++++++++++-
 drivers/gpu/drm/panel/panel-simple.c               | 27 +++++++++++
 3 files changed, 86 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/panel/chunghwa,claa070wp03xg.txt

-- 
2.7.4

^ permalink raw reply

* [PATCH v3] ASoC: exynos: organize the asoc audio into a menu
From: Randy Li @ 2016-09-19 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

It is simple sound card time, we could assign different codec
to a interface without making a specific driver for it. The SPDIF
and I2S interface for Samsung would be possible used by
simple-sound-card, but not sure about the PCM.

Those S3C time entries are left alone as I don't think any new board
would need them.

Signed-off-by: Randy Li <ayaka@soulik.info>
---
 sound/soc/samsung/Kconfig | 57 ++++++++++++++++++++++++-----------------------
 1 file changed, 29 insertions(+), 28 deletions(-)

diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 7b722b0..f6023b4 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,12 +1,14 @@
-config SND_SOC_SAMSUNG
+menuconfig SND_SOC_SAMSUNG
 	tristate "ASoC support for Samsung"
 	depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
 	select SND_SOC_GENERIC_DMAENGINE_PCM
-	help
+	---help---
 	  Say Y or M if you want to add support for codecs attached to
 	  the Samsung SoCs' Audio interfaces. You will also need to
 	  select the audio interfaces to support below.
 
+if SND_SOC_SAMSUNG
+
 config SND_S3C24XX_I2S
 	tristate
 
@@ -18,22 +20,22 @@ config SND_S3C2412_SOC_I2S
 	select SND_S3C_I2SV2_SOC
 
 config SND_SAMSUNG_PCM
-	tristate
+	tristate "Samsung PCM interface support"
 
 config SND_SAMSUNG_AC97
 	tristate
 	select SND_SOC_AC97_BUS
 
 config SND_SAMSUNG_SPDIF
-	tristate
+	tristate "Samsung SPDIF transmitter support"
 	select SND_SOC_SPDIF
 
 config SND_SAMSUNG_I2S
-	tristate
+	tristate "Samsung I2S interface support"
 
 config SND_SOC_SAMSUNG_NEO1973_WM8753
 	tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
-	depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
+	depends on MACH_NEO1973_GTA02
 	select SND_S3C24XX_I2S
 	select SND_SOC_WM8753
 	select SND_SOC_BT_SCO
@@ -43,7 +45,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
 
 config SND_SOC_SAMSUNG_JIVE_WM8750
 	tristate "SoC I2S Audio support for Jive"
-	depends on SND_SOC_SAMSUNG && MACH_JIVE && I2C
+	depends on MACH_JIVE && I2C
 	select SND_SOC_WM8750
 	select SND_S3C2412_SOC_I2S
 	help
@@ -51,7 +53,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
 
 config SND_SOC_SAMSUNG_SMDK_WM8580
 	tristate "SoC I2S Audio support for WM8580 on SMDK"
-	depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
+	depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110
 	depends on I2C
 	select SND_SOC_WM8580
 	select SND_SAMSUNG_I2S
@@ -60,7 +62,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8580
 
 config SND_SOC_SAMSUNG_SMDK_WM8994
 	tristate "SoC I2S Audio support for WM8994 on SMDK"
-	depends on SND_SOC_SAMSUNG
 	depends on I2C=y
 	select MFD_WM8994
 	select SND_SOC_WM8994
@@ -70,7 +71,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
 
 config SND_SOC_SAMSUNG_SMDK2443_WM9710
 	tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
-	depends on SND_SOC_SAMSUNG && MACH_SMDK2443
+	depends on MACH_SMDK2443
 	select AC97_BUS
 	select SND_SOC_AC97_CODEC
 	select SND_SAMSUNG_AC97
@@ -80,7 +81,7 @@ config SND_SOC_SAMSUNG_SMDK2443_WM9710
 
 config SND_SOC_SAMSUNG_LN2440SBC_ALC650
 	tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+	depends on ARCH_S3C24XX
 	select AC97_BUS
 	select SND_SOC_AC97_CODEC
 	select SND_SAMSUNG_AC97
@@ -90,7 +91,7 @@ config SND_SOC_SAMSUNG_LN2440SBC_ALC650
 
 config SND_SOC_SAMSUNG_S3C24XX_UDA134X
 	tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
+	depends on ARCH_S3C24XX
 	select SND_S3C24XX_I2S
 	select SND_SOC_L3
 	select SND_SOC_UDA134X
@@ -102,21 +103,21 @@ config SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
 	tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
+	depends on ARCH_S3C24XX && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_TLV320AIC23_I2C
 	select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_SIMTEC_HERMES
 	tristate "SoC I2S Audio support for Simtec Hermes board"
-	depends on SND_SOC_SAMSUNG && ARCH_S3C24XX && I2C
+	depends on ARCH_S3C24XX && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_SAMSUNG_SIMTEC
 
 config SND_SOC_SAMSUNG_H1940_UDA1380
 	tristate "Audio support for the HP iPAQ H1940"
-	depends on SND_SOC_SAMSUNG && ARCH_H1940 && I2C
+	depends on ARCH_H1940 && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_UDA1380
 	help
@@ -124,7 +125,7 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
 
 config SND_SOC_SAMSUNG_RX1950_UDA1380
 	tristate "Audio support for the HP iPAQ RX1950"
-	depends on SND_SOC_SAMSUNG && MACH_RX1950 && I2C
+	depends on MACH_RX1950 && I2C
 	select SND_S3C24XX_I2S
 	select SND_SOC_UDA1380
 	help
@@ -132,7 +133,7 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
 
 config SND_SOC_SAMSUNG_SMDK_WM9713
 	tristate "SoC AC97 Audio support for SMDK with WM9713"
-	depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
+	depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110
 	select SND_SOC_WM9713
 	select SND_SAMSUNG_AC97
 	help
@@ -140,20 +141,19 @@ config SND_SOC_SAMSUNG_SMDK_WM9713
 
 config SND_SOC_SMARTQ
 	tristate "SoC I2S Audio support for SmartQ board"
-	depends on SND_SOC_SAMSUNG && MACH_SMARTQ && I2C
+	depends on MACH_SMARTQ && I2C
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8750
 
 config SND_SOC_SAMSUNG_SMDK_SPDIF
 	tristate "SoC S/PDIF Audio support for SMDK"
-	depends on SND_SOC_SAMSUNG
 	select SND_SAMSUNG_SPDIF
 	help
 	  Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
 
 config SND_SOC_SMDK_WM8580_PCM
 	tristate "SoC PCM Audio support for WM8580 on SMDK"
-	depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110)
+	depends on MACH_SMDKV210 || MACH_SMDKC110
 	depends on I2C
 	select SND_SOC_WM8580
 	select SND_SAMSUNG_PCM
@@ -162,7 +162,6 @@ config SND_SOC_SMDK_WM8580_PCM
 
 config SND_SOC_SMDK_WM8994_PCM
 	tristate "SoC PCM Audio support for WM8994 on SMDK"
-	depends on SND_SOC_SAMSUNG
 	depends on I2C=y
 	select MFD_WM8994
 	select SND_SOC_WM8994
@@ -172,7 +171,7 @@ config SND_SOC_SMDK_WM8994_PCM
 
 config SND_SOC_SPEYSIDE
 	tristate "Audio support for Wolfson Speyside"
-	depends on SND_SOC_SAMSUNG && I2C && SPI_MASTER
+	depends on I2C && SPI_MASTER
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8996
@@ -182,14 +181,14 @@ config SND_SOC_SPEYSIDE
 
 config SND_SOC_TOBERMORY
 	tristate "Audio support for Wolfson Tobermory"
-	depends on SND_SOC_SAMSUNG && INPUT && I2C
+	depends on INPUT && I2C
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM8962
 
 config SND_SOC_BELLS
 	tristate "Audio support for Wolfson Bells"
-	depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER
+	depends on MFD_ARIZONA && I2C && SPI_MASTER
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM5102
@@ -200,7 +199,7 @@ config SND_SOC_BELLS
 
 config SND_SOC_LOWLAND
 	tristate "Audio support for Wolfson Lowland"
-	depends on SND_SOC_SAMSUNG && I2C
+	depends on I2C
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select SND_SOC_WM5100
@@ -208,7 +207,7 @@ config SND_SOC_LOWLAND
 
 config SND_SOC_LITTLEMILL
 	tristate "Audio support for Wolfson Littlemill"
-	depends on SND_SOC_SAMSUNG && I2C
+	depends on I2C
 	depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST
 	select SND_SAMSUNG_I2S
 	select MFD_WM8994
@@ -216,7 +215,7 @@ config SND_SOC_LITTLEMILL
 
 config SND_SOC_SNOW
 	tristate "Audio support for Google Snow boards"
-	depends on SND_SOC_SAMSUNG && I2C
+	depends on I2C
 	select SND_SOC_MAX98090
 	select SND_SOC_MAX98095
 	select SND_SAMSUNG_I2S
@@ -226,6 +225,8 @@ config SND_SOC_SNOW
 
 config SND_SOC_ARNDALE_RT5631_ALC5631
         tristate "Audio support for RT5631(ALC5631) on Arndale Board"
-        depends on SND_SOC_SAMSUNG && I2C
+        depends on I2C
         select SND_SAMSUNG_I2S
         select SND_SOC_RT5631
+
+endif #SND_SOC_SAMSUNG
-- 
2.7.4

^ permalink raw reply related

* [PATCH] arm64, numa: Add cpu_to_node() implementation.
From: David Daney @ 2016-09-19 18:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: David Daney <david.daney@cavium.com>

The wq_numa_init() function makes a private CPU to node map by calling
cpu_to_node() early in the boot process, before the non-boot CPUs are
brought online.  Since the default implementation of cpu_to_node()
returns zero for CPUs that have never been brought online, the
workqueue system's view is that *all* CPUs are on node zero.

When the unbound workqueue for a non-zero node is created, the
tsk_cpus_allowed() for the worker threads is the empty set because
there are, in the view of the workqueue system, no CPUs on non-zero
nodes.  The code in try_to_wake_up() using this empty cpumask ends up
using the cpumask empty set value of NR_CPUS as an index into the
per-CPU area pointer array, and gets garbage as it is one past the end
of the array.  This results in:

[    0.881970] Unable to handle kernel paging request at virtual address fffffb1008b926a4
[    1.970095] pgd = fffffc00094b0000
[    1.973530] [fffffb1008b926a4] *pgd=0000000000000000, *pud=0000000000000000, *pmd=0000000000000000
[    1.982610] Internal error: Oops: 96000004 [#1] SMP
[    1.987541] Modules linked in:
[    1.990631] CPU: 48 PID: 295 Comm: cpuhp/48 Tainted: G        W       4.8.0-rc6-preempt-vol+ #9
[    1.999435] Hardware name: Cavium ThunderX CN88XX board (DT)
[    2.005159] task: fffffe0fe89cc300 task.stack: fffffe0fe8b8c000
[    2.011158] PC is at try_to_wake_up+0x194/0x34c
[    2.015737] LR is at try_to_wake_up+0x150/0x34c
[    2.020318] pc : [<fffffc00080e7468>] lr : [<fffffc00080e7424>] pstate: 600000c5
[    2.027803] sp : fffffe0fe8b8fb10
[    2.031149] x29: fffffe0fe8b8fb10 x28: 0000000000000000
[    2.036522] x27: fffffc0008c63bc8 x26: 0000000000001000
[    2.041896] x25: fffffc0008c63c80 x24: fffffc0008bfb200
[    2.047270] x23: 00000000000000c0 x22: 0000000000000004
[    2.052642] x21: fffffe0fe89d25bc x20: 0000000000001000
[    2.058014] x19: fffffe0fe89d1d00 x18: 0000000000000000
[    2.063386] x17: 0000000000000000 x16: 0000000000000000
[    2.068760] x15: 0000000000000018 x14: 0000000000000000
[    2.074133] x13: 0000000000000000 x12: 0000000000000000
[    2.079505] x11: 0000000000000000 x10: 0000000000000000
[    2.084879] x9 : 0000000000000000 x8 : 0000000000000000
[    2.090251] x7 : 0000000000000040 x6 : 0000000000000000
[    2.095621] x5 : ffffffffffffffff x4 : 0000000000000000
[    2.100991] x3 : 0000000000000000 x2 : 0000000000000000
[    2.106364] x1 : fffffc0008be4c24 x0 : ffffff0ffffada80
[    2.111737]
[    2.113236] Process cpuhp/48 (pid: 295, stack limit = 0xfffffe0fe8b8c020)
[    2.120102] Stack: (0xfffffe0fe8b8fb10 to 0xfffffe0fe8b90000)
[    2.125914] fb00:                                   fffffe0fe8b8fb80 fffffc00080e7648
.
.
.
[    2.442859] Call trace:
[    2.445327] Exception stack(0xfffffe0fe8b8f940 to 0xfffffe0fe8b8fa70)
[    2.451843] f940: fffffe0fe89d1d00 0000040000000000 fffffe0fe8b8fb10 fffffc00080e7468
[    2.459767] f960: fffffe0fe8b8f980 fffffc00080e4958 ffffff0ff91ab200 fffffc00080e4b64
[    2.467690] f980: fffffe0fe8b8f9d0 fffffc00080e515c fffffe0fe8b8fa80 0000000000000000
[    2.475614] f9a0: fffffe0fe8b8f9d0 fffffc00080e58e4 fffffe0fe8b8fa80 0000000000000000
[    2.483540] f9c0: fffffe0fe8d10000 0000000000000040 fffffe0fe8b8fa50 fffffc00080e5ac4
[    2.491465] f9e0: ffffff0ffffada80 fffffc0008be4c24 0000000000000000 0000000000000000
[    2.499387] fa00: 0000000000000000 ffffffffffffffff 0000000000000000 0000000000000040
[    2.507309] fa20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[    2.515233] fa40: 0000000000000000 0000000000000000 0000000000000000 0000000000000018
[    2.523156] fa60: 0000000000000000 0000000000000000
[    2.528089] [<fffffc00080e7468>] try_to_wake_up+0x194/0x34c
[    2.533723] [<fffffc00080e7648>] wake_up_process+0x28/0x34
[    2.539275] [<fffffc00080d3764>] create_worker+0x110/0x19c
[    2.544824] [<fffffc00080d69dc>] alloc_unbound_pwq+0x3cc/0x4b0
[    2.550724] [<fffffc00080d6bcc>] wq_update_unbound_numa+0x10c/0x1e4
[    2.557066] [<fffffc00080d7d78>] workqueue_online_cpu+0x220/0x28c
[    2.563234] [<fffffc00080bd288>] cpuhp_invoke_callback+0x6c/0x168
[    2.569398] [<fffffc00080bdf74>] cpuhp_up_callbacks+0x44/0xe4
[    2.575210] [<fffffc00080be194>] cpuhp_thread_fun+0x13c/0x148
[    2.581027] [<fffffc00080dfbac>] smpboot_thread_fn+0x19c/0x1a8
[    2.586929] [<fffffc00080dbd64>] kthread+0xdc/0xf0
[    2.591776] [<fffffc0008083380>] ret_from_fork+0x10/0x50
[    2.597147] Code: b00057e1 91304021 91005021 b8626822 (b8606821)
[    2.603464] ---[ end trace 58c0cd36b88802bc ]---
[    2.608138] Kernel panic - not syncing: Fatal exception

Fix by supplying a cpu_to_node() implementation that returns correct
node mappings.

Cc: <stable@vger.kernel.org> # 4.7.x-
Signed-off-by: David Daney <david.daney@cavium.com>

---
 arch/arm64/include/asm/topology.h |  3 +++
 arch/arm64/mm/numa.c              | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h
index 8b57339..8d935447 100644
--- a/arch/arm64/include/asm/topology.h
+++ b/arch/arm64/include/asm/topology.h
@@ -30,6 +30,9 @@ int pcibus_to_node(struct pci_bus *bus);
 				 cpu_all_mask :				\
 				 cpumask_of_node(pcibus_to_node(bus)))
 
+int cpu_to_node(int cpu);
+#define cpu_to_node cpu_to_node
+
 #endif /* CONFIG_NUMA */
 
 #include <asm-generic/topology.h>
diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c
index 5bb15ea..e76281b 100644
--- a/arch/arm64/mm/numa.c
+++ b/arch/arm64/mm/numa.c
@@ -130,6 +130,24 @@ void __init early_map_cpu_to_node(unsigned int cpu, int nid)
 	cpu_to_node_map[cpu] = nid;
 }
 
+int cpu_to_node(int cpu)
+{
+	int nid;
+
+	/*
+	 * Return 0 for unknown mapping so that we report something
+	 * sensible if firmware doesn't supply a proper mapping.
+	 */
+	if (cpu < 0 || cpu >= NR_CPUS)
+		return 0;
+
+	nid = cpu_to_node_map[cpu];
+	if (nid == NUMA_NO_NODE)
+		nid = 0;
+	return nid;
+}
+EXPORT_SYMBOL(cpu_to_node);
+
 /**
  * numa_add_memblk - Set node id to memblk
  * @nid: NUMA node ID of the new memblk
-- 
1.8.3.1

^ permalink raw reply related

* [RFC] arm64: Ensure proper addressing for ldnp/stnp
From: bdegraaf at codeaurora.org @ 2016-09-19 18:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50fcc549-d785-6332-83bd-292a4f44e8d4@redhat.com>

On 2016-09-19 14:28, Laura Abbott wrote:
> On 09/19/2016 10:36 AM, Brent DeGraaf wrote:
>> According to section 6.3.8 of the ARM Programmer's Guide, non-temporal
>> loads and stores do not verify that address dependency is met between 
>> a
>> load of an address to a register and a subsequent non-temporal load or
>> store using that address on the executing PE. Therefore, context 
>> switch
>> code and subroutine calls that use non-temporally accessed addresses 
>> as
>> parameters that might depend on a load of an address into an argument
>> register must ensure that ordering requirements are met by introducing
>> a barrier prior to the successive non-temporal access.  Add 
>> appropriate
>> barriers whereever this specific situation comes into play.
>> 
> 
> Was this found by code inspection or is there a (public) exciting test
> case to observe this behavior?
> 
> Thanks,
> Laura
> 

Code inspection only.

Brent

^ permalink raw reply

* [PATCH] arm: dts: fix rk3066a based boards vdd_log voltage initialization
From: Boris Brezillon @ 2016-09-19 18:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAD=FV=U_BQez2eCqm7mX9kj0dcEsnBKiFWcLAhXXJD+yTZhACw@mail.gmail.com>

On Mon, 19 Sep 2016 11:12:12 -0700
Doug Anderson <dianders@chromium.org> wrote:

> Hi,
> 
> On Mon, Sep 19, 2016 at 11:06 AM, Boris Brezillon
> <boris.brezillon@free-electrons.com> wrote:
> > On Mon, 19 Sep 2016 10:52:51 -0700
> > Doug Anderson <dianders@chromium.org> wrote:
> >  
> >> Hi,
> >>
> >> On Mon, Sep 19, 2016 at 10:48 AM, Boris Brezillon
> >> <boris.brezillon@free-electrons.com> wrote:  
> >> > The PWM chip has always claimed the pins and muxed them to the PWM IP.
> >> > So, this means it's broken from the beginning, and my patch is only
> >> > uncovering the problem (unless the pins stay configured as input until
> >> > the PWM is enabled, which I'm not sure is the case).  
> >>
> >> Such a solution is achievable with the pinctrl APIs pretty easily.
> >> You might not be able to use the automatic "init" state but you can do
> >> something similar and switch to an "active" state once the PWM is
> >> actually turned on the first time.  
> >
> > But is it really the case here (I don't see any code requesting a
> > specific pinmux depending on the PWM state)?  
> 
> It is not happening right now as far as I know.  ...but that's a bug.

Okay.

> 
> > Anyway, we really need to handle this case, we should define the
> > typical voltage when the PWM is disabled. Same as what you suggested
> > with voltage-when-input, but with a different naming (since the concept
> > of pinmux is PWM hardware/driver specific).
> >
> >         voltage-when-pwm-disabled = <...>;  
> 
> Voltage when disabled and voltage when input are two different states.
> A disabled PWM will typically either drive high or low (depending on
> where it was when you turned it off).  Not all "disabled" states will
> mean that the pin is configured as an input.

Well, my point was that, from the regulator PoV, a PWM is either
enabled or disabled. The pinmux config when the PWM is disabled
depends on the PWM driver/hardware, and I don't think it's a good idea
to expose this information at the regulator level, hence the name
"voltage-when-pwm-disabled". Anyway, let's stop bikeshedding, no
matter the name, I think we both agree that a new DT property is needed
to handle this case :-).

^ permalink raw reply

* [RFC] arm64: Ensure proper addressing for ldnp/stnp
From: Laura Abbott @ 2016-09-19 18:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474306586-25118-1-git-send-email-bdegraaf@codeaurora.org>

On 09/19/2016 10:36 AM, Brent DeGraaf wrote:
> According to section 6.3.8 of the ARM Programmer's Guide, non-temporal
> loads and stores do not verify that address dependency is met between a
> load of an address to a register and a subsequent non-temporal load or
> store using that address on the executing PE. Therefore, context switch
> code and subroutine calls that use non-temporally accessed addresses as
> parameters that might depend on a load of an address into an argument
> register must ensure that ordering requirements are met by introducing
> a barrier prior to the successive non-temporal access.  Add appropriate
> barriers whereever this specific situation comes into play.
>

Was this found by code inspection or is there a (public) exciting test
case to observe this behavior?

Thanks,
Laura

> Signed-off-by: Brent DeGraaf <bdegraaf@codeaurora.org>
> ---
>  arch/arm64/kernel/entry.S  | 1 +
>  arch/arm64/lib/copy_page.S | 2 ++
>  2 files changed, 3 insertions(+)
>
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 441420c..982c4d3 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -679,6 +679,7 @@ ENTRY(cpu_switch_to)
>  	ldp	x27, x28, [x8], #16
>  	ldp	x29, x9, [x8], #16
>  	ldr	lr, [x8]
> +	dmb	nshld	// Existence of instructions with loose load-use dependencies (e.g. ldnp/stnp) make this barrier necessary
>  	mov	sp, x9
>  	and	x9, x9, #~(THREAD_SIZE - 1)
>  	msr	sp_el0, x9
> diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S
> index 4c1e700..21c6892 100644
> --- a/arch/arm64/lib/copy_page.S
> +++ b/arch/arm64/lib/copy_page.S
> @@ -47,6 +47,8 @@ alternative_endif
>  	ldp	x14, x15, [x1, #96]
>  	ldp	x16, x17, [x1, #112]
>
> +	dmb	nshld // In case x0 (for stnp) is dependent on a load
> +
>  	mov	x18, #(PAGE_SIZE - 128)
>  	add	x1, x1, #128
>  1:
>

^ permalink raw reply

* [RFC] arm64: Ensure proper addressing for ldnp/stnp
From: bdegraaf at codeaurora.org @ 2016-09-19 18:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <be5f5bfd-fd41-d202-cec9-0ca3fcad28db@arm.com>

On 2016-09-19 14:01, Robin Murphy wrote:
> On 19/09/16 18:36, Brent DeGraaf wrote:
>> According to section 6.3.8 of the ARM Programmer's Guide, non-temporal
>> loads and stores do not verify that address dependency is met between 
>> a
>> load of an address to a register and a subsequent non-temporal load or
>> store using that address on the executing PE. Therefore, context 
>> switch
>> code and subroutine calls that use non-temporally accessed addresses 
>> as
>> parameters that might depend on a load of an address into an argument
>> register must ensure that ordering requirements are met by introducing
>> a barrier prior to the successive non-temporal access.  Add 
>> appropriate
>> barriers whereever this specific situation comes into play.
>> 
>> Signed-off-by: Brent DeGraaf <bdegraaf@codeaurora.org>
>> ---
>>  arch/arm64/kernel/entry.S  | 1 +
>>  arch/arm64/lib/copy_page.S | 2 ++
>>  2 files changed, 3 insertions(+)
>> 
>> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
>> index 441420c..982c4d3 100644
>> --- a/arch/arm64/kernel/entry.S
>> +++ b/arch/arm64/kernel/entry.S
>> @@ -679,6 +679,7 @@ ENTRY(cpu_switch_to)
>>  	ldp	x27, x28, [x8], #16
>>  	ldp	x29, x9, [x8], #16
>>  	ldr	lr, [x8]
>> +	dmb	nshld	// Existence of instructions with loose load-use 
>> dependencies (e.g. ldnp/stnp) make this barrier necessary
>>  	mov	sp, x9
>>  	and	x9, x9, #~(THREAD_SIZE - 1)
>>  	msr	sp_el0, x9
>> diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S
>> index 4c1e700..21c6892 100644
>> --- a/arch/arm64/lib/copy_page.S
>> +++ b/arch/arm64/lib/copy_page.S
>> @@ -47,6 +47,8 @@ alternative_endif
>>  	ldp	x14, x15, [x1, #96]
>>  	ldp	x16, x17, [x1, #112]
>> 
>> +	dmb	nshld // In case x0 (for stnp) is dependent on a load
> 
> The ARMv8 ARM (B2.7.2 in issue j) says that when an address dependency
> exists between a load and a subsequent LDNP, *other* observers may
> observe those accesses in any order. How's that related to an STNP on
> the same CPU?
> 
> Robin.
> 
>> +
>>  	mov	x18, #(PAGE_SIZE - 128)
>>  	add	x1, x1, #128
>>  1:
>> 

Yes, I have seen the section in the ARM ARM about this. But the 
Programmer's Guide goes further, even providing a concrete example:

"Non-temporal loads and stores relax the memory ordering 
requirements...the LDNP instruction might
be observed before the preceding LDR instruction, which can result in 
reading from an unpredictable
address in X0.

For example:
LDR X0, [X3]
LDNP X2, X1, [X0]
To correct the above, you need an explicit load barrier:
LDR X0, [X3]
DMB NSHLD
LDNP X2, X1, [X0]"

Did the ARM ARM leave this out?  Or is the Programmer's Guide section 
incorrect?

Thanks for your comments,
Brent

^ permalink raw reply

* [PATCH v2 0/3] Armada 7k/8k CP110 system controller fixes
From: Marcin Wojtas @ 2016-09-19 18:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160919181549.GE7243@codeaurora.org>

Sure, thanks. I'll send it right away.

Best regards,
Marcin

2016-09-19 20:15 GMT+02:00 Stephen Boyd <sboyd@codeaurora.org>:
> On 09/19, Marcin Wojtas wrote:
>> Hi Stephen,
>>
>> Did you have any chance to take a look at v2? Do you have any remarks?
>>
>
> Hmm I don't have any of these patches in my queue. Probably
> because there was some bug in the second patch so I assumed it
> would go for another round. Please fix that bug and resend.
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v2 0/3] Armada 7k/8k CP110 system controller fixes
From: Stephen Boyd @ 2016-09-19 18:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPv3WKdoas6nJngFh2bLU0wvz2OZMga6G40UMPkfz9aunRawVw@mail.gmail.com>

On 09/19, Marcin Wojtas wrote:
> Hi Stephen,
> 
> Did you have any chance to take a look at v2? Do you have any remarks?
> 

Hmm I don't have any of these patches in my queue. Probably
because there was some bug in the second patch so I assumed it
would go for another round. Please fix that bug and resend.

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

^ permalink raw reply

* [PATCH] arm: dts: fix rk3066a based boards vdd_log voltage initialization
From: Doug Anderson @ 2016-09-19 18:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160919200627.3ca1aae4@bbrezillon>

Hi,

On Mon, Sep 19, 2016 at 11:06 AM, Boris Brezillon
<boris.brezillon@free-electrons.com> wrote:
> On Mon, 19 Sep 2016 10:52:51 -0700
> Doug Anderson <dianders@chromium.org> wrote:
>
>> Hi,
>>
>> On Mon, Sep 19, 2016 at 10:48 AM, Boris Brezillon
>> <boris.brezillon@free-electrons.com> wrote:
>> > The PWM chip has always claimed the pins and muxed them to the PWM IP.
>> > So, this means it's broken from the beginning, and my patch is only
>> > uncovering the problem (unless the pins stay configured as input until
>> > the PWM is enabled, which I'm not sure is the case).
>>
>> Such a solution is achievable with the pinctrl APIs pretty easily.
>> You might not be able to use the automatic "init" state but you can do
>> something similar and switch to an "active" state once the PWM is
>> actually turned on the first time.
>
> But is it really the case here (I don't see any code requesting a
> specific pinmux depending on the PWM state)?

It is not happening right now as far as I know.  ...but that's a bug.

> Anyway, we really need to handle this case, we should define the
> typical voltage when the PWM is disabled. Same as what you suggested
> with voltage-when-input, but with a different naming (since the concept
> of pinmux is PWM hardware/driver specific).
>
>         voltage-when-pwm-disabled = <...>;

Voltage when disabled and voltage when input are two different states.
A disabled PWM will typically either drive high or low (depending on
where it was when you turned it off).  Not all "disabled" states will
mean that the pin is configured as an input.

^ permalink raw reply

* [PATCH V6 3/5] PCI: thunder-pem: Allow to probe PEM-specific register range for ACPI case
From: Bjorn Helgaas @ 2016-09-19 18:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473449047-10499-4-git-send-email-tn@semihalf.com>

On Fri, Sep 09, 2016 at 09:24:05PM +0200, Tomasz Nowicki wrote:
> thunder-pem driver stands for being ACPI based PCI host controller.
> However, there is no standard way to describe its PEM-specific register
> ranges in ACPI tables. Thus we add thunder_pem_init() ACPI extension
> to obtain hardcoded addresses from static resource array.
> Although it is not pretty, it prevents from creating standard mechanism to
> handle similar cases in future.
> 
> Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
> ---
>  drivers/pci/host/pci-thunder-pem.c | 61 ++++++++++++++++++++++++++++++--------
>  1 file changed, 48 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c
> index 6abaf80..b048761 100644
> --- a/drivers/pci/host/pci-thunder-pem.c
> +++ b/drivers/pci/host/pci-thunder-pem.c
> @@ -18,6 +18,7 @@
>  #include <linux/init.h>
>  #include <linux/of_address.h>
>  #include <linux/of_pci.h>
> +#include <linux/pci-acpi.h>
>  #include <linux/pci-ecam.h>
>  #include <linux/platform_device.h>
>  
> @@ -284,6 +285,40 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn,
>  	return pci_generic_config_write(bus, devfn, where, size, val);
>  }
>  
> +#ifdef CONFIG_ACPI
> +static struct resource thunder_pem_reg_res[] = {
> +	[4] = DEFINE_RES_MEM(0x87e0c0000000UL, SZ_16M),
> +	[5] = DEFINE_RES_MEM(0x87e0c1000000UL, SZ_16M),
> +	[6] = DEFINE_RES_MEM(0x87e0c2000000UL, SZ_16M),
> +	[7] = DEFINE_RES_MEM(0x87e0c3000000UL, SZ_16M),
> +	[8] = DEFINE_RES_MEM(0x87e0c4000000UL, SZ_16M),
> +	[9] = DEFINE_RES_MEM(0x87e0c5000000UL, SZ_16M),
> +	[14] = DEFINE_RES_MEM(0x97e0c0000000UL, SZ_16M),
> +	[15] = DEFINE_RES_MEM(0x97e0c1000000UL, SZ_16M),
> +	[16] = DEFINE_RES_MEM(0x97e0c2000000UL, SZ_16M),
> +	[17] = DEFINE_RES_MEM(0x97e0c3000000UL, SZ_16M),
> +	[18] = DEFINE_RES_MEM(0x97e0c4000000UL, SZ_16M),
> +	[19] = DEFINE_RES_MEM(0x97e0c5000000UL, SZ_16M),

1) The "correct" way to discover the resources consumed by an ACPI
   device is to use the _CRS method.  I know there are some issues
   there for bridges (not the fault of ThunderX!) because there's not
   a good way to distinguish windows from resources consumed directly
   by the bridge.

   But we should either do this correctly, or include a comment about
   why we're doing it wrong, so we don't give the impression that this
   is the right way to do it.

   I seem to recall some discussion about why we're doing it this way,
   but I don't remember the details.  It'd be nice to include a
   summary here.

2) This is a little weird because here we define the resource size as
   16MB, in the OF case we get the resource size from OF, in either
   case we ioremap 64K of it, and then as far as I can tell, we only
   ever access PEM_CFG_WR and PEM_CFG_RD, at offsets 0x28 and 0x30
   into the space.

   If the hardware actually decodes the entire 16MB, we should ioremap
   the whole 16MB.  (Strictly speaking, drivers only need to ioremap
   the parts they're using, but in this case nobody claims the entire
   resource because of deficiencies in the ACPI and OF cores, so the
   driver should ioremap the entire thing to help prevent conflicts
   with other devices.)

   It'd be nice if we didn't have the 64KB magic number.  I think
   using devm_ioremap_resource() would be nice.

> +};
> +
> +static struct resource *thunder_pem_acpi_res(struct pci_config_window *cfg)
> +{
> +	struct acpi_device *adev = to_acpi_device(cfg->parent);
> +	struct acpi_pci_root *root = acpi_driver_data(adev);
> +
> +	if ((root->segment >= 4 && root->segment <= 9) ||
> +	    (root->segment >= 14 && root->segment <= 19))
> +		return &thunder_pem_reg_res[root->segment];
> +
> +	return NULL;
> +}
> +#else
> +static struct resource *thunder_pem_acpi_res(struct pci_config_window *cfg)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  static int thunder_pem_init(struct pci_config_window *cfg)
>  {
>  	struct device *dev = cfg->parent;
> @@ -292,24 +327,24 @@ static int thunder_pem_init(struct pci_config_window *cfg)
>  	struct thunder_pem_pci *pem_pci;
>  	struct platform_device *pdev;
>  
> -	/* Only OF support for now */
> -	if (!dev->of_node)
> -		return -EINVAL;
> -
>  	pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL);
>  	if (!pem_pci)
>  		return -ENOMEM;
>  
> -	pdev = to_platform_device(dev);
> -
> -	/*
> -	 * The second register range is the PEM bridge to the PCIe
> -	 * bus.  It has a different config access method than those
> -	 * devices behind the bridge.
> -	 */
> -	res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (acpi_disabled) {
> +		pdev = to_platform_device(dev);
> +
> +		/*
> +		 * The second register range is the PEM bridge to the PCIe
> +		 * bus.  It has a different config access method than those
> +		 * devices behind the bridge.
> +		 */
> +		res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	} else {
> +		res_pem = thunder_pem_acpi_res(cfg);
> +	}
>  	if (!res_pem) {
> -		dev_err(dev, "missing \"reg[1]\"property\n");
> +		dev_err(dev, "missing configuration region\n");
>  		return -EINVAL;
>  	}
>  
> -- 
> 1.9.1
> 

^ permalink raw reply

* find_child_device() on ACPI node works only once
From: Timur Tabi @ 2016-09-19 18:08 UTC (permalink / raw)
  To: linux-arm-kernel

I need help getting my ACPI table parsing code to work correctly.  My 
driver fails to find the child device in a node when the driver is 
unloaded and reloaded.  I suspect that I'm not freeing a resource correctly.

Here is my ACPI table (trimmed):

Device (MAC0) {
	Name (_HID, "QCOM8070")
	Name (_UID, 0)
	Method (_CRS, 0x0, Serialized) {
		Name (RBUF, ResourceTemplate() {
			...
			Return (RBUF)
		}
	}
	Device (IPHY) {
		Name (_HID, "QCOM8071")

		Method (_CRS, 0x0, Serialized) {
			Name (RBUF, ResourceTemplate () {
				...
			Return (RBUF)
		}
	}


So QCOM8071 is a child device for QCOM8070.  The driver probes on 
QCOM8070 and then manually instantiates QCOM8071.

static const struct acpi_device_id emac_acpi_match[] = {
	{
		.id = "QCOM8070",
	},
	{}
};
MODULE_DEVICE_TABLE(acpi, emac_acpi_match);

static struct platform_driver emac_platform_driver = {
	.probe	= emac_probe,
	.remove	= emac_remove,
	.driver = {
		.name		= "qcom-emac",
		.acpi_match_table = ACPI_PTR(emac_acpi_match),
	},
};

In emac_probe, I do this:

struct device *dev;

dev = device_find_child(&pdev->dev, NULL, emac_sgmii_acpi_match);
adpt->sgmii_pdev = to_platform_device(dev);

And here's emac_sgmii_acpi_match:

> static int emac_sgmii_acpi_match(struct device *dev, void *data)
> {
> 	static const struct acpi_device_id match_table[] = {
> 		{
> 			.id = "QCOM8071",
> 		},
> 		{}
> 	};
> 	const struct acpi_device_id *id = acpi_match_device(match_table, dev);
>
> 	return !!id;
> }

When my driver exits, I call

	platform_device_unregister(adpt->sgmii_pdev);

So here's the problem: the second time my driver is loaded, 
emac_sgmii_acpi_match() always returns false.  The QCOM8071 child node 
no longer exists.  It's apparently hidden in some way.

I've been trying for several days to debug this, and I'm at my wits' 
end.  I'm assuming that I'm not freeing the resource properly, but other 
than calling platform_device_unregister(), what else should I do?

-- 
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

* [PATCH] arm: dts: fix rk3066a based boards vdd_log voltage initialization
From: Boris Brezillon @ 2016-09-19 18:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAD=FV=UyW5cXGGmq5xUzZ1aV5NzbBYGOz1gO9V1itrFU-PigAw@mail.gmail.com>

On Mon, 19 Sep 2016 10:52:51 -0700
Doug Anderson <dianders@chromium.org> wrote:

> Hi,
> 
> On Mon, Sep 19, 2016 at 10:48 AM, Boris Brezillon
> <boris.brezillon@free-electrons.com> wrote:
> > The PWM chip has always claimed the pins and muxed them to the PWM IP.
> > So, this means it's broken from the beginning, and my patch is only
> > uncovering the problem (unless the pins stay configured as input until
> > the PWM is enabled, which I'm not sure is the case).  
> 
> Such a solution is achievable with the pinctrl APIs pretty easily.
> You might not be able to use the automatic "init" state but you can do
> something similar and switch to an "active" state once the PWM is
> actually turned on the first time.

But is it really the case here (I don't see any code requesting a
specific pinmux depending on the PWM state)?

Anyway, we really need to handle this case, we should define the
typical voltage when the PWM is disabled. Same as what you suggested
with voltage-when-input, but with a different naming (since the concept
of pinmux is PWM hardware/driver specific).

	voltage-when-pwm-disabled = <...>;

^ permalink raw reply

* [RFC] arm64: Ensure proper addressing for ldnp/stnp
From: Robin Murphy @ 2016-09-19 18:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474306586-25118-1-git-send-email-bdegraaf@codeaurora.org>

On 19/09/16 18:36, Brent DeGraaf wrote:
> According to section 6.3.8 of the ARM Programmer's Guide, non-temporal
> loads and stores do not verify that address dependency is met between a
> load of an address to a register and a subsequent non-temporal load or
> store using that address on the executing PE. Therefore, context switch
> code and subroutine calls that use non-temporally accessed addresses as
> parameters that might depend on a load of an address into an argument
> register must ensure that ordering requirements are met by introducing
> a barrier prior to the successive non-temporal access.  Add appropriate
> barriers whereever this specific situation comes into play.
> 
> Signed-off-by: Brent DeGraaf <bdegraaf@codeaurora.org>
> ---
>  arch/arm64/kernel/entry.S  | 1 +
>  arch/arm64/lib/copy_page.S | 2 ++
>  2 files changed, 3 insertions(+)
> 
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 441420c..982c4d3 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -679,6 +679,7 @@ ENTRY(cpu_switch_to)
>  	ldp	x27, x28, [x8], #16
>  	ldp	x29, x9, [x8], #16
>  	ldr	lr, [x8]
> +	dmb	nshld	// Existence of instructions with loose load-use dependencies (e.g. ldnp/stnp) make this barrier necessary
>  	mov	sp, x9
>  	and	x9, x9, #~(THREAD_SIZE - 1)
>  	msr	sp_el0, x9
> diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S
> index 4c1e700..21c6892 100644
> --- a/arch/arm64/lib/copy_page.S
> +++ b/arch/arm64/lib/copy_page.S
> @@ -47,6 +47,8 @@ alternative_endif
>  	ldp	x14, x15, [x1, #96]
>  	ldp	x16, x17, [x1, #112]
>  
> +	dmb	nshld // In case x0 (for stnp) is dependent on a load

The ARMv8 ARM (B2.7.2 in issue j) says that when an address dependency
exists between a load and a subsequent LDNP, *other* observers may
observe those accesses in any order. How's that related to an STNP on
the same CPU?

Robin.

> +
>  	mov	x18, #(PAGE_SIZE - 128)
>  	add	x1, x1, #128
>  1:
> 

^ permalink raw reply

* [PATCH 1/1 v8] ARM: imx: Added perf functionality to mmdc driver
From: Frank Li @ 2016-09-19 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Zhengyu Shen <zhengyu.shen@nxp.com>

MMDC is a multi-mode DDR controller that supports DDR3/DDR3L x16/x32/x64
and LPDDR2 two channel x16/x32 memory types. MMDC is configurable, high
performance, and optimized. MMDC is present on i.MX6 Quad and i.MX6
QuadPlus devices, but this driver only supports i.MX6 Quad at the moment.
MMDC provides registers for performance counters which read via this
driver to help debug memory throughput and similar issues.

$ perf stat -a -e mmdc/busy-cycles/,mmdc/read-accesses/,mmdc/read-bytes/,mmdc/total-cycles/,mmdc/write-accesses/,mmdc/write-bytes/ dd if=/dev/zero of=/dev/null bs=1M count=5000
Performance counter stats for 'dd if=/dev/zero of=/dev/null bs=1M count=5000':

         898021787      mmdc/busy-cycles/
          14819600      mmdc/read-accesses/
            471.30 MB   mmdc/read-bytes/
        2815419216      mmdc/total-cycles/
          13367354      mmdc/write-accesses/
            427.76 MB   mmdc/write-bytes/

       5.334757334 seconds time elapsed

Signed-off-by: Zhengyu Shen <zhengyu.shen@nxp.com>
Signed-off-by: Frank Li <frank.li@nxp.com>
---
Changes from v7 to v8
    fix a group event check problem, should be slibling.

Changes from v6 to v7
    use mmdc_pmu prefix
    remove unnecessary check
    improve group event check according to mark's feedback.
    check pmu_mmdc->mmdc_events[cfg] at event_add
    only check == 0 at event_del

Changes from v5 to v6
    Improve group event error handle

Changes from v4 to v5
    Remove mmdc_pmu:irq
    remove static variable cpuhp_mmdc_pmu
    remove spin_lock
    check is_sampling_event(event)
    remove unnecessary cast
    use hw_perf_event::prev_count

Changes from v3 to v4:
    Tested and fixed crash relating to removing events with perf fuzzer
    Adjusted formatting
    Moved all perf event code under CONFIG_PERF_EVENTS
        Switched cpuhp_setup_state to cpuhp_setup_state_nocalls

Changes from v2 to v3:
    Use WARN_ONCE instead of returning generic error values
    Replace CPU Notifiers with newer state machine hotplug
    Added additional checks on event_init for grouping and sampling
    Remove useless mmdc_enable_profiling function
    Added comments
    Moved start index of events from 0x01 to 0x00
    Added a counter to pmu_mmdc to only stop hrtimer after all events are finished
    Replace readl_relaxed and writel_relaxed with readl and writel
    Removed duplicate update function
    Used devm_kasprintf when naming mmdcs probed

Changes from v1 to v2:
    Added cpumask and migration handling support to driver
    Validated event during event_init
    Added code to properly stop counters
    Used perf_invalid_context instead of perf_sw_context
    Added hrtimer to poll for overflow
    Added better description
    Added support for multiple mmdcs

 arch/arm/mach-imx/mmdc.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 457 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index db9621c..d82d14c 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011,2016 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -10,12 +10,16 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/hrtimer.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
 
 #include "common.h"
 
@@ -27,8 +31,458 @@
 #define BM_MMDC_MDMISC_DDR_TYPE	0x18
 #define BP_MMDC_MDMISC_DDR_TYPE	0x3
 
+#define TOTAL_CYCLES		0x0
+#define BUSY_CYCLES		0x1
+#define READ_ACCESSES		0x2
+#define WRITE_ACCESSES		0x3
+#define READ_BYTES		0x4
+#define WRITE_BYTES		0x5
+
+/* Enables, resets, freezes, overflow profiling*/
+#define DBG_DIS			0x0
+#define DBG_EN			0x1
+#define DBG_RST			0x2
+#define PRF_FRZ			0x4
+#define CYC_OVF			0x8
+
+#define MMDC_MADPCR0	0x410
+#define MMDC_MADPSR0	0x418
+#define MMDC_MADPSR1	0x41C
+#define MMDC_MADPSR2	0x420
+#define MMDC_MADPSR3	0x424
+#define MMDC_MADPSR4	0x428
+#define MMDC_MADPSR5	0x42C
+
+#define MMDC_NUM_COUNTERS	6
+
+#define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu)
+
 static int ddr_type;
 
+#ifdef CONFIG_PERF_EVENTS
+
+static DEFINE_IDA(mmdc_ida);
+
+PMU_EVENT_ATTR_STRING(total-cycles, mmdc_pmu_total_cycles, "event=0x00")
+PMU_EVENT_ATTR_STRING(busy-cycles, mmdc_pmu_busy_cycles, "event=0x01")
+PMU_EVENT_ATTR_STRING(read-accesses, mmdc_pmu_read_accesses, "event=0x02")
+PMU_EVENT_ATTR_STRING(write-accesses, mmdc_pmu_write_accesses, "config=0x03")
+PMU_EVENT_ATTR_STRING(read-bytes, mmdc_pmu_read_bytes, "event=0x04")
+PMU_EVENT_ATTR_STRING(read-bytes.unit, mmdc_pmu_read_bytes_unit, "MB");
+PMU_EVENT_ATTR_STRING(read-bytes.scale, mmdc_pmu_read_bytes_scale, "0.000001");
+PMU_EVENT_ATTR_STRING(write-bytes, mmdc_pmu_write_bytes, "event=0x05")
+PMU_EVENT_ATTR_STRING(write-bytes.unit, mmdc_pmu_write_bytes_unit, "MB");
+PMU_EVENT_ATTR_STRING(write-bytes.scale, mmdc_pmu_write_bytes_scale, "0.000001");
+
+struct mmdc_pmu {
+	struct pmu pmu;
+	void __iomem *mmdc_base;
+	cpumask_t cpu;
+	struct hrtimer hrtimer;
+	unsigned int active_events;
+	struct device *dev;
+	struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
+	struct hlist_node node;
+};
+
+/*
+ * Polling period is set to one second, overflow of total-cycles (the fastest
+ * increasing counter) takes ten seconds so one second is safe
+ */
+static unsigned int mmdc_pmu_poll_period_us = 1000000;
+
+module_param_named(pmu_pmu_poll_period_us, mmdc_pmu_poll_period_us, uint,
+		S_IRUGO | S_IWUSR);
+
+static ktime_t mmdc_pmu_timer_period(void)
+{
+	return ns_to_ktime((u64)mmdc_pmu_poll_period_us * 1000);
+}
+
+static ssize_t mmdc_pmu_cpumask_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmdc_pmu *pmu_mmdc = dev_get_drvdata(dev);
+
+	return cpumap_print_to_pagebuf(true, buf, &pmu_mmdc->cpu);
+}
+
+static struct device_attribute mmdc_pmu_cpumask_attr =
+	__ATTR(cpumask, S_IRUGO, mmdc_pmu_cpumask_show, NULL);
+
+static struct attribute *mmdc_pmu_cpumask_attrs[] = {
+	&mmdc_pmu_cpumask_attr.attr,
+	NULL,
+};
+
+static struct attribute_group mmdc_pmu_cpumask_attr_group = {
+	.attrs = mmdc_pmu_cpumask_attrs,
+};
+
+static struct attribute *mmdc_pmu_events_attrs[] = {
+	&mmdc_pmu_total_cycles.attr.attr,
+	&mmdc_pmu_busy_cycles.attr.attr,
+	&mmdc_pmu_read_accesses.attr.attr,
+	&mmdc_pmu_write_accesses.attr.attr,
+	&mmdc_pmu_read_bytes.attr.attr,
+	&mmdc_pmu_read_bytes_unit.attr.attr,
+	&mmdc_pmu_read_bytes_scale.attr.attr,
+	&mmdc_pmu_write_bytes.attr.attr,
+	&mmdc_pmu_write_bytes_unit.attr.attr,
+	&mmdc_pmu_write_bytes_scale.attr.attr,
+	NULL,
+};
+
+static struct attribute_group mmdc_pmu_events_attr_group = {
+	.name = "events",
+	.attrs = mmdc_pmu_events_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-63");
+static struct attribute *mmdc_pmu_format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group mmdc_pmu_format_attr_group = {
+	.name = "format",
+	.attrs = mmdc_pmu_format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&mmdc_pmu_events_attr_group,
+	&mmdc_pmu_format_attr_group,
+	&mmdc_pmu_cpumask_attr_group,
+	NULL,
+};
+
+static u32 mmdc_pmu_read_counter(struct mmdc_pmu *pmu_mmdc, int cfg)
+{
+	void __iomem *mmdc_base, *reg;
+
+	mmdc_base = pmu_mmdc->mmdc_base;
+
+	switch (cfg) {
+	case TOTAL_CYCLES:
+		reg = mmdc_base + MMDC_MADPSR0;
+		break;
+	case BUSY_CYCLES:
+		reg = mmdc_base + MMDC_MADPSR1;
+		break;
+	case READ_ACCESSES:
+		reg = mmdc_base + MMDC_MADPSR2;
+		break;
+	case WRITE_ACCESSES:
+		reg = mmdc_base + MMDC_MADPSR3;
+		break;
+	case READ_BYTES:
+		reg = mmdc_base + MMDC_MADPSR4;
+		break;
+	case WRITE_BYTES:
+		reg = mmdc_base + MMDC_MADPSR5;
+		break;
+	default:
+		return WARN_ONCE(1,
+			"invalid configuration %d for mmdc counter", cfg);
+	}
+	return readl(reg);
+}
+
+static int mmdc_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct mmdc_pmu *pmu_mmdc = hlist_entry_safe(node, struct mmdc_pmu, node);
+	int target;
+
+	if (!cpumask_test_and_clear_cpu(cpu, &pmu_mmdc->cpu))
+		return 0;
+
+	target = cpumask_any_but(cpu_online_mask, cpu);
+	if (target >= nr_cpu_ids)
+		return 0;
+
+	perf_pmu_migrate_context(&pmu_mmdc->pmu, cpu, target);
+	cpumask_set_cpu(target, &pmu_mmdc->cpu);
+
+	return 0;
+}
+
+static bool mmdc_pmu_group_event_is_valid(struct perf_event *event,
+					  struct pmu *pmu,
+					  unsigned long *used_counters)
+{
+	int cfg = event->attr.config;
+
+	if (is_software_event(event))
+		return true;
+
+	if (event->pmu != pmu)
+		return false;
+
+	return !test_and_set_bit(cfg, used_counters);
+}
+
+/*
+ * Each event has a single fixed-purpose counter, so we can only have a
+ * single active event for each at any point in time. Here we just check
+ * for duplicates, and rely on mmdc_pmu_event_init to verify that the HW
+ * event numbers are valid.
+ */
+static bool mmdc_pmu_group_is_valid(struct perf_event *event)
+{
+	struct pmu *pmu = event->pmu;
+	struct perf_event *leader = event->group_leader;
+	struct perf_event *sibling;
+	unsigned long counter_mask = 0;
+
+	set_bit(leader->attr.config, &counter_mask);
+
+	if (event != leader) {
+		if (!mmdc_pmu_group_event_is_valid(event, pmu, &counter_mask))
+			return false;
+	}
+
+	list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+		if (!mmdc_pmu_group_event_is_valid(sibling, pmu, &counter_mask))
+			return false;
+	}
+
+	return true;
+}
+
+static int mmdc_pmu_event_init(struct perf_event *event)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	int cfg = event->attr.config;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EOPNOTSUPP;
+
+	if (event->cpu < 0) {
+		dev_warn(pmu_mmdc->dev, "Can't provide per-task data!\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (event->attr.exclude_user		||
+			event->attr.exclude_kernel	||
+			event->attr.exclude_hv		||
+			event->attr.exclude_idle	||
+			event->attr.exclude_host	||
+			event->attr.exclude_guest	||
+			event->attr.sample_period)
+		return -EINVAL;
+
+	if (cfg < 0 || cfg >= MMDC_NUM_COUNTERS)
+		return -EINVAL;
+
+	if (!mmdc_pmu_group_is_valid(event))
+		return -EINVAL;
+
+	event->cpu = cpumask_first(&pmu_mmdc->cpu);
+	return 0;
+}
+
+static void mmdc_pmu_event_update(struct perf_event *event)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	u64 delta, prev_raw_count, new_raw_count;
+
+	do {
+		prev_raw_count = local64_read(&hwc->prev_count);
+		new_raw_count = mmdc_pmu_read_counter(pmu_mmdc,
+						      event->attr.config);
+	} while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+		new_raw_count) != prev_raw_count);
+
+	delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF;
+
+	local64_add(delta, &event->count);
+}
+
+static void mmdc_pmu_event_start(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	void __iomem *mmdc_base, *reg;
+
+	mmdc_base = pmu_mmdc->mmdc_base;
+	reg = mmdc_base + MMDC_MADPCR0;
+
+	/*
+	 * hrtimer is required because mmdc does not provide an interrupt so
+	 * polling is necessary
+	 */
+	hrtimer_start(&pmu_mmdc->hrtimer, mmdc_pmu_timer_period(),
+			HRTIMER_MODE_REL_PINNED);
+
+	local64_set(&hwc->prev_count, 0);
+
+	writel(DBG_RST, reg);
+	writel(DBG_EN, reg);
+}
+
+static int mmdc_pmu_event_add(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	int cfg = event->attr.config;
+
+	if (flags & PERF_EF_START)
+		mmdc_pmu_event_start(event, flags);
+
+	if (pmu_mmdc->mmdc_events[cfg] != NULL)
+		return -EAGAIN;
+
+	pmu_mmdc->mmdc_events[cfg] = event;
+	pmu_mmdc->active_events++;
+
+	local64_set(&hwc->prev_count, mmdc_pmu_read_counter(pmu_mmdc, cfg));
+
+	return 0;
+}
+
+static void mmdc_pmu_event_stop(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	void __iomem *mmdc_base, *reg;
+
+	mmdc_base = pmu_mmdc->mmdc_base;
+	reg = mmdc_base + MMDC_MADPCR0;
+
+	writel(PRF_FRZ, reg);
+	mmdc_pmu_event_update(event);
+}
+
+static void mmdc_pmu_event_del(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	int cfg = event->attr.config;
+
+	pmu_mmdc->mmdc_events[cfg] = NULL;
+	pmu_mmdc->active_events--;
+
+	if (pmu_mmdc->active_events == 0)
+		hrtimer_cancel(&pmu_mmdc->hrtimer);
+
+	mmdc_pmu_event_stop(event, PERF_EF_UPDATE);
+}
+
+static void mmdc_pmu_overflow_handler(struct mmdc_pmu *pmu_mmdc)
+{
+	int i;
+
+	for (i = 0; i < MMDC_NUM_COUNTERS; i++) {
+		struct perf_event *event = pmu_mmdc->mmdc_events[i];
+
+		if (event)
+			mmdc_pmu_event_update(event);
+	}
+}
+
+static enum hrtimer_restart mmdc_pmu_timer_handler(struct hrtimer *hrtimer)
+{
+	struct mmdc_pmu *pmu_mmdc = container_of(hrtimer, struct mmdc_pmu,
+			hrtimer);
+
+	mmdc_pmu_overflow_handler(pmu_mmdc);
+	hrtimer_forward_now(hrtimer, mmdc_pmu_timer_period());
+
+	return HRTIMER_RESTART;
+}
+
+static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc,
+		void __iomem *mmdc_base, struct device *dev)
+{
+	int mmdc_num;
+
+	*pmu_mmdc = (struct mmdc_pmu) {
+		.pmu = (struct pmu) {
+			.task_ctx_nr    = perf_invalid_context,
+			.attr_groups    = attr_groups,
+			.event_init     = mmdc_pmu_event_init,
+			.add            = mmdc_pmu_event_add,
+			.del            = mmdc_pmu_event_del,
+			.start          = mmdc_pmu_event_start,
+			.stop           = mmdc_pmu_event_stop,
+			.read           = mmdc_pmu_event_update,
+		},
+		.mmdc_base = mmdc_base,
+		.dev = dev,
+		.active_events = 0,
+	};
+
+	mmdc_num = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);
+
+	return mmdc_num;
+}
+
+static int imx_mmdc_remove(struct platform_device *pdev)
+{
+	struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&pmu_mmdc->pmu);
+	cpuhp_remove_state_nocalls(CPUHP_ONLINE);
+	kfree(pmu_mmdc);
+	return 0;
+}
+
+static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_base)
+{
+	struct mmdc_pmu *pmu_mmdc;
+	char *name;
+	int mmdc_num;
+	int ret;
+
+	pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);
+	if (!pmu_mmdc) {
+		pr_err("failed to allocate PMU device!\n");
+		return -ENOMEM;
+	}
+
+	mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev);
+	if (mmdc_num == 0)
+		name = "mmdc";
+	else
+		name = devm_kasprintf(&pdev->dev,
+				GFP_KERNEL, "mmdc%d", mmdc_num);
+
+	hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC,
+			HRTIMER_MODE_REL);
+	pmu_mmdc->hrtimer.function = mmdc_pmu_timer_handler;
+
+	cpuhp_state_add_instance_nocalls(CPUHP_ONLINE,
+					 &pmu_mmdc->node);
+	cpumask_set_cpu(smp_processor_id(), &pmu_mmdc->cpu);
+	ret = cpuhp_setup_state_multi(CPUHP_AP_NOTIFY_ONLINE,
+				      "MMDC_ONLINE", NULL,
+				      mmdc_pmu_offline_cpu);
+	if (ret) {
+		pr_err("cpuhp_setup_state_multi failure\n");
+		goto pmu_register_err;
+	}
+
+	ret = perf_pmu_register(&(pmu_mmdc->pmu), name, -1);
+	platform_set_drvdata(pdev, pmu_mmdc);
+	if (ret)
+		goto pmu_register_err;
+	return 0;
+
+pmu_register_err:
+	pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret);
+	hrtimer_cancel(&pmu_mmdc->hrtimer);
+	kfree(pmu_mmdc);
+	return ret;
+}
+
+#else
+#define imx_mmdc_remove NULL
+#define imx_mmdc_perf_init(pdev, mmdc_base) 0
+#endif
+
 static int imx_mmdc_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -62,7 +516,7 @@ static int imx_mmdc_probe(struct platform_device *pdev)
 		return -EBUSY;
 	}
 
-	return 0;
+	return imx_mmdc_perf_init(pdev, mmdc_base);
 }
 
 int imx_mmdc_get_ddr_type(void)
@@ -81,6 +535,7 @@ static struct platform_driver imx_mmdc_driver = {
 		.of_match_table = imx_mmdc_dt_ids,
 	},
 	.probe		= imx_mmdc_probe,
+	.remove		= imx_mmdc_remove,
 };
 
 static int __init imx_mmdc_init(void)
-- 
2.5.2

^ permalink raw reply related

* [PATCH] arm: dts: fix rk3066a based boards vdd_log voltage initialization
From: Doug Anderson @ 2016-09-19 17:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160919194844.0db7b307@bbrezillon>

Hi,

On Mon, Sep 19, 2016 at 10:48 AM, Boris Brezillon
<boris.brezillon@free-electrons.com> wrote:
> The PWM chip has always claimed the pins and muxed them to the PWM IP.
> So, this means it's broken from the beginning, and my patch is only
> uncovering the problem (unless the pins stay configured as input until
> the PWM is enabled, which I'm not sure is the case).

Such a solution is achievable with the pinctrl APIs pretty easily.
You might not be able to use the automatic "init" state but you can do
something similar and switch to an "active" state once the PWM is
actually turned on the first time.

-Doug

^ permalink raw reply

* [PATCH] arm: dts: fix rk3066a based boards vdd_log voltage initialization
From: Boris Brezillon @ 2016-09-19 17:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAD=FV=Ufmvg1P8suOPQ53kpOD1pei4N2dOpKUCxZk001XKj_OA@mail.gmail.com>

On Mon, 19 Sep 2016 10:22:43 -0700
Doug Anderson <dianders@chromium.org> wrote:

> Hi,
> 
> On Mon, Sep 19, 2016 at 10:13 AM, Boris Brezillon
> <boris.brezillon@free-electrons.com> wrote:
> > Correct me if I'm wrong, but the main problem here is that, when we try
> > to detect the initial regulator state, we ran into a "missing entry in
> > the duty-cycle <-> voltage table" error, which then triggers an -EINVAL
> > error preventing the PWM regulator probe to succeed.
> >
> > Of course, adding an entry for the 0% dutycle case would solve the
> > issue, but I wonder if we should not allow "unknown value" at probe
> > time, and let the regulator user set the voltage output when it claims
> > it.
> >
> > Another option would be to fake a valid value in this case (choose the
> > closest entry in the voltage table?).  
> 
> If the goal is to avoid glitching the voltage at bootup, then the
> above doesn't really solve it.
> 
> For instance, you could have:
> 
> 0% - 1.5V
> 100% - 0.8V
> When configured as input: 1.1V
> Max useful value: 1.2V
> 
> So if firmware doesn't touch the PWM regulator then that means you're
> booting up at 1.1V.

Oh! I really didn't consider this case when developing the solution. I
was assuming that the firmware/bootloader would configure the PWM
correctly and leave it activating when booting the kernel.

> 
> If you read out the PWM itself, it will claim that it's running at 0%.
> While that's true, that doesn't mean that the voltage on the system is
> actually 1.5V because at boot the system had configured the pinmux as
> GPIO input.  ...so it's actually 1.1V because the PWM isn't actually
> controlling the pins.

The PWM chip has always claimed the pins and muxed them to the PWM IP.
So, this means it's broken from the beginning, and my patch is only
uncovering the problem (unless the pins stay configured as input until
the PWM is enabled, which I'm not sure is the case).

> 
> So if you want to avoid glitching the line then you want to make sure
> that you properly init to 1.1V, _not_ to 1.5V.
> 
> In the case above, it's possible that 1.5V isn't really so great for
> the hardware lifespan because 1.2V is the maximum useful value.  You
> could argue that the hardware is badly designed in this case, but I
> have certainly seen boards designed where the maximum achievable value
> is higher than the maximum "safe" value.

> 
> -Doug

^ permalink raw reply

* [PATCH 1/1 v7] ARM: imx: Added perf functionality to mmdc driver
From: Frank Li @ 2016-09-19 17:47 UTC (permalink / raw)
  To: linux-arm-kernel

From: Zhengyu Shen <zhengyu.shen@nxp.com>

MMDC is a multi-mode DDR controller that supports DDR3/DDR3L x16/x32/x64
and LPDDR2 two channel x16/x32 memory types. MMDC is configurable, high
performance, and optimized. MMDC is present on i.MX6 Quad and i.MX6
QuadPlus devices, but this driver only supports i.MX6 Quad at the moment.
MMDC provides registers for performance counters which read via this
driver to help debug memory throughput and similar issues.

$ perf stat -a -e mmdc/busy-cycles/,mmdc/read-accesses/,mmdc/read-bytes/,mmdc/total-cycles/,mmdc/write-accesses/,mmdc/write-bytes/ dd if=/dev/zero of=/dev/null bs=1M count=5000
Performance counter stats for 'dd if=/dev/zero of=/dev/null bs=1M count=5000':

         898021787      mmdc/busy-cycles/
          14819600      mmdc/read-accesses/
            471.30 MB   mmdc/read-bytes/
        2815419216      mmdc/total-cycles/
          13367354      mmdc/write-accesses/
            427.76 MB   mmdc/write-bytes/

       5.334757334 seconds time elapsed

Signed-off-by: Zhengyu Shen <zhengyu.shen@nxp.com>
Signed-off-by: Frank Li <frank.li@nxp.com>
---
Changes from v6 to v7
    use mmdc_pmu prefix
    remove unnecessary check
    improve group event check according to mark's feedback.
    check pmu_mmdc->mmdc_events[cfg] at event_add
    only check == 0 at event_del

Changes from v5 to v6
    Improve group event error handle

Changes from v4 to v5
    Remove mmdc_pmu:irq
    remove static variable cpuhp_mmdc_pmu
    remove spin_lock
    check is_sampling_event(event)
    remove unnecessary cast
    use hw_perf_event::prev_count

Changes from v3 to v4:
    Tested and fixed crash relating to removing events with perf fuzzer
    Adjusted formatting
    Moved all perf event code under CONFIG_PERF_EVENTS
        Switched cpuhp_setup_state to cpuhp_setup_state_nocalls

Changes from v2 to v3:
    Use WARN_ONCE instead of returning generic error values
    Replace CPU Notifiers with newer state machine hotplug
    Added additional checks on event_init for grouping and sampling
    Remove useless mmdc_enable_profiling function
    Added comments
    Moved start index of events from 0x01 to 0x00
    Added a counter to pmu_mmdc to only stop hrtimer after all events are finished
    Replace readl_relaxed and writel_relaxed with readl and writel
    Removed duplicate update function
    Used devm_kasprintf when naming mmdcs probed

Changes from v1 to v2:
    Added cpumask and migration handling support to driver
    Validated event during event_init
    Added code to properly stop counters
    Used perf_invalid_context instead of perf_sw_context
    Added hrtimer to poll for overflow
    Added better description
    Added support for multiple mmdcs

 arch/arm/mach-imx/mmdc.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 457 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index db9621c..1f70376 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011,2016 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -10,12 +10,16 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+#include <linux/hrtimer.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
 
 #include "common.h"
 
@@ -27,8 +31,458 @@
 #define BM_MMDC_MDMISC_DDR_TYPE	0x18
 #define BP_MMDC_MDMISC_DDR_TYPE	0x3
 
+#define TOTAL_CYCLES		0x0
+#define BUSY_CYCLES		0x1
+#define READ_ACCESSES		0x2
+#define WRITE_ACCESSES		0x3
+#define READ_BYTES		0x4
+#define WRITE_BYTES		0x5
+
+/* Enables, resets, freezes, overflow profiling*/
+#define DBG_DIS			0x0
+#define DBG_EN			0x1
+#define DBG_RST			0x2
+#define PRF_FRZ			0x4
+#define CYC_OVF			0x8
+
+#define MMDC_MADPCR0	0x410
+#define MMDC_MADPSR0	0x418
+#define MMDC_MADPSR1	0x41C
+#define MMDC_MADPSR2	0x420
+#define MMDC_MADPSR3	0x424
+#define MMDC_MADPSR4	0x428
+#define MMDC_MADPSR5	0x42C
+
+#define MMDC_NUM_COUNTERS	6
+
+#define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu)
+
 static int ddr_type;
 
+#ifdef CONFIG_PERF_EVENTS
+
+static DEFINE_IDA(mmdc_ida);
+
+PMU_EVENT_ATTR_STRING(total-cycles, mmdc_pmu_total_cycles, "event=0x00")
+PMU_EVENT_ATTR_STRING(busy-cycles, mmdc_pmu_busy_cycles, "event=0x01")
+PMU_EVENT_ATTR_STRING(read-accesses, mmdc_pmu_read_accesses, "event=0x02")
+PMU_EVENT_ATTR_STRING(write-accesses, mmdc_pmu_write_accesses, "config=0x03")
+PMU_EVENT_ATTR_STRING(read-bytes, mmdc_pmu_read_bytes, "event=0x04")
+PMU_EVENT_ATTR_STRING(read-bytes.unit, mmdc_pmu_read_bytes_unit, "MB");
+PMU_EVENT_ATTR_STRING(read-bytes.scale, mmdc_pmu_read_bytes_scale, "0.000001");
+PMU_EVENT_ATTR_STRING(write-bytes, mmdc_pmu_write_bytes, "event=0x05")
+PMU_EVENT_ATTR_STRING(write-bytes.unit, mmdc_pmu_write_bytes_unit, "MB");
+PMU_EVENT_ATTR_STRING(write-bytes.scale, mmdc_pmu_write_bytes_scale, "0.000001");
+
+struct mmdc_pmu {
+	struct pmu pmu;
+	void __iomem *mmdc_base;
+	cpumask_t cpu;
+	struct hrtimer hrtimer;
+	unsigned int active_events;
+	struct device *dev;
+	struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
+	struct hlist_node node;
+};
+
+/*
+ * Polling period is set to one second, overflow of total-cycles (the fastest
+ * increasing counter) takes ten seconds so one second is safe
+ */
+static unsigned int mmdc_pmu_poll_period_us = 1000000;
+
+module_param_named(pmu_pmu_poll_period_us, mmdc_pmu_poll_period_us, uint,
+		S_IRUGO | S_IWUSR);
+
+static ktime_t mmdc_pmu_timer_period(void)
+{
+	return ns_to_ktime((u64)mmdc_pmu_poll_period_us * 1000);
+}
+
+static ssize_t mmdc_pmu_cpumask_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct mmdc_pmu *pmu_mmdc = dev_get_drvdata(dev);
+
+	return cpumap_print_to_pagebuf(true, buf, &pmu_mmdc->cpu);
+}
+
+static struct device_attribute mmdc_pmu_cpumask_attr =
+	__ATTR(cpumask, S_IRUGO, mmdc_pmu_cpumask_show, NULL);
+
+static struct attribute *mmdc_pmu_cpumask_attrs[] = {
+	&mmdc_pmu_cpumask_attr.attr,
+	NULL,
+};
+
+static struct attribute_group mmdc_pmu_cpumask_attr_group = {
+	.attrs = mmdc_pmu_cpumask_attrs,
+};
+
+static struct attribute *mmdc_pmu_events_attrs[] = {
+	&mmdc_pmu_total_cycles.attr.attr,
+	&mmdc_pmu_busy_cycles.attr.attr,
+	&mmdc_pmu_read_accesses.attr.attr,
+	&mmdc_pmu_write_accesses.attr.attr,
+	&mmdc_pmu_read_bytes.attr.attr,
+	&mmdc_pmu_read_bytes_unit.attr.attr,
+	&mmdc_pmu_read_bytes_scale.attr.attr,
+	&mmdc_pmu_write_bytes.attr.attr,
+	&mmdc_pmu_write_bytes_unit.attr.attr,
+	&mmdc_pmu_write_bytes_scale.attr.attr,
+	NULL,
+};
+
+static struct attribute_group mmdc_pmu_events_attr_group = {
+	.name = "events",
+	.attrs = mmdc_pmu_events_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-63");
+static struct attribute *mmdc_pmu_format_attrs[] = {
+	&format_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group mmdc_pmu_format_attr_group = {
+	.name = "format",
+	.attrs = mmdc_pmu_format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+	&mmdc_pmu_events_attr_group,
+	&mmdc_pmu_format_attr_group,
+	&mmdc_pmu_cpumask_attr_group,
+	NULL,
+};
+
+static u32 mmdc_pmu_read_counter(struct mmdc_pmu *pmu_mmdc, int cfg)
+{
+	void __iomem *mmdc_base, *reg;
+
+	mmdc_base = pmu_mmdc->mmdc_base;
+
+	switch (cfg) {
+	case TOTAL_CYCLES:
+		reg = mmdc_base + MMDC_MADPSR0;
+		break;
+	case BUSY_CYCLES:
+		reg = mmdc_base + MMDC_MADPSR1;
+		break;
+	case READ_ACCESSES:
+		reg = mmdc_base + MMDC_MADPSR2;
+		break;
+	case WRITE_ACCESSES:
+		reg = mmdc_base + MMDC_MADPSR3;
+		break;
+	case READ_BYTES:
+		reg = mmdc_base + MMDC_MADPSR4;
+		break;
+	case WRITE_BYTES:
+		reg = mmdc_base + MMDC_MADPSR5;
+		break;
+	default:
+		return WARN_ONCE(1,
+			"invalid configuration %d for mmdc counter", cfg);
+	}
+	return readl(reg);
+}
+
+static int mmdc_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
+{
+	struct mmdc_pmu *pmu_mmdc = hlist_entry_safe(node, struct mmdc_pmu, node);
+	int target;
+
+	if (!cpumask_test_and_clear_cpu(cpu, &pmu_mmdc->cpu))
+		return 0;
+
+	target = cpumask_any_but(cpu_online_mask, cpu);
+	if (target >= nr_cpu_ids)
+		return 0;
+
+	perf_pmu_migrate_context(&pmu_mmdc->pmu, cpu, target);
+	cpumask_set_cpu(target, &pmu_mmdc->cpu);
+
+	return 0;
+}
+
+static bool mmdc_pmu_group_event_is_valid(struct perf_event *event,
+					  struct pmu *pmu,
+					  unsigned long *used_counters)
+{
+	int cfg = event->attr.config;
+
+	if (is_software_event(event))
+		return true;
+
+	if (event->pmu != pmu)
+		return false;
+
+	return !test_and_set_bit(cfg, used_counters);
+}
+
+/*
+ * Each event has a single fixed-purpose counter, so we can only have a
+ * single active event for each at any point in time. Here we just check
+ * for duplicates, and rely on mmdc_pmu_event_init to verify that the HW
+ * event numbers are valid.
+ */
+static bool mmdc_pmu_group_is_valid(struct perf_event *event)
+{
+	struct pmu *pmu = event->pmu;
+	struct perf_event *leader = event->group_leader;
+	struct perf_event *sibling;
+	unsigned long counter_mask = 0;
+
+	set_bit(leader->attr.config, &counter_mask);
+
+	if (event != leader) {
+		if (!mmdc_pmu_group_event_is_valid(event, pmu, &counter_mask))
+			return false;
+	}
+
+	list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+		if (!mmdc_pmu_group_event_is_valid(event, pmu, &counter_mask))
+			return false;
+	}
+
+	return true;
+}
+
+static int mmdc_pmu_event_init(struct perf_event *event)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	int cfg = event->attr.config;
+
+	if (event->attr.type != event->pmu->type)
+		return -ENOENT;
+
+	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+		return -EOPNOTSUPP;
+
+	if (event->cpu < 0) {
+		dev_warn(pmu_mmdc->dev, "Can't provide per-task data!\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (event->attr.exclude_user		||
+			event->attr.exclude_kernel	||
+			event->attr.exclude_hv		||
+			event->attr.exclude_idle	||
+			event->attr.exclude_host	||
+			event->attr.exclude_guest	||
+			event->attr.sample_period)
+		return -EINVAL;
+
+	if (cfg < 0 || cfg >= MMDC_NUM_COUNTERS)
+		return -EINVAL;
+
+	if (!mmdc_pmu_group_is_valid(event))
+		return -EINVAL;
+
+	event->cpu = cpumask_first(&pmu_mmdc->cpu);
+	return 0;
+}
+
+static void mmdc_pmu_event_update(struct perf_event *event)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	u64 delta, prev_raw_count, new_raw_count;
+
+	do {
+		prev_raw_count = local64_read(&hwc->prev_count);
+		new_raw_count = mmdc_pmu_read_counter(pmu_mmdc,
+						      event->attr.config);
+	} while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+		new_raw_count) != prev_raw_count);
+
+	delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF;
+
+	local64_add(delta, &event->count);
+}
+
+static void mmdc_pmu_event_start(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+	void __iomem *mmdc_base, *reg;
+
+	mmdc_base = pmu_mmdc->mmdc_base;
+	reg = mmdc_base + MMDC_MADPCR0;
+
+	/*
+	 * hrtimer is required because mmdc does not provide an interrupt so
+	 * polling is necessary
+	 */
+	hrtimer_start(&pmu_mmdc->hrtimer, mmdc_pmu_timer_period(),
+			HRTIMER_MODE_REL_PINNED);
+
+	local64_set(&hwc->prev_count, 0);
+
+	writel(DBG_RST, reg);
+	writel(DBG_EN, reg);
+}
+
+static int mmdc_pmu_event_add(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	struct hw_perf_event *hwc = &event->hw;
+
+	int cfg = event->attr.config;
+
+	if (flags & PERF_EF_START)
+		mmdc_pmu_event_start(event, flags);
+
+	if (pmu_mmdc->mmdc_events[cfg] != NULL)
+		return -EAGAIN;
+
+	pmu_mmdc->mmdc_events[cfg] = event;
+	pmu_mmdc->active_events++;
+
+	local64_set(&hwc->prev_count, mmdc_pmu_read_counter(pmu_mmdc, cfg));
+
+	return 0;
+}
+
+static void mmdc_pmu_event_stop(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	void __iomem *mmdc_base, *reg;
+
+	mmdc_base = pmu_mmdc->mmdc_base;
+	reg = mmdc_base + MMDC_MADPCR0;
+
+	writel(PRF_FRZ, reg);
+	mmdc_pmu_event_update(event);
+}
+
+static void mmdc_pmu_event_del(struct perf_event *event, int flags)
+{
+	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
+	int cfg = event->attr.config;
+
+	pmu_mmdc->mmdc_events[cfg] = NULL;
+	pmu_mmdc->active_events--;
+
+	if (pmu_mmdc->active_events == 0)
+		hrtimer_cancel(&pmu_mmdc->hrtimer);
+
+	mmdc_pmu_event_stop(event, PERF_EF_UPDATE);
+}
+
+static void mmdc_pmu_overflow_handler(struct mmdc_pmu *pmu_mmdc)
+{
+	int i;
+
+	for (i = 0; i < MMDC_NUM_COUNTERS; i++) {
+		struct perf_event *event = pmu_mmdc->mmdc_events[i];
+
+		if (event)
+			mmdc_pmu_event_update(event);
+	}
+}
+
+static enum hrtimer_restart mmdc_pmu_timer_handler(struct hrtimer *hrtimer)
+{
+	struct mmdc_pmu *pmu_mmdc = container_of(hrtimer, struct mmdc_pmu,
+			hrtimer);
+
+	mmdc_pmu_overflow_handler(pmu_mmdc);
+	hrtimer_forward_now(hrtimer, mmdc_pmu_timer_period());
+
+	return HRTIMER_RESTART;
+}
+
+static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc,
+		void __iomem *mmdc_base, struct device *dev)
+{
+	int mmdc_num;
+
+	*pmu_mmdc = (struct mmdc_pmu) {
+		.pmu = (struct pmu) {
+			.task_ctx_nr    = perf_invalid_context,
+			.attr_groups    = attr_groups,
+			.event_init     = mmdc_pmu_event_init,
+			.add            = mmdc_pmu_event_add,
+			.del            = mmdc_pmu_event_del,
+			.start          = mmdc_pmu_event_start,
+			.stop           = mmdc_pmu_event_stop,
+			.read           = mmdc_pmu_event_update,
+		},
+		.mmdc_base = mmdc_base,
+		.dev = dev,
+		.active_events = 0,
+	};
+
+	mmdc_num = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);
+
+	return mmdc_num;
+}
+
+static int imx_mmdc_remove(struct platform_device *pdev)
+{
+	struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev);
+
+	perf_pmu_unregister(&pmu_mmdc->pmu);
+	cpuhp_remove_state_nocalls(CPUHP_ONLINE);
+	kfree(pmu_mmdc);
+	return 0;
+}
+
+static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_base)
+{
+	struct mmdc_pmu *pmu_mmdc;
+	char *name;
+	int mmdc_num;
+	int ret;
+
+	pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);
+	if (!pmu_mmdc) {
+		pr_err("failed to allocate PMU device!\n");
+		return -ENOMEM;
+	}
+
+	mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev);
+	if (mmdc_num == 0)
+		name = "mmdc";
+	else
+		name = devm_kasprintf(&pdev->dev,
+				GFP_KERNEL, "mmdc%d", mmdc_num);
+
+	hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC,
+			HRTIMER_MODE_REL);
+	pmu_mmdc->hrtimer.function = mmdc_pmu_timer_handler;
+
+	cpuhp_state_add_instance_nocalls(CPUHP_ONLINE,
+					 &pmu_mmdc->node);
+	cpumask_set_cpu(smp_processor_id(), &pmu_mmdc->cpu);
+	ret = cpuhp_setup_state_multi(CPUHP_AP_NOTIFY_ONLINE,
+				      "MMDC_ONLINE", NULL,
+				      mmdc_pmu_offline_cpu);
+	if (ret) {
+		pr_err("cpuhp_setup_state_multi failure\n");
+		goto pmu_register_err;
+	}
+
+	ret = perf_pmu_register(&(pmu_mmdc->pmu), name, -1);
+	platform_set_drvdata(pdev, pmu_mmdc);
+	if (ret)
+		goto pmu_register_err;
+	return 0;
+
+pmu_register_err:
+	pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret);
+	hrtimer_cancel(&pmu_mmdc->hrtimer);
+	kfree(pmu_mmdc);
+	return ret;
+}
+
+#else
+#define imx_mmdc_remove NULL
+#define imx_mmdc_perf_init(pdev, mmdc_base) 0
+#endif
+
 static int imx_mmdc_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -62,7 +516,7 @@ static int imx_mmdc_probe(struct platform_device *pdev)
 		return -EBUSY;
 	}
 
-	return 0;
+	return imx_mmdc_perf_init(pdev, mmdc_base);
 }
 
 int imx_mmdc_get_ddr_type(void)
@@ -81,6 +535,7 @@ static struct platform_driver imx_mmdc_driver = {
 		.of_match_table = imx_mmdc_dt_ids,
 	},
 	.probe		= imx_mmdc_probe,
+	.remove		= imx_mmdc_remove,
 };
 
 static int __init imx_mmdc_init(void)
-- 
2.5.2

^ permalink raw reply related

* [RFC] Arm64 boot fail with numa enable in BIOS
From: James Morse @ 2016-09-19 17:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160919140709.GA17464@leverpostej>

On 19/09/16 15:07, Mark Rutland wrote:
> On Mon, Sep 19, 2016 at 09:05:26PM +0800, Yisheng Xie wrote:
>> For the crash log, it seems caused by error number of cpumask.
>> Any ideas about it?

> Much earlier in your log, there was a (non-fatal) warning, as below. Do
> you see this without NUMA/SRAT enabled in your FW?

>> [    0.297337] Detected PIPT I-cache on CPU1
>> [    0.297347] GICv3: CPU1: found redistributor 10001 region 1:0x000000004d140000
>> [    0.297356] CPU1: Booted secondary processor [410fd082]
>> [    0.297375] ------------[ cut here ]------------
>> [    0.320390] WARNING: CPU: 1 PID: 0 at ./include/linux/cpumask.h:121 gic_raise_softirq+0x128/0x17c
>> [    0.329356] Modules linked in:
>> [    0.332434] 
>> [    0.333932] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0-rc4-00163-g803ea3a #21
>> [    0.341581] Hardware name: Hisilicon Hi1616 Evaluation Board (DT)
>> [    0.347735] task: ffff8013e9dd0000 task.stack: ffff8013e9dcc000
>> [    0.353714] PC is at gic_raise_softirq+0x128/0x17c
>> [    0.358550] LR is at gic_raise_softirq+0xa0/0x17c

I've seen this first trace when built with DEBUG_PER_CPU_MAPS. My version of
this trace[0] was just noise due to gic_compute_target_list() and
gic_raise_softirq() sharing an iterator.

This patch silenced it for me:
https://lkml.org/lkml/2016/9/19/623

Yours may be a different problem with the same symptom.


Thanks,

James


[0] gicv3 trace when built with DEBUG_PER_CPU_MAPS
[    3.077738] GICv3: CPU1: found redistributor 1 region 0:0x000000002f120000
[    3.077943] CPU1: Booted secondary processor [410fd0f0]
[    3.078542] ------------[ cut here ]------------
[    3.078746] WARNING: CPU: 1 PID: 0 at ../include/linux/cpumask.h:121
gic_raise_softirq+0x12c/0x170
[    3.078812] Modules linked in:
[    3.078869]
[    3.078930] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0-rc5+ #5188
[    3.078994] Hardware name: Foundation-v8A (DT)
[    3.079059] task: ffff80087a1a0080 task.stack: ffff80087a19c000
[    3.079145] PC is at gic_raise_softirq+0x12c/0x170
[    3.079226] LR is at gic_raise_softirq+0xa4/0x170

^ permalink raw reply

* [PATCH v4 2/2] KVM: arm/arm64: Route vtimer events to user space
From: Alexander Graf @ 2016-09-19 17:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <57DFFAD3.3080009@arm.com>



On 19.09.16 16:48, Marc Zyngier wrote:
> On 19/09/16 12:14, Alexander Graf wrote:
>> We have 2 modes for dealing with interrupts in the ARM world. We can either
>> handle them all using hardware acceleration through the vgic or we can emulate
>> a gic in user space and only drive CPU IRQ pins from there.
>>
>> Unfortunately, when driving IRQs from user space, we never tell user space
>> about timer events that may result in interrupt line state changes, so we
>> lose out on timer events if we run with user space gic emulation.
>>
>> This patch fixes that by routing vtimer expiration events to user space.
>> With this patch I can successfully run edk2 and Linux with user space gic
>> emulation.
>>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>
>> ---
>>
>> v1 -> v2:
>>
>>   - Add back curly brace that got lost
>>
>> v2 -> v3:
>>
>>   - Split into patch set
>>
>> v3 -> v4:
>>
>>   - Improve documentation
>> ---
>>  Documentation/virtual/kvm/api.txt |  30 ++++++++-
>>  arch/arm/include/asm/kvm_host.h   |   3 +
>>  arch/arm/kvm/arm.c                |  22 ++++---
>>  arch/arm64/include/asm/kvm_host.h |   3 +
>>  include/uapi/linux/kvm.h          |  14 +++++
>>  virt/kvm/arm/arch_timer.c         | 125 +++++++++++++++++++++++++++-----------
>>  6 files changed, 155 insertions(+), 42 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index 23937e0..1c0bd86 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -3202,9 +3202,14 @@ struct kvm_run {
>>  	/* in */
>>  	__u8 request_interrupt_window;
>>  
>> -Request that KVM_RUN return when it becomes possible to inject external
>> +[x86] Request that KVM_RUN return when it becomes possible to inject external
>>  interrupts into the guest.  Useful in conjunction with KVM_INTERRUPT.
>>  
>> +[arm*] Bits set to 1 in here mask IRQ lines that would otherwise potentially
>> +trigger forever. These lines are available:
>> +
>> +    KVM_IRQWINDOW_VTIMER  -  Masks hw virtual timer irq while in guest
>> +
>>  	__u8 padding1[7];
>>  
>>  	/* out */
>> @@ -3519,6 +3524,18 @@ Hyper-V SynIC state change. Notification is used to remap SynIC
>>  event/message pages and to enable/disable SynIC messages/events processing
>>  in userspace.
>>  
>> +		/* KVM_EXIT_ARM_TIMER */
>> +		struct {
>> +			__u8 timesource;
>> +		} arm_timer;
>> +
>> +Indicates that a timer triggered that user space needs to handle and
>> +potentially mask with vcpu->run->request_interrupt_window to allow the
>> +guest to proceed. This only happens for timers that got enabled through
>> +KVM_CAP_ARM_TIMER. The following time sources are available:
>> +
>> +    KVM_ARM_TIMER_VTIMER  - virtual cpu timer
>> +
>>  		/* Fix the size of the union. */
>>  		char padding[256];
>>  	};
>> @@ -3739,6 +3756,17 @@ Once this is done the KVM_REG_MIPS_VEC_* and KVM_REG_MIPS_MSA_* registers can be
>>  accessed, and the Config5.MSAEn bit is accessible via the KVM API and also from
>>  the guest.
>>  
>> +6.11 KVM_CAP_ARM_TIMER
>> +
>> +Architectures: arm, arm64
>> +Target: vcpu
>> +Parameters: args[0] contains a bitmap of timers to select (see 5.)
>> +
>> +This capability allows to route per-core timers into user space. When it's
>> +enabled and no in-kernel interrupt controller is in use, the timers selected
>> +by args[0] trigger KVM_EXIT_ARM_TIMER guest exits when they are pending,
>> +unless masked by vcpu->run->request_interrupt_window (see 5.).
>> +
>>  7. Capabilities that can be enabled on VMs
>>  ------------------------------------------
>>  
>> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
>> index de338d9..77d1f73 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -180,6 +180,9 @@ struct kvm_vcpu_arch {
>>  
>>  	/* Detect first run of a vcpu */
>>  	bool has_run_once;
>> +
>> +	/* User space wants timer notifications */
>> +	bool user_space_arm_timers;
> 
> Please move this to the timer structure.

Sure.

> 
>>  };
>>  
>>  struct kvm_vm_stat {
>> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
>> index c84b6ad..57bdb71 100644
>> --- a/arch/arm/kvm/arm.c
>> +++ b/arch/arm/kvm/arm.c
>> @@ -187,6 +187,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>>  	case KVM_CAP_ARM_PSCI_0_2:
>>  	case KVM_CAP_READONLY_MEM:
>>  	case KVM_CAP_MP_STATE:
>> +	case KVM_CAP_ARM_TIMER:
>>  		r = 1;
>>  		break;
>>  	case KVM_CAP_COALESCED_MMIO:
>> @@ -474,13 +475,7 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
>>  			return ret;
>>  	}
>>  
>> -	/*
>> -	 * Enable the arch timers only if we have an in-kernel VGIC
>> -	 * and it has been properly initialized, since we cannot handle
>> -	 * interrupts from the virtual timer with a userspace gic.
>> -	 */
>> -	if (irqchip_in_kernel(kvm) && vgic_initialized(kvm))
>> -		ret = kvm_timer_enable(vcpu);
>> +	ret = kvm_timer_enable(vcpu);
>>  
>>  	return ret;
>>  }
>> @@ -601,6 +596,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>>  			run->exit_reason = KVM_EXIT_INTR;
>>  		}
>>  
>> +		if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
> 
> Since this is a very unlikely event (in the grand scheme of things), how
> about making this unlikely()?
> 
>> +			/* Tell user space about the pending vtimer */
>> +			ret = 0;
>> +			run->exit_reason = KVM_EXIT_ARM_TIMER;
>> +			run->arm_timer.timesource = KVM_ARM_TIMER_VTIMER;
>> +		}
> 
> More importantly: why does it have to be indirected by a
> make_request/check_request, and not be handled as part of the
> kvm_timer_sync() call? We do update the state there, and you could
> directly find out whether an exit is required.

I can try - it seemed like it could easily become quite racy because we
call kvm_timer_sync_hwstate() at multiple places.

> 
>> +
>>  		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
>>  			vcpu->arch.power_off || vcpu->arch.pause) {
>>  			local_irq_enable();
>> @@ -887,6 +889,12 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
>>  		return -EINVAL;
>>  
>>  	switch (cap->cap) {
>> +	case KVM_CAP_ARM_TIMER:
>> +		r = 0;
>> +		if (cap->args[0] != KVM_ARM_TIMER_VTIMER)
>> +			return -EINVAL;
>> +		vcpu->arch.user_space_arm_timers = true;
>> +		break;
>>  	default:
>>  		r = -EINVAL;
>>  		break;
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 3eda975..3d01481 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -270,6 +270,9 @@ struct kvm_vcpu_arch {
>>  
>>  	/* Detect first run of a vcpu */
>>  	bool has_run_once;
>> +
>> +	/* User space wants timer notifications */
>> +	bool user_space_arm_timers;
>>  };
>>  
>>  #define vcpu_gp_regs(v)		(&(v)->arch.ctxt.gp_regs)
>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> index 300ef25..00f4948 100644
>> --- a/include/uapi/linux/kvm.h
>> +++ b/include/uapi/linux/kvm.h
>> @@ -205,6 +205,7 @@ struct kvm_hyperv_exit {
>>  #define KVM_EXIT_S390_STSI        25
>>  #define KVM_EXIT_IOAPIC_EOI       26
>>  #define KVM_EXIT_HYPERV           27
>> +#define KVM_EXIT_ARM_TIMER        28
>>  
>>  /* For KVM_EXIT_INTERNAL_ERROR */
>>  /* Emulate instruction failed. */
>> @@ -361,6 +362,10 @@ struct kvm_run {
>>  		} eoi;
>>  		/* KVM_EXIT_HYPERV */
>>  		struct kvm_hyperv_exit hyperv;
>> +		/* KVM_EXIT_ARM_TIMER */
>> +		struct {
>> +			__u8 timesource;
>> +		} arm_timer;
>>  		/* Fix the size of the union. */
>>  		char padding[256];
>>  	};
>> @@ -870,6 +875,7 @@ struct kvm_ppc_smmu_info {
>>  #define KVM_CAP_S390_USER_INSTR0 130
>>  #define KVM_CAP_MSI_DEVID 131
>>  #define KVM_CAP_PPC_HTM 132
>> +#define KVM_CAP_ARM_TIMER 133
>>  
>>  #ifdef KVM_CAP_IRQ_ROUTING
>>  
>> @@ -1327,4 +1333,12 @@ struct kvm_assigned_msix_entry {
>>  #define KVM_X2APIC_API_USE_32BIT_IDS            (1ULL << 0)
>>  #define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK  (1ULL << 1)
>>  
>> +/* Available with KVM_CAP_ARM_TIMER */
>> +
>> +/* Bits for run->request_interrupt_window */
>> +#define KVM_IRQWINDOW_VTIMER		(1 << 0)
>> +
>> +/* Bits for run->arm_timer.timesource */
>> +#define KVM_ARM_TIMER_VTIMER		(1 << 0)
>> +
>>  #endif /* __LINUX_KVM_H */
>> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
>> index 4309b60..cbbb50dd 100644
>> --- a/virt/kvm/arm/arch_timer.c
>> +++ b/virt/kvm/arm/arch_timer.c
>> @@ -170,16 +170,45 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
>>  {
>>  	int ret;
>>  	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>> +	struct kvm_run *run = vcpu->run;
>>  
>> -	BUG_ON(!vgic_initialized(vcpu->kvm));
>> +	BUG_ON(irqchip_in_kernel(vcpu->kvm) && !vgic_initialized(vcpu->kvm));
>>  
>>  	timer->active_cleared_last = false;
>>  	timer->irq.level = new_level;
>> -	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
>> +	trace_kvm_timer_update_irq(vcpu->vcpu_id, host_vtimer_irq,
>>  				   timer->irq.level);
>> -	ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
>> -					 timer->irq.irq,
>> -					 timer->irq.level);
>> +
>> +	if (irqchip_in_kernel(vcpu->kvm) && vgic_initialized(vcpu->kvm)) {
> 
> Given how many times you repeat this idiom in this patch, you should
> have a single condition that encapsulate it once and for all.

Sure.

> 
>> +		/* Fire the timer in the VGIC */
>> +
>> +		ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
>> +						 timer->irq.irq,
>> +						 timer->irq.level);
>> +	} else if (!vcpu->arch.user_space_arm_timers) {
>> +		/* User space has not activated timer use */
>> +		ret = 0;
>> +	} else {
>> +		/*
>> +		 * Set PENDING_TIMER so that user space can handle the event if
>> +		 *
>> +		 *   1) Level is high
>> +		 *   2) The vtimer is not suppressed by user space
>> +		 *   3) We are not in the timer trigger exit path
>> +		 */
>> +		if (new_level &&
>> +		    !(run->request_interrupt_window & KVM_IRQWINDOW_VTIMER) &&
>> +		    (run->exit_reason != KVM_EXIT_ARM_TIMER)) {
>> +			/* KVM_REQ_PENDING_TIMER means vtimer triggered */
>> +			kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
>> +		}
>> +
>> +		/* Force a new level high check on next entry */
>> +		timer->irq.level = 0;
> 
> I think this could become a bit more simple if you follow the flow I
> mentioned earlier involving kvm_timer_sync(). Also, I only see how you
> flag the line as being high, but not how you lower it. Care to explain
> that flow?

We convert the level triggered timer into an edge up event (kvm exit).
It's then up to user space to poll for the down event. Usually that will
happen when the guest fiddles with the interrupt controller (eoi, enable
line, etc).

Can you think of a different option? We could maybe verify 2 kvm_run
elements on guest entry and just see if they're identical: user space
"active" line and arch timer "IMASK" bit. If not, exit to user space and
let it update its state?

That should at least get rid of any chance for spurious interrupts.

> 
>> +
>> +		ret = 0;
>> +	}
>> +
>>  	WARN_ON(ret);
>>  }
>>  
>> @@ -197,7 +226,8 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
>>  	 * because the guest would never see the interrupt.  Instead wait
>>  	 * until we call this function from kvm_timer_flush_hwstate.
>>  	 */
>> -	if (!vgic_initialized(vcpu->kvm) || !timer->enabled)
>> +	if ((irqchip_in_kernel(vcpu->kvm) && !vgic_initialized(vcpu->kvm)) ||
>> +	    !timer->enabled)
>>  		return -ENODEV;
>>  
>>  	if (kvm_timer_should_fire(vcpu) != timer->irq.level)
>> @@ -275,35 +305,57 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
>>  	* to ensure that hardware interrupts from the timer triggers a guest
>>  	* exit.
>>  	*/
>> -	phys_active = timer->irq.level ||
>> -			kvm_vgic_map_is_active(vcpu, timer->irq.irq);
>> -
>> -	/*
>> -	 * We want to avoid hitting the (re)distributor as much as
>> -	 * possible, as this is a potentially expensive MMIO access
>> -	 * (not to mention locks in the irq layer), and a solution for
>> -	 * this is to cache the "active" state in memory.
>> -	 *
>> -	 * Things to consider: we cannot cache an "active set" state,
>> -	 * because the HW can change this behind our back (it becomes
>> -	 * "clear" in the HW). We must then restrict the caching to
>> -	 * the "clear" state.
>> -	 *
>> -	 * The cache is invalidated on:
>> -	 * - vcpu put, indicating that the HW cannot be trusted to be
>> -	 *   in a sane state on the next vcpu load,
>> -	 * - any change in the interrupt state
>> -	 *
>> -	 * Usage conditions:
>> -	 * - cached value is "active clear"
>> -	 * - value to be programmed is "active clear"
>> -	 */
>> -	if (timer->active_cleared_last && !phys_active)
>> -		return;
>> +	if (irqchip_in_kernel(vcpu->kvm) && vgic_initialized(vcpu->kvm)) {
>> +		phys_active = timer->irq.level ||
>> +				kvm_vgic_map_is_active(vcpu, timer->irq.irq);
>> +
>> +		/*
>> +		 * We want to avoid hitting the (re)distributor as much as
>> +		 * possible, as this is a potentially expensive MMIO access
>> +		 * (not to mention locks in the irq layer), and a solution for
>> +		 * this is to cache the "active" state in memory.
>> +		 *
>> +		 * Things to consider: we cannot cache an "active set" state,
>> +		 * because the HW can change this behind our back (it becomes
>> +		 * "clear" in the HW). We must then restrict the caching to
>> +		 * the "clear" state.
>> +		 *
>> +		 * The cache is invalidated on:
>> +		 * - vcpu put, indicating that the HW cannot be trusted to be
>> +		 *   in a sane state on the next vcpu load,
>> +		 * - any change in the interrupt state
>> +		 *
>> +		 * Usage conditions:
>> +		 * - cached value is "active clear"
>> +		 * - value to be programmed is "active clear"
>> +		 */
>> +		if (timer->active_cleared_last && !phys_active)
>> +			return;
>> +
>> +		ret = irq_set_irqchip_state(host_vtimer_irq,
>> +					    IRQCHIP_STATE_ACTIVE,
>> +					    phys_active);
>> +	} else {
>> +		/* User space tells us whether the timer is in active mode */
>> +		phys_active = vcpu->run->request_interrupt_window &
>> +			      KVM_IRQWINDOW_VTIMER;
> 
> No, this just says "mask the interrupt". It doesn't say anything about
> the state of the timer. More importantly: you sample the shared page.
> What guarantees that the information there is preserved? Is userspace
> writing that bit each time the vcpu thread re-enters the kernel with
> this interrupt being in flight?

The bit is owned by user space, so it has to guarantee that it stays.
It's the way the kvm_run struct rolls :).

> 
>> +
>> +		/* However if the line is high, we exit anyway, so we want
>> +		 * to keep the IRQ masked */
>> +		phys_active = phys_active || timer->irq.level;
> 
> Why would you force the interrupt to be masked as soon as the timer is
> firing? If userspace hasn't masked it, I don't think you should paper
> over it.

This is to make sure that when we hit the second call to
kvm_timer_sync_hwstate() in the exit path, we ignore it. We always set
timer->irq.level = 0 in kvm_timer_update_irq.

> 
>> +
>> +		/*
>> +		 * So we can just explicitly mask or unmask the IRQ, gaining
>> +		 * more compatibility with oddball irq controllers.
>> +		 */
>> +		if (phys_active)
>> +			disable_percpu_irq(host_vtimer_irq);
>> +		else
>> +			enable_percpu_irq(host_vtimer_irq, 0);
> 
> Since you are now targeting random irqchips (as opposed to a GIC
> specifically), what guarantees that the timer is a per-cpu IRQ?

This is the host interrupt controller - and we're already using percpu
irqs on it :). Also as it happens the RPi has them percpu (anything else
wouldn't make sense...).


Alex

^ permalink raw reply

* [PATCH] irqchip/gicv3: silence noisy DEBUG_PER_CPU_MAPS warning
From: Marc Zyngier @ 2016-09-19 17:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1474306155-3303-1-git-send-email-james.morse@arm.com>

Hi James,

On 19/09/16 18:29, James Morse wrote:
> gic_raise_softirq() walks the list of cpus using for_each_cpu(), it calls
> gic_compute_target_list() which advances the iterator by the number of
> CPUs in the cluster.
> 
> If gic_compute_target_list() reaches the last CPU it leaves the iterator
> pointing at the last CPU. This means the next time round the for_each_cpu()
> loop cpumask_next() will be called with an invalid CPU.
> 
> This triggers a warning when built with CONFIG_DEBUG_PER_CPU_MAPS:
> [    3.077738] GICv3: CPU1: found redistributor 1 region 0:0x000000002f120000
> [    3.077943] CPU1: Booted secondary processor [410fd0f0]
> [    3.078542] ------------[ cut here ]------------
> [    3.078746] WARNING: CPU: 1 PID: 0 at ../include/linux/cpumask.h:121 gic_raise_softirq+0x12c/0x170
> [    3.078812] Modules linked in:
> [    3.078869]
> [    3.078930] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.8.0-rc5+ #5188
> [    3.078994] Hardware name: Foundation-v8A (DT)
> [    3.079059] task: ffff80087a1a0080 task.stack: ffff80087a19c000
> [    3.079145] PC is at gic_raise_softirq+0x12c/0x170
> [    3.079226] LR is at gic_raise_softirq+0xa4/0x170
> [    3.079296] pc : [<ffff0000083ead24>] lr : [<ffff0000083eac9c>] pstate: 200001c9
> [    3.081139] Call trace:
> [    3.081202] Exception stack(0xffff80087a19fbe0 to 0xffff80087a19fd10)
> 
> [    3.082269] [<ffff0000083ead24>] gic_raise_softirq+0x12c/0x170
> [    3.082354] [<ffff00000808e614>] smp_send_reschedule+0x34/0x40
> [    3.082433] [<ffff0000080e80a0>] resched_curr+0x50/0x88
> [    3.082512] [<ffff0000080e89d0>] check_preempt_curr+0x60/0xd0
> [    3.082593] [<ffff0000080e8a60>] ttwu_do_wakeup+0x20/0xe8
> [    3.082672] [<ffff0000080e8bb8>] ttwu_do_activate+0x90/0xc0
> [    3.082753] [<ffff0000080ea9a4>] try_to_wake_up+0x224/0x370
> [    3.082836] [<ffff0000080eabc8>] default_wake_function+0x10/0x18
> [    3.082920] [<ffff000008103134>] __wake_up_common+0x5c/0xa0
> [    3.083003] [<ffff0000081031f4>] __wake_up_locked+0x14/0x20
> [    3.083086] [<ffff000008103f80>] complete+0x40/0x60
> [    3.083168] [<ffff00000808df7c>] secondary_start_kernel+0x15c/0x1d0
> [    3.083240] [<00000000808911a4>] 0x808911a4
> [    3.113401] Detected PIPT I-cache on CPU2
> 
> Avoid updating the iterator if the next call to cpumask_next() would
> cause the for_each_cpu() loop to exit.
> 
> There is no change to gic_raise_softirq()'s behaviour, (cpumask_next()s
> eventual call to _find_next_bit() will return early as start >= nbits),
> this patch just silences the warning.
> 
> Signed-off-by: James Morse <james.morse@arm.com>
> ---
>  drivers/irqchip/irq-gic-v3.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index ede5672ab34d..9e37c447cc2c 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -548,6 +548,7 @@ static int gic_starting_cpu(unsigned int cpu)
>  static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
>  				   unsigned long cluster_id)
>  {
> +	int next_cpu;
>  	int cpu = *base_cpu;
>  	unsigned long mpidr = cpu_logical_map(cpu);
>  	u16 tlist = 0;
> @@ -562,9 +563,10 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
>  
>  		tlist |= 1 << (mpidr & 0xf);
>  
> -		cpu = cpumask_next(cpu, mask);
> -		if (cpu >= nr_cpu_ids)
> +		next_cpu = cpumask_next(cpu, mask);
> +		if (next_cpu >= nr_cpu_ids)
>  			goto out;
> +		cpu = next_cpu;
>  
>  		mpidr = cpu_logical_map(cpu);
>  
> 

It took me a while to convince myself that the original code was
correct, and it obviously wasn't... Oh well, paper bag time.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

Thomas, any chance you could pick that one for -rc8?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [RFC] arm64: Ensure proper addressing for ldnp/stnp
From: Brent DeGraaf @ 2016-09-19 17:36 UTC (permalink / raw)
  To: linux-arm-kernel

According to section 6.3.8 of the ARM Programmer's Guide, non-temporal
loads and stores do not verify that address dependency is met between a
load of an address to a register and a subsequent non-temporal load or
store using that address on the executing PE. Therefore, context switch
code and subroutine calls that use non-temporally accessed addresses as
parameters that might depend on a load of an address into an argument
register must ensure that ordering requirements are met by introducing
a barrier prior to the successive non-temporal access.  Add appropriate
barriers whereever this specific situation comes into play.

Signed-off-by: Brent DeGraaf <bdegraaf@codeaurora.org>
---
 arch/arm64/kernel/entry.S  | 1 +
 arch/arm64/lib/copy_page.S | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 441420c..982c4d3 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -679,6 +679,7 @@ ENTRY(cpu_switch_to)
 	ldp	x27, x28, [x8], #16
 	ldp	x29, x9, [x8], #16
 	ldr	lr, [x8]
+	dmb	nshld	// Existence of instructions with loose load-use dependencies (e.g. ldnp/stnp) make this barrier necessary
 	mov	sp, x9
 	and	x9, x9, #~(THREAD_SIZE - 1)
 	msr	sp_el0, x9
diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S
index 4c1e700..21c6892 100644
--- a/arch/arm64/lib/copy_page.S
+++ b/arch/arm64/lib/copy_page.S
@@ -47,6 +47,8 @@ alternative_endif
 	ldp	x14, x15, [x1, #96]
 	ldp	x16, x17, [x1, #112]
 
+	dmb	nshld // In case x0 (for stnp) is dependent on a load
+
 	mov	x18, #(PAGE_SIZE - 128)
 	add	x1, x1, #128
 1:
-- 
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 1/3] i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
From: Noralf Trønnes @ 2016-09-19 17:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87zin3omsa.fsf@eliezer.anholt.net>


Den 19.09.2016 18:51, skrev Eric Anholt:
> Noralf Tr?nnes <noralf@tronnes.org> writes:
>
>> Writing messages larger than the FIFO size results in a hang, rendering
>> the machine unusable. This is because the RXD status flag is set on the
>> first interrupt which results in bcm2835_drain_rxfifo() stealing bytes
>> from the buffer. The controller continues to trigger interrupts waiting
>> for the missing bytes, but bcm2835_fill_txfifo() has none to give.
>> In this situation wait_for_completion_timeout() apparently is unable to
>> stop the madness.
>>
>> The BCM2835 ARM Peripherals datasheet has this to say about the flags:
>>    TXD: is set when the FIFO has space for at least one byte of data.
>>    RXD: is set when the FIFO contains at least one byte of data.
>>    TXW: is set during a write transfer and the FIFO is less than full.
>>    RXR: is set during a read transfer and the FIFO is or more full.
>>
>> Implementing the logic from the downstream i2c-bcm2708 driver solved
>> the hang problem.
>>
>> Signed-off-by: Noralf Tr?nnes <noralf@tronnes.org>
> Patches 1, 3 are:
>
> Reviewed-by: Eric Anholt <eric@anholt.net>
>
> For patch 2 I followed some of it, but couldn't quite say it's a review.
> I trust your testing, and that the path has had a lot more testing in
> the downstream tree, so it's:

I don't know how much testing downstream really has had since this feature
is disabled by default. So there is a possibility that this can break some
devices (while at the same time enable others).
I wondered about adding a module parameter so it could be disabled at
runtime, but decided to see what the review would be first.
It is of course possible to add a this module parameter later should it
turn out to break some device.

Noralf.

> Acked-by: Eric Anholt <eric@anholt.net>
>
> Thanks!

^ permalink raw reply


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