All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2] ARC: Set of patches for IRQ subsystem
From: Vineet Gupta @ 2016-11-08 20:25 UTC (permalink / raw)
  To: linux-snps-arc
In-Reply-To: <1478588912-3991-1-git-send-email-yuriy.kolerov@synopsys.com>

On 11/07/2016 11:08 PM, Yuriy Kolerov wrote:
> The first patch fixes misuse of IRQ numbers. In some places of the
> Linux kernel for ARC hardware IRQ numbers are used as virtual IRQ
> numbers and obviously it is wrong.
>
> The second patch forces the kernel to set a simple distribution mode
> for common interrupts in cases when such interrupts are routed to a
> single core.
>
> Yuriy Kolerov (2):
>   ARC: IRQ: Do not use hwirq as virq and vice versa
>   ARCv2: MCIP: Use IDU_M_DISTRI_DEST mode if there is only 1 destination
>     core
>
>  arch/arc/include/asm/smp.h |  4 ++--
>  arch/arc/kernel/mcip.c     | 33 ++++++++++++++++++++-------------
>  arch/arc/kernel/smp.c      | 13 +++++++++----
>  3 files changed, 31 insertions(+), 19 deletions(-)

Thx Yuriy.

Added to for-curr !

-Vineet

^ permalink raw reply

* Re: [PATCH] staging: iio: ad9832: allocate data before using
From: Jonathan Cameron @ 2016-11-08 20:24 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Lars-Peter Clausen, Michael Hennerich, Hartmut Knaack,
	Peter Meerwald-Stadler, Greg Kroah-Hartman, Eva Rachel Retuya,
	linux-iio, devel, linux-kernel
In-Reply-To: <20161108140115.2250646-1-arnd@arndb.de>

On 08/11/16 14:00, Arnd Bergmann wrote:
> The regulator changes assigned data to an uninitialized pointer:
> 
> drivers/staging/iio/frequency/ad9832.c: In function 'ad9832_probe':
> drivers/staging/iio/frequency/ad9832.c:214:11: error: 'st' may be used uninitialized in this function [-Werror=maybe-uninitialized]
> 
> This moves the allocation of the 'st' structure before its first
> use, as it should have been.
> 
> Fixes: 43a07e48af44 ("staging: iio: ad9832: clean-up regulator 'reg'")
> Fixes: a98461d79ba5 ("staging: iio: ad9832: add DVDD regulator")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Thanks Arnd.

I think I've gotten too reliant on zero day and clearly am not checking my local
build warnings closely enough.  Time to go back to doing pre push out checks more
thoroughly.

Anyhow, applied to the togreg branch of iio.git.  Will probably be the weekend
at least before I send another pull request.

Thanks,

Jonathan
> ---
>  drivers/staging/iio/frequency/ad9832.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
> index 639047fade30..a5b2f068168d 100644
> --- a/drivers/staging/iio/frequency/ad9832.c
> +++ b/drivers/staging/iio/frequency/ad9832.c
> @@ -211,6 +211,13 @@ static int ad9832_probe(struct spi_device *spi)
>  		return -ENODEV;
>  	}
>  
> +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	spi_set_drvdata(spi, indio_dev);
> +	st = iio_priv(indio_dev);
> +
>  	st->avdd = devm_regulator_get(&spi->dev, "avdd");
>  	if (IS_ERR(st->avdd))
>  		return PTR_ERR(st->avdd);
> @@ -233,13 +240,6 @@ static int ad9832_probe(struct spi_device *spi)
>  		goto error_disable_avdd;
>  	}
>  
> -	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> -	if (!indio_dev) {
> -		ret = -ENOMEM;
> -		goto error_disable_dvdd;
> -	}
> -	spi_set_drvdata(spi, indio_dev);
> -	st = iio_priv(indio_dev);
>  	st->mclk = pdata->mclk;
>  	st->spi = spi;
>  
> 


^ permalink raw reply

* [nightly] Core TISDK (daisy/1.6) 2015.06 build 2016-11-08_15-01-12
From: Denys Dmytriyenko @ 2016-11-08 20:24 UTC (permalink / raw)
  To: meta-arago

[-- Attachment #1: Type: text/html, Size: 5097 bytes --]

^ permalink raw reply

* [ath9k-devel] Bringing up More Than Two Station Mode Virtual Interfaces
From: Oleksij Rempel @ 2016-11-08 20:24 UTC (permalink / raw)
  To: ath9k-devel
In-Reply-To: <1477348015.232027.1478581348091@mail.yahoo.com>

Am 08.11.2016 um 06:02 schrieb Jack Fallington:
> I've been having a problem using the ath9k_htc driver and was hoping
> someone here might have some advice.
> 
> I'm trying to connect (on a single channel) to a single AP multiple
> times simultaneously using one physical wireless adapter. I haven't been
> able to bring up more than two virtual interfaces so far.
> 
> Here's my setup.
> 
> Linux Distribution:    Kali Linux 2016.2
> Kernel Version:    4.6.0
> Wireless Adapter:    TP-Link TL-WN722N
> Adapter Chipset:    Atheros AR9271
> Driver: ath9k_htc
> Firmware version: 1.4.0
> 
> Here's what I've tried:
> 
> Disable network-manager.
>     root at kali:~# /etc/init.d/network-manager stop
>     [ ok ] Stopping network-manager (via systemctl):
> network-manager.service.
> 
> Disable hardware encryption, because I've read this adapter won't
> support virtual interfaces with hardware encryption enabled.
>     root at kali:~# echo "options ath9k_htc nohwcrypt=1"
>>/etc/modprobe.d/ath9k_htc.conf
>     root at kali:~# modprobe ath9k_htc
>     root at kali:~# cat /sys/module/ath9k_htc/parameters/nohwcrypt
>     1
> 
> Create three virtual interfaces with unique MAC addresses.
>     root at kali:~# iw dev wlan0 interface add wlan1 type station
>     root at kali:~# iw dev wlan0 interface add wlan2 type station
>     root at kali:~# iw dev wlan0 interface add wlan3 type station
>     root at kali:~# macchanger -r wlan1
>     Current MAC:   [redacted] (unknown)
>     Permanent MAC: [redacted] (unknown)
>     New MAC:       ea:4c:bc:e0:8b:36 (unknown)
>     root at kali:~# macchanger -r wlan2
>     Current MAC:   [redacted] (unknown)
>     Permanent MAC: [redacted] (unknown)
>     New MAC:       52:3a:02:22:4d:4a (unknown)
>     root at kali:~# macchanger -r wlan3
>     Current MAC:   [redacted] (unknown)
>     Permanent MAC: [redacted] (unknown)
>     New MAC:       da:05:ce:1e:d0:41 (unknown)
> 
> Attempt to bring the new virtual interfaces up.
>     root at kali:~# ifconfig wlan1 up
>     root at kali:~# ifconfig wlan2 up
>     root at kali:~# ifconfig wlan3 up
>     SIOCSIFFLAGS: Device or resource busy
> 
> The third interface fails to come up.
> 
> On this page <http://www.candelatech.com/vsta.php>, they say, "We have
> successfully tested more than 200 stations and up to 4 APs per radio/NIC
> using ath9k and our code trees." They don't mention ath9k_htc, but I was
> hoping it also would also allow more than two station mode virtual
> interfaces. Or perhaps it's a firmware or hardware limitation causing my
> problem.

yes.

> Is there anything else I can try? If not, is there another chipset and
> driver combination that would allow me to use at least 20 simultaneous
> station interfaces?

try ath9k.

-- 
Regards,
Oleksij

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 213 bytes
Desc: OpenPGP digital signature
Url : http://lists.ath9k.org/pipermail/ath9k-devel/attachments/20161108/f35ec4f8/attachment.pgp 

^ permalink raw reply

* [GIT PULL 4/4] DaVinci defconfig updates for v4.10
From: Olof Johansson @ 2016-11-08 20:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161104062535.9593-4-nsekhar@ti.com>

On Fri, Nov 04, 2016 at 11:55:35AM +0530, Sekhar Nori wrote:
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
> 
>   Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git tags/davinci-for-v4.10/defconfig
> 
> for you to fetch changes up to 6e9be8608771192851a3adf59f0ba9240e3f802c:
> 
>   ARM: davinci_all_defconfig: enable LED default-on trigger (2016-11-01 11:42:54 +0530)
> 
> ----------------------------------------------------------------
> Some updates to davinci_all_defconfig for MMC,
> LCDC and GPIO/LEDs.
> 
> ----------------------------------------------------------------
> Bartosz Golaszewski (1):
>       ARM: davinci_all_defconfig: enable LCDC DRM driver
> 
> David Lechner (3):
>       ARM: davinci_all_defconfig: enable gpio poweroff driver
>       ARM: davinci_all_defconfig: build MMC into kernel
>       ARM: davinci_all_defconfig: enable LED default-on trigger

Merged, thanks.


-Olof

^ permalink raw reply

* [PATCH v2 2/2] ARM: sunxi: Add the missing clocks to the pinctrl nodes
From: Maxime Ripard @ 2016-11-08 20:24 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot
  Cc: linux-gpio, devicetree, Rob Herring, Chen-Yu Tsai, Maxime Ripard
In-Reply-To: <cover.61acad25a6fb233e39141b52acd217415281bd73.1478636546.git-series.maxime.ripard@free-electrons.com>

The pin controllers also use the two oscillators for debouncing. Add them
to the DTs.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/boot/dts/sun4i-a10.dtsi     | 3 ++-
 arch/arm/boot/dts/sun5i.dtsi         | 3 ++-
 arch/arm/boot/dts/sun6i-a31.dtsi     | 3 ++-
 arch/arm/boot/dts/sun7i-a20.dtsi     | 3 ++-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi | 3 ++-
 arch/arm/boot/dts/sun8i-h3.dtsi      | 3 ++-
 arch/arm/boot/dts/sun9i-a80.dtsi     | 3 ++-
 7 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 7e7dfc2b43db..b14a4281058d 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -967,7 +967,8 @@
 			compatible = "allwinner,sun4i-a10-pinctrl";
 			reg = <0x01c20800 0x400>;
 			interrupts = <28>;
-			clocks = <&apb0_gates 5>;
+			clocks = <&apb0_gates 5>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			interrupt-controller;
 			#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index b4ccee8cfb02..b0fca4ef4dae 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -547,7 +547,8 @@
 		pio: pinctrl@01c20800 {
 			reg = <0x01c20800 0x400>;
 			interrupts = <28>;
-			clocks = <&apb0_gates 5>;
+			clocks = <&apb0_gates 5>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			interrupt-controller;
 			#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 2e8bf93dcfb2..d06dcd1bc5a9 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -471,7 +471,8 @@
 				     <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&ccu CLK_APB1_PIO>;
+			clocks = <&ccu CLK_APB1_PIO>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			interrupt-controller;
 			#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 94cf5a1c7172..f7db067b0de0 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1085,7 +1085,8 @@
 			compatible = "allwinner,sun7i-a20-pinctrl";
 			reg = <0x01c20800 0x400>;
 			interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&apb0_gates 5>;
+			clocks = <&apb0_gates 5>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			interrupt-controller;
 			#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index 300a1bd5a6ec..dc57b0df2f52 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -266,7 +266,8 @@
 			/* compatible gets set in SoC specific dtsi file */
 			reg = <0x01c20800 0x400>;
 			/* interrupts get set in SoC specific dtsi file */
-			clocks = <&ccu CLK_BUS_PIO>;
+			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			interrupt-controller;
 			#interrupt-cells = <3>;
diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index c38b028cac83..98d1c079e2aa 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -321,7 +321,8 @@
 			reg = <0x01c20800 0x400>;
 			interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&ccu CLK_BUS_PIO>;
+			clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			#gpio-cells = <3>;
 			interrupt-controller;
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index ab6a221027ef..025efba21ce0 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -678,7 +678,8 @@
 				     <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&apb0_gates 5>;
+			clocks = <&apb0_gates 5>, <&osc24M>, <&osc32k>;
+			clock-names = "apb", "hosc", "losc";
 			gpio-controller;
 			interrupt-controller;
 			#interrupt-cells = <3>;
-- 
git-series 0.8.11

^ permalink raw reply related

* [PATCH v2 1/2] pinctrl: sunxi: Add support for interrupt debouncing
From: Maxime Ripard @ 2016-11-08 20:24 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot
  Cc: linux-gpio, devicetree, Rob Herring, Chen-Yu Tsai, Maxime Ripard
In-Reply-To: <cover.61acad25a6fb233e39141b52acd217415281bd73.1478636546.git-series.maxime.ripard@free-electrons.com>

The pin controller found in the Allwinner SoCs has support for interrupts
debouncing.

However, this is not done per-pin, preventing us from using the generic
pinconf binding for that, but per irq bank, which, depending on the SoC,
ranges from one to five.

Introduce a device-wide property to deal with this using a microsecond
resolution. We can re-use the per-pin input-debounce property for that, so
let's do it!

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 14 ++++++++++++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.c                                 | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.h                                 |  7 ++++++-
 3 files changed, 102 insertions(+), 0 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index 1685821eea41..350e155d9fc2 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -28,6 +28,20 @@ Required properties:
 - reg: Should contain the register physical address and length for the
   pin controller.
 
+- clocks: phandle to the clocks feeding the pin controller:
+  - "apb": the gated APB parent clock
+  - "hosc": the high frequency oscillator in the system
+  - "losc": the low frequency oscillator in the system
+
+Note: For backward compatibility reasons, the hosc and losc clocks are only
+required if you need to use the optional input-debounce property. Any new
+device tree should set them.
+
+Optional properties:
+  - input-debounce: Array of debouncing periods in microseconds. One period per
+    irq bank found in the controller
+
+
 Please refer to pinctrl-bindings.txt in this directory for details of the
 common pinctrl bindings used by client devices.
 
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 0facbea5f465..5c64fbb3de48 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -870,6 +870,85 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
 	return 0;
 }
 
+static int sunxi_pinctrl_compute_debounce(struct clk *clk, int freq, int *diff)
+{
+	unsigned long clock = clk_get_rate(clk);
+	unsigned int best_diff = ~0, best_div;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		int cur_diff = abs(freq - (clock >> i));
+
+		if (cur_diff < best_diff) {
+			best_diff = cur_diff;
+			best_div = i;
+		}
+	}
+
+	*diff = best_diff;
+	return best_div;
+}
+
+static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
+					struct device_node *node)
+{
+	unsigned int hosc_diff, losc_diff;
+	unsigned int hosc_div, losc_div;
+	struct clk *hosc, *losc;
+	u8 div, src;
+	int i, ret;
+
+	/* Deal with old DTs that didn't have the oscillators */
+	if (of_count_phandle_with_args(node, "clocks", "#clock-cells") != 3)
+		return 0;
+
+	/* If we don't have any setup, bail out */
+	if (!of_find_property(node, "input-debounce", NULL))
+		return 0;
+
+	losc = devm_clk_get(pctl->dev, "losc");
+	if (IS_ERR(losc))
+		return PTR_ERR(losc);
+
+	hosc = devm_clk_get(pctl->dev, "hosc");
+	if (IS_ERR(hosc))
+		return PTR_ERR(hosc);
+
+	for (i = 0; i < pctl->desc->irq_banks; i++) {
+		unsigned long debounce_freq;
+		u32 debounce;
+
+		ret = of_property_read_u32_index(node, "input-debounce",
+						 i, &debounce);
+		if (ret)
+			return ret;
+
+		debounce_freq = USEC_PER_SEC / debounce;
+		losc_div = sunxi_pinctrl_compute_debounce(losc,
+							  debounce_freq,
+							  &losc_diff);
+
+		hosc_div = sunxi_pinctrl_compute_debounce(hosc,
+							  debounce_freq,
+							  &hosc_diff);
+
+		if (hosc_diff < losc_diff) {
+			div = hosc_div;
+			src = 1;
+		} else {
+			div = losc_div;
+			src = 0;
+		}
+
+		writel(src | div << 4,
+		       pctl->membase +
+		       sunxi_irq_debounce_reg_from_bank(i,
+							pctl->desc->irq_bank_base));
+	}
+
+	return 0;
+}
+
 int sunxi_pinctrl_init(struct platform_device *pdev,
 		       const struct sunxi_pinctrl_desc *desc)
 {
@@ -1032,6 +1111,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
 						 pctl);
 	}
 
+	sunxi_pinctrl_setup_debounce(pctl, node);
+
 	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
 
 	return 0;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 0afce1ab12d0..c0d97fe58e84 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -69,6 +69,8 @@
 #define IRQ_STATUS_IRQ_BITS		1
 #define IRQ_STATUS_IRQ_MASK		((1 << IRQ_STATUS_IRQ_BITS) - 1)
 
+#define IRQ_DEBOUNCE_REG	0x218
+
 #define IRQ_MEM_SIZE		0x20
 
 #define IRQ_EDGE_RISING		0x00
@@ -266,6 +268,11 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
 	return irq_num * IRQ_CTRL_IRQ_BITS;
 }
 
+static inline u32 sunxi_irq_debounce_reg_from_bank(u8 bank, unsigned bank_base)
+{
+	return IRQ_DEBOUNCE_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+
 static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base)
 {
 	return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;
-- 
git-series 0.8.11

^ permalink raw reply related

* [PATCH v2 0/2] pinctrl: sunxi: Support the interrupt debouncing
From: Maxime Ripard @ 2016-11-08 20:23 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot
  Cc: linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Chen-Yu Tsai,
	Maxime Ripard

Hi,

The Allwinner pin controllers can setup a different debouncing period based
on two clocks and a prescaler.

This debouncing is applied to the whole IRQ bank, which prevents us from
using the per-pin property that is usually used.

Let me know what you think,
Maxime

Changes from v1:
  - Changed the resolution of the debouncing property to microseconds, and
    switched to the input-debounce instead of a custom one.

Maxime Ripard (2):
  pinctrl: sunxi: Add support for interrupt debouncing
  ARM: sunxi: Add the missing clocks to the pinctrl nodes

 Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 14 ++++++++++++-
 arch/arm/boot/dts/sun4i-a10.dtsi                                      |  3 ++-
 arch/arm/boot/dts/sun5i.dtsi                                          |  3 ++-
 arch/arm/boot/dts/sun6i-a31.dtsi                                      |  3 ++-
 arch/arm/boot/dts/sun7i-a20.dtsi                                      |  3 ++-
 arch/arm/boot/dts/sun8i-a23-a33.dtsi                                  |  3 ++-
 arch/arm/boot/dts/sun8i-h3.dtsi                                       |  3 ++-
 arch/arm/boot/dts/sun9i-a80.dtsi                                      |  3 ++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.c                                 | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.h                                 |  7 ++++++-
 10 files changed, 116 insertions(+), 7 deletions(-)

base-commit: bc5952be2d424b75ed11ff599b70bc9604e98d42
-- 
git-series 0.8.11
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v4 1/2] ARC: IRQ: Do not use hwirq as virq and vice versa
From: Vineet Gupta @ 2016-11-08 20:23 UTC (permalink / raw)
  To: Yuriy Kolerov, linux-snps-arc@lists.infradead.org
  Cc: Alexey.Brodkin@synopsys.com, tglx@linutronix.de,
	linux-kernel@vger.kernel.org
In-Reply-To: <1478588912-3991-2-git-send-email-yuriy.kolerov@synopsys.com>

On 11/07/2016 11:08 PM, Yuriy Kolerov wrote:
> At first smp_ipi_irq_setup() takes a cpu number and a hwirq number for
> the per core local interrupt line in the root interrupt controller and
> registers an appropriate IPI handler per cpu. However this function tries
> to bind a handler to the hwirq as virtual IRQ number and it is a wrong
> behavior. It is necessary to find a mapping of hwirq in the root IRQ
> domain to the actual virq using irq_find_mapping(). Also a declaration
> of smp_ipi_irq_setup() is corrected to denote that this function takes
> a hardware IRQ number but not a virtual IRQ number.
>
> Also there is one more problem related to usage of IRQ numbers. Multicore
> ARC configurations use IDU (Interrupt Distribution Unit) for distributing
> of common interrupts. In fact IDU is a interrupt controller on top of
> main per core interrupt controller.
>
> All common IRQs are physically and linearly mapped to per core
> interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to per
> core <24, 25, 26, 27> interrupts. An initialization code of IDU
> controller (idu_of_init()) creates mappings for all parent interrupts
> <24, 25, ...> and sets a chained IDU handler for them. In the same
> time idu_of_init() must save the first met parent hwirq (idu_first_irq)
> thus in future it is possible to figure out what common hwirq has come
> by subtracting of idu_first_irq from the current parent hwirq (see
> idu_cascade_isr()).
>
> The problem is that idu_of_init() and idu_cascade_isr() use parent virtual
> IRQs as hardware IRQs and perform all the above-described manipulations
> on virtual IRQs. But it is wrong and hardware IRQs must be used instead.

I rephrased the changelog to below

---->
ARC: IRQ: Do not use hwirq as virq and vice versa

This came up when reviewing code to address missing IRQ affinity
setting in AXS103 platform and/or implementing hierarchical IRQ domains

- smp_ipi_irq_setup() callers pass hwirq but in turn calls
  request_percpu_irq() which expects a linux virq. So invoke
  irq_find_mapping() to do the conversion
  (also explicitify this in code by renaming the args appropriately)

- idu_of_init()/idu_cascade_isr() were similarly using linux virq where
  hwirq is expected, so do the conversion using irqd_to_hwirq() helper



>
> Signed-off-by: Yuriy Kolerov <yuriy.kolerov@synopsys.com>
> ---
>  arch/arc/include/asm/smp.h |  4 ++--
>  arch/arc/kernel/mcip.c     | 20 +++++++++-----------
>  arch/arc/kernel/smp.c      | 13 +++++++++----
>  3 files changed, 20 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h
> index 89fdd1b..0861007 100644
> --- a/arch/arc/include/asm/smp.h
> +++ b/arch/arc/include/asm/smp.h
> @@ -37,9 +37,9 @@ extern const char *arc_platform_smp_cpuinfo(void);
>   * API expected BY platform smp code (FROM arch smp code)
>   *
>   * smp_ipi_irq_setup:
> - *	Takes @cpu and @irq to which the arch-common ISR is hooked up
> + *	Takes @cpu and @hwirq to which the arch-common ISR is hooked up
>   */
> -extern int smp_ipi_irq_setup(int cpu, int irq);
> +extern int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq);
>  
>  /*
>   * struct plat_smp_ops	- SMP callbacks provided by platform to ARC SMP
> diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c
> index 72f9179..4f4f04b 100644
> --- a/arch/arc/kernel/mcip.c
> +++ b/arch/arc/kernel/mcip.c
> @@ -219,16 +219,14 @@ static struct irq_chip idu_irq_chip = {
>  
>  };
>  
> -static int idu_first_irq;
> +static irq_hw_number_t idu_first_hwirq;
>  
>  static void idu_cascade_isr(struct irq_desc *desc)
>  {
> -	struct irq_domain *domain = irq_desc_get_handler_data(desc);
> -	unsigned int core_irq = irq_desc_get_irq(desc);
> -	unsigned int idu_irq;
> -
> -	idu_irq = core_irq - idu_first_irq;
> -	generic_handle_irq(irq_find_mapping(domain, idu_irq));
> +	struct irq_domain *idu_domain = irq_desc_get_handler_data(desc);
> +	irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc));
> +	irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq;
> +	generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq));
>  }
>  
>  static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq)
> @@ -294,7 +292,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
>  	struct irq_domain *domain;
>  	/* Read IDU BCR to confirm nr_irqs */
>  	int nr_irqs = of_irq_count(intc);
> -	int i, irq;
> +	int i, virq;
>  
>  	if (!idu_detected)
>  		panic("IDU not detected, but DeviceTree using it");
> @@ -312,11 +310,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
>  		 * however we need it to get the parent virq and set IDU handler
>  		 * as first level isr
>  		 */
> -		irq = irq_of_parse_and_map(intc, i);
> +		virq = irq_of_parse_and_map(intc, i);
>  		if (!i)
> -			idu_first_irq = irq;
> +			idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq));
>  
> -		irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain);
> +		irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain);
>  	}
>  
>  	__mcip_cmd(CMD_IDU_ENABLE, 0);
> diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
> index f183cc6..692ca51 100644
> --- a/arch/arc/kernel/smp.c
> +++ b/arch/arc/kernel/smp.c
> @@ -22,6 +22,7 @@
>  #include <linux/atomic.h>
>  #include <linux/cpumask.h>
>  #include <linux/reboot.h>
> +#include <linux/irqdomain.h>
>  #include <asm/processor.h>
>  #include <asm/setup.h>
>  #include <asm/mach_desc.h>
> @@ -351,20 +352,24 @@ irqreturn_t do_IPI(int irq, void *dev_id)
>   */
>  static DEFINE_PER_CPU(int, ipi_dev);
>  
> -int smp_ipi_irq_setup(int cpu, int irq)
> +int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq)
>  {
>  	int *dev = per_cpu_ptr(&ipi_dev, cpu);
> +	unsigned int virq = irq_find_mapping(NULL, hwirq);
> +
> +	if (!virq)
> +		panic("Cannot find virq for root domain and hwirq=%lu", hwirq);
>  
>  	/* Boot cpu calls request, all call enable */
>  	if (!cpu) {
>  		int rc;
>  
> -		rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev);
> +		rc = request_percpu_irq(virq, do_IPI, "IPI Interrupt", dev);
>  		if (rc)
> -			panic("Percpu IRQ request failed for %d\n", irq);
> +			panic("Percpu IRQ request failed for %u\n", virq);
>  	}
>  
> -	enable_percpu_irq(irq, 0);
> +	enable_percpu_irq(virq, 0);
>  
>  	return 0;
>  }

^ permalink raw reply

* [GIT PULL 3/4] DaVinci device-tree updates for v4.10
From: Olof Johansson @ 2016-11-08 20:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161104062535.9593-3-nsekhar@ti.com>

On Fri, Nov 04, 2016 at 11:55:34AM +0530, Sekhar Nori wrote:
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
> 
>   Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git tags/davinci-for-v4.10/dt
> 
> for you to fetch changes up to 1b499f255589204466d8f8ab26e6b577d7b5c88f:
> 
>   ARM: dts: da850: Add cfgchip syscon node (2016-11-01 15:11:10 +0530)
> 
> ----------------------------------------------------------------
> DaVinci device-tree source additions for
> LCD, SPI and cfgchip syscon.

Merged, thanks!


-Olof

^ permalink raw reply

* [PATCH v4 1/2] ARC: IRQ: Do not use hwirq as virq and vice versa
From: Vineet Gupta @ 2016-11-08 20:23 UTC (permalink / raw)
  To: linux-snps-arc
In-Reply-To: <1478588912-3991-2-git-send-email-yuriy.kolerov@synopsys.com>

On 11/07/2016 11:08 PM, Yuriy Kolerov wrote:
> At first smp_ipi_irq_setup() takes a cpu number and a hwirq number for
> the per core local interrupt line in the root interrupt controller and
> registers an appropriate IPI handler per cpu. However this function tries
> to bind a handler to the hwirq as virtual IRQ number and it is a wrong
> behavior. It is necessary to find a mapping of hwirq in the root IRQ
> domain to the actual virq using irq_find_mapping(). Also a declaration
> of smp_ipi_irq_setup() is corrected to denote that this function takes
> a hardware IRQ number but not a virtual IRQ number.
>
> Also there is one more problem related to usage of IRQ numbers. Multicore
> ARC configurations use IDU (Interrupt Distribution Unit) for distributing
> of common interrupts. In fact IDU is a interrupt controller on top of
> main per core interrupt controller.
>
> All common IRQs are physically and linearly mapped to per core
> interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to per
> core <24, 25, 26, 27> interrupts. An initialization code of IDU
> controller (idu_of_init()) creates mappings for all parent interrupts
> <24, 25, ...> and sets a chained IDU handler for them. In the same
> time idu_of_init() must save the first met parent hwirq (idu_first_irq)
> thus in future it is possible to figure out what common hwirq has come
> by subtracting of idu_first_irq from the current parent hwirq (see
> idu_cascade_isr()).
>
> The problem is that idu_of_init() and idu_cascade_isr() use parent virtual
> IRQs as hardware IRQs and perform all the above-described manipulations
> on virtual IRQs. But it is wrong and hardware IRQs must be used instead.

I rephrased the changelog to below

---->
ARC: IRQ: Do not use hwirq as virq and vice versa

This came up when reviewing code to address missing IRQ affinity
setting in AXS103 platform and/or implementing hierarchical IRQ domains

- smp_ipi_irq_setup() callers pass hwirq but in turn calls
  request_percpu_irq() which expects a linux virq. So invoke
  irq_find_mapping() to do the conversion
  (also explicitify this in code by renaming the args appropriately)

- idu_of_init()/idu_cascade_isr() were similarly using linux virq where
  hwirq is expected, so do the conversion using irqd_to_hwirq() helper



>
> Signed-off-by: Yuriy Kolerov <yuriy.kolerov at synopsys.com>
> ---
>  arch/arc/include/asm/smp.h |  4 ++--
>  arch/arc/kernel/mcip.c     | 20 +++++++++-----------
>  arch/arc/kernel/smp.c      | 13 +++++++++----
>  3 files changed, 20 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h
> index 89fdd1b..0861007 100644
> --- a/arch/arc/include/asm/smp.h
> +++ b/arch/arc/include/asm/smp.h
> @@ -37,9 +37,9 @@ extern const char *arc_platform_smp_cpuinfo(void);
>   * API expected BY platform smp code (FROM arch smp code)
>   *
>   * smp_ipi_irq_setup:
> - *	Takes @cpu and @irq to which the arch-common ISR is hooked up
> + *	Takes @cpu and @hwirq to which the arch-common ISR is hooked up
>   */
> -extern int smp_ipi_irq_setup(int cpu, int irq);
> +extern int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq);
>  
>  /*
>   * struct plat_smp_ops	- SMP callbacks provided by platform to ARC SMP
> diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c
> index 72f9179..4f4f04b 100644
> --- a/arch/arc/kernel/mcip.c
> +++ b/arch/arc/kernel/mcip.c
> @@ -219,16 +219,14 @@ static struct irq_chip idu_irq_chip = {
>  
>  };
>  
> -static int idu_first_irq;
> +static irq_hw_number_t idu_first_hwirq;
>  
>  static void idu_cascade_isr(struct irq_desc *desc)
>  {
> -	struct irq_domain *domain = irq_desc_get_handler_data(desc);
> -	unsigned int core_irq = irq_desc_get_irq(desc);
> -	unsigned int idu_irq;
> -
> -	idu_irq = core_irq - idu_first_irq;
> -	generic_handle_irq(irq_find_mapping(domain, idu_irq));
> +	struct irq_domain *idu_domain = irq_desc_get_handler_data(desc);
> +	irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc));
> +	irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq;
> +	generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq));
>  }
>  
>  static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq)
> @@ -294,7 +292,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
>  	struct irq_domain *domain;
>  	/* Read IDU BCR to confirm nr_irqs */
>  	int nr_irqs = of_irq_count(intc);
> -	int i, irq;
> +	int i, virq;
>  
>  	if (!idu_detected)
>  		panic("IDU not detected, but DeviceTree using it");
> @@ -312,11 +310,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent)
>  		 * however we need it to get the parent virq and set IDU handler
>  		 * as first level isr
>  		 */
> -		irq = irq_of_parse_and_map(intc, i);
> +		virq = irq_of_parse_and_map(intc, i);
>  		if (!i)
> -			idu_first_irq = irq;
> +			idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq));
>  
> -		irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain);
> +		irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain);
>  	}
>  
>  	__mcip_cmd(CMD_IDU_ENABLE, 0);
> diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
> index f183cc6..692ca51 100644
> --- a/arch/arc/kernel/smp.c
> +++ b/arch/arc/kernel/smp.c
> @@ -22,6 +22,7 @@
>  #include <linux/atomic.h>
>  #include <linux/cpumask.h>
>  #include <linux/reboot.h>
> +#include <linux/irqdomain.h>
>  #include <asm/processor.h>
>  #include <asm/setup.h>
>  #include <asm/mach_desc.h>
> @@ -351,20 +352,24 @@ irqreturn_t do_IPI(int irq, void *dev_id)
>   */
>  static DEFINE_PER_CPU(int, ipi_dev);
>  
> -int smp_ipi_irq_setup(int cpu, int irq)
> +int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq)
>  {
>  	int *dev = per_cpu_ptr(&ipi_dev, cpu);
> +	unsigned int virq = irq_find_mapping(NULL, hwirq);
> +
> +	if (!virq)
> +		panic("Cannot find virq for root domain and hwirq=%lu", hwirq);
>  
>  	/* Boot cpu calls request, all call enable */
>  	if (!cpu) {
>  		int rc;
>  
> -		rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev);
> +		rc = request_percpu_irq(virq, do_IPI, "IPI Interrupt", dev);
>  		if (rc)
> -			panic("Percpu IRQ request failed for %d\n", irq);
> +			panic("Percpu IRQ request failed for %u\n", virq);
>  	}
>  
> -	enable_percpu_irq(irq, 0);
> +	enable_percpu_irq(virq, 0);
>  
>  	return 0;
>  }

^ permalink raw reply

* [GIT PULL 2/4] DaVinci SoC updates for v4.10
From: Olof Johansson @ 2016-11-08 20:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161104062535.9593-2-nsekhar@ti.com>

On Fri, Nov 04, 2016 at 11:55:33AM +0530, Sekhar Nori wrote:
> The following changes since commit 766763dbdc1dca11deabdb00077a1c19e2803f0a:
> 
>   ARM: davinci: da8xx: Remove duplicated defines (2016-10-31 16:51:56 +0530)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git tags/davinci-for-v4.10/soc
> 
> for you to fetch changes up to ced95ac0815501f47a6041548d70d8900400912d:
> 
>   ARM: davinci: da8xx: register USB PHY clocks in the DT file (2016-11-01 15:24:24 +0530)
> 
> ----------------------------------------------------------------
> DaVinci SoC support improvements mainly towards an effort to
> get to working USB support.
> 
> - use CFGCHIP syscon device to access common registers
> 
> - define platform data and device tree nodes for newly
>   introduced USB phy driver
> 
> - clock lookup and auxdata lookup for USB phy and also
>   for LCDC (LCD controller)

Merged, thanks.


-Olof

^ permalink raw reply

* Re: [PATCH v11 15/22] vfio: Introduce vfio_set_irqs_validate_and_prepare()
From: Kirti Wankhede @ 2016-11-08 20:22 UTC (permalink / raw)
  To: Alexey Kardashevskiy, alex.williamson, pbonzini, kraxel, cjia
  Cc: qemu-devel, kvm, kevin.tian, jike.song, bjsdjshi, linux-kernel
In-Reply-To: <dd3c9f16-e0fc-fc81-e151-48eab6759070@ozlabs.ru>



On 11/8/2016 2:16 PM, Alexey Kardashevskiy wrote:
> On 05/11/16 08:10, Kirti Wankhede wrote:
>> Vendor driver using mediated device framework would use same mechnism to
>> validate and prepare IRQs. Introducing this function to reduce code
>> replication in multiple drivers.
>>
>> Signed-off-by: Kirti Wankhede <kwankhede@nvidia.com>
>> Signed-off-by: Neo Jia <cjia@nvidia.com>
>> Change-Id: Ie201f269dda0713ca18a07dc4852500bd8b48309
>> ---
>>  drivers/vfio/vfio.c  | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/vfio.h |  4 ++++
>>  2 files changed, 52 insertions(+)
>>
>> diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
>> index 9a03be0942a1..ed2361e4b904 100644
>> --- a/drivers/vfio/vfio.c
>> +++ b/drivers/vfio/vfio.c
>> @@ -1858,6 +1858,54 @@ int vfio_info_add_capability(struct vfio_info_cap *caps, int cap_type_id,
>>  }
>>  EXPORT_SYMBOL(vfio_info_add_capability);
>>  
>> +int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs,
>> +				       int max_irq_type, size_t *data_size)
>> +{
>> +	unsigned long minsz;
>> +	size_t size;
>> +
>> +	minsz = offsetofend(struct vfio_irq_set, count);
>> +
>> +	if ((hdr->argsz < minsz) || (hdr->index >= max_irq_type) ||
>> +	    (hdr->count >= (U32_MAX - hdr->start)) ||
>> +	    (hdr->flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
>> +				VFIO_IRQ_SET_ACTION_TYPE_MASK)))
>> +		return -EINVAL;
>> +
>> +	if (data_size)
> 
> Pointless check, the callers will pass non null pointer with value
> initialized to 0 anyway.
> 

Not always, When VFIO_IRQ_SET_DATA_NONE flag is set, caller can pass
data_size = NULL.

> 
>> +		*data_size = 0;
>> +
>> +	if (hdr->start >= num_irqs || hdr->start + hdr->count > num_irqs)
>> +		return -EINVAL;
>> +
>> +	switch (hdr->flags & VFIO_IRQ_SET_DATA_TYPE_MASK) {
>> +	case VFIO_IRQ_SET_DATA_NONE:
>> +		size = 0;
>> +		break;
>> +	case VFIO_IRQ_SET_DATA_BOOL:
>> +		size = sizeof(uint8_t);
>> +		break;
>> +	case VFIO_IRQ_SET_DATA_EVENTFD:
>> +		size = sizeof(int32_t);
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (size) {
> 
> The whole branch would even work for size == 0.
> 

In that case below check (!data_size) might result in error if data_size
== NULL, whereas its not error case when size == 0, i.e.
VFIO_IRQ_SET_DATA_NONE flag set.

>> +		if (hdr->argsz - minsz < hdr->count * size)
>> +			return -EINVAL;
>> +
>> +		if (!data_size)
>> +			return -EINVAL;
> 
> Redundant check as well.
> 

This is not redundant. If you see above check, it sets its init value to
0 but doesn't fail.

>> +
>> +		*data_size = hdr->count * size;
>> +	}
>> +
>> +	return 0;
>> +}
> 
> It does not really prepare anything as the name suggests. It looks like
> this is 2 different helpers actually:
> 
> int vfio_set_irqs_validate()
> and
> size_t vfio_set_irqs_hdr_to_data_size()
> 

Later one is the prepare.

> 
> And it would make it easier to review/bisect if 16/22 and 17/22 were merged
> into this one as this patch alone adds new code which it does not use and
> all 3 patches are fairly small.
>

I do had all 3 patch merged in one in earlier version of patchset. This
is split as per Alex's suggestion.

> 
>> +EXPORT_SYMBOL(vfio_set_irqs_validate_and_prepare);
> 
> Everything you export in this patchset is EXPORT_SYMBOL() while the
> existing code uses EXPORT_SYMBOL_GPL(), is this for a reason?
> 
> 

We want these symbols to be available to all drivers.

Thanks,
Kirti

>> +
>>  /*
>>   * Pin a set of guest PFNs and return their associated host PFNs for local
>>   * domain only.
>> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
>> index cf90393a11e2..87c9afecd822 100644
>> --- a/include/linux/vfio.h
>> +++ b/include/linux/vfio.h
>> @@ -116,6 +116,10 @@ extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);
>>  extern int vfio_info_add_capability(struct vfio_info_cap *caps,
>>  				    int cap_type_id, void *cap_type);
>>  
>> +extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr,
>> +					      int num_irqs, int max_irq_type,
>> +					      size_t *data_size);
>> +
>>  struct pci_dev;
>>  #ifdef CONFIG_EEH
>>  extern void vfio_spapr_pci_eeh_open(struct pci_dev *pdev);
>>
> 
> 

^ permalink raw reply

* Re: Adding new CAN driver
From: Oliver Hartkopp @ 2016-11-08 20:19 UTC (permalink / raw)
  To: Ramesh Shanmugasundaram, Kurt Van Dijck
  Cc: Kołłątaj, Remigiusz, Alexander Stein,
	Marc Kleine-Budde, Uwe Bonnes, linux-can@vger.kernel.org
In-Reply-To: <SG2PR06MB1038E2022EEA5837EB6BD25BC3A60@SG2PR06MB1038.apcprd06.prod.outlook.com>

On 11/08/2016 10:36 AM, Ramesh Shanmugasundaram wrote:
>>>> for now, IFLA_CAN_TERMINATION may be a boolean (or enumeration).
>>>
>>> ACK. We could start simple with a bool.
>>
>> I would suggest to support a variable resistor (varistor) ranging from 1
>> to 65534 Ohms and a list of discrete termination values as suggested.
>
> If there are use cases for such variable resistor configs, it is OK.
>

I double checked the varistors currently used in CAN context.
They are used to provide ESD (electrostatic discharge) protection %-)

So having a discrete list of discrete termination resistors would 
obviously be sufficient for our use-case.

>>
>> diff --git a/include/uapi/linux/can/netlink.h
>> b/include/uapi/linux/can/netlink.h
>> index 94ffe0c..a07601a 100644
>> --- a/include/uapi/linux/can/netlink.h
>> +++ b/include/uapi/linux/can/netlink.h
>> @@ -91,6 +91,32 @@ struct can_ctrlmode {
>>   	__u32 flags;
>>   };
>>
>> +/*
>> + * CAN hardware-dependent termination resistor constants
>> + *
>> + * Capabilities shown by ip tool if supported by CAN hardware
>
> "Capabilities shown by ip tool if managed by CAN driver" - would that be apt?
> As termination is provided on the CAN bus by somebody (DB9 connector/fixed on board termination/gpio managed etc.), this would clarify the driver's role in managing it.
>
>> + * Unsupported values are filled with zero (CAN_RESISTOR_INVALID)  */
>> +struct can_termination_const {
>> +
>> +	/* range for programmable resistor (if supported) */
>> +	__u16 range_low;	/* lowermost resistor value (Ohm) */
>> +	__u16 range_high;	/* highest resistor value (Ohm) */

Will remove this resistor range stuff next time.

>> +
>> +	/* array of supported discrete resistor values (Ohm) */
>> +	__u16 term[8];

Do you think 8 resistor values are enough?

>> +};
>> +
>> +/*
>> + * CAN termination
>> + */
>> +struct can_termination {
>> +	__u16 term;
>> +};
>> +
>> +#define CAN_RESISTOR_INVALID	0x0000U	/* indicates no value /
>> unsupported */
>> +#define CAN_RESISTOR_DISABLED	0xFFFFU	/* indicates disabled
>> termination */
>> +
>>   #define CAN_CTRLMODE_LOOPBACK		0x01	/* Loopback mode */
>>   #define CAN_CTRLMODE_LISTENONLY		0x02	/* Listen-only mode */
>>   #define CAN_CTRLMODE_3_SAMPLES		0x04	/* Triple sampling mode */
>> @@ -127,6 +153,8 @@ enum {
>>   	IFLA_CAN_BERR_COUNTER,
>>   	IFLA_CAN_DATA_BITTIMING,
>>   	IFLA_CAN_DATA_BITTIMING_CONST,
>> +	IFLA_CAN_TERMINATION,
>> +	IFLA_CAN_TERMINATION_CONST,
>>   	__IFLA_CAN_MAX
>>   };
>>
>> With this interface the ip tool can get the capabilities of the
>> termination analogue to the BITTIMING_CONST values.
>> And it can set the termination with IFLA_CAN_TERMINATION.
>
> ACK.
>
>> The CAN driver would provide a struct can_termination_const - in the case
>> the CAN interface supports termination control.
>>
>> E.g. the mcba_usb driver would provide this:
>>
>> static struct can_termination_const = {
>> 	.range_low = CAN_RESISTOR_INVALID;
>> 	.range_high = CAN_RESISTOR_INVALID;
>> 	.term = { 120, CAN_RESISTOR_DISABLED, CAN_RESISTOR_INVALID }; }
>>
>> Another driver supporting 60 and 120 Ohms but no possibility to disable
>> the termination:
>>
>> static struct can_termination_const = {
>> 	.range_low = CAN_RESISTOR_INVALID;
>> 	.range_high = CAN_RESISTOR_INVALID;
>> 	.term = { 60, 120, CAN_RESISTOR_INVALID }; }
>>
>> Another driver supporting 60 to 5600 Ohms varistor and the possibility to
>> disable the termination:
>>
>> static struct can_termination_const = {
>> 	.range_low = 60;
>> 	.range_high = 5600;
>> 	.term = { CAN_RESISTOR_DISABLED, CAN_RESISTOR_INVALID }; }
>>
>> These termination capabilities might be provided by device tree
>> configuration too - although I don't know how this would be done.
>
> I think it can be something like this
>
> Board DTS file
> &can0 {
> 	...
> 	can-termination = <120>;	/* default value */
> 	
> 	/* GPIO managed */
> 	can-term-gpio = <&gpio0 10 GPIO_ACTIVE_HIGH>;
> 	...
>
> 	/* Regulator managed */
> 	can-term-supply = <&phandle to regulator node>
> };
>
> The driver could manage the respective GPIO/regulator from the phandle. The MMC subsystem code has examples of such config.
>
> Complex cases could use a driver specific hook (as with bittiming) to set TERM values.
>
>>
>> What do you think about this kind of configuration interface?
>>
>
> ACK.
> USB, PCI based CAN designers may have some suggestions/requirements?

Yep.

Anyone?

Regards,
Oliver


^ permalink raw reply

* [PATCH] drm/i915/gen9: fix the WM memory bandwidth WA for Y tiling cases
From: Paulo Zanoni @ 2016-11-08 20:22 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni, stable, Mahesh Kumar

The previous spec version said "double Ytile planes minimum lines",
and I interpreted this as referring to what the spec calls "Y tile
minimum", but in fact it was referring to what the spec calls "Minimum
Scanlines for Y tile". I noticed that Mahesh Kumar had a different
interpretation, so I sent and email to the spec authors and got
clarification on the correct meaning. Also, BSpec was updated and
should be clear now.

Fixes: ee3d532fcb64 ("drm/i915/gen9: unconditionally apply the memory bandwidth WA")
Cc: stable@vger.kernel.org
Cc: Mahesh Kumar <mahesh1.kumar@intel.com>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index cc9e0c0..653525f 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3624,6 +3624,9 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 		y_min_scanlines = 4;
 	}
 
+	if (apply_memory_bw_wa)
+		y_min_scanlines *= 2;
+
 	plane_bytes_per_line = width * cpp;
 	if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 	    fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
@@ -3644,8 +3647,6 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 				 plane_blocks_per_line);
 
 	y_tile_minimum = plane_blocks_per_line * y_min_scanlines;
-	if (apply_memory_bw_wa)
-		y_tile_minimum *= 2;
 
 	if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 	    fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
-- 
2.7.4


^ permalink raw reply related

* [PATCH] drm/i915/gen9: fix the WM memory bandwidth WA for Y tiling cases
From: Paulo Zanoni @ 2016-11-08 20:22 UTC (permalink / raw)
  To: intel-gfx; +Cc: Paulo Zanoni, stable

The previous spec version said "double Ytile planes minimum lines",
and I interpreted this as referring to what the spec calls "Y tile
minimum", but in fact it was referring to what the spec calls "Minimum
Scanlines for Y tile". I noticed that Mahesh Kumar had a different
interpretation, so I sent and email to the spec authors and got
clarification on the correct meaning. Also, BSpec was updated and
should be clear now.

Fixes: ee3d532fcb64 ("drm/i915/gen9: unconditionally apply the memory bandwidth WA")
Cc: stable@vger.kernel.org
Cc: Mahesh Kumar <mahesh1.kumar@intel.com>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index cc9e0c0..653525f 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3624,6 +3624,9 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 		y_min_scanlines = 4;
 	}
 
+	if (apply_memory_bw_wa)
+		y_min_scanlines *= 2;
+
 	plane_bytes_per_line = width * cpp;
 	if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 	    fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
@@ -3644,8 +3647,6 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 				 plane_blocks_per_line);
 
 	y_tile_minimum = plane_blocks_per_line * y_min_scanlines;
-	if (apply_memory_bw_wa)
-		y_tile_minimum *= 2;
 
 	if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
 	    fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related

* [Qemu-devel] [kvm-unit-tests PATCH v4 11/11] arm/arm64: gic: don't just use zero
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

Allow user to select who sends ipis and with which irq,
rather than just always sending irq=0 from cpu0.

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v4: improve structure and make sure spurious checking is
    done even when the sender isn't cpu0
v2: actually check that the irq received was the irq sent,
    and (for gicv2) that the sender is the expected one.
---
 arm/gic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 73 insertions(+), 26 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index d98ca6b9efd5..8e50bc1b35e0 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -11,6 +11,7 @@
  * This work is licensed under the terms of the GNU LGPL, version 2.
  */
 #include <libcflat.h>
+#include <util.h>
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/gic.h>
@@ -34,6 +35,8 @@ static struct gic *gic;
 static int gic_version;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
+static int sender;
+static u32 irq;
 
 static void nr_cpu_check(int nr)
 {
@@ -86,7 +89,16 @@ static void check_acked(cpumask_t *mask)
 
 static u32 gicv2_read_iar(void)
 {
-	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	int src = (iar >> 10) & 7;
+
+	if (src != sender) {
+		report("cpu%d received IPI from unexpected source cpu%d "
+		       "(expected cpu%d)",
+		       false, smp_processor_id(), src, sender);
+	}
+
+	return iar;
 }
 
 static u32 gicv2_irqnr(u32 iar)
@@ -111,9 +123,15 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 	if (irqnr != GICC_INT_SPURIOUS) {
 		gic->write_eoi(irqstat);
-		smp_rmb(); /* pairs with wmb in ipi_test functions */
-		++acked[smp_processor_id()];
-		smp_wmb(); /* pairs with rmb in check_acked */
+		if (irqnr == irq) {
+			smp_rmb(); /* pairs with wmb in ipi_test functions */
+			++acked[smp_processor_id()];
+			smp_wmb(); /* pairs with rmb in check_acked */
+		} else {
+			report("cpu%d received unexpected irq %u "
+			       "(expected %u)",
+			       false, smp_processor_id(), irqnr, irq);
+		}
 	} else {
 		++spurious[smp_processor_id()];
 		smp_wmb();
@@ -122,19 +140,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 static void gicv2_ipi_send_self(void)
 {
-	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(2 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 static void gicv2_ipi_send_tlist(cpumask_t *mask)
 {
 	u8 tlist = (u8)cpumask_bits(mask)[0];
 
-	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(tlist << 16 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 static void gicv2_ipi_send_broadcast(void)
 {
-	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(1 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 #define ICC_SGI1R_AFFINITY_1_SHIFT	16
@@ -200,7 +218,7 @@ static void gicv3_ipi_send_tlist(cpumask_t *mask)
 		/* Send the IPIs for the target list of this cluster */
 		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
 			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
-			 /* irq << 24				| */
+			 irq << 24				|
 			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
 			 tlist);
 
@@ -222,7 +240,7 @@ static void gicv3_ipi_send_self(void)
 
 static void gicv3_ipi_send_broadcast(void)
 {
-	gicv3_write_sgi1r(1ULL << 40);
+	gicv3_write_sgi1r(1ULL << 40 | irq << 24);
 	isb();
 }
 
@@ -234,7 +252,7 @@ static void ipi_test_self(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_clear(&mask);
-	cpumask_set_cpu(0, &mask);
+	cpumask_set_cpu(smp_processor_id(), &mask);
 	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
@@ -249,7 +267,7 @@ static void ipi_test_smp(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
-	for (i = 0; i < nr_cpus; i += 2)
+	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
 		cpumask_clear_cpu(i, &mask);
 	gic->ipi.send_tlist(&mask);
 	check_acked(&mask);
@@ -259,7 +277,7 @@ static void ipi_test_smp(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
-	cpumask_clear_cpu(0, &mask);
+	cpumask_clear_cpu(smp_processor_id(), &mask);
 	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
@@ -276,6 +294,27 @@ static void ipi_enable(void)
 	local_irq_enable();
 }
 
+static void ipi_send(void)
+{
+	int cpu;
+
+	ipi_enable();
+	wait_on_ready();
+	ipi_test_self();
+	ipi_test_smp();
+
+	smp_rmb();
+	for_each_present_cpu(cpu) {
+		if (spurious[cpu]) {
+			printf("ipi: WARN: cpu%d got %d spurious "
+			       "interrupts\n",
+			       spurious[cpu], smp_processor_id());
+		}
+	}
+
+	exit(report_summary());
+}
+
 static void ipi_recv(void)
 {
 	ipi_enable();
@@ -284,6 +323,14 @@ static void ipi_recv(void)
 		wfi();
 }
 
+static void ipi_test(void)
+{
+	if (smp_processor_id() == sender)
+		ipi_send();
+	else
+		ipi_recv();
+}
+
 struct gic gicv2 = {
 	.ipi = {
 		.enable = gicv2_enable_defaults,
@@ -337,30 +384,30 @@ int main(int argc, char **argv)
 		report_prefix_pop();
 
 	} else if (!strcmp(argv[1], "ipi")) {
+		int off, i = 1;
+		long val;
 
 		report_prefix_push(argv[1]);
 		nr_cpu_check(2);
 
-		for_each_present_cpu(cpu) {
-			if (cpu == 0)
+		while (--argc != 1) {
+			off = parse_keyval(argv[++i], &val);
+			if (off == -1)
 				continue;
-			smp_boot_secondary(cpu, ipi_recv);
+			argv[i][off] = '\0';
+			if (strcmp(argv[i], "sender") == 0)
+				sender = val;
+			else if (strcmp(argv[i], "irq") == 0)
+				irq = val;
 		}
-		ipi_enable();
-		wait_on_ready();
-		ipi_test_self();
-		ipi_test_smp();
 
-		smp_rmb();
 		for_each_present_cpu(cpu) {
-			if (spurious[cpu]) {
-				printf("ipi: WARN: cpu%d got %d spurious "
-				       "interrupts\n",
-				       spurious[cpu], smp_processor_id());
-			}
+			if (cpu == 0)
+				continue;
+			smp_boot_secondary(cpu, ipi_test);
 		}
 
-		report_prefix_pop();
+		ipi_test();
 
 	} else {
 		report_abort("Unknown subtest '%s'", argv[1]);
-- 
2.7.4

^ permalink raw reply related

* Re: [v4.9-rc4] dvb-usb/cinergyT2 NULL pointer dereference
From: Mauro Carvalho Chehab @ 2016-11-08 20:22 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Jörg Otte, Patrick Boettcher, Mauro Carvalho Chehab,
	Linux Kernel Mailing List, Linux Media Mailing List
In-Reply-To: <CA+55aFxXoc3GzAXWPZL=RB2xhmhP1acR3m2S_mdoiO97+80kDA@mail.gmail.com>

Em Tue, 8 Nov 2016 10:42:03 -0800
Linus Torvalds <torvalds@linux-foundation.org> escreveu:

> On Sun, Nov 6, 2016 at 7:40 AM, Jörg Otte <jrg.otte@gmail.com> wrote:
> > Since v4.9-rc4 I get following crash in dvb-usb-cinergyT2 module.  
> 
> Looks like it's commit 5ef8ed0e5608f ("[media] cinergyT2-core: don't
> do DMA on stack"), which movced the DMA data array from the stack to
> the "private" pointer. In the process it also added serialization in
> the form of "data_mutex", but and now it oopses on that mutex because
> the private pointer is NULL.
> 
> It looks like the "->private" pointer is allocated in dvb_usb_adapter_init()
> 
> cinergyt2_usb_probe ->
>   dvb_usb_device_init ->
>     dvb_usb_init() ->
>       dvb_usb_adapter_init()
> 
> but the dvb_usb_init() function calls dvb_usb_device_power_ctrl()
> (which calls the "power_ctrl" function, which is
> cinergyt2_power_ctrl() for that drive) *before* it initializes the
> private field.
> 
> Mauro, Patrick, could dvb_usb_adapter_init() be called earlier, perhaps?

Calling it earlier won't work, as we need to load the firmware before
sending the power control commands on some devices.

Probably the best here is to pass an extra optional function parameter
that will initialize the mutex before calling any functions.

Btw, if it broke here, the DMA fixes will likely break on other drivers.
So, after Jörg tests this patch, I'll work on a patch series addressing
this issue on the other drivers I touched.

Regards,
Mauro

-

[PATCH RFC] cinergyT2-core: initialize the mutex early

NOTE: don't merge this patch as-is... I actually folded two patches
together here, in order to make easier to test, but the best is to
place the changes at the core first, and then the changes at the
drivers that would need an early init.

The mutex used to protect the URB data buffer needs to be
inialized early, as otherwise it will cause an OOPS:

dvb-usb: found a 'TerraTec/qanu USB2.0 Highspeed DVB-T Receiver' in warm state.
BUG: unable to handle kernel NULL pointer dereference at           (null)
IP: [<ffffffff846617af>] __mutex_lock_slowpath+0x6f/0x100 PGD 0
Oops: 0002 [#1] SMP
Modules linked in: dvb_usb_cinergyT2(+) dvb_usb
CPU: 0 PID: 2029 Comm: modprobe Not tainted 4.9.0-rc4-dvbmod #24
Hardware name: FUJITSU LIFEBOOK A544/FJNBB35 , BIOS Version 1.17 05/09/2014
task: ffff88020e943840 task.stack: ffff8801f36ec000
RIP: 0010:[<ffffffff846617af>]  [<ffffffff846617af>] __mutex_lock_slowpath+0x6f/0x100
RSP: 0018:ffff8801f36efb10  EFLAGS: 00010282
RAX: 0000000000000000 RBX: ffff88021509bdc8 RCX: 00000000c0000100
RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff88021509bdcc
RBP: ffff8801f36efb58 R08: ffff88021f216320 R09: 0000000000100000
R10: ffff88021f216320 R11: 00000023fee6c5a1 R12: ffff88020e943840
R13: ffff88021509bdcc R14: 00000000ffffffff R15: ffff88021509bdd0
FS:  00007f21adb86740(0000) GS:ffff88021f200000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 0000000215bce000 CR4: 00000000001406f0
Stack:
 ffff88021509bdd0 0000000000000000 0000000000000000 ffffffffc0137c80
 ffff88021509bdc8 ffff8801f5944000 0000000000000001 ffffffffc0136b00
 ffff880213e52000 ffff88021509bdc8 ffffffff84661856 ffff88021509bd80
Call Trace:
 [<ffffffff84661856>] ? mutex_lock+0x16/0x25
 [<ffffffffc013616f>] ? cinergyt2_power_ctrl+0x1f/0x60 [dvb_usb_cinergyT2]
 [<ffffffffc012e67e>] ? dvb_usb_device_init+0x21e/0x5d0 [dvb_usb]
 [<ffffffffc0136021>] ? cinergyt2_usb_probe+0x21/0x50 [dvb_usb_cinergyT2]
 [<ffffffff844326f3>] ? usb_probe_interface+0xf3/0x2a0
 [<ffffffff8438e348>] ? driver_probe_device+0x208/0x2b0
 [<ffffffff8438e477>] ? __driver_attach+0x87/0x90
 [<ffffffff8438e3f0>] ? driver_probe_device+0x2b0/0x2b0
 [<ffffffff8438c612>] ? bus_for_each_dev+0x52/0x80
 [<ffffffff8438d983>] ? bus_add_driver+0x1a3/0x220
 [<ffffffff8438ec06>] ? driver_register+0x56/0xd0
 [<ffffffff84431527>] ? usb_register_driver+0x77/0x130
 [<ffffffffc013a000>] ? 0xffffffffc013a000
 [<ffffffff84000426>] ? do_one_initcall+0x46/0x180
 [<ffffffff840eb2c8>] ? free_vmap_area_noflush+0x38/0x70
 [<ffffffff840f3844>] ? kmem_cache_alloc+0x84/0xc0
 [<ffffffff840b802c>] ? do_init_module+0x50/0x1be
 [<ffffffff84095adb>] ? load_module+0x1d8b/0x2100
 [<ffffffff84093020>] ? find_symbol_in_section+0xa0/0xa0
 [<ffffffff84095fe9>] ? SyS_finit_module+0x89/0x90
 [<ffffffff846637a0>] ? entry_SYSCALL_64_fastpath+0x13/0x94
Code: e8 a7 1d 00 00 8b 03 83 f8 01 0f 84 97 00 00 00 48 8b 43 10 4c 8d 7b 08 48 89 63 10 4c 89 3c 24 41 be ff ff ff ff 48 89 44 24 08 <48> 89 20 4c 89 64 24 10 eb 1a 49 c7 44 24 08 02 00 00 00 c6 43 RIP  [<ffffffff846617af>] __mutex_lock_slowpath+0x6f/0x100 RSP <ffff8801f36efb10>
CR2: 0000000000000000

Reported-by: Jörg Otte <jrg.otte@gmail.com>
Fixes: 6679a901c380 ("[media] cinergyT2-core: don't do DMA on stack")
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

>From cbc7e48a86e8ffd16e49b10061120dfc417397f8 Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Date: Tue, 8 Nov 2016 18:04:24 -0200
Subject: [PATCH] [media] dvb-usb: allow early initialization of usb device
 priv data

On some drivers, we need to initialize a mutex before calling
power control or firmware download routines. Add an extra
parameter to allow it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c
index 7ba975bea96a..1e14f79aa57a 100644
--- a/drivers/media/usb/dvb-usb/a800.c
+++ b/drivers/media/usb/dvb-usb/a800.c
@@ -107,7 +107,7 @@ static int a800_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	return dvb_usb_device_init(intf, &a800_properties,
-				   THIS_MODULE, NULL, adapter_nr);
+				   THIS_MODULE, NULL, adapter_nr, NULL);
 }
 
 /* do not change the order of the ID table */
diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c
index b257780fb380..1625b4714d83 100644
--- a/drivers/media/usb/dvb-usb/af9005.c
+++ b/drivers/media/usb/dvb-usb/af9005.c
@@ -1009,7 +1009,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
 	int ret;
 
 	ret = dvb_usb_device_init(intf, &af9005_properties,
-				  THIS_MODULE, &d, adapter_nr);
+				  THIS_MODULE, &d, adapter_nr, NULL);
 
 	if (ret < 0)
 		return ret;
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
index 2e711362847e..e8f73a96efd9 100644
--- a/drivers/media/usb/dvb-usb/az6027.c
+++ b/drivers/media/usb/dvb-usb/az6027.c
@@ -946,7 +946,7 @@ static int az6027_usb_probe(struct usb_interface *intf,
 				   &az6027_properties,
 				   THIS_MODULE,
 				   NULL,
-				   adapter_nr);
+				   adapter_nr, NULL);
 }
 
 /* I2C */
diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c
index 8ac825413d5a..2aa99c52e39d 100644
--- a/drivers/media/usb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c
@@ -206,24 +206,21 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 	return ret;
 }
 
-static int cinergyt2_usb_probe(struct usb_interface *intf,
-				const struct usb_device_id *id)
+static int cinergyT2_init_mutex(struct dvb_usb_device *d)
 {
-	struct dvb_usb_device *d;
-	struct cinergyt2_state *st;
-	int ret;
-
-	ret = dvb_usb_device_init(intf, &cinergyt2_properties,
-				  THIS_MODULE, &d, adapter_nr);
-	if (ret < 0)
-		return ret;
+	struct cinergyt2_state *st = d->priv;
 
-	st = d->priv;
 	mutex_init(&st->data_mutex);
-
 	return 0;
 }
 
+static int cinergyt2_usb_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &cinergyt2_properties,
+				   THIS_MODULE, NULL, adapter_nr,
+				   cinergyT2_init_mutex);
+}
 
 static struct usb_device_id cinergyt2_usb_table[] = {
 	{ USB_DEVICE(USB_VID_TERRATEC, 0x0038) },
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 39772812269d..73c1a8568b55 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -1465,33 +1465,33 @@ static int cxusb_probe(struct usb_interface *intf,
 	struct cxusb_state *st;
 
 	if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf,
 				&cxusb_bluebird_nano2_needsfirmware_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf,
 				     &cxusb_bluebird_dualdig4_rev2_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0) {
 		st = d->priv;
 		mutex_init(&st->data_mutex);
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index 92d5408684ac..3423b56c92b3 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -871,7 +871,7 @@ static int dib0700_probe(struct usb_interface *intf,
 
 	for (i = 0; i < dib0700_device_count; i++)
 		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE,
-		    &dev, adapter_nr) == 0) {
+		    &dev, adapter_nr, NULL) == 0) {
 			struct dib0700_state *st = dev->priv;
 			u32 hwversion, romversion, fw_version, fwtype;
 
diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c
index a0057641cc86..de4ffe81e8d7 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mb.c
@@ -111,13 +111,13 @@ static int dibusb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	if (0 == dvb_usb_device_init(intf, &dibusb1_1_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
+				     THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &dibusb1_1_an2235_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
+				     THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &dibusb2_0b_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
+				     THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &artec_t1_usb2_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+				     THIS_MODULE, NULL, adapter_nr, NULL))
 		return 0;
 
 	return -EINVAL;
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c
index 08fb8a3f6e0c..d50731bb5372 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mc.c
@@ -23,7 +23,7 @@ static int dibusb_mc_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	return dvb_usb_device_init(intf, &dibusb_mc_properties, THIS_MODULE,
-				   NULL, adapter_nr);
+				   NULL, adapter_nr, NULL);
 }
 
 /* do not change the order of the ID table */
diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c
index 4284f6984dc1..3dad2293e598 100644
--- a/drivers/media/usb/dvb-usb/digitv.c
+++ b/drivers/media/usb/dvb-usb/digitv.c
@@ -269,7 +269,7 @@ static int digitv_probe(struct usb_interface *intf,
 {
 	struct dvb_usb_device *d;
 	int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d,
-				      adapter_nr);
+				      adapter_nr, NULL);
 	if (ret == 0) {
 		u8 b[4] = { 0 };
 
diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c
index f88572c7ae7c..3255fee31433 100644
--- a/drivers/media/usb/dvb-usb/dtt200u.c
+++ b/drivers/media/usb/dvb-usb/dtt200u.c
@@ -149,15 +149,15 @@ static int dtt200u_usb_probe(struct usb_interface *intf,
 	struct dtt200u_state *st;
 
 	if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &wt220u_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
-				     THIS_MODULE, &d, adapter_nr) ||
+				     THIS_MODULE, &d, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
-				     THIS_MODULE, &d, adapter_nr)) {
+				     THIS_MODULE, &d, adapter_nr, NULL)) {
 		st = d->priv;
 		mutex_init(&st->data_mutex);
 
diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c
index c60fb54f445f..36b553cb3133 100644
--- a/drivers/media/usb/dvb-usb/dtv5100.c
+++ b/drivers/media/usb/dvb-usb/dtv5100.c
@@ -165,7 +165,7 @@ static int dtv5100_probe(struct usb_interface *intf,
 	}
 
 	ret = dvb_usb_device_init(intf, &dtv5100_properties,
-				  THIS_MODULE, NULL, adapter_nr);
+				  THIS_MODULE, NULL, adapter_nr, NULL);
 	if (ret)
 		return ret;
 
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index 3896ba9a4179..66493fb25645 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -138,23 +138,14 @@ static int dvb_usb_exit(struct dvb_usb_device *d)
 	return 0;
 }
 
-static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
+static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums,
+			int (init_device)(struct dvb_usb_device *d))
 {
 	int ret = 0;
 
 	mutex_init(&d->usb_mutex);
 	mutex_init(&d->i2c_mutex);
 
-	d->state = DVB_USB_STATE_INIT;
-
-	if (d->props.size_of_priv > 0) {
-		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
-		if (d->priv == NULL) {
-			err("no memory for priv in 'struct dvb_usb_device'");
-			return -ENOMEM;
-		}
-	}
-
 	/* check the capabilities and set appropriate variables */
 	dvb_usb_device_power_ctrl(d, 1);
 
@@ -233,7 +224,8 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
 int dvb_usb_device_init(struct usb_interface *intf,
 			struct dvb_usb_device_properties *props,
 			struct module *owner, struct dvb_usb_device **du,
-			short *adapter_nums)
+			short *adapter_nums,
+			int (init_device)(struct dvb_usb_device *d))
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct dvb_usb_device *d = NULL;
@@ -249,19 +241,42 @@ int dvb_usb_device_init(struct usb_interface *intf,
 		return -ENODEV;
 	}
 
-	if (cold) {
-		info("found a '%s' in cold state, will try to load a firmware", desc->name);
-		ret = dvb_usb_download_firmware(udev, props);
-		if (!props->no_reconnect || ret != 0)
-			return ret;
-	}
-
-	info("found a '%s' in warm state.", desc->name);
 	d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
 	if (d == NULL) {
 		err("no memory for 'struct dvb_usb_device'");
 		return -ENOMEM;
 	}
+	d->state = DVB_USB_STATE_INIT;
+
+	if (d->props.size_of_priv > 0) {
+		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
+		if (d->priv == NULL) {
+			err("no memory for priv in 'struct dvb_usb_device'");
+			ret = -ENOMEM;
+			goto err;
+		}
+	}
+
+	/*
+	 * Some drivers may need to early initialize the device private data,
+	 * for example, when a mutex is serializing URB reads/writes,
+	 * in order for dvb_usb_device_power_ctrl() or firmware load to work.
+	 */
+	if (init_device) {
+		ret = init_device(d);
+		if (ret < 0)
+			goto err;
+	}
+
+	if (cold) {
+		info("found a '%s' in cold state, will try to load a firmware",
+		     desc->name);
+		ret = dvb_usb_download_firmware(udev, props);
+		if (!props->no_reconnect || ret != 0)
+			goto err;
+	} else {
+		info("found a '%s' in warm state.", desc->name);
+	}
 
 	d->udev = udev;
 	memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
@@ -273,12 +288,17 @@ int dvb_usb_device_init(struct usb_interface *intf,
 	if (du != NULL)
 		*du = d;
 
-	ret = dvb_usb_init(d, adapter_nums);
+	ret = dvb_usb_init(d, adapter_nums, init_device);
 
-	if (ret == 0)
+	if (!ret) {
 		info("%s successfully initialized and connected.", desc->name);
-	else
-		info("%s error while loading driver (%d)", desc->name, ret);
+		return 0;
+	}
+err:
+	info("%s error while loading driver (%d)", desc->name, ret);
+
+	kfree(d->priv);
+	kfree(d);
 	return ret;
 }
 EXPORT_SYMBOL(dvb_usb_device_init);
diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h
index 1448c3d27ea2..02c4dd3c206a 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb.h
+++ b/drivers/media/usb/dvb-usb/dvb-usb.h
@@ -458,7 +458,9 @@ struct dvb_usb_device {
 extern int dvb_usb_device_init(struct usb_interface *,
 			       struct dvb_usb_device_properties *,
 			       struct module *, struct dvb_usb_device **,
-			       short *adapter_nums);
+			       short *adapter_nums,
+			       int (init_device)(struct dvb_usb_device *d));
+
 extern void dvb_usb_device_exit(struct usb_interface *);
 
 /* the generic read/write method for device control */
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 2c720cb2fb00..1cb8d96f485e 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -2284,27 +2284,27 @@ static int dw2102_probe(struct usb_interface *intf,
 	s421->adapter->fe[0].frontend_attach = m88rs2000_frontend_attach;
 
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &dw2104_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &dw3101_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &s6x0_properties,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, p1100,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, s660,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, p7500,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, s421,
-			THIS_MODULE, NULL, adapter_nr) ||
+			THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &su3000_properties,
-			 THIS_MODULE, NULL, adapter_nr) ||
+			 THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &t220_properties,
-			 THIS_MODULE, NULL, adapter_nr) ||
+			 THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &tt_s2_4600_properties,
-			 THIS_MODULE, NULL, adapter_nr))
+			 THIS_MODULE, NULL, adapter_nr, NULL))
 		return 0;
 
 	return -ENODEV;
