LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Grant Likely @ 2011-05-02 22:27 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <1300782452-528-4-git-send-email-hs@denx.de>

On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
> - add commandline options:
>   sm501fb.mode:
>     Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>   sm501fb.bpp:
>     Specify bit-per-pixel if not specified mode
> 
> - Add support for encoding display mode information
>   in the device tree using verbatim EDID block.
> 
>   If the "edid" entry in the "smi,sm501" node is present,
>   the driver will build mode database using EDID data
>   and allow setting the display modes from this database.
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>

Merged, thanks.

g.

> cc: Wolfram Sang <w.sang@pengutronix.de>
> cc: Grant Likely <grant.likely@secretlab.ca>
> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> cc: Randy Dunlap <rdunlap@xenotime.net>
> cc: Wolfgang Denk <wd@denx.de>
> cc: Paul Mundt <lethal@linux-sh.org>
> ---
> - changes since v1:
>   add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested from
>   Paul Mundt.
> - changes since v2:
>   add comments from Randy Dunlap:
>   - move parameter documentation to Documentation/fb/sm501.txt
> - changes since v3:
>   - rebased against v2.6.38-rc2
>   - split in 3 patches
>     - of support patch
>     - i/o routine patch
>     - edid support patch
> - changes since v4:
>   - add "info->pdata = &sm501fb_def_pdata;" in sm501fb_probe()
>     as Paul Mundt suggested (and I wrongly deleted)
>   - move kfree(info->edid_data); to patch 3/4
>     as edid_data is only allocated in the CONFIG_OF case
> - changes for v6:
>   - repost complete patchserie
>   - rebased against current head
> 
>  Documentation/fb/sm501.txt |   10 +++++++
>  drivers/video/sm501fb.c    |   65 ++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 70 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/fb/sm501.txt
> 
> diff --git a/Documentation/fb/sm501.txt b/Documentation/fb/sm501.txt
> new file mode 100644
> index 0000000..8d17aeb
> --- /dev/null
> +++ b/Documentation/fb/sm501.txt
> @@ -0,0 +1,10 @@
> +Configuration:
> +
> +You can pass the following kernel command line options to sm501 videoframebuffer:
> +
> +	sm501fb.bpp=	SM501 Display driver:
> +			Specifiy bits-per-pixel if not specified by 'mode'
> +
> +	sm501fb.mode=	SM501 Display driver:
> +			Specify resolution as
> +			"<xres>x<yres>[-<bpp>][@<refresh>]"
> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
> index 5df406c..f31252c 100644
> --- a/drivers/video/sm501fb.c
> +++ b/drivers/video/sm501fb.c
> @@ -41,6 +41,26 @@
>  #include <linux/sm501.h>
>  #include <linux/sm501-regs.h>
>  
> +#include "edid.h"
> +
> +static char *fb_mode = "640x480-16@60";
> +static unsigned long default_bpp = 16;
> +
> +static struct fb_videomode __devinitdata sm501_default_mode = {
> +	.refresh	= 60,
> +	.xres		= 640,
> +	.yres		= 480,
> +	.pixclock	= 20833,
> +	.left_margin	= 142,
> +	.right_margin	= 13,
> +	.upper_margin	= 21,
> +	.lower_margin	= 1,
> +	.hsync_len	= 69,
> +	.vsync_len	= 3,
> +	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +	.vmode		= FB_VMODE_NONINTERLACED
> +};
> +
>  #define NR_PALETTE	256
>  
>  enum sm501_controller {
> @@ -77,6 +97,7 @@ struct sm501fb_info {
>  	void __iomem		*regs2d;	/* 2d remapped registers */
>  	void __iomem		*fbmem;		/* remapped framebuffer */
>  	size_t			 fbmem_len;	/* length of remapped region */
> +	u8 *edid_data;
>  };
>  
>  /* per-framebuffer private data */
> @@ -1725,9 +1746,16 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  	fb->var.vmode		= FB_VMODE_NONINTERLACED;
>  	fb->var.bits_per_pixel  = 16;
>  
> +	if (info->edid_data) {
> +			/* Now build modedb from EDID */
> +			fb_edid_to_monspecs(info->edid_data, &fb->monspecs);
> +			fb_videomode_to_modelist(fb->monspecs.modedb,
> +						 fb->monspecs.modedb_len,
> +						 &fb->modelist);
> +	}
> +
>  	if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
>  		/* TODO read the mode from the current display */
> -
>  	} else {
>  		if (pd->def_mode) {
>  			dev_info(info->dev, "using supplied mode\n");
> @@ -1737,12 +1765,34 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  			fb->var.xres_virtual = fb->var.xres;
>  			fb->var.yres_virtual = fb->var.yres;
>  		} else {
> -			ret = fb_find_mode(&fb->var, fb,
> +			if (info->edid_data)
> +				ret = fb_find_mode(&fb->var, fb, fb_mode,
> +					fb->monspecs.modedb,
> +					fb->monspecs.modedb_len,
> +					&sm501_default_mode, default_bpp);
> +			else
> +				ret = fb_find_mode(&fb->var, fb,
>  					   NULL, NULL, 0, NULL, 8);
>  
> -			if (ret == 0 || ret == 4) {
> -				dev_err(info->dev,
> -					"failed to get initial mode\n");
> +			switch (ret) {
> +			case 1:
> +				dev_info(info->dev, "using mode specified in "
> +						"@mode\n");
> +				break;
> +			case 2:
> +				dev_info(info->dev, "using mode specified in "
> +					"@mode with ignored refresh rate\n");
> +				break;
> +			case 3:
> +				dev_info(info->dev, "using mode default "
> +					"mode\n");
> +				break;
> +			case 4:
> +				dev_info(info->dev, "using mode from list\n");
> +				break;
> +			default:
> +				dev_info(info->dev, "ret = %d\n", ret);
> +				dev_info(info->dev, "failed to find mode\n");
>  				return -EINVAL;
>  			}
>  		}
> @@ -2157,6 +2207,11 @@ static void __exit sm501fb_cleanup(void)
>  module_init(sm501fb_init);
>  module_exit(sm501fb_cleanup);
>  
> +module_param_named(mode, fb_mode, charp, 0);
> +MODULE_PARM_DESC(mode,
> +	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
> +module_param_named(bpp, default_bpp, ulong, 0);
> +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
>  MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
>  MODULE_DESCRIPTION("SM501 Framebuffer driver");
>  MODULE_LICENSE("GPL v2");
> -- 
> 1.7.4
> 

^ permalink raw reply

* Re: [PATCH v6 4/6] video, sm501: add OF binding to support SM501
From: Grant Likely @ 2011-05-02 22:28 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <1300782452-528-5-git-send-email-hs@denx.de>

On Tue, Mar 22, 2011 at 09:27:30AM +0100, Heiko Schocher wrote:
> - add binding to OF, compatible name "smi,sm501"
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>
> Acked-by: Samuel Ortiz <sameo@linux.intel.com>

Merged, thanks.

g.

> cc: Wolfram Sang <w.sang@pengutronix.de>
> cc: Grant Likely <grant.likely@secretlab.ca>
> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> cc: Randy Dunlap <rdunlap@xenotime.net>
> cc: Wolfgang Denk <wd@denx.de>
> cc: Paul Mundt <lethal@linux-sh.org>
> ---
> - changes since v1:
>   add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested from
>   Paul Mundt.
> - changes since v2:
>   add comments from Randy Dunlap:
>   - move parameter documentation to Documentation/fb/sm501.txt
> - changes since v3:
>   - rebased against v2.6.38-rc2
>   - split in 3 patches
>     - of support patch
>       - get rid of "#if defined(CONFIG_PPC_MPC52xx)" usage
>         hide this in DTS, as Paul suggested.
>     - i/o routine patch
>     - edid support patch
> - changes since v4
>   replace remaining CONFIG_PPC_MPC52xx with CONFIG_OF, as
>   it is no longer MPC52xx only.
> - changes since v5
>   free edid_data after its usage, as it is no longer needed,
>   suggested from Paul Mundt. Also fall back to default if
>   kmemdup(edid_data) fails.
> - changes for v6:
>   - repost complete patchserie
>   - rebased against current head
> 
>  Documentation/powerpc/dts-bindings/sm501.txt |   34 +++++++++++++++++++++++++
>  drivers/mfd/sm501.c                          |    8 +++++-
>  drivers/video/sm501fb.c                      |   35 +++++++++++++++++++++++++-
>  3 files changed, 75 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/powerpc/dts-bindings/sm501.txt
> 
> diff --git a/Documentation/powerpc/dts-bindings/sm501.txt b/Documentation/powerpc/dts-bindings/sm501.txt
> new file mode 100644
> index 0000000..7d319fb
> --- /dev/null
> +++ b/Documentation/powerpc/dts-bindings/sm501.txt
> @@ -0,0 +1,34 @@
> +* SM SM501
> +
> +The SM SM501 is a LCD controller, with proper hardware, it can also
> +drive DVI monitors.
> +
> +Required properties:
> +- compatible : should be "smi,sm501".
> +- reg : contain two entries:
> +    - First entry: System Configuration register
> +    - Second entry: IO space (Display Controller register)
> +- interrupts : SMI interrupt to the cpu should be described here.
> +- interrupt-parent : the phandle for the interrupt controller that
> +  services interrupts for this device.
> +
> +Optional properties:
> +- mode : select a video mode:
> +    <xres>x<yres>[-<bpp>][@<refresh>]
> +- edid : verbatim EDID data block describing attached display.
> +  Data from the detailed timing descriptor will be used to
> +  program the display controller.
> +- little-endian: availiable on big endian systems, to
> +  set different foreign endian.
> +- big-endian: availiable on little endian systems, to
> +  set different foreign endian.
> +
> +Example for MPC5200:
> +	display@1,0 {
> +		compatible = "smi,sm501";
> +		reg = <1 0x00000000 0x00800000
> +		       1 0x03e00000 0x00200000>;
> +		interrupts = <1 1 3>;
> +		mode = "640x480-32@60";
> +		edid = [edid-data];
> +	};
> diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
> index 558d5f3..574f696 100644
> --- a/drivers/mfd/sm501.c
> +++ b/drivers/mfd/sm501.c
> @@ -1377,7 +1377,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
>  			sm501_register_gpio(sm);
>  	}
>  
> -	if (pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
> +	if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
>  		if (!sm501_gpio_isregistered(sm))
>  			dev_err(sm->dev, "no gpio available for i2c gpio.\n");
>  		else
> @@ -1735,10 +1735,16 @@ static struct pci_driver sm501_pci_driver = {
>  
>  MODULE_ALIAS("platform:sm501");
>  
> +static struct of_device_id __devinitdata of_sm501_match_tbl[] = {
> +	{ .compatible = "smi,sm501", },
> +	{ /* end */ }
> +};
> +
>  static struct platform_driver sm501_plat_driver = {
>  	.driver		= {
>  		.name	= "sm501",
>  		.owner	= THIS_MODULE,
> +		.of_match_table = of_sm501_match_tbl,
>  	},
>  	.probe		= sm501_plat_probe,
>  	.remove		= sm501_plat_remove,
> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
> index f31252c..f275385 100644
> --- a/drivers/video/sm501fb.c
> +++ b/drivers/video/sm501fb.c
> @@ -1729,6 +1729,15 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
>  		FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
>  
> +#if defined(CONFIG_OF)
> +#ifdef __BIG_ENDIAN
> +	if (of_get_property(info->dev->parent->of_node, "little-endian", NULL))
> +		fb->flags |= FBINFO_FOREIGN_ENDIAN;
> +#else
> +	if (of_get_property(info->dev->parent->of_node, "big-endian", NULL))
> +		fb->flags |= FBINFO_FOREIGN_ENDIAN;
> +#endif
> +#endif
>  	/* fixed data */
>  
>  	fb->fix.type		= FB_TYPE_PACKED_PIXELS;
> @@ -1933,8 +1942,32 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
>  	}
>  
>  	if (info->pdata == NULL) {
> -		dev_info(dev, "using default configuration data\n");
> +		int found = 0;
> +#if defined(CONFIG_OF)
> +		struct device_node *np = pdev->dev.parent->of_node;
> +		const u8 *prop;
> +		const char *cp;
> +		int len;
> +
>  		info->pdata = &sm501fb_def_pdata;
> +		if (np) {
> +			/* Get EDID */
> +			cp = of_get_property(np, "mode", &len);
> +			if (cp)
> +				strcpy(fb_mode, cp);
> +			prop = of_get_property(np, "edid", &len);
> +			if (prop && len == EDID_LENGTH) {
> +				info->edid_data = kmemdup(prop, EDID_LENGTH,
> +							  GFP_KERNEL);
> +				if (info->edid_data)
> +					found = 1;
> +			}
> +		}
> +#endif
> +		if (!found) {
> +			dev_info(dev, "using default configuration data\n");
> +			info->pdata = &sm501fb_def_pdata;
> +		}
>  	}
>  
>  	/* probe for the presence of each panel */
> -- 
> 1.7.4
> 

^ permalink raw reply

* Re: [PATCH v6 6/6] powerpc, tqm5200: update tqm5200_defconfig to fit for charon board.
From: Grant Likely @ 2011-05-02 22:31 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, Heiko Schocher,
	linuxppc-dev, Wolfgang Denk
In-Reply-To: <20110322091027.GC2134@pengutronix.de>

On Tue, Mar 22, 2011 at 10:10:27AM +0100, Wolfram Sang wrote:
> >     As this board is tqm5200 based, added necessary changes
> >     to the tqm5200_defconfig. In previous patchserie I added
> >     the changes to mpc5200_defconfig, as Wolfram Sang mentioned,
> >     but as tqm5200_defconfig is in mainline, and the board is
> >     tqm5200 based, I think, thats the appropriate place, as
> 
> I'd think the perfect solution would have been to merge the
> tqm-defconfig into the mpc5200-defconfig entirely and get rid of it.
> That being said, I don't think this issue is big enough to block this
> series, so fine enough with me.

Merged, thanks.

g.

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Grant Likely @ 2011-05-02 22:37 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <20110502222716.GB15187@ponder.secretlab.ca>

On Mon, May 2, 2011 at 4:27 PM, Grant Likely <grant.likely@secretlab.ca> wr=
ote:
> On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
>> - add commandline options:
>> =A0 sm501fb.mode:
>> =A0 =A0 Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>> =A0 sm501fb.bpp:
>> =A0 =A0 Specify bit-per-pixel if not specified mode
>>
>> - Add support for encoding display mode information
>> =A0 in the device tree using verbatim EDID block.
>>
>> =A0 If the "edid" entry in the "smi,sm501" node is present,
>> =A0 the driver will build mode database using EDID data
>> =A0 and allow setting the display modes from this database.
>>
>> Signed-off-by: Heiko Schocher <hs@denx.de>
>
> Merged, thanks.

This patch causes the following build warning:

  MODPOST vmlinux.o
WARNING: vmlinux.o(.text+0x1d5572): Section mismatch in reference from
the function sm501fb_init_fb() to the variable
.devinit.data:sm501_default_mode
The function sm501fb_init_fb() references
the variable __devinitdata sm501_default_mode.
This is often because sm501fb_init_fb lacks a __devinitdata
annotation or the annotation of sm501_default_mode is wrong.

WARNING: vmlinux.o(.text+0x1d557a): Section mismatch in reference from
the function sm501fb_init_fb() to the variable
.devinit.data:sm501_default_mode
The function sm501fb_init_fb() references
the variable __devinitdata sm501_default_mode.
This is often because sm501fb_init_fb lacks a __devinitdata
annotation or the annotation of sm501_default_mode is wrong.

I've dropped the __devinitdata declaration in what I committed; can
you investigate and post a fixup patch?

>
> g.
>
>> cc: Wolfram Sang <w.sang@pengutronix.de>
>> cc: Grant Likely <grant.likely@secretlab.ca>
>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> cc: linux-fbdev@vger.kernel.org
>> cc: devicetree-discuss@ozlabs.org
>> cc: Ben Dooks <ben@simtec.co.uk>
>> cc: Vincent Sanders <vince@simtec.co.uk>
>> cc: Samuel Ortiz <sameo@linux.intel.com>
>> cc: linux-kernel@vger.kernel.org
>> cc: Randy Dunlap <rdunlap@xenotime.net>
>> cc: Wolfgang Denk <wd@denx.de>
>> cc: Paul Mundt <lethal@linux-sh.org>
>> ---
>> - changes since v1:
>> =A0 add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested =
from
>> =A0 Paul Mundt.
>> - changes since v2:
>> =A0 add comments from Randy Dunlap:
>> =A0 - move parameter documentation to Documentation/fb/sm501.txt
>> - changes since v3:
>> =A0 - rebased against v2.6.38-rc2
>> =A0 - split in 3 patches
>> =A0 =A0 - of support patch
>> =A0 =A0 - i/o routine patch
>> =A0 =A0 - edid support patch
>> - changes since v4:
>> =A0 - add "info->pdata =3D &sm501fb_def_pdata;" in sm501fb_probe()
>> =A0 =A0 as Paul Mundt suggested (and I wrongly deleted)
>> =A0 - move kfree(info->edid_data); to patch 3/4
>> =A0 =A0 as edid_data is only allocated in the CONFIG_OF case
>> - changes for v6:
>> =A0 - repost complete patchserie
>> =A0 - rebased against current head
>>
>> =A0Documentation/fb/sm501.txt | =A0 10 +++++++
>> =A0drivers/video/sm501fb.c =A0 =A0| =A0 65 +++++++++++++++++++++++++++++=
+++++++++++---
>> =A02 files changed, 70 insertions(+), 5 deletions(-)
>> =A0create mode 100644 Documentation/fb/sm501.txt
>>
>> diff --git a/Documentation/fb/sm501.txt b/Documentation/fb/sm501.txt
>> new file mode 100644
>> index 0000000..8d17aeb
>> --- /dev/null
>> +++ b/Documentation/fb/sm501.txt
>> @@ -0,0 +1,10 @@
>> +Configuration:
>> +
>> +You can pass the following kernel command line options to sm501 videofr=
amebuffer:
>> +
>> + =A0 =A0 sm501fb.bpp=3D =A0 =A0SM501 Display driver:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Specifiy bits-per-pixel if not=
 specified by 'mode'
>> +
>> + =A0 =A0 sm501fb.mode=3D =A0 SM501 Display driver:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Specify resolution as
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "<xres>x<yres>[-<bpp>][@<refre=
sh>]"
>> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
>> index 5df406c..f31252c 100644
>> --- a/drivers/video/sm501fb.c
>> +++ b/drivers/video/sm501fb.c
>> @@ -41,6 +41,26 @@
>> =A0#include <linux/sm501.h>
>> =A0#include <linux/sm501-regs.h>
>>
>> +#include "edid.h"
>> +
>> +static char *fb_mode =3D "640x480-16@60";
>> +static unsigned long default_bpp =3D 16;
>> +
>> +static struct fb_videomode __devinitdata sm501_default_mode =3D {
>> + =A0 =A0 .refresh =A0 =A0 =A0 =A0=3D 60,
>> + =A0 =A0 .xres =A0 =A0 =A0 =A0 =A0 =3D 640,
>> + =A0 =A0 .yres =A0 =A0 =A0 =A0 =A0 =3D 480,
>> + =A0 =A0 .pixclock =A0 =A0 =A0 =3D 20833,
>> + =A0 =A0 .left_margin =A0 =A0=3D 142,
>> + =A0 =A0 .right_margin =A0 =3D 13,
>> + =A0 =A0 .upper_margin =A0 =3D 21,
>> + =A0 =A0 .lower_margin =A0 =3D 1,
>> + =A0 =A0 .hsync_len =A0 =A0 =A0=3D 69,
>> + =A0 =A0 .vsync_len =A0 =A0 =A0=3D 3,
>> + =A0 =A0 .sync =A0 =A0 =A0 =A0 =A0 =3D FB_SYNC_HOR_HIGH_ACT | FB_SYNC_V=
ERT_HIGH_ACT,
>> + =A0 =A0 .vmode =A0 =A0 =A0 =A0 =A0=3D FB_VMODE_NONINTERLACED
>> +};
>> +
>> =A0#define NR_PALETTE =A0 256
>>
>> =A0enum sm501_controller {
>> @@ -77,6 +97,7 @@ struct sm501fb_info {
>> =A0 =A0 =A0 void __iomem =A0 =A0 =A0 =A0 =A0 =A0*regs2d; =A0 =A0 =A0 =A0=
/* 2d remapped registers */
>> =A0 =A0 =A0 void __iomem =A0 =A0 =A0 =A0 =A0 =A0*fbmem; =A0 =A0 =A0 =A0 =
/* remapped framebuffer */
>> =A0 =A0 =A0 size_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fbmem_len; =A0 =
=A0 /* length of remapped region */
>> + =A0 =A0 u8 *edid_data;
>> =A0};
>>
>> =A0/* per-framebuffer private data */
>> @@ -1725,9 +1746,16 @@ static int sm501fb_init_fb(struct fb_info *fb,
>> =A0 =A0 =A0 fb->var.vmode =A0 =A0 =A0 =A0 =A0 =3D FB_VMODE_NONINTERLACED=
;
>> =A0 =A0 =A0 fb->var.bits_per_pixel =A0=3D 16;
>>
>> + =A0 =A0 if (info->edid_data) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Now build modedb from EDID =
*/
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb_edid_to_monspecs(info->edid=
_data, &fb->monspecs);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb_videomode_to_modelist(fb->m=
onspecs.modedb,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0fb->monspecs.modedb_len,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0&fb->modelist);
>> + =A0 =A0 }
>> +
>> =A0 =A0 =A0 if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0)=
 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* TODO read the mode from the current displ=
ay */
>> -
>> =A0 =A0 =A0 } else {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (pd->def_mode) {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info->dev, "using s=
upplied mode\n");
>> @@ -1737,12 +1765,34 @@ static int sm501fb_init_fb(struct fb_info *fb,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb->var.xres_virtual =3D fb-=
>var.xres;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb->var.yres_virtual =3D fb-=
>var.yres;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D fb_find_mode(&fb->var,=
 fb,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (info->edid_data)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D fb_fin=
d_mode(&fb->var, fb, fb_mode,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 fb->monspecs.modedb,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 fb->monspecs.modedb_len,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 &sm501_default_mode, default_bpp);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D fb_fin=
d_mode(&fb->var, fb,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0NULL, NULL, 0, NULL, 8);
>>
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ret =3D=3D 0 || ret =3D=3D=
 4) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(info->=
dev,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 "failed to get initial mode\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 switch (ret) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 1:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode specified in "
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 "@mode\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 2:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode specified in "
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 "@mode with ignored refresh rate\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 3:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode default "
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 "mode\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 4:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode from list\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 default:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "ret =3D %d\n", ret);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "failed to find mode\n");
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINV=
AL;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> @@ -2157,6 +2207,11 @@ static void __exit sm501fb_cleanup(void)
>> =A0module_init(sm501fb_init);
>> =A0module_exit(sm501fb_cleanup);
>>
>> +module_param_named(mode, fb_mode, charp, 0);
>> +MODULE_PARM_DESC(mode,
>> + =A0 =A0 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "=
);
>> +module_param_named(bpp, default_bpp, ulong, 0);
>> +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
>> =A0MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
>> =A0MODULE_DESCRIPTION("SM501 Framebuffer driver");
>> =A0MODULE_LICENSE("GPL v2");
>> --
>> 1.7.4
>>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 1/4] crypto: caam - handle interrupt lines shared across rings
From: Kim Phillips @ 2011-05-02 23:27 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Steve Cornelius, linuxppc-dev, linux-crypto
In-Reply-To: <20110415095049.GA2129@gondor.apana.org.au>

On Fri, 15 Apr 2011 17:50:49 +0800
Herbert Xu <herbert@gondor.apana.org.au> wrote:

> On Mon, Apr 11, 2011 at 07:15:16PM -0500, Kim Phillips wrote:
> > - add IRQF_SHARED to request_irq flags to support parts such as
> > the p1023 that has one IRQ line per couple of rings.
> > 
> > - resetting a job ring triggers an interrupt, so move request_irq
> > prior to jr_reset to avoid 'got IRQ but nobody cared' messages.
> > 
> > - disable IRQs in h/w to avoid contention between reset and
> > interrupt status
> > 
> > - delete invalid comment - if there were incomplete jobs,
> > module would be in use, preventing an unload.
> > 
> > Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
> > ---
> > this, and the remaining patches in this series, tested on p1023, p3041,
> > p4080, and 32- and 64-bit p5020.
> 
> All four patches applied.  Thanks Kim!

I don't see them in cryptodev-2.6 - did you forget to push them?

Thanks,

Kim

^ permalink raw reply

* Re: [PATCH 1/4] crypto: caam - handle interrupt lines shared across rings
From: Herbert Xu @ 2011-05-02 23:56 UTC (permalink / raw)
  To: Kim Phillips; +Cc: Steve Cornelius, linuxppc-dev, linux-crypto
In-Reply-To: <20110502182727.366857bd.kim.phillips@freescale.com>

On Mon, May 02, 2011 at 06:27:27PM -0500, Kim Phillips wrote:
>
> I don't see them in cryptodev-2.6 - did you forget to push them?

Indeed, they were stuck on my other machine.  They should be on
master now and should show up on the public mirror soon.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Benjamin Herrenschmidt @ 2011-05-03  1:43 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428192227.8979.49181.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> A lot of this series ends up being fixups to powerpc code; but the 4th
> patch is of importance to every architecture using CONFIG_OF (except
> SPARC, which has its own solution).
> 
> This series (finally!) factors out device tree irq domain decoding
> from arch/powerpc and makes it generic for all architectures.  The
> infrastructure is quite simple.  Any interrupt controller can embed
> the of_irq_domain structure and register it with the core code.  After
> that, device nodes referencing interrupts on that device tree node
> will trigger a call to the domain's map function.

This leads to an immediate reaction from me : why "of_irq_domain" ?

The concept of interrupt domains is completely orthogonal to "OF" and
whether you use the device-tree or not.

Having a remapping mechanism allowing to deal with multiple interrupt
domains without playing stupid numbering tricks is generally useful for
architectures, regardless of their adoption of the device-tree.

The irq domain has one and -only one- op that is related to OF which
allows to map a device node to a domain, but that's 'optional' and only
use if you use the OF resolving process. The whole mechanism can be (and
is under some circumstances on ppc) without a device-tree relationship.

We instanciate IRQs within domains manually in some cases, either
because we lack proper DT informations or bcs the IRQs come from the
firmware or as "created" out of the blue (device-tree). A domain pointer
(or NULL for the default domain) is all is needed.

Thus I object to tying this infrastructure generically to "OF" even if
it's just a mater of naming of the domain structure and location of the
code in the kernel tree.

It should basically all go into kernel/irq/domains.c or something like
that.

Cheers,
Ben.

> PowerPC and x86 have been converted to use of_irq_domain.  MIPS and
> Microblaze have it enabled, but nothing actually registers domains
> yet, so a workaround is in place to preserve the current behaviour
> until it is fixed.
> 
> I'd really like to get patches 1-4 merged into 2.6.40.  Please test.
> I'm also running through build testing here, and when it's complete
> I'll push it out to a 'devicetree/irq-domain' branch on
> git://git.secretlab.ca/git/linux-2.6
> 
> It needs testing.  I've booted it on a powerpc board here without any
> apparent regressions, but that isn't a very big sample.  I've also
> build tested on everything I think is affected.
> 
> I'd also like to get it into linux-next.  Ben, if things checkout okay
> over the next few days, would you be okay with me adding it to
> linux-next, say around Wednesday next week?  As for merging, I think
> this should probably go via your powerpc tree since the that's where
> the bulk of the changes are, but I'm open to other suggestions).
> 
> Patches 5 & 6 are follow-on cleanup work to powerpc, but patch 6 is
> RFC only since there is a locking problem that I haven't fixed yet.
> 
> Cheers,
> g.
> 
> ---
> 
> Grant Likely (6):
>       powerpc: stop exporting irq_map
>       powerpc: make irq_{alloc,free}_virt private and remove count argument
>       powerpc: Make struct irq_host semi-private by moving into irqhost.h
>       dt: generalize of_irq_parse_and_map()
>       powerpc: move irq_alloc_descs_at() call into irq_alloc_virt()
>       powerpc: use irq_alloc_desc() to manage irq allocations
> 
> 
>  arch/microblaze/kernel/irq.c                     |    7 -
>  arch/microblaze/kernel/setup.c                   |    2 
>  arch/mips/kernel/prom.c                          |   14 -
>  arch/powerpc/include/asm/irq.h                   |   88 +------
>  arch/powerpc/include/asm/irqhost.h               |   27 ++
>  arch/powerpc/kernel/irq.c                        |  260 ++++++++++++----------
>  arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    5 
>  arch/powerpc/platforms/52xx/media5200.c          |    5 
>  arch/powerpc/platforms/52xx/mpc52xx_gpt.c        |    1 
>  arch/powerpc/platforms/52xx/mpc52xx_pic.c        |   80 +------
>  arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    5 
>  arch/powerpc/platforms/85xx/socrates_fpga_pic.c  |   26 +-
>  arch/powerpc/platforms/86xx/gef_pic.c            |   10 -
>  arch/powerpc/platforms/8xx/m8xx_setup.c          |    2 
>  arch/powerpc/platforms/cell/axon_msi.c           |   15 +
>  arch/powerpc/platforms/cell/spider-pic.c         |   19 +-
>  arch/powerpc/platforms/embedded6xx/flipper-pic.c |    9 -
>  arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    9 -
>  arch/powerpc/platforms/embedded6xx/wii.c         |    6 -
>  arch/powerpc/platforms/iseries/irq.c             |   10 -
>  arch/powerpc/platforms/powermac/pic.c            |   12 +
>  arch/powerpc/platforms/pseries/ras.c             |    4 
>  arch/powerpc/platforms/pseries/xics.c            |   14 +
>  arch/powerpc/sysdev/cpm1.c                       |    8 -
>  arch/powerpc/sysdev/cpm2_pic.c                   |   10 -
>  arch/powerpc/sysdev/fsl_msi.c                    |    3 
>  arch/powerpc/sysdev/i8259.c                      |    3 
>  arch/powerpc/sysdev/ipic.c                       |   19 +-
>  arch/powerpc/sysdev/mpc8xx_pic.c                 |   10 -
>  arch/powerpc/sysdev/mpc8xxx_gpio.c               |   13 +
>  arch/powerpc/sysdev/mpic.c                       |   33 +--
>  arch/powerpc/sysdev/mpic_msi.c                   |    3 
>  arch/powerpc/sysdev/mpic_pasemi_msi.c            |    5 
>  arch/powerpc/sysdev/mv64x60_pic.c                |   14 +
>  arch/powerpc/sysdev/qe_lib/qe_ic.c               |    9 -
>  arch/powerpc/sysdev/uic.c                        |   13 +
>  arch/powerpc/sysdev/xilinx_intc.c                |    9 -
>  arch/x86/include/asm/irq_controller.h            |   12 -
>  arch/x86/include/asm/prom.h                      |    1 
>  arch/x86/kernel/devicetree.c                     |   77 +------
>  drivers/of/irq.c                                 |  118 ++++++++++
>  include/linux/of_irq.h                           |   31 +++
>  42 files changed, 504 insertions(+), 517 deletions(-)
>  create mode 100644 arch/powerpc/include/asm/irqhost.h
>  delete mode 100644 arch/x86/include/asm/irq_controller.h

^ permalink raw reply

* Re: [PATCH 1/6] powerpc: stop exporting irq_map
From: Benjamin Herrenschmidt @ 2011-05-03  1:44 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200148.8979.66709.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> First step in eliminating irq_map[] table entirely
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  

Ack in principle, needs scrutiny and testing of course :-)

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 2/6] powerpc: make irq_{alloc, free}_virt private and remove count argument
From: Benjamin Herrenschmidt @ 2011-05-03  1:47 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200153.8979.23873.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> irq_alloc_virt() and irq_free_virt() aren't called anywhere but from
> arch/powerpc/kernel/irq.c, and they are only ever called with count=1.
> This patch removes the prototypes from the header file, removes the
> count arguments, and cuts out the dead code.
> 
> Also removes obsolete references to irq_early_init()

Nack.

The count was intended to be able to allocate blocks of interrupts. This
was not used so far because we didn't support MSI blocks (for non-X
MSIs) but that is coming, and unfortunately, the API that was designed
for that is crap and requires contiguous IRQ numbers on the linux side
as well as on the device side (well device side is a HW requirement but
we could have been smarter on the Linux side).

So the ability to allocate blocks will be needed. In fact it's not clear
yet whether we'll also need them to be naturally aligned powers of two
or not at this stage. It depends how the bloody API is going to be used
by drivers.

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/microblaze/kernel/setup.c |    2 -
>  arch/powerpc/include/asm/irq.h |   32 ----------------
>  arch/powerpc/kernel/irq.c      |   82 ++++++++++++++++++++--------------------
>  3 files changed, 40 insertions(+), 76 deletions(-)
> 
> diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
> index 8e2c09b..19d3ab7 100644
> --- a/arch/microblaze/kernel/setup.c
> +++ b/arch/microblaze/kernel/setup.c
> @@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p)
>  
>  	unflatten_device_tree();
>  
> -	/* NOTE I think that this function is not necessary to call */
> -	/* irq_early_init(); */
>  	setup_cpuinfo();
>  
>  	microblaze_cache_init();
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index e1983d5..4d2cc6f 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -264,38 +264,6 @@ extern unsigned int irq_linear_revmap(struct irq_host *host,
>  				      irq_hw_number_t hwirq);
>  
> 
> -
> -/**
> - * irq_alloc_virt - Allocate virtual irq numbers
> - * @host: host owning these new virtual irqs
> - * @count: number of consecutive numbers to allocate
> - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
> - *
> - * This is a low level function that is used internally by irq_create_mapping()
> - * and that can be used by some irq controllers implementations for things
> - * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
> - */
> -extern unsigned int irq_alloc_virt(struct irq_host *host,
> -				   unsigned int count,
> -				   unsigned int hint);
> -
> -/**
> - * irq_free_virt - Free virtual irq numbers
> - * @virq: virtual irq number of the first interrupt to free
> - * @count: number of interrupts to free
> - *
> - * This function is the opposite of irq_alloc_virt. It will not clear reverse
> - * maps, this should be done previously by unmap'ing the interrupt. In fact,
> - * all interrupts covered by the range being freed should have been unmapped
> - * prior to calling this.
> - */
> -extern void irq_free_virt(unsigned int virq, unsigned int count);
> -
> -/**
> - * irq_early_init - Init irq remapping subsystem
> - */
> -extern void irq_early_init(void);
> -
>  static __inline__ int irq_canonicalize(int irq)
>  {
>  	return irq;
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 422672b..5ccf38f 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -647,6 +647,9 @@ void irq_set_virq_count(unsigned int count)
>  		irq_virq_count = count;
>  }
>  
> +static unsigned int irq_alloc_virt(struct irq_host *host, unsigned int hint);
> +static void irq_free_virt(unsigned int virq);
> +
>  static int irq_setup_virq(struct irq_host *host, unsigned int virq,
>  			    irq_hw_number_t hwirq)
>  {
> @@ -675,7 +678,7 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
>  errdesc:
>  	irq_free_descs(virq, 1);
>  error:
> -	irq_free_virt(virq, 1);
> +	irq_free_virt(virq);
>  	return -1;
>  }
>  
> @@ -689,7 +692,7 @@ unsigned int irq_create_direct_mapping(struct irq_host *host)
>  	BUG_ON(host == NULL);
>  	WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
>  
> -	virq = irq_alloc_virt(host, 1, 0);
> +	virq = irq_alloc_virt(host, 0);
>  	if (virq == NO_IRQ) {
>  		pr_debug("irq: create_direct virq allocation failed\n");
>  		return NO_IRQ;
> @@ -742,7 +745,7 @@ unsigned int irq_create_mapping(struct irq_host *host,
>  	} else {
>  		/* Allocate a virtual interrupt number */
>  		hint = hwirq % irq_virq_count;
> -		virq = irq_alloc_virt(host, 1, hint);
> +		virq = irq_alloc_virt(host, hint);
>  		if (virq == NO_IRQ) {
>  			pr_debug("irq: -> virq allocation failed\n");
>  			return NO_IRQ;
> @@ -856,7 +859,7 @@ void irq_dispose_mapping(unsigned int virq)
>  
>  	irq_free_descs(virq, 1);
>  	/* Free it */
> -	irq_free_virt(virq, 1);
> +	irq_free_virt(virq);
>  }
>  EXPORT_SYMBOL_GPL(irq_dispose_mapping);
>  
> @@ -974,36 +977,31 @@ unsigned int irq_linear_revmap(struct irq_host *host,
>  	return revmap[hwirq];
>  }
>  
> -unsigned int irq_alloc_virt(struct irq_host *host,
> -			    unsigned int count,
> -			    unsigned int hint)
> +/**
> + * irq_alloc_virt() - Allocate virtual irq numbers
> + * @host: host owning these new virtual irqs
> + * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
> + *
> + * This is a low level function that is used internally by irq_create_mapping()
> + */
> +static unsigned int irq_alloc_virt(struct irq_host *host, unsigned int hint)
>  {
>  	unsigned long flags;
>  	unsigned int i, j, found = NO_IRQ;
>  
> -	if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
> -		return NO_IRQ;
> -
>  	raw_spin_lock_irqsave(&irq_big_lock, flags);
>  
>  	/* Use hint for 1 interrupt if any */
> -	if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
> +	if (hint >= NUM_ISA_INTERRUPTS &&
>  	    hint < irq_virq_count && irq_map[hint].host == NULL) {
>  		found = hint;
>  		goto hint_found;
>  	}
>  
> -	/* Look for count consecutive numbers in the allocatable
> -	 * (non-legacy) space
> -	 */
> +	/* Look for a free virq in the allocatable (non-legacy) space */
>  	for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
> -		if (irq_map[i].host != NULL)
> -			j = 0;
> -		else
> -			j++;
> -
> -		if (j == count) {
> -			found = i - count + 1;
> +		if (irq_map[i].host == NULL) {
> +			found = i;
>  			break;
>  		}
>  	}
> @@ -1012,36 +1010,36 @@ unsigned int irq_alloc_virt(struct irq_host *host,
>  		return NO_IRQ;
>  	}
>   hint_found:
> -	for (i = found; i < (found + count); i++) {
> -		irq_map[i].hwirq = host->inval_irq;
> -		smp_wmb();
> -		irq_map[i].host = host;
> -	}
> +	irq_map[found].hwirq = host->inval_irq;
> +	smp_wmb();
> +	irq_map[found].host = host;
>  	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
>  	return found;
>  }
>  
> -void irq_free_virt(unsigned int virq, unsigned int count)
> +/**
> + * irq_free_virt() - Free virtual irq numbers
> + * @virq: virtual irq number of the first interrupt to free
> + *
> + * This function is the opposite of irq_alloc_virt. It will not clear reverse
> + * maps, this should be done previously by unmap'ing the interrupt. In fact,
> + * the interrupts being freed should have been unmapped prior to calling this.
> + */
> +static void irq_free_virt(unsigned int virq)
>  {
>  	unsigned long flags;
> -	unsigned int i;
> +	struct irq_host *host;
>  
> -	WARN_ON (virq < NUM_ISA_INTERRUPTS);
> -	WARN_ON (count == 0 || (virq + count) > irq_virq_count);
> +	if ((virq < NUM_ISA_INTERRUPTS) || (virq >= irq_virq_count)) {
> +		WARN_ON(1);
> +		return;
> +	}
>  
>  	raw_spin_lock_irqsave(&irq_big_lock, flags);
> -	for (i = virq; i < (virq + count); i++) {
> -		struct irq_host *host;
> -
> -		if (i < NUM_ISA_INTERRUPTS ||
> -		    (virq + count) > irq_virq_count)
> -			continue;
> -
> -		host = irq_map[i].host;
> -		irq_map[i].hwirq = host->inval_irq;
> -		smp_wmb();
> -		irq_map[i].host = NULL;
> -	}
> +	host = irq_map[virq].host;
> +	irq_map[virq].hwirq = host->inval_irq;
> +	smp_wmb();
> +	irq_map[virq].host = NULL;
>  	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
>  }
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH 3/6] powerpc: Make struct irq_host semi-private by moving into irqhost.h
From: Benjamin Herrenschmidt @ 2011-05-03  1:48 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200158.8979.39548.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> Very few files actually need direct access to struct irq_host members.
> This patch moves the irq_host definition into another file so that it
> isn't brought in by default, and to prepare for the addition of
> struct of_irq_domain, which will factor some of the irq_host behaviour
> out into common code.  This needs to be done because of_irq_domain
> will be embedded inside struct irq_host, and to do that it needs to be
> guaranteed that struct of_irq_domain gets fully defined first.

Why do you want to separate the irq "host" as used by powerpc with the
generic irq domain ? They should be one single thing...

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/powerpc/include/asm/irq.h                   |   20 +--------------
>  arch/powerpc/include/asm/irqhost.h               |   29 ++++++++++++++++++++++
>  arch/powerpc/kernel/irq.c                        |    1 +
>  arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    1 +
>  arch/powerpc/platforms/52xx/media5200.c          |    1 +
>  arch/powerpc/platforms/52xx/mpc52xx_gpt.c        |    1 +
>  arch/powerpc/platforms/52xx/mpc52xx_pic.c        |    1 +
>  arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    1 +
>  arch/powerpc/platforms/cell/axon_msi.c           |    1 +
>  arch/powerpc/platforms/cell/spider-pic.c         |    1 +
>  arch/powerpc/platforms/embedded6xx/flipper-pic.c |    1 +
>  arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    1 +
>  arch/powerpc/platforms/embedded6xx/wii.c         |    6 +++--
>  arch/powerpc/sysdev/fsl_msi.c                    |    1 +
>  arch/powerpc/sysdev/i8259.c                      |    1 +
>  arch/powerpc/sysdev/ipic.c                       |    1 +
>  arch/powerpc/sysdev/mpc8xxx_gpio.c               |    1 +
>  arch/powerpc/sysdev/mpic.c                       |    1 +
>  arch/powerpc/sysdev/mpic_msi.c                   |    1 +
>  arch/powerpc/sysdev/mpic_pasemi_msi.c            |    1 +
>  arch/powerpc/sysdev/qe_lib/qe_ic.c               |    1 +
>  arch/powerpc/sysdev/uic.c                        |    1 +
>  arch/powerpc/sysdev/xilinx_intc.c                |    1 +
>  23 files changed, 54 insertions(+), 21 deletions(-)
>  create mode 100644 arch/powerpc/include/asm/irqhost.h
> 
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index 4d2cc6f..a44be93 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -104,29 +104,11 @@ struct irq_host_ops {
>  		     irq_hw_number_t *out_hwirq, unsigned int *out_type);
>  };
>  
> -struct irq_host {
> -	struct list_head	link;
> -
> -	/* type of reverse mapping technique */
> -	unsigned int		revmap_type;
> +/* Reverse map types; pass into irq_alloc_host revmap_type argument */
>  #define IRQ_HOST_MAP_LEGACY     0 /* legacy 8259, gets irqs 1..15 */
>  #define IRQ_HOST_MAP_NOMAP	1 /* no fast reverse mapping */
>  #define IRQ_HOST_MAP_LINEAR	2 /* linear map of interrupts */
>  #define IRQ_HOST_MAP_TREE	3 /* radix tree */
> -	union {
> -		struct {
> -			unsigned int size;
> -			unsigned int *revmap;
> -		} linear;
> -		struct radix_tree_root tree;
> -	} revmap_data;
> -	struct irq_host_ops	*ops;
> -	void			*host_data;
> -	irq_hw_number_t		inval_irq;
> -
> -	/* Optional device node pointer */
> -	struct device_node	*of_node;
> -};
>  
>  struct irq_data;
>  extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
> diff --git a/arch/powerpc/include/asm/irqhost.h b/arch/powerpc/include/asm/irqhost.h
> new file mode 100644
> index 0000000..958e6c1
> --- /dev/null
> +++ b/arch/powerpc/include/asm/irqhost.h
> @@ -0,0 +1,29 @@
> +#ifndef _ASM_POWERPC_IRQHOST_H
> +#define _ASM_POWERPC_IRQHOST_H
> +
> +#include <linux/list.h>
> +#include <linux/radix-tree.h>
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +
> +struct irq_host {
> +	struct list_head	link;
> +
> +	/* type of reverse mapping technique */
> +	unsigned int		revmap_type;
> +	union {
> +		struct {
> +			unsigned int size;
> +			unsigned int *revmap;
> +		} linear;
> +		struct radix_tree_root tree;
> +	} revmap_data;
> +	struct irq_host_ops	*ops;
> +	void			*host_data;
> +	irq_hw_number_t		inval_irq;
> +
> +	/* Optional device node pointer */
> +	struct device_node	*of_node;
> +};
> +
> +#endif /* _ASM_POWERPC_IRQHOST_H */
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 5ccf38f..b961b19 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -56,6 +56,7 @@
>  #include <linux/of.h>
>  #include <linux/of_irq.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/uaccess.h>
>  #include <asm/system.h>
>  #include <asm/io.h>
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> index a8bc0d4..162bbb7 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> @@ -18,6 +18,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/io.h>
> +#include <asm/irqhost.h>
>  #include <asm/prom.h>
>  
>  static struct device_node *cpld_pic_node;
> diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
> index 96f85e5..e03f2cb 100644
> --- a/arch/powerpc/platforms/52xx/media5200.c
> +++ b/arch/powerpc/platforms/52xx/media5200.c
> @@ -25,6 +25,7 @@
>  #include <linux/irq.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> +#include <asm/irqhost.h>
>  #include <asm/time.h>
>  #include <asm/prom.h>
>  #include <asm/machdep.h>
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> index 6c39b9c..55b2d26 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> @@ -67,6 +67,7 @@
>  #include <linux/watchdog.h>
>  #include <linux/miscdevice.h>
>  #include <linux/uaccess.h>
> +#include <asm/irqhost.h>
>  #include <asm/div64.h>
>  #include <asm/mpc52xx.h>
>  
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> index bb61181..65bbfd1 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> @@ -101,6 +101,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/mpc52xx.h>
> diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> index 5d6c34c..0ca79e0 100644
> --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> @@ -19,6 +19,7 @@
>  #include <linux/bootmem.h>
>  #include <linux/slab.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/cpm2.h>
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index 1e3329e..e1469ae 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -17,6 +17,7 @@
>  #include <linux/debugfs.h>
>  #include <linux/slab.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/dcr.h>
>  #include <asm/machdep.h>
>  #include <asm/prom.h>
> diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
> index 34d2b99..73a5494 100644
> --- a/arch/powerpc/platforms/cell/spider-pic.c
> +++ b/arch/powerpc/platforms/cell/spider-pic.c
> @@ -24,6 +24,7 @@
>  #include <linux/irq.h>
>  #include <linux/ioport.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/pgtable.h>
>  #include <asm/prom.h>
>  #include <asm/io.h>
> diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> index 77cbe4c..1b60a34 100644
> --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> @@ -18,6 +18,7 @@
>  #include <linux/init.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  
>  #include "flipper-pic.h"
> diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> index 44b398b..4f87661 100644
> --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> @@ -18,6 +18,7 @@
>  #include <linux/init.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  
>  #include "hlwd-pic.h"
> diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c
> index 1b5dc1a..c9176a9 100644
> --- a/arch/powerpc/platforms/embedded6xx/wii.c
> +++ b/arch/powerpc/platforms/embedded6xx/wii.c
> @@ -85,9 +85,11 @@ void __init wii_memory_fixups(void)
>  	wii_hole_start = p[0].base + p[0].size;
>  	wii_hole_size = p[1].base - wii_hole_start;
>  
> -	pr_info("MEM1: <%08llx %08llx>\n", p[0].base, p[0].size);
> +	pr_info("MEM1: <%08llx %08llx>\n",
> +		(unsigned long long)p[0].base, (unsigned long long)p[0].size);
>  	pr_info("HOLE: <%08lx %08lx>\n", wii_hole_start, wii_hole_size);
> -	pr_info("MEM2: <%08llx %08llx>\n", p[1].base, p[1].size);
> +	pr_info("MEM2: <%08llx %08llx>\n",
> +		(unsigned long long)p[1].base, (unsigned long long)p[1].size);
>  
>  	p[0].size += wii_hole_size + p[1].size;
>  
> diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
> index d5679dc..2c11b3e 100644
> --- a/arch/powerpc/sysdev/fsl_msi.c
> +++ b/arch/powerpc/sysdev/fsl_msi.c
> @@ -19,6 +19,7 @@
>  #include <linux/slab.h>
>  #include <linux/of_platform.h>
>  #include <sysdev/fsl_soc.h>
> +#include <asm/irqhost.h>
>  #include <asm/prom.h>
>  #include <asm/hw_irq.h>
>  #include <asm/ppc-pci.h>
> diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
> index 142770c..30869f0 100644
> --- a/arch/powerpc/sysdev/i8259.c
> +++ b/arch/powerpc/sysdev/i8259.c
> @@ -13,6 +13,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/delay.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/i8259.h>
>  #include <asm/prom.h>
> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
> index f0ece79..fc3751f 100644
> --- a/arch/powerpc/sysdev/ipic.c
> +++ b/arch/powerpc/sysdev/ipic.c
> @@ -24,6 +24,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/fsl_devices.h>
>  #include <asm/irq.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/ipic.h>
> diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> index fb4963a..f6839a7 100644
> --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
> +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> @@ -17,6 +17,7 @@
>  #include <linux/gpio.h>
>  #include <linux/slab.h>
>  #include <linux/irq.h>
> +#include <asm/irqhost.h>
>  
>  #define MPC8XXX_GPIO_PINS	32
>  
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 824a94f..6e9e594 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -28,6 +28,7 @@
>  #include <linux/pci.h>
>  #include <linux/slab.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/ptrace.h>
>  #include <asm/signal.h>
>  #include <asm/io.h>
> diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
> index 0f67cd7..50176ed 100644
> --- a/arch/powerpc/sysdev/mpic_msi.c
> +++ b/arch/powerpc/sysdev/mpic_msi.c
> @@ -11,6 +11,7 @@
>  #include <linux/irq.h>
>  #include <linux/bitmap.h>
>  #include <linux/msi.h>
> +#include <asm/irqhost.h>
>  #include <asm/mpic.h>
>  #include <asm/prom.h>
>  #include <asm/hw_irq.h>
> diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> index 38e6238..6b11a89 100644
> --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
> +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> @@ -18,6 +18,7 @@
>  #include <linux/irq.h>
>  #include <linux/bootmem.h>
>  #include <linux/msi.h>
> +#include <asm/irqhost.h>
>  #include <asm/mpic.h>
>  #include <asm/prom.h>
>  #include <asm/hw_irq.h>
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> index b2acda0..9dd7746 100644
> --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> @@ -26,6 +26,7 @@
>  #include <linux/device.h>
>  #include <linux/bootmem.h>
>  #include <linux/spinlock.h>
> +#include <asm/irqhost.h>
>  #include <asm/irq.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
> diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
> index 984cd20..a097f4c 100644
> --- a/arch/powerpc/sysdev/uic.c
> +++ b/arch/powerpc/sysdev/uic.c
> @@ -26,6 +26,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel_stat.h>
>  #include <asm/irq.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/dcr.h>
> diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
> index 6183799..28d4ded 100644
> --- a/arch/powerpc/sysdev/xilinx_intc.c
> +++ b/arch/powerpc/sysdev/xilinx_intc.c
> @@ -23,6 +23,7 @@
>  #include <linux/kernel.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/processor.h>
>  #include <asm/i8259.h>

^ permalink raw reply

* Re: [PATCH 4/6] dt: generalize irq_of_create_mapping()
From: Benjamin Herrenschmidt @ 2011-05-03  1:50 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200203.8979.3569.stgit@ponder>

On Thu, 2011-04-28 at 14:02 -0600, Grant Likely wrote:
> This patch creates a common implementation of irq_of_create_mapping()
> and factors out the interrupt domain translation code from powerpc to
> make it available for all architectures.

I think you are going the wrong way around.

First thing first, is to make the irq domain / mapping API generic
without the OF bits.

IE. move the IRQ domain generically, get rid of irq_map by putting the
domain ptr & hw numbers in the irq desc/data etc...

Then you can move over the OF specific bits which are optional and
orthogonal to a large extent.

Cheers,
Ben.

> It creates a new structure, struct of_irq_domain, which can be
> embedded into the private data structure of an interrupt controller.
> Any interrupt controller can call of_irq_domain_add() to register a
> structure with a .map() hook that can translate irq specifiers from
> the device tree into linux irq numbers.
> 
> The patch also modifies the powerpc irq_host to embed the
> of_irq_domain structure and use the new common infrastructure for
> registering domains.  This separates the reverse mapping and irq
> allocation infrastructure of irq_host from the domain registration
> infrastructure.  I elected to split the functionality this way for
> several reasons.  First, with the major irq cleanup done by Thomas
> Gleixner, dynamic allocation of irqs can be handled gracefully with
> irq_alloc_desc*() and interrupt controllers may not need or want an
> irq_host layer to manage it for them.  For example, the new
> irq_chip_generic() already has a method for mapping between hwirq and
> Linux irq.
> 
> Second, the irq_host code currently has a lot of complexity to handle
> all the different reverse mapping types from a single structure.  The
> radix mapping in particular has a lot of support code, but only one
> user.  I didn't want to bring that complexity into the common code
> as-is.  Instead, I'd prefer to create a separate encapsulating
> structure for each revmap, and each type would have a separate .map
> hook.
> 
> For now, the mapping code remains powerpc-specific and further
> generalization will happen in subsequent patches.
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/microblaze/kernel/irq.c             |    7 --
>  arch/mips/kernel/prom.c                  |   14 ----
>  arch/powerpc/include/asm/irq.h           |   21 +++--
>  arch/powerpc/include/asm/irqhost.h       |    4 -
>  arch/powerpc/kernel/irq.c                |   99 ++++++++++++++-----------
>  arch/powerpc/platforms/cell/axon_msi.c   |   12 ++-
>  arch/powerpc/platforms/cell/spider-pic.c |    8 +-
>  arch/powerpc/sysdev/fsl_msi.c            |    2 -
>  arch/powerpc/sysdev/i8259.c              |    2 -
>  arch/powerpc/sysdev/ipic.c               |    2 -
>  arch/powerpc/sysdev/mpic.c               |    4 +
>  arch/powerpc/sysdev/mpic_msi.c           |    2 -
>  arch/powerpc/sysdev/mpic_pasemi_msi.c    |    4 +
>  arch/powerpc/sysdev/qe_lib/qe_ic.c       |    2 -
>  arch/x86/include/asm/irq_controller.h    |   12 ---
>  arch/x86/include/asm/prom.h              |    1 
>  arch/x86/kernel/devicetree.c             |   77 ++++----------------
>  drivers/of/irq.c                         |  118 ++++++++++++++++++++++++++++++
>  include/linux/of_irq.h                   |   31 ++++++++
>  19 files changed, 248 insertions(+), 174 deletions(-)
>  delete mode 100644 arch/x86/include/asm/irq_controller.h
> 
> diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
> index ce7ac84..59bb560 100644
> --- a/arch/microblaze/kernel/irq.c
> +++ b/arch/microblaze/kernel/irq.c
> @@ -54,10 +54,3 @@ unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
>  	return hwirq;
>  }
>  EXPORT_SYMBOL_GPL(irq_create_mapping);
> -
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> -{
> -	return intspec[0];
> -}
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
> index a19811e9..0b82f98 100644
> --- a/arch/mips/kernel/prom.c
> +++ b/arch/mips/kernel/prom.c
> @@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,
>  }
>  #endif
>  
> -/*
> - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
> - *
> - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
> - * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
> - * supported.
> - */
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> -{
> -	return intspec[0];
> -}
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> -
>  void __init early_init_devtree(void *params)
>  {
>  	/* Setup flat device-tree pointer */
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index a44be93..ccefc8c 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -55,11 +55,18 @@ typedef unsigned long irq_hw_number_t;
>   * model). It's the host callbacks that are responsible for setting the
>   * irq_chip on a given irq_desc after it's been mapped.
>   *
> + * irq_host builds upon the of_irq_domain code in drivers/of/irq.c.
> + * of_irq_domain provides all of the translation hooks for registering irq
> + * controllers. irq_host add mapping infrastructure to and from hardware
> + * irq numbers. IRQ controllers that don't need the mapping infrastructure
> + * can use irq_domain directly.
> + *
>   * The host code and data structures are fairly agnostic to the fact that
>   * we use an open firmware device-tree. We do have references to struct
> - * device_node in two places: in irq_find_host() to find the host matching
> - * a given interrupt controller node, and of course as an argument to its
> - * counterpart host->ops->match() callback. However, those are treated as
> + * device_node in two places: in of_irq_domain_find() to find the host matching
> + * a given interrupt controller node (which is actually common of_irq_domain
> + * code), and of course as an argument to its counterpart host->ops->match()
> + * and host->domain->match() callbacks. However, those are treated as
>   * generic pointers by the core and the fact that it's actually a device-node
>   * pointer is purely a convention between callers and implementation. This
>   * code could thus be used on other architectures by replacing those two
> @@ -137,14 +144,6 @@ extern struct irq_host *irq_alloc_host(struct device_node *of_node,
>  				       struct irq_host_ops *ops,
>  				       irq_hw_number_t inval_irq);
>  
> -
> -/**
> - * irq_find_host - Locates a host for a given device node
> - * @node: device-tree node of the interrupt controller
> - */
> -extern struct irq_host *irq_find_host(struct device_node *node);
> -
> -
>  /**
>   * irq_set_default_host - Set a "default" host
>   * @host: default host pointer
> diff --git a/arch/powerpc/include/asm/irqhost.h b/arch/powerpc/include/asm/irqhost.h
> index 958e6c1..a97a513 100644
> --- a/arch/powerpc/include/asm/irqhost.h
> +++ b/arch/powerpc/include/asm/irqhost.h
> @@ -8,6 +8,7 @@
>  
>  struct irq_host {
>  	struct list_head	link;
> +	struct of_irq_domain	domain;
>  
>  	/* type of reverse mapping technique */
>  	unsigned int		revmap_type;
> @@ -21,9 +22,6 @@ struct irq_host {
>  	struct irq_host_ops	*ops;
>  	void			*host_data;
>  	irq_hw_number_t		inval_irq;
> -
> -	/* Optional device node pointer */
> -	struct device_node	*of_node;
>  };
>  
>  #endif /* _ASM_POWERPC_IRQHOST_H */
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index b961b19..9300e1c 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -514,11 +514,40 @@ struct irq_host *virq_to_host(unsigned int virq)
>  }
>  EXPORT_SYMBOL_GPL(virq_to_host);
>  
> -static int default_irq_host_match(struct irq_host *h, struct device_node *np)
> +/**
> + * irq_host_domain_match() - irq_domain hook to call irq_host match ops.
> + *
> + * This functions gets set as the irq domain match function for irq_host
> + * instances *if* the ->ops->match() hook is populated.  If ->match() is
> + * not populated, then the default irq_domain matching behaviour is used
> + * instead.
> + */
> +static bool irq_host_domain_match(struct of_irq_domain *domain,
> +				  struct device_node *controller)
>  {
> -	return h->of_node != NULL && h->of_node == np;
> +	struct irq_host *host = container_of(domain, struct irq_host, domain);
> +	return host->ops->match(host, controller);
>  }
>  
> +static unsigned int irq_host_domain_map(struct of_irq_domain *domain,
> +					struct device_node *controller,
> +					const u32 *intspec,
> +					unsigned int intsize);
> +
> +/**
> + * irq_alloc_host() - Allocate and register an irq_host
> + * @of_node: Device node of the irq controller; this is used mainly as an
> + *           anonymouns context pointer.
> + * @revmap_type: One of IRQ_HOST_MAP_* defined in arch/powerpc/include/asm/irq.h
> + *               Defines the type of reverse map to be used by the irq_host.
> + * @revmap_arg: Currently only used by the IRQ_HOST_MAP_LINEAR which uses it
> + *              to define the size of the reverse map.
> + * @ops: irq_host ops structure for match/map/unmap/remap/xlate operations.
> + * @inval_irq: Value used by irq controller to indicate an invalid irq.
> + *
> + * irq_host implements mapping between hardware irq numbers and the linux
> + * virq number space.  This function allocates and registers an irq_host.
> + */
>  struct irq_host *irq_alloc_host(struct device_node *of_node,
>  				unsigned int revmap_type,
>  				unsigned int revmap_arg,
> @@ -542,10 +571,10 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  	host->revmap_type = revmap_type;
>  	host->inval_irq = inval_irq;
>  	host->ops = ops;
> -	host->of_node = of_node_get(of_node);
> -
> -	if (host->ops->match == NULL)
> -		host->ops->match = default_irq_host_match;
> +	host->domain.controller = of_node_get(of_node);
> +	host->domain.map = irq_host_domain_map;
> +	if (host->ops->match != NULL)
> +		host->domain.match = irq_host_domain_match;
>  
>  	raw_spin_lock_irqsave(&irq_big_lock, flags);
>  
> @@ -561,7 +590,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  			 * instead of the current cruft
>  			 */
>  			if (mem_init_done) {
> -				of_node_put(host->of_node);
> +				of_node_put(host->domain.controller);
>  				kfree(host);
>  			}
>  			return NULL;
> @@ -572,6 +601,8 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  	list_add(&host->link, &irq_hosts);
>  	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
>  
> +	of_irq_domain_add(&host->domain);
> +
>  	/* Additional setups per revmap type */
>  	switch(revmap_type) {
>  	case IRQ_HOST_MAP_LEGACY:
> @@ -611,32 +642,12 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  	return host;
>  }
>  
> -struct irq_host *irq_find_host(struct device_node *node)
> -{
> -	struct irq_host *h, *found = NULL;
> -	unsigned long flags;
> -
> -	/* We might want to match the legacy controller last since
> -	 * it might potentially be set to match all interrupts in
> -	 * the absence of a device node. This isn't a problem so far
> -	 * yet though...
> -	 */
> -	raw_spin_lock_irqsave(&irq_big_lock, flags);
> -	list_for_each_entry(h, &irq_hosts, link)
> -		if (h->ops->match(h, node)) {
> -			found = h;
> -			break;
> -		}
> -	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
> -	return found;
> -}
> -EXPORT_SYMBOL_GPL(irq_find_host);
> -
>  void irq_set_default_host(struct irq_host *host)
>  {
>  	pr_debug("irq: Default host set to @0x%p\n", host);
>  
>  	irq_default_host = host;
> +	of_irq_set_default_domain(&host->domain);
>  }
>  
>  void irq_set_virq_count(unsigned int count)
> @@ -757,30 +768,29 @@ unsigned int irq_create_mapping(struct irq_host *host,
>  		return NO_IRQ;
>  
>  	printk(KERN_DEBUG "irq: irq %lu on host %s mapped to virtual irq %u\n",
> -		hwirq, host->of_node ? host->of_node->full_name : "null", virq);
> +		hwirq, host->domain.controller ? host->domain.controller->full_name : "null", virq);
>  
>  	return virq;
>  }
>  EXPORT_SYMBOL_GPL(irq_create_mapping);
>  
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> +/**
> + * irq_host_domain_map() - Map device tree irq to linux irq number
> + * This hook implements all of the powerpc 'irq_host' behaviour, which means
> + * - calling the ->ops->xlate hook to get the hardware irq number,
> + * - calling of_create_mapping to translate/allocate a linux virq number
> + * - calling irq_set_irq_type() if necessary
> + */
> +static unsigned int irq_host_domain_map(struct of_irq_domain *domain,
> +					struct device_node *controller,
> +					const u32 *intspec,
> +					unsigned int intsize)
>  {
> -	struct irq_host *host;
> +	struct irq_host *host = container_of(domain, struct irq_host, domain);
>  	irq_hw_number_t hwirq;
>  	unsigned int type = IRQ_TYPE_NONE;
>  	unsigned int virq;
>  
> -	if (controller == NULL)
> -		host = irq_default_host;
> -	else
> -		host = irq_find_host(controller);
> -	if (host == NULL) {
> -		printk(KERN_WARNING "irq: no irq host found for %s !\n",
> -		       controller->full_name);
> -		return NO_IRQ;
> -	}
> -
>  	/* If host has no translation, then we assume interrupt line */
>  	if (host->ops->xlate == NULL)
>  		hwirq = intspec[0];
> @@ -801,7 +811,6 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
>  		irq_set_irq_type(virq, type);
>  	return virq;
>  }
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
>  
>  void irq_dispose_mapping(unsigned int virq)
>  {
> @@ -1128,8 +1137,8 @@ static int virq_debug_show(struct seq_file *m, void *private)
>  				p = none;
>  			seq_printf(m, "%-15s  ", p);
>  
> -			if (irq_map[i].host && irq_map[i].host->of_node)
> -				p = irq_map[i].host->of_node->full_name;
> +			if (irq_map[i].host && irq_map[i].host->domain.controller)
> +				p = irq_map[i].host->domain.controller->full_name;
>  			else
>  				p = none;
>  			seq_printf(m, "%s\n", p);
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index e1469ae..f125673 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
>  
>  static struct axon_msic *find_msi_translator(struct pci_dev *dev)
>  {
> -	struct irq_host *irq_host;
> +	struct of_irq_domain *irq_domain;
>  	struct device_node *dn, *tmp;
>  	const phandle *ph;
>  	struct axon_msic *msic = NULL;
> @@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
>  		goto out_error;
>  	}
>  
> -	irq_host = irq_find_host(dn);
> -	if (!irq_host) {
> +	irq_domain = of_irq_domain_find(dn);
> +	if (!irq_domain) {
>  		dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
>  			dn->full_name);
>  		goto out_error;
>  	}
>  
> -	msic = irq_host->host_data;
> +	msic = irq_domain->priv;
>  
>  out_error:
>  	of_node_put(dn);
> @@ -336,7 +336,7 @@ static void axon_msi_shutdown(struct platform_device *device)
>  	u32 tmp;
>  
>  	pr_devel("axon_msi: disabling %s\n",
> -		  msic->irq_host->of_node->full_name);
> +		  msic->irq_host->domain.controller->full_name);
>  	tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
>  	tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
>  	msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
> @@ -399,7 +399,7 @@ static int axon_msi_probe(struct platform_device *device)
>  		goto out_free_fifo;
>  	}
>  
> -	msic->irq_host->host_data = msic;
> +	msic->irq_host->domain.priv = msic;
>  
>  	irq_set_handler_data(virq, msic);
>  	irq_set_chained_handler(virq, axon_msi_cascade);
> diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
> index 73a5494..5bf36ab 100644
> --- a/arch/powerpc/platforms/cell/spider-pic.c
> +++ b/arch/powerpc/platforms/cell/spider-pic.c
> @@ -236,18 +236,20 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
>  	 * tree in case the device-tree is ever fixed
>  	 */
>  	struct of_irq oirq;
> -	if (of_irq_map_one(pic->host->of_node, 0, &oirq) == 0) {
> +	if (of_irq_map_one(pic->host->domain.controller, 0, &oirq) == 0) {
>  		virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
>  					     oirq.size);
>  		return virq;
>  	}
>  
>  	/* Now do the horrible hacks */
> -	tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL);
> +	tmp = of_get_property(pic->host->domain.controller,
> +				"#interrupt-cells", NULL);
>  	if (tmp == NULL)
>  		return NO_IRQ;
>  	intsize = *tmp;
> -	imap = of_get_property(pic->host->of_node, "interrupt-map", &imaplen);
> +	imap = of_get_property(pic->host->domain.controller,
> +				"interrupt-map", &imaplen);
>  	if (imap == NULL || imaplen < (intsize + 1))
>  		return NO_IRQ;
>  	iic = of_find_node_by_phandle(imap[intsize]);
> diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
> index 2c11b3e..b45a25a 100644
> --- a/arch/powerpc/sysdev/fsl_msi.c
> +++ b/arch/powerpc/sysdev/fsl_msi.c
> @@ -82,7 +82,7 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
>  	int rc;
>  
>  	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> -			      msi_data->irqhost->of_node);
> +			      msi_data->irqhost->domain.controller);
>  	if (rc)
>  		return rc;
>  
> diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
> index 30869f0..a6f78fb 100644
> --- a/arch/powerpc/sysdev/i8259.c
> +++ b/arch/powerpc/sysdev/i8259.c
> @@ -166,7 +166,7 @@ static struct resource pic_edgectrl_iores = {
>  
>  static int i8259_host_match(struct irq_host *h, struct device_node *node)
>  {
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int i8259_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
> index fc3751f..5805c7b 100644
> --- a/arch/powerpc/sysdev/ipic.c
> +++ b/arch/powerpc/sysdev/ipic.c
> @@ -676,7 +676,7 @@ static struct irq_chip ipic_edge_irq_chip = {
>  static int ipic_host_match(struct irq_host *h, struct device_node *node)
>  {
>  	/* Exact match, unless ipic node is NULL */
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int ipic_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 6e9e594..cafc364 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -956,7 +956,7 @@ static struct irq_chip mpic_irq_ht_chip = {
>  static int mpic_host_match(struct irq_host *h, struct device_node *node)
>  {
>  	/* Exact match, unless mpic node is NULL */
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int mpic_host_map(struct irq_host *h, unsigned int virq,
> @@ -1296,7 +1296,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
>  
>  	BUG_ON(isu_num >= MPIC_MAX_ISU);
>  
> -	mpic_map(mpic, mpic->irqhost->of_node,
> +	mpic_map(mpic, mpic->irqhost->domain.controller,
>  		 paddr, &mpic->isus[isu_num], 0,
>  		 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
>  
> diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
> index 50176ed..ddf79c7 100644
> --- a/arch/powerpc/sysdev/mpic_msi.c
> +++ b/arch/powerpc/sysdev/mpic_msi.c
> @@ -85,7 +85,7 @@ int mpic_msi_init_allocator(struct mpic *mpic)
>  	int rc;
>  
>  	rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
> -			      mpic->irqhost->of_node);
> +			      mpic->irqhost->domain.controller);
>  	if (rc)
>  		return rc;
>  
> diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> index 6b11a89..857be51 100644
> --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
> +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> @@ -153,8 +153,8 @@ int mpic_pasemi_msi_init(struct mpic *mpic)
>  {
>  	int rc;
>  
> -	if (!mpic->irqhost->of_node ||
> -	    !of_device_is_compatible(mpic->irqhost->of_node,
> +	if (!mpic->irqhost->domain.controller ||
> +	    !of_device_is_compatible(mpic->irqhost->domain.controller,
>  				     "pasemi,pwrficient-openpic"))
>  		return -ENODEV;
>  
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> index 9dd7746..c2ccafa 100644
> --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> @@ -250,7 +250,7 @@ static struct irq_chip qe_ic_irq_chip = {
>  static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
>  {
>  	/* Exact match, unless qe_ic node is NULL */
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h
> deleted file mode 100644
> index 423bbbd..0000000
> --- a/arch/x86/include/asm/irq_controller.h
> +++ /dev/null
> @@ -1,12 +0,0 @@
> -#ifndef __IRQ_CONTROLLER__
> -#define __IRQ_CONTROLLER__
> -
> -struct irq_domain {
> -	int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize,
> -			u32 *out_hwirq, u32 *out_type);
> -	void *priv;
> -	struct device_node *controller;
> -	struct list_head l;
> -};
> -
> -#endif
> diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
> index 971e0b4..eb9d5ab 100644
> --- a/arch/x86/include/asm/prom.h
> +++ b/arch/x86/include/asm/prom.h
> @@ -21,7 +21,6 @@
>  #include <asm/irq.h>
>  #include <asm/atomic.h>
>  #include <asm/setup.h>
> -#include <asm/irq_controller.h>
>  
>  #ifdef CONFIG_OF
>  extern int of_ioapic;
> diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
> index 706a9fb..651e724 100644
> --- a/arch/x86/kernel/devicetree.c
> +++ b/arch/x86/kernel/devicetree.c
> @@ -15,64 +15,14 @@
>  #include <linux/of_pci.h>
>  
>  #include <asm/hpet.h>
> -#include <asm/irq_controller.h>
>  #include <asm/apic.h>
>  #include <asm/pci_x86.h>
>  
>  __initdata u64 initial_dtb;
>  char __initdata cmd_line[COMMAND_LINE_SIZE];
> -static LIST_HEAD(irq_domains);
> -static DEFINE_RAW_SPINLOCK(big_irq_lock);
>  
>  int __initdata of_ioapic;
>  
> -#ifdef CONFIG_X86_IO_APIC
> -static void add_interrupt_host(struct irq_domain *ih)
> -{
> -	unsigned long flags;
> -
> -	raw_spin_lock_irqsave(&big_irq_lock, flags);
> -	list_add(&ih->l, &irq_domains);
> -	raw_spin_unlock_irqrestore(&big_irq_lock, flags);
> -}
> -#endif
> -
> -static struct irq_domain *get_ih_from_node(struct device_node *controller)
> -{
> -	struct irq_domain *ih, *found = NULL;
> -	unsigned long flags;
> -
> -	raw_spin_lock_irqsave(&big_irq_lock, flags);
> -	list_for_each_entry(ih, &irq_domains, l) {
> -		if (ih->controller ==  controller) {
> -			found = ih;
> -			break;
> -		}
> -	}
> -	raw_spin_unlock_irqrestore(&big_irq_lock, flags);
> -	return found;
> -}
> -
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> -{
> -	struct irq_domain *ih;
> -	u32 virq, type;
> -	int ret;
> -
> -	ih = get_ih_from_node(controller);
> -	if (!ih)
> -		return 0;
> -	ret = ih->xlate(ih, intspec, intsize, &virq, &type);
> -	if (ret)
> -		return 0;
> -	if (type == IRQ_TYPE_NONE)
> -		return virq;
> -	irq_set_irq_type(virq, type);
> -	return virq;
> -}
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> -
>  unsigned long pci_address_to_pio(phys_addr_t address)
>  {
>  	/*
> @@ -366,32 +316,33 @@ static struct of_ioapic_type of_ioapic_type[] =
>  	},
>  };
>  
> -static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
> -			u32 *out_hwirq, u32 *out_type)
> +static unsigned int ioapic_of_irq_map(struct of_irq_domain *id,
> +				      struct device_node *np,
> +				      const u32 *intspec, u32 intsize)
>  {
>  	struct io_apic_irq_attr attr;
>  	struct of_ioapic_type *it;
> -	u32 line, idx, type;
> +	u32 line, idx, type, hwirq;
>  
>  	if (intsize < 2)
> -		return -EINVAL;
> +		return 0;
>  
>  	line = *intspec;
>  	idx = (u32) id->priv;
> -	*out_hwirq = line + mp_gsi_routing[idx].gsi_base;
> +	hwirq = line + mp_gsi_routing[idx].gsi_base;
>  
>  	intspec++;
>  	type = *intspec;
>  
>  	if (type >= ARRAY_SIZE(of_ioapic_type))
> -		return -EINVAL;
> +		return 0;
>  
>  	it = of_ioapic_type + type;
> -	*out_type = it->out_type;
> -
>  	set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
>  
> -	return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr);
> +	if (io_apic_setup_irq_pin(hwirq, cpu_to_node(0), &attr))
> +		return 0;
> +	return hwirq;
>  }
>  
>  static void __init ioapic_add_ofnode(struct device_node *np)
> @@ -408,14 +359,14 @@ static void __init ioapic_add_ofnode(struct device_node *np)
>  
>  	for (i = 0; i < nr_ioapics; i++) {
>  		if (r.start == mp_ioapics[i].apicaddr) {
> -			struct irq_domain *id;
> +			struct of_irq_domain *id;
>  
>  			id = kzalloc(sizeof(*id), GFP_KERNEL);
>  			BUG_ON(!id);
> -			id->controller = np;
> -			id->xlate = ioapic_xlate;
> +			id->controller = of_node_get(np);
> +			id->map = ioapic_of_irq_map;
>  			id->priv = (void *)i;
> -			add_interrupt_host(id);
> +			of_irq_domain_add(id);
>  			return;
>  		}
>  	}
> diff --git a/drivers/of/irq.c b/drivers/of/irq.c
> index 75b0d3c..6da0964 100644
> --- a/drivers/of/irq.c
> +++ b/drivers/of/irq.c
> @@ -19,6 +19,7 @@
>   */
>  
>  #include <linux/errno.h>
> +#include <linux/list.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_irq.h>
> @@ -29,6 +30,123 @@
>  #define NO_IRQ 0
>  #endif
>  
> +/*
> + * Device Tree IRQ domains
> + *
> + * IRQ domains provide translation from device tree irq controller nodes to
> + * linux IRQ numbers.  IRQ controllers register an irq_domain with a .map()
> + * hook that performs everything needed to decode and configure a device
> + * tree specified interrupt.
> + */
> +static LIST_HEAD(of_irq_domains);
> +static DEFINE_RAW_SPINLOCK(of_irq_lock);
> +static struct of_irq_domain *of_irq_default_domain;
> +
> +/**
> + * of_irq_domain_default_match() - Return true if the controller pointers match
> + *
> + * Default match behaviour for of_irq_domains.  If the device tree node pointer
> + * matches the value stored in the domain structure, then return true.
> + */
> +static bool of_irq_domain_default_match(struct of_irq_domain *domain,
> +					struct device_node *controller)
> +{
> +	return domain->controller == controller;
> +}
> +
> +/**
> + * of_irq_domain_add() - Register a device tree irq domain
> + * @domain: pointer to domain structure to be registered.
> + *
> + * Adds an of_irq_domain to the global list of domains.
> + */
> +void of_irq_domain_add(struct of_irq_domain *domain)
> +{
> +	unsigned long flags;
> +
> +	if (!domain->match)
> +		domain->match = of_irq_domain_default_match;
> +	if (!domain->map) {
> +		WARN_ON(1);
> +		return;
> +	}
> +
> +	raw_spin_lock_irqsave(&of_irq_lock, flags);
> +	list_add(&domain->list, &of_irq_domains);
> +	raw_spin_unlock_irqrestore(&of_irq_lock, flags);
> +}
> +
> +/**
> + * of_irq_domain_find() - Find the domain that handles a given device tree node
> + *
> + * Returns the pointer to an of_irq_domain capable of translating irq specifiers
> + * for the given irq controller device tree node.  Returns NULL if a suitable
> + * domain could not be found.
> + */
> +struct of_irq_domain *of_irq_domain_find(struct device_node *controller)
> +{
> +	struct of_irq_domain *domain, *found = NULL;
> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&of_irq_lock, flags);
> +	list_for_each_entry(domain, &of_irq_domains, list) {
> +		if (domain->match(domain, controller)) {
> +			found = domain;
> +			break;
> +		}
> +	}
> +	raw_spin_unlock_irqrestore(&of_irq_lock, flags);
> +	return found;
> +}
> +
> +/**
> + * of_irq_set_default_domain() - Set a "default" host
> + * @domain: default domain pointer
> + *
> + * For convenience, it's possible to set a "default" host that will be used
> + * whenever NULL is passed to irq_of_create_mapping(). It makes life easier
> + * for platforms that want to manipulate a few hard coded interrupt numbers
> + * that aren't properly represented in the device-tree.
> + */
> +void of_irq_set_default_domain(struct of_irq_domain *domain)
> +{
> +	pr_debug("irq: Default host set to @0x%p\n", domain);
> +	of_irq_default_domain = domain;
> +}
> +
> +/**
> + * irq_create_of_mapping() - Map a linux irq # from a device tree specifier
> + * @controller - interrupt-controller node in the device tree
> + * @intspec - array of interrupt specifier data.  Points to an array of u32
> + *            values.  Data is *cpu-native* endian u32 values.
> + * @intsize - size of intspec array.
> + *
> + * Given an interrupt controller node pointer and an interrupt specifier, this
> + * function looks up the linux irq number.
> + */
> +unsigned int irq_create_of_mapping(struct device_node *controller,
> +				   const u32 *intspec, unsigned int intsize)
> +{
> +	struct of_irq_domain *domain;
> +
> +	domain = of_irq_domain_find(controller);
> +	if (!domain)
> +		domain = of_irq_default_domain;
> +	if (!domain) {
> +		pr_warn("error: no irq host found for %s !\n",
> +			controller->full_name);
> +#if defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE)
> +		/* FIXME: make Microblaze and MIPS register irq domains */
> +		return intspec[0];
> +#else /* defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE) */
> +		return NO_IRQ;
> +#endif /* defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE) */
> +	}
> +
> +	return domain->map(domain, controller, intspec, intsize);
> +}
> +EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> +
>  /**
>   * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
>   * @device: Device node of the device whose interrupt is to be mapped
> diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
> index 109e013..511dbc3 100644
> --- a/include/linux/of_irq.h
> +++ b/include/linux/of_irq.h
> @@ -33,6 +33,37 @@ struct of_irq {
>  	u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
>  };
>  
> +/**
> + * struct of_irq_domain - Translation domain from device tree to linux irq
> + * @list: Linked list node entry
> + * @match: (optional) Called to determine if the passed device_node
> + *         interrupt-controller can be translated by this irq domain.
> + *         Returns 'true' if it can.
> + * @decode: Translation callback; returns virq, or NO_IRQ if this irq
> + *          domain cannot translate it.
> + * @controller: (optional) pointer to OF node.  By default, if
> + *              'match' is not set, then this of_irq_domain will only
> + *              be used if the device tree node passed in matches the
> + *              controller pointer.
> + * @priv: Private data pointer, not touched by core of_irq_domain code.
> + */
> +struct of_irq_domain {
> +	struct list_head list;
> +	bool (*match)(struct of_irq_domain *d, struct device_node *np);
> +	unsigned int (*map)(struct of_irq_domain *d, struct device_node *np,
> +			    const u32 *intspec, u32 intsize);
> +	struct device_node *controller;
> +	void *priv;
> +};
> +
> +/**
> + * of_irq_domain_add() - Add a device tree interrupt translation domain
> + * @domain: interrupt domain to add.
> + */
> +extern void of_irq_domain_add(struct of_irq_domain *domain);
> +extern void of_irq_set_default_domain(struct of_irq_domain *host);
> +extern struct of_irq_domain *of_irq_domain_find(struct device_node *controller);
> +
>  /*
>   * Workarounds only applied to 32bit powermac machines
>   */

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Heiko Schocher @ 2011-05-03  5:27 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <BANLkTik3L28mmL=LGZ_0nV7vSOX9Miw3ow@mail.gmail.com>

Hello Grant,

Grant Likely wrote:
> On Mon, May 2, 2011 at 4:27 PM, Grant Likely <grant.likely@secretlab.ca> wrote:
>> On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
>>> - add commandline options:
>>>   sm501fb.mode:
>>>     Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>>>   sm501fb.bpp:
>>>     Specify bit-per-pixel if not specified mode
>>>
>>> - Add support for encoding display mode information
>>>   in the device tree using verbatim EDID block.
>>>
>>>   If the "edid" entry in the "smi,sm501" node is present,
>>>   the driver will build mode database using EDID data
>>>   and allow setting the display modes from this database.
>>>
>>> Signed-off-by: Heiko Schocher <hs@denx.de>
>> Merged, thanks.
> 
> This patch causes the following build warning:

Hups ... when I posted the patch, it compiled clean ...

>   MODPOST vmlinux.o
> WARNING: vmlinux.o(.text+0x1d5572): Section mismatch in reference from
> the function sm501fb_init_fb() to the variable
> .devinit.data:sm501_default_mode
> The function sm501fb_init_fb() references
> the variable __devinitdata sm501_default_mode.
> This is often because sm501fb_init_fb lacks a __devinitdata
> annotation or the annotation of sm501_default_mode is wrong.
> 
> WARNING: vmlinux.o(.text+0x1d557a): Section mismatch in reference from
> the function sm501fb_init_fb() to the variable
> .devinit.data:sm501_default_mode
> The function sm501fb_init_fb() references
> the variable __devinitdata sm501_default_mode.
> This is often because sm501fb_init_fb lacks a __devinitdata
> annotation or the annotation of sm501_default_mode is wrong.
> 
> I've dropped the __devinitdata declaration in what I committed; can
> you investigate and post a fixup patch?

Of course, I look ASAP at it, thanks!
(Dummy question: where can I find your tree?)

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Heiko Schocher @ 2011-05-03  5:17 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <20110502221406.GA15043@ponder.secretlab.ca>

Hello Grant,

Grant Likely wrote:
> On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
>> cc: Wolfram Sang <w.sang@pengutronix.de>
>> cc: Grant Likely <grant.likely@secretlab.ca>
>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> cc: linux-fbdev@vger.kernel.org
>> cc: devicetree-discuss@ozlabs.org
>> cc: Ben Dooks <ben@simtec.co.uk>
>> cc: Vincent Sanders <vince@simtec.co.uk>
>> cc: Samuel Ortiz <sameo@linux.intel.com>
>> cc: linux-kernel@vger.kernel.org
>> cc: Randy Dunlap <rdunlap@xenotime.net>
>> cc: Wolfgang Denk <wd@denx.de>
>> cc: Paul Mundt <lethal@linux-sh.org>
>>
>> changes since v5:
>> - repost complete patchseries, as Paul Mundt suggested
>> - rebased against current head
>> - add Acked-by from Samuel Ortiz (MFD parts)
>>   http://www.spinics.net/lists/linux-fbdev/msg02550.html
>>   http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.html
>>
>>   and Benjamin Herrenschmidt (DTS parts)
>>   http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279.html
>> - removed patch 
>>   "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board."
>>   therefore added
>>   "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board."
> 
> Refresh my memory, why was the mpc5200_defconfig updated dropped?

Because it is a board based on the tqm5200 board port ... no other
reason.

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* Re: Login prompt on a video console instead of serial port?
From: Benjamin Herrenschmidt @ 2011-05-03  5:41 UTC (permalink / raw)
  To: Timur Tabi
  Cc: McClintock Matthew-B29882, devicetree-discuss,
	linuxppc-dev@lists.ozlabs.org, linux-fbdev@vger.kernel.org
In-Reply-To: <4DBF0DF1.6050207@freescale.com>

On Mon, 2011-05-02 at 15:02 -0500, Timur Tabi wrote:
> McClintock Matthew-B29882 wrote:
> > Don't you have to spawn a terminal on the framebuffer for the login?
> 
> I suppose, but I don't know how to do that.  And although that would technically
> answer the question in the subject of this thread, I still would have *some*
> boot output on the serial port.  It would be nice if I could get all of stdout
> on the video display, and all of stdin from the serial port.

I don't think we have a way to do that unless you can make a serial
"keyboard" device in the input layer. The VT layer will only get its
input from such a thing, maybe that does exist in the depth of legacy
code in there but it has nothing to do with your device-tree.

> > Right now getty spawns the login on the serial port via /etc/inittab.
> > Something similiar is probably needed for the framebuffer.
> 
> getty appears to work only with serial devices, since it insists on a baud rate
> as one of the parameters.

No, or no existing distro would work :-)

Just fake a baudrate for the tty's

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Grant Likely @ 2011-05-03  5:42 UTC (permalink / raw)
  To: hs
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <4DBF8FF6.8030100@denx.de>

On Mon, May 2, 2011 at 11:17 PM, Heiko Schocher <hs@denx.de> wrote:
> Hello Grant,
>
> Grant Likely wrote:
>> On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
>>> cc: Wolfram Sang <w.sang@pengutronix.de>
>>> cc: Grant Likely <grant.likely@secretlab.ca>
>>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>> cc: linux-fbdev@vger.kernel.org
>>> cc: devicetree-discuss@ozlabs.org
>>> cc: Ben Dooks <ben@simtec.co.uk>
>>> cc: Vincent Sanders <vince@simtec.co.uk>
>>> cc: Samuel Ortiz <sameo@linux.intel.com>
>>> cc: linux-kernel@vger.kernel.org
>>> cc: Randy Dunlap <rdunlap@xenotime.net>
>>> cc: Wolfgang Denk <wd@denx.de>
>>> cc: Paul Mundt <lethal@linux-sh.org>
>>>
>>> changes since v5:
>>> - repost complete patchseries, as Paul Mundt suggested
>>> - rebased against current head
>>> - add Acked-by from Samuel Ortiz (MFD parts)
>>> =A0 http://www.spinics.net/lists/linux-fbdev/msg02550.html
>>> =A0 http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.ht=
ml
>>>
>>> =A0 and Benjamin Herrenschmidt (DTS parts)
>>> =A0 http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279=
.html
>>> - removed patch
>>> =A0 "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board=
."
>>> =A0 therefore added
>>> =A0 "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board=
."
>>
>> Refresh my memory, why was the mpc5200_defconfig updated dropped?
>
> Because it is a board based on the tqm5200 board port ... no other
> reason.

Please send a patch to also update the mpc5200_defconfig.

g.

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Grant Likely @ 2011-05-03  5:43 UTC (permalink / raw)
  To: hs
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <4DBF922F.8040703@denx.de>

On Mon, May 2, 2011 at 11:27 PM, Heiko Schocher <hs@denx.de> wrote:
> Hello Grant,
>
> Grant Likely wrote:
>> On Mon, May 2, 2011 at 4:27 PM, Grant Likely <grant.likely@secretlab.ca>=
 wrote:
>>> On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
>>>> - add commandline options:
>>>> =A0 sm501fb.mode:
>>>> =A0 =A0 Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>>>> =A0 sm501fb.bpp:
>>>> =A0 =A0 Specify bit-per-pixel if not specified mode
>>>>
>>>> - Add support for encoding display mode information
>>>> =A0 in the device tree using verbatim EDID block.
>>>>
>>>> =A0 If the "edid" entry in the "smi,sm501" node is present,
>>>> =A0 the driver will build mode database using EDID data
>>>> =A0 and allow setting the display modes from this database.
>>>>
>>>> Signed-off-by: Heiko Schocher <hs@denx.de>
>>> Merged, thanks.
>>
>> This patch causes the following build warning:
>
> Hups ... when I posted the patch, it compiled clean ...
>
>> =A0 MODPOST vmlinux.o
>> WARNING: vmlinux.o(.text+0x1d5572): Section mismatch in reference from
>> the function sm501fb_init_fb() to the variable
>> .devinit.data:sm501_default_mode
>> The function sm501fb_init_fb() references
>> the variable __devinitdata sm501_default_mode.
>> This is often because sm501fb_init_fb lacks a __devinitdata
>> annotation or the annotation of sm501_default_mode is wrong.
>>
>> WARNING: vmlinux.o(.text+0x1d557a): Section mismatch in reference from
>> the function sm501fb_init_fb() to the variable
>> .devinit.data:sm501_default_mode
>> The function sm501fb_init_fb() references
>> the variable __devinitdata sm501_default_mode.
>> This is often because sm501fb_init_fb lacks a __devinitdata
>> annotation or the annotation of sm501_default_mode is wrong.
>>
>> I've dropped the __devinitdata declaration in what I committed; can
>> you investigate and post a fixup patch?
>
> Of course, I look ASAP at it, thanks!
> (Dummy question: where can I find your tree?)

git://git.secretlab.ca/git/linux-2.6 powerpc/next

g.

>
> bye,
> Heiko
> --
> DENX Software Engineering GmbH, =A0 =A0 MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Anton Blanchard @ 2011-05-03  6:43 UTC (permalink / raw)
  To: benh, tsenglin; +Cc: linuxppc-dev

From: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>

Icswx is a PowerPC instruction to send data to a co-processor. On Book-S
processors the LPAR_ID and process ID (PID) of the owning process are
registered in the window context of the co-processor at initialization
time. When the icswx instruction is executed the L2 generates a cop-reg
transaction on PowerBus. The transaction has no address and the
processor does not perform an MMU access to authenticate the transaction.
The co-processor compares the LPAR_ID and the PID included in the
transaction and the LPAR_ID and PID held in the window context to
determine if the process is authorized to generate the transaction.

The OS needs to assign a 16-bit PID for the process. This cop-PID needs
to be updated during context switch. The cop-PID needs to be destroyed
when the context is destroyed.

Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com>
Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
---

Changes:

- Go back to dynamically allocating the spinlock to avoid the mmu_context.h
  and spinlock_types.h include mess.

Index: linux-powerpc/arch/powerpc/include/asm/cputable.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:21.779140935 +1000
+++ linux-powerpc/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:26.059220272 +1000
@@ -197,6 +197,7 @@ extern const char *powerpc_base_platform
 #define CPU_FTR_STCX_CHECKS_ADDRESS	LONG_ASM_CONST(0x0200000000000000)
 #define CPU_FTR_POPCNTB			LONG_ASM_CONST(0x0400000000000000)
 #define CPU_FTR_POPCNTD			LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_ICSWX			LONG_ASM_CONST(0x1000000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -418,7 +419,8 @@ extern const char *powerpc_base_platform
 	    CPU_FTR_COHERENT_ICACHE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
-	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
+	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+	    CPU_FTR_ICSWX)
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
Index: linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:21.789141120 +1000
+++ linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:26.059220272 +1000
@@ -408,6 +408,7 @@ static inline void subpage_prot_init_new
 #endif /* CONFIG_PPC_SUBPAGE_PROT */
 
 typedef unsigned long mm_context_id_t;
+struct spinlock;
 
 typedef struct {
 	mm_context_id_t id;
@@ -423,6 +424,11 @@ typedef struct {
 #ifdef CONFIG_PPC_SUBPAGE_PROT
 	struct subpage_prot_table spt;
 #endif /* CONFIG_PPC_SUBPAGE_PROT */
+#ifdef CONFIG_PPC_ICSWX
+	struct spinlock *cop_lockp; /* guard acop and cop_pid */
+	unsigned long acop;	/* mask of enabled coprocessor types */
+	unsigned int cop_pid;	/* pid value used with coprocessors */
+#endif /* CONFIG_PPC_ICSWX */
 } mm_context_t;
 
 
Index: linux-powerpc/arch/powerpc/include/asm/mmu_context.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:21.779140935 +1000
+++ linux-powerpc/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:26.059220272 +1000
@@ -32,6 +32,10 @@ extern void __destroy_context(unsigned l
 extern void mmu_context_init(void);
 #endif
 
+extern void switch_cop(struct mm_struct *next);
+extern int use_cop(unsigned long acop, struct mm_struct *mm);
+extern void drop_cop(unsigned long acop, struct mm_struct *mm);
+
 /*
  * switch_mm is the entry point called from the architecture independent
  * code in kernel/sched.c
@@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_s
 	if (prev == next)
 		return;
 
+#ifdef CONFIG_PPC_ICSWX
+	/* Switch coprocessor context only if prev or next uses a coprocessor */
+	if (prev->context.acop || next->context.acop)
+		switch_cop(next);
+#endif /* CONFIG_PPC_ICSWX */
+
 	/* We must stop all altivec streams before changing the HW
 	 * context
 	 */
Index: linux-powerpc/arch/powerpc/include/asm/reg.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:21.799141306 +1000
+++ linux-powerpc/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:26.059220272 +1000
@@ -188,6 +188,7 @@
 
 #define SPRN_CTR	0x009	/* Count Register */
 #define SPRN_DSCR	0x11
+#define SPRN_ACOP	0x1F	/* Available Coprocessor Register */
 #define SPRN_CTRLF	0x088
 #define SPRN_CTRLT	0x098
 #define   CTRL_CT	0xc0000000	/* current thread */
Index: linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c
===================================================================
--- linux-powerpc.orig/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:21.759140565 +1000
+++ linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:26.059220272 +1000
@@ -20,9 +20,205 @@
 #include <linux/idr.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_PPC_ICSWX
+/*
+ * The processor and its L2 cache cause the icswx instruction to
+ * generate a COP_REQ transaction on PowerBus. The transaction has
+ * no address, and the processor does not perform an MMU access
+ * to authenticate the transaction. The command portion of the
+ * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
+ * the coprocessor Process ID (PID), which the coprocessor compares
+ * to the authorized LPID and PID held in the coprocessor, to determine
+ * if the process is authorized to generate the transaction.
+ * The data of the COP_REQ transaction is 128-byte or less and is
+ * placed in cacheable memory on a 128-byte cache line boundary.
+ *
+ * The task to use a coprocessor should use use_cop() to allocate
+ * a coprocessor PID before executing icswx instruction. use_cop()
+ * also enables the coprocessor context switching. Drop_cop() is
+ * used to free the coprocessor PID.
+ *
+ * Example:
+ * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
+ * Each HFI have multiple windows. Each HFI window serves as a
+ * network device sending to and receiving from HFI network.
+ * HFI immediate send function uses icswx instruction. The immediate
+ * send function allows small (single cache-line) packets be sent
+ * without using the regular HFI send FIFO and doorbell, which are
+ * much slower than immediate send.
+ *
+ * For each task intending to use HFI immediate send, the HFI driver
+ * calls use_cop() to obtain a coprocessor PID for the task.
+ * The HFI driver then allocate a free HFI window and save the
+ * coprocessor PID to the HFI window to allow the task to use the
+ * HFI window.
+ *
+ * The HFI driver repeatedly creates immediate send packets and
+ * issues icswx instruction to send data through the HFI window.
+ * The HFI compares the coprocessor PID in the CPU PID register
+ * to the PID held in the HFI window to determine if the transaction
+ * is allowed.
+ *
+ * When the task to release the HFI window, the HFI driver calls
+ * drop_cop() to release the coprocessor PID.
+ */
+
+#define COP_PID_NONE 0
+#define COP_PID_MIN (COP_PID_NONE + 1)
+#define COP_PID_MAX (0xFFFF)
+
+static DEFINE_SPINLOCK(mmu_context_acop_lock);
+static DEFINE_IDA(cop_ida);
+
+void switch_cop(struct mm_struct *next)
+{
+	mtspr(SPRN_PID, next->context.cop_pid);
+	mtspr(SPRN_ACOP, next->context.acop);
+}
+
+static int new_cop_pid(struct ida *ida, int min_id, int max_id,
+		       spinlock_t *lock)
+{
+	int index;
+	int err;
+
+again:
+	if (!ida_pre_get(ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(lock);
+	err = ida_get_new_above(ida, min_id, &index);
+	spin_unlock(lock);
+
+	if (err == -EAGAIN)
+		goto again;
+	else if (err)
+		return err;
+
+	if (index > max_id) {
+		spin_lock(lock);
+		ida_remove(ida, index);
+		spin_unlock(lock);
+		return -ENOMEM;
+	}
+
+	return index;
+}
+
+static void sync_cop(void *arg)
+{
+	struct mm_struct *mm = arg;
+
+	if (mm == current->active_mm)
+		switch_cop(current->active_mm);
+}
+
+/**
+ * Start using a coprocessor.
+ * @acop: mask of coprocessor to be used.
+ * @mm: The mm the coprocessor to associate with. Most likely current mm.
+ *
+ * Return a positive PID if successful. Negative errno otherwise.
+ * The returned PID will be fed to the coprocessor to determine if an
+ * icswx transaction is authenticated.
+ */
+int use_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int ret;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return -ENODEV;
+
+	if (!mm || !acop)
+		return -EINVAL;
+
+	/* We need to make sure mm_users doesn't change */
+	down_read(&mm->mmap_sem);
+	spin_lock(mm->context.cop_lockp);
+
+	if (mm->context.cop_pid == COP_PID_NONE) {
+		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
+				  &mmu_context_acop_lock);
+		if (ret < 0)
+			goto out;
+
+		mm->context.cop_pid = ret;
+	}
+	mm->context.acop |= acop;
+
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+	ret = mm->context.cop_pid;
+
+out:
+	spin_unlock(mm->context.cop_lockp);
+	up_read(&mm->mmap_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(use_cop);
+
+/**
+ * Stop using a coprocessor.
+ * @acop: mask of coprocessor to be stopped.
+ * @mm: The mm the coprocessor associated with.
+ */
+void drop_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int free_pid = COP_PID_NONE;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return;
+
+	if (WARN_ON_ONCE(!mm))
+		return;
+
+	/* We need to make sure mm_users doesn't change */
+	down_read(&mm->mmap_sem);
+	spin_lock(mm->context.cop_lockp);
+
+	mm->context.acop &= ~acop;
+
+	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
+		free_pid = mm->context.cop_pid;
+		mm->context.cop_pid = COP_PID_NONE;
+	}
+
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+	if (free_pid != COP_PID_NONE) {
+		spin_lock(&mmu_context_acop_lock);
+		ida_remove(&cop_ida, free_pid);
+		spin_unlock(&mmu_context_acop_lock);
+	}
+
+	spin_unlock(mm->context.cop_lockp);
+	up_read(&mm->mmap_sem);
+}
+EXPORT_SYMBOL_GPL(drop_cop);
+
+#endif /* CONFIG_PPC_ICSWX */
+
 static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDA(mmu_context_ida);
 
@@ -78,6 +274,16 @@ int init_new_context(struct task_struct
 		slice_set_user_psize(mm, mmu_virtual_psize);
 	subpage_prot_init_new_context(mm);
 	mm->context.id = index;
+#ifdef CONFIG_PPC_ICSWX
+	mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (!mm->context.cop_lockp) {
+		__destroy_context(index);
+		subpage_prot_free(mm);
+		mm->context.id = NO_CONTEXT;
+		return -ENOMEM;
+	}
+	spin_lock_init(mm->context.cop_lockp);
+#endif /* CONFIG_PPC_ICSWX */
 
 	return 0;
 }
@@ -92,6 +298,11 @@ EXPORT_SYMBOL_GPL(__destroy_context);
 
 void destroy_context(struct mm_struct *mm)
 {
+#ifdef CONFIG_PPC_ICSWX
+	drop_cop(mm->context.acop, mm);
+	kfree(mm->context.cop_lockp);
+	mm->context.cop_lockp = NULL;
+#endif /* CONFIG_PPC_ICSWX */
 	__destroy_context(mm->context.id);
 	subpage_prot_free(mm);
 	mm->context.id = MMU_NO_CONTEXT;
Index: linux-powerpc/arch/powerpc/platforms/Kconfig.cputype
===================================================================
--- linux-powerpc.orig/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:21.809141492 +1000
+++ linux-powerpc/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:26.059220272 +1000
@@ -230,6 +230,24 @@ config VSX
 
 	  If in doubt, say Y here.
 
+config PPC_ICSWX
+	bool "Support for PowerPC icswx coprocessor instruction"
+	depends on POWER4
+	default n
+	---help---
+
+	  This option enables kernel support for the PowerPC Initiate
+	  Coprocessor Store Word (icswx) coprocessor instruction on POWER7
+	  or newer processors.
+
+	  This option is only useful if you have a processor that supports
+	  the icswx coprocessor instruction. It does not have any effect
+	  on processors without the icswx coprocessor instruction.
+
+	  This option slightly increases kernel memory usage.
+
+	  If in doubt, say N here.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply

* Re: [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Benjamin Herrenschmidt @ 2011-05-03  6:47 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: tsenglin, linuxppc-dev
In-Reply-To: <20110503164304.7690a1b7@kryten>

On Tue, 2011-05-03 at 16:43 +1000, Anton Blanchard wrote:
> From: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
> 
> Icswx is a PowerPC instruction to send data to a co-processor. On Book-S
> processors the LPAR_ID and process ID (PID) of the owning process are
> registered in the window context of the co-processor at initialization
> time. When the icswx instruction is executed the L2 generates a cop-reg
> transaction on PowerBus. The transaction has no address and the
> processor does not perform an MMU access to authenticate the transaction.
> The co-processor compares the LPAR_ID and the PID included in the
> transaction and the LPAR_ID and PID held in the window context to
> determine if the process is authorized to generate the transaction.
> 
> The OS needs to assign a 16-bit PID for the process. This cop-PID needs
> to be updated during context switch. The cop-PID needs to be destroyed
> when the context is destroyed.

> Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com>
> Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> 
> Changes:
> 
> - Go back to dynamically allocating the spinlock to avoid the mmu_context.h
>   and spinlock_types.h include mess.

My only comment (sorry Anton :-) would have been that we could lazily
allocate the spinlock on the first use_cop() ... or do we have that
potentially called in the wrong context ?

Cheers,
Ben.

> Index: linux-powerpc/arch/powerpc/include/asm/cputable.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:21.779140935 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:26.059220272 +1000
> @@ -197,6 +197,7 @@ extern const char *powerpc_base_platform
>  #define CPU_FTR_STCX_CHECKS_ADDRESS	LONG_ASM_CONST(0x0200000000000000)
>  #define CPU_FTR_POPCNTB			LONG_ASM_CONST(0x0400000000000000)
>  #define CPU_FTR_POPCNTD			LONG_ASM_CONST(0x0800000000000000)
> +#define CPU_FTR_ICSWX			LONG_ASM_CONST(0x1000000000000000)
>  
>  #ifndef __ASSEMBLY__
>  
> @@ -418,7 +419,8 @@ extern const char *powerpc_base_platform
>  	    CPU_FTR_COHERENT_ICACHE | \
>  	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
>  	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
> -	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
> +	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
> +	    CPU_FTR_ICSWX)
>  #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
>  	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
>  	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
> Index: linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:21.789141120 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:26.059220272 +1000
> @@ -408,6 +408,7 @@ static inline void subpage_prot_init_new
>  #endif /* CONFIG_PPC_SUBPAGE_PROT */
>  
>  typedef unsigned long mm_context_id_t;
> +struct spinlock;
>  
>  typedef struct {
>  	mm_context_id_t id;
> @@ -423,6 +424,11 @@ typedef struct {
>  #ifdef CONFIG_PPC_SUBPAGE_PROT
>  	struct subpage_prot_table spt;
>  #endif /* CONFIG_PPC_SUBPAGE_PROT */
> +#ifdef CONFIG_PPC_ICSWX
> +	struct spinlock *cop_lockp; /* guard acop and cop_pid */
> +	unsigned long acop;	/* mask of enabled coprocessor types */
> +	unsigned int cop_pid;	/* pid value used with coprocessors */
> +#endif /* CONFIG_PPC_ICSWX */
>  } mm_context_t;
>  
> 
> Index: linux-powerpc/arch/powerpc/include/asm/mmu_context.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:21.779140935 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:26.059220272 +1000
> @@ -32,6 +32,10 @@ extern void __destroy_context(unsigned l
>  extern void mmu_context_init(void);
>  #endif
>  
> +extern void switch_cop(struct mm_struct *next);
> +extern int use_cop(unsigned long acop, struct mm_struct *mm);
> +extern void drop_cop(unsigned long acop, struct mm_struct *mm);
> +
>  /*
>   * switch_mm is the entry point called from the architecture independent
>   * code in kernel/sched.c
> @@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_s
>  	if (prev == next)
>  		return;
>  
> +#ifdef CONFIG_PPC_ICSWX
> +	/* Switch coprocessor context only if prev or next uses a coprocessor */
> +	if (prev->context.acop || next->context.acop)
> +		switch_cop(next);
> +#endif /* CONFIG_PPC_ICSWX */
> +
>  	/* We must stop all altivec streams before changing the HW
>  	 * context
>  	 */
> Index: linux-powerpc/arch/powerpc/include/asm/reg.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:21.799141306 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:26.059220272 +1000
> @@ -188,6 +188,7 @@
>  
>  #define SPRN_CTR	0x009	/* Count Register */
>  #define SPRN_DSCR	0x11
> +#define SPRN_ACOP	0x1F	/* Available Coprocessor Register */
>  #define SPRN_CTRLF	0x088
>  #define SPRN_CTRLT	0x098
>  #define   CTRL_CT	0xc0000000	/* current thread */
> Index: linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:21.759140565 +1000
> +++ linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:26.059220272 +1000
> @@ -20,9 +20,205 @@
>  #include <linux/idr.h>
>  #include <linux/module.h>
>  #include <linux/gfp.h>
> +#include <linux/slab.h>
>  
>  #include <asm/mmu_context.h>
>  
> +#ifdef CONFIG_PPC_ICSWX
> +/*
> + * The processor and its L2 cache cause the icswx instruction to
> + * generate a COP_REQ transaction on PowerBus. The transaction has
> + * no address, and the processor does not perform an MMU access
> + * to authenticate the transaction. The command portion of the
> + * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> + * the coprocessor Process ID (PID), which the coprocessor compares
> + * to the authorized LPID and PID held in the coprocessor, to determine
> + * if the process is authorized to generate the transaction.
> + * The data of the COP_REQ transaction is 128-byte or less and is
> + * placed in cacheable memory on a 128-byte cache line boundary.
> + *
> + * The task to use a coprocessor should use use_cop() to allocate
> + * a coprocessor PID before executing icswx instruction. use_cop()
> + * also enables the coprocessor context switching. Drop_cop() is
> + * used to free the coprocessor PID.
> + *
> + * Example:
> + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> + * Each HFI have multiple windows. Each HFI window serves as a
> + * network device sending to and receiving from HFI network.
> + * HFI immediate send function uses icswx instruction. The immediate
> + * send function allows small (single cache-line) packets be sent
> + * without using the regular HFI send FIFO and doorbell, which are
> + * much slower than immediate send.
> + *
> + * For each task intending to use HFI immediate send, the HFI driver
> + * calls use_cop() to obtain a coprocessor PID for the task.
> + * The HFI driver then allocate a free HFI window and save the
> + * coprocessor PID to the HFI window to allow the task to use the
> + * HFI window.
> + *
> + * The HFI driver repeatedly creates immediate send packets and
> + * issues icswx instruction to send data through the HFI window.
> + * The HFI compares the coprocessor PID in the CPU PID register
> + * to the PID held in the HFI window to determine if the transaction
> + * is allowed.
> + *
> + * When the task to release the HFI window, the HFI driver calls
> + * drop_cop() to release the coprocessor PID.
> + */
> +
> +#define COP_PID_NONE 0
> +#define COP_PID_MIN (COP_PID_NONE + 1)
> +#define COP_PID_MAX (0xFFFF)
> +
> +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> +static DEFINE_IDA(cop_ida);
> +
> +void switch_cop(struct mm_struct *next)
> +{
> +	mtspr(SPRN_PID, next->context.cop_pid);
> +	mtspr(SPRN_ACOP, next->context.acop);
> +}
> +
> +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> +		       spinlock_t *lock)
> +{
> +	int index;
> +	int err;
> +
> +again:
> +	if (!ida_pre_get(ida, GFP_KERNEL))
> +		return -ENOMEM;
> +
> +	spin_lock(lock);
> +	err = ida_get_new_above(ida, min_id, &index);
> +	spin_unlock(lock);
> +
> +	if (err == -EAGAIN)
> +		goto again;
> +	else if (err)
> +		return err;
> +
> +	if (index > max_id) {
> +		spin_lock(lock);
> +		ida_remove(ida, index);
> +		spin_unlock(lock);
> +		return -ENOMEM;
> +	}
> +
> +	return index;
> +}
> +
> +static void sync_cop(void *arg)
> +{
> +	struct mm_struct *mm = arg;
> +
> +	if (mm == current->active_mm)
> +		switch_cop(current->active_mm);
> +}
> +
> +/**
> + * Start using a coprocessor.
> + * @acop: mask of coprocessor to be used.
> + * @mm: The mm the coprocessor to associate with. Most likely current mm.
> + *
> + * Return a positive PID if successful. Negative errno otherwise.
> + * The returned PID will be fed to the coprocessor to determine if an
> + * icswx transaction is authenticated.
> + */
> +int use_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +	int ret;
> +
> +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> +		return -ENODEV;
> +
> +	if (!mm || !acop)
> +		return -EINVAL;
> +
> +	/* We need to make sure mm_users doesn't change */
> +	down_read(&mm->mmap_sem);
> +	spin_lock(mm->context.cop_lockp);
> +
> +	if (mm->context.cop_pid == COP_PID_NONE) {
> +		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> +				  &mmu_context_acop_lock);
> +		if (ret < 0)
> +			goto out;
> +
> +		mm->context.cop_pid = ret;
> +	}
> +	mm->context.acop |= acop;
> +
> +	sync_cop(mm);
> +
> +	/*
> +	 * If this is a threaded process then there might be other threads
> +	 * running. We need to send an IPI to force them to pick up any
> +	 * change in PID and ACOP.
> +	 */
> +	if (atomic_read(&mm->mm_users) > 1)
> +		smp_call_function(sync_cop, mm, 1);
> +
> +	ret = mm->context.cop_pid;
> +
> +out:
> +	spin_unlock(mm->context.cop_lockp);
> +	up_read(&mm->mmap_sem);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(use_cop);
> +
> +/**
> + * Stop using a coprocessor.
> + * @acop: mask of coprocessor to be stopped.
> + * @mm: The mm the coprocessor associated with.
> + */
> +void drop_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +	int free_pid = COP_PID_NONE;
> +
> +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> +		return;
> +
> +	if (WARN_ON_ONCE(!mm))
> +		return;
> +
> +	/* We need to make sure mm_users doesn't change */
> +	down_read(&mm->mmap_sem);
> +	spin_lock(mm->context.cop_lockp);
> +
> +	mm->context.acop &= ~acop;
> +
> +	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
> +		free_pid = mm->context.cop_pid;
> +		mm->context.cop_pid = COP_PID_NONE;
> +	}
> +
> +	sync_cop(mm);
> +
> +	/*
> +	 * If this is a threaded process then there might be other threads
> +	 * running. We need to send an IPI to force them to pick up any
> +	 * change in PID and ACOP.
> +	 */
> +	if (atomic_read(&mm->mm_users) > 1)
> +		smp_call_function(sync_cop, mm, 1);
> +
> +	if (free_pid != COP_PID_NONE) {
> +		spin_lock(&mmu_context_acop_lock);
> +		ida_remove(&cop_ida, free_pid);
> +		spin_unlock(&mmu_context_acop_lock);
> +	}
> +
> +	spin_unlock(mm->context.cop_lockp);
> +	up_read(&mm->mmap_sem);
> +}
> +EXPORT_SYMBOL_GPL(drop_cop);
> +
> +#endif /* CONFIG_PPC_ICSWX */
> +
>  static DEFINE_SPINLOCK(mmu_context_lock);
>  static DEFINE_IDA(mmu_context_ida);
>  
> @@ -78,6 +274,16 @@ int init_new_context(struct task_struct
>  		slice_set_user_psize(mm, mmu_virtual_psize);
>  	subpage_prot_init_new_context(mm);
>  	mm->context.id = index;
> +#ifdef CONFIG_PPC_ICSWX
> +	mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
> +	if (!mm->context.cop_lockp) {
> +		__destroy_context(index);
> +		subpage_prot_free(mm);
> +		mm->context.id = NO_CONTEXT;
> +		return -ENOMEM;
> +	}
> +	spin_lock_init(mm->context.cop_lockp);
> +#endif /* CONFIG_PPC_ICSWX */
>  
>  	return 0;
>  }
> @@ -92,6 +298,11 @@ EXPORT_SYMBOL_GPL(__destroy_context);
>  
>  void destroy_context(struct mm_struct *mm)
>  {
> +#ifdef CONFIG_PPC_ICSWX
> +	drop_cop(mm->context.acop, mm);
> +	kfree(mm->context.cop_lockp);
> +	mm->context.cop_lockp = NULL;
> +#endif /* CONFIG_PPC_ICSWX */
>  	__destroy_context(mm->context.id);
>  	subpage_prot_free(mm);
>  	mm->context.id = MMU_NO_CONTEXT;
> Index: linux-powerpc/arch/powerpc/platforms/Kconfig.cputype
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:21.809141492 +1000
> +++ linux-powerpc/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:26.059220272 +1000
> @@ -230,6 +230,24 @@ config VSX
>  
>  	  If in doubt, say Y here.
>  
> +config PPC_ICSWX
> +	bool "Support for PowerPC icswx coprocessor instruction"
> +	depends on POWER4
> +	default n
> +	---help---
> +
> +	  This option enables kernel support for the PowerPC Initiate
> +	  Coprocessor Store Word (icswx) coprocessor instruction on POWER7
> +	  or newer processors.
> +
> +	  This option is only useful if you have a processor that supports
> +	  the icswx coprocessor instruction. It does not have any effect
> +	  on processors without the icswx coprocessor instruction.
> +
> +	  This option slightly increases kernel memory usage.
> +
> +	  If in doubt, say N here.
> +
>  config SPE
>  	bool "SPE Support"
>  	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply

* Re: [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Anton Blanchard @ 2011-05-03  6:55 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: tsenglin, linuxppc-dev
In-Reply-To: <1304405237.2513.304.camel@pasglop>


Hi Ben,

> My only comment (sorry Anton :-) would have been that we could lazily
> allocate the spinlock on the first use_cop() ... or do we have that
> potentially called in the wrong context ?

I worry what might happen in a threaded app. It would be a strange
thing to do, but the program may call use_cop from two threads at the
same time. In that case you could corrupt the PID/ACOP values
and leak a spinlock of memory I think.

Anton

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Heiko Schocher @ 2011-05-03  7:24 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <BANLkTimacM29RHExZounuziF+7jARQxdTg@mail.gmail.com>

Hello Grant,

Grant Likely wrote:
> On Mon, May 2, 2011 at 11:17 PM, Heiko Schocher <hs@denx.de> wrote:
>> Hello Grant,
>>
>> Grant Likely wrote:
>>> On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
>>>> cc: Wolfram Sang <w.sang@pengutronix.de>
>>>> cc: Grant Likely <grant.likely@secretlab.ca>
>>>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>>> cc: linux-fbdev@vger.kernel.org
>>>> cc: devicetree-discuss@ozlabs.org
>>>> cc: Ben Dooks <ben@simtec.co.uk>
>>>> cc: Vincent Sanders <vince@simtec.co.uk>
>>>> cc: Samuel Ortiz <sameo@linux.intel.com>
>>>> cc: linux-kernel@vger.kernel.org
>>>> cc: Randy Dunlap <rdunlap@xenotime.net>
>>>> cc: Wolfgang Denk <wd@denx.de>
>>>> cc: Paul Mundt <lethal@linux-sh.org>
>>>>
>>>> changes since v5:
>>>> - repost complete patchseries, as Paul Mundt suggested
>>>> - rebased against current head
>>>> - add Acked-by from Samuel Ortiz (MFD parts)
>>>>   http://www.spinics.net/lists/linux-fbdev/msg02550.html
>>>>   http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.html
>>>>
>>>>   and Benjamin Herrenschmidt (DTS parts)
>>>>   http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279.html
>>>> - removed patch
>>>>   "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board."
>>>>   therefore added
>>>>   "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board."
>>> Refresh my memory, why was the mpc5200_defconfig updated dropped?
>> Because it is a board based on the tqm5200 board port ... no other
>> reason.
> 
> Please send a patch to also update the mpc5200_defconfig.

Ok. Done, just one more question:

Why you didn;t pick up the patches:

- powerpc, 5200: add support for charon board
  (Got an Acked-by from Wolfram Sang)
- powerpc, video: add SM501 support for charon board.

Are there any issues with them, I should fix?

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* Re: [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Benjamin Herrenschmidt @ 2011-05-03  8:57 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: tsenglin, linuxppc-dev
In-Reply-To: <20110503165520.67eab924@kryten>

On Tue, 2011-05-03 at 16:55 +1000, Anton Blanchard wrote:
> Hi Ben,
> 
> > My only comment (sorry Anton :-) would have been that we could lazily
> > allocate the spinlock on the first use_cop() ... or do we have that
> > potentially called in the wrong context ?
> 
> I worry what might happen in a threaded app. It would be a strange
> thing to do, but the program may call use_cop from two threads at the
> same time. In that case you could corrupt the PID/ACOP values
> and leak a spinlock of memory I think.

OK, it's a bit nasty to solve. I'll put the latest patch in my queue and
if all goes well, it should hit next by the end of the week.

Cheers,
Ben.

^ permalink raw reply

* Bootp hangs
From: Guillaume Dargaud @ 2011-05-03 10:12 UTC (permalink / raw)
  To: linuxppc-dev

Hello all,
maybe a bit off topic, more network than kernel, but who knows...
I've had problems booting a new design (ML405 derivative), so I reverted to the old tested one... and it won't boot 
either.
The kernel is in flash and my bootloader puts it in RAM and runs it. The root filesystem  is obtained by NFS, but now it 
hangs:

[...]
[   43.615490] Device Tree Probing 'ethernet'
[   43.619162] xilinx_lltemac 81c00000.ethernet: MAC address is now  0: a:35:72:43: 0
[   43.626002] xilinx_lltemac 81c00000.ethernet: XLlTemac: using DMA mode.
[   43.632799] XLlTemac: Dma base address: phy: 0x84600100, virt: 0xc8020100
[   43.639456] XLlTemac: buffer descriptor size: 32768 (0x8000)
[   43.644843] XLlTemac: Allocating DMA descriptors with kmalloc
[   43.650455] XLlTemac: (buffer_descriptor_init) phy: 0x68b8000, virt: 0xc68b8000, size: 0x8000
[   43.664316] XTemac: PHY detected at address 7.
[   43.670570] xilinx_lltemac 81c00000.ethernet: eth0: Xilinx TEMAC at 0x81C00000 mapped to 0xC801A000, irq=18
[   43.683934] mice: PS/2 mouse device common for all mice
[   43.690323] TCP cubic registered
[   43.692503] NET: Registered protocol family 17
[   44.204479] eth0: XLlTemac: Options: 0x3fa
[   44.207642] eth0: XLlTemac: allocating interrupt 20 for dma mode tx.
[   44.213830] eth0: XLlTemac: allocating interrupt 19 for dma mode rx.
[   46.230373] eth0: XLlTemac: speed set to 1000Mb/s
[   46.233931] eth0: XLlTemac: Send Threshold = 24, Receive Threshold = 4
[   46.240422] eth0: XLlTemac: Send Wait bound = 254, Receive Wait bound = 254
[   47.251413] Sending BOOTP requests .

On the DHCP server this is all I get (which is correct):
May  3 11:58:24 lpsc6186x dhcpd: BOOTREQUEST from 00:0a:35:72:43:00 via eth1
May  3 11:58:24 lpsc6186x dhcpd: BOOTREPLY for 192.168.1.233 to gandalf (00:0a:35:72:43:00) via eth1

After that nothing happens (no new dots after "Sending BOOTP requests ." like when there's no physical connection)

I've tried with 2 different network cards on the server, a crossover cable and 3 switches (10, 100 and 1gbps)
I haven't changed the NFS/DHCP server configuration since it last ran fine.
I haven't updated the system on the server.
I haven't reflashed the kernel on the card.

$ cat /etc/dhcpd.conf:
allow bootp;
allow booting;
ddns-update-style interim;
subnet 192.168.1.0 netmask 255.255.255.0 {
        default-lease-time 21600;
        option routers 192.168.1.185;
        option subnet-mask 255.255.255.0;
        option ntp-servers 192.168.1.185;
#       range dynamic-bootp 192.168.1.128 192.168.1.254;
}
host gandalf {
        hardware ethernet 0:a:35:72:43:0;
        fixed-address 192.168.1.233;
        server-name "192.168.1.185";
        option host-name "gandalf";
        option root-path "192.168.1.185:/media/gandalf,v3,rsize=1024,wsize=1024,proto=udp,nolock,intr";
}


$ cat /etc/sysconfig/dhcpd 
DHCPDARGS=eth1

$ cat /etc/exports
/media/gandalf gandalf(rw,no_root_squash,sync,insecure,fsid=0)


Any idea ?!?
-- 
Guillaume Dargaud
http://www.gdargaud.net/

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Grant Likely @ 2011-05-03 13:22 UTC (permalink / raw)
  To: hs
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <4DBFADBE.5040603@denx.de>

On Tue, May 3, 2011 at 1:24 AM, Heiko Schocher <hs@denx.de> wrote:
>
> Ok. Done, just one more question:
>
> Why you didn;t pick up the patches:
>
> - powerpc, 5200: add support for charon board
> =A0(Got an Acked-by from Wolfram Sang)
> - powerpc, video: add SM501 support for charon board.

I did pick them up and they are in my tree.  Actually, I squashed
those two together since there was no reason to have them split apart.

g.

^ permalink raw reply

* Re: [PATCH 2/2] powerpc: add support for MPIC message register API
From: Scott Wood @ 2011-05-03 15:19 UTC (permalink / raw)
  To: Hollis Blanchard
  Cc: Meador Inge, Wood Scott-B07421,
	devicetree-discuss@lists.ozlabs.org, Kushwaha Prabhakar-B32579,
	openmcapi-dev@googlegroups.com, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4DBED5E9.2070201@mentor.com>

On Mon, 2 May 2011 09:03:53 -0700
Hollis Blanchard <hollis_blanchard@mentor.com> wrote:

> On 05/01/2011 08:41 PM, Kushwaha Prabhakar-B32579 wrote:
> >> Perhaps an allocator could be added in the same patchset that adds such a
> >> user.
> > Yaa. It can be done. Otherwise module has to query each message unit for its availability.
> 
> No, instead the system designer should pick one. If it doesn't matter 
> which one, then the designer is free to pick any.

We should avoid resorting to the notion of a "system designer" if possible
-- it's hard to avoid it when dealing with partitioning, but it shouldn't
be needed for unpartitioned basic driver operation.

> An allocator can't work if you're going to mix drivers. For example, 
> driver A needs MSRG0, and driver B doesn't care. Driver B loads first, 
> the allocator selects MSGR0; driver A loads and fails. Having an 
> allocator at all will create this conflict.

In the absence of partitioning, no driver should need a specific one.  With
partitioning, let the system designer mark those resources as reserved so
they don't get allocated. :-)

-Scott

^ permalink raw reply

* [PATCH] atomic: add *_dec_not_zero
From: Sven Eckelmann @ 2011-05-03 21:30 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arch, linux-mips, linux-m32r, linux-ia64, linux-parisc,
	linux-cris-kernel, linux-s390, linux-sh, x86, Chris Metcalf,
	David Howells, linux-m68k, linux-am33-list, Sven Eckelmann,
	linux-alpha, sparclinux, uclinux-dist-devel, linuxppc-dev,
	linux-arm-kernel

Introduce an *_dec_not_zero operation.  Make this a special case of
*_add_unless because batman-adv uses atomic_dec_not_zero in different
places like re-broadcast queue or aggregation queue management. There
are other non-final patches which may also want to use this macro.

Reported-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: x86@kernel.org
Cc: linux-alpha@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: uclinux-dist-devel@blackfin.uclinux.org
Cc: linux-cris-kernel@axis.com
Cc: linux-ia64@vger.kernel.org
Cc: linux-m32r@ml.linux-m32r.org
Cc: linux-m68k@lists.linux-m68k.org
Cc: linux-mips@linux-mips.org
Cc: linux-am33-list@redhat.com
Cc: linux-parisc@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-s390@vger.kernel.org
Cc: linux-sh@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Cc: linux-arch@vger.kernel.org
---
David S. Miller recommended this change in
 https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2011-May/004560.html

 arch/alpha/include/asm/atomic.h    |    2 ++
 arch/alpha/include/asm/local.h     |    1 +
 arch/arm/include/asm/atomic.h      |    2 ++
 arch/avr32/include/asm/atomic.h    |    1 +
 arch/blackfin/include/asm/atomic.h |    1 +
 arch/cris/include/asm/atomic.h     |    1 +
 arch/frv/include/asm/atomic.h      |    1 +
 arch/h8300/include/asm/atomic.h    |    1 +
 arch/ia64/include/asm/atomic.h     |    2 ++
 arch/m32r/include/asm/atomic.h     |    1 +
 arch/m32r/include/asm/local.h      |    1 +
 arch/m68k/include/asm/atomic.h     |    1 +
 arch/mips/include/asm/atomic.h     |    2 ++
 arch/mips/include/asm/local.h      |    1 +
 arch/mn10300/include/asm/atomic.h  |    1 +
 arch/parisc/include/asm/atomic.h   |    2 ++
 arch/powerpc/include/asm/atomic.h  |    2 ++
 arch/powerpc/include/asm/local.h   |    1 +
 arch/s390/include/asm/atomic.h     |    2 ++
 arch/sh/include/asm/atomic.h       |    1 +
 arch/sparc/include/asm/atomic_32.h |    1 +
 arch/sparc/include/asm/atomic_64.h |    2 ++
 arch/tile/include/asm/atomic.h     |    9 +++++++++
 arch/tile/include/asm/atomic_32.h  |    1 +
 arch/x86/include/asm/atomic.h      |    1 +
 arch/x86/include/asm/atomic64_64.h |    1 +
 arch/xtensa/include/asm/atomic.h   |    1 +
 include/asm-generic/atomic-long.h  |    2 ++
 include/asm-generic/atomic.h       |    1 +
 include/asm-generic/atomic64.h     |    1 +
 include/asm-generic/local.h        |    1 +
 include/asm-generic/local64.h      |    2 ++
 32 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h
index e756d04..7e9434e 100644
--- a/arch/alpha/include/asm/atomic.h
+++ b/arch/alpha/include/asm/atomic.h
@@ -200,6 +200,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /**
  * atomic64_add_unless - add unless the number is a given value
@@ -226,6 +227,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
 #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
diff --git a/arch/alpha/include/asm/local.h b/arch/alpha/include/asm/local.h
index b9e3e33..09fb327 100644
--- a/arch/alpha/include/asm/local.h
+++ b/arch/alpha/include/asm/local.h
@@ -79,6 +79,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
 	c != (u);						\
 })
 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
 
 #define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
 
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 7e79503..a005265 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -218,6 +218,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 	return c != u;
 }
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #define atomic_inc(v)		atomic_add(1, v)
 #define atomic_dec(v)		atomic_sub(1, v)
@@ -459,6 +460,7 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
 #define atomic64_dec_return(v)		atomic64_sub_return(1LL, (v))
 #define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
 #define atomic64_inc_not_zero(v)	atomic64_add_unless((v), 1LL, 0LL)
+#define atomic64_dec_not_zero(v)	atomic64_add_unless((v), -1LL, 0LL)
 
 #else /* !CONFIG_GENERIC_ATOMIC64 */
 #include <asm-generic/atomic64.h>
diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h
index bbce6a1..e6f39c1 100644
--- a/arch/avr32/include/asm/atomic.h
+++ b/arch/avr32/include/asm/atomic.h
@@ -189,6 +189,7 @@ static inline int atomic_sub_if_positive(int i, atomic_t *v)
 #define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0)
 
 #define atomic_inc_not_zero(v)	atomic_add_unless(v, 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
 
 #define smp_mb__before_atomic_dec()	barrier()
diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h
index e485089..900682e 100644
--- a/arch/blackfin/include/asm/atomic.h
+++ b/arch/blackfin/include/asm/atomic.h
@@ -103,6 +103,7 @@ static inline int atomic_test_mask(int mask, atomic_t *v)
 	c != (u);						\
 })
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /*
  * atomic_inc_and_test - increment and test
diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h
index 88dc9b9..9db2767 100644
--- a/arch/cris/include/asm/atomic.h
+++ b/arch/cris/include/asm/atomic.h
@@ -151,6 +151,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 	return ret != u;
 }
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /* Atomic operations are already serializing */
 #define smp_mb__before_atomic_dec()    barrier()
diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h
index fae32c7..90f12a8 100644
--- a/arch/frv/include/asm/atomic.h
+++ b/arch/frv/include/asm/atomic.h
@@ -257,6 +257,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #include <asm-generic/atomic-long.h>
 #endif /* _ASM_ATOMIC_H */
diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h
index 984221a..eda4c8a 100644
--- a/arch/h8300/include/asm/atomic.h
+++ b/arch/h8300/include/asm/atomic.h
@@ -117,6 +117,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 	return ret != u;
 }
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *v)
 {
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h
index 4468814..e2777a9 100644
--- a/arch/ia64/include/asm/atomic.h
+++ b/arch/ia64/include/asm/atomic.h
@@ -106,6 +106,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u)
 {
@@ -123,6 +124,7 @@ static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 #define atomic_add_return(i,v)						\
 ({									\
diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h
index d44a51e..4e0b4ec 100644
--- a/arch/m32r/include/asm/atomic.h
+++ b/arch/m32r/include/asm/atomic.h
@@ -263,6 +263,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 static __inline__ void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
 {
diff --git a/arch/m32r/include/asm/local.h b/arch/m32r/include/asm/local.h
index 734bca8..d536082 100644
--- a/arch/m32r/include/asm/local.h
+++ b/arch/m32r/include/asm/local.h
@@ -272,6 +272,7 @@ static inline int local_add_unless(local_t *l, long a, long u)
 }
 
 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
 
 static inline void local_clear_mask(unsigned long  mask, local_t *addr)
 {
diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h
index 03ae3d1..187a33f 100644
--- a/arch/m68k/include/asm/atomic.h
+++ b/arch/m68k/include/asm/atomic.h
@@ -199,6 +199,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /* Atomic operations are already serializing */
 #define smp_mb__before_atomic_dec()	barrier()
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 4a02fe8..8c4109e 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -326,6 +326,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 	return c != (u);
 }
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #define atomic_dec_return(v) atomic_sub_return(1, (v))
 #define atomic_inc_return(v) atomic_add_return(1, (v))
@@ -698,6 +699,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 #define atomic64_dec_return(v) atomic64_sub_return(1, (v))
 #define atomic64_inc_return(v) atomic64_add_return(1, (v))
diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h
index fffc830..c34d3ca 100644
--- a/arch/mips/include/asm/local.h
+++ b/arch/mips/include/asm/local.h
@@ -137,6 +137,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
 	c != (u);						\
 })
 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
 
 #define local_dec_return(l) local_sub_return(1, (l))
 #define local_inc_return(l) local_add_return(1, (l))
diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h
index 9d773a6..bcad5d1 100644
--- a/arch/mn10300/include/asm/atomic.h
+++ b/arch/mn10300/include/asm/atomic.h
@@ -270,6 +270,7 @@ static inline void atomic_dec(atomic_t *v)
 })
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /**
  * atomic_clear_mask - Atomically clear bits in memory
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index f819559..c2353cf 100644
--- a/arch/parisc/include/asm/atomic.h
+++ b/arch/parisc/include/asm/atomic.h
@@ -221,6 +221,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #define atomic_add(i,v)	((void)(__atomic_add_return( (i),(v))))
 #define atomic_sub(i,v)	((void)(__atomic_add_return(-(i),(v))))
@@ -335,6 +336,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 #else /* CONFIG_64BIT */
 
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index b8f152e..906f49a 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -213,6 +213,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
 #define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
@@ -469,6 +470,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 #else  /* __powerpc64__ */
 #include <asm-generic/atomic64.h>
diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h
index c2410af..3d4c58a 100644
--- a/arch/powerpc/include/asm/local.h
+++ b/arch/powerpc/include/asm/local.h
@@ -134,6 +134,7 @@ static __inline__ int local_add_unless(local_t *l, long a, long u)
 }
 
 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
 
 #define local_sub_and_test(a, l)	(local_sub_return((a), (l)) == 0)
 #define local_dec_and_test(l)		(local_dec_return((l)) == 0)
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index d9db138..09972c3 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -109,6 +109,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #undef __CS_LOOP
 
@@ -326,6 +327,7 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v)
 #define atomic64_dec_return(_v)		atomic64_sub_return(1, _v)
 #define atomic64_dec_and_test(_v)	(atomic64_sub_return(1, _v) == 0)
 #define atomic64_inc_not_zero(v)	atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v)	atomic64_add_unless((v), -1, 0)
 
 #define smp_mb__before_atomic_dec()	smp_mb()
 #define smp_mb__after_atomic_dec()	smp_mb()
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index c798312..848849e 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -31,6 +31,7 @@
 #define atomic_sub_and_test(i,v)	(atomic_sub_return((i), (v)) == 0)
 #define atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
 #define atomic_inc_not_zero(v)		atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v)		atomic_add_unless((v), -1, 0)
 
 #define atomic_inc(v)			atomic_add(1, (v))
 #define atomic_dec(v)			atomic_sub(1, (v))
diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h
index 7ae128b..c7da1e5 100644
--- a/arch/sparc/include/asm/atomic_32.h
+++ b/arch/sparc/include/asm/atomic_32.h
@@ -53,6 +53,7 @@ extern void atomic_set(atomic_t *, int);
 #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /* This is the old 24-bit implementation.  It's still used internally
  * by some sparc-specific code, notably the semaphore implementation.
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h
index bdb2ff8..23ad7cf 100644
--- a/arch/sparc/include/asm/atomic_64.h
+++ b/arch/sparc/include/asm/atomic_64.h
@@ -86,6 +86,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 #define atomic64_cmpxchg(v, o, n) \
 	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
@@ -107,6 +108,7 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 /* Atomic operations are already serializing */
 #define smp_mb__before_atomic_dec()	barrier()
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h
index 75a1602..7fd7be2 100644
--- a/arch/tile/include/asm/atomic.h
+++ b/arch/tile/include/asm/atomic.h
@@ -130,6 +130,15 @@ static inline int atomic_read(const atomic_t *v)
  */
 #define atomic_inc_not_zero(v)		atomic_add_unless((v), 1, 0)
 
+/**
+ * atomic_dec_not_zero - decrement unless the number is zero
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrement @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+#define atomic_dec_not_zero(v)		atomic_add_unless((v), -1, 0)
+
 
 /*
  * We define xchg() and cmpxchg() in the included headers.
diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h
index ed359aee..43137bd 100644
--- a/arch/tile/include/asm/atomic_32.h
+++ b/arch/tile/include/asm/atomic_32.h
@@ -243,6 +243,7 @@ static inline void atomic64_set(atomic64_t *v, u64 n)
 #define atomic64_dec_return(v)		atomic64_sub_return(1LL, (v))
 #define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
 #define atomic64_inc_not_zero(v)	atomic64_add_unless((v), 1LL, 0LL)
+#define atomic64_dec_not_zero(v)	atomic64_add_unless((v), -1LL, 0LL)
 
 /*
  * We need to barrier before modifying the word, since the _atomic_xxx()
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
index 952a826..7102a0b 100644
--- a/arch/x86/include/asm/atomic.h
+++ b/arch/x86/include/asm/atomic.h
@@ -245,6 +245,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 /*
  * atomic_dec_if_positive - decrement by 1 if old value positive
diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h
index 49fd1ea..2cb37f4 100644
--- a/arch/x86/include/asm/atomic64_64.h
+++ b/arch/x86/include/asm/atomic64_64.h
@@ -220,6 +220,7 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
 }
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
 
 /*
  * atomic64_dec_if_positive - decrement by 1 if old value positive
diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h
index a96a061..3b2a7b3 100644
--- a/arch/xtensa/include/asm/atomic.h
+++ b/arch/xtensa/include/asm/atomic.h
@@ -249,6 +249,7 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
index b7babf0..0fe75ab 100644
--- a/include/asm-generic/atomic-long.h
+++ b/include/asm-generic/atomic-long.h
@@ -130,6 +130,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
 }
 
 #define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+#define atomic_long_dec_not_zero(l) atomic64_dec_not_zero((atomic64_t *)(l))
 
 #define atomic_long_cmpxchg(l, old, new) \
 	(atomic64_cmpxchg((atomic64_t *)(l), (old), (new)))
@@ -247,6 +248,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
 }
 
 #define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+#define atomic_long_dec_not_zero(l) atomic_dec_not_zero((atomic_t *)(l))
 
 #define atomic_long_cmpxchg(l, old, new) \
 	(atomic_cmpxchg((atomic_t *)(l), (old), (new)))
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index e994197..4e1d3ef 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -139,6 +139,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 }
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
 
 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 {
diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h
index b18ce4f..f301c46 100644
--- a/include/asm-generic/atomic64.h
+++ b/include/asm-generic/atomic64.h
@@ -38,5 +38,6 @@ extern int	 atomic64_add_unless(atomic64_t *v, long long a, long long u);
 #define atomic64_dec_return(v)		atomic64_sub_return(1LL, (v))
 #define atomic64_dec_and_test(v)	(atomic64_dec_return((v)) == 0)
 #define atomic64_inc_not_zero(v) 	atomic64_add_unless((v), 1LL, 0LL)
+#define atomic64_dec_not_zero(v)	atomic64_add_unless((v), -1LL, 0LL)
 
 #endif  /*  _ASM_GENERIC_ATOMIC64_H  */
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h
index c8a5d68..82ef01f 100644
--- a/include/asm-generic/local.h
+++ b/include/asm-generic/local.h
@@ -44,6 +44,7 @@ typedef struct
 #define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n))
 #define local_add_unless(l, _a, u) atomic_long_add_unless((&(l)->a), (_a), (u))
 #define local_inc_not_zero(l) atomic_long_inc_not_zero(&(l)->a)
+#define local_dec_not_zero(l) atomic_long_dec_not_zero(&(l)->a)
 
 /* Non-atomic variants, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well. */
diff --git a/include/asm-generic/local64.h b/include/asm-generic/local64.h
index 02ac760..aa3a841 100644
--- a/include/asm-generic/local64.h
+++ b/include/asm-generic/local64.h
@@ -45,6 +45,7 @@ typedef struct {
 #define local64_xchg(l, n)	local_xchg((&(l)->a), (n))
 #define local64_add_unless(l, _a, u) local_add_unless((&(l)->a), (_a), (u))
 #define local64_inc_not_zero(l)	local_inc_not_zero(&(l)->a)
+#define local64_dec_not_zero(l)	local_dec_not_zero(&(l)->a)
 
 /* Non-atomic variants, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well. */
@@ -83,6 +84,7 @@ typedef struct {
 #define local64_xchg(l, n)	atomic64_xchg((&(l)->a), (n))
 #define local64_add_unless(l, _a, u) atomic64_add_unless((&(l)->a), (_a), (u))
 #define local64_inc_not_zero(l)	atomic64_inc_not_zero(&(l)->a)
+#define local64_dec_not_zero(l)	atomic64_dec_not_zero(&(l)->a)
 
 /* Non-atomic variants, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well. */
-- 
1.7.4.4

^ permalink raw reply related


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