LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-10 17:21 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: sfr, microblaze-uclinux, devicetree-discuss, jeremy.kerr,
	linuxppc-dev, M. Warner Losh
In-Reply-To: <20100610171029.GA18824@oksana.dev.rtsoft.ru>

On Thu, Jun 10, 2010 at 11:10 AM, Anton Vorontsov
<cbouatmailru@gmail.com> wrote:
> On Thu, Jun 10, 2010 at 10:30:26AM -0600, Grant Likely wrote:
> [...]
>> =A0 =A0 =A0 res =3D kzalloc((sizeof(*res) * num_res), GFP_KERNEL);
>> =A0 =A0 =A0 if (!res) {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 kfree(ofdev); =A0/* or goto an error unwind =
label */
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> =A0 =A0 =A0 }
>> =A0 =A0 =A0 res =3D (struct resource *)&ofdev[1];
>
> You mean ofdev->resource =3D res; ?

Yeah, cut-and-paste error.

g.

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-10 17:20 UTC (permalink / raw)
  To: Mitch Bradley
  Cc: sfr, microblaze-uclinux, devicetree-discuss, jeremy.kerr,
	linuxppc-dev, M. Warner Losh
In-Reply-To: <4C111C34.1010708@firmworks.com>

On Thu, Jun 10, 2010 at 11:09 AM, Mitch Bradley <wmb@firmworks.com> wrote:
> Wow, there is some serious bikeshedding going on with this argument about
> structures and arrays .

I know! Isn't it fun?

g.

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Mitch Bradley @ 2010-06-10 17:09 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: sfr, microblaze-uclinux, devicetree-discuss, jeremy.kerr,
	linuxppc-dev, M. Warner Losh
In-Reply-To: <20100610165243.GA18043@oksana.dev.rtsoft.ru>

Wow, there is some serious bikeshedding going on with this argument 
about structures and arrays .

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-10 17:10 UTC (permalink / raw)
  To: Grant Likely
  Cc: sfr, microblaze-uclinux, devicetree-discuss, jeremy.kerr,
	linuxppc-dev, M. Warner Losh
In-Reply-To: <AANLkTimjIyclTWZZW1A26zOcWroK-bwOkmEqsLm4DINk@mail.gmail.com>

On Thu, Jun 10, 2010 at 10:30:26AM -0600, Grant Likely wrote:
[...]
> C)
> struct of_device *alloc_function(int num_res)
> {
> 	struct device *ofdev;
> 	struct resource *res;
> 	ofdev = kzalloc(sizeof(*ofdev), GFP_KERNEL)
> 	if (!ofdev)
> 		return NULL;
> 	res = kzalloc((sizeof(*res) * num_res), GFP_KERNEL);
> 	if (!res) {
> 		kfree(ofdev);  /* or goto an error unwind label */
> 		return NULL;
> 	}
> 	res = (struct resource *)&ofdev[1];

You mean ofdev->resource = res; ?

> That being said, I'm looking at refactoring to use
> platform_device_alloc() instead, which is effectively option C. (which
> I'd normally avoid, but it removes otherwise duplicate code from
> drivers/of).

Sounds great!

Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: M. Warner Losh @ 2010-06-10 17:09 UTC (permalink / raw)
  To: cbouatmailru
  Cc: sfr, devicetree-discuss, linuxppc-dev, jeremy.kerr,
	microblaze-uclinux
In-Reply-To: <20100610165243.GA18043@oksana.dev.rtsoft.ru>

In message: <20100610165243.GA18043@oksana.dev.rtsoft.ru>
            Anton Vorontsov <cbouatmailru@gmail.com> writes:
: On Thu, Jun 10, 2010 at 10:01:40AM -0600, M. Warner Losh wrote:
: [...]
: > But this requires extra, bogus fields in the structure
: 
: False. The [0] field isn't bogus, it has a defined meaning.
: It says: here is some amount of resouces may be allocated.

Not false: It is extra fields and extra lines of code.  The fact that
it is well defined doesn't make it any less bogus.  But again, that's
just opinion, much like your objection to the equally well defined
structure it replaces is bogus.

: > and creates a bogus sizeof issue.
: 
: Creates? False. The same sizeof problem exists in Grant's
: approach. sizeof(*dev) != what_we_have_allocated. Which is
: isn't great, I agree. And that's exactly why I proposed a
: dedicated allocation in the first place.

Your solution doesn't solve the sizeof issue.  Don't pretend it does.
Both ways allocate a random amount of memory larger than sizeof the
structure.

Warner

^ permalink raw reply

* Re: [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Arnd Bergmann @ 2010-06-10 17:03 UTC (permalink / raw)
  To: Steven A. Falco; +Cc: linuxppc-dev
In-Reply-To: <4C11046D.4080205@harris.com>

On Thursday 10 June 2010, Steven A. Falco wrote:
> > The ifreq structure passed into the ndo_ioctl function is in kernel
> > space, it gets copied there by net/core/dev.c:dev_ioctl().
> > emac_ioctl only accesses the data in that structure, so a copy_from_user
> > is wrong here as far as I can tell.
> 
> net/core/dev.c:dev_ioctl() does a copy_from_user on the overall structure,
> but the structure contains a union, one member of which is an embedded
> pointer to an array.  This pointer member is only used in the case of these
> two ioctls.  Other ioctls use different union members, which are not pointers.

Still unconvinced.

I don't see anywhere in the structure where we actually use a
pointer from ifr_ifru. The if_mii function is defined as

static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
{
        return (struct mii_ioctl_data *) &rq->ifr_ifru;
}

That just returns a pointer to the ifr_ifru member itself,
it does not read a __user pointer. Note how if_mii even
returns a kernel pointer (struct mii_ioctl_data *), not
a struct mii_ioctl_data __user *. You even added a cast
that otherwise should not be needed.

> As I understand it, the copy_from_user in dev_ioctl does not recursively
> copy the array.  In fact it could not do so, because the pointer to array
> is only 4 bytes long, while the array itself is 8 bytes long - so it would
> not fit.  I.e., dev_ioctl would have to allocate storage, and do a second
> copy_from_user to retrieve the array.  It would have to clean up after the
> emac_ioctl ran.  And it would have to do this only for these specific
> ioctl calls which use the array pointer in the union.
>
> Also, the result has to be returned to the user in the same array, which
> needs a copy_to_user of the array data, which is also not done in dev_ioctl.

There is no array, and no pointer in struct ifreq
 
> So I think this second copy_from/copy_to needs to be done somewhere.  I
> added it in the emac_ioctl because that is where the command is fully
> decoded.  It also avoids the problem of allocating space for the copied
> array.  But other fixes are certainly possible as well, which is why I am
> not sure I've hit on the "proper" fix.

No other device driver implementing SIOCGMIIREG does any of this,
so I'm pretty sure it's not the proper fix.

> Thanks very much for reviewing - please let me know if my explanation is
> unclear, or if you see a better way to fix this problem.

In theory, your patch should break the code. Doing a direct access
in place of a copy_to/from_user is a security hole but should still work,
while adding a copy_to/from_user on a kernel pointer should always result
in an EFAULT.

	Arnd

^ permalink raw reply

* Re: [PATCH 0/2] Replace of_device with platform_device
From: Grant Likely @ 2010-06-10 16:46 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Stephen Rothwell, Michal Simek, microblaze-uclinux, linuxppc-dev,
	sparclinux, David Miller
In-Reply-To: <1276151543.1962.48.camel@pasglop>

On Thu, Jun 10, 2010 at 12:32 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Fri, 2010-06-04 at 15:13 -0600, Grant Likely wrote:
>> This series is based on Linus' current tree. =A0It eliminate struct
>> of_device in preparation for the merge of of_platform_bus_type and
>> platform_bus_type.
>>
>> Assuming there are no objections, I'll be putting these to linux-next
>> to stew sometime next week.
>
> I don't see any update to the macio stuff... have you fixed that
> separately or are you up to breaking it -again- ? :-)

It shouldn't need any fixing because I'm not touching the driver side
of the equation (unlike the last breakage where macio_driver had its
own copy of the match table which I missed).  In fact, there aren't
even any logic changes other than dealing with moving some of the
structure members in the sparc arch code.  If I did miss anything,
then it should show up in build testing.

I will try to dig out an mac machine and fire it up though.

>
> You should do build tests with a pmac32 or g5 defconfig every now and
> then.

I frequently build tested on many platforms:

http://kisskb.ellerman.id.au/kisskb/branch/13/

g.

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

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-10 16:52 UTC (permalink / raw)
  To: M. Warner Losh
  Cc: sfr, devicetree-discuss, linuxppc-dev, jeremy.kerr,
	microblaze-uclinux
In-Reply-To: <20100610.100140.8559628065321695.imp@bsdimp.com>

On Thu, Jun 10, 2010 at 10:01:40AM -0600, M. Warner Losh wrote:
[...]
> But this requires extra, bogus fields in the structure

False. The [0] field isn't bogus, it has a defined meaning.
It says: here is some amount of resouces may be allocated.

> and creates a bogus sizeof issue.

Creates? False. The same sizeof problem exists in Grant's
approach. sizeof(*dev) != what_we_have_allocated. Which is
isn't great, I agree. And that's exactly why I proposed a
dedicated allocation in the first place.

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-10 16:30 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
	linuxppc-dev, M. Warner Losh
In-Reply-To: <20100610154741.GA7484@oksana.dev.rtsoft.ru>

On Thu, Jun 10, 2010 at 9:47 AM, Anton Vorontsov <cbouatmailru@gmail.com> w=
rote:
> On Thu, Jun 10, 2010 at 09:13:57AM -0600, M. Warner Losh wrote:
> [...]
>> : >> I told you several ways of how to improve the code (based on
>> : >> the ideas from drivers/base/, so the ideas aren't even mine,
>> : >> fwiw).
>> : >
>> : > I tend to agree with Anton here.
>> :
>> : The reason I'm confident doing it that way is that it is *not* a
>> : structure. =A0There is no structure relationship between the resource
>> : table and the platform_device other than they are allocated with the
>> : same kzalloc() call. =A0All the code that cares about that is containe=
d
>> : within 4 lines of code. =A0I'm resistant to using a structure because =
it
>> : is adds an additional 5-6 lines of code to add a structure that won't
>> : be used anywhere else, and is only 4 lines to begin with.
>>
>> I tend to agree with Grant here. =A0The idiom he's using is very wide
>> spread in the industry and works extremely well. =A0It keeps the
>> ugliness confined to a couple of lines and is less ugly than the
>> alternatives for this design pattern. =A0It is a little surprising when
>> you see the code the first time, granted, but I think its expressive
>> power trumps that small surprise.
>
> Oh, come on. Both constructions are binary equivalent.
>
> So how can people seriously be with *that* code:
>
> =A0 =A0 =A0 =A0dev->resource =3D (void *)&dev[1];
>
> which, semantically, is a nonsense and asks for a fix.
>
> While
> =A0 =A0 =A0 =A0dev_obj->dev.resource =3D dev_obj->resource;
>
> simply makes sense.

Well, my choices are (without whitespace so as not to bias line count):

A)
struct of_device *alloc_function(int num_res)
{
	struct device *ofdev;
	struct resource *res;
	ofdev =3D kzalloc(sizeof(*ofdev) + (sizeof(*res) * num_res), GFP_KERNEL);
	if (!ofdev)
		return NULL;
	res =3D (struct resource *)&ofdev[1];
	...
	return ofdev;
}
10 lines of code

B)
struct of_device_object {
	struct of_device ofdev;
	struct resource resource[0];
};
struct of_device *alloc_function(int num_res)
{
	struct of_device_object *ofobj;
	struct of_device *ofdev;
	struct resource *res;
	ofobj =3D kzalloc(sizeof(*ofobj) + (sizeof(*res) * num_res), GFP_KERNEL);
	if (!ofobj)
		return NULL;
	res =3D ofobj->resource;
	...
	return &ofobj->ofdev;
}
15 lines of code

C)
struct of_device *alloc_function(int num_res)
{
	struct device *ofdev;
	struct resource *res;
	ofdev =3D kzalloc(sizeof(*ofdev), GFP_KERNEL)
	if (!ofdev)
		return NULL;
	res =3D kzalloc((sizeof(*res) * num_res), GFP_KERNEL);
	if (!res) {
		kfree(ofdev);  /* or goto an error unwind label */
		return NULL;
	}
	res =3D (struct resource *)&ofdev[1];
	...
	return ofdev;
}
15 lines of code, plus an extra few lines at kfree(ofdev) time.

When I look at the three, option A is more concise and clearer in it's
intent to me.

That being said, I'm looking at refactoring to use
platform_device_alloc() instead, which is effectively option C. (which
I'd normally avoid, but it removes otherwise duplicate code from
drivers/of).

