* 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: [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: 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: 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: [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
* [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 3/5] Removing dead CONFIG_SMP_750
From: Christoph Egger @ 2010-06-10 12:23 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Paul Mackerras, vamos, linux-kernel, linuxppc-dev
In-Reply-To: <1276150461.1962.42.camel@pasglop>
On Thu, Jun 10, 2010 at 04:14:21PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2010-06-09 at 08:35 -0400, Josh Boyer wrote:
> > On Wed, Jun 09, 2010 at 12:00:21PM +0200, Christoph Egger wrote:
> > >CONFIG_SMP_750 doesn't exist in Kconfig, therefore removing all
> > >references for it from the source code.
> >
> > Yeah, we don't support SMP on 750 at the moment. This code was carried over
> > from the arch/ppc days, and that code was present pre-git. I think we can
> > drop it, but I'll leave that up to Ben. Maybe he has crazy plans for a 750 SMP
> > board.
>
> Nope :-) Though it would be nice to also remove the call sites too and
> thus remove the macro entirely.
SOmething like below?
-----
From: Christoph Egger <siccegge@cs.fau.de>
Subject: [PATCH 3/5] Removing dead CONFIG_SMP_750
CONFIG_SMP_750 doesn't exist in Kconfig, therefore removing all
references for it from the source code.
Signed-off-by: Christoph Egger <siccegge@cs.fau.de>
diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c
index 8aaa8b7..09c7820 100644
--- a/arch/powerpc/mm/tlb_hash32.c
+++ b/arch/powerpc/mm/tlb_hash32.c
@@ -94,11 +94,6 @@ void tlb_flush(struct mmu_gather *tlb)
* the cache operations on the bus. Hence we need to use an IPI
* to get the other CPU(s) to invalidate their TLBs.
*/
-#ifdef CONFIG_SMP_750
-#define FINISH_FLUSH smp_send_tlb_invalidate(0)
-#else
-#define FINISH_FLUSH do { } while (0)
-#endif
static void flush_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
@@ -138,7 +133,6 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
flush_range(&init_mm, start, end);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_kernel_range);
@@ -162,7 +156,6 @@ void flush_tlb_mm(struct mm_struct *mm)
*/
for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
flush_range(mp->vm_mm, mp->vm_start, mp->vm_end);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_mm);
@@ -179,7 +172,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
if (!pmd_none(*pmd))
flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_page);
@@ -192,6 +184,5 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
flush_range(vma->vm_mm, start, end);
- FINISH_FLUSH;
}
EXPORT_SYMBOL(flush_tlb_range);
--
1.6.3.3
^ permalink raw reply related
* Re: [Patch 5/5] PPC64-HWBKPT: Discard extraneous interrupt due to accesses outside symbol length
From: Paul Mackerras @ 2010-06-10 12:40 UTC (permalink / raw)
To: K.Prasad
Cc: Michael Neuling, Benjamin Herrenschmidt, shaggy,
Frederic Weisbecker, David Gibson, linuxppc-dev@ozlabs.org,
Alan Stern, Roland McGrath
In-Reply-To: <20100609102559.GF20332@in.ibm.com>
On Wed, Jun 09, 2010 at 03:55:59PM +0530, K.Prasad wrote:
> + if (!((bp->attr.bp_addr <= dar) &&
> + (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) {
> + /*
> + * This exception is triggered not because of a memory access
> + * on the monitored variable but in the double-word address
> + * range in which it is contained. We will consume this
> + * exception, considering it as 'noise'.
> + */
> + info->extraneous_interrupt = true;
> + }
Ummm, don't you need to add "else info->extraneous_interrupt = false;"
here? I don't see anywhere that you ever clear it otherwise.
Also, I think you need to do the "if (!info->extraneous_interrupt)"
check around the call to perf_bp_event() later on in
hw_breakpoint_handler() as well as around the call in
single_step_dabr_instruction().
Paul.
^ permalink raw reply
* Mac Mini suspend issues - misidentified model
From: Mark Crichton @ 2010-06-10 13:50 UTC (permalink / raw)
To: linuxppc-dev
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
I've dug up and revived my old Mac Mini (PPC) and been trying to get it
to work again. I was looking at getting the system to suspend to ram,
but it didn't seem to be working. So, I tried to trace down the problem.
I took a look at the kernel code, and I think I may have found the
issue. According to /proc/cpuinfo, my model is a "PowerMac10,2". Looking
at platforms/powermac/feature.c, I only see an entry for "PowerMac10,1".
- From my understanding of the code, this means my machine doesn't get
PMAC_MB_MAY_SLEEP set, hence no suspend to ram.
I can easily get a patch together to just copy the PowerMac10,1 entry in
pmac_mb_defs, for the PowerMac10,2, but I also was wondering if there's
some issues I may run into. However, from what I see in the code, this
seems to be a pretty risk-free operation.
Am I on the right track for this one?
Thanks,
Mark Crichton
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAkwQ7aIACgkQOfj2Ja/u/oBxYACeOX5jUQOJ5XloojtoZJXneZL/
734An1mP41QPuLg/RtVllmgQjgdBxdBJ
=LLH3
-----END PGP SIGNATURE-----
^ permalink raw reply
* [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Steven A. Falco @ 2010-06-10 14:00 UTC (permalink / raw)
To: linuxppc-dev@ozlabs.org
SIOCGMIIREG and SIOCSMIIREG access a user data structure via a void
pointer to user space. So, we need copy_from_user and copy_to_user
to move the data.
Signed-off-by: Steven A. Falco <sfalco@harris.com>
---
I believe there is a bug in the way the ibm_newemac driver handles the
SIOCGMIIREG (and SIOCSMIIREG) ioctl. The problem is that emac_ioctl
is handed a "struct ifreq *rq" which contains a user-land pointer to
an array of 16-bit integers.
However, emac_ioctl directly accesses the data, which doesn't work.
I added the following patch to copy the data in and out.
Please note that this patch was tested in an older kernel (2.6.30)
because that is what we are using on our custom hardware. I think
this is still a problem in the current code, but I'd like reviewers
to take a look, to be sure.
--- drivers/net/ibm_newemac/core.c 2010-06-09 19:57:26.000000000 -0400
+++ /home/sfalco/core.c 2010-06-10 09:38:22.000000000 -0400
@@ -2218,6 +2218,7 @@
{
struct emac_instance *dev = netdev_priv(ndev);
struct mii_ioctl_data *data = if_mii(rq);
+ struct mii_ioctl_data user_data;
DBG(dev, "ioctl %08x" NL, cmd);
@@ -2229,13 +2230,19 @@
data->phy_id = dev->phy.address;
/* Fall through */
case SIOCGMIIREG:
- data->val_out = emac_mdio_read(ndev, dev->phy.address,
- data->reg_num);
+ if (copy_from_user(user_data, (char __user *)data, sizeof(user_data)))
+ return -EFAULT;
+ user_data->val_out = emac_mdio_read(ndev, dev->phy.address,
+ user_data->reg_num);
+ if (copy_to_user((char __user *)rq->ifr_data, user_data, sizeof(user_data)))
+ return -EFAULT;
return 0;
case SIOCSMIIREG:
- emac_mdio_write(ndev, dev->phy.address, data->reg_num,
- data->val_in);
+ if (copy_from_user(user_data, (char __user *)data, sizeof(user_data)))
+ return -EFAULT;
+ emac_mdio_write(ndev, dev->phy.address, user_data->reg_num,
+ user_data->val_in);
return 0;
default:
return -EOPNOTSUPP;
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-10 14:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: sfr, monstr, microblaze-uclinux, devicetree-discuss, jeremy.kerr,
linuxppc-dev
In-Reply-To: <1276150663.1962.43.camel@pasglop>
On Thu, Jun 10, 2010 at 12:17 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
>
>> You just introduced an unnamed structure of device + resources,
>> it isn't declared anywhere but in the code itself (either via
>> &foo[1] or buf + sizeof(*foo)).
>>
>> You're not the only one who hacks (or at least have to
>> understand) the OF stuff, so let's try keep this stuff
>> readable?
>>
>> I told you several ways of how to improve the code (based on
>> the ideas from drivers/base/, so the ideas aren't even mine,
>> fwiw).
>
> I tend to agree with Anton here.
The reason I'm confident doing it that way is that it is *not* a
structure. There is no structure relationship between the resource
table and the platform_device other than they are allocated with the
same kzalloc() call. All the code that cares about that is contained
within 4 lines of code. I'm resistant to using a structure because it
is adds an additional 5-6 lines of code to add a structure that won't
be used anywhere else, and is only 4 lines to begin with.
> BTW. Why not make of_device a wrapper (or even alias of)
> platform_device ? :-) That way you get the resource array etc.. for free
> and it will make the whole of_device vs. platform_device issue moot.
of_device is an alias of platform_device now. The resource array in
platform devices is not statically defined. It is allocated
separately. I can't currently use the platform_device_alloc code
which does separate deallocation because the OF code needs its own
release hook to put the node. OTOH, I can probably change the guts of
of_release_dev() to be called by platform_device_release().
okay, I'll try changing this an see how it looks.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 3/5] of/address: Merge all of the bus translation code
From: Grant Likely @ 2010-06-10 14:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Stephen Rothwell, Michal Simek, microblaze-uclinux
In-Reply-To: <1276152212.1962.59.camel@pasglop>
On Thu, Jun 10, 2010 at 12:43 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
>> Microblaze and PowerPC share a large chunk of code for translating
>> OF device tree data into usable addresses. =A0There aren't many differen=
ces
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ^^^^
> Care to comment on these differences ?
Purely cosmetic IIRC, but I will go back and double check. Things
like printk vs. pr_info and some style differences. I looked at them
side-by-side and fixed each difference individually until they were
identical.
>> between the two, so merge the codebase wholesale rather than trying to
>> work out the independent bits.
>
> Well, I don't see ifdef's in the resulting code (but I'm a bit blind),
> so what did you do with the differences ?
>
> This is complex and fragile code, so any change to it must be very
> carefully scrutinized.
>
> Cheers,
> Ben.
>
>> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
>> CC: Michal Simek <monstr@monstr.eu>
>> CC: Wolfram Sang <w.sang@pengutronix.de>
>> CC: Stephen Rothwell <sfr@canb.auug.org.au>
>> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> CC: microblaze-uclinux@itee.uq.edu.au
>> CC: linuxppc-dev@ozlabs.org
>> ---
>> =A0arch/microblaze/include/asm/prom.h =A0| =A0 =A04
>> =A0arch/microblaze/kernel/prom_parse.c | =A0489 ------------------------=
---------
>> =A0arch/powerpc/include/asm/prom.h =A0 =A0 | =A0 =A04
>> =A0arch/powerpc/kernel/prom_parse.c =A0 =A0| =A0515 --------------------=
---------------
>> =A0drivers/of/address.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0517 ++++++++=
+++++++++++++++++++++++++++
>> =A0include/linux/of_address.h =A0 =A0 =A0 =A0 =A0| =A0 =A04
>> =A06 files changed, 515 insertions(+), 1018 deletions(-)
>>
>> diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/includ=
e/asm/prom.h
>> index 644fa32..35cb3de 100644
>> --- a/arch/microblaze/include/asm/prom.h
>> +++ b/arch/microblaze/include/asm/prom.h
>> @@ -52,10 +52,6 @@ extern void pci_create_OF_bus_map(void);
>> =A0 * OF address retreival & translation
>> =A0 */
>>
>> -/* Translate an OF address block into a CPU physical address
>> - */
>> -extern u64 of_translate_address(struct device_node *np, const u32 *addr=
);
>> -
>> =A0/* Extract an address from a device, returns the region size and
>> =A0 * the address space flags too. The PCI version uses a BAR number
>> =A0 * instead of an absolute index
>> diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kerne=
l/prom_parse.c
>> index 7cb5a98..1d610e6 100644
>> --- a/arch/microblaze/kernel/prom_parse.c
>> +++ b/arch/microblaze/kernel/prom_parse.c
>> @@ -10,213 +10,7 @@
>> =A0#include <asm/prom.h>
>> =A0#include <asm/pci-bridge.h>
>>
>> -#define PRu64 =A0 =A0 =A0 =A0"%llx"
>> -
>> -/* Max address size we deal with */
>> -#define OF_MAX_ADDR_CELLS =A0 =A04
>> -#define OF_CHECK_COUNTS(na, ns) =A0 =A0 =A0((na) > 0 && (na) <=3D OF_MA=
X_ADDR_CELLS && \
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (ns) > 0)
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np);
>> -
>> -/* Debug utility */
>> -#ifdef DEBUG
>> -static void of_dump_addr(const char *s, const u32 *addr, int na)
>> -{
>> - =A0 =A0 printk(KERN_INFO "%s", s);
>> - =A0 =A0 while (na--)
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_INFO " %08x", *(addr++));
>> - =A0 =A0 printk(KERN_INFO "\n");
>> -}
>> -#else
>> -static void of_dump_addr(const char *s, const u32 *addr, int na) { }
>> -#endif
>> -
>> -/* Callbacks for bus specific translators */
>> -struct of_bus {
>> - =A0 =A0 const char =A0 =A0 =A0*name;
>> - =A0 =A0 const char =A0 =A0 =A0*addresses;
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*match)(struct device_node *paren=
t);
>> - =A0 =A0 void =A0 =A0 =A0 =A0 =A0 =A0(*count_cells)(struct device_node =
*child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 int *addrc, int *sizec);
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 (*map)(u32 *addr, const u32 *range=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns=
, int pna);
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*translate)(u32 *addr, u64 offset=
, int na);
>> - =A0 =A0 unsigned int =A0 =A0(*get_flags)(const u32 *addr);
>> -};
>> -
>> -/*
>> - * Default translator (generic bus)
>> - */
>> -
>> -static void of_bus_default_count_cells(struct device_node *dev,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 int *addrc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D of_n_addr_cells(dev);
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D of_n_size_cells(dev);
>> -}
>> -
>> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
>> - =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 cp =3D of_read_number(range, na);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr, na);
>> -
>> - =A0 =A0 pr_debug("OF: default map, cp=3D"PRu64", s=3D"PRu64", da=3D"PR=
u64"\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 u64 a =3D of_read_number(addr, na);
>> - =A0 =A0 memset(addr, 0, na * 4);
>> - =A0 =A0 a +=3D offset;
>> - =A0 =A0 if (na > 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 addr[na - 2] =3D a >> 32;
>> - =A0 =A0 addr[na - 1] =3D a & 0xffffffffu;
>> -
>> - =A0 =A0 return 0;
>> -}
>> -
>> -static unsigned int of_bus_default_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 return IORESOURCE_MEM;
>> -}
>> -
>> =A0#ifdef CONFIG_PCI
>> -/*
>> - * PCI bus specific translator
>> - */
>> -
>> -static int of_bus_pci_match(struct device_node *np)
>> -{
>> - =A0 =A0 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
>> - =A0 =A0 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
>> -}
>> -
>> -static void of_bus_pci_count_cells(struct device_node *np,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int *addrc, in=
t *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 3;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 2;
>> -}
>> -
>> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((addr[0] ^ range[0]) & 0x03000000)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 pr_debug("OF: PCI map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"=
\n", cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 switch ((w >> 24) & 0x03) {
>> - =A0 =A0 case 0x01:
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 case 0x02: /* 32 bits */
>> - =A0 =A0 case 0x03: /* 64 bits */
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (w & 0x40000000)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_PREFETCH;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 =
*size,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 if (strcmp(bus->name, "pci")) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 }
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if ((prop[0] & 0xff) =3D=3D ((bar_no * 4) + PC=
I_BASE_ADDRESS_0)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_pci_address);
>> -
>> -int of_pci_address_to_resource(struct device_node *dev, int bar,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct resourc=
e *r)
>> -{
>> - =A0 =A0 const u32 =A0 =A0 =A0 *addrp;
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 size;
>> - =A0 =A0 unsigned int =A0 =A0flags;
>> -
>> - =A0 =A0 addrp =3D of_get_pci_address(dev, bar, &size, &flags);
>> - =A0 =A0 if (addrp =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
>> - =A0 =A0 return __of_address_to_resource(dev, addrp, size, flags, r);
>> -}
>> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
>> -
>> -static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
>> -{
>> - =A0 =A0 return (((pin - 1) + slot) % 4) + 1;
>> -}
>> -
>> =A0int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>> =A0{
>> =A0 =A0 =A0 struct device_node *dn, *ppnode;
>> @@ -291,289 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_=
irq *out_irq)
>> =A0EXPORT_SYMBOL_GPL(of_irq_map_pci);
>> =A0#endif /* CONFIG_PCI */
>>
>> -/*
>> - * ISA bus specific translator
>> - */
>> -
>> -static int of_bus_isa_match(struct device_node *np)
>> -{
>> - =A0 =A0 return !strcmp(np->name, "isa");
>> -}
>> -
>> -static void of_bus_isa_count_cells(struct device_node *child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int *addrc, in=
t *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 2;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 1;
>> -}
>> -
>> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((addr[0] ^ range[0]) & 0x00000001)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 pr_debug("OF: ISA map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"=
\n", cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 if (w & 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 else
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -/*
>> - * Array of bus specific translators
>> - */
>> -
>> -static struct of_bus of_busses[] =3D {
>> -#ifdef CONFIG_PCI
>> - =A0 =A0 /* PCI */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "pci",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "assigned-addresses",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_pci_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_pci_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_pci_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_pci_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_pci_get_flags,
>> - =A0 =A0 },
>> -#endif /* CONFIG_PCI */
>> - =A0 =A0 /* ISA */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "isa",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_isa_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_isa_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_isa_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_isa_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_isa_get_flags,
>> - =A0 =A0 },
>> - =A0 =A0 /* Default */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "default",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D NULL,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_default_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_default_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_default_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_default_get_flags,
>> - =A0 =A0 },
>> -};
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np)
>> -{
>> - =A0 =A0 int i;
>> -
>> - =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(of_busses); i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!of_busses[i].match || of_busses[i].match(=
np))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &of_busses[i];
>> - =A0 =A0 BUG();
>> - =A0 =A0 return NULL;
>> -}
>> -
>> -static int of_translate_one(struct device_node *parent, struct of_bus *=
bus,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct of_bus *pbus, u32 *addr=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> -{
>> - =A0 =A0 const u32 *ranges;
>> - =A0 =A0 unsigned int rlen;
>> - =A0 =A0 int rone;
>> - =A0 =A0 u64 offset =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Normally, an absence of a "ranges" property means we are
>> - =A0 =A0 =A0* crossing a non-translatable boundary, and thus the addres=
ses
>> - =A0 =A0 =A0* below the current not cannot be converted to CPU physical=
ones.
>> - =A0 =A0 =A0* Unfortunately, while this is very clear in the spec, it's=
not
>> - =A0 =A0 =A0* what Apple understood, and they do have things like /uni-=
n or
>> - =A0 =A0 =A0* /ht nodes with no "ranges" property and a lot of perfectl=
y
>> - =A0 =A0 =A0* useable mapped devices below them. Thus we treat the abse=
nce of
>> - =A0 =A0 =A0* "ranges" as equivalent to an empty "ranges" property whic=
h means
>> - =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller no=
t to try
>> - =A0 =A0 =A0* to translate addresses that aren't supposed to be transla=
ted in
>> - =A0 =A0 =A0* the first place. --BenH.
>> - =A0 =A0 =A0*/
>> - =A0 =A0 ranges =3D of_get_property(parent, "ranges", (int *) &rlen);
>> - =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: no ranges, 1:1 translation\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> - =A0 =A0 }
>> -
>> - =A0 =A0 pr_debug("OF: walking ranges...\n");
>> -
>> - =A0 =A0 /* Now walk through the ranges */
>> - =A0 =A0 rlen /=3D 4;
>> - =A0 =A0 rone =3D na + pna + ns;
>> - =A0 =A0 for (; rlen >=3D rone; rlen -=3D rone, ranges +=3D rone) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D bus->map(addr, ranges, na, ns, pna)=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (offset !=3D OF_BAD_ADDR)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (offset =3D=3D OF_BAD_ADDR) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: not found !\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, ranges + na, 4 * pna);
>> -
>> - finish:
>> - =A0 =A0 of_dump_addr("OF: parent translation for:", addr, pna);
>> - =A0 =A0 pr_debug("OF: with offset: "PRu64"\n", offset);
>> -
>> - =A0 =A0 /* Translate it into parent bus space */
>> - =A0 =A0 return pbus->translate(addr, offset, pna);
>> -}
>> -
>> -/*
>> - * Translate an address from the device-tree into a CPU physical addres=
s,
>> - * this walks up the tree and applies the various bus mappings on the
>> - * way.
>> - *
>> - * Note: We consider that crossing any level with #size-cells =3D=3D 0 =
to mean
>> - * that translation is impossible (that is we are not dealing with a va=
lue
>> - * that can be mapped to a cpu physical address). This is not really sp=
ecified
>> - * that way, but this is traditionally the way IBM at least do things
>> - */
>> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
>> -{
>> - =A0 =A0 struct device_node *parent =3D NULL;
>> - =A0 =A0 struct of_bus *bus, *pbus;
>> - =A0 =A0 u32 addr[OF_MAX_ADDR_CELLS];
>> - =A0 =A0 int na, ns, pna, pns;
>> - =A0 =A0 u64 result =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 pr_debug("OF: ** translation for device %s **\n", dev->full_na=
me);
>> -
>> - =A0 =A0 /* Increase refcount at current level */
>> - =A0 =A0 of_node_get(dev);
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> -
>> - =A0 =A0 /* Cound address cells & copy address locally */
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: Bad cell count fo=
r %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev->full_name);
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, in_addr, na * 4);
>> -
>> - =A0 =A0 pr_debug("OF: bus is %s (na=3D%d, ns=3D%d) on %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 bus->name, na, ns, parent->full_name);
>> - =A0 =A0 of_dump_addr("OF: translating address:", addr, na);
>> -
>> - =A0 =A0 /* Translate */
>> - =A0 =A0 for (;;) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Switch to parent bus */
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dev);
>> - =A0 =A0 =A0 =A0 =A0 =A0 dev =3D parent;
>> - =A0 =A0 =A0 =A0 =A0 =A0 parent =3D of_get_parent(dev);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* If root, we have finished */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (parent =3D=3D NULL) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: reached root nod=
e\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 result =3D of_read_number(addr=
, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Get new parent bus and counts */
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus =3D of_match_bus(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus->count_cells(dev, &pna, &pns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!OF_CHECK_COUNTS(pna, pns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: B=
ad cell count for %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev->full_name=
);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: parent bus is %s (na=3D%d, ns=3D=
%d) on %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pbus->name, pna, pns, parent->=
full_name);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Apply bus translation */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (of_translate_one(dev, bus, pbus, addr, na,=
ns, pna))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Complete the move up one level */
>> - =A0 =A0 =A0 =A0 =A0 =A0 na =3D pna;
>> - =A0 =A0 =A0 =A0 =A0 =A0 ns =3D pns;
>> - =A0 =A0 =A0 =A0 =A0 =A0 bus =3D pbus;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_dump_addr("OF: one level translation:", add=
r, na);
>> - =A0 =A0 }
>> - bail:
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 of_node_put(dev);
>> -
>> - =A0 =A0 return result;
>> -}
>> -EXPORT_SYMBOL(of_translate_address);
>> -
>> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, (int *) &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D index) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_address);
>> -
>> =A0void of_parse_dma_window(struct device_node *dn, const void *dma_wind=
ow_prop,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned long *busno, unsigned long *phys, u=
nsigned long *size)
>> =A0{
>> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/=
prom.h
>> index e1c1bdd..8e1d0fe 100644
>> --- a/arch/powerpc/include/asm/prom.h
>> +++ b/arch/powerpc/include/asm/prom.h
>> @@ -45,10 +45,6 @@ extern void pci_create_OF_bus_map(void);
>> =A0 * OF address retreival & translation
>> =A0 */
>>
>> -/* Translate an OF address block into a CPU physical address
>> - */
>> -extern u64 of_translate_address(struct device_node *np, const u32 *addr=
);
>> -
>> =A0/* Translate a DMA address from device space to CPU space */
>> =A0extern u64 of_translate_dma_address(struct device_node *dev,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cons=
t u32 *in_addr);
>> diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom=
_parse.c
>> index a2ef129..64f2606 100644
>> --- a/arch/powerpc/kernel/prom_parse.c
>> +++ b/arch/powerpc/kernel/prom_parse.c
>> @@ -10,225 +10,7 @@
>> =A0#include <asm/prom.h>
>> =A0#include <asm/pci-bridge.h>
>>
>> -#ifdef DEBUG
>> -#define DBG(fmt...) do { printk(fmt); } while(0)
>> -#else
>> -#define DBG(fmt...) do { } while(0)
>> -#endif
>> -
>> -#ifdef CONFIG_PPC64
>> -#define PRu64 =A0 =A0 =A0 =A0"%lx"
>> -#else
>> -#define PRu64 =A0 =A0 =A0 =A0"%llx"
>> -#endif
>> -
>> -/* Max address size we deal with */
>> -#define OF_MAX_ADDR_CELLS =A0 =A04
>> -#define OF_CHECK_COUNTS(na, ns) =A0 =A0 =A0((na) > 0 && (na) <=3D OF_MA=
X_ADDR_CELLS && \
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (ns) > 0)
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np);
>> -
>> -/* Debug utility */
>> -#ifdef DEBUG
>> -static void of_dump_addr(const char *s, const u32 *addr, int na)
>> -{
>> - =A0 =A0 printk("%s", s);
>> - =A0 =A0 while(na--)
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(" %08x", *(addr++));
>> - =A0 =A0 printk("\n");
>> -}
>> -#else
>> -static void of_dump_addr(const char *s, const u32 *addr, int na) { }
>> -#endif
>> -
>> -
>> -/* Callbacks for bus specific translators */
>> -struct of_bus {
>> - =A0 =A0 const char =A0 =A0 =A0*name;
>> - =A0 =A0 const char =A0 =A0 =A0*addresses;
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*match)(struct device_node *paren=
t);
>> - =A0 =A0 void =A0 =A0 =A0 =A0 =A0 =A0(*count_cells)(struct device_node =
*child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec);
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 (*map)(u32 *addr, const u32 *range=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns=
, int pna);
>> - =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*translate)(u32 *addr, u64 offset=
, int na);
>> - =A0 =A0 unsigned int =A0 =A0(*get_flags)(const u32 *addr);
>> -};
>> -
>> -
>> -/*
>> - * Default translator (generic bus)
>> - */
>> -
>> -static void of_bus_default_count_cells(struct device_node *dev,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D of_n_addr_cells(dev);
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D of_n_size_cells(dev);
>> -}
>> -
>> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
>> - =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 cp =3D of_read_number(range, na);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr, na);
>> -
>> - =A0 =A0 DBG("OF: default map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"\=
n",
>> - =A0 =A0 =A0 =A0 cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 u64 a =3D of_read_number(addr, na);
>> - =A0 =A0 memset(addr, 0, na * 4);
>> - =A0 =A0 a +=3D offset;
>> - =A0 =A0 if (na > 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 addr[na - 2] =3D a >> 32;
>> - =A0 =A0 addr[na - 1] =3D a & 0xffffffffu;
>> -
>> - =A0 =A0 return 0;
>> -}
>> -
>> -static unsigned int of_bus_default_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 return IORESOURCE_MEM;
>> -}
>> -
>> -
>> =A0#ifdef CONFIG_PCI
>> -/*
>> - * PCI bus specific translator
>> - */
>> -
>> -static int of_bus_pci_match(struct device_node *np)
>> -{
>> - =A0 =A0 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
>> - =A0 =A0 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
>> -}
>> -
>> -static void of_bus_pci_count_cells(struct device_node *np,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 3;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 2;
>> -}
>> -
>> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 switch((w >> 24) & 0x03) {
>> - =A0 =A0 case 0x01:
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 case 0x02: /* 32 bits */
>> - =A0 =A0 case 0x03: /* 64 bits */
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (w & 0x40000000)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_PREFETCH;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> - =A0 =A0 unsigned int af, rf;
>> -
>> - =A0 =A0 af =3D of_bus_pci_get_flags(addr);
>> - =A0 =A0 rf =3D of_bus_pci_get_flags(range);
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 DBG("OF: PCI map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"\n", =
cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 =
*size,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 if (strcmp(bus->name, "pci")) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 }
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if ((prop[0] & 0xff) =3D=3D ((bar_no * 4) + PC=
I_BASE_ADDRESS_0)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_pci_address);
>> -
>> -int of_pci_address_to_resource(struct device_node *dev, int bar,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct resource=
*r)
>> -{
>> - =A0 =A0 const u32 =A0 =A0 =A0 *addrp;
>> - =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 size;
>> - =A0 =A0 unsigned int =A0 =A0flags;
>> -
>> - =A0 =A0 addrp =3D of_get_pci_address(dev, bar, &size, &flags);
>> - =A0 =A0 if (addrp =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
>> - =A0 =A0 return __of_address_to_resource(dev, addrp, size, flags, r);
>> -}
>> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
>> -
>> =A0int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>> =A0{
>> =A0 =A0 =A0 struct device_node *dn, *ppnode;
>> @@ -310,303 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_=
irq *out_irq)
>> =A0EXPORT_SYMBOL_GPL(of_irq_map_pci);
>> =A0#endif /* CONFIG_PCI */
>>
>> -/*
>> - * ISA bus specific translator
>> - */
>> -
>> -static int of_bus_isa_match(struct device_node *np)
>> -{
>> - =A0 =A0 return !strcmp(np->name, "isa");
>> -}
>> -
>> -static void of_bus_isa_count_cells(struct device_node *child,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> -{
>> - =A0 =A0 if (addrc)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 2;
>> - =A0 =A0 if (sizec)
>> - =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 1;
>> -}
>> -
>> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> -{
>> - =A0 =A0 u64 cp, s, da;
>> -
>> - =A0 =A0 /* Check address type match */
>> - =A0 =A0 if ((addr[0] ^ range[0]) & 0x00000001)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Read address values, skipping high cell */
>> - =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> - =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> - =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> -
>> - =A0 =A0 DBG("OF: ISA map, cp=3D"PRu64", s=3D"PRu64", da=3D"PRu64"\n", =
cp, s, da);
>> -
>> - =A0 =A0 if (da < cp || da >=3D (cp + s))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> - =A0 =A0 return da - cp;
>> -}
>> -
>> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
>> -{
>> - =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> -}
>> -
>> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
>> -{
>> - =A0 =A0 unsigned int flags =3D 0;
>> - =A0 =A0 u32 w =3D addr[0];
>> -
>> - =A0 =A0 if (w & 1)
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> - =A0 =A0 else
>> - =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> - =A0 =A0 return flags;
>> -}
>> -
>> -
>> -/*
>> - * Array of bus specific translators
>> - */
>> -
>> -static struct of_bus of_busses[] =3D {
>> -#ifdef CONFIG_PCI
>> - =A0 =A0 /* PCI */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "pci",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "assigned-addresses",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_pci_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_pci_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_pci_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_pci_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_pci_get_flags,
>> - =A0 =A0 },
>> -#endif /* CONFIG_PCI */
>> - =A0 =A0 /* ISA */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "isa",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_isa_match,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_isa_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_isa_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_isa_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_isa_get_flags,
>> - =A0 =A0 },
>> - =A0 =A0 /* Default */
>> - =A0 =A0 {
>> - =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "default",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> - =A0 =A0 =A0 =A0 =A0 =A0 .match =3D NULL,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_default_count_cells,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_default_map,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_default_translate,
>> - =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_default_get_flags,
>> - =A0 =A0 },
>> -};
>> -
>> -static struct of_bus *of_match_bus(struct device_node *np)
>> -{
>> - =A0 =A0 int i;
>> -
>> - =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(of_busses); i ++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!of_busses[i].match || of_busses[i].match(=
np))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &of_busses[i];
>> - =A0 =A0 BUG();
>> - =A0 =A0 return NULL;
>> -}
>> -
>> -static int of_translate_one(struct device_node *parent, struct of_bus *=
bus,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct of_bus *pbus, u=
32 *addr,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pn=
a, const char *rprop)
>> -{
>> - =A0 =A0 const u32 *ranges;
>> - =A0 =A0 unsigned int rlen;
>> - =A0 =A0 int rone;
>> - =A0 =A0 u64 offset =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 /* Normally, an absence of a "ranges" property means we are
>> - =A0 =A0 =A0* crossing a non-translatable boundary, and thus the addres=
ses
>> - =A0 =A0 =A0* below the current not cannot be converted to CPU physical=
ones.
>> - =A0 =A0 =A0* Unfortunately, while this is very clear in the spec, it's=
not
>> - =A0 =A0 =A0* what Apple understood, and they do have things like /uni-=
n or
>> - =A0 =A0 =A0* /ht nodes with no "ranges" property and a lot of perfectl=
y
>> - =A0 =A0 =A0* useable mapped devices below them. Thus we treat the abse=
nce of
>> - =A0 =A0 =A0* "ranges" as equivalent to an empty "ranges" property whic=
h means
>> - =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller no=
t to try
>> - =A0 =A0 =A0* to translate addresses that aren't supposed to be transla=
ted in
>> - =A0 =A0 =A0* the first place. --BenH.
>> - =A0 =A0 =A0*/
>> - =A0 =A0 ranges =3D of_get_property(parent, rprop, &rlen);
>> - =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> - =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: no ranges, 1:1 translation\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> - =A0 =A0 }
>> -
>> - =A0 =A0 DBG("OF: walking ranges...\n");
>> -
>> - =A0 =A0 /* Now walk through the ranges */
>> - =A0 =A0 rlen /=3D 4;
>> - =A0 =A0 rone =3D na + pna + ns;
>> - =A0 =A0 for (; rlen >=3D rone; rlen -=3D rone, ranges +=3D rone) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 offset =3D bus->map(addr, ranges, na, ns, pna)=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (offset !=3D OF_BAD_ADDR)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 }
>> - =A0 =A0 if (offset =3D=3D OF_BAD_ADDR) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: not found !\n");
>> - =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, ranges + na, 4 * pna);
>> -
>> - finish:
>> - =A0 =A0 of_dump_addr("OF: parent translation for:", addr, pna);
>> - =A0 =A0 DBG("OF: with offset: "PRu64"\n", offset);
>> -
>> - =A0 =A0 /* Translate it into parent bus space */
>> - =A0 =A0 return pbus->translate(addr, offset, pna);
>> -}
>> -
>> -
>> -/*
>> - * Translate an address from the device-tree into a CPU physical addres=
s,
>> - * this walks up the tree and applies the various bus mappings on the
>> - * way.
>> - *
>> - * Note: We consider that crossing any level with #size-cells =3D=3D 0 =
to mean
>> - * that translation is impossible (that is we are not dealing with a va=
lue
>> - * that can be mapped to a cpu physical address). This is not really sp=
ecified
>> - * that way, but this is traditionally the way IBM at least do things
>> - */
>> -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *rprop)
>> -{
>> - =A0 =A0 struct device_node *parent =3D NULL;
>> - =A0 =A0 struct of_bus *bus, *pbus;
>> - =A0 =A0 u32 addr[OF_MAX_ADDR_CELLS];
>> - =A0 =A0 int na, ns, pna, pns;
>> - =A0 =A0 u64 result =3D OF_BAD_ADDR;
>> -
>> - =A0 =A0 DBG("OF: ** translation for device %s **\n", dev->full_name);
>> -
>> - =A0 =A0 /* Increase refcount at current level */
>> - =A0 =A0 of_node_get(dev);
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> -
>> - =A0 =A0 /* Cound address cells & copy address locally */
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: Bad cell count fo=
r %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name);
>> - =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> - =A0 =A0 }
>> - =A0 =A0 memcpy(addr, in_addr, na * 4);
>> -
>> - =A0 =A0 DBG("OF: bus is %s (na=3D%d, ns=3D%d) on %s\n",
>> - =A0 =A0 =A0 =A0 bus->name, na, ns, parent->full_name);
>> - =A0 =A0 of_dump_addr("OF: translating address:", addr, na);
>> -
>> - =A0 =A0 /* Translate */
>> - =A0 =A0 for (;;) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Switch to parent bus */
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dev);
>> - =A0 =A0 =A0 =A0 =A0 =A0 dev =3D parent;
>> - =A0 =A0 =A0 =A0 =A0 =A0 parent =3D of_get_parent(dev);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* If root, we have finished */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (parent =3D=3D NULL) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: reached root node\n")=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 result =3D of_read_number(addr=
, na);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Get new parent bus and counts */
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus =3D of_match_bus(parent);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pbus->count_cells(dev, &pna, &pns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (!OF_CHECK_COUNTS(pna, pns)) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: B=
ad cell count for %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name)=
;
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 DBG("OF: parent bus is %s (na=3D%d, ns=3D%d) o=
n %s\n",
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pbus->name, pna, pns, parent->full_nam=
e);
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Apply bus translation */
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (of_translate_one(dev, bus, pbus, addr, na,=
ns, pna, rprop))
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 /* Complete the move up one level */
>> - =A0 =A0 =A0 =A0 =A0 =A0 na =3D pna;
>> - =A0 =A0 =A0 =A0 =A0 =A0 ns =3D pns;
>> - =A0 =A0 =A0 =A0 =A0 =A0 bus =3D pbus;
>> -
>> - =A0 =A0 =A0 =A0 =A0 =A0 of_dump_addr("OF: one level translation:", add=
r, na);
>> - =A0 =A0 }
>> - bail:
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 of_node_put(dev);
>> -
>> - =A0 =A0 return result;
>> -}
>> -
>> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
>> -{
>> - =A0 =A0 return __of_translate_address(dev, in_addr, "ranges");
>> -}
>> -EXPORT_SYMBOL(of_translate_address);
>> -
>> -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_add=
r)
>> -{
>> - =A0 =A0 return __of_translate_address(dev, in_addr, "dma-ranges");
>> -}
>> -EXPORT_SYMBOL(of_translate_dma_address);
>> -
>> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size=
,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> -{
>> - =A0 =A0 const u32 *prop;
>> - =A0 =A0 unsigned int psize;
>> - =A0 =A0 struct device_node *parent;
>> - =A0 =A0 struct of_bus *bus;
>> - =A0 =A0 int onesize, i, na, ns;
>> -
>> - =A0 =A0 /* Get parent & match bus type */
>> - =A0 =A0 parent =3D of_get_parent(dev);
>> - =A0 =A0 if (parent =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 bus =3D of_match_bus(parent);
>> - =A0 =A0 bus->count_cells(dev, &na, &ns);
>> - =A0 =A0 of_node_put(parent);
>> - =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> - =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> - =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> - =A0 =A0 if (prop =3D=3D NULL)
>> - =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> - =A0 =A0 psize /=3D 4;
>> -
>> - =A0 =A0 onesize =3D na + ns;
>> - =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> - =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D index) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> - =A0 =A0 =A0 =A0 =A0 =A0 }
>> - =A0 =A0 return NULL;
>> -}
>> -EXPORT_SYMBOL(of_get_address);
>> -
>> =A0void of_parse_dma_window(struct device_node *dn, const void *dma_wind=
ow_prop,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned long *busno, unsigned long *phys, u=
nsigned long *size)
>> =A0{
>> diff --git a/drivers/of/address.c b/drivers/of/address.c
>> index c381955..2a905d5 100644
>> --- a/drivers/of/address.c
>> +++ b/drivers/of/address.c
>> @@ -1,11 +1,522 @@
>>
>> =A0#include <linux/io.h>
>> =A0#include <linux/ioport.h>
>> +#include <linux/module.h>
>> =A0#include <linux/of_address.h>
>> +#include <linux/pci_regs.h>
>> +#include <linux/string.h>
>>
>> -int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u64 size, unsigned =
int flags,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct resource *r)
>> +/* Max address size we deal with */
>> +#define OF_MAX_ADDR_CELLS =A0 =A04
>> +#define OF_CHECK_COUNTS(na, ns) =A0 =A0 =A0((na) > 0 && (na) <=3D OF_MA=
X_ADDR_CELLS && \
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (ns) > 0)
>> +
>> +static struct of_bus *of_match_bus(struct device_node *np);
>> +static int __of_address_to_resource(struct device_node *dev, const u32 =
*addrp,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u64 si=
ze, unsigned int flags,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct=
resource *r);
>> +
>> +/* Debug utility */
>> +#ifdef DEBUG
>> +static void of_dump_addr(const char *s, const u32 *addr, int na)
>> +{
>> + =A0 =A0 printk(KERN_DEBUG "%s", s);
>> + =A0 =A0 while (na--)
>> + =A0 =A0 =A0 =A0 =A0 =A0 printk(" %08x", *(addr++));
>> + =A0 =A0 printk("\n");
>> +}
>> +#else
>> +static void of_dump_addr(const char *s, const u32 *addr, int na) { }
>> +#endif
>> +
>> +/* Callbacks for bus specific translators */
>> +struct of_bus {
>> + =A0 =A0 const char =A0 =A0 =A0*name;
>> + =A0 =A0 const char =A0 =A0 =A0*addresses;
>> + =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*match)(struct device_node *paren=
t);
>> + =A0 =A0 void =A0 =A0 =A0 =A0 =A0 =A0(*count_cells)(struct device_node =
*child,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec);
>> + =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 (*map)(u32 *addr, const u32 *range=
,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns=
, int pna);
>> + =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 (*translate)(u32 *addr, u64 offset=
, int na);
>> + =A0 =A0 unsigned int =A0 =A0(*get_flags)(const u32 *addr);
>> +};
>> +
>> +/*
>> + * Default translator (generic bus)
>> + */
>> +
>> +static void of_bus_default_count_cells(struct device_node *dev,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0int *addrc, int *sizec)
>> +{
>> + =A0 =A0 if (addrc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D of_n_addr_cells(dev);
>> + =A0 =A0 if (sizec)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D of_n_size_cells(dev);
>> +}
>> +
>> +static u64 of_bus_default_map(u32 *addr, const u32 *range,
>> + =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pna)
>> +{
>> + =A0 =A0 u64 cp, s, da;
>> +
>> + =A0 =A0 cp =3D of_read_number(range, na);
>> + =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> + =A0 =A0 da =3D of_read_number(addr, na);
>> +
>> + =A0 =A0 pr_debug("OF: default map, cp=3D%llx, s=3D%llx, da=3D%llx\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)cp, (unsigned long long=
)s,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)da);
>> +
>> + =A0 =A0 if (da < cp || da >=3D (cp + s))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> + =A0 =A0 return da - cp;
>> +}
>> +
>> +static int of_bus_default_translate(u32 *addr, u64 offset, int na)
>> +{
>> + =A0 =A0 u64 a =3D of_read_number(addr, na);
>> + =A0 =A0 memset(addr, 0, na * 4);
>> + =A0 =A0 a +=3D offset;
>> + =A0 =A0 if (na > 1)
>> + =A0 =A0 =A0 =A0 =A0 =A0 addr[na - 2] =3D a >> 32;
>> + =A0 =A0 addr[na - 1] =3D a & 0xffffffffu;
>> +
>> + =A0 =A0 return 0;
>> +}
>> +
>> +static unsigned int of_bus_default_get_flags(const u32 *addr)
>> +{
>> + =A0 =A0 return IORESOURCE_MEM;
>> +}
>> +
>> +#ifdef CONFIG_PCI
>> +/*
>> + * PCI bus specific translator
>> + */
>> +
>> +static int of_bus_pci_match(struct device_node *np)
>> +{
>> + =A0 =A0 /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
>> + =A0 =A0 return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
>> +}
>> +
>> +static void of_bus_pci_count_cells(struct device_node *np,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> +{
>> + =A0 =A0 if (addrc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 3;
>> + =A0 =A0 if (sizec)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 2;
>> +}
>> +
>> +static unsigned int of_bus_pci_get_flags(const u32 *addr)
>> +{
>> + =A0 =A0 unsigned int flags =3D 0;
>> + =A0 =A0 u32 w =3D addr[0];
>> +
>> + =A0 =A0 switch((w >> 24) & 0x03) {
>> + =A0 =A0 case 0x01:
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 case 0x02: /* 32 bits */
>> + =A0 =A0 case 0x03: /* 64 bits */
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 }
>> + =A0 =A0 if (w & 0x40000000)
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_PREFETCH;
>> + =A0 =A0 return flags;
>> +}
>> +
>> +static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> +{
>> + =A0 =A0 u64 cp, s, da;
>> + =A0 =A0 unsigned int af, rf;
>> +
>> + =A0 =A0 af =3D of_bus_pci_get_flags(addr);
>> + =A0 =A0 rf =3D of_bus_pci_get_flags(range);
>> +
>> + =A0 =A0 /* Check address type match */
>> + =A0 =A0 if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> +
>> + =A0 =A0 /* Read address values, skipping high cell */
>> + =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> + =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> + =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> +
>> + =A0 =A0 pr_debug("OF: PCI map, cp=3D%llx, s=3D%llx, da=3D%llx\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)cp, (unsigned long long=
)s,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)da);
>> +
>> + =A0 =A0 if (da < cp || da >=3D (cp + s))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> + =A0 =A0 return da - cp;
>> +}
>> +
>> +static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
>> +{
>> + =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> +}
>> +
>> +const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 =
*size,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> +{
>> + =A0 =A0 const u32 *prop;
>> + =A0 =A0 unsigned int psize;
>> + =A0 =A0 struct device_node *parent;
>> + =A0 =A0 struct of_bus *bus;
>> + =A0 =A0 int onesize, i, na, ns;
>> +
>> + =A0 =A0 /* Get parent & match bus type */
>> + =A0 =A0 parent =3D of_get_parent(dev);
>> + =A0 =A0 if (parent =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 bus =3D of_match_bus(parent);
>> + =A0 =A0 if (strcmp(bus->name, "pci")) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(parent);
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 }
>> + =A0 =A0 bus->count_cells(dev, &na, &ns);
>> + =A0 =A0 of_node_put(parent);
>> + =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> +
>> + =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> + =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> + =A0 =A0 if (prop =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 psize /=3D 4;
>> +
>> + =A0 =A0 onesize =3D na + ns;
>> + =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if ((prop[0] & 0xff) =3D=3D ((bar_no * 4) + PC=
I_BASE_ADDRESS_0)) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> + =A0 =A0 return NULL;
>> +}
>> +EXPORT_SYMBOL(of_get_pci_address);
>> +
>> +int of_pci_address_to_resource(struct device_node *dev, int bar,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct resource=
*r)
>> +{
>> + =A0 =A0 const u32 =A0 =A0 =A0 *addrp;
>> + =A0 =A0 u64 =A0 =A0 =A0 =A0 =A0 =A0 size;
>> + =A0 =A0 unsigned int =A0 =A0flags;
>> +
>> + =A0 =A0 addrp =3D of_get_pci_address(dev, bar, &size, &flags);
>> + =A0 =A0 if (addrp =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
>> + =A0 =A0 return __of_address_to_resource(dev, addrp, size, flags, r);
>> +}
>> +EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
>> +#endif /* CONFIG_PCI */
>> +
>> +/*
>> + * ISA bus specific translator
>> + */
>> +
>> +static int of_bus_isa_match(struct device_node *np)
>> +{
>> + =A0 =A0 return !strcmp(np->name, "isa");
>> +}
>> +
>> +static void of_bus_isa_count_cells(struct device_node *child,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int *ad=
drc, int *sizec)
>> +{
>> + =A0 =A0 if (addrc)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *addrc =3D 2;
>> + =A0 =A0 if (sizec)
>> + =A0 =A0 =A0 =A0 =A0 =A0 *sizec =3D 1;
>> +}
>> +
>> +static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, =
int pna)
>> +{
>> + =A0 =A0 u64 cp, s, da;
>> +
>> + =A0 =A0 /* Check address type match */
>> + =A0 =A0 if ((addr[0] ^ range[0]) & 0x00000001)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> +
>> + =A0 =A0 /* Read address values, skipping high cell */
>> + =A0 =A0 cp =3D of_read_number(range + 1, na - 1);
>> + =A0 =A0 s =A0=3D of_read_number(range + na + pna, ns);
>> + =A0 =A0 da =3D of_read_number(addr + 1, na - 1);
>> +
>> + =A0 =A0 pr_debug("OF: ISA map, cp=3D%llx, s=3D%llx, da=3D%llx\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)cp, (unsigned long long=
)s,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0(unsigned long long)da);
>> +
>> + =A0 =A0 if (da < cp || da >=3D (cp + s))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return OF_BAD_ADDR;
>> + =A0 =A0 return da - cp;
>> +}
>> +
>> +static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
>> +{
>> + =A0 =A0 return of_bus_default_translate(addr + 1, offset, na - 1);
>> +}
>> +
>> +static unsigned int of_bus_isa_get_flags(const u32 *addr)
>> +{
>> + =A0 =A0 unsigned int flags =3D 0;
>> + =A0 =A0 u32 w =3D addr[0];
>> +
>> + =A0 =A0 if (w & 1)
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_IO;
>> + =A0 =A0 else
>> + =A0 =A0 =A0 =A0 =A0 =A0 flags |=3D IORESOURCE_MEM;
>> + =A0 =A0 return flags;
>> +}
>> +
>> +/*
>> + * Array of bus specific translators
>> + */
>> +
>> +static struct of_bus of_busses[] =3D {
>> +#ifdef CONFIG_PCI
>> + =A0 =A0 /* PCI */
>> + =A0 =A0 {
>> + =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "pci",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "assigned-addresses",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_pci_match,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_pci_count_cells,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_pci_map,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_pci_translate,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_pci_get_flags,
>> + =A0 =A0 },
>> +#endif /* CONFIG_PCI */
>> + =A0 =A0 /* ISA */
>> + =A0 =A0 {
>> + =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "isa",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .match =3D of_bus_isa_match,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_isa_count_cells,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_isa_map,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_isa_translate,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_isa_get_flags,
>> + =A0 =A0 },
>> + =A0 =A0 /* Default */
>> + =A0 =A0 {
>> + =A0 =A0 =A0 =A0 =A0 =A0 .name =3D "default",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .addresses =3D "reg",
>> + =A0 =A0 =A0 =A0 =A0 =A0 .match =3D NULL,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .count_cells =3D of_bus_default_count_cells,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .map =3D of_bus_default_map,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .translate =3D of_bus_default_translate,
>> + =A0 =A0 =A0 =A0 =A0 =A0 .get_flags =3D of_bus_default_get_flags,
>> + =A0 =A0 },
>> +};
>> +
>> +static struct of_bus *of_match_bus(struct device_node *np)
>> +{
>> + =A0 =A0 int i;
>> +
>> + =A0 =A0 for (i =3D 0; i < ARRAY_SIZE(of_busses); i++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (!of_busses[i].match || of_busses[i].match(=
np))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return &of_busses[i];
>> + =A0 =A0 BUG();
>> + =A0 =A0 return NULL;
>> +}
>> +
>> +static int of_translate_one(struct device_node *parent, struct of_bus *=
bus,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct of_bus *pbus, u=
32 *addr,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int na, int ns, int pn=
a, const char *rprop)
>> +{
>> + =A0 =A0 const u32 *ranges;
>> + =A0 =A0 unsigned int rlen;
>> + =A0 =A0 int rone;
>> + =A0 =A0 u64 offset =3D OF_BAD_ADDR;
>> +
>> + =A0 =A0 /* Normally, an absence of a "ranges" property means we are
>> + =A0 =A0 =A0* crossing a non-translatable boundary, and thus the addres=
ses
>> + =A0 =A0 =A0* below the current not cannot be converted to CPU physical=
ones.
>> + =A0 =A0 =A0* Unfortunately, while this is very clear in the spec, it's=
not
>> + =A0 =A0 =A0* what Apple understood, and they do have things like /uni-=
n or
>> + =A0 =A0 =A0* /ht nodes with no "ranges" property and a lot of perfectl=
y
>> + =A0 =A0 =A0* useable mapped devices below them. Thus we treat the abse=
nce of
>> + =A0 =A0 =A0* "ranges" as equivalent to an empty "ranges" property whic=
h means
>> + =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller no=
t to try
>> + =A0 =A0 =A0* to translate addresses that aren't supposed to be transla=
ted in
>> + =A0 =A0 =A0* the first place. --BenH.
>> + =A0 =A0 =A0*/
>> + =A0 =A0 ranges =3D of_get_property(parent, rprop, &rlen);
>> + =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> + =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: no ranges, 1:1 translation\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> + =A0 =A0 }
>> +
>> + =A0 =A0 pr_debug("OF: walking ranges...\n");
>> +
>> + =A0 =A0 /* Now walk through the ranges */
>> + =A0 =A0 rlen /=3D 4;
>> + =A0 =A0 rone =3D na + pna + ns;
>> + =A0 =A0 for (; rlen >=3D rone; rlen -=3D rone, ranges +=3D rone) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 offset =3D bus->map(addr, ranges, na, ns, pna)=
;
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (offset !=3D OF_BAD_ADDR)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 }
>> + =A0 =A0 if (offset =3D=3D OF_BAD_ADDR) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: not found !\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> + =A0 =A0 }
>> + =A0 =A0 memcpy(addr, ranges + na, 4 * pna);
>> +
>> + finish:
>> + =A0 =A0 of_dump_addr("OF: parent translation for:", addr, pna);
>> + =A0 =A0 pr_debug("OF: with offset: %llx\n", (unsigned long long)offset=
);
>> +
>> + =A0 =A0 /* Translate it into parent bus space */
>> + =A0 =A0 return pbus->translate(addr, offset, pna);
>> +}
>> +
>> +/*
>> + * Translate an address from the device-tree into a CPU physical addres=
s,
>> + * this walks up the tree and applies the various bus mappings on the
>> + * way.
>> + *
>> + * Note: We consider that crossing any level with #size-cells =3D=3D 0 =
to mean
>> + * that translation is impossible (that is we are not dealing with a va=
lue
>> + * that can be mapped to a cpu physical address). This is not really sp=
ecified
>> + * that way, but this is traditionally the way IBM at least do things
>> + */
>> +u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *rprop)
>> +{
>> + =A0 =A0 struct device_node *parent =3D NULL;
>> + =A0 =A0 struct of_bus *bus, *pbus;
>> + =A0 =A0 u32 addr[OF_MAX_ADDR_CELLS];
>> + =A0 =A0 int na, ns, pna, pns;
>> + =A0 =A0 u64 result =3D OF_BAD_ADDR;
>> +
>> + =A0 =A0 pr_debug("OF: ** translation for device %s **\n", dev->full_na=
me);
>> +
>> + =A0 =A0 /* Increase refcount at current level */
>> + =A0 =A0 of_node_get(dev);
>> +
>> + =A0 =A0 /* Get parent & match bus type */
>> + =A0 =A0 parent =3D of_get_parent(dev);
>> + =A0 =A0 if (parent =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> + =A0 =A0 bus =3D of_match_bus(parent);
>> +
>> + =A0 =A0 /* Cound address cells & copy address locally */
>> + =A0 =A0 bus->count_cells(dev, &na, &ns);
>> + =A0 =A0 if (!OF_CHECK_COUNTS(na, ns)) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: Bad cell count fo=
r %s\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name);
>> + =A0 =A0 =A0 =A0 =A0 =A0 goto bail;
>> + =A0 =A0 }
>> + =A0 =A0 memcpy(addr, in_addr, na * 4);
>> +
>> + =A0 =A0 pr_debug("OF: bus is %s (na=3D%d, ns=3D%d) on %s\n",
>> + =A0 =A0 =A0 =A0 bus->name, na, ns, parent->full_name);
>> + =A0 =A0 of_dump_addr("OF: translating address:", addr, na);
>> +
>> + =A0 =A0 /* Translate */
>> + =A0 =A0 for (;;) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Switch to parent bus */
>> + =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dev);
>> + =A0 =A0 =A0 =A0 =A0 =A0 dev =3D parent;
>> + =A0 =A0 =A0 =A0 =A0 =A0 parent =3D of_get_parent(dev);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* If root, we have finished */
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (parent =3D=3D NULL) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: reached root nod=
e\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 result =3D of_read_number(addr=
, na);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Get new parent bus and counts */
>> + =A0 =A0 =A0 =A0 =A0 =A0 pbus =3D of_match_bus(parent);
>> + =A0 =A0 =A0 =A0 =A0 =A0 pbus->count_cells(dev, &pna, &pns);
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (!OF_CHECK_COUNTS(pna, pns)) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "prom_parse: B=
ad cell count for %s\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev->full_name)=
;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: parent bus is %s (na=3D%d, ns=3D=
%d) on %s\n",
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pbus->name, pna, pns, parent->full_nam=
e);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Apply bus translation */
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (of_translate_one(dev, bus, pbus, addr, na,=
ns, pna, rprop))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 /* Complete the move up one level */
>> + =A0 =A0 =A0 =A0 =A0 =A0 na =3D pna;
>> + =A0 =A0 =A0 =A0 =A0 =A0 ns =3D pns;
>> + =A0 =A0 =A0 =A0 =A0 =A0 bus =3D pbus;
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 of_dump_addr("OF: one level translation:", add=
r, na);
>> + =A0 =A0 }
>> + bail:
>> + =A0 =A0 of_node_put(parent);
>> + =A0 =A0 of_node_put(dev);
>> +
>> + =A0 =A0 return result;
>> +}
>> +
>> +u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
>> +{
>> + =A0 =A0 return __of_translate_address(dev, in_addr, "ranges");
>> +}
>> +EXPORT_SYMBOL(of_translate_address);
>> +
>> +u64 of_translate_dma_address(struct device_node *dev, const u32 *in_add=
r)
>> +{
>> + =A0 =A0 return __of_translate_address(dev, in_addr, "dma-ranges");
>> +}
>> +EXPORT_SYMBOL(of_translate_dma_address);
>> +
>> +const u32 *of_get_address(struct device_node *dev, int index, u64 *size=
,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int *flags)
>> +{
>> + =A0 =A0 const u32 *prop;
>> + =A0 =A0 unsigned int psize;
>> + =A0 =A0 struct device_node *parent;
>> + =A0 =A0 struct of_bus *bus;
>> + =A0 =A0 int onesize, i, na, ns;
>> +
>> + =A0 =A0 /* Get parent & match bus type */
>> + =A0 =A0 parent =3D of_get_parent(dev);
>> + =A0 =A0 if (parent =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 bus =3D of_match_bus(parent);
>> + =A0 =A0 bus->count_cells(dev, &na, &ns);
>> + =A0 =A0 of_node_put(parent);
>> + =A0 =A0 if (!OF_CHECK_COUNTS(na, ns))
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> +
>> + =A0 =A0 /* Get "reg" or "assigned-addresses" property */
>> + =A0 =A0 prop =3D of_get_property(dev, bus->addresses, &psize);
>> + =A0 =A0 if (prop =3D=3D NULL)
>> + =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> + =A0 =A0 psize /=3D 4;
>> +
>> + =A0 =A0 onesize =3D na + ns;
>> + =A0 =A0 for (i =3D 0; psize >=3D onesize; psize -=3D onesize, prop +=
=3D onesize, i++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 if (i =3D=3D index) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (size)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *size =3D of_r=
ead_number(prop + na, ns);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (flags)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *flags =3D bus=
->get_flags(prop);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return prop;
>> + =A0 =A0 =A0 =A0 =A0 =A0 }
>> + =A0 =A0 return NULL;
>> +}
>> +EXPORT_SYMBOL(of_get_address);
>> +
>> +static int __of_address_to_resource(struct device_node *dev, const u32 =
*addrp,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u64 si=
ze, unsigned int flags,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct=
resource *r)
>> =A0{
>> =A0 =A0 =A0 u64 taddr;
>>
>> diff --git a/include/linux/of_address.h b/include/linux/of_address.h
>> index 474b794..cc567df 100644
>> --- a/include/linux/of_address.h
>> +++ b/include/linux/of_address.h
>> @@ -3,9 +3,7 @@
>> =A0#include <linux/ioport.h>
>> =A0#include <linux/of.h>
>>
>> -extern int __of_address_to_resource(struct device_node *dev, const u32 =
*addrp,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 u64 si=
ze, unsigned int flags,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct=
resource *r);
>> +extern u64 of_translate_address(struct device_node *np, const u32 *addr=
);
>> =A0extern int of_address_to_resource(struct device_node *dev, int index,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct r=
esource *r);
>> =A0extern void __iomem *of_iomap(struct device_node *device, int index);
>
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 5/5] of/address: restrict 'no-ranges' kludge to powerpc
From: Grant Likely @ 2010-06-10 14:28 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Stephen Rothwell, devicetree-discuss, linuxppc-dev
In-Reply-To: <1276152275.1962.61.camel@pasglop>
On Thu, Jun 10, 2010 at 12:44 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
>> Certain Apple machines don't use the ranges property correctly, but the
>> workaround should not be applied on other architectures. =A0This patch
>> disables the workaround for non-powerpc architectures.
>
> I'm half tempted to add it to the quirk list (which should really be
> made generic) so I can disable it on more 'modern' powerpc as well.
In the mean time, are you okay with this version of the patch?
g.
>
> Cheers,
> Ben.
>
>> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
>> CC: Stephen Rothwell <sfr@canb.auug.org.au>
>> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> CC: linuxppc-dev@lists.ozlabs.org
>> CC: devicetree-discuss@lists.ozlabs.org
>> ---
>> =A0drivers/of/address.c | =A0 11 ++++++++++-
>> =A01 files changed, 10 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/of/address.c b/drivers/of/address.c
>> index 0b04137..5c220c3 100644
>> --- a/drivers/of/address.c
>> +++ b/drivers/of/address.c
>> @@ -346,12 +346,21 @@ static int of_translate_one(struct device_node *pa=
rent, struct of_bus *bus,
>> =A0 =A0 =A0 =A0* a 1:1 translation at that level. It's up to the caller =
not to try
>> =A0 =A0 =A0 =A0* to translate addresses that aren't supposed to be trans=
lated in
>> =A0 =A0 =A0 =A0* the first place. --BenH.
>> + =A0 =A0 =A0*
>> + =A0 =A0 =A0* As far as we know, this damage only exists on Apple machi=
nes, so
>> + =A0 =A0 =A0* This code is only enabled on powerpc. --gcl
>> =A0 =A0 =A0 =A0*/
>> =A0 =A0 =A0 ranges =3D of_get_property(parent, rprop, &rlen);
>> +#if !defined(CONFIG_PPC)
>> + =A0 =A0 if (ranges =3D=3D NULL) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_err("OF: no ranges; cannot translate\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 return 1;
>> + =A0 =A0 }
>> +#endif /* !defined(CONFIG_PPC) */
>> =A0 =A0 =A0 if (ranges =3D=3D NULL || rlen =3D=3D 0) {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 offset =3D of_read_number(addr, na);
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset(addr, 0, pna * 4);
>> - =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: no ranges, 1:1 translation\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("OF: empty ranges; 1:1 translation\n"=
);
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto finish;
>> =A0 =A0 =A0 }
>>
>
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Arnd Bergmann @ 2010-06-10 14:31 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <4C10EFE0.6030106@harris.com>
On Thursday 10 June 2010, Steven A. Falco wrote:
> I believe there is a bug in the way the ibm_newemac driver handles the
> SIOCGMIIREG (and SIOCSMIIREG) ioctl. The problem is that emac_ioctl
> is handed a "struct ifreq *rq" which contains a user-land pointer to
> an array of 16-bit integers.
Did you actually see a bug here, or just think that this could be
a problem?
> However, emac_ioctl directly accesses the data, which doesn't work.
> I added the following patch to copy the data in and out.
>
> Please note that this patch was tested in an older kernel (2.6.30)
> because that is what we are using on our custom hardware. I think
> this is still a problem in the current code, but I'd like reviewers
> to take a look, to be sure.
The ifreq structure passed into the ndo_ioctl function is in kernel
space, it gets copied there by net/core/dev.c:dev_ioctl().
emac_ioctl only accesses the data in that structure, so a copy_from_user
is wrong here as far as I can tell.
Arnd
^ permalink raw reply
* Re: [PATCH] [powerpc] do not expect executable permissions for in-tree shell scripts
From: Olaf Hering @ 2010-06-10 15:20 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, stable, Sean MacLennan
In-Reply-To: <1276151189.1962.47.camel@pasglop>
On Thu, Jun 10, Benjamin Herrenschmidt wrote:
> I still don't like it very much.. why not chmod'ing it +x instead ? :-)
I looked at a few other scripts in the source tree, they are called with
$(CONFIG_SHELL) <name>, or perl <name>, or awk <name> or even sh <name>.
So my change adds some sort of consistency and makes packaging more robust.
Olaf
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: M. Warner Losh @ 2010-06-10 15:13 UTC (permalink / raw)
To: grant.likely
Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev
In-Reply-To: <AANLkTilpUi1cazljWSFbzliY78RKyHUlvBshUD3NPHPv@mail.gmail.com>
In message: <AANLkTilpUi1cazljWSFbzliY78RKyHUlvBshUD3NPHPv@mail.gmail.com>
Grant Likely <grant.likely@secretlab.ca> writes:
: On Thu, Jun 10, 2010 at 12:17 AM, Benjamin Herrenschmidt
: <benh@kernel.crashing.org> wrote:
: >
: >> You just introduced an unnamed structure of device + resources,
: >> it isn't declared anywhere but in the code itself (either via
: >> &foo[1] or buf + sizeof(*foo)).
: >>
: >> You're not the only one who hacks (or at least have to
: >> understand) the OF stuff, so let's try keep this stuff
: >> readable?
: >>
: >> I told you several ways of how to improve the code (based on
: >> the ideas from drivers/base/, so the ideas aren't even mine,
: >> fwiw).
: >
: > I tend to agree with Anton here.
:
: The reason I'm confident doing it that way is that it is *not* a
: structure. There is no structure relationship between the resource
: table and the platform_device other than they are allocated with the
: same kzalloc() call. All the code that cares about that is contained
: within 4 lines of code. I'm resistant to using a structure because it
: is adds an additional 5-6 lines of code to add a structure that won't
: be used anywhere else, and is only 4 lines to begin with.
I tend to agree with Grant here. The idiom he's using is very wide
spread in the industry and works extremely well. It keeps the
ugliness confined to a couple of lines and is less ugly than the
alternatives for this design pattern. It is a little surprising when
you see the code the first time, granted, but I think its expressive
power trumps that small surprise.
Warner
^ permalink raw reply
* Re: [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Steven A. Falco @ 2010-06-10 15:27 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <201006101631.29591.arnd@arndb.de>
On 06/10/2010 10:31 AM, Arnd Bergmann wrote:
>
> On Thursday 10 June 2010, Steven A. Falco wrote:
>> I believe there is a bug in the way the ibm_newemac driver handles the
>> SIOCGMIIREG (and SIOCSMIIREG) ioctl. The problem is that emac_ioctl
>> is handed a "struct ifreq *rq" which contains a user-land pointer to
>> an array of 16-bit integers.
>
> Did you actually see a bug here, or just think that this could be
> a problem?
I did see a problem. I tried using the ioctl, and I didn't get the
correct result. I then added some printk in the driver, and saw that
garbage was being passed in the data array.
I added the copy_from/copy_to, and the ioctl started working.
>
>> However, emac_ioctl directly accesses the data, which doesn't work.
>> I added the following patch to copy the data in and out.
>>
>> Please note that this patch was tested in an older kernel (2.6.30)
>> because that is what we are using on our custom hardware. I think
>> this is still a problem in the current code, but I'd like reviewers
>> to take a look, to be sure.
>
> The ifreq structure passed into the ndo_ioctl function is in kernel
> space, it gets copied there by net/core/dev.c:dev_ioctl().
> emac_ioctl only accesses the data in that structure, so a copy_from_user
> is wrong here as far as I can tell.
net/core/dev.c:dev_ioctl() does a copy_from_user on the overall structure,
but the structure contains a union, one member of which is an embedded
pointer to an array. This pointer member is only used in the case of these
two ioctls. Other ioctls use different union members, which are not pointers.
As I understand it, the copy_from_user in dev_ioctl does not recursively
copy the array. In fact it could not do so, because the pointer to array
is only 4 bytes long, while the array itself is 8 bytes long - so it would
not fit. I.e., dev_ioctl would have to allocate storage, and do a second
copy_from_user to retrieve the array. It would have to clean up after the
emac_ioctl ran. And it would have to do this only for these specific
ioctl calls which use the array pointer in the union.
Also, the result has to be returned to the user in the same array, which
needs a copy_to_user of the array data, which is also not done in dev_ioctl.
So I think this second copy_from/copy_to needs to be done somewhere. I
added it in the emac_ioctl because that is where the command is fully
decoded. It also avoids the problem of allocating space for the copied
array. But other fixes are certainly possible as well, which is why I am
not sure I've hit on the "proper" fix.
Thanks very much for reviewing - please let me know if my explanation is
unclear, or if you see a better way to fix this problem.
Steve
>
> Arnd
--
A: Because it makes the logic of the discussion difficult to follow.
Q: Why shouldn't I top post?
A: No.
Q: Should I top post?
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-10 15:47 UTC (permalink / raw)
To: M. Warner Losh
Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev
In-Reply-To: <20100610.091357.513168276793712624.imp@bsdimp.com>
On Thu, Jun 10, 2010 at 09:13:57AM -0600, M. Warner Losh wrote:
[...]
> : >> I told you several ways of how to improve the code (based on
> : >> the ideas from drivers/base/, so the ideas aren't even mine,
> : >> fwiw).
> : >
> : > I tend to agree with Anton here.
> :
> : The reason I'm confident doing it that way is that it is *not* a
> : structure. There is no structure relationship between the resource
> : table and the platform_device other than they are allocated with the
> : same kzalloc() call. All the code that cares about that is contained
> : within 4 lines of code. I'm resistant to using a structure because it
> : is adds an additional 5-6 lines of code to add a structure that won't
> : be used anywhere else, and is only 4 lines to begin with.
>
> I tend to agree with Grant here. The idiom he's using is very wide
> spread in the industry and works extremely well. It keeps the
> ugliness confined to a couple of lines and is less ugly than the
> alternatives for this design pattern. It is a little surprising when
> you see the code the first time, granted, but I think its expressive
> power trumps that small surprise.
Oh, come on. Both constructions are binary equivalent.
So how can people seriously be with *that* code:
dev->resource = (void *)&dev[1];
which, semantically, is a nonsense and asks for a fix.
While
dev_obj->dev.resource = dev_obj->resource;
simply makes sense.
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: M. Warner Losh @ 2010-06-10 16:01 UTC (permalink / raw)
To: cbouatmailru
Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev
In-Reply-To: <20100610154741.GA7484@oksana.dev.rtsoft.ru>
In message: <20100610154741.GA7484@oksana.dev.rtsoft.ru>
Anton Vorontsov <cbouatmailru@gmail.com> writes:
: On Thu, Jun 10, 2010 at 09:13:57AM -0600, M. Warner Losh wrote:
: [...]
: > : >> I told you several ways of how to improve the code (based on
: > : >> the ideas from drivers/base/, so the ideas aren't even mine,
: > : >> fwiw).
: > : >
: > : > I tend to agree with Anton here.
: > :
: > : The reason I'm confident doing it that way is that it is *not* a
: > : structure. There is no structure relationship between the resource
: > : table and the platform_device other than they are allocated with the
: > : same kzalloc() call. All the code that cares about that is contained
: > : within 4 lines of code. I'm resistant to using a structure because it
: > : is adds an additional 5-6 lines of code to add a structure that won't
: > : be used anywhere else, and is only 4 lines to begin with.
: >
: > I tend to agree with Grant here. The idiom he's using is very wide
: > spread in the industry and works extremely well. It keeps the
: > ugliness confined to a couple of lines and is less ugly than the
: > alternatives for this design pattern. It is a little surprising when
: > you see the code the first time, granted, but I think its expressive
: > power trumps that small surprise.
:
: Oh, come on. Both constructions are binary equivalent.
:
: So how can people seriously be with *that* code:
:
: dev->resource = (void *)&dev[1];
:
: which, semantically, is a nonsense and asks for a fix.
It isn't nonsense. That's just your opinion of it, nothing more.
: While
: dev_obj->dev.resource = dev_obj->resource;
:
: simply makes sense.
But this requires extra, bogus fields in the structure and creates a
bogus sizeof issue.
There are problems both ways. Yelling about it isn't going to make
you any more right, or convince me that I'm wrong. It is an argument
that is at least two decades old...
Warner
^ permalink raw reply
* [PATCH V3] powerpc/mpc512x: Add gpio driver
From: Anatolij Gustschin @ 2010-06-10 16:05 UTC (permalink / raw)
To: linuxppc-dev
Cc: Anatolij Gustschin, Wolfgang Denk, Detlev Zundel, Matthias Fuchs
From: Matthias Fuchs <matthias.fuchs@esd.eu>
This patch adds a gpio driver for MPC512X PowerPCs.
It has been tested on our CAN-CBX-CPU5201 module that
uses a MPC5121 CPU. This platform comes with a couple of
LEDs and configuration switches that have been used for testing.
Signed-off-by: Matthias Fuchs <matthias.fuchs@esd.eu>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
Please consider this patch for inclusion in 2.6.36. Thanks!
v3: - rebase to apply on current mainline tree
- v2 switched to shadow registers but these are
not pre-initialized (zero). As a result, setting
pin direction or ODR register will clear other bits
in direction and ODR registers. Fix this bug by adding
shadow registers initialization code.
v2: - move driver to arch/powerpc/platforms/512x directory
- Kconfig changes are now in arch/powerpc/platform/512x/Kconfig
- put struct mpc512x_gpio_regs in driver's .c file
- rename GPIO_MASK into MPC512x_GPIO_MASK
- use shadow registers instead of r/m/w-operations
- don't use arch_initcall but call mpc512x_add_gpiochips()
from mpc512x platform setup code.
arch/powerpc/platforms/512x/Kconfig | 9 ++
arch/powerpc/platforms/512x/Makefile | 1 +
arch/powerpc/platforms/512x/mpc512x.h | 3 +
arch/powerpc/platforms/512x/mpc512x_gpio.c | 198 ++++++++++++++++++++++++++
arch/powerpc/platforms/512x/mpc512x_shared.c | 3 +
5 files changed, 214 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/platforms/512x/mpc512x_gpio.c
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0..bd763ee 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -30,3 +30,12 @@ config MPC5121_GENERIC
Compatible boards include: Protonic LVT base boards (ZANMCU
and VICVT2).
+
+config MPC512x_GPIO
+ bool "MPC512x GPIO support"
+ depends on PPC_MPC512x
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say Y here if you're going to use hardware that connects to the
+ MPC512x GPIOs.
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 90be2f5..12518e3 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -4,3 +4,4 @@
obj-y += clock.o mpc512x_shared.o
obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o
obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o
+obj-$(CONFIG_MPC512x_GPIO) += mpc512x_gpio.o
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0..4a1b094 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,7 @@ extern void __init mpc512x_init(void);
extern int __init mpc5121_clk_init(void);
void __init mpc512x_declare_of_platform_devices(void);
extern void mpc512x_restart(char *cmd);
+#ifdef CONFIG_MPC512x_GPIO
+extern int mpc512x_add_gpiochips(void);
+#endif
#endif /* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_gpio.c b/arch/powerpc/platforms/512x/mpc512x_gpio.c
new file mode 100644
index 0000000..fc6ad82
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc512x_gpio.c
@@ -0,0 +1,198 @@
+/*
+ * MPC512x gpio driver
+ *
+ * Copyright (c) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ *
+ * derived from ppc4xx gpio driver
+ *
+ * Copyright (c) 2008 Harris Corporation
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ *
+ * Author: Steve Falco <sfalco@harris.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/types.h>
+
+#define MPC512x_GPIO_MASK(gpio) (0x80000000 >> (gpio))
+
+struct mpc512x_gpio_regs {
+ u32 gpdir;
+ u32 gpodr;
+ u32 gpdat;
+ u32 gpier;
+ u32 gpimr;
+ u32 gpicr1;
+ u32 gpicr2;
+};
+
+struct mpc512x_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadow registers */
+ u32 dat;
+ u32 odr;
+ u32 dir;
+};
+
+/*
+ * GPIO LIB API implementation for GPIOs
+ *
+ * There are a maximum of 32 gpios in each gpio controller.
+ */
+static inline struct mpc512x_chip *
+to_mpc512x_gpiochip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct mpc512x_chip, mm_gc);
+}
+
+static int mpc512x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+ return in_be32(®s->gpdat) & MPC512x_GPIO_MASK(gpio);
+}
+
+static inline void
+__mpc512x_gpio_set(struct of_mm_gpio_chip *mm_gc, unsigned int gpio, int val)
+{
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+
+ if (val)
+ chip->dat |= MPC512x_GPIO_MASK(gpio);
+ else
+ chip->dat &= ~MPC512x_GPIO_MASK(gpio);
+
+ out_be32(®s->gpdat, chip->dat);
+}
+
+static void
+mpc512x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ __mpc512x_gpio_set(mm_gc, gpio, val);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc512x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ /* Disable open-drain function */
+ chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpodr, chip->odr);
+
+ /* Float the pin */
+ chip->dir &= ~MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpdir, chip->dir);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ return 0;
+}
+
+static int
+mpc512x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ /* First set initial value */
+ __mpc512x_gpio_set(mm_gc, gpio, val);
+
+ /* Disable open-drain function */
+ chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpodr, chip->odr);
+
+ /* Drive the pin */
+ chip->dir |= MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpdir, chip->dir);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+ return 0;
+}
+
+void __init mpc512x_add_gpiochips(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,mpc5121-gpio") {
+ int ret;
+ struct mpc512x_chip *chip;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_init(&chip->lock);
+
+ mm_gc = &chip->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ gc->ngpio = 32;
+ gc->direction_input = mpc512x_gpio_dir_in;
+ gc->direction_output = mpc512x_gpio_dir_out;
+ gc->get = mpc512x_gpio_get;
+ gc->set = mpc512x_gpio_set;
+
+ ret = of_mm_gpiochip_add(np, mm_gc);
+ if (ret)
+ goto err;
+ continue;
+err:
+ pr_err("%s: registration failed with status %d\n",
+ np->full_name, ret);
+ kfree(chip);
+ /* try others anyway */
+ }
+}
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 707e572..15da1bc 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -178,4 +178,7 @@ void __init mpc512x_init(void)
mpc5121_clk_init();
mpc512x_restart_init();
mpc512x_psc_fifo_init();
+#ifdef CONFIG_MPC512x_GPIO
+ mpc512x_add_gpiochips();
+#endif
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH V4] powerpc/mpc512x: Add gpio driver
From: Anatolij Gustschin @ 2010-06-10 16:21 UTC (permalink / raw)
To: linuxppc-dev
Cc: Anatolij Gustschin, Wolfgang Denk, Detlev Zundel, Matthias Fuchs
In-Reply-To: <1276185950-28451-1-git-send-email-agust@denx.de>
From: Matthias Fuchs <matthias.fuchs@esd.eu>
This patch adds a gpio driver for MPC512X PowerPCs.
It has been tested on our CAN-CBX-CPU5201 module that
uses a MPC5121 CPU. This platform comes with a couple of
LEDs and configuration switches that have been used for testing.
Signed-off-by: Matthias Fuchs <matthias.fuchs@esd.eu>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
Please consider this patch for inclusion in 2.6.36. Thanks!
v4: - actually v3 was rebased but without shadow
registers init code as stated in the v3 changelog.
Correct it now.
v3: - rebase to apply on current mainline tree
- v2 switched to shadow registers but these are
not pre-initialized (zero). As a result, setting
pin direction or ODR register will clear other bits
in direction and ODR registers. Fix this bug by adding
shadow registers initialization code.
v2: - move driver to arch/powerpc/platforms/512x directory
- Kconfig changes are now in arch/powerpc/platform/512x/Kconfig
- put struct mpc512x_gpio_regs in driver's .c file
- rename GPIO_MASK into MPC512x_GPIO_MASK
- use shadow registers instead of r/m/w-operations
- don't use arch_initcall but call mpc512x_add_gpiochips()
from mpc512x platform setup code.
arch/powerpc/platforms/512x/Kconfig | 9 +
arch/powerpc/platforms/512x/Makefile | 1 +
arch/powerpc/platforms/512x/mpc512x.h | 3 +
arch/powerpc/platforms/512x/mpc512x_gpio.c | 204 ++++++++++++++++++++++++++
arch/powerpc/platforms/512x/mpc512x_shared.c | 3 +
5 files changed, 220 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/platforms/512x/mpc512x_gpio.c
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0..bd763ee 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -30,3 +30,12 @@ config MPC5121_GENERIC
Compatible boards include: Protonic LVT base boards (ZANMCU
and VICVT2).
+
+config MPC512x_GPIO
+ bool "MPC512x GPIO support"
+ depends on PPC_MPC512x
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say Y here if you're going to use hardware that connects to the
+ MPC512x GPIOs.
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 90be2f5..12518e3 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -4,3 +4,4 @@
obj-y += clock.o mpc512x_shared.o
obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o
obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o
+obj-$(CONFIG_MPC512x_GPIO) += mpc512x_gpio.o
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0..4a1b094 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,7 @@ extern void __init mpc512x_init(void);
extern int __init mpc5121_clk_init(void);
void __init mpc512x_declare_of_platform_devices(void);
extern void mpc512x_restart(char *cmd);
+#ifdef CONFIG_MPC512x_GPIO
+extern int mpc512x_add_gpiochips(void);
+#endif
#endif /* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_gpio.c b/arch/powerpc/platforms/512x/mpc512x_gpio.c
new file mode 100644
index 0000000..13b2478
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc512x_gpio.c
@@ -0,0 +1,204 @@
+/*
+ * MPC512x gpio driver
+ *
+ * Copyright (c) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ *
+ * derived from ppc4xx gpio driver
+ *
+ * Copyright (c) 2008 Harris Corporation
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ * Copyright (c) MontaVista Software, Inc. 2008.
+ *
+ * Author: Steve Falco <sfalco@harris.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/types.h>
+
+#define MPC512x_GPIO_MASK(gpio) (0x80000000 >> (gpio))
+
+struct mpc512x_gpio_regs {
+ u32 gpdir;
+ u32 gpodr;
+ u32 gpdat;
+ u32 gpier;
+ u32 gpimr;
+ u32 gpicr1;
+ u32 gpicr2;
+};
+
+struct mpc512x_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /* shadow registers */
+ u32 dat;
+ u32 odr;
+ u32 dir;
+};
+
+/*
+ * GPIO LIB API implementation for GPIOs
+ *
+ * There are a maximum of 32 gpios in each gpio controller.
+ */
+static inline struct mpc512x_chip *
+to_mpc512x_gpiochip(struct of_mm_gpio_chip *mm_gc)
+{
+ return container_of(mm_gc, struct mpc512x_chip, mm_gc);
+}
+
+static int mpc512x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+ return in_be32(®s->gpdat) & MPC512x_GPIO_MASK(gpio);
+}
+
+static inline void
+__mpc512x_gpio_set(struct of_mm_gpio_chip *mm_gc, unsigned int gpio, int val)
+{
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+
+
+ if (val)
+ chip->dat |= MPC512x_GPIO_MASK(gpio);
+ else
+ chip->dat &= ~MPC512x_GPIO_MASK(gpio);
+
+ out_be32(®s->gpdat, chip->dat);
+}
+
+static void
+mpc512x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ __mpc512x_gpio_set(mm_gc, gpio, val);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+}
+
+static int mpc512x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ /* Disable open-drain function */
+ chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpodr, chip->odr);
+
+ /* Float the pin */
+ chip->dir &= ~MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpdir, chip->dir);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ return 0;
+}
+
+static int
+mpc512x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct mpc512x_chip *chip = to_mpc512x_gpiochip(mm_gc);
+ struct mpc512x_gpio_regs __iomem *regs = mm_gc->regs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+
+ /* First set initial value */
+ __mpc512x_gpio_set(mm_gc, gpio, val);
+
+ /* Disable open-drain function */
+ chip->odr &= ~MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpodr, chip->odr);
+
+ /* Drive the pin */
+ chip->dir |= MPC512x_GPIO_MASK(gpio);
+ out_be32(®s->gpdir, chip->dir);
+
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
+
+ return 0;
+}
+
+void __init mpc512x_add_gpiochips(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,mpc5121-gpio") {
+ int ret;
+ struct mpc512x_chip *chip;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+ struct mpc512x_gpio_regs __iomem *regs;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_init(&chip->lock);
+
+ mm_gc = &chip->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ gc->ngpio = 32;
+ gc->direction_input = mpc512x_gpio_dir_in;
+ gc->direction_output = mpc512x_gpio_dir_out;
+ gc->get = mpc512x_gpio_get;
+ gc->set = mpc512x_gpio_set;
+
+ ret = of_mm_gpiochip_add(np, mm_gc);
+ if (ret)
+ goto err;
+
+ regs = mm_gc->regs;
+ chip->dat = in_be32(®s->gpdat);
+ chip->dir = in_be32(®s->gpdir);
+ chip->odr = in_be32(®s->gpodr);
+ continue;
+err:
+ pr_err("%s: registration failed with status %d\n",
+ np->full_name, ret);
+ kfree(chip);
+ /* try others anyway */
+ }
+}
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 707e572..15da1bc 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -178,4 +178,7 @@ void __init mpc512x_init(void)
mpc5121_clk_init();
mpc512x_restart_init();
mpc512x_psc_fifo_init();
+#ifdef CONFIG_MPC512x_GPIO
+ mpc512x_add_gpiochips();
+#endif
}
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-10 16:30 UTC (permalink / raw)
To: Anton Vorontsov
Cc: sfr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev, M. Warner Losh
In-Reply-To: <20100610154741.GA7484@oksana.dev.rtsoft.ru>
On Thu, Jun 10, 2010 at 9:47 AM, Anton Vorontsov <cbouatmailru@gmail.com> w=
rote:
> On Thu, Jun 10, 2010 at 09:13:57AM -0600, M. Warner Losh wrote:
> [...]
>> : >> I told you several ways of how to improve the code (based on
>> : >> the ideas from drivers/base/, so the ideas aren't even mine,
>> : >> fwiw).
>> : >
>> : > I tend to agree with Anton here.
>> :
>> : The reason I'm confident doing it that way is that it is *not* a
>> : structure. =A0There is no structure relationship between the resource
>> : table and the platform_device other than they are allocated with the
>> : same kzalloc() call. =A0All the code that cares about that is containe=
d
>> : within 4 lines of code. =A0I'm resistant to using a structure because =
it
>> : is adds an additional 5-6 lines of code to add a structure that won't
>> : be used anywhere else, and is only 4 lines to begin with.
>>
>> I tend to agree with Grant here. =A0The idiom he's using is very wide
>> spread in the industry and works extremely well. =A0It keeps the
>> ugliness confined to a couple of lines and is less ugly than the
>> alternatives for this design pattern. =A0It is a little surprising when
>> you see the code the first time, granted, but I think its expressive
>> power trumps that small surprise.
>
> Oh, come on. Both constructions are binary equivalent.
>
> So how can people seriously be with *that* code:
>
> =A0 =A0 =A0 =A0dev->resource =3D (void *)&dev[1];
>
> which, semantically, is a nonsense and asks for a fix.
>
> While
> =A0 =A0 =A0 =A0dev_obj->dev.resource =3D dev_obj->resource;
>
> simply makes sense.
Well, my choices are (without whitespace so as not to bias line count):
A)
struct of_device *alloc_function(int num_res)
{
struct device *ofdev;
struct resource *res;
ofdev =3D kzalloc(sizeof(*ofdev) + (sizeof(*res) * num_res), GFP_KERNEL);
if (!ofdev)
return NULL;
res =3D (struct resource *)&ofdev[1];
...
return ofdev;
}
10 lines of code
B)
struct of_device_object {
struct of_device ofdev;
struct resource resource[0];
};
struct of_device *alloc_function(int num_res)
{
struct of_device_object *ofobj;
struct of_device *ofdev;
struct resource *res;
ofobj =3D kzalloc(sizeof(*ofobj) + (sizeof(*res) * num_res), GFP_KERNEL);
if (!ofobj)
return NULL;
res =3D ofobj->resource;
...
return &ofobj->ofdev;
}
15 lines of code
C)
struct of_device *alloc_function(int num_res)
{
struct device *ofdev;
struct resource *res;
ofdev =3D kzalloc(sizeof(*ofdev), GFP_KERNEL)
if (!ofdev)
return NULL;
res =3D kzalloc((sizeof(*res) * num_res), GFP_KERNEL);
if (!res) {
kfree(ofdev); /* or goto an error unwind label */
return NULL;
}
res =3D (struct resource *)&ofdev[1];
...
return ofdev;
}
15 lines of code, plus an extra few lines at kfree(ofdev) time.
When I look at the three, option A is more concise and clearer in it's
intent to me.
That being said, I'm looking at refactoring to use
platform_device_alloc() instead, which is effectively option C. (which
I'd normally avoid, but it removes otherwise duplicate code from
drivers/of).
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-10 16:52 UTC (permalink / raw)
To: M. Warner Losh
Cc: sfr, devicetree-discuss, linuxppc-dev, jeremy.kerr,
microblaze-uclinux
In-Reply-To: <20100610.100140.8559628065321695.imp@bsdimp.com>
On Thu, Jun 10, 2010 at 10:01:40AM -0600, M. Warner Losh wrote:
[...]
> But this requires extra, bogus fields in the structure
False. The [0] field isn't bogus, it has a defined meaning.
It says: here is some amount of resouces may be allocated.
> and creates a bogus sizeof issue.
Creates? False. The same sizeof problem exists in Grant's
approach. sizeof(*dev) != what_we_have_allocated. Which is
isn't great, I agree. And that's exactly why I proposed a
dedicated allocation in the first place.
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 0/2] Replace of_device with platform_device
From: Grant Likely @ 2010-06-10 16:46 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Stephen Rothwell, Michal Simek, microblaze-uclinux, linuxppc-dev,
sparclinux, David Miller
In-Reply-To: <1276151543.1962.48.camel@pasglop>
On Thu, Jun 10, 2010 at 12:32 AM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Fri, 2010-06-04 at 15:13 -0600, Grant Likely wrote:
>> This series is based on Linus' current tree. =A0It eliminate struct
>> of_device in preparation for the merge of of_platform_bus_type and
>> platform_bus_type.
>>
>> Assuming there are no objections, I'll be putting these to linux-next
>> to stew sometime next week.
>
> I don't see any update to the macio stuff... have you fixed that
> separately or are you up to breaking it -again- ? :-)
It shouldn't need any fixing because I'm not touching the driver side
of the equation (unlike the last breakage where macio_driver had its
own copy of the match table which I missed). In fact, there aren't
even any logic changes other than dealing with moving some of the
structure members in the sparc arch code. If I did miss anything,
then it should show up in build testing.
I will try to dig out an mac machine and fire it up though.
>
> You should do build tests with a pmac32 or g5 defconfig every now and
> then.
I frequently build tested on many platforms:
http://kisskb.ellerman.id.au/kisskb/branch/13/
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH][RFC] ibm_newemac and SIOCGMIIREG
From: Arnd Bergmann @ 2010-06-10 17:03 UTC (permalink / raw)
To: Steven A. Falco; +Cc: linuxppc-dev
In-Reply-To: <4C11046D.4080205@harris.com>
On Thursday 10 June 2010, Steven A. Falco wrote:
> > The ifreq structure passed into the ndo_ioctl function is in kernel
> > space, it gets copied there by net/core/dev.c:dev_ioctl().
> > emac_ioctl only accesses the data in that structure, so a copy_from_user
> > is wrong here as far as I can tell.
>
> net/core/dev.c:dev_ioctl() does a copy_from_user on the overall structure,
> but the structure contains a union, one member of which is an embedded
> pointer to an array. This pointer member is only used in the case of these
> two ioctls. Other ioctls use different union members, which are not pointers.
Still unconvinced.
I don't see anywhere in the structure where we actually use a
pointer from ifr_ifru. The if_mii function is defined as
static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
{
return (struct mii_ioctl_data *) &rq->ifr_ifru;
}
That just returns a pointer to the ifr_ifru member itself,
it does not read a __user pointer. Note how if_mii even
returns a kernel pointer (struct mii_ioctl_data *), not
a struct mii_ioctl_data __user *. You even added a cast
that otherwise should not be needed.
> As I understand it, the copy_from_user in dev_ioctl does not recursively
> copy the array. In fact it could not do so, because the pointer to array
> is only 4 bytes long, while the array itself is 8 bytes long - so it would
> not fit. I.e., dev_ioctl would have to allocate storage, and do a second
> copy_from_user to retrieve the array. It would have to clean up after the
> emac_ioctl ran. And it would have to do this only for these specific
> ioctl calls which use the array pointer in the union.
>
> Also, the result has to be returned to the user in the same array, which
> needs a copy_to_user of the array data, which is also not done in dev_ioctl.
There is no array, and no pointer in struct ifreq
> So I think this second copy_from/copy_to needs to be done somewhere. I
> added it in the emac_ioctl because that is where the command is fully
> decoded. It also avoids the problem of allocating space for the copied
> array. But other fixes are certainly possible as well, which is why I am
> not sure I've hit on the "proper" fix.
No other device driver implementing SIOCGMIIREG does any of this,
so I'm pretty sure it's not the proper fix.
> Thanks very much for reviewing - please let me know if my explanation is
> unclear, or if you see a better way to fix this problem.
In theory, your patch should break the code. Doing a direct access
in place of a copy_to/from_user is a security hole but should still work,
while adding a copy_to/from_user on a kernel pointer should always result
in an EFAULT.
Arnd
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox