LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [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

* Re: [PATCH] gianfar: Revive the driver for eTSEC devices (disable timestamping)
From: Anton Vorontsov @ 2010-06-10 10:41 UTC (permalink / raw)
  To: Richard Cochran; +Cc: linuxppc-dev, netdev, David Miller, Manfred Rudigier
In-Reply-To: <20100610102226.GA10653@riccoc20.at.omicron.at>

On Thu, Jun 10, 2010 at 12:22:26PM +0200, Richard Cochran wrote:
[...]
> > U-Boot 1.1.6 (Oct  9 2007 - 20:42:39) MPC83XX
> ...
> > CPU: MPC8313E, Rev: 10 at 333.333 MHz
> 
> We have a newer CPU revision:
> 
>    U-Boot 1.3.0 (Dec 23 2008 - 13:38:14) MPC83XX
>    CPU:   e300c3, MPC8313E, Rev: 21 at 333.333 MHz, CSB:  166 MHz
> 
> Perhaps a bug was fixed between revision 10 and 21...
> 
> You mentioned having trouble on the MPC8568EMDS. Was it the same
> problem?

Yep, the symptomps were exactly the same, it didn't want to get
the DHCP answer, while I saw the DHCP requests on the host side.

But I don't know if disabling the timestamping fixes 8568, maybe
there is some additional problem with it, no idea as I don't have
8568 board in my hands any longer. I can try any proposed fixes
as soon as I get it back though.

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

^ permalink raw reply

* Re: [PATCH] gianfar: Revive the driver for eTSEC devices (disable timestamping)
From: Richard Cochran @ 2010-06-10 10:22 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev, netdev, David Miller, Manfred Rudigier
In-Reply-To: <20100610093159.GA30822@oksana.dev.rtsoft.ru>

On Thu, Jun 10, 2010 at 01:31:59PM +0400, Anton Vorontsov wrote:
> > No, we did not set TMR_CTRL[TE].
> 
> So, you deliberately violate the spec and expect it to work
> everywhere? :-)

Sometimes one must read the manual with a grain of salt ;)

> > > Also, I recall that Freescale BSPs were explicitly disabling the
> > > timestamping because of a performance drop.
> > 
> > The BSPs that we have, for the MPC8313ERDB and the P2020RBD both
> > include a (hacky) PTP timestmaping driver. Can you be more specific
> > about where and when Freescale is disabling timestamping?
> 
> Well, bitshrine site no longer allows[1] to list patches at
> http://www.bitshrine.org/gpp/ , but there was a patch for sure.
> 
> I'll try to find it in a bunch of .iso files that I have on disk
> tho.

Thanks, that will help to track the problem down.

> U-Boot 1.1.6 (Oct  9 2007 - 20:42:39) MPC83XX
...
> CPU: MPC8313E, Rev: 10 at 333.333 MHz

We have a newer CPU revision:

   U-Boot 1.3.0 (Dec 23 2008 - 13:38:14) MPC83XX
   CPU:   e300c3, MPC8313E, Rev: 21 at 333.333 MHz, CSB:  166 MHz

Perhaps a bug was fixed between revision 10 and 21...

You mentioned having trouble on the MPC8568EMDS. Was it the same
problem?

Thanks,
Richard

^ permalink raw reply

* Re: CAN Subsystem and MPC52xx onboard controller
From: Wolfgang Grandegger @ 2010-06-10  9:37 UTC (permalink / raw)
  To: Roman Fietze; +Cc: linuxppc-dev
In-Reply-To: <201006101129.15581.roman.fietze@telemotive.de>

On 06/10/2010 11:29 AM, Roman Fietze wrote:
> Hello Wolfram,
> 
> On Thursday 10 June 2010 10:59:23 Wolfram Sang wrote:
> 
>> The mainline kernel works fine here with Phytec based MPC5xxx-boards.
> 
> Reading your answer made me hope again, and I just pulled the newest
> HEAD from the mainline kernel and tried it once more. Now it compiles.
> Thanks for retriggering me again.
> 
> All the other's sill have problems, except pengutronix, most of them
> with an inconsistency (with the socket CAN files?), which shows up as
> 
>   'struct can_bittime_std' declared inside parameter list
> 
> in net/can/dev.c:69

With all other you mean the linux-2.6-denx tree!? These seem to be some
reminders of the old Socket-CAN support merged into that tree (master
branch). I will clean that up a.s.a.p. Nevertheless, whenever possible,
you should use the mainline kernel.

> So I assume we will switch to the mainline kernel, which we already
> use for Atom based x86 development on the MEN boards.

DENX tries to push patches upstream as fast as possible and new projects
are usually based on the mainline kernel tree.

Wolfgang.


> 
> Thanks once more
> 
> Roman
> 

^ permalink raw reply

* Re: [PATCH] gianfar: Revive the driver for eTSEC devices (disable timestamping)
From: Anton Vorontsov @ 2010-06-10  9:31 UTC (permalink / raw)
  To: Richard Cochran; +Cc: linuxppc-dev, netdev, David Miller, Manfred Rudigier
In-Reply-To: <20100610062907.GA3390@riccoc20.at.omicron.at>

