* [PATCH v3 0/2] Add device tree probe for i2c-imx driver
From: Shawn Guo @ 2011-09-15 15:39 UTC (permalink / raw)
To: linux-arm-kernel
Hi Ben,
Hopefully, you can pick up this version.
Thanks.
Changes since v2:
* Drop HS-I2C from binding document fsl-imx-i2c.txt
Changes since v1:
* Fix a couple of typo in fsl-imx-i2c.txt
Shawn Guo (2):
i2c-imx: remove init/exit hooks from platform data
i2c-imx: add device tree probe support
.../devicetree/bindings/i2c/fsl-imx-i2c.txt | 18 ++++++++
arch/arm/plat-mxc/include/mach/i2c.h | 4 --
drivers/i2c/busses/i2c-imx.c | 46 +++++++++----------
3 files changed, 40 insertions(+), 28 deletions(-)
^ permalink raw reply
* [PATCH v3 1/2] i2c-imx: remove init/exit hooks from platform data
From: Shawn Guo @ 2011-09-15 15:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316101193-4295-1-git-send-email-shawn.guo@linaro.org>
The init/exit hooks in platform data are being used nowhere, so can
be removed.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Darius Augulis <augulis.darius@gmail.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/plat-mxc/include/mach/i2c.h | 4 ----
drivers/i2c/busses/i2c-imx.c | 21 +++------------------
2 files changed, 3 insertions(+), 22 deletions(-)
diff --git a/arch/arm/plat-mxc/include/mach/i2c.h b/arch/arm/plat-mxc/include/mach/i2c.h
index 4a5dc5c..375cdd0 100644
--- a/arch/arm/plat-mxc/include/mach/i2c.h
+++ b/arch/arm/plat-mxc/include/mach/i2c.h
@@ -11,14 +11,10 @@
/**
* struct imxi2c_platform_data - structure of platform data for MXC I2C driver
- * @init: Initialise gpio's and other board specific things
- * @exit: Free everything initialised by @init
* @bitrate: Bus speed measured in Hz
*
**/
struct imxi2c_platform_data {
- int (*init)(struct device *dev);
- void (*exit)(struct device *dev);
int bitrate;
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 4c2a62b..54d809e 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -466,7 +466,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
{
struct imx_i2c_struct *i2c_imx;
struct resource *res;
- struct imxi2c_platform_data *pdata;
+ struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
void __iomem *base;
resource_size_t res_size;
int irq;
@@ -485,19 +485,11 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
return -ENOENT;
}
- pdata = pdev->dev.platform_data;
-
- if (pdata && pdata->init) {
- ret = pdata->init(&pdev->dev);
- if (ret)
- return ret;
- }
-
res_size = resource_size(res);
if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
- ret = -EBUSY;
- goto fail0;
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ return -EBUSY;
}
base = ioremap(res->start, res_size);
@@ -586,9 +578,6 @@ fail2:
iounmap(base);
fail1:
release_mem_region(res->start, resource_size(res));
-fail0:
- if (pdata && pdata->exit)
- pdata->exit(&pdev->dev);
return ret; /* Return error number */
}
@@ -611,10 +600,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev)
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
writeb(0, i2c_imx->base + IMX_I2C_I2SR);
- /* Shut down hardware */
- if (pdata && pdata->exit)
- pdata->exit(&pdev->dev);
-
clk_put(i2c_imx->clk);
iounmap(i2c_imx->base);
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 2/2] i2c-imx: add device tree probe support
From: Shawn Guo @ 2011-09-15 15:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316101193-4295-1-git-send-email-shawn.guo@linaro.org>
It adds device tree probe support for i2c-imx driver.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Darius Augulis <augulis.darius@gmail.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
.../devicetree/bindings/i2c/fsl-imx-i2c.txt | 18 ++++++++++++++
drivers/i2c/busses/i2c-imx.c | 25 +++++++++++++++----
2 files changed, 37 insertions(+), 6 deletions(-)
create mode 100644 Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
diff --git a/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt b/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
new file mode 100644
index 0000000..a5189e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
@@ -0,0 +1,18 @@
+* Freescale Inter IC (I2C) for i.MX
+
+Required properties:
+- compatible : Should be "fsl,<chip>-i2c"
+- reg : Should contain I2C registers location and length
+- interrupts : Should contain I2C interrupt
+
+Optional properties:
+- clock-frequency : Constains desired I2C bus clock frequency in Hz.
+ The absence of the propoerty indicates the default frequency 100 kHz.
+
+Examples:
+
+i2c at 83fc4000 { /* I2C2 on i.MX51 */
+ compatible = "fsl,imx51-i2c", "fsl,imx1-i2c";
+ reg = <0x83fc4000 0x4000>;
+ interrupts = <63>;
+};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 54d809e..58832e5 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -48,6 +48,9 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -125,6 +128,11 @@ struct imx_i2c_struct {
unsigned int ifdr; /* IMX_I2C_IFDR */
};
+static const struct of_device_id i2c_imx_dt_ids[] = {
+ { .compatible = "fsl,imx1-i2c", },
+ { /* sentinel */ }
+};
+
/** Functions for IMX I2C adapter driver ***************************************
*******************************************************************************/
@@ -469,7 +477,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
void __iomem *base;
resource_size_t res_size;
- int irq;
+ int irq, bitrate;
int ret;
dev_dbg(&pdev->dev, "<%s>\n", __func__);
@@ -512,6 +520,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev;
i2c_imx->adapter.nr = pdev->id;
+ i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->irq = irq;
i2c_imx->base = base;
i2c_imx->res = res;
@@ -538,10 +547,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
/* Set up clock divider */
- if (pdata && pdata->bitrate)
- i2c_imx_set_clk(i2c_imx, pdata->bitrate);
- else
- i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
+ bitrate = IMX_I2C_BIT_RATE;
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &bitrate);
+ if (ret < 0 && pdata && pdata->bitrate)
+ bitrate = pdata->bitrate;
+ i2c_imx_set_clk(i2c_imx, bitrate);
/* Set up chip registers to defaults */
writeb(0, i2c_imx->base + IMX_I2C_I2CR);
@@ -554,6 +565,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
goto fail5;
}
+ of_i2c_register_devices(&i2c_imx->adapter);
+
/* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx);
@@ -584,7 +597,6 @@ fail1:
static int __exit i2c_imx_remove(struct platform_device *pdev)
{
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
- struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
/* remove adapter */
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
@@ -613,6 +625,7 @@ static struct platform_driver i2c_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = i2c_imx_dt_ids,
}
};
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 0/2] Add device tree probe for i2c-imx driver
From: Ben Dooks @ 2011-09-15 15:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316101193-4295-1-git-send-email-shawn.guo@linaro.org>
On Thu, Sep 15, 2011 at 11:39:51PM +0800, Shawn Guo wrote:
> Hi Ben,
>
> Hopefully, you can pick up this version.
ok, will do it for the weekend.
> Thanks.
>
> Changes since v2:
> * Drop HS-I2C from binding document fsl-imx-i2c.txt
>
> Changes since v1:
> * Fix a couple of typo in fsl-imx-i2c.txt
>
> Shawn Guo (2):
> i2c-imx: remove init/exit hooks from platform data
> i2c-imx: add device tree probe support
>
> .../devicetree/bindings/i2c/fsl-imx-i2c.txt | 18 ++++++++
> arch/arm/plat-mxc/include/mach/i2c.h | 4 --
> drivers/i2c/busses/i2c-imx.c | 46 +++++++++----------
> 3 files changed, 40 insertions(+), 28 deletions(-)
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Ben Dooks, ben at fluff.org, http://www.fluff.org/ben/
Large Hadron Colada: A large Pina Colada that makes the universe disappear.
^ permalink raw reply
* Freescale i.mx25 SDIO/Libertas issue
From: Albert @ 2011-09-15 15:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4DE44F16.8050407@bluewatersys.com>
Hi people, my company is also considering developing a platform for
the MX25 including a wifi module based on marvell's 8686 chip using
the SDIO interface. I am not very experienced in the topic and right now
we are only trying to establish some especifications and making a budget.
I just wanted to know wether it is hard to get all this going.
I have read all this thread but i don't really get what the real problem is,
specially when somebody talks about some firmware and kernel configuration....
I just expected to connect the module to the SDIO bus loading the driver
the and configuring some stuff (wifi-network, access key etc.) what am I missing?
I just wanna know if a rocky like me will be able to pull through with all this.
Thanks a lot :P
^ permalink raw reply
* [PATCH 0/6] mc13783 cleanup
From: Uwe Kleine-König @ 2011-09-15 16:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110915151213.GE32263@sortiz-mobl>
Hi Samuel,
On Thu, Sep 15, 2011 at 05:12:13PM +0200, Samuel Ortiz wrote:
> On Thu, Aug 25, 2011 at 09:05:12AM +0200, Philippe R?tornaz wrote:
> > Le mercredi 24 ao?t 2011 15:27:40, Uwe Kleine-K?nig a ?crit :
> > > Hello,
> > >
> > > this series removes the long obsolte mc13783 API after fixing all
> > > remaining users.
> >
> > I posted a patch last month which was touching this MFD too.
> > We will need to synchronize both patch.
> I applied Uwe's patchset now.
Thanks.
> Could you please sync your code and send me a
> patchset that applies on top of:
>
> git://git.infradead.org/users/sameo/mfd-2.6.git for-next
You can fetch the updated series from
git://git.pengutronix.de/git/ukl/linux-2.6.git mc13783
I also included the last patch that Sascha commented with:
Please ping once the rest is merged.
This is OK as I'm currently substituting Sascha for imx maintainer
duties while he is on vacation. Merging the above branch into the
current imx/for-next branch yields a merge conflict in
drivers/rtc/rtc-twl.c which is only touched on your side and in Linus'
tree below imx/for-next.
I guess you can drop 54d96ef785b5 as it is the same as dec35d19c4 +
34d623d.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* gpio_ensure_requested error on mx31pdk boot
From: Fabio Estevam @ 2011-09-15 16:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110915071427.GD11297@pengutronix.de>
2011/9/15 Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>:
...
> I havn't seen it. Just in case you don't know, that means a gpio was
> used without being (successfully) requested. On the other hand I wonder
> if GPIO-0 is correct here?!
I managed to fix this. It is a bug in the spi-imx driver. Patch will
be sent shortly.
Regards,
Fabio Estevam
^ permalink raw reply
* [PATCH] spi/imx: Fix spi-imx when the hardware SPI chipselects are used
From: Fabio Estevam @ 2011-09-15 16:16 UTC (permalink / raw)
To: linux-arm-kernel
commit 22a85e4cd51 (spi/imx: add device tree probe support) broke spi-imx usage
when the SPI chipselect is the one internal to the controller.
On a mx31pdk board the following error is seen:
Registering mxc_nand as whole device
------------[ cut here ]------------
WARNING: at drivers/gpio/gpiolib.c:101 gpio_ensure_requested+0x4c/0xf4()
autorequest GPIO-0
Modules linked in:
[<c0014410>] (unwind_backtrace+0x0/0xf4) from [<c0025754>] (warn_slowpath_common+0x4c/0x64)
[<c0025754>] (warn_slowpath_common+0x4c/0x64) from [<c0025800>] (warn_slowpath_fmt+0x30/0x40)
[<c0025800>] (warn_slowpath_fmt+0x30/0x40) from [<c0198688>] (gpio_ensure_requested+0x4c/0xf4)
[<c0198688>] (gpio_ensure_requested+0x4c/0xf4) from [<c01988c8>] (gpio_direction_output+0xa0/0x138)
[<c01988c8>] (gpio_direction_output+0xa0/0x138) from [<c01ed198>] (spi_imx_setup+0x38/0x4c)
[<c01ed198>] (spi_imx_setup+0x38/0x4c) from [<c01eb5d0>] (spi_setup+0x38/0x50)
[<c01eb5d0>] (spi_setup+0x38/0x50) from [<c01eb85c>] (spi_add_device+0x94/0x124)
[<c01eb85c>] (spi_add_device+0x94/0x124) from [<c01eb960>] (spi_new_device+0x74/0xac)
[<c01eb960>] (spi_new_device+0x74/0xac) from [<c01eb9b8>] (spi_match_master_to_boardinfo+0x20/0x40)
[<c01eb9b8>] (spi_match_master_to_boardinfo+0x20/0x40) from [<c01eba88>] (spi_register_master+0xb0/0x104)
[<c01eba88>] (spi_register_master+0xb0/0x104) from [<c01ec0b4>] (spi_bitbang_start+0x104/0x17c)
[<c01ec0b4>] (spi_bitbang_start+0x104/0x17c) from [<c02c2c4c>] (spi_imx_probe+0x2fc/0x404)
[<c02c2c4c>] (spi_imx_probe+0x2fc/0x404) from [<c01c2498>] (platform_drv_probe+0x18/0x1c)
[<c01c2498>] (platform_drv_probe+0x18/0x1c) from [<c01c1058>] (driver_probe_device+0x78/0x174)
[<c01c1058>] (driver_probe_device+0x78/0x174) from [<c01c11e0>] (__driver_attach+0x8c/0x90)
[<c01c11e0>] (__driver_attach+0x8c/0x90) from [<c01c0860>] (bus_for_each_dev+0x60/0x8c)
[<c01c0860>] (bus_for_each_dev+0x60/0x8c) from [<c01c0088>] (bus_add_driver+0xa0/0x288)
[<c01c0088>] (bus_add_driver+0xa0/0x288) from [<c01c179c>] (driver_register+0x78/0x18c)
[<c01c179c>] (driver_register+0x78/0x18c) from [<c0008490>] (do_one_initcall+0x34/0x178)
[<c0008490>] (do_one_initcall+0x34/0x178) from [<c03a5204>] (kernel_init+0x74/0x118)
[<c03a5204>] (kernel_init+0x74/0x118) from [<c000f65c>] (kernel_thread_exit+0x0/0x8)
---[ end trace 759f924b30fd5a44 ]---
Fix this issue by using the original chip select logic and make spi-imx to work again.
Tested on a mx31pdk that uses the hardware SPI chipselect pins and also
on a mx27pdk that uses GPIO as SPI chipselect.
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
drivers/spi/spi-imx.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 8ac6542..7821c48 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -783,12 +783,10 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master = spi_master_get(master);
for (i = 0; i < master->num_chipselect; i++) {
- int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
- if (cs_gpio < 0)
- cs_gpio = mxc_platform_info->chipselect[i];
- if (cs_gpio < 0)
+ spi_imx->chipselect[i] = mxc_platform_info->chipselect[i];
+ if (spi_imx->chipselect[i] < 0)
continue;
- spi_imx->chipselect[i] = cs_gpio;
+
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
if (ret) {
while (i > 0) {
--
1.7.1
^ permalink raw reply related
* confusion regarding the CMD19 and CMD21 in eMMC/SD card spec
From: Philip Rakity @ 2011-09-15 16:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGxe1ZH=mrAdfVR7Uw8mYNAD43BAbW7VGuhA1pN9hbSjTG9HVA@mail.gmail.com>
Different committee's --- Different standards.
There is no issue with overlap.
On Sep 15, 2011, at 4:58 AM, Girish K S wrote:
> Dear all,
> The eMMC 4.5 specification mentions that the CMD21 in
> class 2 is a SEND_TUNING BLOCK command. where as the SD card
> specification
> in the given link says CMD19 in class 2 is the SEND_TUNING_BLOCK
> http://www.scribd.com/doc/50685191/53/Figure-4-8-Send-Tuning-Block-Command.
> Also the implementation in the drivers/mmc/host/sdhci.c uses the CMD19
> as the SEND_TUNING_BLOCK.
> Can anybody clarify why there is overlapping in this command number.
> May be my understand is wrong.
>
> In the MMC spec the CMD19 is BUS_TEST_W in class 0 and CMD21 is
> reserved till eMMC 4.41 version.
> But in the SD specification (given link) CMD19 is SEND_TUNING_BLOCK
> and CMD21 is reserved.
>
> Thanks and regards
> Girish K S
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 6/6] arm/imx6q: add suspend/resume support
From: Lorenzo Pieralisi @ 2011-09-15 16:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316097926-913-7-git-send-email-shawn.guo@linaro.org>
On Thu, Sep 15, 2011 at 03:45:26PM +0100, Shawn Guo wrote:
> It adds suspend/resume support for imx6q.
>
> Signed-off-by: Anson Huang <b20788@freescale.com>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
> arch/arm/mach-imx/Makefile | 2 +-
> arch/arm/mach-imx/head-v7.S | 27 +++++++++
> arch/arm/mach-imx/pm-imx6q.c | 88 +++++++++++++++++++++++++++++++
> arch/arm/plat-mxc/include/mach/common.h | 8 +++
> 4 files changed, 124 insertions(+), 1 deletions(-)
> create mode 100644 arch/arm/mach-imx/pm-imx6q.c
>
> diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
> index 16737ba..c787151 100644
> --- a/arch/arm/mach-imx/Makefile
> +++ b/arch/arm/mach-imx/Makefile
> @@ -70,4 +70,4 @@ obj-$(CONFIG_CPU_V7) += head-v7.o
> obj-$(CONFIG_SMP) += platsmp.o
> obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
> obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
> -obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
> +obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o pm-imx6q.o
> diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S
> index ede908b..0a86685 100644
> --- a/arch/arm/mach-imx/head-v7.S
> +++ b/arch/arm/mach-imx/head-v7.S
> @@ -69,3 +69,30 @@ ENTRY(v7_secondary_startup)
> b secondary_startup
> ENDPROC(v7_secondary_startup)
> #endif
> +
> +ENTRY(v7_cpu_resume)
> + bl v7_invalidate_l1
> +
> + /*
> + * Restore L2 AUX_CTRL register saved by suspend procedure
> + * and enable L2
> + */
> + adr r4, 1f
> + ldmia r4, {r5, r6, r7}
> + sub r4, r4, r5
> + add r6, r6, r4
> + add r7, r7, r4
> + ldr r0, [r6]
> + ldr r7, [r7]
> + ldr r1, [r7]
> + str r1, [r0, #L2X0_AUX_CTRL]
> + ldr r1, =0x1
> + str r1, [r0, #L2X0_CTRL]
> +
> + b cpu_resume
> +
> + .align
> +1: .long .
> + .long pl310_pbase
> + .long pl310_aux_ctrl_paddr
Would not something like:
adr r4, pl310_pbase
ldmia r4, {r6, r7}
[...]
pl310_pbase:
.long 0
pl310_aux_ctrl:
.long 0
be better and faster ? Why play with virtual addresses ?
Of course you should initialize the values, but then you can access them
through a PC relative load when running physical.
Your code should be in the .data section for it to be writable (adr does not
work across sections), have a look at Russell's code in sleep.S it is
very well commented and similar to what you need.
> +ENDPROC(v7_cpu_resume)
> diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
> new file mode 100644
> index 0000000..124bcd5
> --- /dev/null
> +++ b/arch/arm/mach-imx/pm-imx6q.c
> @@ -0,0 +1,88 @@
> +/*
> + * Copyright 2011 Freescale Semiconductor, Inc.
> + * Copyright 2011 Linaro Ltd.
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/suspend.h>
> +#include <asm/proc-fns.h>
> +#include <asm/suspend.h>
> +#include <asm/hardware/cache-l2x0.h>
> +#include <mach/common.h>
> +#include <mach/hardware.h>
> +
> +static void __iomem *pl310_vbase;
> +void __iomem *pl310_pbase;
> +
> +static volatile unsigned long pl310_aux_ctrl;
> +volatile unsigned long pl310_aux_ctrl_paddr;
I think that by defining those variables in assembly you would make
your life much simpler.
I think you know your L2 is already initialized here to make sure you
save the right aux value. Hence you should clean the variables above from
L2 to make sure they are available at reset from DRAM (L2 is retained
and you do not clean it on suspend, correct ?)
I do not think that code to save/restore L2 config belongs here though.
More below.
> +
> +static int imx6q_suspend_finish(unsigned long val)
> +{
> + cpu_do_idle();
> + return 0;
> +}
> +
> +static int imx6q_pm_enter(suspend_state_t state)
> +{
> + switch (state) {
> + case PM_SUSPEND_MEM:
> + imx6q_set_lpm(STOP_POWER_OFF);
> + imx_gpc_pre_suspend();
> + imx_set_cpu_jump(0, v7_cpu_resume);
> + /* Zzz ... */
> + cpu_suspend(0, imx6q_suspend_finish);
> + imx_smp_prepare();
> + imx_gpc_post_resume();
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static const struct platform_suspend_ops imx6q_pm_ops = {
> + .enter = imx6q_pm_enter,
> + .valid = suspend_valid_only_mem,
> +};
> +
> +void __init imx6q_pm_init(void)
> +{
> + struct device_node *np;
> + u32 reg[2];
> +
> + np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
> + of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
> + pl310_vbase = ioremap(reg[0], reg[1]);
Mmmm...is this vma ever released ? L2 is already mapped in the L2
driver from DT or through static mappings.
Overall, I think that code to restore PL310 belongs in cache-l2x0.c, not here.
We can easily write an assembly stub that reinitialize L2 before
resume if that's something we should and can do (security ?).
Lorenzo
^ permalink raw reply
* [PATCH 5/5] ARM: gic: add OF based initialization
From: Rob Herring @ 2011-09-15 16:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E72030F.1090300@ti.com>
Benoit,
On 09/15/2011 08:52 AM, Cousson, Benoit wrote:
> On 9/15/2011 3:11 PM, Rob Herring wrote:
>> Benoit,
>>
>> On 09/15/2011 05:07 AM, Cousson, Benoit wrote:
>>> Hi Rob,
>>>
>>> On 9/15/2011 9:55 AM, Thomas Abraham wrote:
>>>> Hi Rob,
>>>>
>>>> On 14 September 2011 22:01, Rob Herring<robherring2@gmail.com> wrote:
>>>>> From: Rob Herring<rob.herring@calxeda.com>
>>>>>
>>>>> This adds gic initialization using device tree data. The
>>>>> initialization
>>>>> functions are intended to be called by a generic OF interrupt
>>>>> controller parsing function once the right pieces are in place.
>>>>>
>>>>> PPIs are handled using 3rd cell of interrupts properties to specify
>>>>> the cpu
>>>>> mask the PPI is assigned to.
>>>>>
>>>>> Signed-off-by: Rob Herring<rob.herring@calxeda.com>
>>>>> ---
>>>>> Documentation/devicetree/bindings/arm/gic.txt | 53
>>>>> ++++++++++++++++++++++++
>>>>> arch/arm/common/gic.c | 55
>>>>> +++++++++++++++++++++++--
>>>>> arch/arm/include/asm/hardware/gic.h | 10 +++++
>>>>> 3 files changed, 114 insertions(+), 4 deletions(-)
>>>>> create mode 100644 Documentation/devicetree/bindings/arm/gic.txt
>>>>
>>>> [...]
>>>>
>>>>
>>>>> diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
>>>>> index d1ccc72..14de380 100644
>>>>> --- a/arch/arm/common/gic.c
>>>>> +++ b/arch/arm/common/gic.c
>>>>
>>>> [...]
>>>>
>>>>> +void __init gic_of_init(struct device_node *node, struct device_node
>>>>> *parent)
>>>>> +{
>>>>> + void __iomem *cpu_base;
>>>>> + void __iomem *dist_base;
>>>>> + int irq;
>>>>> + struct irq_domain *domain =&gic_data[gic_cnt].domain;
>>>>> +
>>>>> + if (WARN_ON(!node))
>>>>> + return;
>>>>> +
>>>>> + dist_base = of_iomap(node, 0);
>>>>> + WARN(!dist_base, "unable to map gic dist registers\n");
>>>>> +
>>>>> + cpu_base = of_iomap(node, 1);
>>>>> + WARN(!cpu_base, "unable to map gic cpu registers\n");
>>>>> +
>>>>> + domain->nr_irq = gic_irq_count(dist_base);
>>>>> + domain->irq_base = irq_alloc_descs(-1, 0, domain->nr_irq,
>>>>> numa_node_id());
>>>>
>>>> For exynos4, all the interrupts originating from GIC are statically
>>>> mapped to start from 32 in the linux virq space (GIC SPI interrupts
>>>> start from 64). In the above code, since irq_base would be 0 for
>>>> exynos4, the interrupt mapping is not working correctly. In your
>>>> previous version of the patch, you have given a option to the platform
>>>> code to choose the offset. Could that option be added to this series
>>>> also. Or a provision to use platform specific translate function
>>>> instead of the irq_domain_simple translator.
>>>
>>> I have another concern on a similar topic.
>>>
>>> On OMAP4 the SoC interrupts external to the MPU (SPI) have an offset of
>>> 32. Only the internal PPI are between 0 and 31.
>>>
>>> For the moment we add 32 to every SoC interrupts in the irq.h define,
>>
>> Those defines will not be used in the DT case. So the question is
>> whether to add 32 or not in the DT. Since we have just a single node and
>> a linear mapping of PPIs and SPIs, the only choice is to have SPIs start
>> at 32. And from the h/w definition, SPIs always start at 32, so it's in
>> agreement.
>
> This is a agreement inside the MPUSS, but not outside.
> Both Tegra and OMAP4 must add an offset to the HW irq number to deal
> with that today.
>
>>> but I'm assuming that this offset calculation should be done thanks to a
>>> dedicated irq domain for the SPI.
>>> The real HW physical number start at 0, and thus this is that value that
>>> should be in the irq binding of the device.
>>>
>>> So ideally we should have a irq domain for the PPI starting at 0 and
>>> another one for the SPI starting at 32. Or 32 and 64 for the exynos4
>>> case, but it looks like the PPI/SPI offset is always 32.
>>>
>>
>> That offset of SPIs is always there. If you have a GIC as a secondary
>> controller, It will have 32 reserved interrupts and the register layout
>> is exactly the same as a cpu's GIC.
>
> Yep, but that's the GIC view and not the SoC one. My concern is to have
> to tweak the HW number provided by the HW spec in order to add that offset.
> If you look at SoC level, the MPUSS is just an IP that can be
> potentially replaced by other one that will not have a GIC. In that case
> you will not change the IRQ mapping at SoC level.
> For example if you replace the Dual-cortexA9 by a single CortexA8, then
> all the interrupts will have to be shifted by 32 just because the MPU
> subsystem is different.
>
Is that a realistic case? That would be a new chip and new device tree.
You could argue that the whole peripheral subsystem DT could be reused
and the numbering needs to be the same. However, there's one thing that
would prevent that. The number of interrupt cells is defined by the
controller binding. So you have to change the peripheral nodes anyway.
It's good that OMAP is trying to standardize the peripheral layout, but
in my experience that's not something you can rely on.
At some point the interrupt numbering is going to differ from the h/w
documentation. If it's not in the DT, then it will be in linux. Right
now its just offset of 32, but if irqdescs get assigned on demand as PPC
is doing, then there will be no relationship to the documentation.
> Since that offset is dependent of the GIC internals and is not exposed
> outside the MPUSS, it should not be visible by the SoC IPs. And the HW
> spec is exposing exactly that.
>
>> Since the idea of splitting PPIs for each core out to a flattened linux
>> irq map has been abandoned, I see no reason to have more than 1 domain
>> with a simple linear translation. Ultimately, domains will do dynamic
>> irqdesc allocation and the translation within the gic will be completely
>> dynamic.
>
> I think the only reason to do that is to separate internal MPU
> interrupts with the external ones that should not have a clue about the
> GIC.
I see 2 options (besides leaving it as is):
- Revert back to my previous binding where PPIs are a sub-node and a
different interrupt parent.
- Use the current binding, but allow SPIs to start at 0. We can still
distinguish PPIs and SPIs by the cpu mask cell. A cpu mask of 0 is a
SPI. If there was ever a reason to have a cpu mask for an SPI, you would
not be able to with this scheme.
Either way you will still have the above issue with the cell size changing.
Rob
^ permalink raw reply
* [RFC PATCH 0/3] genirq: handling GIC per-cpu interrupts
From: Marc Zyngier @ 2011-09-15 16:52 UTC (permalink / raw)
To: linux-arm-kernel
The current GIC per-cpu interrupts (aka PPIs) suffer from a number of
problems:
- They use a completely separate scheme to handle the interrupts,
mostly because the PPI concept doesn't really match the kernel view
of an interrupt.
- PPIs can only be used by the timer code, unless we add more low-level
assembly code.
- The local timer code can only be used by devices generating PPIs,
and not SPIs.
- At least one platform (msm) has started implementing its own
alternative scheme.
- Some low-level code gets duplicated, as usual...
The proposed solution is to handle the PPIs using the same path as
SPIs. A new core API is added to deal with per-cpu interrupts in a
less awkward way. The local timer code is updated to reflect these
changes.
The core API changes are based on an initial patch by Thomas Gleixner.
Tested on ARM Versatile Express (Cortex A5 and A15), ARM RealView
PB11MP, OMAP4 (Panda) and Tegra (Harmony). Patch series against
next-20110831.
Marc Zyngier (3):
genirq: add support for per-cpu dev_id interrupts
ARM: gic: consolidate PPI handling
ARM: gic, local timers: use the request_percpu_irq() interface
arch/arm/common/Kconfig | 1 +
arch/arm/common/gic.c | 38 +++-
arch/arm/include/asm/entry-macro-multi.S | 7 -
arch/arm/include/asm/hardirq.h | 3 -
arch/arm/include/asm/hardware/entry-macro-gic.S | 19 +--
arch/arm/include/asm/hardware/gic.h | 1 -
arch/arm/include/asm/localtimer.h | 19 +-
arch/arm/include/asm/smp.h | 5 -
arch/arm/include/asm/smp_twd.h | 2 +-
arch/arm/kernel/irq.c | 3 -
arch/arm/kernel/smp.c | 33 +---
arch/arm/kernel/smp_twd.c | 47 +++++-
arch/arm/mach-exynos4/include/mach/entry-macro.S | 6 +-
arch/arm/mach-exynos4/mct.c | 5 -
arch/arm/mach-msm/board-msm8x60.c | 11 -
arch/arm/mach-msm/include/mach/entry-macro-qgic.S | 73 +-------
arch/arm/mach-msm/timer.c | 69 ++++---
arch/arm/mach-omap2/include/mach/entry-macro.S | 14 +--
arch/arm/mach-shmobile/entry-intc.S | 3 -
arch/arm/mach-shmobile/include/mach/entry-macro.S | 3 -
include/linux/interrupt.h | 40 +++-
include/linux/irq.h | 25 +++-
include/linux/irqdesc.h | 3 +
kernel/irq/Kconfig | 4 +
kernel/irq/chip.c | 58 ++++++
kernel/irq/internals.h | 2 +
kernel/irq/manage.c | 209 ++++++++++++++++++++-
kernel/irq/settings.h | 7 +
28 files changed, 461 insertions(+), 249 deletions(-)
^ permalink raw reply
* [RFC PATCH 1/3] genirq: add support for per-cpu dev_id interrupts
From: Marc Zyngier @ 2011-09-15 16:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316105551-17505-1-git-send-email-marc.zyngier@arm.com>
The ARM GIC interrupt controller offers per CPU interrupts (PPIs),
which are usually used to connect local timers to each core.
Each CPU has its own private interface to the GIC,
and only sees the PPIs that are directly connect to it.
While these timers are separate devices and have a separate
interrupt line to a core, they all use the same IRQ number.
For these devices, request_irq() is not the right API as it
assumes that an IRQ number is visible by a number of CPUs
(through the affinity setting), but makes it very awkward to
express that an IRQ number can be handled by all CPUs, and
yet be a different interrupt line on each CPU, requiring a
different dev_id cookie to be passed back to the handler.
The *_percpu_irq() functions is designed to overcome these
limitations, by providing a per-cpu dev_id vector:
int request_percpu_irq(unsigned int irq, irq_handler_t handler,
const char *devname, void __percpu *percpu_dev_id);
void free_percpu_irq(unsigned int, void __percpu *);
int setup_percpu_irq(unsigned int irq, struct irqaction *new);
void remove_percpu_irq(unsigned int irq, struct irqaction *act);
void enable_percpu_irq(unsigned int irq);
void disable_percpu_irq(unsigned int irq);
The API has a number of limitations:
- no interrupt sharing
- no threading
- common handler across all the CPUs
Once the interrupt is requested using setup_percpu_irq() or
request_percpu_irq(), it must be enabled by each core that wishes
its local interrupt to be delivered.
Based on an initial patch by Thomas Gleixner.
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
include/linux/interrupt.h | 40 ++++++---
include/linux/irq.h | 25 +++++-
include/linux/irqdesc.h | 3 +
kernel/irq/Kconfig | 4 +
kernel/irq/chip.c | 58 +++++++++++++
kernel/irq/internals.h | 2 +
kernel/irq/manage.c | 209 ++++++++++++++++++++++++++++++++++++++++++++-
kernel/irq/settings.h | 7 ++
8 files changed, 332 insertions(+), 16 deletions(-)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index a103732..f9b7fa3 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -95,6 +95,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
* @flags: flags (see IRQF_* above)
* @name: name of the device
* @dev_id: cookie to identify the device
+ * @percpu_dev_id: cookie to identify the device
* @next: pointer to the next irqaction for shared interrupts
* @irq: interrupt number
* @dir: pointer to the proc/irq/NN/name entry
@@ -104,17 +105,20 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
* @thread_mask: bitmask for keeping track of @thread activity
*/
struct irqaction {
- irq_handler_t handler;
- unsigned long flags;
- void *dev_id;
- struct irqaction *next;
- int irq;
- irq_handler_t thread_fn;
- struct task_struct *thread;
- unsigned long thread_flags;
- unsigned long thread_mask;
- const char *name;
- struct proc_dir_entry *dir;
+ irq_handler_t handler;
+ unsigned long flags;
+ void *dev_id;
+#ifdef CONFIG_IRQ_PERCPU_DEVID
+ void __percpu *percpu_dev_id;
+#endif
+ struct irqaction *next;
+ int irq;
+ irq_handler_t thread_fn;
+ struct task_struct *thread;
+ unsigned long thread_flags;
+ unsigned long thread_mask;
+ const char *name;
+ struct proc_dir_entry *dir;
} ____cacheline_internodealigned_in_smp;
extern irqreturn_t no_action(int cpl, void *dev_id);
@@ -136,6 +140,10 @@ extern int __must_check
request_any_context_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev_id);
+extern int __must_check
+request_percpu_irq(unsigned int irq, irq_handler_t handler,
+ const char *devname, void __percpu *percpu_dev_id);
+
extern void exit_irq_thread(void);
#else
@@ -164,10 +172,18 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
return request_irq(irq, handler, flags, name, dev_id);
}
+static inline int __must_check
+request_percpu_irq(unsigned int irq, irq_handler_t handler,
+ const char *devname, void __percpu *percpu_dev_id)
+{
+ return request_irq(irq, handler, 0, name, dev_id);
+}
+
static inline void exit_irq_thread(void) { }
#endif
extern void free_irq(unsigned int, void *);
+extern void free_percpu_irq(unsigned int, void __percpu *);
struct device;
@@ -207,7 +223,9 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
extern void disable_irq_nosync(unsigned int irq);
extern void disable_irq(unsigned int irq);
+extern void disable_percpu_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);
+extern void enable_percpu_irq(unsigned int irq);
/* The following three functions are for the core kernel use only. */
#ifdef CONFIG_GENERIC_HARDIRQS
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 5951730..1e14fd1 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -66,6 +66,7 @@ typedef void (*irq_preflow_handler_t)(struct irq_data *data);
* IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set)
* IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context
* IRQ_NESTED_TRHEAD - Interrupt nests into another thread
+ * IRQ_PER_CPU_DEVID - Dev_id is a per-cpu variable
*/
enum {
IRQ_TYPE_NONE = 0x00000000,
@@ -88,12 +89,13 @@ enum {
IRQ_MOVE_PCNTXT = (1 << 14),
IRQ_NESTED_THREAD = (1 << 15),
IRQ_NOTHREAD = (1 << 16),
+ IRQ_PER_CPU_DEVID = (1 << 17),
};
#define IRQF_MODIFY_MASK \
(IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
- IRQ_PER_CPU | IRQ_NESTED_THREAD)
+ IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID)
#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
@@ -365,6 +367,8 @@ enum {
struct irqaction;
extern int setup_irq(unsigned int irq, struct irqaction *new);
extern void remove_irq(unsigned int irq, struct irqaction *act);
+extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
+extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
extern void irq_cpu_online(void);
extern void irq_cpu_offline(void);
@@ -392,6 +396,7 @@ extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
+extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_nested_irq(unsigned int irq);
@@ -481,6 +486,24 @@ static inline void irq_set_nested_thread(unsigned int irq, bool nest)
irq_clear_status_flags(irq, IRQ_NESTED_THREAD);
}
+#ifdef CONFIG_IRQ_PERCPU_DEVID
+static inline int irq_set_percpu_devid(unsigned int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (!desc)
+ return -EINVAL;
+
+ if (!zalloc_cpumask_var(&desc->percpu_enabled, GFP_KERNEL))
+ return -ENOMEM;
+
+ irq_set_status_flags(irq,
+ IRQ_NOAUTOEN | IRQ_PER_CPU | IRQ_NOTHREAD |
+ IRQ_NOPROBE | IRQ_PER_CPU_DEVID);
+ return 0;
+}
+#endif
+
/* Handle dynamic irq creation and destruction */
extern unsigned int create_irq_nr(unsigned int irq_want, int node);
extern int create_irq(void);
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 150134a..0b4419a 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -53,6 +53,9 @@ struct irq_desc {
unsigned long last_unhandled; /* Aging timer for unhandled count */
unsigned int irqs_unhandled;
raw_spinlock_t lock;
+#ifdef CONFIG_IRQ_PERCPU_DEVID
+ cpumask_var_t percpu_enabled;
+#endif
#ifdef CONFIG_SMP
const struct cpumask *affinity_hint;
struct irq_affinity_notify *affinity_notify;
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 5a38bf4..75c0631 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -60,6 +60,10 @@ config IRQ_DOMAIN
config IRQ_FORCED_THREADING
bool
+# Support per CPU dev id
+config IRQ_PERCPU_DEVID
+ bool
+
config SPARSE_IRQ
bool "Support sparse irq numbering"
depends on HAVE_SPARSE_IRQ
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index d5a3009..d65b23f 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -204,6 +204,30 @@ void irq_disable(struct irq_desc *desc)
}
}
+#ifdef CONFIG_IRQ_PERCPU_DEVID
+void irq_percpu_enable(struct irq_desc *desc)
+{
+ unsigned int cpu = get_cpu();
+ if (desc->irq_data.chip->irq_enable)
+ desc->irq_data.chip->irq_enable(&desc->irq_data);
+ else
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ cpumask_set_cpu(cpu, desc->percpu_enabled);
+ put_cpu();
+}
+
+void irq_percpu_disable(struct irq_desc *desc)
+{
+ unsigned int cpu = get_cpu();
+ if (desc->irq_data.chip->irq_disable) {
+ desc->irq_data.chip->irq_disable(&desc->irq_data);
+ irq_state_set_masked(desc);
+ }
+ cpumask_clear_cpu(cpu, desc->percpu_enabled);
+ put_cpu();
+}
+#endif
+
static inline void mask_ack_irq(struct irq_desc *desc)
{
if (desc->irq_data.chip->irq_mask_ack)
@@ -544,6 +568,40 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
chip->irq_eoi(&desc->irq_data);
}
+#ifdef CONFIG_IRQ_PERCPU_DEVID
+/**
+ * handle_percpu_devid_irq - Per CPU local irq handler with per cpu dev ids
+ * @irq: the interrupt number
+ * @desc: the interrupt description structure for this irq
+ *
+ * Per CPU interrupts on SMP machines without locking requirements. Same as
+ * handle_percpu_irq() above but with the following extras:
+ *
+ * action->percpu_dev_id is a pointer to percpu variables which
+ * contain the real device id for the cpu on which this handler is
+ * called
+ */
+void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irqaction *action = desc->action;
+ void *dev_id = __this_cpu_ptr(action->percpu_dev_id);
+ irqreturn_t res;
+
+ kstat_incr_irqs_this_cpu(irq, desc);
+
+ if (chip->irq_ack)
+ chip->irq_ack(&desc->irq_data);
+
+ trace_irq_handler_entry(irq, action);
+ res = action->handler(irq, dev_id);
+ trace_irq_handler_exit(irq, action, res);
+
+ if (chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
+}
+#endif
+
void
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
const char *name)
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 6546431..a57fd3b 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -71,6 +71,8 @@ extern int irq_startup(struct irq_desc *desc);
extern void irq_shutdown(struct irq_desc *desc);
extern void irq_enable(struct irq_desc *desc);
extern void irq_disable(struct irq_desc *desc);
+extern void irq_percpu_enable(struct irq_desc *desc);
+extern void irq_percpu_disable(struct irq_desc *desc);
extern void mask_irq(struct irq_desc *desc);
extern void unmask_irq(struct irq_desc *desc);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 9b956fa..9f10b07 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1118,6 +1118,8 @@ int setup_irq(unsigned int irq, struct irqaction *act)
int retval;
struct irq_desc *desc = irq_to_desc(irq);
+ if (irq_settings_is_per_cpu_devid(desc))
+ return -EINVAL;
chip_bus_lock(desc);
retval = __setup_irq(irq, desc, act);
chip_bus_sync_unlock(desc);
@@ -1126,7 +1128,7 @@ int setup_irq(unsigned int irq, struct irqaction *act)
}
EXPORT_SYMBOL_GPL(setup_irq);
- /*
+/*
* Internal function to unregister an irqaction - used to free
* regular and special interrupts that are part of the architecture.
*/
@@ -1224,7 +1226,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
*/
void remove_irq(unsigned int irq, struct irqaction *act)
{
- __free_irq(irq, act->dev_id);
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (desc && !irq_settings_is_per_cpu_devid(desc))
+ __free_irq(irq, act->dev_id);
}
EXPORT_SYMBOL_GPL(remove_irq);
@@ -1246,7 +1251,7 @@ void free_irq(unsigned int irq, void *dev_id)
{
struct irq_desc *desc = irq_to_desc(irq);
- if (!desc)
+ if (!desc || irq_settings_is_per_cpu_devid(desc))
return;
#ifdef CONFIG_SMP
@@ -1324,7 +1329,8 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
if (!desc)
return -EINVAL;
- if (!irq_settings_can_request(desc))
+ if (!irq_settings_can_request(desc) ||
+ irq_settings_is_per_cpu_devid(desc))
return -EINVAL;
if (!handler) {
@@ -1409,3 +1415,198 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler,
return !ret ? IRQC_IS_HARDIRQ : ret;
}
EXPORT_SYMBOL_GPL(request_any_context_irq);
+
+#ifdef CONFIG_IRQ_PERCPU_DEVID
+void enable_percpu_irq(unsigned int irq)
+{
+ unsigned long flags;
+ struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
+
+ if (!desc)
+ return;
+
+ irq_percpu_enable(desc);
+ irq_put_desc_busunlock(desc, flags);
+}
+EXPORT_SYMBOL(enable_percpu_irq);
+
+void disable_percpu_irq(unsigned int irq)
+{
+ unsigned long flags;
+ struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
+
+ if (!desc)
+ return;
+
+ irq_percpu_disable(desc);
+ irq_put_desc_busunlock(desc, flags);
+}
+EXPORT_SYMBOL(disable_percpu_irq);
+
+/*
+ * Internal function to unregister a percpu irqaction.
+ */
+static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_id)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irqaction *action;
+ unsigned long flags;
+
+ WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
+
+ if (!desc)
+ return NULL;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+
+ action = desc->action;
+ if (!action || action->percpu_dev_id != dev_id) {
+ WARN(1, "Trying to free already-free IRQ %d\n", irq);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ return NULL;
+ }
+
+ /* Found it - now remove it from the list of entries: */
+ WARN(!cpumask_empty(desc->percpu_enabled),
+ "percpu IRQ %d still enabled on CPU%d!\n",
+ irq, cpumask_first(desc->percpu_enabled));
+ desc->action = NULL;
+
+#ifdef CONFIG_SMP
+ /* make sure affinity_hint is cleaned up */
+ if (WARN_ON_ONCE(desc->affinity_hint))
+ desc->affinity_hint = NULL;
+#endif
+
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+
+ unregister_handler_proc(irq, action);
+
+ /* Make sure it's not being used on another CPU: */
+ synchronize_irq(irq);
+
+ module_put(desc->owner);
+ return action;
+}
+
+/**
+ * remove_percpu_irq - free a per-cpu interrupt
+ * @irq: Interrupt line to free
+ * @act: irqaction for the interrupt
+ *
+ * Used to remove interrupts statically setup by the early boot process.
+ */
+void remove_percpu_irq(unsigned int irq, struct irqaction *act)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (desc && irq_settings_is_per_cpu_devid(desc))
+ __free_percpu_irq(irq, act->percpu_dev_id);
+}
+EXPORT_SYMBOL_GPL(remove_percpu_irq);
+
+/**
+ * free_percpu_irq - free an interrupt allocated with request_percpu_irq
+ * @irq: Interrupt line to free
+ * @dev_id: Device identity to free
+ *
+ * Remove a percpu interrupt handler. The handler is removed, but
+ * the interrupt line is not disabled. This must be done on each
+ * CPU before calling this function. The function does not return
+ * until any executing interrupts for this IRQ have completed.
+ *
+ * This function must not be called from interrupt context.
+ */
+void free_percpu_irq(unsigned int irq, void __percpu *dev_id)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (!desc || !irq_settings_is_per_cpu_devid(desc))
+ return;
+
+#ifdef CONFIG_SMP
+ if (WARN_ON(desc->affinity_notify))
+ desc->affinity_notify = NULL;
+#endif
+
+ chip_bus_lock(desc);
+ kfree(__free_percpu_irq(irq, dev_id));
+ chip_bus_sync_unlock(desc);
+}
+EXPORT_SYMBOL(free_percpu_irq);
+
+/**
+ * setup_percpu_irq - setup a per-cpu interrupt
+ * @irq: Interrupt line to setup
+ * @act: irqaction for the interrupt
+ *
+ * Used to statically setup per-cpu interrupts in the early boot process.
+ */
+int setup_percpu_irq(unsigned int irq, struct irqaction *act)
+{
+ int retval;
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (!irq_settings_is_per_cpu_devid(desc))
+ return -EINVAL;
+ chip_bus_lock(desc);
+ retval = __setup_irq(irq, desc, act);
+ chip_bus_sync_unlock(desc);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(setup_percpu_irq);
+
+/**
+ * request_percpu_irq - allocate a percpu interrupt line
+ * @irq: Interrupt line to allocate
+ * @handler: Function to be called when the IRQ occurs.
+ * Primary handler for threaded interrupts
+ * If NULL and thread_fn != NULL the default
+ * primary handler is installed
+ * @devname: An ascii name for the claiming device
+ * @dev_id: A percpu cookie passed back to the handler function
+ *
+ * This call allocates interrupt resources, but doesn't
+ * automatically enable the interrupt. It has to be done on each
+ * CPU using enable_percpu_irq().
+ *
+ * Dev_id must be globally unique. It is a per-cpu variable, and
+ * the handler gets called with the interrupted CPU's instance of
+ * that variable.
+ */
+int request_percpu_irq(unsigned int irq, irq_handler_t handler,
+ const char *devname, void __percpu *dev_id)
+{
+ struct irqaction *action;
+ struct irq_desc *desc;
+ int retval;
+
+ if (!dev_id)
+ return -EINVAL;
+
+ desc = irq_to_desc(irq);
+ if (!desc || !irq_settings_can_request(desc) ||
+ !irq_settings_is_per_cpu_devid(desc))
+ return -EINVAL;
+
+ action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = IRQF_PERCPU;
+ action->name = devname;
+ action->percpu_dev_id = dev_id;
+
+ chip_bus_lock(desc);
+ retval = __setup_irq(irq, desc, action);
+ chip_bus_sync_unlock(desc);
+
+ if (retval)
+ kfree(action);
+
+ return retval;
+}
+EXPORT_SYMBOL(request_percpu_irq);
+#endif
diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
index f166783..1162f10 100644
--- a/kernel/irq/settings.h
+++ b/kernel/irq/settings.h
@@ -13,6 +13,7 @@ enum {
_IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT,
_IRQ_NO_BALANCING = IRQ_NO_BALANCING,
_IRQ_NESTED_THREAD = IRQ_NESTED_THREAD,
+ _IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID,
_IRQF_MODIFY_MASK = IRQF_MODIFY_MASK,
};
@@ -24,6 +25,7 @@ enum {
#define IRQ_NOTHREAD GOT_YOU_MORON
#define IRQ_NOAUTOEN GOT_YOU_MORON
#define IRQ_NESTED_THREAD GOT_YOU_MORON
+#define IRQ_PER_CPU_DEVID GOT_YOU_MORON
#undef IRQF_MODIFY_MASK
#define IRQF_MODIFY_MASK GOT_YOU_MORON
@@ -39,6 +41,11 @@ static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)
return desc->status_use_accessors & _IRQ_PER_CPU;
}
+static inline bool irq_settings_is_per_cpu_devid(struct irq_desc *desc)
+{
+ return desc->status_use_accessors & _IRQ_PER_CPU_DEVID;
+}
+
static inline void irq_settings_set_per_cpu(struct irq_desc *desc)
{
desc->status_use_accessors |= _IRQ_PER_CPU;
--
1.7.0.4
^ permalink raw reply related
* [RFC PATCH 2/3] ARM: gic: consolidate PPI handling
From: Marc Zyngier @ 2011-09-15 16:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316105551-17505-1-git-send-email-marc.zyngier@arm.com>
PPI handling is a bit of an odd beast. It uses its own low level
handling code and is hardwired to the local timers (hence lacking
a registration interface).
Instead, switch the low handling to the normal SPI handling code.
PPIs are handled by the handle_percpu_devid_irq flow.
This also allows the removal of some duplicated code.
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: David Brown <davidb@codeaurora.org>
Cc: Bryan Huntsman <bryanh@codeaurora.org>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/common/Kconfig | 1 +
arch/arm/common/gic.c | 70 +++++++++++++++++++-
arch/arm/include/asm/entry-macro-multi.S | 7 --
arch/arm/include/asm/hardirq.h | 3 -
arch/arm/include/asm/hardware/entry-macro-gic.S | 19 +-----
arch/arm/include/asm/localtimer.h | 6 +-
arch/arm/include/asm/smp.h | 5 --
arch/arm/kernel/irq.c | 3 -
arch/arm/kernel/smp.c | 27 ++------
arch/arm/mach-exynos4/include/mach/entry-macro.S | 6 +--
arch/arm/mach-msm/board-msm8x60.c | 11 ---
arch/arm/mach-msm/include/mach/entry-macro-qgic.S | 73 +--------------------
arch/arm/mach-omap2/include/mach/entry-macro.S | 14 +----
arch/arm/mach-shmobile/entry-intc.S | 3 -
arch/arm/mach-shmobile/include/mach/entry-macro.S | 3 -
15 files changed, 84 insertions(+), 167 deletions(-)
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 4b71766..114a432 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -1,4 +1,5 @@
config ARM_GIC
+ select IRQ_PERCPU_DEVID
bool
config ARM_VIC
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 666b278..4bbcce8 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -28,10 +28,14 @@
#include <linux/smp.h>
#include <linux/cpumask.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>
+#include <asm/localtimer.h>
static DEFINE_SPINLOCK(irq_controller_lock);
@@ -255,6 +259,32 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
+#ifdef CONFIG_LOCAL_TIMERS
+#define gic_ppi_handler percpu_timer_handler
+#else
+static irqreturn_t gic_ppi_handler(int irq, void *dev_id)
+{
+ return IRQ_NONE;
+}
+#endif
+
+#define PPI_IRQACT(nr) \
+ { \
+ .handler = gic_ppi_handler, \
+ .flags = IRQF_PERCPU | IRQF_TIMER, \
+ .irq = nr, \
+ .name = "PPI-" # nr, \
+ }
+
+static struct irqaction ppi_irqaction_template[16] __initdata = {
+ PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3),
+ PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7),
+ PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11),
+ PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15),
+};
+
+static struct irqaction *ppi_irqaction;
+
static void __init gic_dist_init(struct gic_chip_data *gic,
unsigned int irq_start)
{
@@ -262,6 +292,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
u32 cpumask;
void __iomem *base = gic->dist_base;
u32 cpu = 0;
+ u32 nrppis = 0, ppi_base = 0;
#ifdef CONFIG_SMP
cpu = cpu_logical_map(smp_processor_id());
@@ -283,6 +314,28 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
gic_irqs = 1020;
/*
+ * Nobody would be insane enough to use PPIs on a secondary
+ * GIC, right?
+ */
+ if (gic == &gic_data[0]) {
+ nrppis = 16 - (irq_start & 15);
+ ppi_base = gic->irq_offset + 32 - nrppis;
+
+ ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis],
+ sizeof(*ppi_irqaction) * nrppis,
+ GFP_KERNEL);
+
+ if (nrppis && !ppi_irqaction) {
+ pr_err("GIC: Can't allocate PPI memory");
+ nrppis = 0;
+ ppi_base = 0;
+ }
+ }
+
+ pr_info("Configuring GIC with %d sources (%d PPIs)\n",
+ gic_irqs, (gic == &gic_data[0]) ? nrppis : 0);
+
+ /*
* Set all global interrupts to be level triggered, active low.
*/
for (i = 32; i < gic_irqs; i += 16)
@@ -317,7 +370,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
/*
* Setup the Linux IRQ subsystem.
*/
- for (i = irq_start; i < irq_limit; i++) {
+ for (i = 0; i < nrppis; i++) {
+ int ppi = i + ppi_base;
+ int err;
+
+ irq_set_percpu_devid(ppi);
+ irq_set_chip_and_handler(ppi, &gic_chip,
+ handle_percpu_devid_irq);
+ irq_set_chip_data(ppi, gic);
+ set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
+
+ err = setup_percpu_irq(ppi, &ppi_irqaction[i]);
+ if (err)
+ pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err);
+ }
+
+ for (i = irq_start + nrppis; i < irq_limit; i++) {
irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
irq_set_chip_data(i, gic);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S
index 2f1e209..88d6181 100644
--- a/arch/arm/include/asm/entry-macro-multi.S
+++ b/arch/arm/include/asm/entry-macro-multi.S
@@ -25,13 +25,6 @@
movne r1, sp
adrne lr, BSYM(1b)
bne do_IPI
-
-#ifdef CONFIG_LOCAL_TIMERS
- test_for_ltirq r0, r2, r6, lr
- movne r0, sp
- adrne lr, BSYM(1b)
- bne do_local_timer
-#endif
#endif
9997:
.endm
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 89ad180..ddf07a9 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -9,9 +9,6 @@
typedef struct {
unsigned int __softirq_pending;
-#ifdef CONFIG_LOCAL_TIMERS
- unsigned int local_timer_irqs;
-#endif
#ifdef CONFIG_SMP
unsigned int ipi_irqs[NR_IPI];
#endif
diff --git a/arch/arm/include/asm/hardware/entry-macro-gic.S b/arch/arm/include/asm/hardware/entry-macro-gic.S
index c115b82..74ebc80 100644
--- a/arch/arm/include/asm/hardware/entry-macro-gic.S
+++ b/arch/arm/include/asm/hardware/entry-macro-gic.S
@@ -22,15 +22,11 @@
* interrupt controller spec. To wit:
*
* Interrupts 0-15 are IPI
- * 16-28 are reserved
- * 29-31 are local. We allow 30 to be used for the watchdog.
+ * 16-31 are local. We allow 30 to be used for the watchdog.
* 32-1020 are global
* 1021-1022 are reserved
* 1023 is "spurious" (no interrupt)
*
- * For now, we ignore all local interrupts so only return an interrupt if it's
- * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs.
- *
* A simple read from the controller will tell us the number of the highest
* priority enabled interrupt. We then just need to check whether it is in the
* valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@
ldr \tmp, =1021
bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #29
+ cmp \irqnr, #15
cmpcc \irqnr, \irqnr
cmpne \irqnr, \tmp
cmpcs \irqnr, \irqnr
@@ -62,14 +58,3 @@
strcc \irqstat, [\base, #GIC_CPU_EOI]
cmpcs \irqnr, \irqnr
.endm
-
-/* As above, this assumes that irqstat and base are preserved.. */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #29
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
- .endm
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index 080d74f..e3663f7 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -10,6 +10,8 @@
#ifndef __ASM_ARM_LOCALTIMER_H
#define __ASM_ARM_LOCALTIMER_H
+#include <linux/interrupt.h>
+
struct clock_event_device;
/*
@@ -18,9 +20,9 @@ struct clock_event_device;
void percpu_timer_setup(void);
/*
- * Called from assembly, this is the local timer IRQ handler
+ * Per-cpu timer IRQ handler
*/
-asmlinkage void do_local_timer(struct pt_regs *);
+irqreturn_t percpu_timer_handler(int irq, void *dev_id);
#ifdef CONFIG_LOCAL_TIMERS
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 674ebcd..7c2299f 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -94,9 +94,4 @@ extern void platform_cpu_enable(unsigned int cpu);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-/*
- * show local interrupt info
- */
-extern void show_local_irqs(struct seq_file *, int);
-
#endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index e20a5d0..8e744f6 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -58,9 +58,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
#ifdef CONFIG_SMP
show_ipi_list(p, prec);
#endif
-#ifdef CONFIG_LOCAL_TIMERS
- show_local_irqs(p, prec);
-#endif
seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
return 0;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 04d7b80..e3dbd99 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -504,10 +504,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
for (i = 0; i < NR_IPI; i++)
sum += __get_irq_stat(cpu, ipi_irqs[i]);
-#ifdef CONFIG_LOCAL_TIMERS
- sum += __get_irq_stat(cpu, local_timer_irqs);
-#endif
-
return sum;
}
@@ -525,29 +521,16 @@ static void ipi_timer(void)
}
#ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
+irqreturn_t percpu_timer_handler(int irq, void *dev_id)
{
- struct pt_regs *old_regs = set_irq_regs(regs);
- int cpu = smp_processor_id();
+ struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
if (local_timer_ack()) {
- __inc_irq_stat(cpu, local_timer_irqs);
- ipi_timer();
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
}
- set_irq_regs(old_regs);
-}
-
-void show_local_irqs(struct seq_file *p, int prec)
-{
- unsigned int cpu;
-
- seq_printf(p, "%*s: ", prec, "LOC");
-
- for_each_present_cpu(cpu)
- seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
-
- seq_printf(p, " Local timer interrupts\n");
+ return IRQ_NONE;
}
#endif
diff --git a/arch/arm/mach-exynos4/include/mach/entry-macro.S b/arch/arm/mach-exynos4/include/mach/entry-macro.S
index d7a1e28..807d05d 100644
--- a/arch/arm/mach-exynos4/include/mach/entry-macro.S
+++ b/arch/arm/mach-exynos4/include/mach/entry-macro.S
@@ -55,7 +55,7 @@
bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #29
+ cmp \irqnr, #15
cmpcc \irqnr, \irqnr
cmpne \irqnr, \tmp
cmpcs \irqnr, \irqnr
@@ -77,7 +77,3 @@
cmpcs \irqnr, \irqnr
.endm
- /* As above, this assumes that irqstat and base are preserved.. */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- .endm
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 9221f54..106170f 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -53,8 +53,6 @@ static void __init msm8x60_map_io(void)
static void __init msm8x60_init_irq(void)
{
- unsigned int i;
-
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
(void *)MSM_QGIC_CPU_BASE);
@@ -66,15 +64,6 @@ static void __init msm8x60_init_irq(void)
*/
if (!machine_is_msm8x60_sim())
writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
-
- /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
- * as they are configured as level, which does not play nice with
- * handle_percpu_irq.
- */
- for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
- if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
- irq_set_handler(i, handle_percpu_irq);
- }
}
static void __init msm8x60_init(void)
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
index 1246715..717076f 100644
--- a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
+++ b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
@@ -8,81 +8,10 @@
* warranty of any kind, whether express or implied.
*/
-#include <mach/hardware.h>
-#include <asm/hardware/gic.h>
+#include <asm/hardware/entry-macro-gic.S>
.macro disable_fiq
.endm
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =gic_cpu_base_addr
- ldr \base, [\base]
- .endm
-
.macro arch_ret_to_user, tmp1, tmp2
.endm
-
- /*
- * The interrupt numbering scheme is defined in the
- * interrupt controller spec. To wit:
- *
- * Migrated the code from ARM MP port to be more consistent
- * with interrupt processing , the following still holds true
- * however, all interrupts are treated the same regardless of
- * if they are local IPI or PPI
- *
- * Interrupts 0-15 are IPI
- * 16-31 are PPI
- * (16-18 are the timers)
- * 32-1020 are global
- * 1021-1022 are reserved
- * 1023 is "spurious" (no interrupt)
- *
- * A simple read from the controller will tell us the number of the
- * highest priority enabled interrupt. We then just need to check
- * whether it is in the valid range for an IRQ (0-1020 inclusive).
- *
- * Base ARM code assumes that the local (private) peripheral interrupts
- * are not valid, we treat them differently, in that the privates are
- * handled like normal shared interrupts with the exception that only
- * one processor can register the interrupt and the handler must be
- * the same for all processors.
- */
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
- ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
- 9-0 =int # */
-
- bic \irqnr, \irqstat, #0x1c00 @mask src
- cmp \irqnr, #15
- ldr \tmp, =1021
- cmpcc \irqnr, \irqnr
- cmpne \irqnr, \tmp
- cmpcs \irqnr, \irqnr
-
- .endm
-
- /* We assume that irqstat (the raw value of the IRQ acknowledge
- * register) is preserved from the macro above.
- * If there is an IPI, we immediately signal end of interrupt on the
- * controller, since this requires the original irqstat value which
- * we won't easily be able to recreate later.
- */
- .macro test_for_ipi, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #16
- strcc \irqstat, [\base, #GIC_CPU_EOI]
- cmpcs \irqnr, \irqnr
- .endm
-
- /* As above, this assumes that irqstat and base are preserved.. */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #16
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
- .endm
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
index ceb8b7e..feb90a1 100644
--- a/arch/arm/mach-omap2/include/mach/entry-macro.S
+++ b/arch/arm/mach-omap2/include/mach/entry-macro.S
@@ -78,7 +78,7 @@
4401: ldr \irqstat, [\base, #GIC_CPU_INTACK]
ldr \tmp, =1021
bic \irqnr, \irqstat, #0x1c00
- cmp \irqnr, #29
+ cmp \irqnr, #15
cmpcc \irqnr, \irqnr
cmpne \irqnr, \tmp
cmpcs \irqnr, \irqnr
@@ -101,18 +101,6 @@
it cs
cmpcs \irqnr, \irqnr
.endm
-
- /* As above, this assumes that irqstat and base are preserved */
-
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- bic \irqnr, \irqstat, #0x1c00
- mov \tmp, #0
- cmp \irqnr, #29
- itt eq
- moveq \tmp, #1
- streq \irqstat, [\base, #GIC_CPU_EOI]
- cmp \tmp, #0
- .endm
#endif /* CONFIG_SMP */
#else /* MULTI_OMAP2 */
diff --git a/arch/arm/mach-shmobile/entry-intc.S b/arch/arm/mach-shmobile/entry-intc.S
index cac0a7a..1a1c00c 100644
--- a/arch/arm/mach-shmobile/entry-intc.S
+++ b/arch/arm/mach-shmobile/entry-intc.S
@@ -51,7 +51,4 @@
.macro test_for_ipi, irqnr, irqstat, base, tmp
.endm
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- .endm
-
arch_irq_handler shmobile_handle_irq_intc
diff --git a/arch/arm/mach-shmobile/include/mach/entry-macro.S b/arch/arm/mach-shmobile/include/mach/entry-macro.S
index d791f10..8d4a416 100644
--- a/arch/arm/mach-shmobile/include/mach/entry-macro.S
+++ b/arch/arm/mach-shmobile/include/mach/entry-macro.S
@@ -27,8 +27,5 @@
.macro test_for_ipi, irqnr, irqstat, base, tmp
.endm
- .macro test_for_ltirq, irqnr, irqstat, base, tmp
- .endm
-
.macro arch_ret_to_user, tmp1, tmp2
.endm
--
1.7.0.4
^ permalink raw reply related
* [RFC PATCH 3/3] ARM: gic, local timers: use the request_percpu_irq() interface
From: Marc Zyngier @ 2011-09-15 16:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316105551-17505-1-git-send-email-marc.zyngier@arm.com>
This patch remove the hardcoded link between local timers and PPIs,
and convert the PPI users (TWD and MSM timers) to the new *_percpu_irq
interface.
PPIs are now useable for more than just the local timers.
Cc: David Brown <davidb@codeaurora.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
arch/arm/common/gic.c | 52 --------------------------
arch/arm/include/asm/hardware/gic.h | 1 -
arch/arm/include/asm/localtimer.h | 17 ++++-----
arch/arm/include/asm/smp_twd.h | 2 +-
arch/arm/kernel/smp.c | 16 +--------
arch/arm/kernel/smp_twd.c | 47 +++++++++++++++++++++++-
arch/arm/mach-exynos4/mct.c | 5 ---
arch/arm/mach-msm/timer.c | 69 ++++++++++++++++++++---------------
8 files changed, 94 insertions(+), 115 deletions(-)
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 4bbcce8..8e2f0c3 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -35,7 +35,6 @@
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>
-#include <asm/localtimer.h>
static DEFINE_SPINLOCK(irq_controller_lock);
@@ -259,32 +258,6 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
irq_set_chained_handler(irq, gic_handle_cascade_irq);
}
-#ifdef CONFIG_LOCAL_TIMERS
-#define gic_ppi_handler percpu_timer_handler
-#else
-static irqreturn_t gic_ppi_handler(int irq, void *dev_id)
-{
- return IRQ_NONE;
-}
-#endif
-
-#define PPI_IRQACT(nr) \
- { \
- .handler = gic_ppi_handler, \
- .flags = IRQF_PERCPU | IRQF_TIMER, \
- .irq = nr, \
- .name = "PPI-" # nr, \
- }
-
-static struct irqaction ppi_irqaction_template[16] __initdata = {
- PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3),
- PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7),
- PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11),
- PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15),
-};
-
-static struct irqaction *ppi_irqaction;
-
static void __init gic_dist_init(struct gic_chip_data *gic,
unsigned int irq_start)
{
@@ -320,16 +293,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
if (gic == &gic_data[0]) {
nrppis = 16 - (irq_start & 15);
ppi_base = gic->irq_offset + 32 - nrppis;
-
- ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis],
- sizeof(*ppi_irqaction) * nrppis,
- GFP_KERNEL);
-
- if (nrppis && !ppi_irqaction) {
- pr_err("GIC: Can't allocate PPI memory");
- nrppis = 0;
- ppi_base = 0;
- }
}
pr_info("Configuring GIC with %d sources (%d PPIs)\n",
@@ -372,17 +335,12 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
*/
for (i = 0; i < nrppis; i++) {
int ppi = i + ppi_base;
- int err;
irq_set_percpu_devid(ppi);
irq_set_chip_and_handler(ppi, &gic_chip,
handle_percpu_devid_irq);
irq_set_chip_data(ppi, gic);
set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
-
- err = setup_percpu_irq(ppi, &ppi_irqaction[i]);
- if (err)
- pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err);
}
for (i = irq_start + nrppis; i < irq_limit; i++) {
@@ -443,16 +401,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr)
gic_cpu_init(&gic_data[gic_nr]);
}
-void __cpuinit gic_enable_ppi(unsigned int irq)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- irq_set_status_flags(irq, IRQ_NOPROBE);
- gic_unmask_irq(irq_get_irq_data(irq));
- local_irq_restore(flags);
-}
-
#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 435d3f8..2dadd50 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -40,7 +40,6 @@ void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
void gic_secondary_init(unsigned int);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
-void gic_enable_ppi(unsigned int);
struct gic_chip_data {
unsigned int irq_offset;
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index e3663f7..f5e1cec 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -19,27 +19,20 @@ struct clock_event_device;
*/
void percpu_timer_setup(void);
-/*
- * Per-cpu timer IRQ handler
- */
-irqreturn_t percpu_timer_handler(int irq, void *dev_id);
-
-
#ifdef CONFIG_LOCAL_TIMERS
#ifdef CONFIG_HAVE_ARM_TWD
#include "smp_twd.h"
-#define local_timer_ack() twd_timer_ack()
+#define local_timer_stop(c) twd_timer_stop((c))
#else
/*
- * Platform provides this to acknowledge a local timer IRQ.
- * Returns true if the local timer IRQ is to be processed.
+ * Stop the local timer
*/
-int local_timer_ack(void);
+void local_timer_stop(struct clock_event_device *);
#endif
@@ -54,6 +47,10 @@ static inline int local_timer_setup(struct clock_event_device *evt)
{
return -ENXIO;
}
+
+static inline void local_timer_stop(struct clock_event_device *evt)
+{
+}
#endif
#endif
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index fed9981..ef9ffba 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -22,7 +22,7 @@ struct clock_event_device;
extern void __iomem *twd_base;
-int twd_timer_ack(void);
void twd_timer_setup(struct clock_event_device *);
+void twd_timer_stop(struct clock_event_device *);
#endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index e3dbd99..c206aed 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -520,20 +520,6 @@ static void ipi_timer(void)
irq_exit();
}
-#ifdef CONFIG_LOCAL_TIMERS
-irqreturn_t percpu_timer_handler(int irq, void *dev_id)
-{
- struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
-
- if (local_timer_ack()) {
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-#endif
-
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
static void smp_timer_broadcast(const struct cpumask *mask)
{
@@ -584,7 +570,7 @@ static void percpu_timer_stop(void)
unsigned int cpu = smp_processor_id();
struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
- evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ local_timer_stop(evt);
}
#endif
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 01c1862..566c0fe 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
#include <asm/hardware/gic.h>
/* set up by the platform code */
@@ -26,6 +27,8 @@ void __iomem *twd_base;
static unsigned long twd_timer_rate;
+static struct clock_event_device __percpu **twd_evt;
+
static void twd_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
@@ -80,6 +83,12 @@ int twd_timer_ack(void)
return 0;
}
+void twd_timer_stop(struct clock_event_device *clk)
+{
+ twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+ disable_percpu_irq(clk->irq);
+}
+
static void __cpuinit twd_calibrate_rate(void)
{
unsigned long count;
@@ -119,11 +128,43 @@ static void __cpuinit twd_calibrate_rate(void)
}
}
+static irqreturn_t twd_handler(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+
+ if (twd_timer_ack()) {
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
/*
* Setup the local clock events for a CPU.
*/
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
{
+ struct clock_event_device **this_cpu_clk;
+
+ if (!twd_evt) {
+ int err;
+
+ twd_evt = alloc_percpu(struct clock_event_device *);
+ if (!twd_evt) {
+ pr_err("twd: can't allocate memory\n");
+ return;
+ }
+
+ err = request_percpu_irq(clk->irq, twd_handler,
+ "twd", twd_evt);
+ if (err) {
+ pr_err("twd: can't register interrupt %d (%d)\n",
+ clk->irq, err);
+ return;
+ }
+ }
+
twd_calibrate_rate();
clk->name = "local_timer";
@@ -137,8 +178,10 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
+ this_cpu_clk = __this_cpu_ptr(twd_evt);
+ *this_cpu_clk = clk;
+
clockevents_register_device(clk);
- /* Make sure our local interrupt controller has this enabled */
- gic_enable_ppi(clk->irq);
+ enable_percpu_irq(clk->irq);
}
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c
index f3638fa..3a1e4f3 100644
--- a/arch/arm/mach-exynos4/mct.c
+++ b/arch/arm/mach-exynos4/mct.c
@@ -396,11 +396,6 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
return 0;
}
-int local_timer_ack(void)
-{
- return 0;
-}
-
#endif /* CONFIG_LOCAL_TIMERS */
static void __init exynos4_timer_resources(void)
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 63621f1..701d5e6 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -71,12 +71,16 @@ enum timer_location {
struct msm_clock {
struct clock_event_device clockevent;
struct clocksource clocksource;
- struct irqaction irq;
+ unsigned int irq;
void __iomem *regbase;
uint32_t freq;
uint32_t shift;
void __iomem *global_counter;
void __iomem *local_counter;
+ union {
+ struct clock_event_device *evt;
+ struct clock_event_device __percpu **percpu_evt;
+ };
};
enum {
@@ -87,13 +91,10 @@ enum {
static struct msm_clock msm_clocks[];
-static struct clock_event_device *local_clock_event;
static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
{
- struct clock_event_device *evt = dev_id;
- if (smp_processor_id() != 0)
- evt = local_clock_event;
+ struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
if (evt->event_handler == NULL)
return IRQ_HANDLED;
evt->event_handler(evt);
@@ -171,13 +172,7 @@ static struct msm_clock msm_clocks[] = {
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
- .irq = {
- .name = "gp_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
- .handler = msm_timer_interrupt,
- .dev_id = &msm_clocks[0].clockevent,
- .irq = INT_GP_TIMER_EXP
- },
+ .irq = INT_GP_TIMER_EXP,
.freq = GPT_HZ,
},
[MSM_CLOCK_DGT] = {
@@ -196,13 +191,7 @@ static struct msm_clock msm_clocks[] = {
.mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
- .irq = {
- .name = "dg_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
- .handler = msm_timer_interrupt,
- .dev_id = &msm_clocks[1].clockevent,
- .irq = INT_DEBUG_TIMER_EXP
- },
+ .irq = INT_DEBUG_TIMER_EXP,
.freq = DGT_HZ >> MSM_DGT_SHIFT,
.shift = MSM_DGT_SHIFT,
}
@@ -261,10 +250,30 @@ static void __init msm_timer_init(void)
printk(KERN_ERR "msm_timer_init: clocksource_register "
"failed for %s\n", cs->name);
- res = setup_irq(clock->irq.irq, &clock->irq);
+ ce->irq = clock->irq;
+ if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+ clock->percpu_evt = alloc_percpu(struct clock_event_device *);
+ if (!clock->percpu_evt) {
+ pr_err("msm_timer_init: memory allocation "
+ "failed for %s\n", ce->name);
+ continue;
+ }
+
+ *__this_cpu_ptr(clock->percpu_evt) = ce;
+ res = request_percpu_irq(ce->irq, msm_timer_interrupt,
+ ce->name, clock->percpu_evt);
+ if (!res)
+ enable_percpu_irq(ce->irq);
+ } else {
+ clock->evt = ce;
+ res = request_irq(ce->irq, msm_timer_interrupt,
+ IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+ ce->name, &clock->evt);
+ }
+
if (res)
- printk(KERN_ERR "msm_timer_init: setup_irq "
- "failed for %s\n", cs->name);
+ pr_err("msm_timer_init: request_irq failed for %s\n",
+ ce->name);
clockevents_register_device(ce);
}
@@ -273,6 +282,7 @@ static void __init msm_timer_init(void)
#ifdef CONFIG_SMP
int __cpuinit local_timer_setup(struct clock_event_device *evt)
{
+ static bool local_timer_inited;
struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
/* Use existing clock_event for cpu 0 */
@@ -281,12 +291,13 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
- if (!local_clock_event) {
+ if (!local_timer_inited) {
writel(0, clock->regbase + TIMER_ENABLE);
writel(0, clock->regbase + TIMER_CLEAR);
writel(~0, clock->regbase + TIMER_MATCH_VAL);
+ local_timer_inited = true;
}
- evt->irq = clock->irq.irq;
+ evt->irq = clock->irq;
evt->name = "local_timer";
evt->features = CLOCK_EVT_FEAT_ONESHOT;
evt->rating = clock->clockevent.rating;
@@ -298,17 +309,17 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
evt->min_delta_ns = clockevent_delta2ns(4, evt);
- local_clock_event = evt;
-
- gic_enable_ppi(clock->irq.irq);
+ *__this_cpu_ptr(clock->percpu_evt) = evt;
+ enable_percpu_irq(evt->irq);
clockevents_register_device(evt);
return 0;
}
-inline int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
{
- return 1;
+ evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+ disable_percpu_irq(evt->irq);
}
#endif
--
1.7.0.4
^ permalink raw reply related
* [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver
From: Tony Lindgren @ 2011-09-15 16:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <B85A65D85D7EB246BE421B3FB0FBB59302575A050D@dbde02.ent.ti.com>
* Mohammed, Afzal <afzal@ti.com> [110915 01:13]:
> Hi Tony,
>
> On Thu, Sep 15, 2011 at 11:12:53, DebBarma, Tarun Kanti wrote:
> > On Thu, Sep 15, 2011 at 3:15 AM, Tony Lindgren <tony@atomide.com> wrote:
> > > * Tarun Kanti DebBarma <tarun.kanti@ti.com> [110908 13:36]:
> > >> removed from timer code. New set of timers present on
> > >> OMAP4 are now supported.
> > > Also, as we don't need the support for different register offsets for
> > > the first two omap4 timers, please rather implement support for the
> > > new timers and the timeouts directly in plat-omap/dmtimer.c.
> > >
> > > That way we can still keep the minimal timer support simple for
> > > clocksource and clockevent. Of course this means that we'll be only
> > > supporting the first two timers as system timers on omap4, but that's
> > > fine.
> > Ok, I can make the change!
> > But, do we have to keep OMAP5 in mind right now where even timers[1,2] require addition of offsets?
>
> We need clocksource & clockevent to be able to work with
> timers requiring addition of offsets. Without this AM335X,
> TI816X and TI814X SoC's will not boot.
OK. Then how about let's do the following things:
1. Modify the inline access functions to take the PEND and others
if needed registers as a parameter
2. Modify mach-omap2/timer.c to initialize the PEND and others
in the SoC specific timer_init function
3. Move all the non-minimal stuff into dmtimer.c as that will
eventually be a device driver at some point
This way we can still share some of the inline access functions
and keep the system timer code minimal. Then the device driver
like features will be limited to dmtimer.c as that usage is more
complex with than with system timer.
Regards,
Tony
^ permalink raw reply
* [PATCH v15 06/12] OMAP: dmtimer: switch-over to platform device driver
From: Tony Lindgren @ 2011-09-15 17:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110915165810.GA2284@atomide.com>
* Tony Lindgren <tony@atomide.com> [110915 09:24]:
> * Mohammed, Afzal <afzal@ti.com> [110915 01:13]:
> >
> > We need clocksource & clockevent to be able to work with
> > timers requiring addition of offsets. Without this AM335X,
> > TI816X and TI814X SoC's will not boot.
>
> OK. Then how about let's do the following things:
>
> 1. Modify the inline access functions to take the PEND and others
> if needed registers as a parameter
>
> 2. Modify mach-omap2/timer.c to initialize the PEND and others
> in the SoC specific timer_init function
Also, let's do these changes first then rebase the dmtimer
series on those changes as it simplifies the dmtimer series
a bit.
Regards,
Tony
^ permalink raw reply
* [PATCH 1/4] AM3517 : support for suspend/resume
From: Kevin Hilman @ 2011-09-15 17:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <FCCFB4CDC6E5564B9182F639FC356087037AF843DD@dbde02.ent.ti.com>
"Koyamangalath, Abhilash" <abhilash.kv@ti.com> writes:
> hi Kevin
>
> On Tue, Sep 13, 2011 at 11:54 PM, Hilman, Kevin wrote:
>> Hi Abhilash,
>>
>> "Koyamangalath, Abhilash" <abhilash.kv@ti.com> writes:
>>
>>> Hi
>>>
>>> On Wed, Aug 31, 2011 at 4:28 AM, Hilman, Kevin wrote:
>>>>
>>>> Abhilash K V <abhilash.kv@ti.com> writes:
>>>>
> <snip>
>>>>
>>>> In addition to Russell's comments about using the latest code from
>>>> mainline, I have some comments below.
>>> [Abhilash K V] I have reworked the patch against the tip (as suggested by
>>> Russell).
>>> And I've incorporated all of Kevin's comments too.
>>
>> Great, thanks!
>>
>>> There is one "known" issue left which needs to be closed before I can submit v2 of this patch.
>>> With no_console_suspend, suspend to RAM hangs right now on AM3517, after
>>> the message:
>>> Disabling non-boot CPUs ...
>>> There is no error message or dump.
>>> I found that this crash is happening in a call to pr_warning(), from _omap_device_deactivate().
>>> The same code does not produce this issue on omap34xx due to this snippet from omap_sram_idle() :
>>> /* PER */
>>> if (per_next_state < PWRDM_POWER_ON) {
>>> per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
>>> omap_uart_prepare_idle(2);
>>> omap_uart_prepare_idle(3);
>>> omap2_gpio_prepare_for_idle(per_going_off);
>>> if (per_next_state == PWRDM_POWER_OFF)
>>> omap3_per_save_context();
>>> }
>>> /* CORE */
>>> if (core_next_state < PWRDM_POWER_ON) {
>>> omap_uart_prepare_idle(0);
>>> omap_uart_prepare_idle(1);
>>> if (core_next_state == PWRDM_POWER_OFF) {
>>> omap3_core_save_context();
>>> omap3_cm_save_context();
>>> }
>>> }
>>> This happens in preparation to the suspend operation (I,e. the WFI).
>>> As seen here, on 34xx the sequence in which the uarts are disabled is 2, 3, 0 and 1.The console-uart, which is uart-1 here (starting from uart-0) is disabled last.
>>
>>> For AM3517 EVM, the console-uart is uart-2 and this ought to be
>>> disabled at the last to prevent this crash from occurring.
>>
>> There are several other OMAP3 platforms (n900, Beagle, etc.) where the
>> UART console is also UART2, so console ordering is not the problem.
>
> [Abhilash K V] OK. Yet changing the order so that uart-2 is disabled
> at the last seems to rid me of the crash on AM35x. I understand that
> holding the console_sem before suspend (your fix below) is the way to
> go, but I'm just curious over what's happening here.
You're unlucky. :)
Each time an omap_device is disabled, we print a message if it's a new
worst case value.
What's happening to you is that one of the UARTs disabled after the
console is getting a new worst case value. Because of the missing
console locking, it's trying to write to the console, and boom.
> Simply put what is the rationale behind choosing this order of
> UART-disables ?
The order is not important at all.
Changing the order might fix this problem for your current situation,
but the same problem could pop up elsewhere.
In fact, even if you disable the console UART last, we can still try to
print the "new worst case" messages after the console is disabled.
That's why the console locking is important.
>>
>> The fact that that pr_warning is making it to the console suggests that
>> the console is not locked. In the idle path, we take the console lock
>> (using console_trylock(), just above the code you showed above.)
>>
>> But during suspend, there was an assumption (by me[2]) that the console
>> would always be locked in the suspend path. During no_console_suspend,
>> it appears that is not the case.
>>
>> Can you try the patch below[1] to see if that fixes your problem? I
>> think it should.
> [Abhilash K V] Yes it does, thanks.
Great, thanks for testing. I'll add a Tested-by for you, and post it
to the list.
Kevin
^ permalink raw reply
* [PATCH 02/25] OMAP4: Redefine mandatory barriers for OMAP to include interconnect barriers.
From: Kevin Hilman @ 2011-09-15 17:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4E7080F8.9020302@ti.com>
Santosh <santosh.shilimkar@ti.com> writes:
> On Wednesday 14 September 2011 01:57 AM, Tony Lindgren wrote:
>> * Santosh Shilimkar<santosh.shilimkar@ti.com> [110904 06:22]:
>>> On OMAP4 SOC intecronnects has many write buffers in the async bridges
>>> and they can be drained only with stongly ordered accesses.
>>
>> This is not correct, strongly ordered access does not guarantee
>> anything here. If it fixes issues, it's because it makes the writes
>> to reach the device faster. Strongly ordered does not affect anything
>> outside ARM, so the bus access won't change.
>>
> What I said is the aync bridges WB and what is said is correct
> from MPU accesses point of view.
>
> It's not about faster or slower. With device memory the, writes
> can get stuck into write buffers where as with SO, the write buffers
> will be bypassed.
>
> The behaviours is limited to the MPU side async bridge boundary which
> is the problem. The statement is not for l3 and l4 interconnect which
> probably you mean.
>
> There is always a hardware signal to communicate CPU at async bridges
> to ensure that data is not stuck in these bridges before CPU
> clock/voltage is cut. Unfortunately we have a BUG on OMAP44XX devices
> and the dual channel makes it even worst since both pipes have the
> same BUG. So what we are doing is issuing SO write/read accesses
> on these pipes so that there is nothing stuck there before MPU
> hits low power states and also avoids any race conditions when
> both channels are used together by some initiators. The behaviour
> is validated at RTL level and there is no ambiguity about it.
>
> May be you have mistaken the L3 and L4 as the interconnect levels
> in this case.
Sounds to me like the changelog needs to be a bit more verbose.
Remember, we're all probably going to forget the gory details of this in
a few months and want to be able to go back to the code w/changelog to
refresh our memories.
Thanks,
Kevin
^ permalink raw reply
* [PATCH 02/25] OMAP4: Redefine mandatory barriers for OMAP to include interconnect barriers.
From: Shilimkar, Santosh @ 2011-09-15 17:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87obyl7mj8.fsf@ti.com>
On Thu, Sep 15, 2011 at 10:47 PM, Kevin Hilman <khilman@ti.com> wrote:
> Santosh <santosh.shilimkar@ti.com> writes:
>
>> On Wednesday 14 September 2011 01:57 AM, Tony Lindgren wrote:
>>> * Santosh Shilimkar<santosh.shilimkar@ti.com> ?[110904 06:22]:
>>>> On OMAP4 SOC intecronnects has many write buffers in the async bridges
>>>> and they can be drained only with stongly ordered accesses.
>>>
>>> This is not correct, strongly ordered access does not guarantee
>>> anything here. If it fixes issues, it's because it makes the writes
>>> to reach the device faster. Strongly ordered does not affect anything
>>> outside ARM, so the bus access won't change.
>>>
>> What I said is the aync bridges WB and what is said is correct
>> from MPU accesses point of view.
>>
>> It's not about faster or slower. With device memory the, writes
>> can get stuck into write buffers where as with SO, the write buffers
>> will be bypassed.
>>
>> The behaviours is limited to the MPU side async bridge boundary which
>> is the problem. The statement is not for l3 and l4 interconnect which
>> probably you mean.
>>
>> There is always a hardware signal to communicate CPU at async bridges
>> to ensure that data is not stuck in these bridges before CPU
>> clock/voltage is cut. Unfortunately we have a BUG on OMAP44XX devices
>> and the dual channel makes it even worst since both pipes have the
>> same BUG. So what we are doing is issuing SO write/read accesses
>> on these pipes so that there is nothing stuck there before MPU
>> hits low power states and also avoids any race conditions when
>> both channels are used together by some initiators. The behaviour
>> is validated at RTL level and there is no ambiguity about it.
>>
>> May be you have mistaken the L3 and L4 as the interconnect levels
>> in this case.
>
> Sounds to me like the changelog needs to be a bit more verbose.
>
> Remember, we're all probably going to forget the gory details of this in
> a few months and want to be able to go back to the code w/changelog to
> refresh our memories.
>
Change log was accurate but I agree it needs more description to make it
clear. I plan to update it.
^ permalink raw reply
* [PATCH 1/3] ARM: debug: use kconfig choice for selecting DEBUG_LL UART
From: Stephen Boyd @ 2011-09-15 17:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1313530873-24961-1-git-send-email-will.deacon@arm.com>
On 08/16/11 14:41, Will Deacon wrote:
> +choice
> + prompt "Kernel low-level debugging port"
> + depends on DEBUG_LL
> +
> + config DEBUG_DC21285_PORT
> + bool "Kernel low-level debugging messages via footbridge serial port"
> + depends on FOOTBRIDGE
> + help
> + Say Y here if you want the debug print routines to direct
> + their output to the serial port in the DC21285 (Footbridge).
> + Saying N will cause the debug messages to appear on the first
> + 16550 serial port.
> +
> + config DEBUG_CLPS711X_UART2
> + bool "Kernel low-level debugging messages via UART2"
> + depends on ARCH_CLPS711X
> + help
> + Say Y here if you want the debug print routines to direct
> + their output to the second serial port on these devices.
> + Saying N will cause the debug messages to appear on the first
> + serial port.
How would I unselect this UART2 config to get serial output on UART1? As
far as I can tell there isn't an option for NONE in a choice menu.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* [PATCH 02/25] OMAP4: Redefine mandatory barriers for OMAP to include interconnect barriers.
From: Tony Lindgren @ 2011-09-15 17:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMQu2gy6yVA7zWAPUsnzCtixHkjzkn6UnbapR0mpoJ+AwNMAcQ@mail.gmail.com>
* Shilimkar, Santosh <santosh.shilimkar@ti.com> [110915 09:51]:
> On Thu, Sep 15, 2011 at 10:47 PM, Kevin Hilman <khilman@ti.com> wrote:
> > Santosh <santosh.shilimkar@ti.com> writes:
> >
> >> On Wednesday 14 September 2011 01:57 AM, Tony Lindgren wrote:
> >>> * Santosh Shilimkar<santosh.shilimkar@ti.com> ?[110904 06:22]:
> >>>> On OMAP4 SOC intecronnects has many write buffers in the async bridges
> >>>> and they can be drained only with stongly ordered accesses.
> >>>
> >>> This is not correct, strongly ordered access does not guarantee
> >>> anything here. If it fixes issues, it's because it makes the writes
> >>> to reach the device faster. Strongly ordered does not affect anything
> >>> outside ARM, so the bus access won't change.
> >>>
> >> What I said is the aync bridges WB and what is said is correct
> >> from MPU accesses point of view.
> >>
> >> It's not about faster or slower. With device memory the, writes
> >> can get stuck into write buffers where as with SO, the write buffers
> >> will be bypassed.
> >>
> >> The behaviours is limited to the MPU side async bridge boundary which
> >> is the problem. The statement is not for l3 and l4 interconnect which
> >> probably you mean.
> >>
> >> There is always a hardware signal to communicate CPU at async bridges
> >> to ensure that data is not stuck in these bridges before CPU
> >> clock/voltage is cut. Unfortunately we have a BUG on OMAP44XX devices
> >> and the dual channel makes it even worst since both pipes have the
> >> same BUG. So what we are doing is issuing SO write/read accesses
> >> on these pipes so that there is nothing stuck there before MPU
> >> hits low power states and also avoids any race conditions when
> >> both channels are used together by some initiators. The behaviour
> >> is validated at RTL level and there is no ambiguity about it.
> >>
> >> May be you have mistaken the L3 and L4 as the interconnect levels
> >> in this case.
> >
> > Sounds to me like the changelog needs to be a bit more verbose.
> >
> > Remember, we're all probably going to forget the gory details of this in
> > a few months and want to be able to go back to the code w/changelog to
> > refresh our memories.
> >
> Change log was accurate but I agree it needs more description to make it
> clear. I plan to update it.
Please also include the errata in the description and set it up with
a Kconfig entry with something like ARM_ERRATA_XXXXXX or TI_ERRATA_XXXXXX.
Also it would be best to apply this fix at the end of the PM series so
it is easier to verify the bug and potentially remove the hack if
a better fix is ever available.
Regards,
Tony
^ permalink raw reply
* READ THIS: the next mach-types update
From: Olof Johansson @ 2011-09-15 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110915102528.GI6267@n2100.arm.linux.org.uk>
On Thu, Sep 15, 2011 at 3:25 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> The following will be deleted from the machine database:
>
> ?tegra ? ? ? ? ? ? ? ? ? MACH_TEGRA ? ? ? ? ? ? ?TEGRA ? ? ? ? ? ? ? ? ? 3738
>
> as it doesn't conform to the policy of this being a _platform_ database
> not a _soc_ database.
Yes, please. It looks like it has been renamed 'peaboy' now but it
still seems bogus. Maybe 3739 is meant to supersede it.
-Olof
^ permalink raw reply
* [PATCH] spi/imx: Fix spi-imx when the hardware SPI chipselects are used
From: Uwe Kleine-König @ 2011-09-15 18:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316103406-16401-1-git-send-email-fabio.estevam@freescale.com>
On Thu, Sep 15, 2011 at 01:16:46PM -0300, Fabio Estevam wrote:
> commit 22a85e4cd51 (spi/imx: add device tree probe support) broke spi-imx usage
> when the SPI chipselect is the one internal to the controller.
>
> On a mx31pdk board the following error is seen:
>
> Registering mxc_nand as whole device
> ------------[ cut here ]------------
> WARNING: at drivers/gpio/gpiolib.c:101 gpio_ensure_requested+0x4c/0xf4()
> autorequest GPIO-0
> Modules linked in:
> [<c0014410>] (unwind_backtrace+0x0/0xf4) from [<c0025754>] (warn_slowpath_common+0x4c/0x64)
> [<c0025754>] (warn_slowpath_common+0x4c/0x64) from [<c0025800>] (warn_slowpath_fmt+0x30/0x40)
> [<c0025800>] (warn_slowpath_fmt+0x30/0x40) from [<c0198688>] (gpio_ensure_requested+0x4c/0xf4)
> [<c0198688>] (gpio_ensure_requested+0x4c/0xf4) from [<c01988c8>] (gpio_direction_output+0xa0/0x138)
> [<c01988c8>] (gpio_direction_output+0xa0/0x138) from [<c01ed198>] (spi_imx_setup+0x38/0x4c)
> [<c01ed198>] (spi_imx_setup+0x38/0x4c) from [<c01eb5d0>] (spi_setup+0x38/0x50)
> [<c01eb5d0>] (spi_setup+0x38/0x50) from [<c01eb85c>] (spi_add_device+0x94/0x124)
> [<c01eb85c>] (spi_add_device+0x94/0x124) from [<c01eb960>] (spi_new_device+0x74/0xac)
> [<c01eb960>] (spi_new_device+0x74/0xac) from [<c01eb9b8>] (spi_match_master_to_boardinfo+0x20/0x40)
> [<c01eb9b8>] (spi_match_master_to_boardinfo+0x20/0x40) from [<c01eba88>] (spi_register_master+0xb0/0x104)
> [<c01eba88>] (spi_register_master+0xb0/0x104) from [<c01ec0b4>] (spi_bitbang_start+0x104/0x17c)
> [<c01ec0b4>] (spi_bitbang_start+0x104/0x17c) from [<c02c2c4c>] (spi_imx_probe+0x2fc/0x404)
> [<c02c2c4c>] (spi_imx_probe+0x2fc/0x404) from [<c01c2498>] (platform_drv_probe+0x18/0x1c)
> [<c01c2498>] (platform_drv_probe+0x18/0x1c) from [<c01c1058>] (driver_probe_device+0x78/0x174)
> [<c01c1058>] (driver_probe_device+0x78/0x174) from [<c01c11e0>] (__driver_attach+0x8c/0x90)
> [<c01c11e0>] (__driver_attach+0x8c/0x90) from [<c01c0860>] (bus_for_each_dev+0x60/0x8c)
> [<c01c0860>] (bus_for_each_dev+0x60/0x8c) from [<c01c0088>] (bus_add_driver+0xa0/0x288)
> [<c01c0088>] (bus_add_driver+0xa0/0x288) from [<c01c179c>] (driver_register+0x78/0x18c)
> [<c01c179c>] (driver_register+0x78/0x18c) from [<c0008490>] (do_one_initcall+0x34/0x178)
> [<c0008490>] (do_one_initcall+0x34/0x178) from [<c03a5204>] (kernel_init+0x74/0x118)
> [<c03a5204>] (kernel_init+0x74/0x118) from [<c000f65c>] (kernel_thread_exit+0x0/0x8)
> ---[ end trace 759f924b30fd5a44 ]---
>
> Fix this issue by using the original chip select logic and make spi-imx to work again.
>
> Tested on a mx31pdk that uses the hardware SPI chipselect pins and also
> on a mx27pdk that uses GPIO as SPI chipselect.
>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> ---
> drivers/spi/spi-imx.c | 8 +++-----
> 1 files changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
> index 8ac6542..7821c48 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -783,12 +783,10 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
> spi_imx->bitbang.master = spi_master_get(master);
>
> for (i = 0; i < master->num_chipselect; i++) {
> - int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
> - if (cs_gpio < 0)
> - cs_gpio = mxc_platform_info->chipselect[i];
> - if (cs_gpio < 0)
> + spi_imx->chipselect[i] = mxc_platform_info->chipselect[i];
> + if (spi_imx->chipselect[i] < 0)
> continue;
> - spi_imx->chipselect[i] = cs_gpio;
> +
> ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
> if (ret) {
> while (i > 0) {
I think this is wrong. My first guess is you need to move
spi_imx->chipselect[i] = cs_gpio;
before
if (cs_gpio < 0)
continue;
Does that make sense and works?
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* [RFC PATCH 03/11] DT: regulator: Helper routine to extract regulator_init_data
From: Rob Herring @ 2011-09-15 18:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110915134427.GJ7988@opensource.wolfsonmicro.com>
On 09/15/2011 08:44 AM, Mark Brown wrote:
> On Thu, Sep 15, 2011 at 04:51:59PM +0530, Rajendra Nayak wrote:
>
>> .../devicetree/bindings/regulator/regulator.txt | 37 +++++++++
>> drivers/of/Kconfig | 6 ++
>> drivers/of/Makefile | 1 +
>> drivers/of/of_regulator.c | 85 ++++++++++++++++++++
>> include/linux/of_regulator.h | 23 +++++
>
> Don't go hiding the bindings for things away from the code they're
> binding. Bindings for the regualtor API are a regulator API thing and
> should be part of the regulator API code.
>
Agreed, but FYI not all subsystem maintainers agree. Moving of_i2c.c
into i2c was rejected.
Rob
>> +Required properties:
>> +- compatible: Must be "regulator";
>
> Is this idiomatic or should we just have a helper that parses a big list
> of properties from the device node?
>
>> +- mode-fast: boolean, Can handle fast changes in its load
>> +- mode-normal: boolean, Normal regulator power supply mode
>> +- mode-idle: boolean, Can be more efficient during light loads
>> +- mode-standby: boolean, Can be most efficient during light loads
>
> I guess these are actually permissions to set the given modes? The
> documentation should be clearer.
>
>> +- apply-uV: apply uV constraint if min == max
>
> This seems a bit Linux/runtime policy specific (especially the last
> bit).
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox