LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 03/21]arch:powerpc:eeh.c remove one to many l's in the word.
From: Justin P. Mattock @ 2011-02-25  6:10 UTC (permalink / raw)
  To: trivial; +Cc: paulus, linuxppc-dev, Justin P. Mattock, linux-kernel

The patch below removes an extra "l" in the word.

Signed-off-by: Justin P. Mattock <justinmattock@gmail.com>

---
 arch/powerpc/platforms/pseries/eeh.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 17a11c8..3cc4d10 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -876,7 +876,7 @@ void eeh_restore_bars(struct pci_dn *pdn)
  *
  * Save the values of the device bars. Unlike the restore
  * routine, this routine is *not* recursive. This is because
- * PCI devices are added individuallly; but, for the restore,
+ * PCI devices are added individually; but, for the restore,
  * an entire slot is reset at a time.
  */
 static void eeh_save_bars(struct pci_dn *pdn)
-- 
1.7.4.1

^ permalink raw reply related

* RE: Open Firmware and interrupt trigger
From: Robert Thorhuus @ 2011-02-25  7:29 UTC (permalink / raw)
  To: avorontsov@mvista.com; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1298580418.8833.428.camel@pasglop>

Thank you Benjamin!

Sorry for not using your qouting schema :(

Benjamin, you are right about the IRQ flags. Those interrupt.h flags seems =
to differ from my processor reference manual.

None the less. Antov, I saw that the code snippet I refer to below:

> 	ret =3D of_irq_to_resource(dn, 0, &irq_res);
> 	if (ret =3D=3D NO_IRQ)
> 		irq_res.start =3D irq_res.end =3D 0;
> 	else
> 		irq_res.flags =3D 0;

, originates from the first version of the file pata_of_platform.c and you =
are the creator :)
Could you explain the hardcoded ".flags =3D 0" part?=20
Looking amatuer-vise in the code it seems that the only thing one is able t=
o control (through Device Tree) regarding interrupts and pata, is the actua=
l IRQ number. Is this a correct assumption?

Thanks
BR
Robert


-----Original Message-----
From: Benjamin Herrenschmidt [mailto:benh@kernel.crashing.org]=20
Sent: den 24 februari 2011 21:47
To: Robert Thorhuus
Cc: linuxppc-dev@lists.ozlabs.org
Subject: Re: Open Firmware and interrupt trigger

On Wed, 2011-02-23 at 22:18 +0100, Robert Thorhuus wrote:
> Hello!
>=20
> I'm quite new to linux and Open Firmware.
>=20
> I have a PPC processor. To this I have a Compact Flash connected. The Com=
pact Flash is using external interrupt 0 of the processor.
> In my DTS file I have specified a Compact Flash node and within it I have=
 an interrupt element:
> interrupt =3D <0 2 0 0>;
>=20
> Here I thought the first number was the ID of the interrupt and the secon=
d one should be a number indicating how the interrupt is triggered (high, l=
ow, raising, falling).
>=20
> The interrupt is active low.
>=20
> But I could not get it to work which ever value I chose.
>=20
> Looking in the code I found this in function __devinit pata_of_platform_p=
robe in file pata_of_platform.c:
>=20
> 	ret =3D of_irq_to_resource(dn, 0, &irq_res);
> 	if (ret =3D=3D NO_IRQ)
> 		irq_res.start =3D irq_res.end =3D 0;
> 	else
> 		irq_res.flags =3D 0;
>=20
> Here "flags" will be zero whatever I do in the DTS. As far as I can under=
stand the flags are defined in interrupts.h:
> #define IRQF_TRIGGER_NONE       0x00000000
> #define IRQF_TRIGGER_RISING     0x00000001
> #define IRQF_TRIGGER_FALLING    0x00000002
> #define IRQF_TRIGGER_HIGH       0x00000004
> #define IRQF_TRIGGER_LOW        0x00000008

Actually, the .dts flags depend on the specific interrupt controller you ar=
e using. For example, MPIC uses a different mapping scheme (for historical =
reasons). Check booting-without-of.txt.

> So modifying the code to:
> 	else
> 		irq_res.flags =3D 2;
>=20
> I get it to work.
>=20
> Could someone please explain to me why the "flags" parameter is hardcoded=
 zero or just point in a good direction.

That does indeed look odd. Might be worth trying to figure out with the git=
 history who came up with that code in the first place and ask that person.=
 Without answer, I think it's valid to patch that out.

Cheers,
Ben.

> Thank you
>=20
> BR
> Robert
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* Re: [PATCH V11 2/4] ptp: Added a clock that uses the eTSEC found on the MPC85xx.
From: Richard Cochran @ 2011-02-25  7:53 UTC (permalink / raw)
  To: Scott Wood
  Cc: John Stultz, Christoph Lameter, Russell King, Rodolfo Giometti,
	Arnd Bergmann, Peter Zijlstra, linux-api, devicetree-discuss,
	linux-kernel, Paul Mackerras, Alan Cox, netdev, Mike Frysinger,
	Thomas Gleixner, linuxppc-dev, David Miller, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <20110224112731.2d9bf080@schlenkerla>

On Thu, Feb 24, 2011 at 11:27:31AM -0600, Scott Wood wrote:

> My vote, if it goes in a separate node at all, is "fsl,etsec-ptp",

So, that is what the patch does.

> and let the driver use SVR.

What is SVR?

Thanks,
Richard

^ permalink raw reply

* RE: Open Firmware and interrupt trigger
From: Benjamin Herrenschmidt @ 2011-02-25  8:47 UTC (permalink / raw)
  To: Robert Thorhuus; +Cc: avorontsov@mvista.com, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <9081694521850B4D91387C8C2E612B591062A0DD26@ESESSCMS0361.eemea.ericsson.se>

On Fri, 2011-02-25 at 08:29 +0100, Robert Thorhuus wrote:
> Thank you Benjamin!
> 
> Sorry for not using your qouting schema :(
> 
> Benjamin, you are right about the IRQ flags. Those interrupt.h flags
> seems to differ from my processor reference manual.

Check the bindings or the driver. IE. What interrupt controller does
your board/processor use ? Use the flags defined by the device-tree
bindings for that controller.

> None the less. Antov, I saw that the code snippet I refer to below:
> 
> > 	ret = of_irq_to_resource(dn, 0, &irq_res);
> > 	if (ret == NO_IRQ)
> > 		irq_res.start = irq_res.end = 0;
> > 	else
> > 		irq_res.flags = 0;
> 
> , originates from the first version of the file pata_of_platform.c and
> you are the creator :)

I don't think so :-)

>From the git commit logs:

Author: Anton Vorontsov <avorontsov@ru.mvista.com>  2008-01-10 06:10:41
Committer: Olof Johansson <olof@lixom.net>  2008-01-16 03:23:43

> Could you explain the hardcoded ".flags = 0" part? 
> Looking amatuer-vise in the code it seems that the only thing one is
> able to control (through Device Tree) regarding interrupts and pata,
> is the actual IRQ number. Is this a correct assumption?

I think the trick is that of_irq_to_resource() will establish the right
trigger settings already, so the flags might not be relevant from a
driver standpoint. 0 means use the default as established by
of_irq_to_resource() when it creates the interrupt mapping for that
interrupt.

I suspect the problem might be the value in your device-tree being
incorrect. You need to dbl check the binding (ie. the definition of that
value for your specific type of interrupt controller). You won't find
that in the processor documentation but rather in the binding document
describing the way that interrupt controller is represented in a
device-tree.

Tell us what the interrupt controller is (what your platform/processor
is) and we should be able to help you get it right.

Cheers,
Ben.

> Thanks
> BR
> Robert
> 
> 
> -----Original Message-----
> From: Benjamin Herrenschmidt [mailto:benh@kernel.crashing.org] 
> Sent: den 24 februari 2011 21:47
> To: Robert Thorhuus
> Cc: linuxppc-dev@lists.ozlabs.org
> Subject: Re: Open Firmware and interrupt trigger
> 
> On Wed, 2011-02-23 at 22:18 +0100, Robert Thorhuus wrote:
> > Hello!
> > 
> > I'm quite new to linux and Open Firmware.
> > 
> > I have a PPC processor. To this I have a Compact Flash connected.
> The Compact Flash is using external interrupt 0 of the processor.
> > In my DTS file I have specified a Compact Flash node and within it I
> have an interrupt element:
> > interrupt = <0 2 0 0>;
> > 
> > Here I thought the first number was the ID of the interrupt and the
> second one should be a number indicating how the interrupt is
> triggered (high, low, raising, falling).
> > 
> > The interrupt is active low.
> > 
> > But I could not get it to work which ever value I chose.
> > 
> > Looking in the code I found this in function __devinit
> pata_of_platform_probe in file pata_of_platform.c:
> > 
> > 	ret = of_irq_to_resource(dn, 0, &irq_res);
> > 	if (ret == NO_IRQ)
> > 		irq_res.start = irq_res.end = 0;
> > 	else
> > 		irq_res.flags = 0;
> > 
> > Here "flags" will be zero whatever I do in the DTS. As far as I can
> understand the flags are defined in interrupts.h:
> > #define IRQF_TRIGGER_NONE       0x00000000
> > #define IRQF_TRIGGER_RISING     0x00000001
> > #define IRQF_TRIGGER_FALLING    0x00000002
> > #define IRQF_TRIGGER_HIGH       0x00000004
> > #define IRQF_TRIGGER_LOW        0x00000008
> 
> Actually, the .dts flags depend on the specific interrupt controller
> you are using. For example, MPIC uses a different mapping scheme (for
> historical reasons). Check booting-without-of.txt.
> 
> > So modifying the code to:
> > 	else
> > 		irq_res.flags = 2;
> > 
> > I get it to work.
> > 
> > Could someone please explain to me why the "flags" parameter is
> hardcoded zero or just point in a good direction.
> 
> That does indeed look odd. Might be worth trying to figure out with
> the git history who came up with that code in the first place and ask
> that person. Without answer, I think it's valid to patch that out.
> 
> Cheers,
> Ben.
> 
> > Thank you
> > 
> > BR
> > Robert
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/linuxppc-dev
> 

^ permalink raw reply

* Re: [RFC PATCH 01/15] dt/powerpc: move of_bus_type infrastructure to ibmebus
From: Benjamin Herrenschmidt @ 2011-02-25  8:53 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: sfr, devicetree-discuss, linux-kernel, sparclinux, linuxppc-dev,
	davem
In-Reply-To: <201102241546.48790.arnd@arndb.de>

On Thu, 2011-02-24 at 15:46 +0100, Arnd Bergmann wrote:
> On Wednesday 23 February 2011, Grant Likely wrote:
> > arch/powerpc/kernel/ibmebus.c is the only remaining user of the
> > of_bus_type support code for initializing the bus and registering
> > drivers.  All others have either been switched to the vanilla platform
> > bus or already have their own infrastructure.
> > 
> > This patch moves the functionality that ibmebus is using out of
> > drivers/of/{platform,device}.c and into ibmebus.c where it is actually
> > used.  Also renames the moved symbols from of_platform_* to
> > ibmebus_bus_* to reflect the actual usage.
> > 
> > This patch is part of moving all of the of_platform_bus_type users
> > over to the platform_bus_type.
> > 
> > Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> 
> The ibmebus is essentially the platform bus of the IBM Power Systems (a.k.a.
> pSeries a.k.a. System p), I think it would make a lot of sense to convert
> the two drivers (ehca and ehea) on this bus into platform drivers as well.
> 
> The original reason for this bus was to provide a different IOMMU for them
> than what is used on the PCI devices. This should now be possible in simpler
> ways.

Well, it's really the IBM "GX" bus but yeah, it could be converted I
suppose. The "special" iommu functions mostly derive from the fact that
the two adapters we are interested in have their own translation
mechanism built-in. The GX bus sits "above" the TCEs used as an iommu on
these systems.

> > +static void ibmebus_bus_device_shutdown(struct device *dev)
> > +{
> > +	struct platform_device *of_dev = to_platform_device(dev);
> > +	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
> > +
> > +	if (dev->driver && drv->shutdown)
> > +		drv->shutdown(of_dev);
> > +}
> 
> neither of the drivers provides a shutdown function.

Right but they might grow one ... and people will wonder why it doesn't
work if you remove the above :-)

 .../...

> These are also unused in the drivers.

Same reasoning, however it becomes moot if we convert them to platform.

Cheers,
Ben.

^ permalink raw reply

* Re: Resources used by driver ?
From: Guillaume Dargaud @ 2011-02-25 13:01 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <AANLkTin9zsXJX0QrJ2cAZJjAdbGYnQ-S4QCdpzEbrUF_@mail.gmail.com>

On Wednesday 16 February 2011 08:01:10 Srivatsan S wrote:
> You can use oprofile to profile the functions of your module. Follow the
> link.
> http://oprofile.sourceforge.net/ <http://oprofile.sourceforge.net/news/>

OK, after some wrestling, I got oprofile installed in my OS (buildroot 2011.02-
rc1) and my kernel (xilinx patches 2.6.35+).

When I start oprofile, I get the following:
# opcontrol --vmlinux=/vmlinux
The specified file /vmlinux does not seem to be valid
Make sure you are using the non-compressed image file (e.g. vmlinux not 
vmlinuz)

# file /vmlinux
/vmlinux: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), 
statically linked, with unknown capability 0x41000000 = 0x11676e75, with 
unknown capability 0x10000 = 0x90402, not stripped

I used the vmlinux generated found in ../linus-2.6-xlnx/vmlinux
What's wrong with it ?
-- 
Guillaume Dargaud
http://www.gdargaud.net/

^ permalink raw reply

* Re: Resources used by driver ?
From: Guillaume Dargaud @ 2011-02-25 14:18 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <201102251401.33063.dargaud@lpsc.in2p3.fr>

> When I start oprofile, I get the following:
> # opcontrol --vmlinux=/vmlinux
> The specified file /vmlinux does not seem to be valid
> Make sure you are using the non-compressed image file (e.g. vmlinux not
> vmlinuz)

Sorry, I had an incomplete install of objdump/binutils on my target. I'm now 
trying to understand how to use oprofile.
-- 
Guillaume Dargaud
http://www.gdargaud.net/

^ permalink raw reply

* RE: [RFC PATCH 06/15] dt: xilinx_hwicap: merge platform and of_platformdriver bindings
From: Stephen Neuendorffer @ 2011-02-25 18:25 UTC (permalink / raw)
  To: Grant Likely, Benjamin Herrenschmidt, devicetree-discuss, sfr,
	linux-kernel, davem
  Cc: sparclinux, linuxppc-dev
In-Reply-To: <20110223043405.20795.19903.stgit@localhost6.localdomain6>

Minor nit below

Acked-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>

Steve

> -----Original Message-----
> From: linuxppc-dev-bounces+stephen=3Dneuendorffer.name@lists.ozlabs.org
[mailto:linuxppc-dev-
> bounces+stephen=3Dneuendorffer.name@lists.ozlabs.org] On Behalf Of Grant
Likely
> Sent: Tuesday, February 22, 2011 8:34 PM
> To: Benjamin Herrenschmidt; devicetree-discuss@lists.ozlabs.org;
sfr@canb.auug.org.au; linux-
> kernel@vger.kernel.org; davem@davemloft.net
> Cc: sparclinux@vger.kernel.org; linuxppc-dev@lists.ozlabs.org
> Subject: [RFC PATCH 06/15] dt: xilinx_hwicap: merge platform and
of_platformdriver bindings
> =

> of_platform_driver is getting removed, and a single platform_driver
> can now support both devicetree and non-devicetree use cases.  This
> patch merges the two driver registrations.
> =

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  drivers/char/xilinx_hwicap/xilinx_hwicap.c |  129
+++++++++++-----------------
>  1 files changed, 49 insertions(+), 80 deletions(-)
> =

> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> index 9f2272e..a55e877 100644
> --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> @@ -714,20 +714,29 @@ static int __devexit hwicap_remove(struct device
*dev)
>  	return 0;		/* success */
>  }
> =

> -static int __devinit hwicap_drv_probe(struct platform_device *pdev)
> +#ifdef CONFIG_OF
> +static int __devinit hwicap_of_probe(struct platform_device *op)
>  {
> -	struct resource *res;
> -	const struct config_registers *regs;
> +	struct resource res;
> +	const unsigned int *id;
>  	const char *family;
> +	int rc;
> +	const struct hwicap_driver_config *config =3D
op->dev.of_match->data;
> +	const struct config_registers *regs;
> =

> -	res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
> -	if (!res)
> -		return -ENODEV;
> +
> +	rc =3D of_address_to_resource(op->dev.of_node, 0, &res);
> +	if (rc) {
> +		dev_err(&op->dev, "invalid address\n");
> +		return rc;
> +	}
> +
> +	id =3D of_get_property(op->dev.of_node, "port-number", NULL);
> =

>  	/* It's most likely that we're using V4, if the family is not
>  	   specified */
>  	regs =3D &v4_config_registers;
> -	family =3D pdev->dev.platform_data;
> +	family =3D of_get_property(op->dev.of_node, "xlnx,family", NULL);
> =

>  	if (family) {
>  		if (!strcmp(family, "virtex2p")) {
> @@ -738,54 +747,33 @@ static int __devinit hwicap_drv_probe(struct
platform_device *pdev)
>  			regs =3D &v5_config_registers;
>  		}
>  	}
> -
> -	return hwicap_setup(&pdev->dev, pdev->id, res,
> -			&buffer_icap_config, regs);
> +	return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
> +			regs);
>  }
> -
> -static int __devexit hwicap_drv_remove(struct platform_device *pdev)
> +#else
> +static inline int hwicap_of_probe(struct platform_device *op)
>  {
> -	return hwicap_remove(&pdev->dev);
> +	return -EINVAL;
>  }
> +#endif /* CONFIG_OF */
> =

> -static struct platform_driver hwicap_platform_driver =3D {
> -	.probe =3D hwicap_drv_probe,
> -	.remove =3D hwicap_drv_remove,
> -	.driver =3D {
> -		.owner =3D THIS_MODULE,
> -		.name =3D DRIVER_NAME,
> -	},
> -};
> -
> -/*
---------------------------------------------------------------------
> - * OF bus binding
> - */
> -
> -#if defined(CONFIG_OF)
> -static int __devinit
> -hwicap_of_probe(struct platform_device *op, const struct of_device_id
*match)
> +static int __devinit hwicap_drv_probe(struct platform_device *pdev)
>  {
> -	struct resource res;
> -	const unsigned int *id;
> -	const char *family;
> -	int rc;
> -	const struct hwicap_driver_config *config =3D match->data;
> +	struct resource *res;
>  	const struct config_registers *regs;
> +	const char *family;
> =

> -	dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);
> -
> -	rc =3D of_address_to_resource(op->dev.of_node, 0, &res);
> -	if (rc) {
> -		dev_err(&op->dev, "invalid address\n");
> -		return rc;
> -	}
> +	if (pdev->dev.of_match)
> +		return hwicap_of_probe(pdev);
> =

> -	id =3D of_get_property(op->dev.of_node, "port-number", NULL);
> +	res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> =

>  	/* It's most likely that we're using V4, if the family is not
>  	   specified */
>  	regs =3D &v4_config_registers;
> -	family =3D of_get_property(op->dev.of_node, "xlnx,family", NULL);
> +	family =3D pdev->dev.platform_data;
> =

>  	if (family) {
>  		if (!strcmp(family, "virtex2p")) {
> @@ -796,15 +784,17 @@ hwicap_of_probe(struct platform_device *op,
const struct of_device_id *match)
>  			regs =3D &v5_config_registers;
>  		}
>  	}
> -	return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
> -			regs);
> +
> +	return hwicap_setup(&pdev->dev, pdev->id, res,
> +			&buffer_icap_config, regs);
>  }
> =

> -static int __devexit hwicap_of_remove(struct platform_device *op)
> +static int __devexit hwicap_drv_remove(struct platform_device *pdev)
>  {
> -	return hwicap_remove(&op->dev);
> +	return hwicap_remove(&pdev->dev);
>  }
> =

> +#ifdef CONFIG_OF
>  /* Match table for of_platform binding */

Does the comment still make sense?

>  static const struct of_device_id __devinitconst hwicap_of_match[] =3D {
>  	{ .compatible =3D "xlnx,opb-hwicap-1.00.b", .data =3D
&buffer_icap_config},
> @@ -812,33 +802,23 @@ static const struct of_device_id __devinitconst
hwicap_of_match[] =3D {
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, hwicap_of_match);
> +#else
> +#define hwicap_of_match NULL
> +#endif
> =

> -static struct of_platform_driver hwicap_of_driver =3D {
> -	.probe =3D hwicap_of_probe,
> -	.remove =3D __devexit_p(hwicap_of_remove),
> +static struct platform_driver hwicap_platform_driver =3D {
> +	.probe =3D hwicap_drv_probe,
> +	.remove =3D hwicap_drv_remove,
>  	.driver =3D {
> -		.name =3D DRIVER_NAME,
>  		.owner =3D THIS_MODULE,
> +		.name =3D DRIVER_NAME,
>  		.of_match_table =3D hwicap_of_match,
>  	},
>  };
> =

> -/* Registration helpers to keep the number of #ifdefs to a minimum */
> -static inline int __init hwicap_of_register(void)
> -{
> -	pr_debug("hwicap: calling of_register_platform_driver()\n");
> -	return of_register_platform_driver(&hwicap_of_driver);
> -}
> -
> -static inline void __exit hwicap_of_unregister(void)
> -{
> -	of_unregister_platform_driver(&hwicap_of_driver);
> -}
> -#else /* CONFIG_OF */
> -/* CONFIG_OF not enabled; do nothing helpers */
> -static inline int __init hwicap_of_register(void) { return 0; }
> -static inline void __exit hwicap_of_unregister(void) { }
> -#endif /* CONFIG_OF */
> +/*
---------------------------------------------------------------------
> + * OF bus binding
> + */
> =

>  static int __init hwicap_module_init(void)
>  {
> @@ -856,21 +836,12 @@ static int __init hwicap_module_init(void)
>  		return retval;
> =

>  	retval =3D platform_driver_register(&hwicap_platform_driver);
> -
> -	if (retval)
> -		goto failed1;
> -
> -	retval =3D hwicap_of_register();
> -
>  	if (retval)
> -		goto failed2;
> +		goto failed;
> =

>  	return retval;
> =

> - failed2:
> -	platform_driver_unregister(&hwicap_platform_driver);
> -
> - failed1:
> + failed:
>  	unregister_chrdev_region(devt, HWICAP_DEVICES);
> =

>  	return retval;
> @@ -884,8 +855,6 @@ static void __exit hwicap_module_cleanup(void)
> =

>  	platform_driver_unregister(&hwicap_platform_driver);
> =

> -	hwicap_of_unregister();
> -
>  	unregister_chrdev_region(devt, HWICAP_DEVICES);
>  }
> =

> =

> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* [PATCH] rapidio: Fix sysfs config attribute to access 16MB of maint space
From: Alexandre Bounine @ 2011-02-25 18:26 UTC (permalink / raw)
  To: akpm, linux-kernel, linuxppc-dev; +Cc: Alexandre Bounine, Thomas Moll
In-Reply-To: <1298658385-9842-1-git-send-email-alexandre.bounine@idt.com>

Fixes sysfs config attribute to allow access to entire 16MB maintenance
space of RapidIO devices.

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Li Yang <leoli@freescale.com>
Cc: Thomas Moll <thomas.moll@sysgo.com>
Cc: Micha Nelissen <micha@neli.hopto.org>
---
 drivers/rapidio/rio-sysfs.c |   12 ++++++------
 include/linux/rio_regs.h    |    4 +++-
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index e3ebfec..c04dbc7 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -78,9 +78,9 @@ rio_read_config(struct file *filp, struct kobject *kobj,
 
 	/* Several chips lock up trying to read undefined config space */
 	if (capable(CAP_SYS_ADMIN))
-		size = 0x200000;
+		size = RIO_MAINT_SPACE_SZ;
 
-	if (off > size)
+	if (off >= size)
 		return 0;
 	if (off + count > size) {
 		size -= off;
@@ -148,10 +148,10 @@ rio_write_config(struct file *filp, struct kobject *kobj,
 	loff_t init_off = off;
 	u8 *data = (u8 *) buf;
 
-	if (off > 0x200000)
+	if (off >= RIO_MAINT_SPACE_SZ)
 		return 0;
-	if (off + count > 0x200000) {
-		size = 0x200000 - off;
+	if (off + count > RIO_MAINT_SPACE_SZ) {
+		size = RIO_MAINT_SPACE_SZ - off;
 		count = size;
 	}
 
@@ -201,7 +201,7 @@ static struct bin_attribute rio_config_attr = {
 		 .name = "config",
 		 .mode = S_IRUGO | S_IWUSR,
 		 },
-	.size = 0x200000,
+	.size = RIO_MAINT_SPACE_SZ,
 	.read = rio_read_config,
 	.write = rio_write_config,
 };
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index d63dcba..9026b30 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -14,10 +14,12 @@
 #define LINUX_RIO_REGS_H
 
 /*
- * In RapidIO, each device has a 2MB configuration space that is
+ * In RapidIO, each device has a 16MB configuration space that is
  * accessed via maintenance transactions.  Portions of configuration
  * space are standardized and/or reserved.
  */
+#define RIO_MAINT_SPACE_SZ	0x1000000 /* 16MB of RapidIO mainenance space */
+
 #define RIO_DEV_ID_CAR		0x00	/* [I] Device Identity CAR */
 #define RIO_DEV_INFO_CAR	0x04	/* [I] Device Information CAR */
 #define RIO_ASM_ID_CAR		0x08	/* [I] Assembly Identity CAR */
-- 
1.7.3.1

^ permalink raw reply related

* [PATCH -mm V2] rapidio: Add new sysfs attributes
From: Alexandre Bounine @ 2011-02-25 18:26 UTC (permalink / raw)
  To: akpm, linux-kernel, linuxppc-dev; +Cc: Alexandre Bounine, Thomas Moll

Add new sysfs attributes.

1. Routing information required to to reach the RIO device:
destid - device destination ID (real for for endpoint, route for switch)
hopcount - hopcount for maintenance requests (switches only)

2. device linking information:
lprev - name of device that precedes the given device in the enumeration
        or discovery order (displayed along with of the port to which it
        is attached).
lnext - names of devices (with corresponding port numbers) that are
        attached to the given device as next in the enumeration or
        discovery order (switches only)

Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Li Yang <leoli@freescale.com>
Cc: Thomas Moll <thomas.moll@sysgo.com>
Cc: Micha Nelissen <micha@neli.hopto.org>
---
 Documentation/rapidio/sysfs.txt |   17 +++++++++++++--
 drivers/rapidio/rio-sysfs.c     |   41 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/Documentation/rapidio/sysfs.txt b/Documentation/rapidio/sysfs.txt
index d6d986e..97f71ce 100755
--- a/Documentation/rapidio/sysfs.txt
+++ b/Documentation/rapidio/sysfs.txt
@@ -36,6 +36,10 @@ device_rev - returns the device revision level
    asm_did - returns identifier for the assembly containing the device
    asm_rev - returns revision level of the assembly containing the device
    asm_vid - returns vendor identifier of the assembly containing the device
+   destid  - returns device destination ID assigned by the enumeration routine
+             (see 4.1 for switch specific details)
+   lprev   - returns name of previous device (switch) on the path to the device
+             that that owns this attribute
 
 In addition to the files listed above, each device has a binary attribute file
 that allows read/write access to the device configuration registers using
@@ -66,9 +70,16 @@ set by the switch initialization routine during enumeration or discovery process
 
 4.1 Common Switch Attributes
 
- routes - reports switch routing information in "destID port" format. This
-          attribute reports only valid routing table entries, one line for
-          each entry.
+   routes - reports switch routing information in "destID port" format. This
+            attribute reports only valid routing table entries, one line for
+            each entry.
+   destid - device destination ID that defines a route to the switch
+ hopcount - number of hops on the path to the switch
+    lnext - returns names of devices linked to the switch except one of a device
+            linked to the ingress port (reported as "lprev"). This is an array
+            names with number of lines equal to number of ports in switch. If
+            a switch port has no attached device, returns "null" instead of
+            a device name.
 
 4.2 Device-specific Switch Attributes
 
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index c04dbc7..4dbe360 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -34,6 +34,8 @@ rio_config_attr(device_rev, "0x%08x\n");
 rio_config_attr(asm_did, "0x%04x\n");
 rio_config_attr(asm_vid, "0x%04x\n");
 rio_config_attr(asm_rev, "0x%04x\n");
+rio_config_attr(destid, "0x%04x\n");
+rio_config_attr(hopcount, "0x%02x\n");
 
 static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -53,6 +55,35 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
 	return (str - buf);
 }
 
+static ssize_t lprev_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct rio_dev *rdev = to_rio_dev(dev);
+
+	return sprintf(buf, "%s\n",
+			(rdev->prev) ? rio_name(rdev->prev) : "root");
+}
+
+static ssize_t lnext_show(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct rio_dev *rdev = to_rio_dev(dev);
+	char *str = buf;
+	int i;
+
+	if (rdev->pef & RIO_PEF_SWITCH) {
+		for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
+			if (rdev->rswitch->nextdev[i])
+				str += sprintf(str, "%s\n",
+					rio_name(rdev->rswitch->nextdev[i]));
+			else
+				str += sprintf(str, "null\n");
+		}
+	}
+
+	return str - buf;
+}
+
 struct device_attribute rio_dev_attrs[] = {
 	__ATTR_RO(did),
 	__ATTR_RO(vid),
@@ -60,10 +91,14 @@ struct device_attribute rio_dev_attrs[] = {
 	__ATTR_RO(asm_did),
 	__ATTR_RO(asm_vid),
 	__ATTR_RO(asm_rev),
+	__ATTR_RO(lprev),
+	__ATTR_RO(destid),
 	__ATTR_NULL,
 };
 
 static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
+static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL);
+static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL);
 
 static ssize_t
 rio_read_config(struct file *filp, struct kobject *kobj,
@@ -219,7 +254,9 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
 	err = device_create_bin_file(&rdev->dev, &rio_config_attr);
 
 	if (!err && (rdev->pef & RIO_PEF_SWITCH)) {
-		err = device_create_file(&rdev->dev, &dev_attr_routes);
+		err |= device_create_file(&rdev->dev, &dev_attr_routes);
+		err |= device_create_file(&rdev->dev, &dev_attr_lnext);
+		err |= device_create_file(&rdev->dev, &dev_attr_hopcount);
 		if (!err && rdev->rswitch->sw_sysfs)
 			err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
 	}
@@ -242,6 +279,8 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
 	device_remove_bin_file(&rdev->dev, &rio_config_attr);
 	if (rdev->pef & RIO_PEF_SWITCH) {
 		device_remove_file(&rdev->dev, &dev_attr_routes);
+		device_remove_file(&rdev->dev, &dev_attr_lnext);
+		device_remove_file(&rdev->dev, &dev_attr_hopcount);
 		if (rdev->rswitch->sw_sysfs)
 			rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
 	}
-- 
1.7.3.1

^ permalink raw reply related

* Re: [PATCH] tty/serial: Relax the device_type restriction from of_serial
From: Grant Likely @ 2011-02-25 19:22 UTC (permalink / raw)
  To: devicetree-discuss, Greg Kroah-Hartman, linux-kernel,
	linuxppc-dev, Arnd Bergmann, Benjamin Herrenschmidt
In-Reply-To: <20110223021221.17638.42707.stgit@localhost6.localdomain6>

Hi Arnd and Ben,

I forgot to cc you guys on this patch.  Greg has it in his tree, but I
wanted to make sure you noticed it.  If you have any objections, let
me know and I'll ask Greg to drop it.

Thanks,
g.


On Tue, Feb 22, 2011 at 7:12 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> There is no need to test for a device_type property in ns8250
> compatible serial ports. =A0device_type is an OpenFirmware property that
> is not required when using the flattened tree representation.
>
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> =A0drivers/tty/serial/of_serial.c | =A0 18 +++++++++---------
> =A01 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_seria=
l.c
> index 5c7abe4..6a18ca6 100644
> --- a/drivers/tty/serial/of_serial.c
> +++ b/drivers/tty/serial/of_serial.c
> @@ -160,17 +160,17 @@ static int of_platform_serial_remove(struct platfor=
m_device *ofdev)
> =A0* A few common types, add more as needed.
> =A0*/
> =A0static struct of_device_id __devinitdata of_platform_serial_table[] =
=3D {
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ns8250", =A0 .data =
=3D (void *)PORT_8250, },
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ns16450", =A0.data =
=3D (void *)PORT_16450, },
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ns16550a", .data =3D=
 (void *)PORT_16550A, },
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ns16550", =A0.data =
=3D (void *)PORT_16550, },
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ns16750", =A0.data =
=3D (void *)PORT_16750, },
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ns16850", =A0.data =
=3D (void *)PORT_16850, },
> + =A0 =A0 =A0 { .compatible =3D "ns8250", =A0 .data =3D (void *)PORT_8250=
, },
> + =A0 =A0 =A0 { .compatible =3D "ns16450", =A0.data =3D (void *)PORT_1645=
0, },
> + =A0 =A0 =A0 { .compatible =3D "ns16550a", .data =3D (void *)PORT_16550A=
, },
> + =A0 =A0 =A0 { .compatible =3D "ns16550", =A0.data =3D (void *)PORT_1655=
0, },
> + =A0 =A0 =A0 { .compatible =3D "ns16750", =A0.data =3D (void *)PORT_1675=
0, },
> + =A0 =A0 =A0 { .compatible =3D "ns16850", =A0.data =3D (void *)PORT_1685=
0, },
> =A0#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
> - =A0 =A0 =A0 { .type =3D "serial", .compatible =3D "ibm,qpace-nwp-serial=
",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 .data =3D (void *)PORT_NWPSERIAL, },
> + =A0 =A0 =A0 { .compatible =3D "ibm,qpace-nwp-serial",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .data =3D (void *)PORT_NWPSERIAL, },
> =A0#endif
> - =A0 =A0 =A0 { .type =3D "serial", =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 .data =3D (void *)PORT_UNKNOWN, },
> + =A0 =A0 =A0 { .type =3D "serial", =A0 =A0 =A0 =A0 .data =3D (void *)POR=
T_UNKNOWN, },
> =A0 =A0 =A0 =A0{ /* end of list */ },
> =A0};
>
>
>



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

^ permalink raw reply

* Re: [PATCH] tty/serial: Relax the device_type restriction from of_serial
From: Benjamin Herrenschmidt @ 2011-02-25 21:40 UTC (permalink / raw)
  To: Grant Likely
  Cc: devicetree-discuss, Greg Kroah-Hartman, linuxppc-dev,
	linux-kernel, Arnd Bergmann
In-Reply-To: <AANLkTinx2YxOs3Y-XDHaWe44Bw8HqiMyanouV5Bo3KuX@mail.gmail.com>

On Fri, 2011-02-25 at 12:22 -0700, Grant Likely wrote:
> Hi Arnd and Ben,
> 
> I forgot to cc you guys on this patch.  Greg has it in his tree, but I
> wanted to make sure you noticed it.  If you have any objections, let
> me know and I'll ask Greg to drop it.

No objection. Device-types are a thing of the past :-)

Cheers,
Ben.

> Thanks,
> g.
> 
> 
> On Tue, Feb 22, 2011 at 7:12 PM, Grant Likely <grant.likely@secretlab.ca> wrote:
> > There is no need to test for a device_type property in ns8250
> > compatible serial ports.  device_type is an OpenFirmware property that
> > is not required when using the flattened tree representation.
> >
> > Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> > ---
> >  drivers/tty/serial/of_serial.c |   18 +++++++++---------
> >  1 files changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
> > index 5c7abe4..6a18ca6 100644
> > --- a/drivers/tty/serial/of_serial.c
> > +++ b/drivers/tty/serial/of_serial.c
> > @@ -160,17 +160,17 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
> >  * A few common types, add more as needed.
> >  */
> >  static struct of_device_id __devinitdata of_platform_serial_table[] = {
> > -       { .type = "serial", .compatible = "ns8250",   .data = (void *)PORT_8250, },
> > -       { .type = "serial", .compatible = "ns16450",  .data = (void *)PORT_16450, },
> > -       { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
> > -       { .type = "serial", .compatible = "ns16550",  .data = (void *)PORT_16550, },
> > -       { .type = "serial", .compatible = "ns16750",  .data = (void *)PORT_16750, },
> > -       { .type = "serial", .compatible = "ns16850",  .data = (void *)PORT_16850, },
> > +       { .compatible = "ns8250",   .data = (void *)PORT_8250, },
> > +       { .compatible = "ns16450",  .data = (void *)PORT_16450, },
> > +       { .compatible = "ns16550a", .data = (void *)PORT_16550A, },
> > +       { .compatible = "ns16550",  .data = (void *)PORT_16550, },
> > +       { .compatible = "ns16750",  .data = (void *)PORT_16750, },
> > +       { .compatible = "ns16850",  .data = (void *)PORT_16850, },
> >  #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
> > -       { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
> > -                                       .data = (void *)PORT_NWPSERIAL, },
> > +       { .compatible = "ibm,qpace-nwp-serial",
> > +               .data = (void *)PORT_NWPSERIAL, },
> >  #endif
> > -       { .type = "serial",                           .data = (void *)PORT_UNKNOWN, },
> > +       { .type = "serial",         .data = (void *)PORT_UNKNOWN, },
> >        { /* end of list */ },
> >  };
> >
> >
> >
> 
> 
> 

^ permalink raw reply

* [PATCH v4 0/2]  powerpc: Open PIC binding and "pic-no-reset"
From: Meador Inge @ 2011-02-25 21:59 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: devicetree-discuss, Dave Kleikamp, Hollis Blanchard

This patch set provides a binding for Open PIC and implements support for
a new property, specified by that binding, called "pic-no-reset".

v4 - Per Ben's feedback the protected sources implementation was left
     completely intact.  As such, the DTS cleanup and "protected-sources"
     removal patches were dropped.

v3 - the Open PIC binding was changed to be more consistent with existing
     bindings, several DTS files were cleaned up, "no-reset" was changed to
     "pic-no-reset", and a check to treat "protected-sources" as a synonym for
     "pic-no-reset" was added.

Signed-off-by: Meador Inge <meador_inge@mentor.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Hollis Blanchard <hollis_blanchard@mentor.com>
Cc: Dave Kleikamp <shaggy@linux.vnet.ibm.com>

Meador Inge (2):
  powerpc: document the Open PIC device tree binding
  powerpc: make MPIC honor the "pic-no-reset" device tree property

 Documentation/powerpc/dts-bindings/open-pic.txt |   98 +++++++++++++++++++++++
 arch/powerpc/include/asm/mpic.h                 |    6 ++
 arch/powerpc/sysdev/mpic.c                      |   67 ++++++++++++----
 3 files changed, 155 insertions(+), 16 deletions(-)
 create mode 100644 Documentation/powerpc/dts-bindings/open-pic.txt

^ permalink raw reply

* [PATCH v4 1/2] powerpc: document the Open PIC device tree binding
From: Meador Inge @ 2011-02-25 21:59 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: devicetree-discuss, Hollis Blanchard, Stuart Yoder
In-Reply-To: <1298671177-19572-1-git-send-email-meador_inge@mentor.com>

This binding documents several properties that have been in use for quite
some time, and adds one new property 'pic-no-reset', which controls the runtime
initialization behavior of the PIC.  More specifically, the presence of
'pic-no-reset' mandates that the PIC shall not be reset during runtime
initialization and that any initialization related to interrupt sources
shall be limited to sources explicitly referenced in the device tree.  This
functionality is useful in AMP systems where multiple OSes are sharing the
PIC and the reinitialization of the PIC can interfere with OSes that are
already up and running.

The interrupt specifier definition is based off of Stuart Yoder's FSL MPIC
binding.

Signed-off-by: Meador Inge <meador_inge@mentor.com>
Cc: Hollis Blanchard <hollis_blanchard@mentor.com>
Cc: Stuart Yoder <stuart.yoder@freescale.com>
---
 Documentation/powerpc/dts-bindings/open-pic.txt |   98 +++++++++++++++++++++++
 1 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/powerpc/dts-bindings/open-pic.txt

diff --git a/Documentation/powerpc/dts-bindings/open-pic.txt b/Documentation/powerpc/dts-bindings/open-pic.txt
new file mode 100644
index 0000000..909a902
--- /dev/null
+++ b/Documentation/powerpc/dts-bindings/open-pic.txt
@@ -0,0 +1,98 @@
+* Open PIC Binding
+
+This binding specifies what properties must be available in the device tree
+representation of an Open PIC compliant interrupt controller.  This binding is
+based on the binding defined for Open PIC in [1] and is a superset of that
+binding.
+
+Required properties:
+
+  NOTE: Many of these descriptions were paraphrased here from [1] to aid
+        readability.
+
+    - compatible: Specifies the compatibility list for the PIC.  The type
+      shall be <string> and the value shall include "open-pic".
+
+    - reg: Specifies the base physical address(s) and size(s) of this
+      PIC's addressable register space.  The type shall be <prop-encoded-array>.
+
+    - interrupt-controller: The presence of this property identifies the node
+      as an Open PIC.  No property value shall be defined.
+
+    - #interrupt-cells: Specifies the number of cells needed to encode an
+      interrupt source.  The type shall be a <u32> and the value shall be 2.
+
+    - #address-cells: Specifies the number of cells needed to encode an
+      address.  The type shall be <u32> and the value shall be 0.  As such,
+      'interrupt-map' nodes do not have to specify a parent unit address.
+
+Optional properties:
+
+    - pic-no-reset: The presence of this property indicates that the PIC
+      shall not be reset during runtime initialization.  No property value shall
+      be defined.  The presence of this property also mandates that any
+      initialization related to interrupt sources shall be limited to sources
+      explicitly referenced in the device tree.
+
+* Interrupt Specifier Definition
+
+  Interrupt specifiers consists of 2 cells encoded as
+  follows:
+
+    - <1st-cell>: The interrupt-number that identifies the interrupt source.
+
+    - <2nd-cell>: The level-sense information, encoded as follows:
+                    0 = low-to-high edge triggered
+                    1 = active low level-sensitive
+                    2 = active high level-sensitive
+                    3 = high-to-low edge triggered
+
+* Examples
+
+Example 1:
+
+	/*
+	 * An Open PIC interrupt controller
+	 */
+	mpic: pic@40000 {
+		// This is an interrupt controller node.
+		interrupt-controller;
+
+		// No address cells so that 'interrupt-map' nodes which reference
+		// this Open PIC node do not need a parent address specifier.
+		#address-cells = <0>;
+
+		// Two cells to encode interrupt sources.
+		#interrupt-cells = <2>;
+
+		// Offset address of 0x40000 and size of 0x40000.
+		reg = <0x40000 0x40000>;
+
+		// Compatible with Open PIC.
+		compatible = "open-pic";
+
+		// The PIC shall not be reset.
+		pic-no-reset;
+	};
+
+Example 2:
+
+	/*
+	 * An interrupt generating device that is wired to an Open PIC.
+	 */
+	serial0: serial@4500 {
+		// Interrupt source '42' that is active high level-sensitive.
+		// Note that there are only two cells as specified in the interrupt
+		// parent's '#interrupt-cells' property.
+		interrupts = <42 2>;
+
+		// The interrupt controller that this device is wired to.
+		interrupt-parent = <&mpic>;
+	};
+
+* References
+
+[1] Power.org (TM) Standard for Embedded Power Architecture (TM) Platform
+    Requirements (ePAPR), Version 1.0, July 2008.
+    (http://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.0.pdf)
+
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH v4 2/2] powerpc: make MPIC honor the "pic-no-reset" device tree property
From: Meador Inge @ 2011-02-25 21:59 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: devicetree-discuss, Hollis Blanchard
In-Reply-To: <1298671177-19572-1-git-send-email-meador_inge@mentor.com>

This property, defined in the Open PIC binding, tells the kernel not to use the
reset bit in the global configuration register.  Additionally, its presence
mandates that only sources which are actually used (i.e. appear in the device
tree) should have their VECPRI bits initialized.

Although, "pic-no-reset" can be used for the same use cases that
"protected-sources" is covering, the "protected-sources" implementation was
left completely intact.  This is a more pragmatic approach as there are
already several existing systems which use protected sources.  If
"pic-no-reset" *and* "protected-sources" are both used, however, then
"pic-no-reset" takes precedence in terms of the init behavior and the
sanity checks done by protected sources will still take place.

Signed-off-by: Meador Inge <meador_inge@mentor.com>
Cc: Hollis Blanchard <hollis_blanchard@mentor.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/mpic.h |    6 +++
 arch/powerpc/sysdev/mpic.c      |   67 +++++++++++++++++++++++++++++---------
 2 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index e000cce..7e1be12 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -325,6 +325,8 @@ struct mpic
 #ifdef CONFIG_PM
 	struct mpic_irq_save	*save_data;
 #endif
+
+	int cpu;
 };
 
 /*
@@ -367,6 +369,10 @@ struct mpic
 #define MPIC_SINGLE_DEST_CPU		0x00001000
 /* Enable CoreInt delivery of interrupts */
 #define MPIC_ENABLE_COREINT		0x00002000
+/* Disable resetting of the MPIC.
+ * NOTE: This flag trumps MPIC_WANTS_RESET.
+ */
+#define MPIC_NO_RESET			0x00004000
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK		0xf0000000
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index b0c8469..eac1a3b 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -308,6 +308,15 @@ static inline void mpic_map(struct mpic *mpic, struct device_node *node,
 #define mpic_map(m,n,p,b,o,s)	_mpic_map_mmio(m,p,b,o,s)
 #endif /* !CONFIG_PPC_DCR */
 
+static inline void mpic_init_vector(struct mpic *mpic, int source)
+{
+	/* start with vector = source number, and masked */
+	u32 vecpri = MPIC_VECPRI_MASK | source | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
+
+	/* init hw */
+	mpic_irq_write(source, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+	mpic_irq_write(source, MPIC_INFO(IRQ_DESTINATION), 1 << mpic->cpu);
+}
 
 
 /* Check if we have one of those nice broken MPICs with a flipped endian on
@@ -622,6 +631,14 @@ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
 	return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
 }
 
+/* Determine if the linux irq is a timer interrupt */
+static unsigned int mpic_is_timer_interrupt(struct mpic *mpic, unsigned int irq)
+{
+	unsigned int src = mpic_irq_to_hw(irq);
+
+	return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[3]);
+}
+
 
 /* Convert a cpu mask from logical to physical cpu numbers. */
 static inline u32 mpic_physmask(u32 cpumask)
@@ -967,6 +984,15 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
 	if (hw >= mpic->irq_count)
 		return -EINVAL;
 
+	/* If the MPIC was reset, then all vectors have already been
+	 * initialized.  Otherwise, the appropriate vector needs to be
+	 * initialized here to ensure that only used sources are setup with
+	 * a vector.
+	 */
+	if (mpic->flags & MPIC_NO_RESET)
+		if (!(mpic_is_ipi(mpic, hw) || mpic_is_timer_interrupt(mpic, hw)))
+			mpic_init_vector(mpic, hw);
+
 	mpic_msi_reserve_hwirq(mpic, hw);
 
 	/* Default chip */
@@ -1033,6 +1059,11 @@ static struct irq_host_ops mpic_host_ops = {
 	.xlate = mpic_host_xlate,
 };
 
+static int mpic_reset_prohibited(struct device_node *node)
+{
+	return node && of_get_property(node, "pic-no-reset", NULL);
+}
+
 /*
  * Exported functions
  */
@@ -1153,7 +1184,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
 	mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
 	/* Reset */
-	if (flags & MPIC_WANTS_RESET) {
+
+	/* When using a device-node, reset requests are only honored if the MPIC
+	 * is allowed to reset.
+	 */
+	if (mpic_reset_prohibited(node)) {
+		mpic->flags |= MPIC_NO_RESET;
+	}
+
+	if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) {
+		printk(KERN_DEBUG "mpic: Resetting\n");
 		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
 			   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
 			   | MPIC_GREG_GCONF_RESET);
@@ -1270,7 +1310,6 @@ void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count)
 void __init mpic_init(struct mpic *mpic)
 {
 	int i;
-	int cpu;
 
 	BUG_ON(mpic->num_sources == 0);
 
@@ -1314,21 +1353,17 @@ void __init mpic_init(struct mpic *mpic)
 	mpic_pasemi_msi_init(mpic);
 
 	if (mpic->flags & MPIC_PRIMARY)
-		cpu = hard_smp_processor_id();
+		mpic->cpu = hard_smp_processor_id();
 	else
-		cpu = 0;
+		mpic->cpu = 0;
 
-	for (i = 0; i < mpic->num_sources; i++) {
-		/* start with vector = source number, and masked */
-		u32 vecpri = MPIC_VECPRI_MASK | i |
-			(8 << MPIC_VECPRI_PRIORITY_SHIFT);
-		
-		/* check if protected */
-		if (mpic->protected && test_bit(i, mpic->protected))
-			continue;
-		/* init hw */
-		mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
-		mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
+	if (!(mpic->flags & MPIC_NO_RESET)) {
+		for (i = 0; i < mpic->num_sources; i++) {
+			/* check if protected */
+			if (mpic->protected && test_bit(i, mpic->protected))
+				continue;
+			mpic_init_vector(mpic, i);
+		}
 	}
 	
 	/* Init spurious vector */
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 0/8] fsldma: lockup fixes
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder

Hello everyone,

I've been chasing random infrequent controller lockups in the fsldma driver
for a long time. I finally managed to find the problem and fix it. I'm not
quite sure about the exact sequence of events which causes the race
condition, but it is related to using the hardware registers to track the
controller state. See the patch changelogs for more detail.

The problems were quickly found by turning on DMAPOOL_DEBUG inside
mm/dmapool.c. This poisons memory allocated with the dmapool API.

With dmapool poisoning turned on, the dmatest driver would start producing
failures within a few seconds. After this patchset has been applied, I have
run several iterations of the 10 threads per channel, 100000 iterations per
thread test without any problems.

I have made some changes which effect the 85xx/86xx part. I believe that
the changes only effect features which have been unused since the rewrite
in Jan 2010. It would be very good to get a test report from an 85xx/86xx
user.

While making the previous changes, I noticed that the fsldma driver does
not respect the automatic DMA unmapping of src and dst buffers. I have
added support for this feature. This also required a fix to dmatest, which
was sending incorrect flags.

The "support async_tx dependencies" patch could be split apart from the
automatic unmapping patch if it is desirable. They both touch the same
piece of code, so I thought it was ok to combine them. Let me know.

I would really like to see this go into 2.6.39. I think we can get it
reviewed before then. :)

Ira W. Snyder (8):
  fsldma: move related helper functions near each other
  fsldma: use channel name in printk output
  fsldma: improve link descriptor debugging
  fsldma: minor codingstyle and consistency fixes
  fsldma: fix controller lockups
  fsldma: support async_tx dependencies and automatic unmapping
  dmatest: fix automatic buffer unmap type
  fsldma: reduce locking during descriptor cleanup

 drivers/dma/dmatest.c |    7 +-
 drivers/dma/fsldma.c  |  485 +++++++++++++++++++++++++-----------------------
 drivers/dma/fsldma.h  |    6 +-
 3 files changed, 263 insertions(+), 235 deletions(-)

-- 
1.7.3.4

^ permalink raw reply

* [PATCH 3/8] fsldma: improve link descriptor debugging
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

This adds better tracking to link descriptor allocations, callbacks, and
frees. This makes it much easier to track errors with link descriptors.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   21 +++++++++++++++------
 1 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 6e3d3d7..851993c 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -416,6 +416,10 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
 	desc->async_tx.tx_submit = fsl_dma_tx_submit;
 	desc->async_tx.phys = pdesc;
 
+#ifdef FSL_DMA_LD_DEBUG
+	dev_dbg(chan->dev, "%s: LD %p allocated\n", chan->name, desc);
+#endif
+
 	return desc;
 }
 
@@ -467,6 +471,9 @@ static void fsldma_free_desc_list(struct fsldma_chan *chan,
 
 	list_for_each_entry_safe(desc, _desc, list, node) {
 		list_del(&desc->node);
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p free\n", chan->name, desc);
+#endif
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 }
@@ -478,6 +485,9 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
 
 	list_for_each_entry_safe_reverse(desc, _desc, list, node) {
 		list_del(&desc->node);
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p free\n", chan->name, desc);
+#endif
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 }
@@ -554,9 +564,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
-#ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
-#endif
 
 		copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
 
@@ -642,9 +649,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
 			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
-#ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
-#endif
 
 		set_desc_cnt(chan, &new->hw, len);
 		set_desc_src(chan, &new->hw, src);
@@ -881,13 +885,18 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 		callback_param = desc->async_tx.callback_param;
 		if (callback) {
 			spin_unlock_irqrestore(&chan->desc_lock, flags);
+#ifdef FSL_DMA_LD_DEBUG
 			dev_dbg(chan->dev, "%s: LD %p callback\n", name, desc);
+#endif
 			callback(callback_param);
 			spin_lock_irqsave(&chan->desc_lock, flags);
 		}
 
 		/* Run any dependencies, then free the descriptor */
 		dma_run_dependencies(&desc->async_tx);
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p free\n", name, desc);
+#endif
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 1/8] fsldma: move related helper functions near each other
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

This is a purely cosmetic cleanup. It is nice to have related functions
right next to each other in the code.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  116 +++++++++++++++++++++++++++----------------------
 1 files changed, 64 insertions(+), 52 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 4de947a..2e1af45 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -39,33 +39,9 @@
 
 static const char msg_ld_oom[] = "No free memory for link descriptor\n";
 
-static void dma_init(struct fsldma_chan *chan)
-{
-	/* Reset the channel */
-	DMA_OUT(chan, &chan->regs->mr, 0, 32);
-
-	switch (chan->feature & FSL_DMA_IP_MASK) {
-	case FSL_DMA_IP_85XX:
-		/* Set the channel to below modes:
-		 * EIE - Error interrupt enable
-		 * EOSIE - End of segments interrupt enable (basic mode)
-		 * EOLNIE - End of links interrupt enable
-		 * BWC - Bandwidth sharing among channels
-		 */
-		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
-				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
-				| FSL_DMA_MR_EOSIE, 32);
-		break;
-	case FSL_DMA_IP_83XX:
-		/* Set the channel to below modes:
-		 * EOTIE - End-of-transfer interrupt enable
-		 * PRC_RM - PCI read multiple
-		 */
-		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
-				| FSL_DMA_MR_PRC_RM, 32);
-		break;
-	}
-}
+/*
+ * Register Helpers
+ */
 
 static void set_sr(struct fsldma_chan *chan, u32 val)
 {
@@ -77,6 +53,30 @@ static u32 get_sr(struct fsldma_chan *chan)
 	return DMA_IN(chan, &chan->regs->sr, 32);
 }
 
+static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
+{
+	DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
+}
+
+static dma_addr_t get_cdar(struct fsldma_chan *chan)
+{
+	return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
+}
+
+static dma_addr_t get_ndar(struct fsldma_chan *chan)
+{
+	return DMA_IN(chan, &chan->regs->ndar, 64);
+}
+
+static u32 get_bcr(struct fsldma_chan *chan)
+{
+	return DMA_IN(chan, &chan->regs->bcr, 32);
+}
+
+/*
+ * Descriptor Helpers
+ */
+
 static void set_desc_cnt(struct fsldma_chan *chan,
 				struct fsl_dma_ld_hw *hw, u32 count)
 {
@@ -113,24 +113,49 @@ static void set_desc_next(struct fsldma_chan *chan,
 	hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64);
 }
 
-static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr)
+static void set_ld_eol(struct fsldma_chan *chan,
+			struct fsl_desc_sw *desc)
 {
-	DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64);
-}
+	u64 snoop_bits;
 
-static dma_addr_t get_cdar(struct fsldma_chan *chan)
-{
-	return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
-}
+	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
+		? FSL_DMA_SNEN : 0;
 
-static dma_addr_t get_ndar(struct fsldma_chan *chan)
-{
-	return DMA_IN(chan, &chan->regs->ndar, 64);
+	desc->hw.next_ln_addr = CPU_TO_DMA(chan,
+		DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
+			| snoop_bits, 64);
 }
 
-static u32 get_bcr(struct fsldma_chan *chan)
+/*
+ * DMA Engine Hardware Control Helpers
+ */
+
+static void dma_init(struct fsldma_chan *chan)
 {
-	return DMA_IN(chan, &chan->regs->bcr, 32);
+	/* Reset the channel */
+	DMA_OUT(chan, &chan->regs->mr, 0, 32);
+
+	switch (chan->feature & FSL_DMA_IP_MASK) {
+	case FSL_DMA_IP_85XX:
+		/* Set the channel to below modes:
+		 * EIE - Error interrupt enable
+		 * EOSIE - End of segments interrupt enable (basic mode)
+		 * EOLNIE - End of links interrupt enable
+		 * BWC - Bandwidth sharing among channels
+		 */
+		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
+				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
+				| FSL_DMA_MR_EOSIE, 32);
+		break;
+	case FSL_DMA_IP_83XX:
+		/* Set the channel to below modes:
+		 * EOTIE - End-of-transfer interrupt enable
+		 * PRC_RM - PCI read multiple
+		 */
+		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE
+				| FSL_DMA_MR_PRC_RM, 32);
+		break;
+	}
 }
 
 static int dma_is_idle(struct fsldma_chan *chan)
@@ -185,19 +210,6 @@ static void dma_halt(struct fsldma_chan *chan)
 		dev_err(chan->dev, "DMA halt timeout!\n");
 }
 
-static void set_ld_eol(struct fsldma_chan *chan,
-			struct fsl_desc_sw *desc)
-{
-	u64 snoop_bits;
-
-	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
-		? FSL_DMA_SNEN : 0;
-
-	desc->hw.next_ln_addr = CPU_TO_DMA(chan,
-		DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
-			| snoop_bits, 64);
-}
-
 /**
  * fsl_chan_set_src_loop_size - Set source address hold transfer size
  * @chan : Freescale DMA channel
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 4/8] fsldma: minor codingstyle and consistency fixes
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

This fixes some minor violations of the coding style. It also changes
the style of the device_prep_dma_*() function definitions so they are
identical.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   29 +++++++++++++----------------
 drivers/dma/fsldma.h |    4 ++--
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 851993c..06421c0 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -84,7 +84,7 @@ static void set_desc_cnt(struct fsldma_chan *chan,
 }
 
 static void set_desc_src(struct fsldma_chan *chan,
-				struct fsl_dma_ld_hw *hw, dma_addr_t src)
+			 struct fsl_dma_ld_hw *hw, dma_addr_t src)
 {
 	u64 snoop_bits;
 
@@ -94,7 +94,7 @@ static void set_desc_src(struct fsldma_chan *chan,
 }
 
 static void set_desc_dst(struct fsldma_chan *chan,
-				struct fsl_dma_ld_hw *hw, dma_addr_t dst)
+			 struct fsl_dma_ld_hw *hw, dma_addr_t dst)
 {
 	u64 snoop_bits;
 
@@ -104,7 +104,7 @@ static void set_desc_dst(struct fsldma_chan *chan,
 }
 
 static void set_desc_next(struct fsldma_chan *chan,
-				struct fsl_dma_ld_hw *hw, dma_addr_t next)
+			  struct fsl_dma_ld_hw *hw, dma_addr_t next)
 {
 	u64 snoop_bits;
 
@@ -113,8 +113,7 @@ static void set_desc_next(struct fsldma_chan *chan,
 	hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64);
 }
 
-static void set_ld_eol(struct fsldma_chan *chan,
-			struct fsl_desc_sw *desc)
+static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 {
 	u64 snoop_bits;
 
@@ -333,8 +332,7 @@ static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable)
 		chan->feature &= ~FSL_DMA_CHAN_START_EXT;
 }
 
-static void append_ld_queue(struct fsldma_chan *chan,
-			    struct fsl_desc_sw *desc)
+static void append_ld_queue(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
 {
 	struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev);
 
@@ -375,8 +373,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
 	cookie = chan->common.cookie;
 	list_for_each_entry(child, &desc->tx_list, node) {
 		cookie++;
-		if (cookie < 0)
-			cookie = 1;
+		if (cookie < DMA_MIN_COOKIE)
+			cookie = DMA_MIN_COOKIE;
 
 		child->async_tx.cookie = cookie;
 	}
@@ -397,8 +395,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
  *
  * Return - The descriptor allocated. NULL for failed.
  */
-static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
-					struct fsldma_chan *chan)
+static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan)
 {
 	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
@@ -423,7 +420,6 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
 	return desc;
 }
 
-
 /**
  * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel.
  * @chan : Freescale DMA channel
@@ -534,14 +530,15 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
 	/* Insert the link descriptor to the LD ring */
 	list_add_tail(&new->node, &new->tx_list);
 
-	/* Set End-of-link to the last link descriptor of new list*/
+	/* Set End-of-link to the last link descriptor of new list */
 	set_ld_eol(chan, new);
 
 	return &new->async_tx;
 }
 