[-- Attachment #1: Type: text/plain, Size: 3466 bytes --]

On Thu, Jun 10, 2010 at 08:29:08AM +0200, Richard Cochran wrote:
> On Wed, Jun 09, 2010 at 11:32:19PM +0400, Anton Vorontsov wrote:
> > Since commit cc772ab7cdcaa24d1fae332d92a1602788644f7a ("gianfar: Add
> > hardware RX timestamping support"), the driver no longer works on
> > at least MPC8313ERDB and MPC8568EMDS boards (and possibly much more
> > boards as well).
> 
> What do you mean by, "no longer works?" The driver works fine for us,

For me it doesn't even able to receive DHCP answer, boot logs
attached. tcpdump on the host side:

12:56:15.266562 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:e0:0c:00:7e:21, length 548
12:56:15.266697 IP 10.0.0.2.67 > 10.0.0.32.68: BOOTP/DHCP, Reply, length 324
12:56:22.106691 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:e0:0c:00:7e:21, length 548
12:56:22.106843 IP 10.0.0.2.67 > 10.0.0.32.68: BOOTP/DHCP, Reply, length 324
12:56:33.698908 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:e0:0c:00:7e:21, length 548
12:56:33.699083 IP 10.0.0.2.67 > 10.0.0.32.68: BOOTP/DHCP, Reply, length 324
12:56:53.607275 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 00:e0:0c:00:7e:21, length 548
12:56:53.607430 IP 10.0.0.2.67 > 10.0.0.32.68: BOOTP/DHCP, Reply, length 324

> > That's how MPC8313 Reference Manual describes RCTRL_TS_ENABLE bit:
> > 
> >   Timestamp incoming packets as padding bytes. PAL field is set
> >   to 8 if the PAL field is programmed to less than 8. Must be set
> >   to zero if TMR_CTRL[TE]=0.
> > 
> > I see that the commit above sets this bit, but it doesn't handle
> > TMR_CTRL. Manfred probably had this bit set by the firmware for
> > his boards. But obviously this isn't true for all boards in the
> > wild.
> 
> No, we did not set TMR_CTRL[TE].

So, you deliberately violate the spec and expect it to work
everywhere? :-)

> For the Rx timestamps, we simply enabled them unconditionally. The
> effect of not setting TMR_CTRL[TE] was that the timestamps were
> invalid, but that should not matter if user space has not configured
> the PTP clock.

It seems to matter here, but I haven't tested if enabling the
TE bit actually solves the problem. Disabling timestamping
makes the driver work for sure though.

> > Also, I recall that Freescale BSPs were explicitly disabling the
> > timestamping because of a performance drop.
> 
> The BSPs that we have, for the MPC8313ERDB and the P2020RBD both
> include a (hacky) PTP timestmaping driver. Can you be more specific
> about where and when Freescale is disabling timestamping?

Well, bitshrine site no longer allows[1] to list patches at
http://www.bitshrine.org/gpp/ , but there was a patch for sure.

I'll try to find it in a bunch of .iso files that I have on disk
tho.

> > For now, the best way to deal with this is just disable the
> > timestamping, and later we can discuss proper device tree bindings
> > and implement enabling this feature via some property.
> 
> Okay, but now we want to identify what exactly works and what not. As
> mentioned, we tested this driver on four different boards and did not
> see any problems.

Sure thing, I would happily test any patches. Or if you need
to dump some register from my board, feel free to send a patch
that adds a bunch of printks and I'll send the output to you.

Thanks,

[1] http://lists.nongnu.org/archive/html/ltib/2010-04/msg00192.html

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

[-- Attachment #2: wk.log --]
[-- Type: text/plain, Size: 8094 bytes --]

U-Boot 1.1.6 (Oct  9 2007 - 20:42:39) MPC83XX

Clock configuration:
  Coherent System Bus:  166 MHz
  Core:                 333 MHz
  Local Bus Controller: 166 MHz
  Local Bus:             41 MHz
  DDR:                  333 MHz
  SEC:                   55 MHz
  I2C1:                 166 MHz
  I2C2:                 166 MHz
  TSEC1:                166 MHz
  TSEC2:                166 MHz
  USB MPH:                0 MHz
  USB DR:                55 MHz
CPU: MPC8313E, Rev: 10 at 333.333 MHz
Board: Freescale MPC8313ERDB
I2C:   ready
DRAM:  Initializing
   DDR RAM: 128 MB
FLASH:  8 MB
NAND:  32 MiB
In:    serial
Out:   serial
Err:   serial
Net:   TSEC0, TSEC1
=>
=>
=> setenv ethact TSEC1 ; setenv ipaddr 10.0.0.99 ; setenv serverip 10.0.0.2 ; setenv bootargs console=ttyS0,115200 ip=on debug ; tftp a00000 uImage ; tftp 900000 dtb ; bootm a00000 - 900000
Waiting for PHY auto negotiation to complete. done
Speed: 100, full duplex
Using TSEC1 device
TFTP from server 10.0.0.2; our IP address is 10.0.0.99
Filename 'uImage'.
Load address: 0xa00000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         ##############################
done
Bytes transferred = 1482399 (169e9f hex)
Speed: 100, full duplex
Using TSEC1 device
TFTP from server 10.0.0.2; our IP address is 10.0.0.99
Filename 'dtb'.
Load address: 0x900000
Loading: ####
done
Bytes transferred = 20000 (4e20 hex)
## Booting image at 00a00000 ...
   Image Name:   Linux-2.6.35-rc2-00059-gf7c3a62
   Created:      2010-06-10   8:59:46 UTC
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    1482335 Bytes =  1.4 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
   Booting using flat device tree at 0x900000
Using MPC831x RDB machine description
Linux version 2.6.35-rc2-00059-gf7c3a62 (cbou@oksana) (gcc version 4.2.0 (MontaVista 4.2.0-16.0.20.0800760 2008-04-05)) #85 Thu Jun 10 12:59:44 MSD 2010
Found legacy serial port 0 for /soc8313@e0000000/serial@4500
  mem=e0004500, taddr=e0004500, irq=0, clk=166666660, speed=0
Found legacy serial port 1 for /soc8313@e0000000/serial@4600
  mem=e0004600, taddr=e0004600, irq=0, clk=166666660, speed=0
bootconsole [udbg0] enabled
setup_arch: bootmem
mpc831x_rdb_setup_arch()
arch: exit
Top of RAM: 0x8000000, Total RAM: 0x8000000
Memory hole size: 0MB
Zone PFN ranges:
  DMA      0x00000000 -> 0x00008000
  Normal   empty
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
    0: 0x00000000 -> 0x00008000
On node 0 totalpages: 32768
free_area_init_node: node 0, pgdat c0302840, node_mem_map c0321000
  DMA zone: 256 pages used for memmap
  DMA zone: 0 pages reserved
  DMA zone: 32512 pages, LIFO batch:7
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 32512
Kernel command line: console=ttyS0,115200 ip=on debug
PID hash table entries: 512 (order: -1, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 126708k/131072k available (2980k kernel code, 4364k reserved, 136k data, 83k bss, 164k init)
Kernel virtual memory layout:
  * 0xfffdf000..0xfffff000  : fixmap
  * 0xfdffc000..0xfe000000  : early ioremap
  * 0xc9000000..0xfdffc000  : vmalloc & ioremap
SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Hierarchical RCU implementation.
        RCU-based detection of stalled CPUs is disabled.
        Verbose stalled-CPUs detection is disabled.
NR_IRQS:512 nr_irqs:512
IPIC (128 IRQ sources) at c9000700
time_init: decrementer frequency = 41.666665 MHz
time_init: processor frequency   = 333.333320 MHz
clocksource: timebase mult[6000004] shift[22] registered
clockevent: decrementer mult[aaaaaa3] shift[32] cpu[0]
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
NET: Registered protocol family 16

  alloc irq_desc for 38 on node 0
  alloc kstat_irqs on node 0
irq: irq 38 on host /soc8313@e0000000/pic@700 mapped to virtual irq 38
Registering ipic with sysfs...
bio: create slab <bio-0> at 0
SCSI subsystem initialized
Switching to clocksource timebase
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
  alloc irq_desc for 16 on node 0
  alloc kstat_irqs on node 0
irq: irq 9 on host /soc8313@e0000000/pic@700 mapped to virtual irq 16
  alloc irq_desc for 17 on node 0
  alloc kstat_irqs on node 0
irq: irq 10 on host /soc8313@e0000000/pic@700 mapped to virtual irq 17
msgmni has been set to 247
alg: No test for stdrng (krng)
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0xe0004500 (irq = 16) is a 16550A
console [ttyS0] enabled, bootconsole disabled
console [ttyS0] enabled, bootconsole disabled
serial8250.0: ttyS1 at MMIO 0xe0004600 (irq = 17) is a 16550A
brd: module loaded
loop: module loaded
Fixed MDIO Bus: probed
  alloc irq_desc for 37 on node 0
  alloc kstat_irqs on node 0
irq: irq 37 on host /soc8313@e0000000/pic@700 mapped to virtual irq 37
  alloc irq_desc for 36 on node 0
  alloc kstat_irqs on node 0
irq: irq 36 on host /soc8313@e0000000/pic@700 mapped to virtual irq 36
  alloc irq_desc for 35 on node 0
  alloc kstat_irqs on node 0
irq: irq 35 on host /soc8313@e0000000/pic@700 mapped to virtual irq 35
eth0: Gianfar Ethernet Controller Version 1.2, 00:04:9f:ef:23:33
eth0: Running with NAPI enabled
eth0: RX BD ring size for Q[0]: 256
eth0: TX BD ring size for Q[0]: 256
  alloc irq_desc for 34 on node 0
  alloc kstat_irqs on node 0
irq: irq 34 on host /soc8313@e0000000/pic@700 mapped to virtual irq 34
  alloc irq_desc for 33 on node 0
  alloc kstat_irqs on node 0
irq: irq 33 on host /soc8313@e0000000/pic@700 mapped to virtual irq 33
  alloc irq_desc for 32 on node 0
  alloc kstat_irqs on node 0
irq: irq 32 on host /soc8313@e0000000/pic@700 mapped to virtual irq 32
eth1: Gianfar Ethernet Controller Version 1.2, 00:e0:0c:00:7e:21
eth1: Running with NAPI enabled
eth1: RX BD ring size for Q[0]: 256
eth1: TX BD ring size for Q[0]: 256
Freescale PowerQUICC MII Bus: probed
  alloc irq_desc for 20 on node 0
  alloc kstat_irqs on node 0
irq: irq 20 on host /soc8313@e0000000/pic@700 mapped to virtual irq 20
Freescale PowerQUICC MII Bus: probed
md: linear personality registered for level -1
md: raid0 personality registered for level 0
md: raid1 personality registered for level 1
TCP cubic registered
NET: Registered protocol family 17
Sending DHCP requests .
PHY: 0:01 - Link is Up - 1000/Full
PHY: mdio@e0024520:04 - Link is Up - 100/Full
., OK
IP-Config: Got DHCP answer from 10.0.0.2, my address is 10.0.0.32
IP-Config: Complete:
     device=eth1, addr=10.0.0.32, mask=255.255.255.0, gw=10.0.0.2,
     host=10.0.0.32, domain=local.net, nis-domain=(none),
     bootserver=10.0.0.2, rootserver=10.0.0.2, rootpath=/opt/montavista/cge/devkit/ppc/83xx/target/
md: Waiting for all devices to be available before autodetect
md: If you don't use raid, use raid=noautodetect
md: Autodetecting RAID arrays.
md: Scanned 0 and added 0 devices.
md: autorun ...
md: ... autorun DONE.
Looking up port of RPC 100003/2 on 10.0.0.2
Looking up port of RPC 100005/1 on 10.0.0.2
VFS: Mounted root (nfs filesystem) readonly on device 0:10.
Freeing unused kernel memory: 164k init

[-- Attachment #3: nwk.log --]
[-- Type: text/plain, Size: 7537 bytes --]

U-Boot 1.1.6 (Oct  9 2007 - 20:42:39) MPC83XX

Clock configuration:
  Coherent System Bus:  166 MHz
  Core:                 333 MHz
  Local Bus Controller: 166 MHz
  Local Bus:             41 MHz
  DDR:                  333 MHz
  SEC:                   55 MHz
  I2C1:                 166 MHz
  I2C2:                 166 MHz
  TSEC1:                166 MHz
  TSEC2:                166 MHz
  USB MPH:                0 MHz
  USB DR:                55 MHz
CPU: MPC8313E, Rev: 10 at 333.333 MHz
Board: Freescale MPC8313ERDB
I2C:   ready
DRAM:  Initializing
   DDR RAM: 128 MB
FLASH:  8 MB
NAND:  32 MiB
In:    serial
Out:   serial
Err:   serial
Net:   TSEC0, TSEC1
=>
=>
=> setenv ethact TSEC1 ; setenv ipaddr 10.0.0.99 ; setenv serverip 10.0.0.2 ; setenv bootargs console=ttyS0,115200 ip=on debug ; tftp a00000 uImage ; tftp 900000 dtb ; bootm a00000 - 900000
Waiting for PHY auto negotiation to complete. done
Speed: 100, full duplex
Using TSEC1 device
TFTP from server 10.0.0.2; our IP address is 10.0.0.99
Filename 'uImage'.
Load address: 0xa00000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         ##############################
done
Bytes transferred = 1482397 (169e9d hex)
Speed: 100, full duplex
Using TSEC1 device
TFTP from server 10.0.0.2; our IP address is 10.0.0.99
Filename 'dtb'.
Load address: 0x900000
Loading: ####
done
Bytes transferred = 20000 (4e20 hex)
## Booting image at 00a00000 ...
   Image Name:   Linux-2.6.35-rc2-00058-ge411f2d
   Created:      2010-06-10   8:52:33 UTC
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    1482333 Bytes =  1.4 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
   Booting using flat device tree at 0x900000
Using MPC831x RDB machine description
Linux version 2.6.35-rc2-00058-ge411f2d (cbou@oksana) (gcc version 4.2.0 (MontaVista 4.2.0-16.0.20.0800760 2008-04-05)) #84 Thu Jun 10 12:52:32 MSD 2010
Found legacy serial port 0 for /soc8313@e0000000/serial@4500
  mem=e0004500, taddr=e0004500, irq=0, clk=166666660, speed=0
Found legacy serial port 1 for /soc8313@e0000000/serial@4600
  mem=e0004600, taddr=e0004600, irq=0, clk=166666660, speed=0
bootconsole [udbg0] enabled
setup_arch: bootmem
mpc831x_rdb_setup_arch()
arch: exit
Top of RAM: 0x8000000, Total RAM: 0x8000000
Memory hole size: 0MB
Zone PFN ranges:
  DMA      0x00000000 -> 0x00008000
  Normal   empty
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
    0: 0x00000000 -> 0x00008000
On node 0 totalpages: 32768
free_area_init_node: node 0, pgdat c0302840, node_mem_map c0321000
  DMA zone: 256 pages used for memmap
  DMA zone: 0 pages reserved
  DMA zone: 32512 pages, LIFO batch:7
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 32512
Kernel command line: console=ttyS0,115200 ip=on debug
PID hash table entries: 512 (order: -1, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 126708k/131072k available (2980k kernel code, 4364k reserved, 136k data, 83k bss, 164k init)
Kernel virtual memory layout:
  * 0xfffdf000..0xfffff000  : fixmap
  * 0xfdffc000..0xfe000000  : early ioremap
  * 0xc9000000..0xfdffc000  : vmalloc & ioremap
SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Hierarchical RCU implementation.
        RCU-based detection of stalled CPUs is disabled.
        Verbose stalled-CPUs detection is disabled.
NR_IRQS:512 nr_irqs:512
IPIC (128 IRQ sources) at c9000700
time_init: decrementer frequency = 41.666665 MHz
time_init: processor frequency   = 333.333320 MHz
clocksource: timebase mult[6000004] shift[22] registered
clockevent: decrementer mult[aaaaaa3] shift[32] cpu[0]
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
NET: Registered protocol family 16

  alloc irq_desc for 38 on node 0
  alloc kstat_irqs on node 0
irq: irq 38 on host /soc8313@e0000000/pic@700 mapped to virtual irq 38
Registering ipic with sysfs...
bio: create slab <bio-0> at 0
SCSI subsystem initialized
Switching to clocksource timebase
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
TCP reno registered
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
  alloc irq_desc for 16 on node 0
  alloc kstat_irqs on node 0
irq: irq 9 on host /soc8313@e0000000/pic@700 mapped to virtual irq 16
  alloc irq_desc for 17 on node 0
  alloc kstat_irqs on node 0
irq: irq 10 on host /soc8313@e0000000/pic@700 mapped to virtual irq 17
msgmni has been set to 247
alg: No test for stdrng (krng)
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0xe0004500 (irq = 16) is a 16550A
console [ttyS0] enabled, bootconsole disabled
console [ttyS0] enabled, bootconsole disabled
serial8250.0: ttyS1 at MMIO 0xe0004600 (irq = 17) is a 16550A
brd: module loaded
loop: module loaded
Fixed MDIO Bus: probed
  alloc irq_desc for 37 on node 0
  alloc kstat_irqs on node 0
irq: irq 37 on host /soc8313@e0000000/pic@700 mapped to virtual irq 37
  alloc irq_desc for 36 on node 0
  alloc kstat_irqs on node 0
irq: irq 36 on host /soc8313@e0000000/pic@700 mapped to virtual irq 36
  alloc irq_desc for 35 on node 0
  alloc kstat_irqs on node 0
irq: irq 35 on host /soc8313@e0000000/pic@700 mapped to virtual irq 35
eth0: Gianfar Ethernet Controller Version 1.2, 00:04:9f:ef:23:33
eth0: Running with NAPI enabled
eth0: RX BD ring size for Q[0]: 256
eth0: TX BD ring size for Q[0]: 256
  alloc irq_desc for 34 on node 0
  alloc kstat_irqs on node 0
irq: irq 34 on host /soc8313@e0000000/pic@700 mapped to virtual irq 34
  alloc irq_desc for 33 on node 0
  alloc kstat_irqs on node 0
irq: irq 33 on host /soc8313@e0000000/pic@700 mapped to virtual irq 33
  alloc irq_desc for 32 on node 0
  alloc kstat_irqs on node 0
irq: irq 32 on host /soc8313@e0000000/pic@700 mapped to virtual irq 32
eth1: Gianfar Ethernet Controller Version 1.2, 00:e0:0c:00:7e:21
eth1: Running with NAPI enabled
eth1: RX BD ring size for Q[0]: 256
eth1: TX BD ring size for Q[0]: 256
Freescale PowerQUICC MII Bus: probed
  alloc irq_desc for 20 on node 0
  alloc kstat_irqs on node 0
irq: irq 20 on host /soc8313@e0000000/pic@700 mapped to virtual irq 20
Freescale PowerQUICC MII Bus: probed
md: linear personality registered for level -1
md: raid0 personality registered for level 0
md: raid1 personality registered for level 1
TCP cubic registered
NET: Registered protocol family 17
Sending DHCP requests .
PHY: 0:01 - Link is Up - 1000/Full
PHY: mdio@e0024520:04 - Link is Up - 100/Full
..... timed out!
IP-Config: Reopening network devices...
Sending DHCP requests .
PHY: 0:01 - Link is Up - 1000/Full
PHY: mdio@e0024520:04 - Link is Up - 100/Full
.

^ permalink raw reply

* Re: CAN Subsystem and MPC52xx onboard controller
From: Roman Fietze @ 2010-06-10  9:29 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linuxppc-dev
In-Reply-To: <20100610085923.GE5333@pengutronix.de>

Hello Wolfram,

On Thursday 10 June 2010 10:59:23 Wolfram Sang wrote:

> The mainline kernel works fine here with Phytec based MPC5xxx-boards.

Reading your answer made me hope again, and I just pulled the newest
HEAD from the mainline kernel and tried it once more. Now it compiles.
Thanks for retriggering me again.

All the other's sill have problems, except pengutronix, most of them
with an inconsistency (with the socket CAN files?), which shows up as

  'struct can_bittime_std' declared inside parameter list

in net/can/dev.c:69

So I assume we will switch to the mainline kernel, which we already
use for Atom based x86 development on the MEN boards.


Thanks once more

Roman

=2D-=20
Roman Fietze                Telemotive AG B=FCro M=FChlhausen
Breitwiesen                              73347 M=FChlhausen
Tel.: +49(0)7335/18493-45        http://www.telemotive.de

^ permalink raw reply

* Re: CAN Subsystem and MPC52xx onboard controller
From: Wolfgang Grandegger @ 2010-06-10  9:25 UTC (permalink / raw)
  To: Roman Fietze; +Cc: linuxppc-dev
In-Reply-To: <201006101041.27926.roman.fietze@telemotive.de>

On 06/10/2010 10:41 AM, Roman Fietze wrote:
> Hello List Members,
> 
> I have tried multiple versions/branches and git repos (torvalds,
> benh/{next,master}, denx, pengutronix, ...) to get a 2.6.34 or HEAD
> version of that repos that compiles w/o errors when the CAN subsystem
> is enabled and the MPC5xxx onboard driver is selected starting with
> the lite5200b_defconfig.
> 
> Until now I'm out of luck. If other's also have compile problems I can
> of course offer to try to dig into the sources.

Hm, kernel.org's "linux-2.6.34.tar.bz2" builds here just fine with
lite5200b_defconfig and Socket-CAN support enabled for the MSCAN. I can
imaging that there are issues with more recent "-rc" versions due to
Grant's OF platform device generalization. Also the DTS entries entries
for MSCAN in lite5200b.dts seem OK.

> Q0:
> 
> I'm somewhat unsure what repos to use in general to develop using the
> 2.6 on a Lite5200B compatible board (for the 2.4 we always used the
> DENX repos).

Please use the mainline kernel for that board.

Wolfgang.

^ permalink raw reply

* Re: [PATCH v21 011/100] eclone (11/11): Document sys_eclone
From: Arnd Bergmann @ 2010-06-10  9:15 UTC (permalink / raw)
  To: Sukadev Bhattiprolu
  Cc: randy.dunlap, Albert Cahalan, linux-kernel, hpa, linuxppc-dev,
	roland
In-Reply-To: <20100609181431.GB1211@us.ibm.com>

On Wednesday 09 June 2010, Sukadev Bhattiprolu wrote:
> Albert and Randy point out that this would require #ifdefs in the
> application code that intends to be portable across say IA64 and x86.
> 
> Can we instead have all architectures specify [base, size] ?

No objections from me on that.

	Arnd

^ permalink raw reply

* Re: CAN Subsystem and MPC52xx onboard controller
From: Wolfram Sang @ 2010-06-10  8:59 UTC (permalink / raw)
  To: Roman Fietze; +Cc: linuxppc-dev
In-Reply-To: <201006101041.27926.roman.fietze@telemotive.de>

[-- Attachment #1: Type: text/plain, Size: 574 bytes --]

> And which one is "good" or "better" for CAN+MPC52xx if that's
> different?

The mainline kernel works fine here with Phytec based MPC5xxx-boards. Some
custom boards, too. You probably already know that it is always best to
stay as close to mainline as possible ;) Maybe just the lite-support is
slightly bit-rotten? What kind of build-errors do you get with the
mainline-kernel?

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: [PATCH 5b/5] Removing dead CONFIG_PPC47x
From: Benjamin Herrenschmidt @ 2010-06-10  8:59 UTC (permalink / raw)
  To: Josh Boyer
  Cc: Stephen Rothwell, Dave Kleikamp, vamos, linux-kernel,
	linuxppc-dev, Christoph Egger, Paul Mackerras, Torez Smith
In-Reply-To: <20100609120522.GH7801@zod.rchland.ibm.com>

On Wed, 2010-06-09 at 08:05 -0400, Josh Boyer wrote:
> On Wed, Jun 09, 2010 at 01:02:39PM +0200, Christoph Egger wrote:
> >CONFIG_PPC47x should actually be spelled CONFIG_PPC_47x as reported by
> >Andreas Schwab.
> >
> >Signed-off-by: Christoph Egger <siccegge@cs.fau.de>
> 
> Thanks, I'll pull this one in and get it merged.

I pulled your tree along with a couple of other things. I'll do a few
tests tomorrow before sending to Linus.

Cheers,
Ben.

> josh
> 
> >---
> > arch/powerpc/mm/44x_mmu.c |    4 ----
> > 1 files changed, 0 insertions(+), 4 deletions(-)
> >
> >diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
> >index d8c6efb..f70da7e 100644
> >--- a/arch/powerpc/mm/44x_mmu.c
> >+++ b/arch/powerpc/mm/44x_mmu.c
> >@@ -76,11 +76,11 @@ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
> > 		"tlbwe	%1,%3,%5\n"
> > 		"tlbwe	%0,%3,%6\n"
> > 	:
> >-#ifdef CONFIG_PPC47x
> >+#ifdef CONFIG_PPC_47x
> > 	: "r" (PPC47x_TLB2_S_RWX),
> > #else
> > 	: "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
> > #endif
> > 	  "r" (phys),
> > 	  "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M),
> > 	  "r" (entry),
> >-- 
> >1.6.3.3
> >

^ permalink raw reply

* CAN Subsystem and MPC52xx onboard controller
From: Roman Fietze @ 2010-06-10  8:41 UTC (permalink / raw)
  To: linuxppc-dev

Hello List Members,

I have tried multiple versions/branches and git repos (torvalds,
benh/{next,master}, denx, pengutronix, ...) to get a 2.6.34 or HEAD
version of that repos that compiles w/o errors when the CAN subsystem
is enabled and the MPC5xxx onboard driver is selected starting with
the lite5200b_defconfig.

Until now I'm out of luck. If other's also have compile problems I can
of course offer to try to dig into the sources.

Q0:

I'm somewhat unsure what repos to use in general to develop using the
2.6 on a Lite5200B compatible board (for the 2.4 we always used the
DENX repos).

Q1:

And which one is "good" or "better" for CAN+MPC52xx if that's
different?


Thanks for any enlightenment


Roman

=2D-=20
Roman Fietze                Telemotive AG B=FCro M=FChlhausen
Breitwiesen                              73347 M=FChlhausen
Tel.: +49(0)7335/18493-45        http://www.telemotive.de

^ permalink raw reply

* [PATCH v2] lite5200: fix ethernet phy address
From: Dmitry Eremin-Solenikov @ 2010-06-10  7:16 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Yogesh Chaudhari, Paul Mackerras, René Bürgel

According to my schematics, on Lite5200 board ethernet phy uses address
0 (all ADDR lines are pulled down). With this change I can talk to
onboard phy (LXT971) and correctly use autonegotiation.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: René Bürgel <r.buergel@unicontrol.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Yogesh Chaudhari <mr.yogesh@gmail.com>
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 arch/powerpc/boot/dts/lite5200.dts |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index 82ff2b1..2b64d8e 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -230,8 +230,8 @@
 			reg = <0x3000 0x400>;	// fec range, since we need to setup fec interrupts
 			interrupts = <2 5 0>;	// these are for "mii command finished", not link changes & co.
 
-			phy0: ethernet-phy@1 {
-				reg = <1>;
+			phy0: ethernet-phy@0 {
+				reg = <0>;
 			};
 		};
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH] lite5200: fix ethernet phy address
From: Dmitry Eremin-Solenikov @ 2010-06-10  7:11 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Yogesh Chaudhari, Paul Mackerras, René Bürgel

According to my schematics, on Lite5200 board ethernet phy uses address
0 (all ADDR lines are pulled down). With this change I can talk to
onboard phy (LXT971) and correctly use autonegotiation.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: René Bürgel <r.buergel@unicontrol.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Yogesh Chaudhari <mr.yogesh@gmail.com>
---
 arch/powerpc/boot/dts/lite5200.dts |   25 +++++++++++++++++++++++--
 1 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index 82ff2b1..3532e6f 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -230,8 +230,8 @@
 			reg = <0x3000 0x400>;	// fec range, since we need to setup fec interrupts
 			interrupts = <2 5 0>;	// these are for "mii command finished", not link changes & co.
 
-			phy0: ethernet-phy@1 {
-				reg = <1>;
+			phy0: ethernet-phy@0 {
+				reg = <0>;
 			};
 		};
 
@@ -281,4 +281,25 @@
 			  0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
 			  0x01000000 0 0x00000000 0xb0000000 0 0x01000000>;
 	};
+
+		/*
+	localbus {
+		compatible = "fsl,mpc5200b-lpb","fsl,mpc5200-lpb","simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+
+		ranges = <0 0 0xff000000 0x01000000>;
+
+		flash@0,0 {
+			compatible = "cfi-flash";
+			reg = <0 0x01000000 0x00800000>;
+			bank-width = <1>;
+			#size-cells = <1>;
+			#address-cells = <1>;
+
+		};
+	};
+*/
+
 };
-- 
1.7.1

^ permalink raw reply related

* Re: Port Linux to ML510
From: srikanth krishnakar @ 2010-06-10  7:04 UTC (permalink / raw)
  To: kostas padarnitsas; +Cc: linuxppc-dev
In-Reply-To: <BAY152-w7029D1872C3896BB5E40DBCD70@phx.gbl>

[-- Attachment #1: Type: text/plain, Size: 1374 bytes --]

Hi kostas,

You need to verify that the driver version of serial and Ethernet (probably
X-LLTEMAC) provided in the virtex440.dts matches version used in kernel.
Look for "compatible = <version>" in the drivers. You can probably use EDK
11.2 as it is the latest from Xilinx.

Have you generated your own DTS and Bitstream (download.bit) files ?

If not then you should look for suitable download.bit for you kernel.

-Srikant

2010/6/10 kostas padarnitsas <kpada84@hotmail.com>

>  Hello,
>
> I am trying to port Linux to PowerPC on the ML510 Xilinx board. I am using
> EDK 10.1.3 to build the hardware and also device tree generator and the
> linux kernel from xilinx git. I followed the tutorial from
> http://xilinx.wikidot.com/powerpc-linux but I have no output. I have
> attached my .mhs file and the .dts.  Any ideas what may cause this problem
> because I did the same thing with ML507 and it was working perfectly?
>
> Thanks in advance,
> Kostas
>
> ------------------------------
> Your E-mail and More On-the-Go. Get Windows Live Hotmail Free. Sign up
> now. <https://signup.live.com/signup.aspx?id=60969>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>



-- 
"The Good You Do, The Best You GET"

Regards
Srikanth Krishnakar
**********************

[-- Attachment #2: Type: text/html, Size: 2053 bytes --]

^ permalink raw reply

* Re: [PATCH] - PCI EEH pci_restore_state fix allowing for repeated adapter recovery per state save
From: Benjamin Herrenschmidt @ 2010-06-10  6:48 UTC (permalink / raw)
  To: Brad Peters; +Cc: linuxppc-dev, rlary
In-Reply-To: <4C084CBC.7090002@linux.vnet.ibm.com>

On Thu, 2010-06-03 at 17:45 -0700, Brad Peters wrote:
> Patch Overview:
> The pci_restore_state API is shared by both power management code and Extended
> Error Handling (EEH) code on Power.  This patch adds an additional recovery
> function to pci_restore_state API.  The problem being addressed is that Power
> Management semantics only allow the saved state of PCI device to be restored
> once per save.  With this patch, EEH is able to restore the saved state
> each time a PCI error is detected, enabling recovery in the face of repeated errors.

You should at the very least send that to the PCI maintainer (Jesse
Barnes), though I would recommend the linux-pci list and CC lkml.

Cheers,
Ben.

> There was some discussion of renaming the existing and new functions to more
> clearly break out unconditional restore from the default conditional one, but a
> name change seemed a heavy-handed change to force on the 200+ current users.
> 
> Bit more detail:
> PCI device drivers which support EEH/AER save their  pci state once during
> driver initialization and during EEH/AER error recovery, restore the
> original saved state.  What we found was that our pci driver code would
> recover from the first EEH error and fail to recover on subsequent
> EEH errors. This issue results from pci_restore_state() function
> restoring the state during initialization on the first EEH error.
> 
> What this patch does is to provide the pci_force_restore_state() for use
> by PCI drivers which support EEH/AER that require the original saved
> state be restored each time an EEH/AER error is detected.
> 
> 
> Signed-off by: Brad Peters <bpeters@us.ibm.com>
> Signed-off by: Richard A Lary <rlary@linux.vnet.ibm.com>
> 
> -- 
> Brad Peters
> IBM
> Linux on System-P Platform Serviceability Team Lead
> bpeters@linux.vnet.ibm.com
> 
> 
> -----------------
> 
> 
> diff -uNrp -X linux-2.6.34/Documentation/dontdiff
> linux-2.6.34.orig/drivers/pci/pci.c linux-2.6.34/drivers/pci/pci.c
> --- linux-2.6.34.orig/drivers/pci/pci.c	2010-05-16 14:17:36.000000000 -0700
> +++ linux-2.6.34/drivers/pci/pci.c	2010-05-26 17:16:20.000000000 -0700
> @@ -920,19 +920,11 @@ pci_save_state(struct pci_dev *dev)
>  	return 0;
>  }
> 
> -/**
> - * pci_restore_state - Restore the saved state of a PCI device
> - * @dev: - PCI device that we're dealing with
> - */
> -int
> -pci_restore_state(struct pci_dev *dev)
> +static void __pci_restore_state(struct pci_dev *dev)
>  {
>  	int i;
>  	u32 val;
> 
> -	if (!dev->state_saved)
> -		return 0;
> -
>  	/* PCI Express register must be restored first */
>  	pci_restore_pcie_state(dev);
> 
> @@ -953,12 +945,44 @@ pci_restore_state(struct pci_dev *dev)
>  	pci_restore_pcix_state(dev);
>  	pci_restore_msi_state(dev);
>  	pci_restore_iov_state(dev);
> +}
> +
> +
> +/**
> + * pci_restore_state - Restore the saved state of a PCI device
> + *                     only if dev->state_saved is not 0. Used by
> + *                     power management suspend/restore routines.
> + * @dev: - PCI device that we're dealing with
> + */
> +int
> +pci_restore_state(struct pci_dev *dev)
> +{
> +
> +	if (!dev->state_saved)
> +		return 0;
> +
> +	__pci_restore_state(dev);
> 
>  	dev->state_saved = false;
> 
>  	return 0;
>  }
> 
> +/**
> + * pci_force_restore_state - Restore the saved state of a PCI device
> + *                           even if dev->state_saved is 0. Used by
> + *                           EEH and AER PCI error recovery.
> + * @dev: - PCI device that we're dealing with
> + */
> +int
> +pci_force_restore_state(struct pci_dev *dev)
> +{
> +	__pci_restore_state(dev);
> +
> +	return 0;
> +}
> +
> +
> 
>  static int do_pci_enable_device(struct pci_dev *dev, int bars)
>  {
>  	int err;
> @@ -3039,6 +3063,7 @@ EXPORT_SYMBOL(pci_select_bars);
>  EXPORT_SYMBOL(pci_set_power_state);
>  EXPORT_SYMBOL(pci_save_state);
>  EXPORT_SYMBOL(pci_restore_state);
> +EXPORT_SYMBOL(pci_force_restore_state);
>  EXPORT_SYMBOL(pci_pme_capable);
>  EXPORT_SYMBOL(pci_pme_active);
>  EXPORT_SYMBOL(pci_wake_from_d3);
> diff -uNrp -X linux-2.6.34/Documentation/dontdiff
> linux-2.6.34.orig/include/linux/pci.h linux-2.6.34/include/linux/pci.h
> --- linux-2.6.34.orig/include/linux/pci.h	2010-05-16 14:17:36.000000000 -0700
> +++ linux-2.6.34/include/linux/pci.h	2010-05-26 17:16:21.000000000 -0700
> @@ -792,6 +792,7 @@ size_t pci_get_rom_size(struct pci_dev *
>  /* Power management related routines */
>  int pci_save_state(struct pci_dev *dev);
>  int pci_restore_state(struct pci_dev *dev);
> +int pci_force_restore_state(struct pci_dev *dev);
>  int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
>  int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
>  pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
> @@ -1155,6 +1156,11 @@ static inline int pci_restore_state(stru
>  	return 0;
>  }
> 
> +static inline int pci_force_restore_state(struct pci_dev *dev)
> +{
> +	return 0;
> +}
> +
>  static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
>  {
>  	return 0;
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

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

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.  This 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.

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
> ---
>  drivers/of/address.c |   11 ++++++++++-
>  1 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 *parent, struct of_bus *bus,
>  	 * a 1:1 translation at that level. It's up to the caller not to try
>  	 * to translate addresses that aren't supposed to be translated in
>  	 * the first place. --BenH.
> +	 *
> +	 * As far as we know, this damage only exists on Apple machines, so
> +	 * This code is only enabled on powerpc. --gcl
>  	 */
>  	ranges = of_get_property(parent, rprop, &rlen);
> +#if !defined(CONFIG_PPC)
> +	if (ranges == NULL) {
> +		pr_err("OF: no ranges; cannot translate\n");
> +		return 1;
> +	}
> +#endif /* !defined(CONFIG_PPC) */
>  	if (ranges == NULL || rlen == 0) {
>  		offset = of_read_number(addr, na);
>  		memset(addr, 0, pna * 4);
> -		pr_debug("OF: no ranges, 1:1 translation\n");
> +		pr_debug("OF: empty ranges; 1:1 translation\n");
>  		goto finish;
>  	}
>  

^ permalink raw reply

* Re: [PATCH 4/5] of/address: little-endian fixes
From: Benjamin Herrenschmidt @ 2010-06-10  6:43 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, Stephen Rothwell, Michal Simek, microblaze-uclinux
In-Reply-To: <20100608141013.25879.34892.stgit@angua>

On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
> Fix some endian issues in the OF address translation code.
> 
> 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>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> CC: microblaze-uclinux@itee.uq.edu.au
> CC: linuxppc-dev@ozlabs.org
> ---
>  drivers/of/address.c |   12 +++++++-----
>  1 files changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 2a905d5..0b04137 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -22,7 +22,7 @@ static void of_dump_addr(const char *s, const u32 *addr, int na)
>  {
>  	printk(KERN_DEBUG "%s", s);
>  	while (na--)
> -		printk(" %08x", *(addr++));
> +		printk(" %08x", be32_to_cpu(*(addr++)));
>  	printk("\n");
>  }
>  #else
> @@ -79,8 +79,8 @@ static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>  	memset(addr, 0, na * 4);
>  	a += offset;
>  	if (na > 1)
> -		addr[na - 2] = a >> 32;
> -	addr[na - 1] = a & 0xffffffffu;
> +		addr[na - 2] = cpu_to_be32(a >> 32);
> +	addr[na - 1] = cpu_to_be32(a & 0xffffffffu);
>  
>  	return 0;
>  }
> @@ -190,14 +190,16 @@ const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
>  	psize /= 4;
>  
>  	onesize = na + ns;
> -	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -		if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> +	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) {
> +		u32 val = be32_to_cpu(prop[0]);
> +		if ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
>  			if (size)
>  				*size = of_read_number(prop + na, ns);
>  			if (flags)
>  				*flags = bus->get_flags(prop);
>  			return prop;
>  		}
> +	}
>  	return NULL;
>  }
>  EXPORT_SYMBOL(of_get_pci_address);

^ permalink raw reply

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

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.  There aren't many differences
                                                           ^^^^
Care to comment on these differences ?

> 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
> ---
>  arch/microblaze/include/asm/prom.h  |    4 
>  arch/microblaze/kernel/prom_parse.c |  489 ---------------------------------
>  arch/powerpc/include/asm/prom.h     |    4 
>  arch/powerpc/kernel/prom_parse.c    |  515 -----------------------------------
>  drivers/of/address.c                |  517 +++++++++++++++++++++++++++++++++++
>  include/linux/of_address.h          |    4 
>  6 files changed, 515 insertions(+), 1018 deletions(-)
> 
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/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);
>   * OF address retreival & translation
>   */
>  
> -/* Translate an OF address block into a CPU physical address
> - */
> -extern u64 of_translate_address(struct device_node *np, const u32 *addr);
> -
>  /* Extract an address from a device, returns the region size and
>   * the address space flags too. The PCI version uses a BAR number
>   * instead of an absolute index
> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/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 @@
>  #include <asm/prom.h>
>  #include <asm/pci-bridge.h>
>  
> -#define PRu64	"%llx"
> -
> -/* Max address size we deal with */
> -#define OF_MAX_ADDR_CELLS	4
> -#define OF_CHECK_COUNTS(na, ns)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
> -			(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)
> -{
> -	printk(KERN_INFO "%s", s);
> -	while (na--)
> -		printk(KERN_INFO " %08x", *(addr++));
> -	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 {
> -	const char	*name;
> -	const char	*addresses;
> -	int		(*match)(struct device_node *parent);
> -	void		(*count_cells)(struct device_node *child,
> -					int *addrc, int *sizec);
> -	u64		(*map)(u32 *addr, const u32 *range,
> -				int na, int ns, int pna);
> -	int		(*translate)(u32 *addr, u64 offset, int na);
> -	unsigned int	(*get_flags)(const u32 *addr);
> -};
> -
> -/*
> - * Default translator (generic bus)
> - */
> -
> -static void of_bus_default_count_cells(struct device_node *dev,
> -					int *addrc, int *sizec)
> -{
> -	if (addrc)
> -		*addrc = of_n_addr_cells(dev);
> -	if (sizec)
> -		*sizec = of_n_size_cells(dev);
> -}
> -
> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
> -		int na, int ns, int pna)
> -{
> -	u64 cp, s, da;
> -
> -	cp = of_read_number(range, na);
> -	s  = of_read_number(range + na + pna, ns);
> -	da = of_read_number(addr, na);
> -
> -	pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
> -		cp, s, da);
> -
> -	if (da < cp || da >= (cp + s))
> -		return OF_BAD_ADDR;
> -	return da - cp;
> -}
> -
> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
> -{
> -	u64 a = of_read_number(addr, na);
> -	memset(addr, 0, na * 4);
> -	a += offset;
> -	if (na > 1)
> -		addr[na - 2] = a >> 32;
> -	addr[na - 1] = a & 0xffffffffu;
> -
> -	return 0;
> -}
> -
> -static unsigned int of_bus_default_get_flags(const u32 *addr)
> -{
> -	return IORESOURCE_MEM;
> -}
> -
>  #ifdef CONFIG_PCI
> -/*
> - * PCI bus specific translator
> - */
> -
> -static int of_bus_pci_match(struct device_node *np)
> -{
> -	/* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
> -	return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
> -}
> -
> -static void of_bus_pci_count_cells(struct device_node *np,
> -				int *addrc, int *sizec)
> -{
> -	if (addrc)
> -		*addrc = 3;
> -	if (sizec)
> -		*sizec = 2;
> -}
> -
> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
> -{
> -	u64 cp, s, da;
> -
> -	/* Check address type match */
> -	if ((addr[0] ^ range[0]) & 0x03000000)
> -		return OF_BAD_ADDR;
> -
> -	/* Read address values, skipping high cell */
> -	cp = of_read_number(range + 1, na - 1);
> -	s  = of_read_number(range + na + pna, ns);
> -	da = of_read_number(addr + 1, na - 1);
> -
> -	pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -	if (da < cp || da >= (cp + s))
> -		return OF_BAD_ADDR;
> -	return da - cp;
> -}
> -
> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
> -{
> -	return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
> -{
> -	unsigned int flags = 0;
> -	u32 w = addr[0];
> -
> -	switch ((w >> 24) & 0x03) {
> -	case 0x01:
> -		flags |= IORESOURCE_IO;
> -		break;
> -	case 0x02: /* 32 bits */
> -	case 0x03: /* 64 bits */
> -		flags |= IORESOURCE_MEM;
> -		break;
> -	}
> -	if (w & 0x40000000)
> -		flags |= IORESOURCE_PREFETCH;
> -	return flags;
> -}
> -
> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
> -			unsigned int *flags)
> -{
> -	const u32 *prop;
> -	unsigned int psize;
> -	struct device_node *parent;
> -	struct of_bus *bus;
> -	int onesize, i, na, ns;
> -
> -	/* Get parent & match bus type */
> -	parent = of_get_parent(dev);
> -	if (parent == NULL)
> -		return NULL;
> -	bus = of_match_bus(parent);
> -	if (strcmp(bus->name, "pci")) {
> -		of_node_put(parent);
> -		return NULL;
> -	}
> -	bus->count_cells(dev, &na, &ns);
> -	of_node_put(parent);
> -	if (!OF_CHECK_COUNTS(na, ns))
> -		return NULL;
> -
> -	/* Get "reg" or "assigned-addresses" property */
> -	prop = of_get_property(dev, bus->addresses, &psize);
> -	if (prop == NULL)
> -		return NULL;
> -	psize /= 4;
> -
> -	onesize = na + ns;
> -	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -		if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> -			if (size)
> -				*size = of_read_number(prop + na, ns);
> -			if (flags)
> -				*flags = bus->get_flags(prop);
> -			return prop;
> -		}
> -	return NULL;
> -}
> -EXPORT_SYMBOL(of_get_pci_address);
> -
> -int of_pci_address_to_resource(struct device_node *dev, int bar,
> -				struct resource *r)
> -{
> -	const u32	*addrp;
> -	u64		size;
> -	unsigned int	flags;
> -
> -	addrp = of_get_pci_address(dev, bar, &size, &flags);
> -	if (addrp == NULL)
> -		return -EINVAL;
> -	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)
> -{
> -	return (((pin - 1) + slot) % 4) + 1;
> -}
> -
>  int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>  {
>  	struct device_node *dn, *ppnode;
> @@ -291,289 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>  EXPORT_SYMBOL_GPL(of_irq_map_pci);
>  #endif /* CONFIG_PCI */
>  
> -/*
> - * ISA bus specific translator
> - */
> -
> -static int of_bus_isa_match(struct device_node *np)
> -{
> -	return !strcmp(np->name, "isa");
> -}
> -
> -static void of_bus_isa_count_cells(struct device_node *child,
> -				int *addrc, int *sizec)
> -{
> -	if (addrc)
> -		*addrc = 2;
> -	if (sizec)
> -		*sizec = 1;
> -}
> -
> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
> -{
> -	u64 cp, s, da;
> -
> -	/* Check address type match */
> -	if ((addr[0] ^ range[0]) & 0x00000001)
> -		return OF_BAD_ADDR;
> -
> -	/* Read address values, skipping high cell */
> -	cp = of_read_number(range + 1, na - 1);
> -	s  = of_read_number(range + na + pna, ns);
> -	da = of_read_number(addr + 1, na - 1);
> -
> -	pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -	if (da < cp || da >= (cp + s))
> -		return OF_BAD_ADDR;
> -	return da - cp;
> -}
> -
> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
> -{
> -	return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
> -{
> -	unsigned int flags = 0;
> -	u32 w = addr[0];
> -
> -	if (w & 1)
> -		flags |= IORESOURCE_IO;
> -	else
> -		flags |= IORESOURCE_MEM;
> -	return flags;
> -}
> -
> -/*
> - * Array of bus specific translators
> - */
> -
> -static struct of_bus of_busses[] = {
> -#ifdef CONFIG_PCI
> -	/* PCI */
> -	{
> -		.name = "pci",
> -		.addresses = "assigned-addresses",
> -		.match = of_bus_pci_match,
> -		.count_cells = of_bus_pci_count_cells,
> -		.map = of_bus_pci_map,
> -		.translate = of_bus_pci_translate,
> -		.get_flags = of_bus_pci_get_flags,
> -	},
> -#endif /* CONFIG_PCI */
> -	/* ISA */
> -	{
> -		.name = "isa",
> -		.addresses = "reg",
> -		.match = of_bus_isa_match,
> -		.count_cells = of_bus_isa_count_cells,
> -		.map = of_bus_isa_map,
> -		.translate = of_bus_isa_translate,
> -		.get_flags = of_bus_isa_get_flags,
> -	},
> -	/* Default */
> -	{
> -		.name = "default",
> -		.addresses = "reg",
> -		.match = NULL,
> -		.count_cells = of_bus_default_count_cells,
> -		.map = of_bus_default_map,
> -		.translate = of_bus_default_translate,
> -		.get_flags = of_bus_default_get_flags,
> -	},
> -};
> -
> -static struct of_bus *of_match_bus(struct device_node *np)
> -{
> -	int i;
> -
> -	for (i = 0; i < ARRAY_SIZE(of_busses); i++)
> -		if (!of_busses[i].match || of_busses[i].match(np))
> -			return &of_busses[i];
> -	BUG();
> -	return NULL;
> -}
> -
> -static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> -			struct of_bus *pbus, u32 *addr,
> -			int na, int ns, int pna)
> -{
> -	const u32 *ranges;
> -	unsigned int rlen;
> -	int rone;
> -	u64 offset = OF_BAD_ADDR;
> -
> -	/* Normally, an absence of a "ranges" property means we are
> -	 * crossing a non-translatable boundary, and thus the addresses
> -	 * below the current not cannot be converted to CPU physical ones.
> -	 * Unfortunately, while this is very clear in the spec, it's not
> -	 * what Apple understood, and they do have things like /uni-n or
> -	 * /ht nodes with no "ranges" property and a lot of perfectly
> -	 * useable mapped devices below them. Thus we treat the absence of
> -	 * "ranges" as equivalent to an empty "ranges" property which means
> -	 * a 1:1 translation at that level. It's up to the caller not to try
> -	 * to translate addresses that aren't supposed to be translated in
> -	 * the first place. --BenH.
> -	 */
> -	ranges = of_get_property(parent, "ranges", (int *) &rlen);
> -	if (ranges == NULL || rlen == 0) {
> -		offset = of_read_number(addr, na);
> -		memset(addr, 0, pna * 4);
> -		pr_debug("OF: no ranges, 1:1 translation\n");
> -		goto finish;
> -	}
> -
> -	pr_debug("OF: walking ranges...\n");
> -
> -	/* Now walk through the ranges */
> -	rlen /= 4;
> -	rone = na + pna + ns;
> -	for (; rlen >= rone; rlen -= rone, ranges += rone) {
> -		offset = bus->map(addr, ranges, na, ns, pna);
> -		if (offset != OF_BAD_ADDR)
> -			break;
> -	}
> -	if (offset == OF_BAD_ADDR) {
> -		pr_debug("OF: not found !\n");
> -		return 1;
> -	}
> -	memcpy(addr, ranges + na, 4 * pna);
> -
> - finish:
> -	of_dump_addr("OF: parent translation for:", addr, pna);
> -	pr_debug("OF: with offset: "PRu64"\n", offset);
> -
> -	/* Translate it into parent bus space */
> -	return pbus->translate(addr, offset, pna);
> -}
> -
> -/*
> - * Translate an address from the device-tree into a CPU physical address,
> - * this walks up the tree and applies the various bus mappings on the
> - * way.
> - *
> - * Note: We consider that crossing any level with #size-cells == 0 to mean
> - * that translation is impossible (that is we are not dealing with a value
> - * that can be mapped to a cpu physical address). This is not really specified
> - * 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)
> -{
> -	struct device_node *parent = NULL;
> -	struct of_bus *bus, *pbus;
> -	u32 addr[OF_MAX_ADDR_CELLS];
> -	int na, ns, pna, pns;
> -	u64 result = OF_BAD_ADDR;
> -
> -	pr_debug("OF: ** translation for device %s **\n", dev->full_name);
> -
> -	/* Increase refcount at current level */
> -	of_node_get(dev);
> -
> -	/* Get parent & match bus type */
> -	parent = of_get_parent(dev);
> -	if (parent == NULL)
> -		goto bail;
> -	bus = of_match_bus(parent);
> -
> -	/* Cound address cells & copy address locally */
> -	bus->count_cells(dev, &na, &ns);
> -	if (!OF_CHECK_COUNTS(na, ns)) {
> -		printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -			dev->full_name);
> -		goto bail;
> -	}
> -	memcpy(addr, in_addr, na * 4);
> -
> -	pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
> -		bus->name, na, ns, parent->full_name);
> -	of_dump_addr("OF: translating address:", addr, na);
> -
> -	/* Translate */
> -	for (;;) {
> -		/* Switch to parent bus */
> -		of_node_put(dev);
> -		dev = parent;
> -		parent = of_get_parent(dev);
> -
> -		/* If root, we have finished */
> -		if (parent == NULL) {
> -			pr_debug("OF: reached root node\n");
> -			result = of_read_number(addr, na);
> -			break;
> -		}
> -
> -		/* Get new parent bus and counts */
> -		pbus = of_match_bus(parent);
> -		pbus->count_cells(dev, &pna, &pns);
> -		if (!OF_CHECK_COUNTS(pna, pns)) {
> -			printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -				dev->full_name);
> -			break;
> -		}
> -
> -		pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
> -			pbus->name, pna, pns, parent->full_name);
> -
> -		/* Apply bus translation */
> -		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
> -			break;
> -
> -		/* Complete the move up one level */
> -		na = pna;
> -		ns = pns;
> -		bus = pbus;
> -
> -		of_dump_addr("OF: one level translation:", addr, na);
> -	}
> - bail:
> -	of_node_put(parent);
> -	of_node_put(dev);
> -
> -	return result;
> -}
> -EXPORT_SYMBOL(of_translate_address);
> -
> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
> -			unsigned int *flags)
> -{
> -	const u32 *prop;
> -	unsigned int psize;
> -	struct device_node *parent;
> -	struct of_bus *bus;
> -	int onesize, i, na, ns;
> -
> -	/* Get parent & match bus type */
> -	parent = of_get_parent(dev);
> -	if (parent == NULL)
> -		return NULL;
> -	bus = of_match_bus(parent);
> -	bus->count_cells(dev, &na, &ns);
> -	of_node_put(parent);
> -	if (!OF_CHECK_COUNTS(na, ns))
> -		return NULL;
> -
> -	/* Get "reg" or "assigned-addresses" property */
> -	prop = of_get_property(dev, bus->addresses, (int *) &psize);
> -	if (prop == NULL)
> -		return NULL;
> -	psize /= 4;
> -
> -	onesize = na + ns;
> -	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -		if (i == index) {
> -			if (size)
> -				*size = of_read_number(prop + na, ns);
> -			if (flags)
> -				*flags = bus->get_flags(prop);
> -			return prop;
> -		}
> -	return NULL;
> -}
> -EXPORT_SYMBOL(of_get_address);
> -
>  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>  		unsigned long *busno, unsigned long *phys, unsigned long *size)
>  {
> 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);
>   * OF address retreival & translation
>   */
>  
> -/* Translate an OF address block into a CPU physical address
> - */
> -extern u64 of_translate_address(struct device_node *np, const u32 *addr);
> -
>  /* Translate a DMA address from device space to CPU space */
>  extern u64 of_translate_dma_address(struct device_node *dev,
>  				    const 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 @@
>  #include <asm/prom.h>
>  #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	"%lx"
> -#else
> -#define PRu64	"%llx"
> -#endif
> -
> -/* Max address size we deal with */
> -#define OF_MAX_ADDR_CELLS	4
> -#define OF_CHECK_COUNTS(na, ns)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
> -			(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)
> -{
> -	printk("%s", s);
> -	while(na--)
> -		printk(" %08x", *(addr++));
> -	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 {
> -	const char	*name;
> -	const char	*addresses;
> -	int		(*match)(struct device_node *parent);
> -	void		(*count_cells)(struct device_node *child,
> -				       int *addrc, int *sizec);
> -	u64		(*map)(u32 *addr, const u32 *range,
> -				int na, int ns, int pna);
> -	int		(*translate)(u32 *addr, u64 offset, int na);
> -	unsigned int	(*get_flags)(const u32 *addr);
> -};
> -
> -
> -/*
> - * Default translator (generic bus)
> - */
> -
> -static void of_bus_default_count_cells(struct device_node *dev,
> -				       int *addrc, int *sizec)
> -{
> -	if (addrc)
> -		*addrc = of_n_addr_cells(dev);
> -	if (sizec)
> -		*sizec = of_n_size_cells(dev);
> -}
> -
> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
> -		int na, int ns, int pna)
> -{
> -	u64 cp, s, da;
> -
> -	cp = of_read_number(range, na);
> -	s  = of_read_number(range + na + pna, ns);
> -	da = of_read_number(addr, na);
> -
> -	DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
> -	    cp, s, da);
> -
> -	if (da < cp || da >= (cp + s))
> -		return OF_BAD_ADDR;
> -	return da - cp;
> -}
> -
> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
> -{
> -	u64 a = of_read_number(addr, na);
> -	memset(addr, 0, na * 4);
> -	a += offset;
> -	if (na > 1)
> -		addr[na - 2] = a >> 32;
> -	addr[na - 1] = a & 0xffffffffu;
> -
> -	return 0;
> -}
> -
> -static unsigned int of_bus_default_get_flags(const u32 *addr)
> -{
> -	return IORESOURCE_MEM;
> -}
> -
> -
>  #ifdef CONFIG_PCI
> -/*
> - * PCI bus specific translator
> - */
> -
> -static int of_bus_pci_match(struct device_node *np)
> -{
> -	/* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
> -	return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
> -}
> -
> -static void of_bus_pci_count_cells(struct device_node *np,
> -				   int *addrc, int *sizec)
> -{
> -	if (addrc)
> -		*addrc = 3;
> -	if (sizec)
> -		*sizec = 2;
> -}
> -
> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
> -{
> -	unsigned int flags = 0;
> -	u32 w = addr[0];
> -
> -	switch((w >> 24) & 0x03) {
> -	case 0x01:
> -		flags |= IORESOURCE_IO;
> -		break;
> -	case 0x02: /* 32 bits */
> -	case 0x03: /* 64 bits */
> -		flags |= IORESOURCE_MEM;
> -		break;
> -	}
> -	if (w & 0x40000000)
> -		flags |= IORESOURCE_PREFETCH;
> -	return flags;
> -}
> -
> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
> -{
> -	u64 cp, s, da;
> -	unsigned int af, rf;
> -
> -	af = of_bus_pci_get_flags(addr);
> -	rf = of_bus_pci_get_flags(range);
> -
> -	/* Check address type match */
> -	if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
> -		return OF_BAD_ADDR;
> -
> -	/* Read address values, skipping high cell */
> -	cp = of_read_number(range + 1, na - 1);
> -	s  = of_read_number(range + na + pna, ns);
> -	da = of_read_number(addr + 1, na - 1);
> -
> -	DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -	if (da < cp || da >= (cp + s))
> -		return OF_BAD_ADDR;
> -	return da - cp;
> -}
> -
> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
> -{
> -	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,
> -			unsigned int *flags)
> -{
> -	const u32 *prop;
> -	unsigned int psize;
> -	struct device_node *parent;
> -	struct of_bus *bus;
> -	int onesize, i, na, ns;
> -
> -	/* Get parent & match bus type */
> -	parent = of_get_parent(dev);
> -	if (parent == NULL)
> -		return NULL;
> -	bus = of_match_bus(parent);
> -	if (strcmp(bus->name, "pci")) {
> -		of_node_put(parent);
> -		return NULL;
> -	}
> -	bus->count_cells(dev, &na, &ns);
> -	of_node_put(parent);
> -	if (!OF_CHECK_COUNTS(na, ns))
> -		return NULL;
> -
> -	/* Get "reg" or "assigned-addresses" property */
> -	prop = of_get_property(dev, bus->addresses, &psize);
> -	if (prop == NULL)
> -		return NULL;
> -	psize /= 4;
> -
> -	onesize = na + ns;
> -	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -		if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> -			if (size)
> -				*size = of_read_number(prop + na, ns);
> -			if (flags)
> -				*flags = bus->get_flags(prop);
> -			return prop;
> -		}
> -	return NULL;
> -}
> -EXPORT_SYMBOL(of_get_pci_address);
> -
> -int of_pci_address_to_resource(struct device_node *dev, int bar,
> -			       struct resource *r)
> -{
> -	const u32	*addrp;
> -	u64		size;
> -	unsigned int	flags;
> -
> -	addrp = of_get_pci_address(dev, bar, &size, &flags);
> -	if (addrp == NULL)
> -		return -EINVAL;
> -	return __of_address_to_resource(dev, addrp, size, flags, r);
> -}
> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
> -
>  int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>  {
>  	struct device_node *dn, *ppnode;
> @@ -310,303 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>  EXPORT_SYMBOL_GPL(of_irq_map_pci);
>  #endif /* CONFIG_PCI */
>  
> -/*
> - * ISA bus specific translator
> - */
> -
> -static int of_bus_isa_match(struct device_node *np)
> -{
> -	return !strcmp(np->name, "isa");
> -}
> -
> -static void of_bus_isa_count_cells(struct device_node *child,
> -				   int *addrc, int *sizec)
> -{
> -	if (addrc)
> -		*addrc = 2;
> -	if (sizec)
> -		*sizec = 1;
> -}
> -
> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
> -{
> -	u64 cp, s, da;
> -
> -	/* Check address type match */
> -	if ((addr[0] ^ range[0]) & 0x00000001)
> -		return OF_BAD_ADDR;
> -
> -	/* Read address values, skipping high cell */
> -	cp = of_read_number(range + 1, na - 1);
> -	s  = of_read_number(range + na + pna, ns);
> -	da = of_read_number(addr + 1, na - 1);
> -
> -	DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -	if (da < cp || da >= (cp + s))
> -		return OF_BAD_ADDR;
> -	return da - cp;
> -}
> -
> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
> -{
> -	return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
> -{
> -	unsigned int flags = 0;
> -	u32 w = addr[0];
> -
> -	if (w & 1)
> -		flags |= IORESOURCE_IO;
> -	else
> -		flags |= IORESOURCE_MEM;
> -	return flags;
> -}
> -
> -
> -/*
> - * Array of bus specific translators
> - */
> -
> -static struct of_bus of_busses[] = {
> -#ifdef CONFIG_PCI
> -	/* PCI */
> -	{
> -		.name = "pci",
> -		.addresses = "assigned-addresses",
> -		.match = of_bus_pci_match,
> -		.count_cells = of_bus_pci_count_cells,
> -		.map = of_bus_pci_map,
> -		.translate = of_bus_pci_translate,
> -		.get_flags = of_bus_pci_get_flags,
> -	},
> -#endif /* CONFIG_PCI */
> -	/* ISA */
> -	{
> -		.name = "isa",
> -		.addresses = "reg",
> -		.match = of_bus_isa_match,
> -		.count_cells = of_bus_isa_count_cells,
> -		.map = of_bus_isa_map,
> -		.translate = of_bus_isa_translate,
> -		.get_flags = of_bus_isa_get_flags,
> -	},
> -	/* Default */
> -	{
> -		.name = "default",
> -		.addresses = "reg",
> -		.match = NULL,
> -		.count_cells = of_bus_default_count_cells,
> -		.map = of_bus_default_map,
> -		.translate = of_bus_default_translate,
> -		.get_flags = of_bus_default_get_flags,
> -	},
> -};
> -
> -static struct of_bus *of_match_bus(struct device_node *np)
> -{
> -	int i;
> -
> -	for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
> -		if (!of_busses[i].match || of_busses[i].match(np))
> -			return &of_busses[i];
> -	BUG();
> -	return NULL;
> -}
> -
> -static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> -			    struct of_bus *pbus, u32 *addr,
> -			    int na, int ns, int pna, const char *rprop)
> -{
> -	const u32 *ranges;
> -	unsigned int rlen;
> -	int rone;
> -	u64 offset = OF_BAD_ADDR;
> -
> -	/* Normally, an absence of a "ranges" property means we are
> -	 * crossing a non-translatable boundary, and thus the addresses
> -	 * below the current not cannot be converted to CPU physical ones.
> -	 * Unfortunately, while this is very clear in the spec, it's not
> -	 * what Apple understood, and they do have things like /uni-n or
> -	 * /ht nodes with no "ranges" property and a lot of perfectly
> -	 * useable mapped devices below them. Thus we treat the absence of
> -	 * "ranges" as equivalent to an empty "ranges" property which means
> -	 * a 1:1 translation at that level. It's up to the caller not to try
> -	 * to translate addresses that aren't supposed to be translated in
> -	 * the first place. --BenH.
> -	 */
> -	ranges = of_get_property(parent, rprop, &rlen);
> -	if (ranges == NULL || rlen == 0) {
> -		offset = of_read_number(addr, na);
> -		memset(addr, 0, pna * 4);
> -		DBG("OF: no ranges, 1:1 translation\n");
> -		goto finish;
> -	}
> -
> -	DBG("OF: walking ranges...\n");
> -
> -	/* Now walk through the ranges */
> -	rlen /= 4;
> -	rone = na + pna + ns;
> -	for (; rlen >= rone; rlen -= rone, ranges += rone) {
> -		offset = bus->map(addr, ranges, na, ns, pna);
> -		if (offset != OF_BAD_ADDR)
> -			break;
> -	}
> -	if (offset == OF_BAD_ADDR) {
> -		DBG("OF: not found !\n");
> -		return 1;
> -	}
> -	memcpy(addr, ranges + na, 4 * pna);
> -
> - finish:
> -	of_dump_addr("OF: parent translation for:", addr, pna);
> -	DBG("OF: with offset: "PRu64"\n", offset);
> -
> -	/* Translate it into parent bus space */
> -	return pbus->translate(addr, offset, pna);
> -}
> -
> -
> -/*
> - * Translate an address from the device-tree into a CPU physical address,
> - * this walks up the tree and applies the various bus mappings on the
> - * way.
> - *
> - * Note: We consider that crossing any level with #size-cells == 0 to mean
> - * that translation is impossible (that is we are not dealing with a value
> - * that can be mapped to a cpu physical address). This is not really specified
> - * 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,
> -			   const char *rprop)
> -{
> -	struct device_node *parent = NULL;
> -	struct of_bus *bus, *pbus;
> -	u32 addr[OF_MAX_ADDR_CELLS];
> -	int na, ns, pna, pns;
> -	u64 result = OF_BAD_ADDR;
> -
> -	DBG("OF: ** translation for device %s **\n", dev->full_name);
> -
> -	/* Increase refcount at current level */
> -	of_node_get(dev);
> -
> -	/* Get parent & match bus type */
> -	parent = of_get_parent(dev);
> -	if (parent == NULL)
> -		goto bail;
> -	bus = of_match_bus(parent);
> -
> -	/* Cound address cells & copy address locally */
> -	bus->count_cells(dev, &na, &ns);
> -	if (!OF_CHECK_COUNTS(na, ns)) {
> -		printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -		       dev->full_name);
> -		goto bail;
> -	}
> -	memcpy(addr, in_addr, na * 4);
> -
> -	DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
> -	    bus->name, na, ns, parent->full_name);
> -	of_dump_addr("OF: translating address:", addr, na);
> -
> -	/* Translate */
> -	for (;;) {
> -		/* Switch to parent bus */
> -		of_node_put(dev);
> -		dev = parent;
> -		parent = of_get_parent(dev);
> -
> -		/* If root, we have finished */
> -		if (parent == NULL) {
> -			DBG("OF: reached root node\n");
> -			result = of_read_number(addr, na);
> -			break;
> -		}
> -
> -		/* Get new parent bus and counts */
> -		pbus = of_match_bus(parent);
> -		pbus->count_cells(dev, &pna, &pns);
> -		if (!OF_CHECK_COUNTS(pna, pns)) {
> -			printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -			       dev->full_name);
> -			break;
> -		}
> -
> -		DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
> -		    pbus->name, pna, pns, parent->full_name);
> -
> -		/* Apply bus translation */
> -		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
> -			break;
> -
> -		/* Complete the move up one level */
> -		na = pna;
> -		ns = pns;
> -		bus = pbus;
> -
> -		of_dump_addr("OF: one level translation:", addr, na);
> -	}
> - bail:
> -	of_node_put(parent);
> -	of_node_put(dev);
> -
> -	return result;
> -}
> -
> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
> -{
> -	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_addr)
> -{
> -	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,
> -		    unsigned int *flags)
> -{
> -	const u32 *prop;
> -	unsigned int psize;
> -	struct device_node *parent;
> -	struct of_bus *bus;
> -	int onesize, i, na, ns;
> -
> -	/* Get parent & match bus type */
> -	parent = of_get_parent(dev);
> -	if (parent == NULL)
> -		return NULL;
> -	bus = of_match_bus(parent);
> -	bus->count_cells(dev, &na, &ns);
> -	of_node_put(parent);
> -	if (!OF_CHECK_COUNTS(na, ns))
> -		return NULL;
> -
> -	/* Get "reg" or "assigned-addresses" property */
> -	prop = of_get_property(dev, bus->addresses, &psize);
> -	if (prop == NULL)
> -		return NULL;
> -	psize /= 4;
> -
> -	onesize = na + ns;
> -	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -		if (i == index) {
> -			if (size)
> -				*size = of_read_number(prop + na, ns);
> -			if (flags)
> -				*flags = bus->get_flags(prop);
> -			return prop;
> -		}
> -	return NULL;
> -}
> -EXPORT_SYMBOL(of_get_address);
> -
>  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>  		unsigned long *busno, unsigned long *phys, unsigned long *size)
>  {
> 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 @@
>  
>  #include <linux/io.h>
>  #include <linux/ioport.h>
> +#include <linux/module.h>
>  #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,
> -			     u64 size, unsigned int flags,
> -			     struct resource *r)
> +/* Max address size we deal with */
> +#define OF_MAX_ADDR_CELLS	4
> +#define OF_CHECK_COUNTS(na, ns)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
> +			(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,
> +				    u64 size, unsigned int flags,
> +				    struct resource *r);
> +
> +/* Debug utility */
> +#ifdef DEBUG
> +static void of_dump_addr(const char *s, const u32 *addr, int na)
> +{
> +	printk(KERN_DEBUG "%s", s);
> +	while (na--)
> +		printk(" %08x", *(addr++));
> +	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 {
> +	const char	*name;
> +	const char	*addresses;
> +	int		(*match)(struct device_node *parent);
> +	void		(*count_cells)(struct device_node *child,
> +				       int *addrc, int *sizec);
> +	u64		(*map)(u32 *addr, const u32 *range,
> +				int na, int ns, int pna);
> +	int		(*translate)(u32 *addr, u64 offset, int na);
> +	unsigned int	(*get_flags)(const u32 *addr);
> +};
> +
> +/*
> + * Default translator (generic bus)
> + */
> +
> +static void of_bus_default_count_cells(struct device_node *dev,
> +				       int *addrc, int *sizec)
> +{
> +	if (addrc)
> +		*addrc = of_n_addr_cells(dev);
> +	if (sizec)
> +		*sizec = of_n_size_cells(dev);
> +}
> +
> +static u64 of_bus_default_map(u32 *addr, const u32 *range,
> +		int na, int ns, int pna)
> +{
> +	u64 cp, s, da;
> +
> +	cp = of_read_number(range, na);
> +	s  = of_read_number(range + na + pna, ns);
> +	da = of_read_number(addr, na);
> +
> +	pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
> +		 (unsigned long long)cp, (unsigned long long)s,
> +		 (unsigned long long)da);
> +
> +	if (da < cp || da >= (cp + s))
> +		return OF_BAD_ADDR;
> +	return da - cp;
> +}
> +
> +static int of_bus_default_translate(u32 *addr, u64 offset, int na)
> +{
> +	u64 a = of_read_number(addr, na);
> +	memset(addr, 0, na * 4);
> +	a += offset;
> +	if (na > 1)
> +		addr[na - 2] = a >> 32;
> +	addr[na - 1] = a & 0xffffffffu;
> +
> +	return 0;
> +}
> +
> +static unsigned int of_bus_default_get_flags(const u32 *addr)
> +{
> +	return IORESOURCE_MEM;
> +}
> +
> +#ifdef CONFIG_PCI
> +/*
> + * PCI bus specific translator
> + */
> +
> +static int of_bus_pci_match(struct device_node *np)
> +{
> +	/* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
> +	return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
> +}
> +
> +static void of_bus_pci_count_cells(struct device_node *np,
> +				   int *addrc, int *sizec)
> +{
> +	if (addrc)
> +		*addrc = 3;
> +	if (sizec)
> +		*sizec = 2;
> +}
> +
> +static unsigned int of_bus_pci_get_flags(const u32 *addr)
> +{
> +	unsigned int flags = 0;
> +	u32 w = addr[0];
> +
> +	switch((w >> 24) & 0x03) {
> +	case 0x01:
> +		flags |= IORESOURCE_IO;
> +		break;
> +	case 0x02: /* 32 bits */
> +	case 0x03: /* 64 bits */
> +		flags |= IORESOURCE_MEM;
> +		break;
> +	}
> +	if (w & 0x40000000)
> +		flags |= IORESOURCE_PREFETCH;
> +	return flags;
> +}
> +
> +static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
> +{
> +	u64 cp, s, da;
> +	unsigned int af, rf;
> +
> +	af = of_bus_pci_get_flags(addr);
> +	rf = of_bus_pci_get_flags(range);
> +
> +	/* Check address type match */
> +	if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
> +		return OF_BAD_ADDR;
> +
> +	/* Read address values, skipping high cell */
> +	cp = of_read_number(range + 1, na - 1);
> +	s  = of_read_number(range + na + pna, ns);
> +	da = of_read_number(addr + 1, na - 1);
> +
> +	pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n",
> +		 (unsigned long long)cp, (unsigned long long)s,
> +		 (unsigned long long)da);
> +
> +	if (da < cp || da >= (cp + s))
> +		return OF_BAD_ADDR;
> +	return da - cp;
> +}
> +
> +static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
> +{
> +	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,
> +			unsigned int *flags)
> +{
> +	const u32 *prop;
> +	unsigned int psize;
> +	struct device_node *parent;
> +	struct of_bus *bus;
> +	int onesize, i, na, ns;
> +
> +	/* Get parent & match bus type */
> +	parent = of_get_parent(dev);
> +	if (parent == NULL)
> +		return NULL;
> +	bus = of_match_bus(parent);
> +	if (strcmp(bus->name, "pci")) {
> +		of_node_put(parent);
> +		return NULL;
> +	}
> +	bus->count_cells(dev, &na, &ns);
> +	of_node_put(parent);
> +	if (!OF_CHECK_COUNTS(na, ns))
> +		return NULL;
> +
> +	/* Get "reg" or "assigned-addresses" property */
> +	prop = of_get_property(dev, bus->addresses, &psize);
> +	if (prop == NULL)
> +		return NULL;
> +	psize /= 4;
> +
> +	onesize = na + ns;
> +	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> +		if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> +			if (size)
> +				*size = of_read_number(prop + na, ns);
> +			if (flags)
> +				*flags = bus->get_flags(prop);
> +			return prop;
> +		}
> +	return NULL;
> +}
> +EXPORT_SYMBOL(of_get_pci_address);
> +
> +int of_pci_address_to_resource(struct device_node *dev, int bar,
> +			       struct resource *r)
> +{
> +	const u32	*addrp;
> +	u64		size;
> +	unsigned int	flags;
> +
> +	addrp = of_get_pci_address(dev, bar, &size, &flags);
> +	if (addrp == NULL)
> +		return -EINVAL;
> +	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)
> +{
> +	return !strcmp(np->name, "isa");
> +}
> +
> +static void of_bus_isa_count_cells(struct device_node *child,
> +				   int *addrc, int *sizec)
> +{
> +	if (addrc)
> +		*addrc = 2;
> +	if (sizec)
> +		*sizec = 1;
> +}
> +
> +static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
> +{
> +	u64 cp, s, da;
> +
> +	/* Check address type match */
> +	if ((addr[0] ^ range[0]) & 0x00000001)
> +		return OF_BAD_ADDR;
> +
> +	/* Read address values, skipping high cell */
> +	cp = of_read_number(range + 1, na - 1);
> +	s  = of_read_number(range + na + pna, ns);
> +	da = of_read_number(addr + 1, na - 1);
> +
> +	pr_debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n",
> +		 (unsigned long long)cp, (unsigned long long)s,
> +		 (unsigned long long)da);
> +
> +	if (da < cp || da >= (cp + s))
> +		return OF_BAD_ADDR;
> +	return da - cp;
> +}
> +
> +static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
> +{
> +	return of_bus_default_translate(addr + 1, offset, na - 1);
> +}
> +
> +static unsigned int of_bus_isa_get_flags(const u32 *addr)
> +{
> +	unsigned int flags = 0;
> +	u32 w = addr[0];
> +
> +	if (w & 1)
> +		flags |= IORESOURCE_IO;
> +	else
> +		flags |= IORESOURCE_MEM;
> +	return flags;
> +}
> +
> +/*
> + * Array of bus specific translators
> + */
> +
> +static struct of_bus of_busses[] = {
> +#ifdef CONFIG_PCI
> +	/* PCI */
> +	{
> +		.name = "pci",
> +		.addresses = "assigned-addresses",
> +		.match = of_bus_pci_match,
> +		.count_cells = of_bus_pci_count_cells,
> +		.map = of_bus_pci_map,
> +		.translate = of_bus_pci_translate,
> +		.get_flags = of_bus_pci_get_flags,
> +	},
> +#endif /* CONFIG_PCI */
> +	/* ISA */
> +	{
> +		.name = "isa",
> +		.addresses = "reg",
> +		.match = of_bus_isa_match,
> +		.count_cells = of_bus_isa_count_cells,
> +		.map = of_bus_isa_map,
> +		.translate = of_bus_isa_translate,
> +		.get_flags = of_bus_isa_get_flags,
> +	},
> +	/* Default */
> +	{
> +		.name = "default",
> +		.addresses = "reg",
> +		.match = NULL,
> +		.count_cells = of_bus_default_count_cells,
> +		.map = of_bus_default_map,
> +		.translate = of_bus_default_translate,
> +		.get_flags = of_bus_default_get_flags,
> +	},
> +};
> +
> +static struct of_bus *of_match_bus(struct device_node *np)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(of_busses); i++)
> +		if (!of_busses[i].match || of_busses[i].match(np))
> +			return &of_busses[i];
> +	BUG();
> +	return NULL;
> +}
> +
> +static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> +			    struct of_bus *pbus, u32 *addr,
> +			    int na, int ns, int pna, const char *rprop)
> +{
> +	const u32 *ranges;
> +	unsigned int rlen;
> +	int rone;
> +	u64 offset = OF_BAD_ADDR;
> +
> +	/* Normally, an absence of a "ranges" property means we are
> +	 * crossing a non-translatable boundary, and thus the addresses
> +	 * below the current not cannot be converted to CPU physical ones.
> +	 * Unfortunately, while this is very clear in the spec, it's not
> +	 * what Apple understood, and they do have things like /uni-n or
> +	 * /ht nodes with no "ranges" property and a lot of perfectly
> +	 * useable mapped devices below them. Thus we treat the absence of
> +	 * "ranges" as equivalent to an empty "ranges" property which means
> +	 * a 1:1 translation at that level. It's up to the caller not to try
> +	 * to translate addresses that aren't supposed to be translated in
> +	 * the first place. --BenH.
> +	 */
> +	ranges = of_get_property(parent, rprop, &rlen);
> +	if (ranges == NULL || rlen == 0) {
> +		offset = of_read_number(addr, na);
> +		memset(addr, 0, pna * 4);
> +		pr_debug("OF: no ranges, 1:1 translation\n");
> +		goto finish;
> +	}
> +
> +	pr_debug("OF: walking ranges...\n");
> +
> +	/* Now walk through the ranges */
> +	rlen /= 4;
> +	rone = na + pna + ns;
> +	for (; rlen >= rone; rlen -= rone, ranges += rone) {
> +		offset = bus->map(addr, ranges, na, ns, pna);
> +		if (offset != OF_BAD_ADDR)
> +			break;
> +	}
> +	if (offset == OF_BAD_ADDR) {
> +		pr_debug("OF: not found !\n");
> +		return 1;
> +	}
> +	memcpy(addr, ranges + na, 4 * pna);
> +
> + finish:
> +	of_dump_addr("OF: parent translation for:", addr, pna);
> +	pr_debug("OF: with offset: %llx\n", (unsigned long long)offset);
> +
> +	/* Translate it into parent bus space */
> +	return pbus->translate(addr, offset, pna);
> +}
> +
> +/*
> + * Translate an address from the device-tree into a CPU physical address,
> + * this walks up the tree and applies the various bus mappings on the
> + * way.
> + *
> + * Note: We consider that crossing any level with #size-cells == 0 to mean
> + * that translation is impossible (that is we are not dealing with a value
> + * that can be mapped to a cpu physical address). This is not really specified
> + * 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,
> +			   const char *rprop)
> +{
> +	struct device_node *parent = NULL;
> +	struct of_bus *bus, *pbus;
> +	u32 addr[OF_MAX_ADDR_CELLS];
> +	int na, ns, pna, pns;
> +	u64 result = OF_BAD_ADDR;
> +
> +	pr_debug("OF: ** translation for device %s **\n", dev->full_name);
> +
> +	/* Increase refcount at current level */
> +	of_node_get(dev);
> +
> +	/* Get parent & match bus type */
> +	parent = of_get_parent(dev);
> +	if (parent == NULL)
> +		goto bail;
> +	bus = of_match_bus(parent);
> +
> +	/* Cound address cells & copy address locally */
> +	bus->count_cells(dev, &na, &ns);
> +	if (!OF_CHECK_COUNTS(na, ns)) {
> +		printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> +		       dev->full_name);
> +		goto bail;
> +	}
> +	memcpy(addr, in_addr, na * 4);
> +
> +	pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
> +	    bus->name, na, ns, parent->full_name);
> +	of_dump_addr("OF: translating address:", addr, na);
> +
> +	/* Translate */
> +	for (;;) {
> +		/* Switch to parent bus */
> +		of_node_put(dev);
> +		dev = parent;
> +		parent = of_get_parent(dev);
> +
> +		/* If root, we have finished */
> +		if (parent == NULL) {
> +			pr_debug("OF: reached root node\n");
> +			result = of_read_number(addr, na);
> +			break;
> +		}
> +
> +		/* Get new parent bus and counts */
> +		pbus = of_match_bus(parent);
> +		pbus->count_cells(dev, &pna, &pns);
> +		if (!OF_CHECK_COUNTS(pna, pns)) {
> +			printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> +			       dev->full_name);
> +			break;
> +		}
> +
> +		pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
> +		    pbus->name, pna, pns, parent->full_name);
> +
> +		/* Apply bus translation */
> +		if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
> +			break;
> +
> +		/* Complete the move up one level */
> +		na = pna;
> +		ns = pns;
> +		bus = pbus;
> +
> +		of_dump_addr("OF: one level translation:", addr, na);
> +	}
> + bail:
> +	of_node_put(parent);
> +	of_node_put(dev);
> +
> +	return result;
> +}
> +
> +u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
> +{
> +	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_addr)
> +{
> +	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,
> +		    unsigned int *flags)
> +{
> +	const u32 *prop;
> +	unsigned int psize;
> +	struct device_node *parent;
> +	struct of_bus *bus;
> +	int onesize, i, na, ns;
> +
> +	/* Get parent & match bus type */
> +	parent = of_get_parent(dev);
> +	if (parent == NULL)
> +		return NULL;
> +	bus = of_match_bus(parent);
> +	bus->count_cells(dev, &na, &ns);
> +	of_node_put(parent);
> +	if (!OF_CHECK_COUNTS(na, ns))
> +		return NULL;
> +
> +	/* Get "reg" or "assigned-addresses" property */
> +	prop = of_get_property(dev, bus->addresses, &psize);
> +	if (prop == NULL)
> +		return NULL;
> +	psize /= 4;
> +
> +	onesize = na + ns;
> +	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> +		if (i == index) {
> +			if (size)
> +				*size = of_read_number(prop + na, ns);
> +			if (flags)
> +				*flags = bus->get_flags(prop);
> +			return prop;
> +		}
> +	return NULL;
> +}
> +EXPORT_SYMBOL(of_get_address);
> +
> +static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> +				    u64 size, unsigned int flags,
> +				    struct resource *r)
>  {
>  	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 @@
>  #include <linux/ioport.h>
>  #include <linux/of.h>
>  
> -extern int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> -				    u64 size, unsigned int flags,
> -				    struct resource *r);
> +extern u64 of_translate_address(struct device_node *np, const u32 *addr);
>  extern int of_address_to_resource(struct device_node *dev, int index,
>  				  struct resource *r);
>  extern void __iomem *of_iomap(struct device_node *device, int index);

^ permalink raw reply

* Re: [PATCH 2/5] of/address: merge of_address_to_resource()
From: Benjamin Herrenschmidt @ 2010-06-10  6:41 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, Stephen Rothwell, Michal Simek, microblaze-uclinux
In-Reply-To: <20100608141002.25879.82283.stgit@angua>

On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
> Merge common code between PowerPC and Microblaze.  This patch also
> moves the prototype of pci_address_to_pio() out of pci-bridge.h and
> into prom.h because the only user of pci_address_to_pio() is
> of_address_to_resource().
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> CC: Michal Simek <monstr@monstr.eu>
> CC: Grant Likely <grant.likely@secretlab.ca>
> CC: Wolfram Sang <w.sang@pengutronix.de>
> CC: Stephen Rothwell <sfr@canb.auug.org.au>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> CC: microblaze-uclinux@itee.uq.edu.au
> CC: linuxppc-dev@ozlabs.org
> ---
>  arch/microblaze/include/asm/pci-bridge.h |    5 ---
>  arch/microblaze/include/asm/prom.h       |   17 +++++-----
>  arch/microblaze/kernel/prom_parse.c      |   46 +--------------------------
>  arch/powerpc/include/asm/pci-bridge.h    |    5 ---
>  arch/powerpc/include/asm/prom.h          |   17 +++++-----
>  arch/powerpc/kernel/prom_parse.c         |   47 +---------------------------
>  drivers/of/address.c                     |   51 ++++++++++++++++++++++++++++++
>  include/linux/of_address.h               |    5 +++
>  8 files changed, 76 insertions(+), 117 deletions(-)
> 
> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> index 0c77cda..0c68764 100644
> --- a/arch/microblaze/include/asm/pci-bridge.h
> +++ b/arch/microblaze/include/asm/pci-bridge.h
> @@ -172,13 +172,8 @@ static inline int pci_has_flag(int flag)
>  
>  extern struct list_head hose_list;
>  
> -extern unsigned long pci_address_to_pio(phys_addr_t address);
>  extern int pcibios_vaddr_is_ioport(void __iomem *address);
>  #else
> -static inline unsigned long pci_address_to_pio(phys_addr_t address)
> -{
> -	return (unsigned long)-1;
> -}
>  static inline int pcibios_vaddr_is_ioport(void __iomem *address)
>  {
>  	return 0;
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
> index b6698ef..644fa32 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -65,17 +65,18 @@ extern const u32 *of_get_address(struct device_node *dev, int index,
>  extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no,
>  			u64 *size, unsigned int *flags);
>  
> -/* Get an address as a resource. Note that if your address is
> - * a PIO address, the conversion will fail if the physical address
> - * can't be internally converted to an IO token with
> - * pci_address_to_pio(), that is because it's either called to early
> - * or it can't be matched to any host bridge IO space
> - */
> -extern int of_address_to_resource(struct device_node *dev, int index,
> -				struct resource *r);
>  extern int of_pci_address_to_resource(struct device_node *dev, int bar,
>  				struct resource *r);
>  
> +#ifdef CONFIG_PCI
> +extern unsigned long pci_address_to_pio(phys_addr_t address);
> +#else
> +static inline unsigned long pci_address_to_pio(phys_addr_t address)
> +{
> +	return (unsigned long)-1;
> +}
> +#endif	/* CONFIG_PCI */
> +
>  /* Parse the ibm,dma-window property of an OF node into the busno, phys and
>   * size parameters.
>   */
> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
> index 5003ee8..7cb5a98 100644
> --- a/arch/microblaze/kernel/prom_parse.c
> +++ b/arch/microblaze/kernel/prom_parse.c
> @@ -6,6 +6,7 @@
>  #include <linux/module.h>
>  #include <linux/ioport.h>
>  #include <linux/etherdevice.h>
> +#include <linux/of_address.h>
>  #include <asm/prom.h>
>  #include <asm/pci-bridge.h>
>  
> @@ -17,9 +18,6 @@
>  			(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, u64 size, unsigned int flags,
> -		struct resource *r);
>  
>  /* Debug utility */
>  #ifdef DEBUG
> @@ -576,48 +574,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
>  }
>  EXPORT_SYMBOL(of_get_address);
>  
> -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> -				u64 size, unsigned int flags,
> -				struct resource *r)
> -{
> -	u64 taddr;
> -
> -	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
> -		return -EINVAL;
> -	taddr = of_translate_address(dev, addrp);
> -	if (taddr == OF_BAD_ADDR)
> -		return -EINVAL;
> -	memset(r, 0, sizeof(struct resource));
> -	if (flags & IORESOURCE_IO) {
> -		unsigned long port;
> -		port = -1; /* pci_address_to_pio(taddr); */
> -		if (port == (unsigned long)-1)
> -			return -EINVAL;
> -		r->start = port;
> -		r->end = port + size - 1;
> -	} else {
> -		r->start = taddr;
> -		r->end = taddr + size - 1;
> -	}
> -	r->flags = flags;
> -	r->name = dev->name;
> -	return 0;
> -}
> -
> -int of_address_to_resource(struct device_node *dev, int index,
> -			struct resource *r)
> -{
> -	const u32	*addrp;
> -	u64		size;
> -	unsigned int	flags;
> -
> -	addrp = of_get_address(dev, index, &size, &flags);
> -	if (addrp == NULL)
> -		return -EINVAL;
> -	return __of_address_to_resource(dev, addrp, size, flags, r);
> -}
> -EXPORT_SYMBOL_GPL(of_address_to_resource);
> -
>  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>  		unsigned long *busno, unsigned long *phys, unsigned long *size)
>  {
> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> index 76e1f31..51e9e6f 100644
> --- a/arch/powerpc/include/asm/pci-bridge.h
> +++ b/arch/powerpc/include/asm/pci-bridge.h
> @@ -303,13 +303,8 @@ extern void pcibios_free_controller(struct pci_controller *phb);
>  extern void pcibios_setup_phb_resources(struct pci_controller *hose);
>  
>  #ifdef CONFIG_PCI
> -extern unsigned long pci_address_to_pio(phys_addr_t address);
>  extern int pcibios_vaddr_is_ioport(void __iomem *address);
>  #else
> -static inline unsigned long pci_address_to_pio(phys_addr_t address)
> -{
> -	return (unsigned long)-1;
> -}
>  static inline int pcibios_vaddr_is_ioport(void __iomem *address)
>  {
>  	return 0;
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index e0bdbc6..e1c1bdd 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -70,14 +70,6 @@ static inline const u32 *of_get_pci_address(struct device_node *dev,
>  }
>  #endif /* CONFIG_PCI */
>  
> -/* Get an address as a resource. Note that if your address is
> - * a PIO address, the conversion will fail if the physical address
> - * can't be internally converted to an IO token with
> - * pci_address_to_pio(), that is because it's either called to early
> - * or it can't be matched to any host bridge IO space
> - */
> -extern int of_address_to_resource(struct device_node *dev, int index,
> -				  struct resource *r);
>  #ifdef CONFIG_PCI
>  extern int of_pci_address_to_resource(struct device_node *dev, int bar,
>  				      struct resource *r);
> @@ -89,6 +81,15 @@ static inline int of_pci_address_to_resource(struct device_node *dev, int bar,
>  }
>  #endif /* CONFIG_PCI */
>  
> +#ifdef CONFIG_PCI
> +extern unsigned long pci_address_to_pio(phys_addr_t address);
> +#else
> +static inline unsigned long pci_address_to_pio(phys_addr_t address)
> +{
> +	return (unsigned long)-1;
> +}
> +#endif	/* CONFIG_PCI */
> +
>  /* Parse the ibm,dma-window property of an OF node into the busno, phys and
>   * size parameters.
>   */
> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
> index dfb73c4..a2ef129 100644
> --- a/arch/powerpc/kernel/prom_parse.c
> +++ b/arch/powerpc/kernel/prom_parse.c
> @@ -6,6 +6,7 @@
>  #include <linux/module.h>
>  #include <linux/ioport.h>
>  #include <linux/etherdevice.h>
> +#include <linux/of_address.h>
>  #include <asm/prom.h>
>  #include <asm/pci-bridge.h>
>  
> @@ -27,10 +28,6 @@
>  			(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, u64 size, unsigned int flags,
> -		struct resource *r);
> -
>  
>  /* Debug utility */
>  #ifdef DEBUG
> @@ -610,48 +607,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
>  }
>  EXPORT_SYMBOL(of_get_address);
>  
> -static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> -				    u64 size, unsigned int flags,
> -				    struct resource *r)
> -{
> -	u64 taddr;
> -
> -	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
> -		return -EINVAL;
> -	taddr = of_translate_address(dev, addrp);
> -	if (taddr == OF_BAD_ADDR)
> -		return -EINVAL;
> -	memset(r, 0, sizeof(struct resource));
> -	if (flags & IORESOURCE_IO) {
> -		unsigned long port;
> -		port = pci_address_to_pio(taddr);
> -		if (port == (unsigned long)-1)
> -			return -EINVAL;
> -		r->start = port;
> -		r->end = port + size - 1;
> -	} else {
> -		r->start = taddr;
> -		r->end = taddr + size - 1;
> -	}
> -	r->flags = flags;
> -	r->name = dev->name;
> -	return 0;
> -}
> -
> -int of_address_to_resource(struct device_node *dev, int index,
> -			   struct resource *r)
> -{
> -	const u32	*addrp;
> -	u64		size;
> -	unsigned int	flags;
> -
> -	addrp = of_get_address(dev, index, &size, &flags);
> -	if (addrp == NULL)
> -		return -EINVAL;
> -	return __of_address_to_resource(dev, addrp, size, flags, r);
> -}
> -EXPORT_SYMBOL_GPL(of_address_to_resource);
> -
>  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>  		unsigned long *busno, unsigned long *phys, unsigned long *size)
>  {
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 258528d..c381955 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -3,6 +3,57 @@
>  #include <linux/ioport.h>
>  #include <linux/of_address.h>
>  
> +int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> +			     u64 size, unsigned int flags,
> +			     struct resource *r)
> +{
> +	u64 taddr;
> +
> +	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
> +		return -EINVAL;
> +	taddr = of_translate_address(dev, addrp);
> +	if (taddr == OF_BAD_ADDR)
> +		return -EINVAL;
> +	memset(r, 0, sizeof(struct resource));
> +	if (flags & IORESOURCE_IO) {
> +		unsigned long port;
> +		port = pci_address_to_pio(taddr);
> +		if (port == (unsigned long)-1)
> +			return -EINVAL;
> +		r->start = port;
> +		r->end = port + size - 1;
> +	} else {
> +		r->start = taddr;
> +		r->end = taddr + size - 1;
> +	}
> +	r->flags = flags;
> +	r->name = dev->name;
> +	return 0;
> +}
> +
> +/**
> + * of_address_to_resource - Translate device tree address and return as resource
> + *
> + * Note that if your address is a PIO address, the conversion will fail if
> + * the physical address can't be internally converted to an IO token with
> + * pci_address_to_pio(), that is because it's either called to early or it
> + * can't be matched to any host bridge IO space
> + */
> +int of_address_to_resource(struct device_node *dev, int index,
> +			   struct resource *r)
> +{
> +	const u32	*addrp;
> +	u64		size;
> +	unsigned int	flags;
> +
> +	addrp = of_get_address(dev, index, &size, &flags);
> +	if (addrp == NULL)
> +		return -EINVAL;
> +	return __of_address_to_resource(dev, addrp, size, flags, r);
> +}
> +EXPORT_SYMBOL_GPL(of_address_to_resource);
> +
> +
>  /**
>   * of_iomap - Maps the memory mapped IO for a given device_node
>   * @device:	the device whose io range will be mapped
> diff --git a/include/linux/of_address.h b/include/linux/of_address.h
> index 570831d..474b794 100644
> --- a/include/linux/of_address.h
> +++ b/include/linux/of_address.h
> @@ -3,6 +3,11 @@
>  #include <linux/ioport.h>
>  #include <linux/of.h>
>  
> +extern int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> +				    u64 size, unsigned int flags,
> +				    struct resource *r);
> +extern int of_address_to_resource(struct device_node *dev, int index,
> +				  struct resource *r);
>  extern void __iomem *of_iomap(struct device_node *device, int index);
>  
>  #endif /* __OF_ADDRESS_H */