diff --git a/drivers/media/usb/dvb-usb/friio.c b/drivers/media/usb/dvb-usb/friio.c
index 474a17e4db0c..3854ac7434ad 100644
--- a/drivers/media/usb/dvb-usb/friio.c
+++ b/drivers/media/usb/dvb-usb/friio.c
@@ -437,7 +437,7 @@ static int friio_probe(struct usb_interface *intf,
 	}
 
 	ret = dvb_usb_device_init(intf, &friio_properties,
-				  THIS_MODULE, &d, adapter_nr);
+				  THIS_MODULE, &d, adapter_nr, NULL);
 	if (ret == 0)
 		friio_streaming_ctrl(&d->adapter[0], 1);
 
diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c
index 2829e3082d15..cede0d8b0f8a 100644
--- a/drivers/media/usb/dvb-usb/gp8psk.c
+++ b/drivers/media/usb/dvb-usb/gp8psk.c
@@ -262,7 +262,7 @@ static int gp8psk_usb_probe(struct usb_interface *intf,
 	int ret;
 	struct usb_device *udev = interface_to_usbdev(intf);
 	ret = dvb_usb_device_init(intf, &gp8psk_properties,
-				  THIS_MODULE, NULL, adapter_nr);
+				  THIS_MODULE, NULL, adapter_nr, NULL);
 	if (ret == 0) {
 		info("found Genpix USB device pID = %x (hex)",
 			le16_to_cpu(udev->descriptor.idProduct));
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index eafc5c82467f..b4c83f36abee 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -835,14 +835,14 @@ static int m920x_probe(struct usb_interface *intf,
 		 */
 
 		ret = dvb_usb_device_init(intf, &megasky_properties,
-					  THIS_MODULE, &d, adapter_nr);
+					  THIS_MODULE, &d, adapter_nr, NULL);
 		if (ret == 0) {
 			rc_init_seq = megasky_rc_init;
 			goto found;
 		}
 
 		ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties,
-					  THIS_MODULE, &d, adapter_nr);
+					  THIS_MODULE, &d, adapter_nr, NULL);
 		if (ret == 0) {
 			/* No remote control, so no rc_init_seq */
 			goto found;
@@ -850,28 +850,28 @@ static int m920x_probe(struct usb_interface *intf,
 
 		/* This configures both tuners on the TV Walker Twin */
 		ret = dvb_usb_device_init(intf, &tvwalkertwin_properties,
-					  THIS_MODULE, &d, adapter_nr);
+					  THIS_MODULE, &d, adapter_nr, NULL);
 		if (ret == 0) {
 			rc_init_seq = tvwalkertwin_rc_init;
 			goto found;
 		}
 
 		ret = dvb_usb_device_init(intf, &dposh_properties,
-					  THIS_MODULE, &d, adapter_nr);
+					  THIS_MODULE, &d, adapter_nr, NULL);
 		if (ret == 0) {
 			/* Remote controller not supported yet. */
 			goto found;
 		}
 
 		ret = dvb_usb_device_init(intf, &pinnacle_pctv310e_properties,
-					  THIS_MODULE, &d, adapter_nr);
+					  THIS_MODULE, &d, adapter_nr, NULL);
 		if (ret == 0) {
 			rc_init_seq = pinnacle310e_init;
 			goto found;
 		}
 
 		ret = dvb_usb_device_init(intf, &vp7049_properties,
-					  THIS_MODULE, &d, adapter_nr);
+					  THIS_MODULE, &d, adapter_nr, NULL);
 		if (ret == 0) {
 			rc_init_seq = vp7049_rc_init;
 			goto found;
diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c
index 1babd3341910..0d8f06430ca5 100644
--- a/drivers/media/usb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c
@@ -157,7 +157,7 @@ static int nova_t_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	return dvb_usb_device_init(intf, &nova_t_properties,
-				   THIS_MODULE, NULL, adapter_nr);
+				   THIS_MODULE, NULL, adapter_nr, NULL);
 }
 
 /* do not change the order of the ID table */
diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
index 2566d2f1c2ad..9f2f156e2939 100644
--- a/drivers/media/usb/dvb-usb/opera1.c
+++ b/drivers/media/usb/dvb-usb/opera1.c
@@ -563,7 +563,7 @@ static int opera1_probe(struct usb_interface *intf,
 	}
 
 	if (0 != dvb_usb_device_init(intf, &opera1_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+				     THIS_MODULE, NULL, adapter_nr, NULL))
 		return -EINVAL;
 	return 0;
 }
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index 07fa08be9e99..2f844ff39840 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -1059,9 +1059,9 @@ static int pctv452e_usb_probe(struct usb_interface *intf,
 				const struct usb_device_id *id)
 {
 	if (0 == dvb_usb_device_init(intf, &pctv452e_properties,
-					THIS_MODULE, NULL, adapter_nr) ||
+					THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &tt_connect_s2_3600_properties,
-					THIS_MODULE, NULL, adapter_nr))
+					THIS_MODULE, NULL, adapter_nr, NULL))
 		return 0;
 
 	return -ENODEV;
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 4706628a3ed5..80fc5043e4cf 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -765,7 +765,7 @@ static int technisat_usb2_probe(struct usb_interface *intf,
 	struct dvb_usb_device *dev;
 
 	if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
-				&dev, adapter_nr) != 0)
+				&dev, adapter_nr, NULL) != 0)
 		return -ENODEV;
 
 	if (dev) {
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
index ecc207fbaf3c..192057ea58c0 100644
--- a/drivers/media/usb/dvb-usb/ttusb2.c
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
@@ -604,11 +604,11 @@ static int ttusb2_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
-				     THIS_MODULE, NULL, adapter_nr) ||
+				     THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
-				     THIS_MODULE, NULL, adapter_nr) ||
+				     THIS_MODULE, NULL, adapter_nr, NULL) ||
 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
-				     THIS_MODULE, NULL, adapter_nr))
+				     THIS_MODULE, NULL, adapter_nr, NULL))
 		return 0;
 	return -ENODEV;
 }
diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c
index 58ad5b4f856c..9af8cca5f2d2 100644
--- a/drivers/media/usb/dvb-usb/umt-010.c
+++ b/drivers/media/usb/dvb-usb/umt-010.c
@@ -78,7 +78,7 @@ static int umt_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	if (0 == dvb_usb_device_init(intf, &umt_properties,
-				     THIS_MODULE, NULL, adapter_nr))
+				     THIS_MODULE, NULL, adapter_nr, NULL))
 		return 0;
 	return -EINVAL;
 }
diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c
index 40de33de90a7..e95a84e3f9de 100644
--- a/drivers/media/usb/dvb-usb/vp702x.c
+++ b/drivers/media/usb/dvb-usb/vp702x.c
@@ -337,7 +337,7 @@ static int vp702x_usb_probe(struct usb_interface *intf,
 	int ret;
 
 	ret = dvb_usb_device_init(intf, &vp702x_properties,
-				   THIS_MODULE, &d, adapter_nr);
+				   THIS_MODULE, &d, adapter_nr, NULL);
 	if (ret)
 		goto out;
 
diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c
index 13340af0d39c..350603bbe3da 100644
--- a/drivers/media/usb/dvb-usb/vp7045.c
+++ b/drivers/media/usb/dvb-usb/vp7045.c
@@ -225,7 +225,7 @@ static int vp7045_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	return dvb_usb_device_init(intf, &vp7045_properties,
-				   THIS_MODULE, NULL, adapter_nr);
+				   THIS_MODULE, NULL, adapter_nr, NULL);
 }
 
 static struct usb_device_id vp7045_usb_table [] = {

^ permalink raw reply related

* [Qemu-devel] [kvm-unit-tests PATCH v4 10/11] arm/arm64: gicv3: add an IPI test
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v4:
 - heavily comment gicv3_ipi_send_tlist() [Eric]
 - changes needed for gicv2 iar/irqstat fix to other patch
v2:
 - use IRM for gicv3 broadcast
---
 arm/gic.c                  | 195 ++++++++++++++++++++++++++++++++++++++++++---
 arm/unittests.cfg          |   6 ++
 lib/arm/asm/arch_gicv3.h   |  23 ++++++
 lib/arm64/asm/arch_gicv3.h |  22 +++++
 4 files changed, 236 insertions(+), 10 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index efefab7296d4..d98ca6b9efd5 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -3,6 +3,8 @@
  *
  * GICv2
  *   + test sending/receiving IPIs
+ * GICv3
+ *   + test sending/receiving IPIs
  *
  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
@@ -16,6 +18,19 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
+struct gic {
+	struct {
+		void (*enable)(void);
+		void (*send_self)(void);
+		void (*send_tlist)(cpumask_t *);
+		void (*send_broadcast)(void);
+	} ipi;
+	u32 (*read_iar)(void);
+	u32 (*irqnr)(u32 iar);
+	void (*write_eoi)(u32);
+};
+
+static struct gic *gic;
 static int gic_version;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
@@ -69,13 +84,33 @@ static void check_acked(cpumask_t *mask)
 	       false, missing, extra, unexpected);
 }
 
+static u32 gicv2_read_iar(void)
+{
+	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+}
+
+static u32 gicv2_irqnr(u32 iar)
+{
+	return iar & GICC_IAR_INT_ID_MASK;
+}
+
+static void gicv2_write_eoi(u32 irqstat)
+{
+	writel(irqstat, gicv2_cpu_base() + GIC_CPU_EOI);
+}
+
+static u32 gicv3_irqnr(u32 iar)
+{
+	return iar;
+}
+
 static void ipi_handler(struct pt_regs *regs __unused)
 {
-	u32 irqstat = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
-	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	u32 irqstat = gic->read_iar();
+	u32 irqnr = gic->irqnr(irqstat);
 
 	if (irqnr != GICC_INT_SPURIOUS) {
-		writel(irqstat, gicv2_cpu_base() + GIC_CPU_EOI);
+		gic->write_eoi(irqstat);
 		smp_rmb(); /* pairs with wmb in ipi_test functions */
 		++acked[smp_processor_id()];
 		smp_wmb(); /* pairs with rmb in check_acked */
@@ -85,6 +120,112 @@ static void ipi_handler(struct pt_regs *regs __unused)
 	}
 }
 
+static void gicv2_ipi_send_self(void)
+{
+	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+static void gicv2_ipi_send_tlist(cpumask_t *mask)
+{
+	u8 tlist = (u8)cpumask_bits(mask)[0];
+
+	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+static void gicv2_ipi_send_broadcast(void)
+{
+	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+#define ICC_SGI1R_AFFINITY_1_SHIFT	16
+#define ICC_SGI1R_AFFINITY_2_SHIFT	32
+#define ICC_SGI1R_AFFINITY_3_SHIFT	48
+#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
+	(MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
+
+static void gicv3_ipi_send_tlist(cpumask_t *mask)
+{
+	u16 tlist;
+	int cpu;
+
+	/*
+	 * For each cpu in the mask collect its peers, which are also in
+	 * the mask, in order to form target lists.
+	 */
+	for_each_cpu(cpu, mask) {
+		u64 mpidr = cpus[cpu], sgi1r;
+		u64 cluster_id;
+
+		/*
+		 * GICv3 can send IPIs to up 16 peer cpus with a single
+		 * write to ICC_SGI1R_EL1 (using the target list). Peers
+		 * are cpus that have nearly identical MPIDRs, the only
+		 * difference being Aff0. The matching upper affinity
+		 * levels form the cluster ID.
+		 */
+		cluster_id = mpidr & ~0xffUL;
+		tlist = 0;
+
+		/*
+		 * Sort of open code for_each_cpu in order to have a
+		 * nested for_each_cpu loop.
+		 */
+		while (cpu < nr_cpus) {
+			if ((mpidr & 0xff) >= 16) {
+				printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
+					cpu, (int)(mpidr & 0xff));
+				break;
+			}
+
+			tlist |= 1 << (mpidr & 0xf);
+
+			cpu = cpumask_next(cpu, mask);
+			if (cpu >= nr_cpus)
+				break;
+
+			mpidr = cpus[cpu];
+
+			if (cluster_id != (mpidr & ~0xffUL)) {
+				/*
+				 * The next cpu isn't in our cluster. Roll
+				 * back the cpu index allowing the outer
+				 * for_each_cpu to find it again with
+				 * cpumask_next
+				 */
+				--cpu;
+				break;
+			}
+		}
+
+		/* Send the IPIs for the target list of this cluster */
+		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
+			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
+			 /* irq << 24				| */
+			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
+			 tlist);
+
+		gicv3_write_sgi1r(sgi1r);
+	}
+
+	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
+	isb();
+}
+
+static void gicv3_ipi_send_self(void)
+{
+	cpumask_t mask;
+
+	cpumask_clear(&mask);
+	cpumask_set_cpu(smp_processor_id(), &mask);
+	gicv3_ipi_send_tlist(&mask);
+}
+
+static void gicv3_ipi_send_broadcast(void)
+{
+	gicv3_write_sgi1r(1ULL << 40);
+	isb();
+}
+
 static void ipi_test_self(void)
 {
 	cpumask_t mask;
@@ -94,7 +235,7 @@ static void ipi_test_self(void)
 	smp_wmb();
 	cpumask_clear(&mask);
 	cpumask_set_cpu(0, &mask);
-	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
 }
@@ -102,14 +243,15 @@ static void ipi_test_self(void)
 static void ipi_test_smp(void)
 {
 	cpumask_t mask;
-	unsigned long tlist;
+	int i;
 
 	report_prefix_push("target-list");
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
-	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
-	cpumask_bits(&mask)[0] = tlist;
-	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	cpumask_copy(&mask, &cpu_present_mask);
+	for (i = 0; i < nr_cpus; i += 2)
+		cpumask_clear_cpu(i, &mask);
+	gic->ipi.send_tlist(&mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
@@ -118,14 +260,14 @@ static void ipi_test_smp(void)
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
 	cpumask_clear_cpu(0, &mask);
-	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
 }
 
 static void ipi_enable(void)
 {
-	gicv2_enable_defaults();
+	gic->ipi.enable();
 #ifdef __arm__
 	install_exception_handler(EXCPTN_IRQ, ipi_handler);
 #else
@@ -142,6 +284,30 @@ static void ipi_recv(void)
 		wfi();
 }
 
+struct gic gicv2 = {
+	.ipi = {
+		.enable = gicv2_enable_defaults,
+		.send_self = gicv2_ipi_send_self,
+		.send_tlist = gicv2_ipi_send_tlist,
+		.send_broadcast = gicv2_ipi_send_broadcast,
+	},
+	.read_iar = gicv2_read_iar,
+	.irqnr = gicv2_irqnr,
+	.write_eoi = gicv2_write_eoi,
+};
+
+struct gic gicv3 = {
+	.ipi = {
+		.enable = gicv3_enable_defaults,
+		.send_self = gicv3_ipi_send_self,
+		.send_tlist = gicv3_ipi_send_tlist,
+		.send_broadcast = gicv3_ipi_send_broadcast,
+	},
+	.read_iar = gicv3_read_iar,
+	.irqnr = gicv3_irqnr,
+	.write_eoi = gicv3_write_eoir,
+};
+
 int main(int argc, char **argv)
 {
 	char pfx[8];
@@ -154,6 +320,15 @@ int main(int argc, char **argv)
 	snprintf(pfx, 8, "gicv%d", gic_version);
 	report_prefix_push(pfx);
 
+	switch (gic_version) {
+	case 2:
+		gic = &gicv2;
+		break;
+	case 3:
+		gic = &gicv3;
+		break;
+	}
+
 	if (argc < 2) {
 
 		report_prefix_push("ipi");
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index 68bf5cd6008f..ce3cee73c4bf 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -61,3 +61,9 @@ file = gic.flat
 smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
 extra_params = -machine gic-version=2 -append 'ipi'
 groups = gic
+
+[gicv3-ipi]
+file = gic.flat
+smp = $MAX_SMP
+extra_params = -machine gic-version=3 -append 'ipi'
+groups = gic
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
index 81a1e5f6c29c..cbcec024a2a6 100644
--- a/lib/arm/asm/arch_gicv3.h
+++ b/lib/arm/asm/arch_gicv3.h
@@ -16,10 +16,28 @@
 #define __stringify xstr
 
 #define __ACCESS_CP15(CRn, Op1, CRm, Op2)	p15, Op1, %0, CRn, CRm, Op2
+#define __ACCESS_CP15_64(Op1, CRm)		p15, Op1, %Q0, %R0, CRm
 
+#define ICC_EOIR1			__ACCESS_CP15(c12, 0, c12, 1)
+#define ICC_IAR1			__ACCESS_CP15(c12, 0, c12, 0)
+#define ICC_SGI1R			__ACCESS_CP15_64(0, c12)
 #define ICC_PMR				__ACCESS_CP15(c4, 0, c6, 0)
 #define ICC_IGRPEN1			__ACCESS_CP15(c12, 0, c12, 7)
 
+static inline void gicv3_write_eoir(u32 irq)
+{
+	asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (val));
+	isb();
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+	u32 irqstat;
+	asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat));
+	dsb(sy);
+	return irqstat;
+}
+
 static inline void gicv3_write_pmr(u32 val)
 {
 	asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
@@ -31,6 +49,11 @@ static inline void gicv3_write_grpen1(u32 val)
 	isb();
 }
 
+static inline void gicv3_write_sgi1r(u64 val)
+{
+	asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val));
+}
+
 static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
 {
 	u64 val = readl(addr);
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
index 6d353567f56a..874775828016 100644
--- a/lib/arm64/asm/arch_gicv3.h
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -10,6 +10,9 @@
 
 #include <asm/sysreg.h>
 
+#define ICC_EOIR1_EL1			sys_reg(3, 0, 12, 12, 1)
+#define ICC_IAR1_EL1			sys_reg(3, 0, 12, 12, 0)
+#define ICC_SGI1R_EL1			sys_reg(3, 0, 12, 11, 5)
 #define ICC_PMR_EL1			sys_reg(3, 0, 4, 6, 0)
 #define ICC_GRPEN1_EL1			sys_reg(3, 0, 12, 12, 7)
 
@@ -27,6 +30,20 @@
  * sets the GP register's most significant bits to 0 with an explicit cast.
  */
 
+static inline void gicv3_write_eoir(u32 irq)
+{
+	asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq));
+	isb();
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+	u64 irqstat;
+	asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+	dsb(sy);
+	return (u64)irqstat;
+}
+
 static inline void gicv3_write_pmr(u32 val)
 {
 	asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
@@ -38,6 +55,11 @@ static inline void gicv3_write_grpen1(u32 val)
 	isb();
 }
 