-static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
-	struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src,
+static struct dma_async_tx_descriptor *
+fsl_dma_prep_memcpy(struct dma_chan *dchan,
+	dma_addr_t dma_dst, dma_addr_t dma_src,
 	size_t len, unsigned long flags)
 {
 	struct fsldma_chan *chan;
@@ -591,7 +588,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 	new->async_tx.flags = flags; /* client is in control of this ack */
 	new->async_tx.cookie = -EBUSY;
 
-	/* Set End-of-link to the last link descriptor of new list*/
+	/* Set End-of-link to the last link descriptor of new list */
 	set_ld_eol(chan, new);
 
 	return &first->async_tx;
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 113e713..49189da 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -102,8 +102,8 @@ struct fsl_desc_sw {
 } __attribute__((aligned(32)));
 
 struct fsldma_chan_regs {
-	u32 mr;	/* 0x00 - Mode Register */
-	u32 sr;	/* 0x04 - Status Register */
+	u32 mr;		/* 0x00 - Mode Register */
+	u32 sr;		/* 0x04 - Status Register */
 	u64 cdar;	/* 0x08 - Current descriptor address register */
 	u64 sar;	/* 0x10 - Source Address Register */
 	u64 dar;	/* 0x18 - Destination Address Register */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 2/8] fsldma: use channel name in printk output
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

This makes debugging the driver much easier when multiple channels are
running concurrently. In addition, you can see how much descriptor
memory each channel has allocated via the dmapool API in sysfs.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   60 +++++++++++++++++++++++++++----------------------
 drivers/dma/fsldma.h |    1 +
 2 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 2e1af45..6e3d3d7 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -37,7 +37,7 @@
 
 #include "fsldma.h"
 
-static const char msg_ld_oom[] = "No free memory for link descriptor\n";
+static const char msg_ld_oom[] = "No free memory for link descriptor";
 
 /*
  * Register Helpers
@@ -207,7 +207,7 @@ static void dma_halt(struct fsldma_chan *chan)
 	}
 
 	if (!dma_is_idle(chan))
-		dev_err(chan->dev, "DMA halt timeout!\n");
+		dev_err(chan->dev, "%s: DMA halt timeout!\n", chan->name);
 }
 
 /**
@@ -400,12 +400,13 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
 static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
 					struct fsldma_chan *chan)
 {
+	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
 	dma_addr_t pdesc;
 
 	desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc);
 	if (!desc) {
-		dev_dbg(chan->dev, "out of memory for link desc\n");
+		dev_dbg(chan->dev, "%s: out of memory for link desc\n", name);
 		return NULL;
 	}
 
@@ -439,13 +440,12 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan)
 	 * We need the descriptor to be aligned to 32bytes
 	 * for meeting FSL DMA specification requirement.
 	 */
-	chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool",
-					  chan->dev,
+	chan->desc_pool = dma_pool_create(chan->name, chan->dev,
 					  sizeof(struct fsl_desc_sw),
 					  __alignof__(struct fsl_desc_sw), 0);
 	if (!chan->desc_pool) {
-		dev_err(chan->dev, "unable to allocate channel %d "
-				   "descriptor pool\n", chan->id);
+		dev_err(chan->dev, "%s: unable to allocate descriptor pool\n",
+				   chan->name);
 		return -ENOMEM;
 	}
 
@@ -491,7 +491,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
 	unsigned long flags;
 
-	dev_dbg(chan->dev, "Free all channel resources.\n");
+	dev_dbg(chan->dev, "%s: Free all channel resources.\n", chan->name);
 	spin_lock_irqsave(&chan->desc_lock, flags);
 	fsldma_free_desc_list(chan, &chan->ld_pending);
 	fsldma_free_desc_list(chan, &chan->ld_running);
@@ -514,7 +514,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
 
 	new = fsl_dma_alloc_descriptor(chan);
 	if (!new) {
-		dev_err(chan->dev, msg_ld_oom);
+		dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 		return NULL;
 	}
 
@@ -551,11 +551,11 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 		/* Allocate the link descriptor from DMA pool */
 		new = fsl_dma_alloc_descriptor(chan);
 		if (!new) {
-			dev_err(chan->dev, msg_ld_oom);
+			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
 #ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
 #endif
 
 		copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT);
@@ -639,11 +639,11 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
 		/* allocate and populate the descriptor */
 		new = fsl_dma_alloc_descriptor(chan);
 		if (!new) {
-			dev_err(chan->dev, msg_ld_oom);
+			dev_err(chan->dev, "%s: %s\n", chan->name, msg_ld_oom);
 			goto fail;
 		}
 #ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+		dev_dbg(chan->dev, "%s: new link desc alloc %p\n", chan->name, new);
 #endif
 
 		set_desc_cnt(chan, &new->hw, len);
@@ -815,7 +815,7 @@ static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan)
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
 	if (list_empty(&chan->ld_running)) {
-		dev_dbg(chan->dev, "no running descriptors\n");
+		dev_dbg(chan->dev, "%s: no running descriptors\n", chan->name);
 		goto out_unlock;
 	}
 
@@ -859,11 +859,13 @@ static enum dma_status fsldma_desc_status(struct fsldma_chan *chan,
 static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 {
 	struct fsl_desc_sw *desc, *_desc;
+	const char *name = chan->name;
 	unsigned long flags;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
-	dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie);
+	dev_dbg(chan->dev, "%s: chan completed_cookie = %d\n",
+			   name, chan->completed_cookie);
 	list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
 		dma_async_tx_callback callback;
 		void *callback_param;
@@ -879,7 +881,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 		callback_param = desc->async_tx.callback_param;
 		if (callback) {
 			spin_unlock_irqrestore(&chan->desc_lock, flags);
-			dev_dbg(chan->dev, "LD %p callback\n", desc);
+			dev_dbg(chan->dev, "%s: LD %p callback\n", name, desc);
 			callback(callback_param);
 			spin_lock_irqsave(&chan->desc_lock, flags);
 		}
@@ -903,6 +905,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
+	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
 	unsigned long flags;
 
@@ -913,7 +916,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * don't need to do any work at all
 	 */
 	if (list_empty(&chan->ld_pending)) {
-		dev_dbg(chan->dev, "no pending LDs\n");
+		dev_dbg(chan->dev, "%s: no pending LDs\n", name);
 		goto out_unlock;
 	}
 
@@ -923,7 +926,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * at the end of the current transaction
 	 */
 	if (!dma_is_idle(chan)) {
-		dev_dbg(chan->dev, "DMA controller still busy\n");
+		dev_dbg(chan->dev, "%s: DMA controller still busy\n", name);
 		goto out_unlock;
 	}
 
@@ -996,6 +999,7 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
 static irqreturn_t fsldma_chan_irq(int irq, void *data)
 {
 	struct fsldma_chan *chan = data;
+	const char *name = chan->name;
 	int update_cookie = 0;
 	int xfer_ld_q = 0;
 	u32 stat;
@@ -1003,14 +1007,14 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	/* save and clear the status register */
 	stat = get_sr(chan);
 	set_sr(chan, stat);
-	dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat);
+	dev_dbg(chan->dev, "%s: irq: stat = 0x%x\n", name, stat);
 
 	stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
 	if (!stat)
 		return IRQ_NONE;
 
 	if (stat & FSL_DMA_SR_TE)
-		dev_err(chan->dev, "Transfer Error!\n");
+		dev_err(chan->dev, "%s: Transfer Error!\n", name);
 
 	/*
 	 * Programming Error
@@ -1018,7 +1022,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * triger a PE interrupt.
 	 */
 	if (stat & FSL_DMA_SR_PE) {
-		dev_dbg(chan->dev, "irq: Programming Error INT\n");
+		dev_dbg(chan->dev, "%s: irq: Programming Error INT\n", name);
 		if (get_bcr(chan) == 0) {
 			/* BCR register is 0, this is a DMA_INTERRUPT async_tx.
 			 * Now, update the completed cookie, and continue the
@@ -1035,8 +1039,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * we will recycle the used descriptor.
 	 */
 	if (stat & FSL_DMA_SR_EOSI) {
-		dev_dbg(chan->dev, "irq: End-of-segments INT\n");
-		dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n",
+		dev_dbg(chan->dev, "%s: irq: End-of-segments INT\n", name);
+		dev_dbg(chan->dev, "%s: irq: clndar 0x%llx, nlndar 0x%llx\n",
+			name,
 			(unsigned long long)get_cdar(chan),
 			(unsigned long long)get_ndar(chan));
 		stat &= ~FSL_DMA_SR_EOSI;
@@ -1048,7 +1053,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * and start the next transfer if it exist.
 	 */
 	if (stat & FSL_DMA_SR_EOCDI) {
-		dev_dbg(chan->dev, "irq: End-of-Chain link INT\n");
+		dev_dbg(chan->dev, "%s: irq: End-of-Chain link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOCDI;
 		update_cookie = 1;
 		xfer_ld_q = 1;
@@ -1060,7 +1065,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 * prepare next transfer.
 	 */
 	if (stat & FSL_DMA_SR_EOLNI) {
-		dev_dbg(chan->dev, "irq: End-of-link INT\n");
+		dev_dbg(chan->dev, "%s: irq: End-of-link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOLNI;
 		xfer_ld_q = 1;
 	}
@@ -1070,9 +1075,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	if (xfer_ld_q)
 		fsl_chan_xfer_ld_queue(chan);
 	if (stat)
-		dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat);
+		dev_dbg(chan->dev, "%s: irq: unhandled sr 0x%02x\n", name, stat);
 
-	dev_dbg(chan->dev, "irq: Exit\n");
+	dev_dbg(chan->dev, "%s: irq: Exit\n", name);
 	tasklet_schedule(&chan->tasklet);
 	return IRQ_HANDLED;
 }
@@ -1242,6 +1247,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
 
 	fdev->chan[chan->id] = chan;
 	tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan);
+	snprintf(chan->name, sizeof(chan->name), "chan%d", chan->id);
 
 	/* Initialize the channel */
 	dma_init(chan);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index ba9f403..113e713 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -135,6 +135,7 @@ struct fsldma_device {
 #define FSL_DMA_CHAN_START_EXT	0x00002000
 
 struct fsldma_chan {
+	char name[8];			/* Channel name */
 	struct fsldma_chan_regs __iomem *regs;
 	dma_cookie_t completed_cookie;	/* The maximum cookie completed */
 	spinlock_t desc_lock;		/* Descriptor operation lock */
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 7/8] dmatest: fix automatic buffer unmap type
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

The dmatest code relies on the DMAEngine API to automatically call
dma_unmap_single() on src buffers. The flags it passes are incorrect,
fix them.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/dmatest.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 5589358..7e1b0aa 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -285,7 +285,12 @@ static int dmatest_func(void *data)
 
 	set_user_nice(current, 10);
 
-	flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT;
+	/*
+	 * src buffers are freed by the DMAEngine code with dma_unmap_single()
+	 * dst buffers are freed by ourselves below
+	 */
+	flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT
+	      | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE;
 
 	while (!kthread_should_stop()
 	       && !(iterations && total_tests >= iterations)) {
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 8/8] fsldma: reduce locking during descriptor cleanup
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

This merges the fsl_chan_ld_cleanup() function into the dma_do_tasklet()
function to reduce locking overhead. In the best case, we will be able
to keep the DMA controller busy while we are freeing used descriptors.
In all cases, the spinlock is grabbed two times fewer than before on
each transaction.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  114 +++++++++++++++++++++----------------------------
 1 files changed, 49 insertions(+), 65 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 4014790..3dc27a9 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -872,67 +872,16 @@ static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
 }
 
 /**
- * fsl_chan_ld_cleanup - Clean up link descriptors
- * @chan : Freescale DMA channel
- *
- * This function is run after the queue of running descriptors has been
- * executed by the DMA engine. It will run any callbacks, and then free
- * the descriptors.
- *
- * HARDWARE STATE: idle
- */
-static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
-{
-	struct fsl_desc_sw *desc, *_desc;
-	const char *name = chan->name;
-	LIST_HEAD(ld_cleanup);
-	unsigned long flags;
-
-	spin_lock_irqsave(&chan->desc_lock, flags);
-
-	/* update the cookie if we have some descriptors to cleanup */
-	if (!list_empty(&chan->ld_running)) {
-		dma_cookie_t cookie;
-
-		desc = to_fsl_desc(chan->ld_running.prev);
-		cookie = desc->async_tx.cookie;
-
-		chan->completed_cookie = cookie;
-		dev_dbg(chan->dev, "%s: completed_cookie=%d\n", name, cookie);
-	}
-
-	/*
-	 * move the descriptors to a temporary list so we can drop the lock
-	 * during the entire cleanup operation
-	 */
-	list_splice_tail_init(&chan->ld_running, &ld_cleanup);
-
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
-
-	/* Run the callback for each descriptor, in order */
-	list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
-
-		/* Remove from the list of transactions */
-		list_del(&desc->node);
-
-		/* Run all cleanup for this descriptor */
-		fsldma_cleanup_descriptor(chan, desc);
-	}
-}
-
-/**
  * fsl_chan_xfer_ld_queue - transfer any pending transactions
  * @chan : Freescale DMA channel
  *
  * HARDWARE STATE: idle
+ * LOCKING: must hold chan->desc_lock
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
 	const char *name = chan->name;
 	struct fsl_desc_sw *desc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&chan->desc_lock, flags);
 
 	/*
 	 * If the list of pending descriptors is empty, then we
@@ -940,7 +889,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 */
 	if (list_empty(&chan->ld_pending)) {
 		dev_dbg(chan->dev, "%s: no pending LDs\n", name);
-		goto out_unlock;
+		return;
 	}
 
 	/*
@@ -950,7 +899,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 */
 	if (!chan->idle) {
 		dev_dbg(chan->dev, "%s: DMA controller still busy\n", name);
-		goto out_unlock;
+		return;
 	}
 
 	/*
@@ -975,9 +924,6 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 
 	dma_start(chan);
 	chan->idle = false;
-
-out_unlock:
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
@@ -987,7 +933,11 @@ out_unlock:
 static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
 {
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->desc_lock, flags);
 	fsl_chan_xfer_ld_queue(chan);
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
@@ -1089,21 +1039,55 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 static void dma_do_tasklet(unsigned long data)
 {
 	struct fsldma_chan *chan = (struct fsldma_chan *)data;
+	struct fsl_desc_sw *desc, *_desc;
+	const char *name = chan->name;
+	LIST_HEAD(ld_cleanup);
 	unsigned long flags;
 
-	dev_dbg(chan->dev, "%s: tasklet entry\n", chan->name);
+	dev_dbg(chan->dev, "%s: tasklet entry\n", name);
 
-	/* run all callbacks, free all used descriptors */
-	fsl_chan_ld_cleanup(chan);
-
-	/* the channel is now idle */
 	spin_lock_irqsave(&chan->desc_lock, flags);
+
+	/* update the cookie if we have some descriptors to cleanup */
+	if (!list_empty(&chan->ld_running)) {
+		dma_cookie_t cookie;
+
+		desc = to_fsl_desc(chan->ld_running.prev);
+		cookie = desc->async_tx.cookie;
+
+		chan->completed_cookie = cookie;
+		dev_dbg(chan->dev, "%s: completed_cookie=%d\n", name, cookie);
+	}
+
+	/*
+	 * move the descriptors to a temporary list so we can drop the lock
+	 * during the entire cleanup operation
+	 */
+	list_splice_tail_init(&chan->ld_running, &ld_cleanup);
+
+	/* the hardware is now idle and ready for more */
 	chan->idle = true;
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
-	/* start any pending transactions automatically */
+	/*
+	 * Start any pending transactions automatically
+	 *
+	 * In the ideal case, we keep the DMA controller busy while we go
+	 * ahead and free the descriptors below.
+	 */
 	fsl_chan_xfer_ld_queue(chan);
-	dev_dbg(chan->dev, "%s: tasklet exit\n", chan->name);
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+	/* Run the callback for each descriptor, in order */
+	list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
+
+		/* Remove from the list of transactions */
+		list_del(&desc->node);
+
+		/* Run all cleanup for this descriptor */
+		fsldma_cleanup_descriptor(chan, desc);
+	}
+
+	dev_dbg(chan->dev, "%s: tasklet exit\n", name);
 }
 
 static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 6/8] fsldma: support async_tx dependencies and automatic unmapping
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