^ permalink raw reply

* Re: [PATCH 1/5] of/address: merge of_iomap()
From: Benjamin Herrenschmidt @ 2010-06-10  6:40 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, Stephen Rothwell, Michal Simek, microblaze-uclinux
In-Reply-To: <20100608140957.25879.98286.stgit@angua>

On Tue, 2010-06-08 at 08:09 -0600, Grant Likely wrote:
> Merge common code between Microblaze and PowerPC.  This patch creates
> new of_address.h and address.c files to containing address translation
> and mapping routines.  First routine to be moved it of_iomap()
> 
> 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>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

> CC: microblaze-uclinux@itee.uq.edu.au
> CC: linuxppc-dev@ozlabs.org
> ---
>  arch/microblaze/include/asm/prom.h  |   10 +---------
>  arch/microblaze/kernel/prom_parse.c |   11 -----------
>  arch/powerpc/include/asm/prom.h     |   10 +---------
>  arch/powerpc/kernel/prom_parse.c    |   11 -----------
>  drivers/of/Kconfig                  |    4 ++++
>  drivers/of/Makefile                 |    1 +
>  drivers/of/address.c                |   22 ++++++++++++++++++++++
>  include/linux/of_address.h          |    9 +++++++++
>  8 files changed, 38 insertions(+), 40 deletions(-)
>  create mode 100644 drivers/of/address.c
>  create mode 100644 include/linux/of_address.h
> 
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
> index 3659930..b6698ef 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -20,6 +20,7 @@
>  #ifndef __ASSEMBLY__
>  
>  #include <linux/types.h>
> +#include <linux/of_address.h>
>  #include <linux/of_irq.h>
>  #include <linux/of_fdt.h>
>  #include <linux/proc_fs.h>
> @@ -107,15 +108,6 @@ extern const void *of_get_mac_address(struct device_node *np);
>  struct pci_dev;
>  extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
>  
> -/**
> - * of_iomap - Maps the memory mapped IO for a given device_node
> - * @device:	the device whose io range will be mapped
> - * @index:	index of the io range
> - *
> - * Returns a pointer to the mapped memory
> - */
> -extern void __iomem *of_iomap(struct device_node *device, int index);
> -
>  #endif /* __ASSEMBLY__ */
>  #endif /* __KERNEL__ */
>  #endif /* _ASM_MICROBLAZE_PROM_H */
> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
> index 70c0471..5003ee8 100644
> --- a/arch/microblaze/kernel/prom_parse.c
> +++ b/arch/microblaze/kernel/prom_parse.c
> @@ -697,14 +697,3 @@ const void *of_get_mac_address(struct device_node *np)
>  	return NULL;
>  }
>  EXPORT_SYMBOL(of_get_mac_address);
> -
> -void __iomem *of_iomap(struct device_node *np, int index)
> -{
> -	struct resource res;
> -
> -	if (of_address_to_resource(np, index, &res))
> -		return NULL;
> -
> -	return ioremap(res.start, 1 + res.end - res.start);
> -}
> -EXPORT_SYMBOL(of_iomap);
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index 2440984..e0bdbc6 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -18,6 +18,7 @@
>   */
>  #include <linux/types.h>
>  #include <linux/of_fdt.h>
> +#include <linux/of_address.h>
>  #include <linux/of_irq.h>
>  #include <linux/proc_fs.h>
>  #include <linux/platform_device.h>
> @@ -136,14 +137,5 @@ extern void of_irq_map_init(unsigned int flags);
>  struct pci_dev;
>  extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
>  
> -/**
> - * of_iomap - Maps the memory mapped IO for a given device_node
> - * @device:	the device whose io range will be mapped
> - * @index:	index of the io range
> - *
> - * Returns a pointer to the mapped memory
> - */
> -extern void __iomem *of_iomap(struct device_node *device, int index);
> -
>  #endif /* __KERNEL__ */
>  #endif /* _POWERPC_PROM_H */
> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
> index ef518e3..dfb73c4 100644
> --- a/arch/powerpc/kernel/prom_parse.c
> +++ b/arch/powerpc/kernel/prom_parse.c
> @@ -822,14 +822,3 @@ const void *of_get_mac_address(struct device_node *np)
>  	return NULL;
>  }
>  EXPORT_SYMBOL(of_get_mac_address);
> -
> -void __iomem *of_iomap(struct device_node *np, int index)
> -{
> -	struct resource res;
> -
> -	if (of_address_to_resource(np, index, &res))
> -		return NULL;
> -
> -	return ioremap(res.start, 1 + res.end - res.start);
> -}
> -EXPORT_SYMBOL(of_iomap);
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index b87495e..097f42a 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -6,6 +6,10 @@ config OF_DYNAMIC
>  	def_bool y
>  	depends on OF && PPC_OF
>  
> +config OF_ADDRESS
> +	def_bool y
> +	depends on OF && !SPARC
> +
>  config OF_IRQ
>  	def_bool y
>  	depends on OF && !SPARC
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index 3631a5e..0052c40 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -1,5 +1,6 @@
>  obj-y = base.o
>  obj-$(CONFIG_OF_FLATTREE) += fdt.o
> +obj-$(CONFIG_OF_ADDRESS)  += address.o
>  obj-$(CONFIG_OF_IRQ)    += irq.o
>  obj-$(CONFIG_OF_DEVICE) += device.o platform.o
>  obj-$(CONFIG_OF_GPIO)   += gpio.o
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> new file mode 100644
> index 0000000..258528d
> --- /dev/null
> +++ b/drivers/of/address.c
> @@ -0,0 +1,22 @@
> +
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/of_address.h>
> +
> +/**
> + * of_iomap - Maps the memory mapped IO for a given device_node
> + * @device:	the device whose io range will be mapped
> + * @index:	index of the io range
> + *
> + * Returns a pointer to the mapped memory
> + */
> +void __iomem *of_iomap(struct device_node *np, int index)
> +{
> +	struct resource res;
> +
> +	if (of_address_to_resource(np, index, &res))
> +		return NULL;
> +
> +	return ioremap(res.start, 1 + res.end - res.start);
> +}
> +EXPORT_SYMBOL(of_iomap);
> diff --git a/include/linux/of_address.h b/include/linux/of_address.h
> new file mode 100644
> index 0000000..570831d
> --- /dev/null
> +++ b/include/linux/of_address.h
> @@ -0,0 +1,9 @@
> +#ifndef __OF_ADDRESS_H
> +#define __OF_ADDRESS_H
> +#include <linux/ioport.h>
> +#include <linux/of.h>
> +
> +extern void __iomem *of_iomap(struct device_node *device, int index);
> +
> +#endif /* __OF_ADDRESS_H */
> +