g.

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

^ permalink raw reply

* [PATCH V4] powerpc/mpc512x: Add gpio driver
From: Anatolij Gustschin @ 2010-06-10 16:21 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Anatolij Gustschin, Wolfgang Denk, Detlev Zundel, Matthias Fuchs
In-Reply-To: <1276185950-28451-1-git-send-email-agust@denx.de>

From: Matthias Fuchs <matthias.fuchs@esd.eu>

This patch adds a gpio driver for MPC512X PowerPCs.

It has been tested on our CAN-CBX-CPU5201 module that
uses a MPC5121 CPU. This platform comes with a couple of
LEDs and configuration switches that have been used for testing.

Signed-off-by: Matthias Fuchs <matthias.fuchs@esd.eu>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
Please consider this patch for inclusion in 2.6.36. Thanks!

v4: - actually v3 was rebased but without shadow
      registers init code as stated in the v3 changelog.
      Correct it now.

v3: - rebase to apply on current mainline tree
    - v2 switched to shadow registers but these are
      not pre-initialized (zero). As a result, setting
      pin direction or ODR register will clear other bits
      in direction and ODR registers. Fix this bug by adding
      shadow registers initialization code.

v2: - move driver to arch/powerpc/platforms/512x directory
    - Kconfig changes are now in arch/powerpc/platform/512x/Kconfig
    - put struct mpc512x_gpio_regs in driver's .c file
    - rename GPIO_MASK into MPC512x_GPIO_MASK
    - use shadow registers instead of r/m/w-operations
    - don't use arch_initcall but call mpc512x_add_gpiochips()
      from mpc512x platform setup code.

 arch/powerpc/platforms/512x/Kconfig          |    9 +
 arch/powerpc/platforms/512x/Makefile         |    1 +
 arch/powerpc/platforms/512x/mpc512x.h        |    3 +
 arch/powerpc/platforms/512x/mpc512x_gpio.c   |  204 ++++++++++++++++++++++++++
 arch/powerpc/platforms/512x/mpc512x_shared.c |    3 +
 5 files changed, 220 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/mpc512x_gpio.c

diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0..bd763ee 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -30,3 +30,12 @@ config MPC5121_GENERIC
 
 	  Compatible boards include:  Protonic LVT base boards (ZANMCU
 	  and VICVT2).
+
+config MPC512x_GPIO
+	bool "MPC512x GPIO support"
+	depends on PPC_MPC512x
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Say Y here if you're going to use hardware that connects to the
+	  MPC512x GPIOs.
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 90be2f5..12518e3 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -4,3 +4,4 @@
 obj-y				+= clock.o mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC5121_GENERIC)	+= mpc5121_generic.o
+obj-$(CONFIG_MPC512x_GPIO)	+= mpc512x_gpio.o
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0..4a1b094 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,7 @@ extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
+#ifdef CONFIG_MPC512x_GPIO
+extern int mpc512x_add_gpiochips(void);
+#endif
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_gpio.c b/arch/powerpc/platforms/512x/mpc512x_gpio.c
new file mode 100644
index 0000000..13b2478
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc512x_gpio.c
@@ -0,0 +1,204 @@
+/*
+ * MPC512x gpio driver
+ *
+ * Copyright (c) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ *
+ * derived from ppc4xx gpio driver
+ *
+ * Copyright (c) 2008 Harris Corporation
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ *
+ * Author: Steve Falco <sfalco@harris.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/types.h>
+
+#define MPC512x_GPIO_MASK(gpio) (0x80000000 >> (gpio))
+
+struct mpc512x_gpio_regs {
+	u32 gpdir;
+	u32 gpodr;
+	u32 gpdat;
+	u32 gpier;
+	u32 gpimr;
+	u32 gpicr1;
+	u32 gpicr2;
+};
+
+struct mpc512x_chip {
+	struct of_mm_gpio_chip mm_gc;
+	spinlock_t lock;
+
+	/* shadow registers */
+	u32 dat;
+	u32 odr;
+	u32 dir;
+};
+
+/*
+ * GPIO LIB API implementation for GPIOs
+ *
+ * There are a maximum of 32 gpios in each gpio controller.
+ */
+static inline struct mpc512x_chip *
+to_mpc512x_gpiochip(struct of_mm_gpio_chip *mm_gc)
+{
+	return container_of(mm_gc, struct mpc512x_chip, mm_gc);
+}
+
+static int mpc512x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+	return in_be32(&regs->gpdat) & MPC512x_GPIO_MASK(gpio);
+}
+
+static inline void
+__mpc512x_gpio_set(struct of_mm_gpio_chip *mm_gc, unsigned int gpio, int val)
+{
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+
+	if (val)
+		chip->dat |= MPC512x_GPIO_MASK(gpio);
+	else
+		chip->dat &= ~MPC512x_GPIO_MASK(gpio);
+
+	out_be32(&regs->gpdat, chip->dat);
+}
+
+static void
+mpc512x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	__mpc512x_gpio_set(mm_gc, gpio, val);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc512x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	/* Disable open-drain function */
+	chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpodr, chip->odr);
+
+	/* Float the pin */
+	chip->dir &= ~MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpdir, chip->dir);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int
+mpc512x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	/* First set initial value */
+	__mpc512x_gpio_set(mm_gc, gpio, val);
+
+	/* Disable open-drain function */
+	chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpodr, chip->odr);
+
+	/* Drive the pin */
+	chip->dir |= MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpdir, chip->dir);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+	return 0;
+}
+
+void __init mpc512x_add_gpiochips(void)
+{
+	struct device_node *np;
+
+	for_each_compatible_node(np, NULL, "fsl,mpc5121-gpio") {
+		int ret;
+		struct mpc512x_chip *chip;
+		struct of_mm_gpio_chip *mm_gc;
+		struct of_gpio_chip *of_gc;
+		struct gpio_chip *gc;
+		struct mpc512x_gpio_regs __iomem *regs;
+
+		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+		if (!chip) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		spin_lock_init(&chip->lock);
+
+		mm_gc = &chip->mm_gc;
+		of_gc = &mm_gc->of_gc;
+		gc = &of_gc->gc;
+
+		gc->ngpio = 32;
+		gc->direction_input = mpc512x_gpio_dir_in;
+		gc->direction_output = mpc512x_gpio_dir_out;
+		gc->get = mpc512x_gpio_get;
+		gc->set = mpc512x_gpio_set;
+
+		ret = of_mm_gpiochip_add(np, mm_gc);
+		if (ret)
+			goto err;
+
+		regs = mm_gc->regs;
+		chip->dat = in_be32(&regs->gpdat);
+		chip->dir = in_be32(&regs->gpdir);
+		chip->odr = in_be32(&regs->gpodr);
+		continue;
+err:
+		pr_err("%s: registration failed with status %d\n",
+		       np->full_name, ret);
+		kfree(chip);
+		/* try others anyway */
+	}
+}
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 707e572..15da1bc 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -178,4 +178,7 @@ void __init mpc512x_init(void)
 	mpc5121_clk_init();
 	mpc512x_restart_init();
 	mpc512x_psc_fifo_init();
+#ifdef CONFIG_MPC512x_GPIO
+	mpc512x_add_gpiochips();
+#endif
 }
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH V3] powerpc/mpc512x: Add gpio driver
From: Anatolij Gustschin @ 2010-06-10 16:05 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Anatolij Gustschin, Wolfgang Denk, Detlev Zundel, Matthias Fuchs

From: Matthias Fuchs <matthias.fuchs@esd.eu>

This patch adds a gpio driver for MPC512X PowerPCs.

It has been tested on our CAN-CBX-CPU5201 module that
uses a MPC5121 CPU. This platform comes with a couple of
LEDs and configuration switches that have been used for testing.

Signed-off-by: Matthias Fuchs <matthias.fuchs@esd.eu>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
Please consider this patch for inclusion in 2.6.36. Thanks!

v3: - rebase to apply on current mainline tree
    - v2 switched to shadow registers but these are
      not pre-initialized (zero). As a result, setting
      pin direction or ODR register will clear other bits
      in direction and ODR registers. Fix this bug by adding
      shadow registers initialization code.

v2: - move driver to arch/powerpc/platforms/512x directory
    - Kconfig changes are now in arch/powerpc/platform/512x/Kconfig
    - put struct mpc512x_gpio_regs in driver's .c file
    - rename GPIO_MASK into MPC512x_GPIO_MASK
    - use shadow registers instead of r/m/w-operations
    - don't use arch_initcall but call mpc512x_add_gpiochips()
      from mpc512x platform setup code.

 arch/powerpc/platforms/512x/Kconfig          |    9 ++
 arch/powerpc/platforms/512x/Makefile         |    1 +
 arch/powerpc/platforms/512x/mpc512x.h        |    3 +
 arch/powerpc/platforms/512x/mpc512x_gpio.c   |  198 ++++++++++++++++++++++++++
 arch/powerpc/platforms/512x/mpc512x_shared.c |    3 +
 5 files changed, 214 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/mpc512x_gpio.c

diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0..bd763ee 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -30,3 +30,12 @@ config MPC5121_GENERIC
 
 	  Compatible boards include:  Protonic LVT base boards (ZANMCU
 	  and VICVT2).
+
+config MPC512x_GPIO
+	bool "MPC512x GPIO support"
+	depends on PPC_MPC512x
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Say Y here if you're going to use hardware that connects to the
+	  MPC512x GPIOs.
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 90be2f5..12518e3 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -4,3 +4,4 @@
 obj-y				+= clock.o mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC5121_GENERIC)	+= mpc5121_generic.o
+obj-$(CONFIG_MPC512x_GPIO)	+= mpc512x_gpio.o
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0..4a1b094 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,7 @@ extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
+#ifdef CONFIG_MPC512x_GPIO
+extern int mpc512x_add_gpiochips(void);
+#endif
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_gpio.c b/arch/powerpc/platforms/512x/mpc512x_gpio.c
new file mode 100644
index 0000000..fc6ad82
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc512x_gpio.c
@@ -0,0 +1,198 @@
+/*
+ * MPC512x gpio driver
+ *
+ * Copyright (c) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ *
+ * derived from ppc4xx gpio driver
+ *
+ * Copyright (c) 2008 Harris Corporation
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ *
+ * Author: Steve Falco <sfalco@harris.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/types.h>
+
+#define MPC512x_GPIO_MASK(gpio) (0x80000000 >> (gpio))
+
+struct mpc512x_gpio_regs {
+	u32 gpdir;
+	u32 gpodr;
+	u32 gpdat;
+	u32 gpier;
+	u32 gpimr;
+	u32 gpicr1;
+	u32 gpicr2;
+};
+
+struct mpc512x_chip {
+	struct of_mm_gpio_chip mm_gc;
+	spinlock_t lock;
+
+	/* shadow registers */
+	u32 dat;
+	u32 odr;
+	u32 dir;
+};
+
+/*
+ * GPIO LIB API implementation for GPIOs
+ *
+ * There are a maximum of 32 gpios in each gpio controller.
+ */
+static inline struct mpc512x_chip *
+to_mpc512x_gpiochip(struct of_mm_gpio_chip *mm_gc)
+{
+	return container_of(mm_gc, struct mpc512x_chip, mm_gc);
+}
+
+static int mpc512x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+	return in_be32(&regs->gpdat) & MPC512x_GPIO_MASK(gpio);
+}
+
+static inline void
+__mpc512x_gpio_set(struct of_mm_gpio_chip *mm_gc, unsigned int gpio, int val)
+{
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+
+	if (val)
+		chip->dat |= MPC512x_GPIO_MASK(gpio);
+	else
+		chip->dat &= ~MPC512x_GPIO_MASK(gpio);
+
+	out_be32(&regs->gpdat, chip->dat);
+}
+
+static void
+mpc512x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	__mpc512x_gpio_set(mm_gc, gpio, val);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc512x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	/* Disable open-drain function */
+	chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpodr, chip->odr);
+
+	/* Float the pin */
+	chip->dir &= ~MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpdir, chip->dir);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int
+mpc512x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+	struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	/* First set initial value */
+	__mpc512x_gpio_set(mm_gc, gpio, val);
+
+	/* Disable open-drain function */
+	chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpodr, chip->odr);
+
+	/* Drive the pin */
+	chip->dir |= MPC512x_GPIO_MASK(gpio);
+	out_be32(&regs->gpdir, chip->dir);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+	return 0;
+}
+
+void __init mpc512x_add_gpiochips(void)
+{
+	struct device_node *np;
+
+	for_each_compatible_node(np, NULL, "fsl,mpc5121-gpio") {
+		int ret;
+		struct mpc512x_chip *chip;
+		struct of_mm_gpio_chip *mm_gc;
+		struct of_gpio_chip *of_gc;
+		struct gpio_chip *gc;
+
+		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+		if (!chip) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		spin_lock_init(&chip->lock);
+
+		mm_gc = &chip->mm_gc;
+		of_gc = &mm_gc->of_gc;
+		gc = &of_gc->gc;
+
+		gc->ngpio = 32;
+		gc->direction_input = mpc512x_gpio_dir_in;
+		gc->direction_output = mpc512x_gpio_dir_out;
+		gc->get = mpc512x_gpio_get;
+		gc->set = mpc512x_gpio_set;
+
+		ret = of_mm_gpiochip_add(np, mm_gc);
+		if (ret)
+			goto err;
+		continue;
+err:
+		pr_err("%s: registration failed with status %d\n",
+		       np->full_name, ret);
+		kfree(chip);
+		/* try others anyway */
+	}
+}
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 707e572..15da1bc 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -178,4 +178,7 @@ void __init mpc512x_init(void)
 	mpc5121_clk_init();
 	mpc512x_restart_init();
 	mpc512x_psc_fifo_init();