+static inline void gicv3_write_sgi1r(u64 val)
+{
+	asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val));
+}
+
 #define gicv3_read_typer(c)		readq(c)
 
 #endif /* __ASSEMBLY__ */
-- 
2.7.4

^ permalink raw reply related

* [Qemu-devel] [kvm-unit-tests PATCH v4 09/11] arm/arm64: add initial gicv3 support
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v4:
 - only take defines from kernel we need now [Andre]
 - simplify enable by not caring if we reinit the distributor [drew]
v2:
 - configure irqs as NS GRP1
---
 lib/arm/asm/arch_gicv3.h   | 42 +++++++++++++++++++++
 lib/arm/asm/gic-v3.h       | 92 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h          |  1 +
 lib/arm/gic.c              | 56 ++++++++++++++++++++++++++++
 lib/arm64/asm/arch_gicv3.h | 44 ++++++++++++++++++++++
 lib/arm64/asm/gic-v3.h     |  1 +
 lib/arm64/asm/sysreg.h     | 44 ++++++++++++++++++++++
 7 files changed, 280 insertions(+)
 create mode 100644 lib/arm/asm/arch_gicv3.h
 create mode 100644 lib/arm/asm/gic-v3.h
 create mode 100644 lib/arm64/asm/arch_gicv3.h
 create mode 100644 lib/arm64/asm/gic-v3.h
 create mode 100644 lib/arm64/asm/sysreg.h

diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
new file mode 100644
index 000000000000..81a1e5f6c29c
--- /dev/null
+++ b/lib/arm/asm/arch_gicv3.h
@@ -0,0 +1,42 @@
+/*
+ * All ripped off from arch/arm/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_ARCH_GICV3_H_
+#define _ASMARM_ARCH_GICV3_H_
+
+#ifndef __ASSEMBLY__
+#include <libcflat.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+#define __stringify xstr
+
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2)	p15, Op1, %0, CRn, CRm, Op2
+
+#define ICC_PMR				__ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_IGRPEN1			__ACCESS_CP15(c12, 0, c12, 7)
+
+static inline void gicv3_write_pmr(u32 val)
+{
+	asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+	asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val));
+	isb();
+}
+
+static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
+{
+	u64 val = readl(addr);
+	val |= (u64)readl(addr + 4) << 32;
+	return val;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_ARCH_GICV3_H_ */
diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
new file mode 100644
index 000000000000..03321f8c860f
--- /dev/null
+++ b/lib/arm/asm/gic-v3.h
@@ -0,0 +1,92 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_V3_H_
+#define _ASMARM_GIC_V3_H_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
+#endif
+
+#define GICD_CTLR			0x0000
+#define GICD_TYPER			0x0004
+#define GICD_IGROUPR			0x0080
+
+#define GICD_CTLR_RWP			(1U << 31)
+#define GICD_CTLR_ARE_NS		(1U << 4)
+#define GICD_CTLR_ENABLE_G1A		(1U << 1)
+#define GICD_CTLR_ENABLE_G1		(1U << 0)
+
+#define GICR_TYPER			0x0008
+#define GICR_IGROUPR0			GICD_IGROUPR
+#define GICR_TYPER_LAST			(1U << 4)
+
+
+#include <asm/arch_gicv3.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/setup.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+struct gicv3_data {
+	void *dist_base;
+	void *redist_base[NR_CPUS];
+	unsigned int irq_nr;
+};
+extern struct gicv3_data gicv3_data;
+
+#define gicv3_dist_base()		(gicv3_data.dist_base)
+#define gicv3_redist_base()		(gicv3_data.redist_base[smp_processor_id()])
+#define gicv3_sgi_base()		(gicv3_data.redist_base[smp_processor_id()] + SZ_64K)
+
+extern int gicv3_init(void);
+extern void gicv3_enable_defaults(void);
+
+static inline void gicv3_do_wait_for_rwp(void *base)
+{
+	int count = 100000;	/* 1s */
+
+	while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) {
+		if (!--count) {
+			printf("GICv3: RWP timeout!\n");
+			abort();
+		}
+		cpu_relax();
+		udelay(10);
+	};
+}
+
+static inline void gicv3_dist_wait_for_rwp(void)
+{
+	gicv3_do_wait_for_rwp(gicv3_dist_base());
+}
+
+static inline void gicv3_redist_wait_for_rwp(void)
+{
+	gicv3_do_wait_for_rwp(gicv3_redist_base());
+}
+
+static inline u32 mpidr_compress(u64 mpidr)
+{
+	u64 compressed = mpidr & MPIDR_HWID_BITMASK;
+
+	compressed = (((compressed >> 32) & 0xff) << 24) | compressed;
+	return compressed;
+}
+
+static inline u64 mpidr_uncompress(u32 compressed)
+{
+	u64 mpidr = ((u64)compressed >> 24) << 32;
+
+	mpidr |= compressed & MPIDR_HWID_BITMASK;
+	return mpidr;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V3_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index 328e078a9ae1..4897bc592cdd 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -7,6 +7,7 @@
 #define _ASMARM_GIC_H_
 
 #include <asm/gic-v2.h>
+#include <asm/gic-v3.h>
 
 #define GIC_CPU_CTRL			0x00
 #define GIC_CPU_PRIMASK			0x04
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index 91d78c9a0cc2..af58a11ea13e 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -8,9 +8,11 @@
 #include <asm/io.h>
 
 struct gicv2_data gicv2_data;
+struct gicv3_data gicv3_data;
 
 /*
  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
  */
 static bool
 gic_get_dt_bases(const char *compatible, void **base1, void **base2)
@@ -48,10 +50,18 @@ int gicv2_init(void)
 			&gicv2_data.dist_base, &gicv2_data.cpu_base);
 }
 
+int gicv3_init(void)
+{
+	return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
+			&gicv3_data.redist_base[0]);
+}
+
 int gic_init(void)
 {
 	if (gicv2_init())
 		return 2;
+	else if (gicv3_init())
+		return 3;
 	return 0;
 }
 
@@ -73,3 +83,49 @@ void gicv2_enable_defaults(void)
 	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
 	writel(GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
 }
+
+void gicv3_set_redist_base(void)
+{
+	u32 aff = mpidr_compress(get_mpidr());
+	void *ptr = gicv3_data.redist_base[0];
+	u64 typer;
+
+	do {
+		typer = gicv3_read_typer(ptr + GICR_TYPER);
+		if ((typer >> 32) == aff) {
+			gicv3_redist_base() = ptr;
+			return;
+		}
+		ptr += SZ_64K * 2; /* skip RD_base and SGI_base */
+	} while (!(typer & GICR_TYPER_LAST));
+	assert(0);
+}
+
+void gicv3_enable_defaults(void)
+{
+	void *dist = gicv3_dist_base();
+	void *sgi_base;
+	unsigned int i;
+
+	gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv3_data.irq_nr > 1020)
+		gicv3_data.irq_nr = 1020;
+
+	writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+	       dist + GICD_CTLR);
+	gicv3_dist_wait_for_rwp();
+
+	if (!gicv3_redist_base())
+		gicv3_set_redist_base();
+	sgi_base = gicv3_sgi_base();
+
+	writel(~0, sgi_base + GICR_IGROUPR0);
+	writel(GICD_INT_EN_SET_SGI, sgi_base + GIC_DIST_ENABLE_SET);
+
+	for (i = 0; i < 32; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, sgi_base + GIC_DIST_PRI + i);
+	gicv3_redist_wait_for_rwp();
+
+	gicv3_write_pmr(0xf0);
+	gicv3_write_grpen1(1);
+}
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
new file mode 100644
index 000000000000..6d353567f56a
--- /dev/null
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -0,0 +1,44 @@
+/*
+ * All ripped off from arch/arm64/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_ARCH_GICV3_H_
+#define _ASMARM64_ARCH_GICV3_H_
+
+#include <asm/sysreg.h>
+
+#define ICC_PMR_EL1			sys_reg(3, 0, 4, 6, 0)
+#define ICC_GRPEN1_EL1			sys_reg(3, 0, 12, 12, 7)
+
+#ifndef __ASSEMBLY__
+
+#include <libcflat.h>
+#include <asm/barrier.h>
+
+#define __stringify xstr
+
+/*
+ * Low-level accessors
+ *
+ * These system registers are 32 bits, but we make sure that the compiler
+ * sets the GP register's most significant bits to 0 with an explicit cast.
+ */
+
+static inline void gicv3_write_pmr(u32 val)
+{
+	asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+	asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
+	isb();
+}
+
+#define gicv3_read_typer(c)		readq(c)
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASMARM64_ARCH_GICV3_H_ */
diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h
new file mode 100644
index 000000000000..8ee5d4d9c181
--- /dev/null
+++ b/lib/arm64/asm/gic-v3.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v3.h"
diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h
new file mode 100644
index 000000000000..544a46cb8cc5
--- /dev/null
+++ b/lib/arm64/asm/sysreg.h
@@ -0,0 +1,44 @@
+/*
+ * Ripped off from arch/arm64/include/asm/sysreg.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_SYSREG_H_
+#define _ASMARM64_SYSREG_H_
+
+#define sys_reg(op0, op1, crn, crm, op2) \
+	((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
+
+#ifdef __ASSEMBLY__
+	.irp	num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+	.equ	.L__reg_num_x\num, \num
+	.endr
+	.equ	.L__reg_num_xzr, 31
+
+	.macro	mrs_s, rt, sreg
+	.inst	0xd5200000|(\sreg)|(.L__reg_num_\rt)
+	.endm
+
+	.macro	msr_s, sreg, rt
+	.inst	0xd5000000|(\sreg)|(.L__reg_num_\rt)
+	.endm
+#else
+asm(
+"	.irp	num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
+"	.equ	.L__reg_num_x\\num, \\num\n"
+"	.endr\n"
+"	.equ	.L__reg_num_xzr, 31\n"
+"\n"
+"	.macro	mrs_s, rt, sreg\n"
+"	.inst	0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n"
+"	.endm\n"
+"\n"
+"	.macro	msr_s, sreg, rt\n"
+"	.inst	0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n"
+"	.endm\n"
+);
+#endif
+
+#endif /* _ASMARM64_SYSREG_H_ */
-- 
2.7.4

^ permalink raw reply related

* [Qemu-devel] [kvm-unit-tests PATCH v4 07/11] arm/arm64: gicv2: add an IPI test
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v4: properly mask irqnr in ipi_handler
v2: add more details in the output if a test fails,
    report spurious interrupts if we get them
---
 arm/Makefile.common |   6 +-
 arm/gic.c           | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 arm/unittests.cfg   |   7 ++
 lib/arm/asm/gic.h   |   6 ++
 4 files changed, 211 insertions(+), 3 deletions(-)
 create mode 100644 arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 41239c37e092..bc38183ab86e 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
 	LOADADDR = 0x40000000
 endif
 
-tests-common = \
-	$(TEST_DIR)/selftest.flat \
-	$(TEST_DIR)/spinlock-test.flat
+tests-common  = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/gic.flat
 
 all: test_cases
 
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 000000000000..efefab7296d4
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,195 @@
+/*
+ * GIC tests
+ *
+ * GICv2
+ *   + test sending/receiving IPIs
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+static int gic_version;
+static int acked[NR_CPUS], spurious[NR_CPUS];
+static cpumask_t ready;
+
+static void nr_cpu_check(int nr)
+{
+	if (nr_cpus < nr)
+		report_abort("At least %d cpus required", nr);
+}
+
+static void wait_on_ready(void)
+{
+	cpumask_set_cpu(smp_processor_id(), &ready);
+	while (!cpumask_full(&ready))
+		cpu_relax();
+}
+
+static void check_acked(cpumask_t *mask)
+{
+	int missing = 0, extra = 0, unexpected = 0;
+	int nr_pass, cpu, i;
+
+	/* Wait up to 5s for all interrupts to be delivered */
+	for (i = 0; i < 50; ++i) {
+		mdelay(100);
+		nr_pass = 0;
+		for_each_present_cpu(cpu) {
+			smp_rmb();
+			nr_pass += cpumask_test_cpu(cpu, mask) ?
+				acked[cpu] == 1 : acked[cpu] == 0;
+		}
+		if (nr_pass == nr_cpus) {
+			report("Completed in %d ms", true, ++i * 100);
+			return;
+		}
+	}
+
+	for_each_present_cpu(cpu) {
+		if (cpumask_test_cpu(cpu, mask)) {
+			if (!acked[cpu])
+				++missing;
+			else if (acked[cpu] > 1)
+				++extra;
+		} else {
+			if (acked[cpu])
+				++unexpected;
+		}
+	}
+
+	report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
+	       false, missing, extra, unexpected);
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+	u32 irqstat = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+	if (irqnr != GICC_INT_SPURIOUS) {
+		writel(irqstat, gicv2_cpu_base() + GIC_CPU_EOI);
+		smp_rmb(); /* pairs with wmb in ipi_test functions */
+		++acked[smp_processor_id()];
+		smp_wmb(); /* pairs with rmb in check_acked */
+	} else {
+		++spurious[smp_processor_id()];
+		smp_wmb();
+	}
+}
+
+static void ipi_test_self(void)
+{
+	cpumask_t mask;
+
+	report_prefix_push("self");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	cpumask_clear(&mask);
+	cpumask_set_cpu(0, &mask);
+	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+}
+
+static void ipi_test_smp(void)
+{
+	cpumask_t mask;
+	unsigned long tlist;
+
+	report_prefix_push("target-list");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
+	cpumask_bits(&mask)[0] = tlist;
+	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+
+	report_prefix_push("broadcast");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	cpumask_copy(&mask, &cpu_present_mask);
+	cpumask_clear_cpu(0, &mask);
+	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+}
+
+static void ipi_enable(void)
+{
+	gicv2_enable_defaults();
+#ifdef __arm__
+	install_exception_handler(EXCPTN_IRQ, ipi_handler);
+#else
+	install_irq_handler(EL1H_IRQ, ipi_handler);
+#endif
+	local_irq_enable();
+}
+
+static void ipi_recv(void)
+{
+	ipi_enable();
+	cpumask_set_cpu(smp_processor_id(), &ready);
+	while (1)
+		wfi();
+}
+
+int main(int argc, char **argv)
+{
+	char pfx[8];
+	int cpu;
+
+	gic_version = gic_init();
+	if (!gic_version)
+		report_abort("No gic present!");
+
+	snprintf(pfx, 8, "gicv%d", gic_version);
+	report_prefix_push(pfx);
+
+	if (argc < 2) {
+
+		report_prefix_push("ipi");
+		ipi_enable();
+		ipi_test_self();
+		report_prefix_pop();
+
+	} else if (!strcmp(argv[1], "ipi")) {
+
+		report_prefix_push(argv[1]);
+		nr_cpu_check(2);
+
+		for_each_present_cpu(cpu) {
+			if (cpu == 0)
+				continue;
+			smp_boot_secondary(cpu, ipi_recv);
+		}
+		ipi_enable();
+		wait_on_ready();
+		ipi_test_self();
+		ipi_test_smp();
+
+		smp_rmb();
+		for_each_present_cpu(cpu) {
+			if (spurious[cpu]) {
+				printf("ipi: WARN: cpu%d got %d spurious "
+				       "interrupts\n",
+				       spurious[cpu], smp_processor_id());
+			}
+		}
+
+		report_prefix_pop();
+
+	} else {
+		report_abort("Unknown subtest '%s'", argv[1]);
+	}
+
+	return report_summary();
+}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index 3f6fa45c587e..68bf5cd6008f 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -54,3 +54,10 @@ file = selftest.flat
 smp = $MAX_SMP
 extra_params = -append 'smp'
 groups = selftest
+
+# Test GIC emulation
+[gicv2-ipi]
+file = gic.flat
+smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
+extra_params = -machine gic-version=2 -append 'ipi'
+groups = gic
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index ec92f1064dc0..328e078a9ae1 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -10,14 +10,20 @@
 
 #define GIC_CPU_CTRL			0x00
 #define GIC_CPU_PRIMASK			0x04
+#define GIC_CPU_INTACK			0x0c
+#define GIC_CPU_EOI			0x10
 
 #define GICC_ENABLE			0x1
 #define GICC_INT_PRI_THRESHOLD		0xf0
 
+#define GICC_IAR_INT_ID_MASK		0x3ff
+#define GICC_INT_SPURIOUS		1023
+
 #define GIC_DIST_CTRL			0x000
 #define GIC_DIST_CTR			0x004
 #define GIC_DIST_ENABLE_SET		0x100
 #define GIC_DIST_PRI			0x400
+#define GIC_DIST_SOFTINT		0xf00
 
 #define GICD_ENABLE			0x1
 #define GICD_INT_EN_SET_SGI		0x0000ffff
-- 
2.7.4

^ permalink raw reply related

* [GIT PULL 1/4] DaVinci cleanup for v4.10
From: Olof Johansson @ 2016-11-08 20:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161104062535.9593-1-nsekhar@ti.com>

On Fri, Nov 04, 2016 at 11:55:32AM +0530, Sekhar Nori wrote:
> The following changes since commit 1001354ca34179f3db924eb66672442a173147dc:
> 
>   Linux 4.9-rc1 (2016-10-15 12:17:50 -0700)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/nsekhar/linux-davinci.git tags/davinci-for-v4.10/cleanup
> 
> for you to fetch changes up to 766763dbdc1dca11deabdb00077a1c19e2803f0a:
> 
>   ARM: davinci: da8xx: Remove duplicated defines (2016-10-31 16:51:56 +0530)
> 
> ----------------------------------------------------------------
> Clean-up some unnecessary code from mach-davinci.
> 
> - Remove now unneeded dma resources where drivers
>   are already converted to use the dma_slave_map[]
>   structure.
> 
> - Remove some duplicated defines related to USB support.

We don't have a cleanup branch in our tree any more, but thanks for breaking
this out for us anyway! I've merged it into next/soc.


-Olof

^ permalink raw reply

* [Qemu-devel] [kvm-unit-tests PATCH v4 08/11] libcflat: add IS_ALIGNED() macro, and page sizes
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Peter Xu,
	Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

From: Peter Xu <peterx@redhat.com>

These macros will be useful to do page alignment checks.

Signed-off-by: Peter Xu <peterx@redhat.com>
[drew: also added SZ_64K]
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/libcflat.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 82005f5d014f..143fc53061fe 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -33,6 +33,12 @@
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
 #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
 #define ALIGN(x, a)		__ALIGN((x), (a))
+#define IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
+
+#define SZ_4K			(0x1000)
+#define SZ_64K			(0x10000)
+#define SZ_2M			(0x200000)
+#define SZ_1G			(0x40000000)
 
 typedef uint8_t		u8;
 typedef int8_t		s8;
-- 
2.7.4

^ permalink raw reply related

* [Qemu-devel] [kvm-unit-tests PATCH v4 06/11] arm/arm64: add initial gicv2 support
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

Add some gicv2 support. This just adds init and enable
functions, allowing unit tests to start messing with it.

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v4:
 - only take defines from kernel we need now [Andre]
 - moved defines to asm/gic.h so they'll be shared with v3 [drew]
 - simplify enable by not caring if we reinit the distributor [drew]
 - init all GICD_INT_DEF_PRI_X4 registers [Eric]
---
 arm/Makefile.common    |  1 +
 lib/arm/asm/gic-v2.h   | 28 +++++++++++++++++++
 lib/arm/asm/gic.h      | 44 +++++++++++++++++++++++++++++
 lib/arm/gic.c          | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm64/asm/gic-v2.h |  1 +
 lib/arm64/asm/gic.h    |  1 +
 6 files changed, 150 insertions(+)
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm/gic.c
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic.h

diff --git a/arm/Makefile.common b/arm/Makefile.common
index ccb554d9251a..41239c37e092 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
 cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/gic.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
new file mode 100644
index 000000000000..f91530f88355
--- /dev/null
+++ b/lib/arm/asm/gic-v2.h
@@ -0,0 +1,28 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_V2_H_
+#define _ASMARM_GIC_V2_H_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v2.h>. Include <asm/gic.h>
+#endif
+
+struct gicv2_data {
+	void *dist_base;
+	void *cpu_base;
+	unsigned int irq_nr;
+};
+extern struct gicv2_data gicv2_data;
+
+#define gicv2_dist_base()		(gicv2_data.dist_base)
+#define gicv2_cpu_base()		(gicv2_data.cpu_base)
+
+extern int gicv2_init(void);
+extern void gicv2_enable_defaults(void);
+
+#endif /* _ASMARM_GIC_V2_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
new file mode 100644
index 000000000000..ec92f1064dc0
--- /dev/null
+++ b/lib/arm/asm/gic.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_H_
+#define _ASMARM_GIC_H_
+
+#include <asm/gic-v2.h>
+
+#define GIC_CPU_CTRL			0x00
+#define GIC_CPU_PRIMASK			0x04
+
+#define GICC_ENABLE			0x1
+#define GICC_INT_PRI_THRESHOLD		0xf0
+
+#define GIC_DIST_CTRL			0x000
+#define GIC_DIST_CTR			0x004
+#define GIC_DIST_ENABLE_SET		0x100
+#define GIC_DIST_PRI			0x400
+
+#define GICD_ENABLE			0x1
+#define GICD_INT_EN_SET_SGI		0x0000ffff
+#define GICD_INT_DEF_PRI		0xa0
+#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
+					(GICD_INT_DEF_PRI << 16) |\
+					(GICD_INT_DEF_PRI << 8) |\
+					GICD_INT_DEF_PRI)
+
+#define GICD_TYPER_IRQS(typer)		((((typer) & 0x1f) + 1) * 32)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * gic_init will try to find all known gics, and then
+ * initialize the gic data for the one found.
+ * returns
+ *  0   : no gic was found
+ *  > 0 : the gic version of the gic found
+ */
+extern int gic_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
new file mode 100644
index 000000000000..91d78c9a0cc2
--- /dev/null
+++ b/lib/arm/gic.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <devicetree.h>
+#include <asm/gic.h>
+#include <asm/io.h>
+
+struct gicv2_data gicv2_data;
+
+/*
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ */
+static bool
+gic_get_dt_bases(const char *compatible, void **base1, void **base2)
+{
+	struct dt_pbus_reg reg;
+	struct dt_device gic;
+	struct dt_bus bus;
+	int node, ret;
+
+	dt_bus_init_defaults(&bus);
+	dt_device_init(&gic, &bus, NULL);
+
+	node = dt_device_find_compatible(&gic, compatible);
+	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
+
+	if (node == -FDT_ERR_NOTFOUND)
+		return false;
+
+	dt_device_bind_node(&gic, node);
+
+	ret = dt_pbus_translate(&gic, 0, &reg);
+	assert(ret == 0);
+	*base1 = ioremap(reg.addr, reg.size);
+
+	ret = dt_pbus_translate(&gic, 1, &reg);
+	assert(ret == 0);
+	*base2 = ioremap(reg.addr, reg.size);
+
+	return true;
+}
+
+int gicv2_init(void)
+{
+	return gic_get_dt_bases("arm,cortex-a15-gic",
+			&gicv2_data.dist_base, &gicv2_data.cpu_base);
+}
+
+int gic_init(void)
+{
+	if (gicv2_init())
+		return 2;
+	return 0;
+}
+
+void gicv2_enable_defaults(void)
+{
+	void *dist = gicv2_dist_base();
+	void *cpu_base = gicv2_cpu_base();
+	unsigned int i;
+
+	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GIC_DIST_CTR));
+	if (gicv2_data.irq_nr > 1020)
+		gicv2_data.irq_nr = 1020;
+
+	for (i = 0; i < gicv2_data.irq_nr; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, dist + i + GIC_DIST_PRI);
+
+	writel(GICD_INT_EN_SET_SGI, dist + GIC_DIST_ENABLE_SET);
+	writel(GICD_ENABLE, dist + GIC_DIST_CTRL);
+	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
+	writel(GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
+}
diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
new file mode 100644
index 000000000000..52226624a209
--- /dev/null
+++ b/lib/arm64/asm/gic-v2.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v2.h"
diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
new file mode 100644
index 000000000000..e5eb302a31b4
--- /dev/null
+++ b/lib/arm64/asm/gic.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic.h"
-- 
2.7.4

^ permalink raw reply related

* [kvm-unit-tests PATCH v4 08/11] libcflat: add IS_ALIGNED() macro, and page sizes
From: Andrew Jones @ 2016-11-08 20:21 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: pbonzini, andre.przywara, peter.maydell, alex.bennee,
	marc.zyngier, eric.auger, christoffer.dall, Peter Xu,
	Andrew Jones
In-Reply-To: <1478636499-14339-1-git-send-email-drjones@redhat.com>

From: Peter Xu <peterx@redhat.com>

These macros will be useful to do page alignment checks.

Signed-off-by: Peter Xu <peterx@redhat.com>
[drew: also added SZ_64K]
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/libcflat.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 82005f5d014f..143fc53061fe 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -33,6 +33,12 @@
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
 #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
 #define ALIGN(x, a)		__ALIGN((x), (a))
+#define IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
+
+#define SZ_4K			(0x1000)
+#define SZ_64K			(0x10000)
+#define SZ_2M			(0x200000)
+#define SZ_1G			(0x40000000)
 
 typedef uint8_t		u8;
 typedef int8_t		s8;
-- 
2.7.4

^ permalink raw reply related


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.