^ permalink raw reply

* Re: [PATCH 5/5] of/irq: merge of_irq_map_one()
From: Benjamin Herrenschmidt @ 2010-06-10  6:40 UTC (permalink / raw)
  To: Grant Likely
  Cc: Stephen Rothwell, Michal Simek, microblaze-uclinux,
	devicetree-discuss, linuxppc-dev
In-Reply-To: <20100604212155.10552.19260.stgit@angua>

On Fri, 2010-06-04 at 15:21 -0600, Grant Likely wrote:
> Merge common implementation of of_irq_map_one().  Rename it to
> __of_irq_map_one() so that arch code can either use the stock
> implementation, or override it to handle platform quirks.

Similar comment to before, I think the breakup of functions causes more
complication and bloat than just keeping the quirks in the generic code.

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
> CC: devicetree-discuss@lists.ozlabs.org
> ---
>  arch/microblaze/include/asm/prom.h  |    3 -
>  arch/microblaze/kernel/prom_parse.c |   73 ------------------------------
>  arch/powerpc/include/asm/prom.h     |    3 -
>  arch/powerpc/kernel/prom_parse.c    |   55 -----------------------
>  drivers/of/irq.c                    |   85 +++++++++++++++++++++++++++++++++++
>  include/linux/of_irq.h              |    6 ++
>  6 files changed, 91 insertions(+), 134 deletions(-)
> 
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
> index 89fca70..3659930 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -107,9 +107,6 @@ extern const void *of_get_mac_address(struct device_node *np);
>  struct pci_dev;
>  extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
>  
> -extern int of_irq_to_resource(struct device_node *dev, int index,
> -			struct resource *r);
> -
>  /**
>   * of_iomap - Maps the memory mapped IO for a given device_node
>   * @device:	the device whose io range will be mapped
> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
> index 02ec946..70c0471 100644
> --- a/arch/microblaze/kernel/prom_parse.c
> +++ b/arch/microblaze/kernel/prom_parse.c
> @@ -656,49 +656,7 @@ struct device_node *of_irq_find_parent_by_phandle(phandle p)
>  int of_irq_map_one(struct device_node *device,
>  			int index, struct of_irq *out_irq)
>  {
> -	struct device_node *p;
> -	const u32 *intspec, *tmp, *addr;
> -	u32 intsize, intlen;
> -	int res;
> -
> -	pr_debug("of_irq_map_one: dev=%s, index=%d\n",
> -			device->full_name, index);
> -
> -	/* Get the interrupts property */
> -	intspec = of_get_property(device, "interrupts", (int *) &intlen);
> -	if (intspec == NULL)
> -		return -EINVAL;
> -	intlen /= sizeof(u32);
> -
> -	pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen);
> -
> -	/* Get the reg property (if any) */
> -	addr = of_get_property(device, "reg", NULL);
> -
> -	/* Look for the interrupt parent. */
> -	p = of_irq_find_parent(device);
> -	if (p == NULL)
> -		return -EINVAL;
> -
> -	/* Get size of interrupt specifier */
> -	tmp = of_get_property(p, "#interrupt-cells", NULL);
> -	if (tmp == NULL) {
> -		of_node_put(p);
> -		return -EINVAL;
> -	}
> -	intsize = *tmp;
> -
> -	pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
> -
> -	/* Check index */
> -	if ((index + 1) * intsize > intlen)
> -		return -EINVAL;
> -
> -	/* Get new specifier and map it */
> -	res = of_irq_map_raw(p, intspec + index * intsize, intsize,
> -				addr, out_irq);
> -	of_node_put(p);
> -	return res;
> +	return __of_irq_map_one(device, index, out_irq);
>  }
>  EXPORT_SYMBOL_GPL(of_irq_map_one);
>  
> @@ -740,35 +698,6 @@ const void *of_get_mac_address(struct device_node *np)
>  }
>  EXPORT_SYMBOL(of_get_mac_address);
>  
> -int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
> -{
> -	struct of_irq out_irq;
> -	int irq;
> -	int res;
> -
> -	res = of_irq_map_one(dev, index, &out_irq);
> -
> -	/* Get irq for the device */
> -	if (res) {
> -		pr_debug("IRQ not found... code = %d", res);
> -		return NO_IRQ;
> -	}
> -	/* Assuming single interrupt controller... */
> -	irq = out_irq.specifier[0];
> -
> -	pr_debug("IRQ found = %d", irq);
> -
> -	/* Only dereference the resource if both the
> -	 * resource and the irq are valid. */
> -	if (r && irq != NO_IRQ) {
> -		r->start = r->end = irq;
> -		r->flags = IORESOURCE_IRQ;
> -	}
> -
> -	return irq;
> -}
> -EXPORT_SYMBOL_GPL(of_irq_to_resource);
> -
>  void __iomem *of_iomap(struct device_node *np, int index)
>  {
>  	struct resource res;
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index 187ef4e..2440984 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -136,9 +136,6 @@ extern void of_irq_map_init(unsigned int flags);
>  struct pci_dev;
>  extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
>  
> -extern int of_irq_to_resource(struct device_node *dev, int index,
> -			struct resource *r);
> -
>  /**
>   * of_iomap - Maps the memory mapped IO for a given device_node
>   * @device:	the device whose io range will be mapped
> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
> index 89ca7b3..ef518e3 100644
> --- a/arch/powerpc/kernel/prom_parse.c
> +++ b/arch/powerpc/kernel/prom_parse.c
> @@ -777,49 +777,11 @@ static int of_irq_map_oldworld(struct device_node *device, int index,
>  
>  int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
>  {
> -	struct device_node *p;
> -	const u32 *intspec, *tmp, *addr;
> -	u32 intsize, intlen;
> -	int res = -EINVAL;
> -
> -	DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
> -
>  	/* OldWorld mac stuff is "special", handle out of line */
>  	if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
>  		return of_irq_map_oldworld(device, index, out_irq);
>  
> -	/* Get the interrupts property */
> -	intspec = of_get_property(device, "interrupts", &intlen);
> -	if (intspec == NULL)
> -		return -EINVAL;
> -	intlen /= sizeof(u32);
> -
> -	/* Get the reg property (if any) */
> -	addr = of_get_property(device, "reg", NULL);
> -
> -	/* Look for the interrupt parent. */
> -	p = of_irq_find_parent(device);
> -	if (p == NULL)
> -		return -EINVAL;
> -
> -	/* Get size of interrupt specifier */
> -	tmp = of_get_property(p, "#interrupt-cells", NULL);
> -	if (tmp == NULL)
> -		goto out;
> -	intsize = *tmp;
> -
> -	DBG(" intsize=%d intlen=%d\n", intsize, intlen);
> -
> -	/* Check index */
> -	if ((index + 1) * intsize > intlen)
> -		goto out;
> -
> -	/* Get new specifier and map it */
> -	res = of_irq_map_raw(p, intspec + index * intsize, intsize,
> -			     addr, out_irq);
> -out:
> -	of_node_put(p);
> -	return res;
> +	return __of_irq_map_one(device, index, out_irq);
>  }
>  EXPORT_SYMBOL_GPL(of_irq_map_one);
>  
> @@ -861,21 +823,6 @@ const void *of_get_mac_address(struct device_node *np)
>  }
>  EXPORT_SYMBOL(of_get_mac_address);
>  
> -int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
> -{
> -	int irq = irq_of_parse_and_map(dev, index);
> -
> -	/* Only dereference the resource if both the
> -	 * resource and the irq are valid. */
> -	if (r && irq != NO_IRQ) {
> -		r->start = r->end = irq;
> -		r->flags = IORESOURCE_IRQ;
> -	}
> -
> -	return irq;
> -}
> -EXPORT_SYMBOL_GPL(of_irq_to_resource);
> -
>  void __iomem *of_iomap(struct device_node *np, int index)
>  {
>  	struct resource res;
> diff --git a/drivers/of/irq.c b/drivers/of/irq.c
> index 351c87a..dd420e5 100644
> --- a/drivers/of/irq.c
> +++ b/drivers/of/irq.c
> @@ -31,7 +31,7 @@
>   * Returns a pointer to the interrupt parent node, or NULL if the interrupt
>   * parent could not be determined.
>   */
> -struct device_node *of_irq_find_parent(struct device_node *child)
> +static struct device_node *of_irq_find_parent(struct device_node *child)
>  {
>  	struct device_node *p;
>  	const phandle *parp;
> @@ -240,6 +240,67 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
>  }
>  EXPORT_SYMBOL_GPL(of_irq_map_raw);
>  
> +/**
> + * of_irq_map_one - Resolve an interrupt for a device
> + * @device: the device whose interrupt is to be resolved
> + * @index: index of the interrupt to resolve
> + * @out_irq: structure of_irq filled by this function
> + *
> + * This function resolves an interrupt, walking the tree, for a given
> + * device-tree node. It's the high level pendant to of_irq_map_raw().
> + *
> + * Architecture code must provide of_irq_map_one() which can simply be a
> + * wrapper around __of_irq_map_one(), or can override it to deal with
> + * arch specific quirks and bugs.
> + */
> +int __of_irq_map_one(struct device_node *device, int index,
> +		     struct of_irq *out_irq)
> +{
> +	struct device_node *p;
> +	const u32 *intspec, *tmp, *addr;
> +	u32 intsize, intlen;
> +	int res = -EINVAL;
> +
> +	pr_debug("of_irq_map_one: dev=%s, index=%d\n",
> +		 device->full_name, index);
> +
> +	/* Get the interrupts property */
> +	intspec = of_get_property(device, "interrupts", &intlen);
> +	if (intspec == NULL)
> +		return -EINVAL;
> +	intlen /= sizeof(u32);
> +
> +	pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen);
> +
> +	/* Get the reg property (if any) */
> +	addr = of_get_property(device, "reg", NULL);
> +
> +	/* Look for the interrupt parent. */
> +	p = of_irq_find_parent(device);
> +	if (p == NULL)
> +		return -EINVAL;
> +
> +	/* Get size of interrupt specifier */
> +	tmp = of_get_property(p, "#interrupt-cells", NULL);
> +	if (tmp == NULL)
> +		goto out;
> +	intsize = *tmp;
> +
> +	pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
> +
> +	/* Check index */
> +	if ((index + 1) * intsize > intlen)
> +		goto out;
> +
> +	/* Get new specifier and map it */
> +	res = of_irq_map_raw(p, intspec + index * intsize, intsize,
> +			     addr, out_irq);
> + out:
> +	of_node_put(p);
> +	return res;
> +}
> +EXPORT_SYMBOL_GPL(__of_irq_map_one);
> +
>  unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
>  {
>  	struct of_irq oirq;
> @@ -251,3 +312,25 @@ unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
>  				     oirq.size);
>  }
>  EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
> +
> +/**
> + * of_irq_to_resource - Decode a node's IRQ and return it as a resource
> + * @dev: pointer to device tree node
> + * @index: zero-based index of the irq
> + * @r: pointer to resource structure to return result into.
> + */
> +unsigned int of_irq_to_resource(struct device_node *dev, int index,
> +				struct resource *r)
> +{
> +	unsigned int irq = irq_of_parse_and_map(dev, index);
> +
> +	/* Only dereference the resource if both the
> +	 * resource and the irq are valid. */
> +	if (r && irq != NO_IRQ) {
> +		r->start = r->end = irq;
> +		r->flags = IORESOURCE_IRQ;
> +	}
> +
> +	return irq;
> +}
> +EXPORT_SYMBOL_GPL(of_irq_to_resource);
> diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
> index 51c520b..935a14d 100644
> --- a/include/linux/of_irq.h
> +++ b/include/linux/of_irq.h
> @@ -5,6 +5,7 @@
>  struct of_irq;
>  #include <linux/types.h>
>  #include <linux/of.h>
> +#include <linux/ioport.h>
>  
>  /*
>   * irq_of_parse_and_map() is used ba all OF enabled platforms; but SPARC
> @@ -31,14 +32,17 @@ struct of_irq {
>  };
>  
>  extern struct device_node *of_irq_find_parent_by_phandle(phandle p);
> -extern struct device_node *of_irq_find_parent(struct device_node *child);
>  extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
>  			 u32 ointsize, const u32 *addr, struct of_irq *out_irq);
> +extern int __of_irq_map_one(struct device_node *device, int index,
> +			    struct of_irq *out_irq);
>  extern int of_irq_map_one(struct device_node *device, int index,
>  			  struct of_irq *out_irq);
>  extern unsigned int irq_create_of_mapping(struct device_node *controller,
>  					  const u32 *intspec,
>  					  unsigned int intsize);
> +extern unsigned int of_irq_to_resource(struct device_node *dev, int index,
> +				       struct resource *r);
>  
>  #endif /* CONFIG_OF_IRQ */
>  #endif /* CONFIG_OF */