+#ifdef CONFIG_MPC512x_GPIO
+	mpc512x_add_gpiochips();
+#endif
 }
-- 
1.7.0.4

^ permalink raw reply related

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: M. Warner Losh @ 2010-06-10 16:01 UTC (permalink / raw)
  To: cbouatmailru
  Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
	linuxppc-dev
In-Reply-To: <20100610154741.GA7484@oksana.dev.rtsoft.ru>

In message: <20100610154741.GA7484@oksana.dev.rtsoft.ru>
            Anton Vorontsov <cbouatmailru@gmail.com> writes:
: On Thu, Jun 10, 2010 at 09:13:57AM -0600, M. Warner Losh wrote:
: [...]
: > : >> I told you several ways of how to improve the code (based on
: > : >> the ideas from drivers/base/, so the ideas aren't even mine,
: > : >> fwiw).
: > : >
: > : > I tend to agree with Anton here.
: > : 
: > : The reason I'm confident doing it that way is that it is *not* a
: > : structure.  There is no structure relationship between the resource
: > : table and the platform_device other than they are allocated with the
: > : same kzalloc() call.  All the code that cares about that is contained
: > : within 4 lines of code.  I'm resistant to using a structure because it
: > : is adds an additional 5-6 lines of code to add a structure that won't
: > : be used anywhere else, and is only 4 lines to begin with.
: > 
: > I tend to agree with Grant here.  The idiom he's using is very wide
: > spread in the industry and works extremely well.  It keeps the
: > ugliness confined to a couple of lines and is less ugly than the
: > alternatives for this design pattern.  It is a little surprising when
: > you see the code the first time, granted, but I think its expressive
: > power trumps that small surprise.
: 
: Oh, come on. Both constructions are binary equivalent.
: 
: So how can people seriously be with *that* code:
: 
: 	dev->resource = (void *)&dev[1];
: 
: which, semantically, is a nonsense and asks for a fix.

It isn't nonsense.  That's just your opinion of it, nothing more.

: While
: 	dev_obj->dev.resource = dev_obj->resource;
: 
: simply makes sense.

But this requires extra, bogus fields in the structure and creates a
bogus sizeof issue.

There are problems both ways.  Yelling about it isn't going to make
you any more right, or convince me that I'm wrong.  It is an argument
that is at least two decades old...

Warner

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-10 15:47 UTC (permalink / raw)
  To: M. Warner Losh
  Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
	linuxppc-dev
In-Reply-To: <20100610.091357.513168276793712624.imp@bsdimp.com>

On Thu, Jun 10, 2010 at 09:13:57AM -0600, M. Warner Losh wrote:
[...]
> : >> I told you several ways of how to improve the code (based on
> : >> the ideas from drivers/base/, so the ideas aren't even mine,
> : >> fwiw).
> : >
> : > I tend to agree with Anton here.
> : 
> : The reason I'm confident doing it that way is that it is *not* a
> : structure.  There is no structure relationship between the resource
> : table and the platform_device other than they are allocated with the
> : same kzalloc() call.  All the code that cares about that is contained
> : within 4 lines of code.  I'm resistant to using a structure because it
> : is adds an additional 5-6 lines of code to add a structure that won't
> : be used anywhere else, and is only 4 lines to begin with.
> 
> I tend to agree with Grant here.  The idiom he's using is very wide
> spread in the industry and works extremely well.  It keeps the
> ugliness confined to a couple of lines and is less ugly than the
> alternatives for this design pattern.  It is a little surprising when
> you see the code the first time, granted, but I think its expressive
> power trumps that small surprise.

Oh, come on. Both constructions are binary equivalent.

So how can people seriously be with *that* code:

	dev->resource = (void *)&dev[1];

which, semantically, is a nonsense and asks for a fix.

While
	dev_obj->dev.resource = dev_obj->resource;

simply makes sense.

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Steven A. Falco @ 2010-06-10 15:27 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <201006101631.29591.arnd@arndb.de>

On 06/10/2010 10:31 AM, Arnd Bergmann wrote:
> 
> On Thursday 10 June 2010, Steven A. Falco wrote:
>> I believe there is a bug in the way the ibm_newemac driver handles the
>> SIOCGMIIREG (and SIOCSMIIREG) ioctl.  The problem is that emac_ioctl
>> is handed a "struct ifreq *rq" which contains a user-land pointer to
>> an array of 16-bit integers.
> 
> Did you actually see a bug here, or just think that this could be
> a problem?

I did see a problem.  I tried using the ioctl, and I didn't get the
correct result.  I then added some printk in the driver, and saw that
garbage was being passed in the data array.

I added the copy_from/copy_to, and the ioctl started working.

> 
>> However, emac_ioctl directly accesses the data, which doesn't work.
>> I added the following patch to copy the data in and out.
>>
>> Please note that this patch was tested in an older kernel (2.6.30)
>> because that is what we are using on our custom hardware.  I think
>> this is still a problem in the current code, but I'd like reviewers
>> to take a look, to be sure.
> 
> The ifreq structure passed into the ndo_ioctl function is in kernel
> space, it gets copied there by net/core/dev.c:dev_ioctl().
> emac_ioctl only accesses the data in that structure, so a copy_from_user
> is wrong here as far as I can tell.

net/core/dev.c:dev_ioctl() does a copy_from_user on the overall structure,
but the structure contains a union, one member of which is an embedded
pointer to an array.  This pointer member is only used in the case of these
two ioctls.  Other ioctls use different union members, which are not pointers.

As I understand it, the copy_from_user in dev_ioctl does not recursively
copy the array.  In fact it could not do so, because the pointer to array
is only 4 bytes long, while the array itself is 8 bytes long - so it would
not fit.  I.e., dev_ioctl would have to allocate storage, and do a second
copy_from_user to retrieve the array.  It would have to clean up after the
emac_ioctl ran.  And it would have to do this only for these specific
ioctl calls which use the array pointer in the union.

Also, the result has to be returned to the user in the same array, which
needs a copy_to_user of the array data, which is also not done in dev_ioctl.

So I think this second copy_from/copy_to needs to be done somewhere.  I
added it in the emac_ioctl because that is where the command is fully
decoded.  It also avoids the problem of allocating space for the copied
array.  But other fixes are certainly possible as well, which is why I am
not sure I've hit on the "proper" fix.

Thanks very much for reviewing - please let me know if my explanation is
unclear, or if you see a better way to fix this problem.

	Steve

> 
> 	Arnd


-- 
A: Because it makes the logic of the discussion difficult to follow.
Q: Why shouldn't I top post?
A: No.
Q: Should I top post?

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: M. Warner Losh @ 2010-06-10 15:13 UTC (permalink / raw)
  To: grant.likely
  Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
	linuxppc-dev
In-Reply-To: <AANLkTilpUi1cazljWSFbzliY78RKyHUlvBshUD3NPHPv@mail.gmail.com>

In message: <AANLkTilpUi1cazljWSFbzliY78RKyHUlvBshUD3NPHPv@mail.gmail.com>
            Grant Likely <grant.likely@secretlab.ca> writes:
: On Thu, Jun 10, 2010 at 12:17 AM, Benjamin Herrenschmidt
: <benh@kernel.crashing.org> wrote:
: >
: >> You just introduced an unnamed structure of device + resources,
: >> it isn't declared anywhere but in the code itself (either via
: >> &foo[1] or buf + sizeof(*foo)).
: >>
: >> You're not the only one who hacks (or at least have to
: >> understand) the OF stuff, so let's try keep this stuff
: >> readable?
: >>
: >> I told you several ways of how to improve the code (based on
: >> the ideas from drivers/base/, so the ideas aren't even mine,
: >> fwiw).
: >
: > I tend to agree with Anton here.
: 
: The reason I'm confident doing it that way is that it is *not* a
: structure.  There is no structure relationship between the resource
: table and the platform_device other than they are allocated with the
: same kzalloc() call.  All the code that cares about that is contained
: within 4 lines of code.  I'm resistant to using a structure because it
: is adds an additional 5-6 lines of code to add a structure that won't
: be used anywhere else, and is only 4 lines to begin with.

I tend to agree with Grant here.  The idiom he's using is very wide
spread in the industry and works extremely well.  It keeps the
ugliness confined to a couple of lines and is less ugly than the
alternatives for this design pattern.  It is a little surprising when
you see the code the first time, granted, but I think its expressive
power trumps that small surprise.

Warner

^ permalink raw reply

* Re: [PATCH] [powerpc] do not expect executable permissions for in-tree shell scripts
From: Olaf Hering @ 2010-06-10 15:20 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, stable, Sean MacLennan
In-Reply-To: <1276151189.1962.47.camel@pasglop>

On Thu, Jun 10, Benjamin Herrenschmidt wrote:

> I still don't like it very much.. why not chmod'ing it +x instead ? :-)

I looked at a few other scripts in the source tree, they are called with
$(CONFIG_SHELL) <name>, or perl <name>, or awk <name> or even sh <name>.

So my change adds some sort of consistency and makes packaging more robust.


Olaf

^ permalink raw reply

* Re: [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Arnd Bergmann @ 2010-06-10 14:31 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <4C10EFE0.6030106@harris.com>

On Thursday 10 June 2010, Steven A. Falco wrote:
> I believe there is a bug in the way the ibm_newemac driver handles the
> SIOCGMIIREG (and SIOCSMIIREG) ioctl.  The problem is that emac_ioctl
> is handed a "struct ifreq *rq" which contains a user-land pointer to
> an array of 16-bit integers.

Did you actually see a bug here, or just think that this could be
a problem?

> However, emac_ioctl directly accesses the data, which doesn't work.
> I added the following patch to copy the data in and out.
> 
> Please note that this patch was tested in an older kernel (2.6.30)
> because that is what we are using on our custom hardware.  I think
> this is still a problem in the current code, but I'd like reviewers
> to take a look, to be sure.

The ifreq structure passed into the ndo_ioctl function is in kernel
space, it gets copied there by net/core/dev.c:dev_ioctl().
emac_ioctl only accesses the data in that structure, so a copy_from_user
is wrong here as far as I can tell.

	Arnd

^ permalink raw reply

* Re: [PATCH 5/5] of/address: restrict 'no-ranges' kludge to powerpc
From: Grant Likely @ 2010-06-10 14:28 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Stephen Rothwell, devicetree-discuss, linuxppc-dev
In-Reply-To: <1276152275.1962.61.camel@pasglop>

On Thu, Jun 10, 2010 at 12:44 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
>> Certain Apple machines don't use the ranges property correctly, but the
>> workaround should not be applied on other architectures. =A0This patch
>> disables the workaround for non-powerpc architectures.
>
> I'm half tempted to add it to the quirk list (which should really be
> made generic) so I can disable it on more 'modern' powerpc as well.

In the mean time, are you okay with this version of the patch?

g.

>
> Cheers,
> Ben.
>
>> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
>> CC: Stephen Rothwell <sfr@canb.auug.org.au>
>> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> CC: linuxppc-dev@lists.ozlabs.org
>> CC: devicetree-discuss@lists.ozlabs.org
>> ---
>> =A0drivers/of/address.c | =A0 11 ++++++++++-
>> =A01 files changed, 10 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/of/address.c b/drivers/of/address.c
>> index 0b04137..5c220c3 100644
>> --- a/drivers/of/address.c
>> +++ b/drivers/of/address.c
>> @@ -346,12 +346,21 @@ static int of_translate_one(struct device_node *pa=
rent, struct of_bus *bus,
>> =A0 =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller =
not to try
>> =A0 =A0 =A0 =A0* to translate addresses that aren't supposed to be trans=
lated in
>> =A0 =A0 =A0 =A0* the first place. --BenH.
>> + =A0 =A0 =A0*
>> + =A0 =A0 =A0* As far as we know, this damage only exists on Apple machi=
nes, so
>> + =A0 =A0 =A0* This code is only enabled on powerpc. --gcl
>> =A0 =A0 =A0 =A0*/
>> =A0 =A0 =A0 ranges =3D of_get_property(parent, rprop, &rlen);
>> +#if !defined(CONFIG_PPC)
>> + =A0 =A0 if (ranges =3D=3D NULL) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_err("OF: no ranges; cannot translate\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> + =A0 =A0 }
>> +#endif /* !defined(CONFIG_PPC) */
>> =A0 =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: no ranges, 1:1 translation\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: empty ranges; 1:1 translation\n"=
);
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> =A0 =A0 =A0 }
>>
>
>
>



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

^ permalink raw reply

* Re: [PATCH 3/5] of/address: Merge all of the bus translation code
From: Grant Likely @ 2010-06-10 14:26 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev, Stephen Rothwell, Michal Simek, microblaze-uclinux
In-Reply-To: <1276152212.1962.59.camel@pasglop>

On Thu, Jun 10, 2010 at 12:43 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
>> Microblaze and PowerPC share a large chunk of code for translating
>> OF device tree data into usable addresses. =A0There aren't many differen=
ces
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ^^^^
> Care to comment on these differences ?

Purely cosmetic IIRC, but I will go back and double check.  Things
like printk vs. pr_info and some style differences.  I looked at them
side-by-side and fixed each difference individually until they were
identical.

>> between the two, so merge the codebase wholesale rather than trying to
>> work out the independent bits.
>
> Well, I don't see ifdef's in the resulting code (but I'm a bit blind),
> so what did you do with the differences ?
>
> This is complex and fragile code, so any change to it must be very
> carefully scrutinized.
>
> Cheers,
> Ben.
>
>> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
>> CC: Michal Simek <monstr@monstr.eu>
>> CC: Wolfram Sang <w.sang@pengutronix.de>
>> CC: Stephen Rothwell <sfr@canb.auug.org.au>
>> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> CC: microblaze-uclinux@itee.uq.edu.au
>> CC: linuxppc-dev@ozlabs.org
>> ---
>> =A0arch/microblaze/include/asm/prom.h =A0| =A0 =A04
>> =A0arch/microblaze/kernel/prom_parse.c | =A0489 ------------------------=
---------
>> =A0arch/powerpc/include/asm/prom.h =A0 =A0 | =A0 =A04
>> =A0arch/powerpc/kernel/prom_parse.c =A0 =A0| =A0515 --------------------=
---------------
>> =A0drivers/of/address.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0517 ++++++++=
+++++++++++++++++++++++++++
>> =A0include/linux/of_address.h =A0 =A0 =A0 =A0 =A0| =A0 =A04
>> =A06 files changed, 515 insertions(+), 1018 deletions(-)
>>
>> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/includ=
e/asm/prom.h
>> index 644fa32..35cb3de 100644
>> --- a/arch/microblaze/include/asm/prom.h
>> +++ b/arch/microblaze/include/asm/prom.h
>> @@ -52,10 +52,6 @@ extern void pci_create_OF_bus_map(void);
>> =A0 * OF address retreival & translation
>> =A0 */
>>
>> -/* Translate an OF address block into a CPU physical address
>> - */
>> -extern u64 of_translate_address(struct device_node *np, const u32 *addr=
);
>> -
>> =A0/* Extract an address from a device, returns the region size and
>> =A0 * the address space flags too. The PCI version uses a BAR number
>> =A0 * instead of an absolute index
>> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kerne=
l/prom_parse.c
>> index 7cb5a98..1d610e6 100644
>> --- a/arch/microblaze/kernel/prom_parse.c
>> +++ b/arch/microblaze/kernel/prom_parse.c
>> @@ -10,213 +10,7 @@
>> =A0#include <asm/prom.h>
>> =A0#include <asm/pci-bridge.h>
>>
>> -#define PRu64 =A0 =A0 =A0 =A0"%llx"
>> -
>> -/* Max address size we deal with */
>> -#define OF_MAX_ADDR_CELLS =A0 =A04
>> -#define OF_CHECK_COUNTS(na, ns) =A0 =A0 =A0((na) > 0 && (na) <=3D OF_MA=
X_ADDR_CELLS && \
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (ns) > 0)
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np);
>> -
>> -/* Debug utility */
>> -#ifdef DEBUG
>> -static void of_dump_addr(const char *s, const u32 *addr, int na)
>> -{
>> - =A0 =A0 printk(KERN_INFO "%s", s);
>> - =A0 =A0 while (na--)
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_INFO " %08x", *(addr++));
>> - =A0 =A0 printk(KERN_INFO "\n");
>> -}
>> -#else
>> -static void of_dump_addr(const char *s, const u32 *addr, int na) { }
>> -#endif
>> -
>> -/* Callbacks for bus specific translators */
>> -struct of_bus {
>> - =A0 =A0 const char =A0 =A0 =A0*name;
>> - =A0 =A0 const char =A0 =A0 =A0*addresses;
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*match)(struct device_node *paren=
t);
>> - =A0 =A0 void =A0 =A0 =A0 =A0 =A0 =A0(*count_cells)(struct device_node =
*child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 int *addrc, int *sizec);
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 (*map)(u32 *addr, const u32 *range=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns=
, int pna);
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*translate)(u32 *addr, u64 offset=
, int na);
>> - =A0 =A0 unsigned int =A0 =A0(*get_flags)(const u32 *addr);
>> -};
>> -
>> -/*
>> - * Default translator (generic bus)
>> - */
>> -
>> -static void of_bus_default_count_cells(struct device_node *dev,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 int *addrc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D of_n_addr_cells(dev);
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D of_n_size_cells(dev);
>> -}
>> -
>> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
>> - =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 cp =3D of_read_number(range, na);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr, na);
>> -
>> - =A0 =A0 pr_debug("OF: default map, cp=3D"PRu64", s=3D"PRu64", da=3D"PR=
u64"\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 u64 a =3D of_read_number(addr, na);
>> - =A0 =A0 memset(addr, 0, na * 4);
>> - =A0 =A0 a +=3D offset;
>> - =A0 =A0 if (na > 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 addr[na - 2] =3D a >> 32;
>> - =A0 =A0 addr[na - 1] =3D a & 0xffffffffu;
>> -
>> - =A0 =A0 return 0;
>> -}
>> -
>> -static unsigned int of_bus_default_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 return IORESOURCE_MEM;
>> -}
>> -
>> =A0#ifdef CONFIG_PCI
>> -/*
>> - * PCI bus specific translator
>> - */
>> -
>> -static int of_bus_pci_match(struct device_node *np)
>> -{
>> - =A0 =A0 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
>> - =A0 =A0 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
>> -}
>> -
>> -static void of_bus_pci_count_cells(struct device_node *np,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int *addrc, in=
t *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 3;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 2;
>> -}
>> -
>> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((addr[0] ^ range[0]) & 0x03000000)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 pr_debug("OF: PCI map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"=
\n", cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 switch ((w >> 24) & 0x03) {
>> - =A0 =A0 case 0x01:
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 case 0x02: /* 32 bits */
>> - =A0 =A0 case 0x03: /* 64 bits */
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (w & 0x40000000)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_PREFETCH;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 =
*size,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 if (strcmp(bus->name, "pci")) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 }
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if ((prop[0] & 0xff) =3D=3D ((bar_no * 4) + PC=
I_BASE_ADDRESS_0)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_pci_address);
>> -
>> -int of_pci_address_to_resource(struct device_node *dev, int bar,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct resourc=
e *r)
>> -{
>> - =A0 =A0 const u32 =A0 =A0 =A0 *addrp;
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 size;
>> - =A0 =A0 unsigned int =A0 =A0flags;
>> -
>> - =A0 =A0 addrp =3D of_get_pci_address(dev, bar, &size, &flags);
>> - =A0 =A0 if (addrp =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
>> - =A0 =A0 return __of_address_to_resource(dev, addrp, size, flags, r);
>> -}
>> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
>> -
>> -static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
>> -{
>> - =A0 =A0 return (((pin - 1) + slot) % 4) + 1;
>> -}
>> -
>> =A0int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>> =A0{
>> =A0 =A0 =A0 struct device_node *dn, *ppnode;
>> @@ -291,289 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_=
irq *out_irq)
>> =A0EXPORT_SYMBOL_GPL(of_irq_map_pci);
>> =A0#endif /* CONFIG_PCI */
>>
>> -/*
>> - * ISA bus specific translator
>> - */
>> -
>> -static int of_bus_isa_match(struct device_node *np)
>> -{
>> - =A0 =A0 return !strcmp(np->name, "isa");
>> -}
>> -
>> -static void of_bus_isa_count_cells(struct device_node *child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int *addrc, in=
t *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 2;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 1;
>> -}
>> -
>> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((addr[0] ^ range[0]) & 0x00000001)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 pr_debug("OF: ISA map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"=
\n", cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 if (w & 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 else
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -/*
>> - * Array of bus specific translators
>> - */
>> -
>> -static struct of_bus of_busses[] =3D {
>> -#ifdef CONFIG_PCI
>> - =A0 =A0 /* PCI */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "pci",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "assigned-addresses",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_pci_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_pci_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_pci_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_pci_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_pci_get_flags,
>> - =A0 =A0 },
>> -#endif /* CONFIG_PCI */
>> - =A0 =A0 /* ISA */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "isa",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_isa_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_isa_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_isa_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_isa_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_isa_get_flags,
>> - =A0 =A0 },
>> - =A0 =A0 /* Default */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "default",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D NULL,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_default_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_default_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_default_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_default_get_flags,
>> - =A0 =A0 },
>> -};
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np)
>> -{
>> - =A0 =A0 int i;
>> -
>> - =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(of_busses); i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!of_busses[i].match || of_busses[i].match(=
np))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &of_busses[i];
>> - =A0 =A0 BUG();
>> - =A0 =A0 return NULL;
>> -}
>> -
>> -static int of_translate_one(struct device_node *parent, struct of_bus *=
bus,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct of_bus *pbus, u32 *addr=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> -{
>> - =A0 =A0 const u32 *ranges;
>> - =A0 =A0 unsigned int rlen;
>> - =A0 =A0 int rone;
>> - =A0 =A0 u64 offset =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Normally, an absence of a "ranges" property means we are
>> - =A0 =A0 =A0* crossing a non-translatable boundary, and thus the addres=
ses
>> - =A0 =A0 =A0* below the current not cannot be converted to CPU physical=
 ones.
>> - =A0 =A0 =A0* Unfortunately, while this is very clear in the spec, it's=
 not
>> - =A0 =A0 =A0* what Apple understood, and they do have things like /uni-=
n or
>> - =A0 =A0 =A0* /ht nodes with no "ranges" property and a lot of perfectl=
y
>> - =A0 =A0 =A0* useable mapped devices below them. Thus we treat the abse=
nce of
>> - =A0 =A0 =A0* "ranges" as equivalent to an empty "ranges" property whic=
h means
>> - =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller no=
t to try
>> - =A0 =A0 =A0* to translate addresses that aren't supposed to be transla=
ted in
>> - =A0 =A0 =A0* the first place. --BenH.
>> - =A0 =A0 =A0*/
>> - =A0 =A0 ranges =3D of_get_property(parent, "ranges", (int *) &rlen);
>> - =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: no ranges, 1:1 translation\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> - =A0 =A0 }
>> -
>> - =A0 =A0 pr_debug("OF: walking ranges...\n");
>> -
>> - =A0 =A0 /* Now walk through the ranges */
>> - =A0 =A0 rlen /=3D 4;
>> - =A0 =A0 rone =3D na + pna + ns;
>> - =A0 =A0 for (; rlen >=3D rone; rlen -=3D rone, ranges +=3D rone) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D bus->map(addr, ranges, na, ns, pna)=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (offset !=3D OF_BAD_ADDR)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (offset =3D=3D OF_BAD_ADDR) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: not found !\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, ranges + na, 4 * pna);
>> -
>> - finish:
>> - =A0 =A0 of_dump_addr("OF: parent translation for:", addr, pna);
>> - =A0 =A0 pr_debug("OF: with offset: "PRu64"\n", offset);
>> -
>> - =A0 =A0 /* Translate it into parent bus space */
>> - =A0 =A0 return pbus->translate(addr, offset, pna);
>> -}
>> -
>> -/*
>> - * Translate an address from the device-tree into a CPU physical addres=
s,
>> - * this walks up the tree and applies the various bus mappings on the
>> - * way.
>> - *
>> - * Note: We consider that crossing any level with #size-cells =3D=3D 0 =
to mean
>> - * that translation is impossible (that is we are not dealing with a va=
lue
>> - * that can be mapped to a cpu physical address). This is not really sp=
ecified
>> - * that way, but this is traditionally the way IBM at least do things
>> - */
>> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
>> -{
>> - =A0 =A0 struct device_node *parent =3D NULL;
>> - =A0 =A0 struct of_bus *bus, *pbus;
>> - =A0 =A0 u32 addr[OF_MAX_ADDR_CELLS];
>> - =A0 =A0 int na, ns, pna, pns;
>> - =A0 =A0 u64 result =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 pr_debug("OF: ** translation for device %s **\n", dev->full_na=
me);
>> -
>> - =A0 =A0 /* Increase refcount at current level */
>> - =A0 =A0 of_node_get(dev);
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> -
>> - =A0 =A0 /* Cound address cells & copy address locally */
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: Bad cell count fo=
r %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev->full_name);
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, in_addr, na * 4);
>> -
>> - =A0 =A0 pr_debug("OF: bus is %s (na=3D%d, ns=3D%d) on %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 bus->name, na, ns, parent->full_name);
>> - =A0 =A0 of_dump_addr("OF: translating address:", addr, na);
>> -
>> - =A0 =A0 /* Translate */
>> - =A0 =A0 for (;;) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Switch to parent bus */
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dev);
>> - =A0 =A0 =A0 =A0 =A0 =A0 dev =3D parent;
>> - =A0 =A0 =A0 =A0 =A0 =A0 parent =3D of_get_parent(dev);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* If root, we have finished */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (parent =3D=3D NULL) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: reached root nod=
e\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 result =3D of_read_number(addr=
, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Get new parent bus and counts */
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus =3D of_match_bus(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus->count_cells(dev, &pna, &pns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!OF_CHECK_COUNTS(pna, pns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: B=
ad cell count for %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev->full_name=
);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: parent bus is %s (na=3D%d, ns=3D=
%d) on %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pbus->name, pna, pns, parent->=
full_name);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Apply bus translation */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (of_translate_one(dev, bus, pbus, addr, na,=
 ns, pna))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Complete the move up one level */
>> - =A0 =A0 =A0 =A0 =A0 =A0 na =3D pna;
>> - =A0 =A0 =A0 =A0 =A0 =A0 ns =3D pns;
>> - =A0 =A0 =A0 =A0 =A0 =A0 bus =3D pbus;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_dump_addr("OF: one level translation:", add=
r, na);
>> - =A0 =A0 }
>> - bail:
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 of_node_put(dev);
>> -
>> - =A0 =A0 return result;
>> -}
>> -EXPORT_SYMBOL(of_translate_address);
>> -
>> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, (int *) &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D index) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_address);
>> -
>> =A0void of_parse_dma_window(struct device_node *dn, const void *dma_wind=
ow_prop,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned long *busno, unsigned long *phys, u=
nsigned long *size)
>> =A0{
>> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/=
prom.h
>> index e1c1bdd..8e1d0fe 100644
>> --- a/arch/powerpc/include/asm/prom.h
>> +++ b/arch/powerpc/include/asm/prom.h
>> @@ -45,10 +45,6 @@ extern void pci_create_OF_bus_map(void);
>> =A0 * OF address retreival & translation
>> =A0 */
>>
>> -/* Translate an OF address block into a CPU physical address
>> - */
>> -extern u64 of_translate_address(struct device_node *np, const u32 *addr=
);
>> -
>> =A0/* Translate a DMA address from device space to CPU space */
>> =A0extern u64 of_translate_dma_address(struct device_node *dev,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cons=
t u32 *in_addr);
>> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom=
_parse.c
>> index a2ef129..64f2606 100644
>> --- a/arch/powerpc/kernel/prom_parse.c
>> +++ b/arch/powerpc/kernel/prom_parse.c
>> @@ -10,225 +10,7 @@
>> =A0#include <asm/prom.h>
>> =A0#include <asm/pci-bridge.h>
>>
>> -#ifdef DEBUG
>> -#define DBG(fmt...) do { printk(fmt); } while(0)
>> -#else
>> -#define DBG(fmt...) do { } while(0)
>> -#endif
>> -
>> -#ifdef CONFIG_PPC64
>> -#define PRu64 =A0 =A0 =A0 =A0"%lx"
>> -#else
>> -#define PRu64 =A0 =A0 =A0 =A0"%llx"
>> -#endif
>> -
>> -/* Max address size we deal with */
>> -#define OF_MAX_ADDR_CELLS =A0 =A04
>> -#define OF_CHECK_COUNTS(na, ns) =A0 =A0 =A0((na) > 0 && (na) <=3D OF_MA=
X_ADDR_CELLS && \
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (ns) > 0)
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np);
>> -
>> -/* Debug utility */
>> -#ifdef DEBUG
>> -static void of_dump_addr(const char *s, const u32 *addr, int na)
>> -{
>> - =A0 =A0 printk("%s", s);
>> - =A0 =A0 while(na--)
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(" %08x", *(addr++));
>> - =A0 =A0 printk("\n");
>> -}
>> -#else
>> -static void of_dump_addr(const char *s, const u32 *addr, int na) { }
>> -#endif
>> -
>> -
>> -/* Callbacks for bus specific translators */
>> -struct of_bus {
>> - =A0 =A0 const char =A0 =A0 =A0*name;
>> - =A0 =A0 const char =A0 =A0 =A0*addresses;
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*match)(struct device_node *paren=
t);
>> - =A0 =A0 void =A0 =A0 =A0 =A0 =A0 =A0(*count_cells)(struct device_node =
*child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec);
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 (*map)(u32 *addr, const u32 *range=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns=
, int pna);
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*translate)(u32 *addr, u64 offset=
, int na);
>> - =A0 =A0 unsigned int =A0 =A0(*get_flags)(const u32 *addr);
>> -};
>> -
>> -
>> -/*
>> - * Default translator (generic bus)
>> - */
>> -
>> -static void of_bus_default_count_cells(struct device_node *dev,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D of_n_addr_cells(dev);
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D of_n_size_cells(dev);
>> -}
>> -
>> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
>> - =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 cp =3D of_read_number(range, na);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr, na);
>> -
>> - =A0 =A0 DBG("OF: default map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"\=
n",
>> - =A0 =A0 =A0 =A0 cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 u64 a =3D of_read_number(addr, na);
>> - =A0 =A0 memset(addr, 0, na * 4);
>> - =A0 =A0 a +=3D offset;
>> - =A0 =A0 if (na > 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 addr[na - 2] =3D a >> 32;
>> - =A0 =A0 addr[na - 1] =3D a & 0xffffffffu;
>> -
>> - =A0 =A0 return 0;
>> -}
>> -
>> -static unsigned int of_bus_default_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 return IORESOURCE_MEM;
>> -}
>> -
>> -
>> =A0#ifdef CONFIG_PCI
>> -/*
>> - * PCI bus specific translator
>> - */
>> -
>> -static int of_bus_pci_match(struct device_node *np)
>> -{
>> - =A0 =A0 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
>> - =A0 =A0 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
>> -}
>> -
>> -static void of_bus_pci_count_cells(struct device_node *np,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 3;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 2;
>> -}
>> -
>> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 switch((w >> 24) & 0x03) {
>> - =A0 =A0 case 0x01:
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 case 0x02: /* 32 bits */
>> - =A0 =A0 case 0x03: /* 64 bits */
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (w & 0x40000000)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_PREFETCH;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> - =A0 =A0 unsigned int af, rf;
>> -
>> - =A0 =A0 af =3D of_bus_pci_get_flags(addr);
>> - =A0 =A0 rf =3D of_bus_pci_get_flags(range);
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 DBG("OF: PCI map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"\n", =
cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 =
*size,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 if (strcmp(bus->name, "pci")) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 }
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if ((prop[0] & 0xff) =3D=3D ((bar_no * 4) + PC=
I_BASE_ADDRESS_0)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_pci_address);
>> -
>> -int of_pci_address_to_resource(struct device_node *dev, int bar,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct resource=
 *r)
>> -{
>> - =A0 =A0 const u32 =A0 =A0 =A0 *addrp;
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 size;
>> - =A0 =A0 unsigned int =A0 =A0flags;
>> -
>> - =A0 =A0 addrp =3D of_get_pci_address(dev, bar, &size, &flags);
>> - =A0 =A0 if (addrp =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
>> - =A0 =A0 return __of_address_to_resource(dev, addrp, size, flags, r);
>> -}
>> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
>> -
>> =A0int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>> =A0{
>> =A0 =A0 =A0 struct device_node *dn, *ppnode;
>> @@ -310,303 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_=
irq *out_irq)
>> =A0EXPORT_SYMBOL_GPL(of_irq_map_pci);
>> =A0#endif /* CONFIG_PCI */
>>
>> -/*
>> - * ISA bus specific translator
>> - */
>> -
>> -static int of_bus_isa_match(struct device_node *np)
>> -{
>> - =A0 =A0 return !strcmp(np->name, "isa");
>> -}
>> -
>> -static void of_bus_isa_count_cells(struct device_node *child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 2;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 1;
>> -}
>> -
>> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((addr[0] ^ range[0]) & 0x00000001)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 DBG("OF: ISA map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"\n", =
cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 if (w & 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 else
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -
>> -/*
>> - * Array of bus specific translators
>> - */
>> -
>> -static struct of_bus of_busses[] =3D {
>> -#ifdef CONFIG_PCI
>> - =A0 =A0 /* PCI */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "pci",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "assigned-addresses",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_pci_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_pci_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_pci_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_pci_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_pci_get_flags,
>> - =A0 =A0 },
>> -#endif /* CONFIG_PCI */
>> - =A0 =A0 /* ISA */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "isa",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_isa_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_isa_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_isa_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_isa_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_isa_get_flags,
>> - =A0 =A0 },
>> - =A0 =A0 /* Default */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "default",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D NULL,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_default_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_default_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_default_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_default_get_flags,
>> - =A0 =A0 },
>> -};
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np)
>> -{
>> - =A0 =A0 int i;
>> -
>> - =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(of_busses); i ++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!of_busses[i].match || of_busses[i].match(=
np))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &of_busses[i];
>> - =A0 =A0 BUG();
>> - =A0 =A0 return NULL;
>> -}
>> -
>> -static int of_translate_one(struct device_node *parent, struct of_bus *=
bus,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct of_bus *pbus, u=
32 *addr,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pn=
a, const char *rprop)
>> -{
>> - =A0 =A0 const u32 *ranges;
>> - =A0 =A0 unsigned int rlen;
>> - =A0 =A0 int rone;
>> - =A0 =A0 u64 offset =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Normally, an absence of a "ranges" property means we are
>> - =A0 =A0 =A0* crossing a non-translatable boundary, and thus the addres=
ses
>> - =A0 =A0 =A0* below the current not cannot be converted to CPU physical=
 ones.
>> - =A0 =A0 =A0* Unfortunately, while this is very clear in the spec, it's=
 not
>> - =A0 =A0 =A0* what Apple understood, and they do have things like /uni-=
n or
>> - =A0 =A0 =A0* /ht nodes with no "ranges" property and a lot of perfectl=
y
>> - =A0 =A0 =A0* useable mapped devices below them. Thus we treat the abse=
nce of
>> - =A0 =A0 =A0* "ranges" as equivalent to an empty "ranges" property whic=
h means
>> - =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller no=
t to try
>> - =A0 =A0 =A0* to translate addresses that aren't supposed to be transla=
ted in
>> - =A0 =A0 =A0* the first place. --BenH.
>> - =A0 =A0 =A0*/
>> - =A0 =A0 ranges =3D of_get_property(parent, rprop, &rlen);
>> - =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> - =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: no ranges, 1:1 translation\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> - =A0 =A0 }
>> -
>> - =A0 =A0 DBG("OF: walking ranges...\n");
>> -
>> - =A0 =A0 /* Now walk through the ranges */
>> - =A0 =A0 rlen /=3D 4;
>> - =A0 =A0 rone =3D na + pna + ns;
>> - =A0 =A0 for (; rlen >=3D rone; rlen -=3D rone, ranges +=3D rone) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D bus->map(addr, ranges, na, ns, pna)=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (offset !=3D OF_BAD_ADDR)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (offset =3D=3D OF_BAD_ADDR) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: not found !\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, ranges + na, 4 * pna);
>> -
>> - finish:
>> - =A0 =A0 of_dump_addr("OF: parent translation for:", addr, pna);
>> - =A0 =A0 DBG("OF: with offset: "PRu64"\n", offset);
>> -
>> - =A0 =A0 /* Translate it into parent bus space */
>> - =A0 =A0 return pbus->translate(addr, offset, pna);
>> -}
>> -
>> -
>> -/*
>> - * Translate an address from the device-tree into a CPU physical addres=
s,
>> - * this walks up the tree and applies the various bus mappings on the
>> - * way.
>> - *
>> - * Note: We consider that crossing any level with #size-cells =3D=3D 0 =
to mean
>> - * that translation is impossible (that is we are not dealing with a va=
lue
>> - * that can be mapped to a cpu physical address). This is not really sp=
ecified
>> - * that way, but this is traditionally the way IBM at least do things
>> - */
>> -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *rprop)
>> -{
>> - =A0 =A0 struct device_node *parent =3D NULL;
>> - =A0 =A0 struct of_bus *bus, *pbus;
>> - =A0 =A0 u32 addr[OF_MAX_ADDR_CELLS];
>> - =A0 =A0 int na, ns, pna, pns;
>> - =A0 =A0 u64 result =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 DBG("OF: ** translation for device %s **\n", dev->full_name);
>> -
>> - =A0 =A0 /* Increase refcount at current level */
>> - =A0 =A0 of_node_get(dev);
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> -
>> - =A0 =A0 /* Cound address cells & copy address locally */
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: Bad cell count fo=
r %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name);
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, in_addr, na * 4);
>> -
>> - =A0 =A0 DBG("OF: bus is %s (na=3D%d, ns=3D%d) on %s\n",
>> - =A0 =A0 =A0 =A0 bus->name, na, ns, parent->full_name);
>> - =A0 =A0 of_dump_addr("OF: translating address:", addr, na);
>> -
>> - =A0 =A0 /* Translate */
>> - =A0 =A0 for (;;) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Switch to parent bus */
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dev);
>> - =A0 =A0 =A0 =A0 =A0 =A0 dev =3D parent;
>> - =A0 =A0 =A0 =A0 =A0 =A0 parent =3D of_get_parent(dev);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* If root, we have finished */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (parent =3D=3D NULL) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: reached root node\n")=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 result =3D of_read_number(addr=
, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Get new parent bus and counts */
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus =3D of_match_bus(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus->count_cells(dev, &pna, &pns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!OF_CHECK_COUNTS(pna, pns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: B=
ad cell count for %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name)=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: parent bus is %s (na=3D%d, ns=3D%d) o=
n %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pbus->name, pna, pns, parent->full_nam=
e);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Apply bus translation */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (of_translate_one(dev, bus, pbus, addr, na,=
 ns, pna, rprop))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Complete the move up one level */
>> - =A0 =A0 =A0 =A0 =A0 =A0 na =3D pna;
>> - =A0 =A0 =A0 =A0 =A0 =A0 ns =3D pns;
>> - =A0 =A0 =A0 =A0 =A0 =A0 bus =3D pbus;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_dump_addr("OF: one level translation:", add=
r, na);
>> - =A0 =A0 }
>> - bail:
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 of_node_put(dev);
>> -
>> - =A0 =A0 return result;
>> -}
>> -
>> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
>> -{
>> - =A0 =A0 return __of_translate_address(dev, in_addr, "ranges");
>> -}
>> -EXPORT_SYMBOL(of_translate_address);
>> -
>> -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_add=
r)
>> -{
>> - =A0 =A0 return __of_translate_address(dev, in_addr, "dma-ranges");
>> -}
>> -EXPORT_SYMBOL(of_translate_dma_address);
>> -
>> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D index) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_address);
>> -
>> =A0void of_parse_dma_window(struct device_node *dn, const void *dma_wind=
ow_prop,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned long *busno, unsigned long *phys, u=
nsigned long *size)
>> =A0{
>> diff --git a/drivers/of/address.c b/drivers/of/address.c
>> index c381955..2a905d5 100644
>> --- a/drivers/of/address.c
>> +++ b/drivers/of/address.c
>> @@ -1,11 +1,522 @@
>>
>> =A0#include <linux/io.h>
>> =A0#include <linux/ioport.h>
>> +#include <linux/module.h>
>> =A0#include <linux/of_address.h>
>> +#include <linux/pci_regs.h>
>> +#include <linux/string.h>
>>
>> -int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u64 size, unsigned =
int flags,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct resource *r)
>> +/* Max address size we deal with */
>> +#define OF_MAX_ADDR_CELLS =A0 =A04
>> +#define OF_CHECK_COUNTS(na, ns) =A0 =A0 =A0((na) > 0 && (na) <=3D OF_MA=
X_ADDR_CELLS && \
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (ns) > 0)
>> +
>> +static struct of_bus *of_match_bus(struct device_node *np);
>> +static int __of_address_to_resource(struct device_node *dev, const u32 =
*addrp,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u64 si=
ze, unsigned int flags,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct=
 resource *r);
>> +
>> +/* Debug utility */
>> +#ifdef DEBUG
>> +static void of_dump_addr(const char *s, const u32 *addr, int na)
>> +{
>> + =A0 =A0 printk(KERN_DEBUG "%s", s);
>> + =A0 =A0 while (na--)
>> + =A0 =A0 =A0 =A0 =A0 =A0 printk(" %08x", *(addr++));
>> + =A0 =A0 printk("\n");
>> +}
>> +#else
>> +static void of_dump_addr(const char *s, const u32 *addr, int na) { }
>> +#endif
>> +
>> +/* Callbacks for bus specific translators */
>> +struct of_bus {
>> + =A0 =A0 const char =A0 =A0 =A0*name;
>> + =A0 =A0 const char =A0 =A0 =A0*addresses;
>> + =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*match)(struct device_node *paren=
t);
>> + =A0 =A0 void =A0 =A0 =A0 =A0 =A0 =A0(*count_cells)(struct device_node =
*child,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec);
>> + =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 (*map)(u32 *addr, const u32 *range=
,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns=
, int pna);
>> + =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*translate)(u32 *addr, u64 offset=
, int na);
>> + =A0 =A0 unsigned int =A0 =A0(*get_flags)(const u32 *addr);
>> +};
>> +
>> +/*
>> + * Default translator (generic bus)
>> + */
>> +
>> +static void of_bus_default_count_cells(struct device_node *dev,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec)
>> +{
>> + =A0 =A0 if (addrc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D of_n_addr_cells(dev);
>> + =A0 =A0 if (sizec)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D of_n_size_cells(dev);
>> +}
>> +
>> +static u64 of_bus_default_map(u32 *addr, const u32 *range,
>> + =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> +{
>> + =A0 =A0 u64 cp, s, da;
>> +
>> + =A0 =A0 cp =3D of_read_number(range, na);
>> + =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> + =A0 =A0 da =3D of_read_number(addr, na);
>> +
>> + =A0 =A0 pr_debug("OF: default map, cp=3D%llx, s=3D%llx, da=3D%llx\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)cp, (unsigned long long=
)s,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)da);
>> +
>> + =A0 =A0 if (da < cp || da >=3D (cp + s))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> + =A0 =A0 return da - cp;
>> +}
>> +
>> +static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>> +{
>> + =A0 =A0 u64 a =3D of_read_number(addr, na);
>> + =A0 =A0 memset(addr, 0, na * 4);
>> + =A0 =A0 a +=3D offset;
>> + =A0 =A0 if (na > 1)
>> + =A0 =A0 =A0 =A0 =A0 =A0 addr[na - 2] =3D a >> 32;
>> + =A0 =A0 addr[na - 1] =3D a & 0xffffffffu;
>> +
>> + =A0 =A0 return 0;
>> +}
>> +
>> +static unsigned int of_bus_default_get_flags(const u32 *addr)
>> +{
>> + =A0 =A0 return IORESOURCE_MEM;
>> +}
>> +
>> +#ifdef CONFIG_PCI
>> +/*
>> + * PCI bus specific translator
>> + */
>> +
>> +static int of_bus_pci_match(struct device_node *np)
>> +{
>> + =A0 =A0 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
>> + =A0 =A0 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
>> +}
>> +
>> +static void of_bus_pci_count_cells(struct device_node *np,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> +{
>> + =A0 =A0 if (addrc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 3;
>> + =A0 =A0 if (sizec)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 2;
>> +}
>> +
>> +static unsigned int of_bus_pci_get_flags(const u32 *addr)
>> +{
>> + =A0 =A0 unsigned int flags =3D 0;
>> + =A0 =A0 u32 w =3D addr[0];
>> +
>> + =A0 =A0 switch((w >> 24) & 0x03) {
>> + =A0 =A0 case 0x01:
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 case 0x02: /* 32 bits */
>> + =A0 =A0 case 0x03: /* 64 bits */
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 }
>> + =A0 =A0 if (w & 0x40000000)
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_PREFETCH;
>> + =A0 =A0 return flags;
>> +}
>> +
>> +static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> +{
>> + =A0 =A0 u64 cp, s, da;
>> + =A0 =A0 unsigned int af, rf;
>> +
>> + =A0 =A0 af =3D of_bus_pci_get_flags(addr);
>> + =A0 =A0 rf =3D of_bus_pci_get_flags(range);
>> +
>> + =A0 =A0 /* Check address type match */
>> + =A0 =A0 if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> +
>> + =A0 =A0 /* Read address values, skipping high cell */
>> + =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> + =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> + =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> +
>> + =A0 =A0 pr_debug("OF: PCI map, cp=3D%llx, s=3D%llx, da=3D%llx\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)cp, (unsigned long long=
)s,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)da);
>> +
>> + =A0 =A0 if (da < cp || da >=3D (cp + s))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> + =A0 =A0 return da - cp;
>> +}
>> +
>> +static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
>> +{
>> + =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> +}
>> +
>> +const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 =
*size,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> +{
>> + =A0 =A0 const u32 *prop;
>> + =A0 =A0 unsigned int psize;
>> + =A0 =A0 struct device_node *parent;
>> + =A0 =A0 struct of_bus *bus;
>> + =A0 =A0 int onesize, i, na, ns;
>> +
>> + =A0 =A0 /* Get parent & match bus type */
>> + =A0 =A0 parent =3D of_get_parent(dev);
>> + =A0 =A0 if (parent =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 bus =3D of_match_bus(parent);
>> + =A0 =A0 if (strcmp(bus->name, "pci")) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(parent);
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 }
>> + =A0 =A0 bus->count_cells(dev, &na, &ns);
>> + =A0 =A0 of_node_put(parent);
>> + =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> +
>> + =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> + =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> + =A0 =A0 if (prop =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 psize /=3D 4;
>> +
>> + =A0 =A0 onesize =3D na + ns;
>> + =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if ((prop[0] & 0xff) =3D=3D ((bar_no * 4) + PC=
I_BASE_ADDRESS_0)) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> + =A0 =A0 return NULL;
>> +}
>> +EXPORT_SYMBOL(of_get_pci_address);
>> +
>> +int of_pci_address_to_resource(struct device_node *dev, int bar,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct resource=
 *r)
>> +{
>> + =A0 =A0 const u32 =A0 =A0 =A0 *addrp;
>> + =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 size;
>> + =A0 =A0 unsigned int =A0 =A0flags;
>> +
>> + =A0 =A0 addrp =3D of_get_pci_address(dev, bar, &size, &flags);
>> + =A0 =A0 if (addrp =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
>> + =A0 =A0 return __of_address_to_resource(dev, addrp, size, flags, r);
>> +}
>> +EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
>> +#endif /* CONFIG_PCI */
>> +
>> +/*
>> + * ISA bus specific translator
>> + */
>> +
>> +static int of_bus_isa_match(struct device_node *np)
>> +{
>> + =A0 =A0 return !strcmp(np->name, "isa");
>> +}
>> +
>> +static void of_bus_isa_count_cells(struct device_node *child,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> +{
>> + =A0 =A0 if (addrc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 2;
>> + =A0 =A0 if (sizec)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 1;
>> +}
>> +
>> +static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> +{
>> + =A0 =A0 u64 cp, s, da;
>> +
>> + =A0 =A0 /* Check address type match */
>> + =A0 =A0 if ((addr[0] ^ range[0]) & 0x00000001)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> +
>> + =A0 =A0 /* Read address values, skipping high cell */
>> + =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> + =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> + =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> +
>> + =A0 =A0 pr_debug("OF: ISA map, cp=3D%llx, s=3D%llx, da=3D%llx\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)cp, (unsigned long long=
)s,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)da);
>> +
>> + =A0 =A0 if (da < cp || da >=3D (cp + s))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> + =A0 =A0 return da - cp;
>> +}
>> +
>> +static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
>> +{
>> + =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> +}
>> +
>> +static unsigned int of_bus_isa_get_flags(const u32 *addr)
>> +{
>> + =A0 =A0 unsigned int flags =3D 0;
>> + =A0 =A0 u32 w =3D addr[0];
>> +
>> + =A0 =A0 if (w & 1)
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> + =A0 =A0 else
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> + =A0 =A0 return flags;
>> +}
>> +
>> +/*
>> + * Array of bus specific translators
>> + */
>> +
>> +static struct of_bus of_busses[] =3D {
>> +#ifdef CONFIG_PCI
>> + =A0 =A0 /* PCI */
>> + =A0 =A0 {
>> + =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "pci",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "assigned-addresses",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_pci_match,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_pci_count_cells,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_pci_map,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_pci_translate,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_pci_get_flags,
>> + =A0 =A0 },
>> +#endif /* CONFIG_PCI */
>> + =A0 =A0 /* ISA */
>> + =A0 =A0 {
>> + =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "isa",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_isa_match,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_isa_count_cells,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_isa_map,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_isa_translate,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_isa_get_flags,
>> + =A0 =A0 },
>> + =A0 =A0 /* Default */
>> + =A0 =A0 {
>> + =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "default",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .match =3D NULL,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_default_count_cells,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_default_map,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_default_translate,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_default_get_flags,
>> + =A0 =A0 },
>> +};
>> +
>> +static struct of_bus *of_match_bus(struct device_node *np)
>> +{
>> + =A0 =A0 int i;
>> +
>> + =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(of_busses); i++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (!of_busses[i].match || of_busses[i].match(=
np))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &of_busses[i];
>> + =A0 =A0 BUG();
>> + =A0 =A0 return NULL;
>> +}
>> +
>> +static int of_translate_one(struct device_node *parent, struct of_bus *=
bus,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct of_bus *pbus, u=
32 *addr,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pn=
a, const char *rprop)
>> +{
>> + =A0 =A0 const u32 *ranges;
>> + =A0 =A0 unsigned int rlen;
>> + =A0 =A0 int rone;
>> + =A0 =A0 u64 offset =3D OF_BAD_ADDR;
>> +
>> + =A0 =A0 /* Normally, an absence of a "ranges" property means we are
>> + =A0 =A0 =A0* crossing a non-translatable boundary, and thus the addres=
ses
>> + =A0 =A0 =A0* below the current not cannot be converted to CPU physical=
 ones.
>> + =A0 =A0 =A0* Unfortunately, while this is very clear in the spec, it's=
 not
>> + =A0 =A0 =A0* what Apple understood, and they do have things like /uni-=
n or
>> + =A0 =A0 =A0* /ht nodes with no "ranges" property and a lot of perfectl=
y
>> + =A0 =A0 =A0* useable mapped devices below them. Thus we treat the abse=
nce of
>> + =A0 =A0 =A0* "ranges" as equivalent to an empty "ranges" property whic=
h means
>> + =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller no=
t to try
>> + =A0 =A0 =A0* to translate addresses that aren't supposed to be transla=
ted in
>> + =A0 =A0 =A0* the first place. --BenH.
>> + =A0 =A0 =A0*/
>> + =A0 =A0 ranges =3D of_get_property(parent, rprop, &rlen);
>> + =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> + =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: no ranges, 1:1 translation\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> + =A0 =A0 }
>> +
>> + =A0 =A0 pr_debug("OF: walking ranges...\n");
>> +
>> + =A0 =A0 /* Now walk through the ranges */
>> + =A0 =A0 rlen /=3D 4;
>> + =A0 =A0 rone =3D na + pna + ns;
>> + =A0 =A0 for (; rlen >=3D rone; rlen -=3D rone, ranges +=3D rone) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 offset =3D bus->map(addr, ranges, na, ns, pna)=
;
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (offset !=3D OF_BAD_ADDR)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 }
>> + =A0 =A0 if (offset =3D=3D OF_BAD_ADDR) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: not found !\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> + =A0 =A0 }
>> + =A0 =A0 memcpy(addr, ranges + na, 4 * pna);
>> +
>> + finish:
>> + =A0 =A0 of_dump_addr("OF: parent translation for:", addr, pna);
>> + =A0 =A0 pr_debug("OF: with offset: %llx\n", (unsigned long long)offset=
);
>> +
>> + =A0 =A0 /* Translate it into parent bus space */
>> + =A0 =A0 return pbus->translate(addr, offset, pna);
>> +}
>> +
>> +/*
>> + * Translate an address from the device-tree into a CPU physical addres=
s,
>> + * this walks up the tree and applies the various bus mappings on the
>> + * way.
>> + *
>> + * Note: We consider that crossing any level with #size-cells =3D=3D 0 =
to mean
>> + * that translation is impossible (that is we are not dealing with a va=
lue
>> + * that can be mapped to a cpu physical address). This is not really sp=
ecified
>> + * that way, but this is traditionally the way IBM at least do things
>> + */
>> +u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *rprop)
>> +{
>> + =A0 =A0 struct device_node *parent =3D NULL;
>> + =A0 =A0 struct of_bus *bus, *pbus;
>> + =A0 =A0 u32 addr[OF_MAX_ADDR_CELLS];
>> + =A0 =A0 int na, ns, pna, pns;
>> + =A0 =A0 u64 result =3D OF_BAD_ADDR;
>> +
>> + =A0 =A0 pr_debug("OF: ** translation for device %s **\n", dev->full_na=
me);
>> +
>> + =A0 =A0 /* Increase refcount at current level */
>> + =A0 =A0 of_node_get(dev);
>> +
>> + =A0 =A0 /* Get parent & match bus type */
>> + =A0 =A0 parent =3D of_get_parent(dev);
>> + =A0 =A0 if (parent =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> + =A0 =A0 bus =3D of_match_bus(parent);
>> +
>> + =A0 =A0 /* Cound address cells & copy address locally */
>> + =A0 =A0 bus->count_cells(dev, &na, &ns);
>> + =A0 =A0 if (!OF_CHECK_COUNTS(na, ns)) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: Bad cell count fo=
r %s\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name);
>> + =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> + =A0 =A0 }
>> + =A0 =A0 memcpy(addr, in_addr, na * 4);
>> +
>> + =A0 =A0 pr_debug("OF: bus is %s (na=3D%d, ns=3D%d) on %s\n",
>> + =A0 =A0 =A0 =A0 bus->name, na, ns, parent->full_name);
>> + =A0 =A0 of_dump_addr("OF: translating address:", addr, na);
>> +
>> + =A0 =A0 /* Translate */
>> + =A0 =A0 for (;;) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Switch to parent bus */
>> + =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dev);
>> + =A0 =A0 =A0 =A0 =A0 =A0 dev =3D parent;
>> + =A0 =A0 =A0 =A0 =A0 =A0 parent =3D of_get_parent(dev);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* If root, we have finished */
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (parent =3D=3D NULL) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: reached root nod=
e\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 result =3D of_read_number(addr=
, na);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Get new parent bus and counts */
>> + =A0 =A0 =A0 =A0 =A0 =A0 pbus =3D of_match_bus(parent);
>> + =A0 =A0 =A0 =A0 =A0 =A0 pbus->count_cells(dev, &pna, &pns);
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (!OF_CHECK_COUNTS(pna, pns)) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: B=
ad cell count for %s\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name)=
;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: parent bus is %s (na=3D%d, ns=3D=
%d) on %s\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pbus->name, pna, pns, parent->full_nam=
e);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Apply bus translation */
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (of_translate_one(dev, bus, pbus, addr, na,=
 ns, pna, rprop))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Complete the move up one level */
>> + =A0 =A0 =A0 =A0 =A0 =A0 na =3D pna;
>> + =A0 =A0 =A0 =A0 =A0 =A0 ns =3D pns;
>> + =A0 =A0 =A0 =A0 =A0 =A0 bus =3D pbus;
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 of_dump_addr("OF: one level translation:", add=
r, na);
>> + =A0 =A0 }
>> + bail:
>> + =A0 =A0 of_node_put(parent);
>> + =A0 =A0 of_node_put(dev);
>> +
>> + =A0 =A0 return result;
>> +}
>> +
>> +u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
>> +{
>> + =A0 =A0 return __of_translate_address(dev, in_addr, "ranges");
>> +}
>> +EXPORT_SYMBOL(of_translate_address);
>> +
>> +u64 of_translate_dma_address(struct device_node *dev, const u32 *in_add=
r)
>> +{
>> + =A0 =A0 return __of_translate_address(dev, in_addr, "dma-ranges");
>> +}
>> +EXPORT_SYMBOL(of_translate_dma_address);
>> +
>> +const u32 *of_get_address(struct device_node *dev, int index, u64 *size=
,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> +{
>> + =A0 =A0 const u32 *prop;
>> + =A0 =A0 unsigned int psize;
>> + =A0 =A0 struct device_node *parent;
>> + =A0 =A0 struct of_bus *bus;
>> + =A0 =A0 int onesize, i, na, ns;
>> +
>> + =A0 =A0 /* Get parent & match bus type */
>> + =A0 =A0 parent =3D of_get_parent(dev);
>> + =A0 =A0 if (parent =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 bus =3D of_match_bus(parent);
>> + =A0 =A0 bus->count_cells(dev, &na, &ns);
>> + =A0 =A0 of_node_put(parent);
>> + =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> +
>> + =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> + =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> + =A0 =A0 if (prop =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 psize /=3D 4;
>> +
>> + =A0 =A0 onesize =3D na + ns;
>> + =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D index) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> + =A0 =A0 return NULL;
>> +}
>> +EXPORT_SYMBOL(of_get_address);
>> +
>> +static int __of_address_to_resource(struct device_node *dev, const u32 =
*addrp,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u64 si=
ze, unsigned int flags,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct=
 resource *r)
>> =A0{
>> =A0 =A0 =A0 u64 taddr;
>>
>> diff --git a/include/linux/of_address.h b/include/linux/of_address.h
>> index 474b794..cc567df 100644
>> --- a/include/linux/of_address.h
>> +++ b/include/linux/of_address.h
>> @@ -3,9 +3,7 @@
>> =A0#include <linux/ioport.h>
>> =A0#include <linux/of.h>
>>
>> -extern int __of_address_to_resource(struct device_node *dev, const u32 =
*addrp,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u64 si=
ze, unsigned int flags,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct=
 resource *r);
>> +extern u64 of_translate_address(struct device_node *np, const u32 *addr=
);
>> =A0extern int of_address_to_resource(struct device_node *dev, int index,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct r=
esource *r);
>> =A0extern void __iomem *of_iomap(struct device_node *device, int index);
>
>
>



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

^ permalink raw reply

* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-10 14:18 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: sfr, monstr, microblaze-uclinux, devicetree-discuss, jeremy.kerr,
	linuxppc-dev
In-Reply-To: <1276150663.1962.43.camel@pasglop>

On Thu, Jun 10, 2010 at 12:17 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
>
>> You just introduced an unnamed structure of device + resources,
>> it isn't declared anywhere but in the code itself (either via
>> &foo[1] or buf + sizeof(*foo)).
>>
>> You're not the only one who hacks (or at least have to
>> understand) the OF stuff, so let's try keep this stuff
>> readable?
>>
>> I told you several ways of how to improve the code (based on
>> the ideas from drivers/base/, so the ideas aren't even mine,
>> fwiw).
>
> I tend to agree with Anton here.

The reason I'm confident doing it that way is that it is *not* a
structure.  There is no structure relationship between the resource
table and the platform_device other than they are allocated with the
same kzalloc() call.  All the code that cares about that is contained
within 4 lines of code.  I'm resistant to using a structure because it
is adds an additional 5-6 lines of code to add a structure that won't
be used anywhere else, and is only 4 lines to begin with.

> BTW. Why not make of_device a wrapper (or even alias of)
> platform_device ? :-) That way you get the resource array etc.. for free
> and it will make the whole of_device vs. platform_device issue moot.