Previous to this patch, the dma_run_dependencies() function has been
called while holding desc_lock. This function can call tx_submit() for
other descriptors, which may try to re-grab the lock. Avoid this by
moving the descriptors to be cleaned up to a temporary list, and
dropping the lock before cleanup.

At the same time, add support for automatic unmapping of src and dst
buffers, as offered by the DMAEngine API.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  132 ++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 95 insertions(+), 37 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index d3c5100..4014790 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -78,6 +78,11 @@ static void set_desc_cnt(struct fsldma_chan *chan,
 	hw->count = CPU_TO_DMA(chan, count, 32);
 }
 
+static u32 get_desc_cnt(struct fsldma_chan *chan, struct fsl_desc_sw *desc)
+{
+	return DMA_TO_CPU(chan, desc->hw.count, 32);
+}
+
 static void set_desc_src(struct fsldma_chan *chan,
 			 struct fsl_dma_ld_hw *hw, dma_addr_t src)
 {
@@ -88,6 +93,16 @@ static void set_desc_src(struct fsldma_chan *chan,
 	hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64);
 }
 
+static dma_addr_t get_desc_src(struct fsldma_chan *chan,
+			       struct fsl_desc_sw *desc)
+{
+	u64 snoop_bits;
+
+	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+		? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0;
+	return DMA_TO_CPU(chan, desc->hw.src_addr, 64) & ~snoop_bits;
+}
+
 static void set_desc_dst(struct fsldma_chan *chan,
 			 struct fsl_dma_ld_hw *hw, dma_addr_t dst)
 {
@@ -98,6 +113,16 @@ static void set_desc_dst(struct fsldma_chan *chan,
 	hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64);
 }
 
+static dma_addr_t get_desc_dst(struct fsldma_chan *chan,
+			       struct fsl_desc_sw *desc)
+{
+	u64 snoop_bits;
+
+	snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
+		? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0;
+	return DMA_TO_CPU(chan, desc->hw.dst_addr, 64) & ~snoop_bits;
+}
+
 static void set_desc_next(struct fsldma_chan *chan,
 			  struct fsl_dma_ld_hw *hw, dma_addr_t next)
 {
@@ -796,6 +821,57 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 }
 
 /**
+ * fsldma_cleanup_descriptor - cleanup and free a single link descriptor
+ * @chan: Freescale DMA channel
+ * @desc: descriptor to cleanup and free
+ *
+ * This function is used on a descriptor which has been executed by the DMA
+ * controller. It will run any callbacks, submit any dependencies, and then
+ * free the descriptor.
+ */
+static void fsldma_cleanup_descriptor(struct fsldma_chan *chan,
+				      struct fsl_desc_sw *desc)
+{
+	struct dma_async_tx_descriptor *txd = &desc->async_tx;
+	struct device *dev = chan->common.device->dev;
+	dma_addr_t src = get_desc_src(chan, desc);
+	dma_addr_t dst = get_desc_dst(chan, desc);
+	u32 len = get_desc_cnt(chan, desc);
+
+	/* Run the link descriptor callback function */
+	if (txd->callback) {
+#ifdef FSL_DMA_LD_DEBUG
+		dev_dbg(chan->dev, "%s: LD %p callback\n", chan->name, desc);
+#endif
+		txd->callback(txd->callback_param);
+	}
+
+	/* Run any dependencies */
+	dma_run_dependencies(txd);
+
+	/* Unmap the dst buffer, if requested */
+	if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+		if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+			dma_unmap_single(dev, dst, len, DMA_FROM_DEVICE);
+		else
+			dma_unmap_page(dev, dst, len, DMA_FROM_DEVICE);
+	}
+
+	/* Unmap the src buffer, if requested */
+	if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+		if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+			dma_unmap_single(dev, src, len, DMA_TO_DEVICE);
+		else
+			dma_unmap_page(dev, src, len, DMA_TO_DEVICE);
+	}
+
+#ifdef FSL_DMA_LD_DEBUG
+	dev_dbg(chan->dev, "%s: LD %p free\n", chan->name, desc);
+#endif
+	dma_pool_free(chan->desc_pool, desc, txd->phys);
+}
+
+/**
  * fsl_chan_ld_cleanup - Clean up link descriptors
  * @chan : Freescale DMA channel
  *
@@ -809,57 +885,39 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 {
 	struct fsl_desc_sw *desc, *_desc;
 	const char *name = chan->name;
+	LIST_HEAD(ld_cleanup);
 	unsigned long flags;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
-	/* if the ld_running list is empty, there is nothing to do */
-	if (list_empty(&chan->ld_running)) {
-		dev_dbg(chan->dev, "%s: no descriptors to cleanup\n", name);
-		goto out_unlock;
+	/* update the cookie if we have some descriptors to cleanup */
+	if (!list_empty(&chan->ld_running)) {
+		dma_cookie_t cookie;
+
+		desc = to_fsl_desc(chan->ld_running.prev);
+		cookie = desc->async_tx.cookie;
+
+		chan->completed_cookie = cookie;
+		dev_dbg(chan->dev, "%s: completed_cookie=%d\n", name, cookie);
 	}
 
 	/*
-	 * Get the last descriptor, update the cookie to it
-	 *
-	 * This is done before callbacks run so that clients can check the
-	 * status of their DMA transfer inside the callback.
+	 * move the descriptors to a temporary list so we can drop the lock
+	 * during the entire cleanup operation
 	 */
-	desc = to_fsl_desc(chan->ld_running.prev);
-	chan->completed_cookie = desc->async_tx.cookie;
-	dev_dbg(chan->dev, "%s: completed_cookie = %d\n",
-			   name, chan->completed_cookie);
+	list_splice_tail_init(&chan->ld_running, &ld_cleanup);
+
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
 	/* Run the callback for each descriptor, in order */
-	list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
-		dma_async_tx_callback callback;
-		void *callback_param;
+	list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) {
 
-		/* Remove from the list of running transactions */
+		/* Remove from the list of transactions */
 		list_del(&desc->node);
 
-		/* Run the link descriptor callback function */
-		callback = desc->async_tx.callback;
-		callback_param = desc->async_tx.callback_param;
-		if (callback) {
-			spin_unlock_irqrestore(&chan->desc_lock, flags);
-#ifdef FSL_DMA_LD_DEBUG
-			dev_dbg(chan->dev, "%s: LD %p callback\n", name, desc);
-#endif
-			callback(callback_param);
-			spin_lock_irqsave(&chan->desc_lock, flags);
-		}
-
-		/* Run any dependencies, then free the descriptor */
-		dma_run_dependencies(&desc->async_tx);
-#ifdef FSL_DMA_LD_DEBUG
-		dev_dbg(chan->dev, "%s: LD %p free\n", name, desc);
-#endif
-		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
+		/* Run all cleanup for this descriptor */
+		fsldma_cleanup_descriptor(chan, desc);
 	}
-
-out_unlock:
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
 /**
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH 5/8] fsldma: fix controller lockups
From: Ira W. Snyder @ 2011-02-26  0:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: dan.j.williams, linux-kernel, Ira W. Snyder
In-Reply-To: <1298679805-14108-1-git-send-email-iws@ovro.caltech.edu>

Enabling poisoning in the dmapool API quickly showed that the DMA
controller was fetching descriptors that should not have been in use.
This has caused intermittent controller lockups during testing.

I have been unable to figure out the exact set of conditions which cause
this to happen. However, I believe it is related to the driver using the
hardware registers to track whether the controller is busy or not. The
code can incorrectly decide that the hardware is idle due to lag between
register writes and the hardware actually becoming busy.

To fix this, the driver has been reworked to explicitly track the state
of the hardware, rather than try to guess what it is doing based on the
register values.

This has passed dmatest with 10 threads per channel, 100000 iterations
per thread several times without error. Previously, this would fail
within a few seconds.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |  187 +++++++++++++++++++-------------------------------
 drivers/dma/fsldma.h |    1 +
 2 files changed, 72 insertions(+), 116 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 06421c0..d3c5100 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -63,11 +63,6 @@ static dma_addr_t get_cdar(struct fsldma_chan *chan)
 	return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN;
 }
 
-static dma_addr_t get_ndar(struct fsldma_chan *chan)
-{
-	return DMA_IN(chan, &chan->regs->ndar, 64);
-}
-
 static u32 get_bcr(struct fsldma_chan *chan)
 {
 	return DMA_IN(chan, &chan->regs->bcr, 32);
@@ -138,13 +133,11 @@ static void dma_init(struct fsldma_chan *chan)
 	case FSL_DMA_IP_85XX:
 		/* Set the channel to below modes:
 		 * EIE - Error interrupt enable
-		 * EOSIE - End of segments interrupt enable (basic mode)
 		 * EOLNIE - End of links interrupt enable
 		 * BWC - Bandwidth sharing among channels
 		 */
 		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
-				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
-				| FSL_DMA_MR_EOSIE, 32);
+				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE, 32);
 		break;
 	case FSL_DMA_IP_83XX:
 		/* Set the channel to below modes:
@@ -757,14 +750,15 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 
 	switch (cmd) {
 	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&chan->desc_lock, flags);
+
 		/* Halt the DMA engine */
 		dma_halt(chan);
 
-		spin_lock_irqsave(&chan->desc_lock, flags);
-
 		/* Remove and free all of the descriptors in the LD queue */
 		fsldma_free_desc_list(chan, &chan->ld_pending);
 		fsldma_free_desc_list(chan, &chan->ld_running);
+		chan->idle = true;
 
 		spin_unlock_irqrestore(&chan->desc_lock, flags);
 		return 0;
@@ -802,78 +796,45 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
 }
 
 /**
- * fsl_dma_update_completed_cookie - Update the completed cookie.
+ * fsl_chan_ld_cleanup - Clean up link descriptors
  * @chan : Freescale DMA channel
  *
- * CONTEXT: hardirq
+ * This function is run after the queue of running descriptors has been
+ * executed by the DMA engine. It will run any callbacks, and then free
+ * the descriptors.
+ *
+ * HARDWARE STATE: idle
  */
-static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan)
+static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 {
-	struct fsl_desc_sw *desc;
+	struct fsl_desc_sw *desc, *_desc;
+	const char *name = chan->name;
 	unsigned long flags;
-	dma_cookie_t cookie;
 
 	spin_lock_irqsave(&chan->desc_lock, flags);
 
+	/* if the ld_running list is empty, there is nothing to do */
 	if (list_empty(&chan->ld_running)) {
-		dev_dbg(chan->dev, "%s: no running descriptors\n", chan->name);
+		dev_dbg(chan->dev, "%s: no descriptors to cleanup\n", name);
 		goto out_unlock;
 	}
 
-	/* Get the last descriptor, update the cookie to that */
+	/*
+	 * Get the last descriptor, update the cookie to it
+	 *
+	 * This is done before callbacks run so that clients can check the
+	 * status of their DMA transfer inside the callback.
+	 */
 	desc = to_fsl_desc(chan->ld_running.prev);
-	if (dma_is_idle(chan))
-		cookie = desc->async_tx.cookie;
-	else {
-		cookie = desc->async_tx.cookie - 1;
-		if (unlikely(cookie < DMA_MIN_COOKIE))
-			cookie = DMA_MAX_COOKIE;
-	}
-
-	chan->completed_cookie = cookie;
-
-out_unlock:
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
-}
-
-/**
- * fsldma_desc_status - Check the status of a descriptor
- * @chan: Freescale DMA channel
- * @desc: DMA SW descriptor
- *
- * This function will return the status of the given descriptor
- */
-static enum dma_status fsldma_desc_status(struct fsldma_chan *chan,
-					  struct fsl_desc_sw *desc)
-{
-	return dma_async_is_complete(desc->async_tx.cookie,
-				     chan->completed_cookie,
-				     chan->common.cookie);
-}
-
-/**
- * fsl_chan_ld_cleanup - Clean up link descriptors
- * @chan : Freescale DMA channel
- *
- * This function clean up the ld_queue of DMA channel.
- */
-static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
-{
-	struct fsl_desc_sw *desc, *_desc;
-	const char *name = chan->name;
-	unsigned long flags;
-
-	spin_lock_irqsave(&chan->desc_lock, flags);
-
-	dev_dbg(chan->dev, "%s: chan completed_cookie = %d\n",
+	chan->completed_cookie = desc->async_tx.cookie;
+	dev_dbg(chan->dev, "%s: completed_cookie = %d\n",
 			   name, chan->completed_cookie);
+
+	/* Run the callback for each descriptor, in order */
 	list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) {
 		dma_async_tx_callback callback;
 		void *callback_param;
 
-		if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS)
-			break;
-
 		/* Remove from the list of running transactions */
 		list_del(&desc->node);
 
@@ -897,6 +858,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
 		dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys);
 	}
 
+out_unlock:
 	spin_unlock_irqrestore(&chan->desc_lock, flags);
 }
 
@@ -904,10 +866,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan)
  * fsl_chan_xfer_ld_queue - transfer any pending transactions
  * @chan : Freescale DMA channel
  *
- * This will make sure that any pending transactions will be run.
- * If the DMA controller is idle, it will be started. Otherwise,
- * the DMA controller's interrupt handler will start any pending
- * transactions when it becomes idle.
+ * HARDWARE STATE: idle
  */
 static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 {
@@ -927,23 +886,16 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	}
 
 	/*
-	 * The DMA controller is not idle, which means the interrupt
-	 * handler will start any queued transactions when it runs
-	 * at the end of the current transaction
+	 * The DMA controller is not idle, which means that the interrupt
+	 * handler will start any queued transactions when it runs after
+	 * this transaction finishes
 	 */
-	if (!dma_is_idle(chan)) {
+	if (!chan->idle) {
 		dev_dbg(chan->dev, "%s: DMA controller still busy\n", name);
 		goto out_unlock;
 	}
 
 	/*
-	 * TODO:
-	 * make sure the dma_halt() function really un-wedges the
-	 * controller as much as possible
-	 */
-	dma_halt(chan);
-
-	/*
 	 * If there are some link descriptors which have not been
 	 * transferred, we need to start the controller
 	 */
@@ -952,6 +904,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * Move all elements from the queue of pending transactions
 	 * onto the list of running transactions
 	 */
+	dev_dbg(chan->dev, "%s: idle, starting controller\n", name);
 	desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node);
 	list_splice_tail_init(&chan->ld_pending, &chan->ld_running);
 
@@ -960,7 +913,10 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan)
 	 * then start the DMA transaction
 	 */
 	set_cdar(chan, desc->async_tx.phys);
+	get_cdar(chan);
+
 	dma_start(chan);
+	chan->idle = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&chan->desc_lock, flags);
@@ -985,16 +941,18 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
 					struct dma_tx_state *txstate)
 {
 	struct fsldma_chan *chan = to_fsl_chan(dchan);
-	dma_cookie_t last_used;
 	dma_cookie_t last_complete;
+	dma_cookie_t last_used;
+	unsigned long flags;
 
-	fsl_chan_ld_cleanup(chan);
+	spin_lock_irqsave(&chan->desc_lock, flags);
 
-	last_used = dchan->cookie;
 	last_complete = chan->completed_cookie;
+	last_used = dchan->cookie;
 
-	dma_set_tx_state(txstate, last_complete, last_used, 0);
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
 
+	dma_set_tx_state(txstate, last_complete, last_used, 0);
 	return dma_async_is_complete(cookie, last_complete, last_used);
 }
 
@@ -1006,8 +964,6 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 {
 	struct fsldma_chan *chan = data;
 	const char *name = chan->name;
-	int update_cookie = 0;
-	int xfer_ld_q = 0;
 	u32 stat;
 
 	/* save and clear the status register */
@@ -1015,6 +971,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	set_sr(chan, stat);
 	dev_dbg(chan->dev, "%s: irq: stat = 0x%x\n", name, stat);
 
+	/* check that this was really our device */
 	stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH);
 	if (!stat)
 		return IRQ_NONE;
@@ -1029,29 +986,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	 */
 	if (stat & FSL_DMA_SR_PE) {
 		dev_dbg(chan->dev, "%s: irq: Programming Error INT\n", name);
-		if (get_bcr(chan) == 0) {
-			/* BCR register is 0, this is a DMA_INTERRUPT async_tx.
-			 * Now, update the completed cookie, and continue the
-			 * next uncompleted transfer.
-			 */
-			update_cookie = 1;
-			xfer_ld_q = 1;
-		}
 		stat &= ~FSL_DMA_SR_PE;
-	}
-
-	/*
-	 * If the link descriptor segment transfer finishes,
-	 * we will recycle the used descriptor.
-	 */
-	if (stat & FSL_DMA_SR_EOSI) {
-		dev_dbg(chan->dev, "%s: irq: End-of-segments INT\n", name);
-		dev_dbg(chan->dev, "%s: irq: clndar 0x%llx, nlndar 0x%llx\n",
-			name,
-			(unsigned long long)get_cdar(chan),
-			(unsigned long long)get_ndar(chan));
-		stat &= ~FSL_DMA_SR_EOSI;
-		update_cookie = 1;
+		if (get_bcr(chan) != 0)
+			dev_err(chan->dev, "%s: Programming Error!\n", name);
 	}
 
 	/*
@@ -1061,8 +998,6 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	if (stat & FSL_DMA_SR_EOCDI) {
 		dev_dbg(chan->dev, "%s: irq: End-of-Chain link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOCDI;
-		update_cookie = 1;
-		xfer_ld_q = 1;
 	}
 
 	/*
@@ -1073,25 +1008,44 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
 	if (stat & FSL_DMA_SR_EOLNI) {
 		dev_dbg(chan->dev, "%s: irq: End-of-link INT\n", name);
 		stat &= ~FSL_DMA_SR_EOLNI;
-		xfer_ld_q = 1;
 	}
 
-	if (update_cookie)
-		fsl_dma_update_completed_cookie(chan);
-	if (xfer_ld_q)
-		fsl_chan_xfer_ld_queue(chan);
+	/* check that the DMA controller is really idle */
+	if (!dma_is_idle(chan))
+		dev_err(chan->dev, "%s: irq: controller not idle!\n", name);
+
+	/* check that we handled all of the bits */
 	if (stat)
-		dev_dbg(chan->dev, "%s: irq: unhandled sr 0x%02x\n", name, stat);
+		dev_err(chan->dev, "%s: irq: unhandled sr 0x%02x\n", name, stat);
 
-	dev_dbg(chan->dev, "%s: irq: Exit\n", name);
+	/*
+	 * Schedule the tasklet to handle all cleanup of the current
+	 * transaction. It will start a new transaction if there is
+	 * one pending.
+	 */
 	tasklet_schedule(&chan->tasklet);
+	dev_dbg(chan->dev, "%s: irq: Exit\n", name);
 	return IRQ_HANDLED;
 }
 
 static void dma_do_tasklet(unsigned long data)
 {
 	struct fsldma_chan *chan = (struct fsldma_chan *)data;
+	unsigned long flags;
+
+	dev_dbg(chan->dev, "%s: tasklet entry\n", chan->name);
+
+	/* run all callbacks, free all used descriptors */
 	fsl_chan_ld_cleanup(chan);
+
+	/* the channel is now idle */
+	spin_lock_irqsave(&chan->desc_lock, flags);
+	chan->idle = true;
+	spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+	/* start any pending transactions automatically */
+	fsl_chan_xfer_ld_queue(chan);
+	dev_dbg(chan->dev, "%s: tasklet exit\n", chan->name);
 }
 
 static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
@@ -1274,6 +1228,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev,
 	spin_lock_init(&chan->desc_lock);
 	INIT_LIST_HEAD(&chan->ld_pending);
 	INIT_LIST_HEAD(&chan->ld_running);
+	chan->idle = true;
 
 	chan->common.device = &fdev->common;
 
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 49189da..9cb5aa5 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -148,6 +148,7 @@ struct fsldma_chan {
 	int id;				/* Raw id of this channel */
 	struct tasklet_struct tasklet;
 	u32 feature;
+	bool idle;			/* DMA controller is idle */
 
 	void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable);
 	void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable);
-- 
1.7.3.4

^ permalink raw reply related

* RE: [PATCH][v1] RTC driver(Linux) for PT7C4338 chip.
From: Jain Priyanka-B32167 @ 2011-02-28  4:12 UTC (permalink / raw)
  To: Alessandro Zummo, Paul Gortmaker, linuxppc-dev@lists.ozlabs.org
  Cc: Gala Kumar-B11780, Gupta Maneesh-B18878, Timur Tabi,
	rtc-linux@googlegroups.com, Aggrwal Poonam-B10812
In-Reply-To: <AANLkTinQtDAo07jHNSo=wE=iRzO8hk1pQbRvBFq40TOB@mail.gmail.com>

Hi,

I have posted RTC driver patch back in October, 2010 with reminders for rev=
iew in between but still waiting for review and acknowledgement.
Linux Maintainer list suggests Alessandro and Paul as maintainer which are =
already in To-- list.
Please let me know what else I need to do to get it review and acknowledge.

Thanks
Priyanka




> -----Original Message-----
> From: Timur Tabi [mailto:timur.tabi@gmail.com]
> Sent: Thursday, February 24, 2011 1:41 AM
> To: Alessandro Zummo
> Cc: Jain Priyanka-B32167; Paul Gortmaker; rtc-linux@googlegroups.com;
> linuxppc-dev@lists.ozlabs.org; Gala Kumar-B11780; Gupta Maneesh-B18878;
> Aggrwal Poonam-B10812
> Subject: Re: [PATCH][v1] RTC driver(Linux) for PT7C4338 chip.
>=20
> On Wed, Feb 23, 2011 at 4:00 AM, Jain Priyanka-B32167
> <B32167@freescale.com> wrote:
> > Hi,
> >
> > =A0Please review and acknowledge this patch.
>=20
> Alessandro,
>=20
> Aren't you the RTC maintainer?  Priyanka has been asking for months for
> you to review and ack this patch, and then pick up for the next kernel
> release.  Is there something else that she needs to do to get your
> attention?  You can find it in patchworks here:
>=20
> http://patchwork.ozlabs.org/patch/69206/
>=20
> Notice that it was originally posted back in October, so it could have
> been included in 2.6.38.
>=20
> --
> Timur Tabi
> Linux kernel developer at Freescale

^ permalink raw reply


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