^ permalink raw reply

* Re: [PATCH 4/5] of/irq: Merge of_irq_map_raw()
From: Benjamin Herrenschmidt @ 2010-06-10  6:38 UTC (permalink / raw)
  To: Grant Likely
  Cc: Stephen Rothwell, Michal Simek, microblaze-uclinux,
	devicetree-discuss, linuxppc-dev
In-Reply-To: <20100604212150.10552.3378.stgit@angua>

On Fri, 2010-06-04 at 15:21 -0600, Grant Likely wrote:
> Merge common code between PowerPC and Microblaze
> 
> 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>

Acked-by : Benjamin Herrenschmidt <benh@kernel.crashing.org>

I haven't double checked that the code was absolutely identical... if
you haven't, please do so :-)

Cheers,
Ben.

> CC: microblaze-uclinux@itee.uq.edu.au
> CC: linuxppc-dev@ozlabs.org
> CC: devicetree-discuss@lists.ozlabs.org
> ---
>  arch/microblaze/include/asm/prom.h  |   21 ----
>  arch/microblaze/kernel/prom_parse.c |  176 ---------------------------------
>  arch/powerpc/include/asm/prom.h     |   21 ----
>  arch/powerpc/kernel/prom_parse.c    |  171 --------------------------------
>  drivers/of/irq.c                    |  188 +++++++++++++++++++++++++++++++++++
>  include/linux/of_irq.h              |    2 
>  6 files changed, 190 insertions(+), 389 deletions(-)
> 
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
> index da7069c..89fca70 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -94,27 +94,6 @@ extern const void *of_get_mac_address(struct device_node *np);
>   */
>  
>  /**
> - * of_irq_map_raw - Low level interrupt tree parsing
> - * @parent:	the device interrupt parent
> - * @intspec:	interrupt specifier ("interrupts" property of the device)
> - * @ointsize:	size of the passed in interrupt specifier
> - * @addr:	address specifier (start of "reg" property of the device)
> - * @out_irq:	structure of_irq filled by this function
> - *
> - * Returns 0 on success and a negative number on error
> - *
> - * This function is a low-level interrupt tree walking function. It
> - * can be used to do a partial walk with synthetized reg and interrupts
> - * properties, for example when resolving PCI interrupts when no device
> - * node exist for the parent.
> - *
> - */
> -
> -extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
> -			u32 ointsize, const u32 *addr,
> -			struct of_irq *out_irq);
> -
> -/**
>   * of_irq_map_pci - Resolve the interrupt for a PCI device
>   * @pdev:	the device whose interrupt is to be resolved
>   * @out_irq:	structure of_irq filled by this function
> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
> index 946f14d..02ec946 100644
> --- a/arch/microblaze/kernel/prom_parse.c
> +++ b/arch/microblaze/kernel/prom_parse.c
> @@ -653,182 +653,6 @@ struct device_node *of_irq_find_parent_by_phandle(phandle p)
>  	return of_find_node_by_phandle(p);
>  }
>  
> -int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
> -		const u32 *addr, struct of_irq *out_irq)
> -{
> -	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
> -	const u32 *tmp, *imap, *imask;
> -	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
> -	int imaplen, match, i;
> -
> -	pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],"
> -		"ointsize=%d\n",
> -		parent->full_name, intspec[0], intspec[1], ointsize);
> -
> -	ipar = of_node_get(parent);
> -
> -	/* First get the #interrupt-cells property of the current cursor
> -	 * that tells us how to interpret the passed-in intspec. If there
> -	 * is none, we are nice and just walk up the tree
> -	 */
> -	do {
> -		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
> -		if (tmp != NULL) {
> -			intsize = *tmp;
> -			break;
> -		}
> -		tnode = ipar;
> -		ipar = of_irq_find_parent(ipar);
> -		of_node_put(tnode);
> -	} while (ipar);
> -	if (ipar == NULL) {
> -		pr_debug(" -> no parent found !\n");
> -		goto fail;
> -	}
> -
> -	pr_debug("of_irq_map_raw: ipar=%s, size=%d\n",
> -			ipar->full_name, intsize);
> -
> -	if (ointsize != intsize)
> -		return -EINVAL;
> -
> -	/* Look for this #address-cells. We have to implement the old linux
> -	 * trick of looking for the parent here as some device-trees rely on it
> -	 */
> -	old = of_node_get(ipar);
> -	do {
> -		tmp = of_get_property(old, "#address-cells", NULL);
> -		tnode = of_get_parent(old);
> -		of_node_put(old);
> -		old = tnode;
> -	} while (old && tmp == NULL);
> -	of_node_put(old);
> -	old = NULL;
> -	addrsize = (tmp == NULL) ? 2 : *tmp;
> -
> -	pr_debug(" -> addrsize=%d\n", addrsize);
> -
> -	/* Now start the actual "proper" walk of the interrupt tree */
> -	while (ipar != NULL) {
> -		/* Now check if cursor is an interrupt-controller and if it is
> -		 * then we are done
> -		 */
> -		if (of_get_property(ipar, "interrupt-controller", NULL) !=
> -				NULL) {
> -			pr_debug(" -> got it !\n");
> -			memcpy(out_irq->specifier, intspec,
> -				intsize * sizeof(u32));
> -			out_irq->size = intsize;
> -			out_irq->controller = ipar;
> -			of_node_put(old);
> -			return 0;
> -		}
> -
> -		/* Now look for an interrupt-map */
> -		imap = of_get_property(ipar, "interrupt-map", &imaplen);
> -		/* No interrupt map, check for an interrupt parent */
> -		if (imap == NULL) {
> -			pr_debug(" -> no map, getting parent\n");
> -			newpar = of_irq_find_parent(ipar);
> -			goto skiplevel;
> -		}
> -		imaplen /= sizeof(u32);
> -
> -		/* Look for a mask */
> -		imask = of_get_property(ipar, "interrupt-map-mask", NULL);
> -
> -		/* If we were passed no "reg" property and we attempt to parse
> -		 * an interrupt-map, then #address-cells must be 0.
> -		 * Fail if it's not.
> -		 */
> -		if (addr == NULL && addrsize != 0) {
> -			pr_debug(" -> no reg passed in when needed !\n");
> -			goto fail;
> -		}
> -
> -		/* Parse interrupt-map */
> -		match = 0;
> -		while (imaplen > (addrsize + intsize + 1) && !match) {
> -			/* Compare specifiers */
> -			match = 1;
> -			for (i = 0; i < addrsize && match; ++i) {
> -				u32 mask = imask ? imask[i] : 0xffffffffu;
> -				match = ((addr[i] ^ imap[i]) & mask) == 0;
> -			}
> -			for (; i < (addrsize + intsize) && match; ++i) {
> -				u32 mask = imask ? imask[i] : 0xffffffffu;
> -				match =
> -					((intspec[i-addrsize] ^ imap[i])
> -						& mask) == 0;
> -			}
> -			imap += addrsize + intsize;
> -			imaplen -= addrsize + intsize;
> -
> -			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
> -
> -			/* Get the interrupt parent */
> -			newpar = of_irq_find_parent_by_phandle((phandle)*imap);
> -			imap++;
> -			--imaplen;
> -
> -			/* Check if not found */
> -			if (newpar == NULL) {
> -				pr_debug(" -> imap parent not found !\n");
> -				goto fail;
> -			}
> -
> -			/* Get #interrupt-cells and #address-cells of new
> -			 * parent
> -			 */
> -			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
> -			if (tmp == NULL) {
> -				pr_debug(" -> parent lacks "
> -						"#interrupt-cells!\n");
> -				goto fail;
> -			}
> -			newintsize = *tmp;
> -			tmp = of_get_property(newpar, "#address-cells", NULL);
> -			newaddrsize = (tmp == NULL) ? 0 : *tmp;
> -
> -			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
> -				newintsize, newaddrsize);
> -
> -			/* Check for malformed properties */
> -			if (imaplen < (newaddrsize + newintsize))
> -				goto fail;
> -
> -			imap += newaddrsize + newintsize;
> -			imaplen -= newaddrsize + newintsize;
> -
> -			pr_debug(" -> imaplen=%d\n", imaplen);
> -		}
> -		if (!match)
> -			goto fail;
> -
> -		of_node_put(old);
> -		old = of_node_get(newpar);
> -		addrsize = newaddrsize;
> -		intsize = newintsize;
> -		intspec = imap - intsize;
> -		addr = intspec - addrsize;
> -
> -skiplevel:
> -		/* Iterate again with new parent */
> -		pr_debug(" -> new parent: %s\n",
> -				newpar ? newpar->full_name : "<>");
> -		of_node_put(ipar);
> -		ipar = newpar;
> -		newpar = NULL;
> -	}
> -fail:
> -	of_node_put(ipar);
> -	of_node_put(old);
> -	of_node_put(newpar);
> -
> -	return -EINVAL;
> -}
> -EXPORT_SYMBOL_GPL(of_irq_map_raw);
> -
>  int of_irq_map_one(struct device_node *device,
>  			int index, struct of_irq *out_irq)
>  {
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index 47d41b6..187ef4e 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -123,27 +123,6 @@ extern const void *of_get_mac_address(struct device_node *np);
>  extern void of_irq_map_init(unsigned int flags);
>  
>  /**
> - * of_irq_map_raw - Low level interrupt tree parsing
> - * @parent:	the device interrupt parent
> - * @intspec:	interrupt specifier ("interrupts" property of the device)
> - * @ointsize:   size of the passed in interrupt specifier
> - * @addr:	address specifier (start of "reg" property of the device)
> - * @out_irq:	structure of_irq filled by this function
> - *
> - * Returns 0 on success and a negative number on error
> - *
> - * This function is a low-level interrupt tree walking function. It
> - * can be used to do a partial walk with synthetized reg and interrupts
> - * properties, for example when resolving PCI interrupts when no device
> - * node exist for the parent.
> - *
> - */
> -
> -extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
> -			  u32 ointsize, const u32 *addr,
> -			  struct of_irq *out_irq);
> -
> -/**
>   * of_irq_map_pci - Resolve the interrupt for a PCI device
>   * @pdev:	the device whose interrupt is to be resolved
>   * @out_irq:	structure of_irq filled by this function
> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
> index 39e977d..89ca7b3 100644
> --- a/arch/powerpc/kernel/prom_parse.c
> +++ b/arch/powerpc/kernel/prom_parse.c
> @@ -731,177 +731,6 @@ void of_irq_map_init(unsigned int flags)
>  
>  }
>  
> -int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
> -		const u32 *addr, struct of_irq *out_irq)
> -{
> -	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
> -	const u32 *tmp, *imap, *imask;
> -	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
> -	int imaplen, match, i;
> -
> -	DBG("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
> -	    parent->full_name, intspec[0], intspec[1], ointsize);
> -
> -	ipar = of_node_get(parent);
> -
> -	/* First get the #interrupt-cells property of the current cursor
> -	 * that tells us how to interpret the passed-in intspec. If there
> -	 * is none, we are nice and just walk up the tree
> -	 */
> -	do {
> -		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
> -		if (tmp != NULL) {
> -			intsize = *tmp;
> -			break;
> -		}
> -		tnode = ipar;
> -		ipar = of_irq_find_parent(ipar);
> -		of_node_put(tnode);
> -	} while (ipar);
> -	if (ipar == NULL) {
> -		DBG(" -> no parent found !\n");
> -		goto fail;
> -	}
> -
> -	DBG("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize);
> -
> -	if (ointsize != intsize)
> -		return -EINVAL;
> -
> -	/* Look for this #address-cells. We have to implement the old linux
> -	 * trick of looking for the parent here as some device-trees rely on it
> -	 */
> -	old = of_node_get(ipar);
> -	do {
> -		tmp = of_get_property(old, "#address-cells", NULL);
> -		tnode = of_get_parent(old);
> -		of_node_put(old);
> -		old = tnode;
> -	} while(old && tmp == NULL);
> -	of_node_put(old);
> -	old = NULL;
> -	addrsize = (tmp == NULL) ? 2 : *tmp;
> -
> -	DBG(" -> addrsize=%d\n", addrsize);
> -
> -	/* Now start the actual "proper" walk of the interrupt tree */
> -	while (ipar != NULL) {
> -		/* Now check if cursor is an interrupt-controller and if it is
> -		 * then we are done
> -		 */
> -		if (of_get_property(ipar, "interrupt-controller", NULL) !=
> -				NULL) {
> -			DBG(" -> got it !\n");
> -			memcpy(out_irq->specifier, intspec,
> -			       intsize * sizeof(u32));
> -			out_irq->size = intsize;
> -			out_irq->controller = ipar;
> -			of_node_put(old);
> -			return 0;
> -		}
> -
> -		/* Now look for an interrupt-map */
> -		imap = of_get_property(ipar, "interrupt-map", &imaplen);
> -		/* No interrupt map, check for an interrupt parent */
> -		if (imap == NULL) {
> -			DBG(" -> no map, getting parent\n");
> -			newpar = of_irq_find_parent(ipar);
> -			goto skiplevel;
> -		}
> -		imaplen /= sizeof(u32);
> -
> -		/* Look for a mask */
> -		imask = of_get_property(ipar, "interrupt-map-mask", NULL);
> -
> -		/* If we were passed no "reg" property and we attempt to parse
> -		 * an interrupt-map, then #address-cells must be 0.
> -		 * Fail if it's not.
> -		 */
> -		if (addr == NULL && addrsize != 0) {
> -			DBG(" -> no reg passed in when needed !\n");
> -			goto fail;
> -		}
> -
> -		/* Parse interrupt-map */
> -		match = 0;
> -		while (imaplen > (addrsize + intsize + 1) && !match) {
> -			/* Compare specifiers */
> -			match = 1;
> -			for (i = 0; i < addrsize && match; ++i) {
> -				u32 mask = imask ? imask[i] : 0xffffffffu;
> -				match = ((addr[i] ^ imap[i]) & mask) == 0;
> -			}
> -			for (; i < (addrsize + intsize) && match; ++i) {
> -				u32 mask = imask ? imask[i] : 0xffffffffu;
> -				match =
> -				   ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
> -			}
> -			imap += addrsize + intsize;
> -			imaplen -= addrsize + intsize;
> -
> -			DBG(" -> match=%d (imaplen=%d)\n", match, imaplen);
> -
> -			/* Get the interrupt parent */
> -			newpar = of_irq_find_parent_by_phandle((phandle)*imap);
> -			imap++;
> -			--imaplen;
> -
> -			/* Check if not found */
> -			if (newpar == NULL) {
> -				DBG(" -> imap parent not found !\n");
> -				goto fail;
> -			}
> -
> -			/* Get #interrupt-cells and #address-cells of new
> -			 * parent
> -			 */
> -			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
> -			if (tmp == NULL) {
> -				DBG(" -> parent lacks #interrupt-cells !\n");
> -				goto fail;
> -			}
> -			newintsize = *tmp;
> -			tmp = of_get_property(newpar, "#address-cells", NULL);
> -			newaddrsize = (tmp == NULL) ? 0 : *tmp;
> -
> -			DBG(" -> newintsize=%d, newaddrsize=%d\n",
> -			    newintsize, newaddrsize);
> -
> -			/* Check for malformed properties */
> -			if (imaplen < (newaddrsize + newintsize))
> -				goto fail;
> -
> -			imap += newaddrsize + newintsize;
> -			imaplen -= newaddrsize + newintsize;
> -
> -			DBG(" -> imaplen=%d\n", imaplen);
> -		}
> -		if (!match)
> -			goto fail;
> -
> -		of_node_put(old);
> -		old = of_node_get(newpar);
> -		addrsize = newaddrsize;
> -		intsize = newintsize;
> -		intspec = imap - intsize;
> -		addr = intspec - addrsize;
> -
> -	skiplevel:
> -		/* Iterate again with new parent */
> -		DBG(" -> new parent: %s\n", newpar ? newpar->full_name : "<>");
> -		of_node_put(ipar);
> -		ipar = newpar;
> -		newpar = NULL;
> -	}
> - fail:
> -	of_node_put(ipar);
> -	of_node_put(old);
> -	of_node_put(newpar);
> -
> -	return -EINVAL;
> -}
> -EXPORT_SYMBOL_GPL(of_irq_map_raw);
> -
>  #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
>  static int of_irq_map_oldworld(struct device_node *device, int index,
>  			       struct of_irq *out_irq)
> diff --git a/drivers/of/irq.c b/drivers/of/irq.c
> index ad569ca..351c87a 100644
> --- a/drivers/of/irq.c
> +++ b/drivers/of/irq.c
> @@ -52,6 +52,194 @@ struct device_node *of_irq_find_parent(struct device_node *child)
>  	return p;
>  }
>  
> +/**
> + * of_irq_map_raw - Low level interrupt tree parsing
> + * @parent:	the device interrupt parent
> + * @intspec:	interrupt specifier ("interrupts" property of the device)
> + * @ointsize:	size of the passed in interrupt specifier
> + * @addr:	address specifier (start of "reg" property of the device)
> + * @out_irq:	structure of_irq filled by this function
> + *
> + * Returns 0 on success and a negative number on error
> + *
> + * This function is a low-level interrupt tree walking function. It
> + * can be used to do a partial walk with synthetized reg and interrupts
> + * properties, for example when resolving PCI interrupts when no device
> + * node exist for the parent.
> + */
> +int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
> +		const u32 *addr, struct of_irq *out_irq)
> +{
> +	struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
> +	const u32 *tmp, *imap, *imask;
> +	u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
> +	int imaplen, match, i;
> +
> +	pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n",
> +		 parent->full_name, intspec[0], intspec[1], ointsize);
> +
> +	ipar = of_node_get(parent);
> +
> +	/* First get the #interrupt-cells property of the current cursor
> +	 * that tells us how to interpret the passed-in intspec. If there
> +	 * is none, we are nice and just walk up the tree
> +	 */
> +	do {
> +		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
> +		if (tmp != NULL) {
> +			intsize = *tmp;
> +			break;
> +		}
> +		tnode = ipar;
> +		ipar = of_irq_find_parent(ipar);
> +		of_node_put(tnode);
> +	} while (ipar);
> +	if (ipar == NULL) {
> +		pr_debug(" -> no parent found !\n");
> +		goto fail;
> +	}
> +
> +	pr_debug("of_irq_map_raw: ipar=%s, size=%d\n",
> +		 ipar->full_name, intsize);
> +
> +	if (ointsize != intsize)
> +		return -EINVAL;
> +
> +	/* Look for this #address-cells. We have to implement the old linux
> +	 * trick of looking for the parent here as some device-trees rely on it
> +	 */
> +	old = of_node_get(ipar);
> +	do {
> +		tmp = of_get_property(old, "#address-cells", NULL);
> +		tnode = of_get_parent(old);
> +		of_node_put(old);
> +		old = tnode;
> +	} while (old && tmp == NULL);
> +	of_node_put(old);
> +	old = NULL;
> +	addrsize = (tmp == NULL) ? 2 : *tmp;
> +
> +	pr_debug(" -> addrsize=%d\n", addrsize);
> +
> +	/* Now start the actual "proper" walk of the interrupt tree */
> +	while (ipar != NULL) {
> +		/* Now check if cursor is an interrupt-controller and if it is
> +		 * then we are done
> +		 */
> +		if (of_get_property(ipar, "interrupt-controller", NULL) !=
> +				NULL) {
> +			pr_debug(" -> got it !\n");
> +			memcpy(out_irq->specifier, intspec,
> +			       intsize * sizeof(u32));
> +			out_irq->size = intsize;
> +			out_irq->controller = ipar;
> +			of_node_put(old);
> +			return 0;
> +		}
> +
> +		/* Now look for an interrupt-map */
> +		imap = of_get_property(ipar, "interrupt-map", &imaplen);
> +		/* No interrupt map, check for an interrupt parent */
> +		if (imap == NULL) {
> +			pr_debug(" -> no map, getting parent\n");
> +			newpar = of_irq_find_parent(ipar);
> +			goto skiplevel;
> +		}
> +		imaplen /= sizeof(u32);
> +
> +		/* Look for a mask */
> +		imask = of_get_property(ipar, "interrupt-map-mask", NULL);
> +
> +		/* If we were passed no "reg" property and we attempt to parse
> +		 * an interrupt-map, then #address-cells must be 0.
> +		 * Fail if it's not.
> +		 */
> +		if (addr == NULL && addrsize != 0) {
> +			pr_debug(" -> no reg passed in when needed !\n");
> +			goto fail;
> +		}
> +
> +		/* Parse interrupt-map */
> +		match = 0;
> +		while (imaplen > (addrsize + intsize + 1) && !match) {
> +			/* Compare specifiers */
> +			match = 1;
> +			for (i = 0; i < addrsize && match; ++i) {
> +				u32 mask = imask ? imask[i] : 0xffffffffu;
> +				match = ((addr[i] ^ imap[i]) & mask) == 0;
> +			}
> +			for (; i < (addrsize + intsize) && match; ++i) {
> +				u32 mask = imask ? imask[i] : 0xffffffffu;
> +				match =
> +				   ((intspec[i-addrsize] ^ imap[i]) & mask) == 0;
> +			}
> +			imap += addrsize + intsize;
> +			imaplen -= addrsize + intsize;
> +
> +			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
> +
> +			/* Get the interrupt parent */
> +			newpar = of_irq_find_parent_by_phandle((phandle)*imap);
> +			imap++;
> +			--imaplen;
> +
> +			/* Check if not found */
> +			if (newpar == NULL) {
> +				pr_debug(" -> imap parent not found !\n");
> +				goto fail;
> +			}
> +
> +			/* Get #interrupt-cells and #address-cells of new
> +			 * parent
> +			 */
> +			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
> +			if (tmp == NULL) {
> +				pr_debug(" -> parent lacks #interrupt-cells!\n");
> +				goto fail;
> +			}
> +			newintsize = *tmp;
> +			tmp = of_get_property(newpar, "#address-cells", NULL);
> +			newaddrsize = (tmp == NULL) ? 0 : *tmp;
> +
> +			pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
> +			    newintsize, newaddrsize);
> +
> +			/* Check for malformed properties */
> +			if (imaplen < (newaddrsize + newintsize))
> +				goto fail;
> +
> +			imap += newaddrsize + newintsize;
> +			imaplen -= newaddrsize + newintsize;
> +
> +			pr_debug(" -> imaplen=%d\n", imaplen);
> +		}
> +		if (!match)
> +			goto fail;
> +
> +		of_node_put(old);
> +		old = of_node_get(newpar);
> +		addrsize = newaddrsize;
> +		intsize = newintsize;
> +		intspec = imap - intsize;
> +		addr = intspec - addrsize;
> +
> +	skiplevel:
> +		/* Iterate again with new parent */
> +		pr_debug(" -> new parent: %s\n",
> +			 newpar ? newpar->full_name : "<>");
> +		of_node_put(ipar);
> +		ipar = newpar;
> +		newpar = NULL;
> +	}
> + fail:
> +	of_node_put(ipar);
> +	of_node_put(old);
> +	of_node_put(newpar);
> +
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL_GPL(of_irq_map_raw);
> +
>  unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
>  {
>  	struct of_irq oirq;
> diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
> index f98b27b..51c520b 100644
> --- a/include/linux/of_irq.h
> +++ b/include/linux/of_irq.h
> @@ -32,6 +32,8 @@ struct of_irq {
>  
>  extern struct device_node *of_irq_find_parent_by_phandle(phandle p);
>  extern struct device_node *of_irq_find_parent(struct device_node *child);
> +extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
> +			 u32 ointsize, const u32 *addr, struct of_irq *out_irq);
>  extern int of_irq_map_one(struct device_node *device, int index,
>  			  struct of_irq *out_irq);
>  extern unsigned int irq_create_of_mapping(struct device_node *controller,

^ permalink raw reply

* Re: [PATCH 3/5] of/irq: merge of_irq_find_parent()
From: Benjamin Herrenschmidt @ 2010-06-10  6:38 UTC (permalink / raw)
  To: Grant Likely
  Cc: Stephen Rothwell, Michal Simek, linuxppc-dev, devicetree-discuss,
	microblaze-uclinux
In-Reply-To: <20100604212145.10552.95452.stgit@angua>

On Fri, 2010-06-04 at 15:21 -0600, Grant Likely wrote:
> Merge common code between PowerPC and Microblaze.  Also create a new
> arch hook, of_irq_find_parent_by_phandle() to handle arch-specific
> quirks.

First, you changeset comment should be much more verbose as to
what that arch specific quirk is about etc... it took me time to figure
it out again :-)

I dislike the naming you use. Your "of_irq_find_parent_by_phandle"
doesn't ring "right" to me.

I'm tempted to say we should put the quirks in the common code, your
attempt at "abstracting" them just makes the code much harder to follow.

Also, if we stick to your approach the "default" variant should either
be an inline protected by an ifndef or a weak function.

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> CC: Michal Simek <monstr@monstr.eu>
> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> CC: Stephen Rothwell <sfr@canb.auug.org.au>
> CC: microblaze-uclinux@itee.uq.edu.au
> CC: linuxppc-dev@lists.ozlabs.org
> CC: devicetree-discuss@lists.ozlabs.org
> ---
>  arch/microblaze/kernel/prom_parse.c |   22 +++-------------------
>  arch/powerpc/kernel/prom_parse.c    |   30 +++++-------------------------
>  drivers/of/irq.c                    |   28 ++++++++++++++++++++++++++++
>  include/linux/of_irq.h              |    2 ++
>  4 files changed, 38 insertions(+), 44 deletions(-)
> 
> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
> index af1b2a7..946f14d 100644
> --- a/arch/microblaze/kernel/prom_parse.c
> +++ b/arch/microblaze/kernel/prom_parse.c
> @@ -648,25 +648,9 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>   * Interrupt remapper
>   */
>  
> -static struct device_node *of_irq_find_parent(struct device_node *child)
> +struct device_node *of_irq_find_parent_by_phandle(phandle p)
>  {
> -	struct device_node *p;
> -	const phandle *parp;
> -
> -	if (!of_node_get(child))
> -		return NULL;
> -
> -	do {
> -		parp = of_get_property(child, "interrupt-parent", NULL);
> -		if (parp == NULL)
> -			p = of_get_parent(child);
> -		else
> -			p = of_find_node_by_phandle(*parp);
> -		of_node_put(child);
> -		child = p;
> -	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
> -
> -	return p;
> +	return of_find_node_by_phandle(p);
>  }
>  
>  int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
> @@ -783,7 +767,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
>  			pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
>  
>  			/* Get the interrupt parent */
> -			newpar = of_find_node_by_phandle((phandle)*imap);
> +			newpar = of_irq_find_parent_by_phandle((phandle)*imap);
>  			imap++;
>  			--imaplen;
>  
> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
> index 8362620..39e977d 100644
> --- a/arch/powerpc/kernel/prom_parse.c
> +++ b/arch/powerpc/kernel/prom_parse.c
> @@ -685,29 +685,12 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>  static unsigned int of_irq_workarounds;
>  static struct device_node *of_irq_dflt_pic;
>  
> -static struct device_node *of_irq_find_parent(struct device_node *child)
> +struct device_node *of_irq_find_parent_by_phandle(phandle p)
>  {
> -	struct device_node *p;
> -	const phandle *parp;
> -
> -	if (!of_node_get(child))
> -		return NULL;
> -
> -	do {
> -		parp = of_get_property(child, "interrupt-parent", NULL);
> -		if (parp == NULL)
> -			p = of_get_parent(child);
> -		else {
> -			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
> -				p = of_node_get(of_irq_dflt_pic);
> -			else
> -				p = of_find_node_by_phandle(*parp);
> -		}
> -		of_node_put(child);
> -		child = p;
> -	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
> +	if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
> +		return of_node_get(of_irq_dflt_pic);
>  
> -	return p;
> +	return of_find_node_by_phandle(p);
>  }
>  
>  /* This doesn't need to be called if you don't have any special workaround
> @@ -859,10 +842,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
>  			DBG(" -> match=%d (imaplen=%d)\n", match, imaplen);
>  
>  			/* Get the interrupt parent */
> -			if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
> -				newpar = of_node_get(of_irq_dflt_pic);
> -			else
> -				newpar = of_find_node_by_phandle((phandle)*imap);
> +			newpar = of_irq_find_parent_by_phandle((phandle)*imap);
>  			imap++;
>  			--imaplen;
>  
> diff --git a/drivers/of/irq.c b/drivers/of/irq.c
> index 56ad1aa..ad569ca 100644
> --- a/drivers/of/irq.c
> +++ b/drivers/of/irq.c
> @@ -24,6 +24,34 @@
>  #include <linux/of_irq.h>
>  #include <linux/string.h>
>  
> +/**
> + * of_irq_find_parent - Given a device node, find its interrupt parent node
> + * @child: pointer to device node
> + *
> + * Returns a pointer to the interrupt parent node, or NULL if the interrupt
> + * parent could not be determined.
> + */
> +struct device_node *of_irq_find_parent(struct device_node *child)
> +{
> +	struct device_node *p;
> +	const phandle *parp;
> +
> +	if (!of_node_get(child))
> +		return NULL;
> +
> +	do {
> +		parp = of_get_property(child, "interrupt-parent", NULL);
> +		if (parp == NULL)
> +			p = of_get_parent(child);
> +		else
> +			p = of_irq_find_parent_by_phandle(*parp);
> +		of_node_put(child);
> +		child = p;
> +	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
> +
> +	return p;
> +}
> +
>  unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
>  {
>  	struct of_irq oirq;
> diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
> index 0e37c05..f98b27b 100644
> --- a/include/linux/of_irq.h
> +++ b/include/linux/of_irq.h
> @@ -30,6 +30,8 @@ struct of_irq {
>  	u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
>  };
>  
> +extern struct device_node *of_irq_find_parent_by_phandle(phandle p);
> +extern struct device_node *of_irq_find_parent(struct device_node *child);
>  extern int of_irq_map_one(struct device_node *device, int index,
>  			  struct of_irq *out_irq);
>  extern unsigned int irq_create_of_mapping(struct device_node *controller,

^ permalink raw reply

* Re: [PATCH 1/5] of/irq: Move irq_of_parse_and_map() to common code
From: Benjamin Herrenschmidt @ 2010-06-10  6:33 UTC (permalink / raw)
  To: Grant Likely
  Cc: Stephen Rothwell, Michal Simek, microblaze-uclinux,
	devicetree-discuss, linuxppc-dev, sparclinux, Jeremy Kerr,
	David S. Miller
In-Reply-To: <20100604212134.10552.70717.stgit@angua>

On Fri, 2010-06-04 at 15:21 -0600, Grant Likely wrote:
> Merge common code between PowerPC and Microblaze.  SPARC implements
> irq_of_parse_and_map(), but the implementation is different, so it
> does not use this code.
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> CC: Michal Simek <monstr@monstr.eu>
> CC: "David S. Miller" <davem@davemloft.net>
> CC: Stephen Rothwell <sfr@canb.auug.org.au>

Acked-by : Benjamin Herrenschmidt <benh@kernel.crashing.org>

> CC: Jeremy Kerr <jeremy.kerr@canonical.com>
> CC: microblaze-uclinux@itee.uq.edu.au
> CC: linuxppc-dev@ozlabs.org
> CC: sparclinux@vger.kernel.org
> CC: devicetree-discuss@lists.ozlabs.org
> ---
>  arch/microblaze/include/asm/irq.h  |   13 -----------
>  arch/microblaze/include/asm/prom.h |   26 +----------------------
>  arch/microblaze/kernel/irq.c       |   14 ++----------
>  arch/powerpc/include/asm/irq.h     |   13 -----------
>  arch/powerpc/include/asm/prom.h    |   27 +-----------------------
>  arch/powerpc/kernel/irq.c          |   14 ++----------
>  arch/sparc/include/asm/prom.h      |    1 -
>  drivers/of/Kconfig                 |    4 ++++
>  drivers/of/Makefile                |    1 +
>  drivers/of/irq.c                   |   37 ++++++++++++++++++++++++++++++++
>  drivers/of/of_mdio.c               |    1 +
>  include/linux/of_irq.h             |   41 ++++++++++++++++++++++++++++++++++++
>  12 files changed, 90 insertions(+), 102 deletions(-)
>  create mode 100644 drivers/of/irq.c
>  create mode 100644 include/linux/of_irq.h
> 
> diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h
> index 31a35c3..10d75c1 100644
> --- a/arch/microblaze/include/asm/irq.h
> +++ b/arch/microblaze/include/asm/irq.h
> @@ -62,17 +62,4 @@ struct irq_host;
>  extern unsigned int irq_create_mapping(struct irq_host *host,
>  					irq_hw_number_t hwirq);
>  
> -/**
> - * irq_create_of_mapping - Map a hardware interrupt into linux virq space
> - * @controller: Device node of the interrupt controller
> - * @inspec: Interrupt specifier from the device-tree
> - * @intsize: Size of the interrupt specifier from the device-tree
> - *
> - * This function is identical to irq_create_mapping except that it takes
> - * as input informations straight from the device-tree (typically the results
> - * of the of_irq_map_*() functions.
> - */
> -extern unsigned int irq_create_of_mapping(struct device_node *controller,
> -					u32 *intspec, unsigned int intsize);
> -
>  #endif /* _ASM_MICROBLAZE_IRQ_H */
> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
> index e7d67a3..e9fb2eb 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -20,6 +20,7 @@
>  #ifndef __ASSEMBLY__
>  
>  #include <linux/types.h>
> +#include <linux/of_irq.h>
>  #include <linux/of_fdt.h>
>  #include <linux/proc_fs.h>
>  #include <linux/platform_device.h>
> @@ -92,18 +93,6 @@ extern const void *of_get_mac_address(struct device_node *np);
>   * OF interrupt mapping
>   */
>  
> -/* This structure is returned when an interrupt is mapped. The controller
> - * field needs to be put() after use
> - */
> -
> -#define OF_MAX_IRQ_SPEC		4 /* We handle specifiers of at most 4 cells */
> -
> -struct of_irq {
> -	struct device_node *controller; /* Interrupt controller node */
> -	u32 size; /* Specifier size */
> -	u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
> -};
> -
>  /**
>   * of_irq_map_init - Initialize the irq remapper
>   * @flags:	flags defining workarounds to enable
> @@ -139,19 +128,6 @@ extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
>  			struct of_irq *out_irq);
>  
>  /**
> - * of_irq_map_one - Resolve an interrupt for a device
> - * @device:	the device whose interrupt is to be resolved
> - * @index:	index of the interrupt to resolve
> - * @out_irq:	structure of_irq filled by this function
> - *
> - * This function resolves an interrupt, walking the tree, for a given
> - * device-tree node. It's the high level pendant to of_irq_map_raw().
> - * It also implements the workarounds for OldWolrd Macs.
> - */
> -extern int of_irq_map_one(struct device_node *device, int index,
> -			struct of_irq *out_irq);
> -
> -/**
>   * of_irq_map_pci - Resolve the interrupt for a PCI device
>   * @pdev:	the device whose interrupt is to be resolved
>   * @out_irq:	structure of_irq filled by this function
> diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
> index 8f120ac..dd32b09 100644
> --- a/arch/microblaze/kernel/irq.c
> +++ b/arch/microblaze/kernel/irq.c
> @@ -17,20 +17,10 @@
>  #include <linux/seq_file.h>
>  #include <linux/kernel_stat.h>
>  #include <linux/irq.h>
> +#include <linux/of_irq.h>
>  
>  #include <asm/prom.h>
>  
> -unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
> -{
> -	struct of_irq oirq;
> -
> -	if (of_irq_map_one(dev, index, &oirq))
> -		return NO_IRQ;
> -
> -	return oirq.specifier[0];
> -}
> -EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
> -
>  static u32 concurrent_irq;
>  
>  void __irq_entry do_IRQ(struct pt_regs *regs)
> @@ -104,7 +94,7 @@ unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
>  EXPORT_SYMBOL_GPL(irq_create_mapping);
>  
>  unsigned int irq_create_of_mapping(struct device_node *controller,
> -					u32 *intspec, unsigned int intsize)
> +				   const u32 *intspec, unsigned int intsize)
>  {
>  	return intspec[0];
>  }
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index e054bae..a3b5124 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -304,19 +304,6 @@ extern void irq_free_virt(unsigned int virq, unsigned int count);
>  /* -- OF helpers -- */
>  
>  /**
> - * irq_create_of_mapping - Map a hardware interrupt into linux virq space
> - * @controller: Device node of the interrupt controller
> - * @inspec: Interrupt specifier from the device-tree
> - * @intsize: Size of the interrupt specifier from the device-tree
> - *
> - * This function is identical to irq_create_mapping except that it takes
> - * as input informations straight from the device-tree (typically the results
> - * of the of_irq_map_*() functions.
> - */
> -extern unsigned int irq_create_of_mapping(struct device_node *controller,
> -					  const u32 *intspec, unsigned int intsize);
> -
> -/**
>   * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space
>   * @device: Device node of the device whose interrupt is to be mapped
>   * @index: Index of the interrupt to map
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index ddd408a..47d41b6 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -18,6 +18,7 @@
>   */
>  #include <linux/types.h>
>  #include <linux/of_fdt.h>
> +#include <linux/of_irq.h>
>  #include <linux/proc_fs.h>
>  #include <linux/platform_device.h>
>  #include <asm/irq.h>
> @@ -108,18 +109,6 @@ extern const void *of_get_mac_address(struct device_node *np);
>   * OF interrupt mapping
>   */
>  
> -/* This structure is returned when an interrupt is mapped. The controller
> - * field needs to be put() after use
> - */
> -
> -#define OF_MAX_IRQ_SPEC		 4 /* We handle specifiers of at most 4 cells */
> -
> -struct of_irq {
> -	struct device_node *controller;	/* Interrupt controller node */
> -	u32 size;			/* Specifier size */
> -	u32 specifier[OF_MAX_IRQ_SPEC];	/* Specifier copy */
> -};
> -
>  /**
>   * of_irq_map_init - Initialize the irq remapper
>   * @flags:	flags defining workarounds to enable
> @@ -154,20 +143,6 @@ extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec,
>  			  u32 ointsize, const u32 *addr,
>  			  struct of_irq *out_irq);
>  
> -
> -/**
> - * of_irq_map_one - Resolve an interrupt for a device
> - * @device:	the device whose interrupt is to be resolved
> - * @index:     	index of the interrupt to resolve
> - * @out_irq:	structure of_irq filled by this function
> - *
> - * This function resolves an interrupt, walking the tree, for a given
> - * device-tree node. It's the high level pendant to of_irq_map_raw().
> - * It also implements the workarounds for OldWolrd Macs.
> - */
> -extern int of_irq_map_one(struct device_node *device, int index,
> -			  struct of_irq *out_irq);
> -
>  /**
>   * of_irq_map_pci - Resolve the interrupt for a PCI device
>   * @pdev:	the device whose interrupt is to be resolved
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 30817d9..2676ef2 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -53,6 +53,8 @@
>  #include <linux/bootmem.h>
>  #include <linux/pci.h>
>  #include <linux/debugfs.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
>  
>  #include <asm/uaccess.h>
>  #include <asm/system.h>
> @@ -813,18 +815,6 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
>  }
>  EXPORT_SYMBOL_GPL(irq_create_of_mapping);
>  
> -unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
> -{
> -	struct of_irq oirq;
> -
> -	if (of_irq_map_one(dev, index, &oirq))
> -		return NO_IRQ;
> -
> -	return irq_create_of_mapping(oirq.controller, oirq.specifier,
> -				     oirq.size);
> -}
> -EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
> -
>  void irq_dispose_mapping(unsigned int virq)
>  {
>  	struct irq_host *host;
> diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
> index f845828..ac69574 100644
> --- a/arch/sparc/include/asm/prom.h
> +++ b/arch/sparc/include/asm/prom.h
> @@ -56,7 +56,6 @@ extern void of_fill_in_cpu_data(void);
>   * register them in the of_device objects, whereas powerpc computes them
>   * on request.
>   */
> -extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
>  static inline void irq_dispose_mapping(unsigned int virq)
>  {
>  }
> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
> index 7cecc8f..b87495e 100644
> --- a/drivers/of/Kconfig
> +++ b/drivers/of/Kconfig
> @@ -6,6 +6,10 @@ config OF_DYNAMIC
>  	def_bool y
>  	depends on OF && PPC_OF
>  
> +config OF_IRQ
> +	def_bool y
> +	depends on OF && !SPARC
> +
>  config OF_DEVICE
>  	def_bool y
>  	depends on OF && (SPARC || PPC_OF || MICROBLAZE)
> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
> index f232cc9..3631a5e 100644
> --- a/drivers/of/Makefile
> +++ b/drivers/of/Makefile
> @@ -1,5 +1,6 @@
>  obj-y = base.o
>  obj-$(CONFIG_OF_FLATTREE) += fdt.o
> +obj-$(CONFIG_OF_IRQ)    += irq.o
>  obj-$(CONFIG_OF_DEVICE) += device.o platform.o
>  obj-$(CONFIG_OF_GPIO)   += gpio.o
>  obj-$(CONFIG_OF_I2C)	+= of_i2c.o
> diff --git a/drivers/of/irq.c b/drivers/of/irq.c
> new file mode 100644
> index 0000000..56ad1aa
> --- /dev/null
> +++ b/drivers/of/irq.c
> @@ -0,0 +1,37 @@
> +/*
> + *  Derived from arch/i386/kernel/irq.c
> + *    Copyright (C) 1992 Linus Torvalds
> + *  Adapted from arch/i386 by Gary Thomas
> + *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
> + *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
> + *    Copyright (C) 1996-2001 Cort Dougan
> + *  Adapted for Power Macintosh by Paul Mackerras
> + *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * This file contains the code used to make IRQ descriptions in the
> + * device tree to actual irq numbers on an interrupt controller
> + * driver.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/string.h>
> +
> +unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
> +{
> +	struct of_irq oirq;
> +
> +	if (of_irq_map_one(dev, index, &oirq))
> +		return NO_IRQ;
> +
> +	return irq_create_of_mapping(oirq.controller, oirq.specifier,
> +				     oirq.size);
> +}
> +EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
> diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
> index 42a6715..1fce00e 100644
> --- a/drivers/of/of_mdio.c
> +++ b/drivers/of/of_mdio.c
> @@ -15,6 +15,7 @@
>  #include <linux/err.h>
>  #include <linux/phy.h>
>  #include <linux/of.h>
> +#include <linux/of_irq.h>
>  #include <linux/of_mdio.h>
>  #include <linux/module.h>
>  
> diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
> new file mode 100644
> index 0000000..0e37c05
> --- /dev/null
> +++ b/include/linux/of_irq.h
> @@ -0,0 +1,41 @@
> +#ifndef __OF_IRQ_H
> +#define __OF_IRQ_H
> +
> +#if defined(CONFIG_OF)
> +struct of_irq;
> +#include <linux/types.h>
> +#include <linux/of.h>
> +
> +/*
> + * irq_of_parse_and_map() is used ba all OF enabled platforms; but SPARC
> + * implements it differently.  However, the prototype is the same for all,
> + * so declare it here regardless of the CONFIG_OF_IRQ setting.
> + */
> +extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
> +
> +#if defined(CONFIG_OF_IRQ)
> +/**
> + * of_irq - container for device_node/irq_specifier pair for an irq controller
> + * @controller: pointer to interrupt controller device tree node
> + * @size: size of interrupt specifier
> + * @specifier: array of cells @size long specifing the specific interrupt
> + *
> + * This structure is returned when an interrupt is mapped. The controller
> + * field needs to be put() after use
> + */
> +#define OF_MAX_IRQ_SPEC		4 /* We handle specifiers of at most 4 cells */
> +struct of_irq {
> +	struct device_node *controller; /* Interrupt controller node */
> +	u32 size; /* Specifier size */
> +	u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
> +};
> +
> +extern int of_irq_map_one(struct device_node *device, int index,
> +			  struct of_irq *out_irq);
> +extern unsigned int irq_create_of_mapping(struct device_node *controller,
> +					  const u32 *intspec,
> +					  unsigned int intsize);
> +
> +#endif /* CONFIG_OF_IRQ */
> +#endif /* CONFIG_OF */
> +#endif /* __OF_IRQ_H */

^ permalink raw reply

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

On Fri, 2010-06-04 at 15:13 -0600, Grant Likely wrote:
> This series is based on Linus' current tree.  It 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- ? :-)

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

Cheers,
Ben.

^ permalink raw reply


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