of_device is an alias of platform_device now.  The resource array in
platform devices is not statically defined.  It is allocated
separately.  I can't currently use the platform_device_alloc code
which does separate deallocation because the OF code needs its own
release hook to put the node.  OTOH, I can probably change the guts of
of_release_dev() to be called by platform_device_release().

okay, I'll try changing this an see how it looks.

g.

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

^ permalink raw reply

* [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Steven A. Falco @ 2010-06-10 14:00 UTC (permalink / raw)
  To: linuxppc-dev@ozlabs.org

SIOCGMIIREG and SIOCSMIIREG access a user data structure via a void
pointer to user space.  So, we need copy_from_user and copy_to_user
to move the data.

Signed-off-by: Steven A. Falco <sfalco@harris.com>

---

I believe there is a bug in the way the ibm_newemac driver handles the
SIOCGMIIREG (and SIOCSMIIREG) ioctl.  The problem is that emac_ioctl
is handed a "struct ifreq *rq" which contains a user-land pointer to
an array of 16-bit integers.

However, emac_ioctl directly accesses the data, which doesn't work.
I added the following patch to copy the data in and out.

Please note that this patch was tested in an older kernel (2.6.30)
because that is what we are using on our custom hardware.  I think
this is still a problem in the current code, but I'd like reviewers
to take a look, to be sure.

--- drivers/net/ibm_newemac/core.c	2010-06-09 19:57:26.000000000 -0400
+++ /home/sfalco/core.c	2010-06-10 09:38:22.000000000 -0400
@@ -2218,6 +2218,7 @@
 {
 	struct emac_instance *dev = netdev_priv(ndev);
 	struct mii_ioctl_data *data = if_mii(rq);
+	struct mii_ioctl_data user_data;
 
 	DBG(dev, "ioctl %08x" NL, cmd);
 
@@ -2229,13 +2230,19 @@
 		data->phy_id = dev->phy.address;
 		/* Fall through */
 	case SIOCGMIIREG:
-		data->val_out = emac_mdio_read(ndev, dev->phy.address,
-					       data->reg_num);
+		if (copy_from_user(user_data, (char __user *)data, sizeof(user_data)))
+			return -EFAULT;
+		user_data->val_out = emac_mdio_read(ndev, dev->phy.address,
+					       user_data->reg_num);
+		if (copy_to_user((char __user *)rq->ifr_data, user_data, sizeof(user_data)))
+			return -EFAULT;
 		return 0;
 
 	case SIOCSMIIREG:
-		emac_mdio_write(ndev, dev->phy.address, data->reg_num,
-				data->val_in);
+		if (copy_from_user(user_data, (char __user *)data, sizeof(user_data)))
+			return -EFAULT;
+		emac_mdio_write(ndev, dev->phy.address, user_data->reg_num,
+				user_data->val_in);
 		return 0;
 	default:
 		return -EOPNOTSUPP;

^ permalink raw reply

* Mac Mini suspend issues - misidentified model
From: Mark Crichton @ 2010-06-10 13:50 UTC (permalink / raw)
  To: linuxppc-dev

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I've dug up and revived my old Mac Mini (PPC) and been trying to get it
to work again. I was looking at getting the system to suspend to ram,
but it didn't seem to be working. So, I tried to trace down the problem.

I took a look at the kernel code, and I think I may have found the
issue. According to /proc/cpuinfo, my model is a "PowerMac10,2". Looking
at platforms/powermac/feature.c, I only see an entry for "PowerMac10,1".
- From my understanding of the code, this means my machine doesn't get
PMAC_MB_MAY_SLEEP set, hence no suspend to ram.

I can easily get a patch together to just copy the PowerMac10,1 entry in
pmac_mb_defs, for the PowerMac10,2, but I also was wondering if there's
some issues I may run into. However, from what I see in the code, this
seems to be a pretty risk-free operation.

Am I on the right track for this one?

Thanks,
Mark Crichton
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkwQ7aIACgkQOfj2Ja/u/oBxYACeOX5jUQOJ5XloojtoZJXneZL/
734An1mP41QPuLg/RtVllmgQjgdBxdBJ
=LLH3
-----END PGP SIGNATURE-----

^ permalink raw reply

* Re: [Patch 5/5] PPC64-HWBKPT: Discard extraneous interrupt due to accesses outside symbol length
From: Paul Mackerras @ 2010-06-10 12:40 UTC (permalink / raw)
  To: K.Prasad
  Cc: Michael Neuling, Benjamin Herrenschmidt, shaggy,
	Frederic Weisbecker, David Gibson, linuxppc-dev@ozlabs.org,
	Alan Stern, Roland McGrath
In-Reply-To: <20100609102559.GF20332@in.ibm.com>

On Wed, Jun 09, 2010 at 03:55:59PM +0530, K.Prasad wrote:

> +	if (!((bp->attr.bp_addr <= dar) &&
> +	     (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) {
> +		/*
> +		 * This exception is triggered not because of a memory access
> +		 * on the monitored variable but in the double-word address
> +		 * range in which it is contained. We will consume this
> +		 * exception, considering it as 'noise'.
> +		 */
> +		info->extraneous_interrupt = true;
> +	}

Ummm, don't you need to add "else info->extraneous_interrupt = false;"
here?  I don't see anywhere that you ever clear it otherwise.

Also, I think you need to do the "if (!info->extraneous_interrupt)"
check around the call to perf_bp_event() later on in
hw_breakpoint_handler() as well as around the call in
single_step_dabr_instruction().

Paul.

^ permalink raw reply

* Re: [PATCH 3/5] Removing dead CONFIG_SMP_750
From: Christoph Egger @ 2010-06-10 12:23 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Paul Mackerras, vamos, linux-kernel, linuxppc-dev
In-Reply-To: <1276150461.1962.42.camel@pasglop>

On Thu, Jun 10, 2010 at 04:14:21PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2010-06-09 at 08:35 -0400, Josh Boyer wrote:
> > On Wed, Jun 09, 2010 at 12:00:21PM +0200, Christoph Egger wrote:
> > >CONFIG_SMP_750 doesn't exist in Kconfig, therefore removing all
> > >references for it from the source code.
> > 
> > Yeah, we don't support SMP on 750 at the moment.  This code was carried over
> > from the arch/ppc days, and that code was present pre-git.  I think we can
> > drop it, but I'll leave that up to Ben.  Maybe he has crazy plans for a 750 SMP
> > board.
> 
> Nope :-) Though it would be nice to also remove the call sites too and
> thus remove the macro entirely.

SOmething like below?

-----
From: Christoph Egger <siccegge@cs.fau.de>
Subject: [PATCH 3/5] Removing dead CONFIG_SMP_750

CONFIG_SMP_750 doesn't exist in Kconfig, therefore removing all
references for it from the source code.

Signed-off-by: Christoph Egger <siccegge@cs.fau.de>

diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c
index 8aaa8b7..09c7820 100644
--- a/arch/powerpc/mm/tlb_hash32.c
+++ b/arch/powerpc/mm/tlb_hash32.c
@@ -94,11 +94,6 @@ void tlb_flush(struct mmu_gather *tlb)
  * the cache operations on the bus.  Hence we need to use an IPI
  * to get the other CPU(s) to invalidate their TLBs.
  */
-#ifdef CONFIG_SMP_750
-#define FINISH_FLUSH   smp_send_tlb_invalidate(0)
-#else
-#define FINISH_FLUSH   do { } while (0)
-#endif
 
 static void flush_range(struct mm_struct *mm, unsigned long start,
                        unsigned long end)
@@ -138,7 +133,6 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
        flush_range(&init_mm, start, end);
-       FINISH_FLUSH;
 }
 EXPORT_SYMBOL(flush_tlb_kernel_range);
 
@@ -162,7 +156,6 @@ void flush_tlb_mm(struct mm_struct *mm)
         */
        for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
                flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
-       FINISH_FLUSH;
 }
 EXPORT_SYMBOL(flush_tlb_mm);
 
@@ -179,7 +172,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
        pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
        if (!pmd_none(*pmd))
                flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
-       FINISH_FLUSH;
 }
 EXPORT_SYMBOL(flush_tlb_page);
 
@@ -192,6 +184,5 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                     unsigned long end)
 {
        flush_range(vma->vm_mm, start, end);
-       FINISH_FLUSH;
 }
 EXPORT_SYMBOL(flush_tlb_range);
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 5/5] hvc_console: Fix race between hvc_close and hvc_remove
From: John Kacur @ 2010-06-10 11:03 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Greg Kroah-Hartman, linuxppc-dev, Clark Williams, Rusty Russell,
	Arnaldo Carvalho de Melo, Luis Claudio R. Goncalves, Amit Shah,
	Alan Cox
In-Reply-To: <1276167780-23002-1-git-send-email-jkacur@redhat.com>

From: Amit Shah <amit.shah@redhat.com>

Alan pointed out a race in the code where hvc_remove is invoked. The
recent virtio_console work is the first user of hvc_remove().

Alan describes it thus:

The hvc_console assumes that a close and remove call can't occur at the
same time.

In addition tty_hangup(tty) is problematic as tty_hangup is asynchronous
itself....

So this can happen

        hvc_close                               hvc_remove
        hung up ? - no
                                                lock
                                                tty = hp->tty
                                                unlock
        lock
        hp->tty = NULL
        unlock
        notify del
        kref_put the hvc struct
        close completes
        tty is destroyed
                                                tty_hangup dead tty
                                                tty->ops will be NULL
                                                NULL->...

This patch adds some tty krefs and also converts to using tty_vhangup().

Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
CC: Alan Cox <alan@lxorguk.ukuu.org.uk>
CC: linuxppc-dev@ozlabs.org
CC: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/char/hvc_console.c |   31 +++++++++++++++++++++----------
 1 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 416d342..da70f68 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -312,6 +312,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 	spin_lock_irqsave(&hp->lock, flags);
 	/* Check and then increment for fast path open. */
 	if (hp->count++ > 0) {
+		tty_kref_get(tty);
 		spin_unlock_irqrestore(&hp->lock, flags);
 		hvc_kick();
 		return 0;
@@ -319,7 +320,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 
 	tty->driver_data = hp;
 
-	hp->tty = tty;
+	hp->tty = tty_kref_get(tty);
 
 	spin_unlock_irqrestore(&hp->lock, flags);
 
@@ -336,6 +337,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 		spin_lock_irqsave(&hp->lock, flags);
 		hp->tty = NULL;
 		spin_unlock_irqrestore(&hp->lock, flags);
+		tty_kref_put(tty);
 		tty->driver_data = NULL;
 		kref_put(&hp->kref, destroy_hvc_struct);
 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
@@ -363,13 +365,18 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 		return;
 
 	hp = tty->driver_data;
+
 	spin_lock_irqsave(&hp->lock, flags);
+	tty_kref_get(tty);
 
 	if (--hp->count == 0) {
 		/* We are done with the tty pointer now. */
 		hp->tty = NULL;
 		spin_unlock_irqrestore(&hp->lock, flags);
 
+		/* Put the ref obtained in hvc_open() */
+		tty_kref_put(tty);
+
 		if (hp->ops->notifier_del)
 			hp->ops->notifier_del(hp, hp->data);
 
@@ -389,6 +396,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 		spin_unlock_irqrestore(&hp->lock, flags);
 	}
 
+	tty_kref_put(tty);
 	kref_put(&hp->kref, destroy_hvc_struct);
 }
 
@@ -424,10 +432,11 @@ static void hvc_hangup(struct tty_struct *tty)
 	spin_unlock_irqrestore(&hp->lock, flags);
 
 	if (hp->ops->notifier_hangup)
-			hp->ops->notifier_hangup(hp, hp->data);
+		hp->ops->notifier_hangup(hp, hp->data);
 
 	while(temp_open_count) {
 		--temp_open_count;
+		tty_kref_put(tty);
 		kref_put(&hp->kref, destroy_hvc_struct);
 	}
 }
@@ -592,7 +601,7 @@ int hvc_poll(struct hvc_struct *hp)
 	}
 
 	/* No tty attached, just skip */
-	tty = hp->tty;
+	tty = tty_kref_get(hp->tty);
 	if (tty == NULL)
 		goto bail;
 
@@ -672,6 +681,8 @@ int hvc_poll(struct hvc_struct *hp)
 
 		tty_flip_buffer_push(tty);
 	}
+	if (tty)
+		tty_kref_put(tty);
 
 	return poll_mask;
 }
@@ -806,7 +817,7 @@ int hvc_remove(struct hvc_struct *hp)
 	struct tty_struct *tty;
 
 	spin_lock_irqsave(&hp->lock, flags);
-	tty = hp->tty;
+	tty = tty_kref_get(hp->tty);
 
 	if (hp->index < MAX_NR_HVC_CONSOLES)
 		vtermnos[hp->index] = -1;
@@ -818,18 +829,18 @@ int hvc_remove(struct hvc_struct *hp)
 	/*
 	 * We 'put' the instance that was grabbed when the kref instance
 	 * was initialized using kref_init().  Let the last holder of this
-	 * kref cause it to be removed, which will probably be the tty_hangup
+	 * kref cause it to be removed, which will probably be the tty_vhangup
 	 * below.
 	 */
 	kref_put(&hp->kref, destroy_hvc_struct);
 
 	/*
-	 * This function call will auto chain call hvc_hangup.  The tty should
-	 * always be valid at this time unless a simultaneous tty close already
-	 * cleaned up the hvc_struct.
+	 * This function call will auto chain call hvc_hangup.
 	 */
-	if (tty)
-		tty_hangup(tty);
+	if (tty) {
+		tty_vhangup(tty);
+		tty_kref_put(tty);
+	}
 	return 0;
 }
 EXPORT_SYMBOL_GPL(hvc_remove);
-- 
1.6.6.1

^ permalink raw reply related


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