* [PATCH 3/3] PowerPC: 440EPx/GRx incorrect write to DDR SDRAM errata workaround
From: Valentine Barshak @ 2007-09-21 14:50 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <20070921144149.GA4150@ru.mvista.com>
Add a workaround for PowerPC 440EPx/GRx incorrect write to
DDR SDRAM errata. Data can be written to wrong address
in SDRAM when write pipelining enabled on plb0. We disable
it in the cpu_setup for these processors at early init.
Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
---
arch/powerpc/kernel/cpu_setup_44x.S | 25 ++++++++++++++++++++++++-
arch/powerpc/kernel/cputable.c | 3 +++
2 files changed, 27 insertions(+), 1 deletion(-)
diff -ruN linux-2.6.orig/arch/powerpc/kernel/cpu_setup_44x.S linux-2.6/arch/powerpc/kernel/cpu_setup_44x.S
--- linux-2.6.orig/arch/powerpc/kernel/cpu_setup_44x.S 2007-09-21 15:31:14.000000000 +0400
+++ linux-2.6/arch/powerpc/kernel/cpu_setup_44x.S 2007-09-21 16:07:12.000000000 +0400
@@ -20,7 +20,14 @@
_GLOBAL(__setup_cpu_440ep)
b __init_fpu_44x
_GLOBAL(__setup_cpu_440epx)
- b __init_fpu_44x
+ mflr r4
+ bl __init_fpu_44x
+ bl __plb_disable_wrp
+ mtlr r4
+ blr
+_GLOBAL(__setup_cpu_440grx)
+ b __plb_disable_wrp
+
/* enable APU between CPU and FPU */
_GLOBAL(__init_fpu_44x)
@@ -31,3 +38,19 @@
isync
blr
+/*
+ * Workaround for the incorrect write to DDR SDRAM errata.
+ * The write address can be corrupted during writes to
+ * DDR SDRAM when write pipelining is enabled on PLB0.
+ * Disable write pipelining here.
+ */
+#define DCRN_PLB4A0_ACR 0x81
+
+_GLOBAL(__plb_disable_wrp)
+ mfdcr r3,DCRN_PLB4A0_ACR
+ /* clear WRP bit in PLB4A0_ACR */
+ rlwinm r3,r3,0,8,6
+ mtdcr DCRN_PLB4A0_ACR,r3
+ isync
+ blr
+
diff -ruN linux-2.6.orig/arch/powerpc/kernel/cputable.c linux-2.6/arch/powerpc/kernel/cputable.c
--- linux-2.6.orig/arch/powerpc/kernel/cputable.c 2007-09-21 15:55:23.000000000 +0400
+++ linux-2.6/arch/powerpc/kernel/cputable.c 2007-09-21 16:08:23.000000000 +0400
@@ -33,6 +33,7 @@
#ifdef CONFIG_PPC32
extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
@@ -1146,6 +1147,8 @@
.cpu_user_features = COMMON_USER_BOOKE,
.icache_bsize = 32,
.dcache_bsize = 32,
+ .cpu_setup = __setup_cpu_440grx,
+ .platform = "ppc440",
},
{ /* 440GP Rev. B */
.pvr_mask = 0xf0000fff,
^ permalink raw reply
* AMCC yosemite 440ep PCI slot doesn't work.
From: Andrew Liu @ 2007-09-21 10:53 UTC (permalink / raw)
To: linuxppc-dev
Hello All,
when insert a RealTek RTL8139 network card into PCI slot,
After system boot up,
root@localhost:/root> ifconfig eth2 192.168.17.12
irq 25: nobody cared (try booting with the "irqpoll" option)
Call Trace:
[cf135af0] [c0008820] show_stack+0x48/0x190 (unreliable)
[cf135b20] [c003c414] __report_bad_irq+0x34/0xac
[cf135b40] [c003c714] note_interrupt+0x288/0x2c8
[cf135b70] [c003b818] __do_IRQ+0x104/0x110
[cf135b90] [c0006900] do_IRQ+0xbc/0xc0
[cf135ba0] [c00020c0] ret_from_except+0x0/0x18
[cf135c60] [00000019] 0x19
[cf135c90] [c000668c] do_softirq+0x54/0x58
[cf135ca0] [c001df40] irq_exit+0x48/0x58
[cf135cb0] [c00068b4] do_IRQ+0x70/0xc0
[cf135cc0] [c00020c0] ret_from_except+0x0/0x18
[cf135d80] [c003c2b4] setup_irq+0x1ac/0x200
[cf135da0] [c003c3cc] request_irq+0xc4/0xd8
[cf135dd0] [c0122328] rtl8139_open+0x38/0x210
[cf135df0] [c0187500] dev_open+0x7c/0xcc
[cf135e10] [c0187420] dev_change_flags+0x16c/0x1d0
[cf135e30] [c01cbff0] devinet_ioctl+0x604/0x720
[cf135ea0] [c01cc1f8] inet_ioctl+0x98/0xbc
[cf135eb0] [c0179328] sock_ioctl+0x60/0x260
[cf135ed0] [c006c360] do_ioctl+0x38/0x84
[cf135ee0] [c006c438] vfs_ioctl+0x8c/0x40c
[cf135f10] [c006c7f8] sys_ioctl+0x40/0x74
[cf135f40] [c0001a84] ret_from_syscall+0x0/0x3c
handlers:
[<c0122bd4>] (rtl8139_interrupt+0x0/0x52c)
Disabling IRQ #25
root@localhost:/root>
Message from syslogd@localhost at Thu Jan 1 00:02:13 1970 ...
localhost kernel: Disabling IRQ #25
root@localhost:/root>
The system boot up information as follows:
root@localhost:/root> dmesg
Linux version 2.6.23-rc6-gea60adb5 (sliu@localhost.localdomain) (gcc
version 4.0.0 (DENX ELDK 4.1 4.0.0)) #3 Fri Sep 21 18:37:59 CST 2007
AMCC PowerPC 440EP Yosemite Platform
Entering add_active_range(0, 0, 65536) 0 entries of 256 used
Zone PFN ranges:
DMA 0 -> 65536
Normal 65536 -> 65536
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
0: 0 -> 65536
On node 0 totalpages: 65536
DMA zone: 512 pages used for memmap
DMA zone: 0 pages reserved
DMA zone: 65024 pages, LIFO batch:15
Normal zone: 0 pages used for memmap
Movable zone: 0 pages used for memmap
Built 1 zonelists in Zone order. Total pages: 65024
Kernel command line: root=/dev/nfs rw
nfsroot=128.224.149.6:/tftpboot/sliu/rootfs
ip=128.224.149.11::128.224.149.1:255.255.255.0:yosemite:eth0:off
console=ttyS0,9600
PID hash table entries: 1024 (order: 10, 4096 bytes)
console [ttyS0] enabled
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 256896k available (2052k kernel code, 716k data, 152k init, 0k
highmem)
Calibrating delay loop... 798.72 BogoMIPS (lpj=1597440)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
PCI: Probing PCI hardware
PCI: Scanning bus 0000:00
PCI: Found 0000:00:0c.0 [10ec/8139] 000200 00
PCI: Calling quirk c000444c for 0000:00:0c.0
PCI: Fixups for bus 0000:00
PCI: Bus scan for 0000:00 returning with max=00
PCI: fixup irq: (0000:00:0c.0) got 25
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
TCP established hash table entries: 8192 (order: 4, 65536 bytes)
TCP bind hash table entries: 8192 (order: 3, 32768 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP reno registered
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
PCI: Calling quirk c00fbab4 for 0000:00:0c.0
PCI: Calling quirk c02ae3b8 for 0000:00:0c.0
Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled
serial8250: ttyS0 at MMIO 0x0 (irq = 0) is a 16550A
serial8250: ttyS1 at MMIO 0x0 (irq = 1) is a 16550A
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
PPC 4xx OCP EMAC driver, version 3.54
mal0: initialized, 4 TX channels, 2 RX channels
zmii0: bridge in RMII mode
eth0: emac0, MAC 00:10:ec:00:87:42
eth0: found Generic MII PHY (0x01)
eth1: emac1, MAC 00:00:00:00:00:00
eth1: found Generic MII PHY (0x03)
8139too Fast Ethernet driver 0.9.28
eth2: RealTek RTL8139 at 0xd1012f00, 00:0e:2e:7e:f5:e6, IRQ 25
eth2: Identified 8139 chip type 'RTL-8100B/8139D'
pegasus: v0.6.14 (2006/09/27), Pegasus/Pegasus II USB Ethernet driver
usbcore: registered new interface driver pegasus
Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
ide: Assuming 33MHz system bus speed for PIO modes; override with idebus=xx
usbmon: debugfs is not available
ohci_hcd: 2006 August 04 USB 1.1 'Open' Host Controller (OHCI) Driver
ppc-soc-ohci ppc-soc-ohci.0: USB Host Controller
ppc-soc-ohci ppc-soc-ohci.0: new USB bus registered, assigned bus number 1
ppc-soc-ohci ppc-soc-ohci.0: irq 40, io mem 0xef601000
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
ether gadget: using random self ethernet address
ether gadget: using random host ethernet address
usb0: Ethernet Gadget, version: May Day 2005
usb0: using musbhsfc_udc, OUT ep2 IN ep1 STATUS ep3
usb0: MAC 66:91:74:ab:fb:61
usb0: HOST MAC 1a:b5:87:5d:8f:00
usb0: RNDIS ready
musbhsfc_udc: registered gadget driver 'ether'
TCP cubic registered
NET: Registered protocol family 1
NET: Registered protocol family 17
usb 1-1: new full speed USB device using ppc-soc-ohci and address 2
usb 1-1: configuration #1 chosen from 1 choice
eth0: link is up, 100 FDX, pause enabled
scsi0 : SCSI emulation for USB Mass Storage devices
usb-storage: device found at 2
usb-storage: waiting for device to settle before scanning
IP-Config: Complete:
device=eth0, addr=128.224.149.11, mask=255.255.255.0,
gw=128.224.149.1,
host=yosemite, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=128.224.149.6, rootpath=
Looking up port of RPC 100003/2 on 128.224.149.6
Looking up port of RPC 100005/1 on 128.224.149.6
VFS: Mounted root (nfs filesystem).
Freeing unused kernel memory: 152k init
scsi 0:0:0:0: Direct-Access Kingston DataTraveler 2.0 6.16 PQ: 0
ANSI: 0 CCS
sd 0:0:0:0: [sda] 244735 512-byte hardware sectors (125 MB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Mode Sense: 45 00 00 08
sd 0:0:0:0: [sda] Assuming drive cache: write through
sd 0:0:0:0: [sda] 244735 512-byte hardware sectors (125 MB)
sd 0:0:0:0: [sda] Write Protect is off
sd 0:0:0:0: [sda] Mode Sense: 45 00 00 08
sd 0:0:0:0: [sda] Assuming drive cache: write through
sda: sda1
sd 0:0:0:0: [sda] Attached SCSI removable disk
sd 0:0:0:0: Attached scsi generic sg0 type 0
usb-storage: device scan complete
irq 25: nobody cared (try booting with the "irqpoll" option)
Call Trace:
[cf135af0] [c0008820] show_stack+0x48/0x190 (unreliable)
[cf135b20] [c003c414] __report_bad_irq+0x34/0xac
[cf135b40] [c003c714] note_interrupt+0x288/0x2c8
[cf135b70] [c003b818] __do_IRQ+0x104/0x110
[cf135b90] [c0006900] do_IRQ+0xbc/0xc0
[cf135ba0] [c00020c0] ret_from_except+0x0/0x18
[cf135c60] [00000019] 0x19
[cf135c90] [c000668c] do_softirq+0x54/0x58
[cf135ca0] [c001df40] irq_exit+0x48/0x58
[cf135cb0] [c00068b4] do_IRQ+0x70/0xc0
[cf135cc0] [c00020c0] ret_from_except+0x0/0x18
[cf135d80] [c003c2b4] setup_irq+0x1ac/0x200
[cf135da0] [c003c3cc] request_irq+0xc4/0xd8
[cf135dd0] [c0122328] rtl8139_open+0x38/0x210
[cf135df0] [c0187500] dev_open+0x7c/0xcc
[cf135e10] [c0187420] dev_change_flags+0x16c/0x1d0
[cf135e30] [c01cbff0] devinet_ioctl+0x604/0x720
[cf135ea0] [c01cc1f8] inet_ioctl+0x98/0xbc
[cf135eb0] [c0179328] sock_ioctl+0x60/0x260
[cf135ed0] [c006c360] do_ioctl+0x38/0x84
[cf135ee0] [c006c438] vfs_ioctl+0x8c/0x40c
[cf135f10] [c006c7f8] sys_ioctl+0x40/0x74
[cf135f40] [c0001a84] ret_from_syscall+0x0/0x3c
handlers:
[<c0122bd4>] (rtl8139_interrupt+0x0/0x52c)
Disabling IRQ #25
eth2: link up, 100Mbps, full-duplex, lpa 0x45E1
Who can give some advice?
Thanks.
BRs,
Andrew.
^ permalink raw reply
* Re: AMCC yosemite 440ep PCI slot doesn't work.
From: Valentine Barshak @ 2007-09-21 15:14 UTC (permalink / raw)
To: Andrew Liu; +Cc: linuxppc-dev
In-Reply-To: <46F3A2C4.7000202@windriver.com>
Andrew Liu wrote:
> Hello All,
>
> when insert a RealTek RTL8139 network card into PCI slot,
> After system boot up,
>
> root@localhost:/root> ifconfig eth2 192.168.17.12
> irq 25: nobody cared (try booting with the "irqpoll" option)
> Call Trace:
> [cf135af0] [c0008820] show_stack+0x48/0x190 (unreliable)
> [cf135b20] [c003c414] __report_bad_irq+0x34/0xac
> [cf135b40] [c003c714] note_interrupt+0x288/0x2c8
> [cf135b70] [c003b818] __do_IRQ+0x104/0x110
> [cf135b90] [c0006900] do_IRQ+0xbc/0xc0
> [cf135ba0] [c00020c0] ret_from_except+0x0/0x18
> [cf135c60] [00000019] 0x19
> [cf135c90] [c000668c] do_softirq+0x54/0x58
> [cf135ca0] [c001df40] irq_exit+0x48/0x58
> [cf135cb0] [c00068b4] do_IRQ+0x70/0xc0
> [cf135cc0] [c00020c0] ret_from_except+0x0/0x18
> [cf135d80] [c003c2b4] setup_irq+0x1ac/0x200
> [cf135da0] [c003c3cc] request_irq+0xc4/0xd8
> [cf135dd0] [c0122328] rtl8139_open+0x38/0x210
> [cf135df0] [c0187500] dev_open+0x7c/0xcc
> [cf135e10] [c0187420] dev_change_flags+0x16c/0x1d0
> [cf135e30] [c01cbff0] devinet_ioctl+0x604/0x720
> [cf135ea0] [c01cc1f8] inet_ioctl+0x98/0xbc
> [cf135eb0] [c0179328] sock_ioctl+0x60/0x260
> [cf135ed0] [c006c360] do_ioctl+0x38/0x84
> [cf135ee0] [c006c438] vfs_ioctl+0x8c/0x40c
> [cf135f10] [c006c7f8] sys_ioctl+0x40/0x74
> [cf135f40] [c0001a84] ret_from_syscall+0x0/0x3c
> handlers:
> [<c0122bd4>] (rtl8139_interrupt+0x0/0x52c)
> Disabling IRQ #25
> root@localhost:/root>
> Message from syslogd@localhost at Thu Jan 1 00:02:13 1970 ...
> localhost kernel: Disabling IRQ #25
>
> root@localhost:/root>
>
>
> The system boot up information as follows:
> root@localhost:/root> dmesg
> Linux version 2.6.23-rc6-gea60adb5 (sliu@localhost.localdomain) (gcc
> version 4.0.0 (DENX ELDK 4.1 4.0.0)) #3 Fri Sep 21 18:37:59 CST 2007
> AMCC PowerPC 440EP Yosemite Platform
> Entering add_active_range(0, 0, 65536) 0 entries of 256 used
> Zone PFN ranges:
> DMA 0 -> 65536
> Normal 65536 -> 65536
> Movable zone start PFN for each node
> early_node_map[1] active PFN ranges
> 0: 0 -> 65536
> On node 0 totalpages: 65536
> DMA zone: 512 pages used for memmap
> DMA zone: 0 pages reserved
> DMA zone: 65024 pages, LIFO batch:15
> Normal zone: 0 pages used for memmap
> Movable zone: 0 pages used for memmap
> Built 1 zonelists in Zone order. Total pages: 65024
> Kernel command line: root=/dev/nfs rw
> nfsroot=128.224.149.6:/tftpboot/sliu/rootfs
> ip=128.224.149.11::128.224.149.1:255.255.255.0:yosemite:eth0:off
> console=ttyS0,9600
> PID hash table entries: 1024 (order: 10, 4096 bytes)
> console [ttyS0] enabled
> Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
> Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
> Memory: 256896k available (2052k kernel code, 716k data, 152k init, 0k
> highmem)
> Calibrating delay loop... 798.72 BogoMIPS (lpj=1597440)
> Mount-cache hash table entries: 512
> NET: Registered protocol family 16
> PCI: Probing PCI hardware
> PCI: Scanning bus 0000:00
> PCI: Found 0000:00:0c.0 [10ec/8139] 000200 00
> PCI: Calling quirk c000444c for 0000:00:0c.0
> PCI: Fixups for bus 0000:00
> PCI: Bus scan for 0000:00 returning with max=00
> PCI: fixup irq: (0000:00:0c.0) got 25
> SCSI subsystem initialized
> usbcore: registered new interface driver usbfs
> usbcore: registered new interface driver hub
> usbcore: registered new device driver usb
> NET: Registered protocol family 2
> IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
> TCP established hash table entries: 8192 (order: 4, 65536 bytes)
> TCP bind hash table entries: 8192 (order: 3, 32768 bytes)
> TCP: Hash tables configured (established 8192 bind 8192)
> TCP reno registered
> io scheduler noop registered
> io scheduler anticipatory registered (default)
> io scheduler deadline registered
> io scheduler cfq registered
> PCI: Calling quirk c00fbab4 for 0000:00:0c.0
> PCI: Calling quirk c02ae3b8 for 0000:00:0c.0
> Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled
> serial8250: ttyS0 at MMIO 0x0 (irq = 0) is a 16550A
> serial8250: ttyS1 at MMIO 0x0 (irq = 1) is a 16550A
> RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
> PPC 4xx OCP EMAC driver, version 3.54
> mal0: initialized, 4 TX channels, 2 RX channels
> zmii0: bridge in RMII mode
> eth0: emac0, MAC 00:10:ec:00:87:42
> eth0: found Generic MII PHY (0x01)
> eth1: emac1, MAC 00:00:00:00:00:00
> eth1: found Generic MII PHY (0x03)
> 8139too Fast Ethernet driver 0.9.28
> eth2: RealTek RTL8139 at 0xd1012f00, 00:0e:2e:7e:f5:e6, IRQ 25
> eth2: Identified 8139 chip type 'RTL-8100B/8139D'
> pegasus: v0.6.14 (2006/09/27), Pegasus/Pegasus II USB Ethernet driver
> usbcore: registered new interface driver pegasus
> Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
> ide: Assuming 33MHz system bus speed for PIO modes; override with idebus=xx
> usbmon: debugfs is not available
> ohci_hcd: 2006 August 04 USB 1.1 'Open' Host Controller (OHCI) Driver
> ppc-soc-ohci ppc-soc-ohci.0: USB Host Controller
> ppc-soc-ohci ppc-soc-ohci.0: new USB bus registered, assigned bus number 1
> ppc-soc-ohci ppc-soc-ohci.0: irq 40, io mem 0xef601000
> usb usb1: configuration #1 chosen from 1 choice
> hub 1-0:1.0: USB hub found
> hub 1-0:1.0: 2 ports detected
> Initializing USB Mass Storage driver...
> usbcore: registered new interface driver usb-storage
> USB Mass Storage support registered.
> ether gadget: using random self ethernet address
> ether gadget: using random host ethernet address
> usb0: Ethernet Gadget, version: May Day 2005
> usb0: using musbhsfc_udc, OUT ep2 IN ep1 STATUS ep3
> usb0: MAC 66:91:74:ab:fb:61
> usb0: HOST MAC 1a:b5:87:5d:8f:00
> usb0: RNDIS ready
> musbhsfc_udc: registered gadget driver 'ether'
> TCP cubic registered
> NET: Registered protocol family 1
> NET: Registered protocol family 17
> usb 1-1: new full speed USB device using ppc-soc-ohci and address 2
> usb 1-1: configuration #1 chosen from 1 choice
> eth0: link is up, 100 FDX, pause enabled
> scsi0 : SCSI emulation for USB Mass Storage devices
> usb-storage: device found at 2
> usb-storage: waiting for device to settle before scanning
> IP-Config: Complete:
> device=eth0, addr=128.224.149.11, mask=255.255.255.0,
> gw=128.224.149.1,
> host=yosemite, domain=, nis-domain=(none),
> bootserver=255.255.255.255, rootserver=128.224.149.6, rootpath=
> Looking up port of RPC 100003/2 on 128.224.149.6
> Looking up port of RPC 100005/1 on 128.224.149.6
> VFS: Mounted root (nfs filesystem).
> Freeing unused kernel memory: 152k init
> scsi 0:0:0:0: Direct-Access Kingston DataTraveler 2.0 6.16 PQ: 0
> ANSI: 0 CCS
> sd 0:0:0:0: [sda] 244735 512-byte hardware sectors (125 MB)
> sd 0:0:0:0: [sda] Write Protect is off
> sd 0:0:0:0: [sda] Mode Sense: 45 00 00 08
> sd 0:0:0:0: [sda] Assuming drive cache: write through
> sd 0:0:0:0: [sda] 244735 512-byte hardware sectors (125 MB)
> sd 0:0:0:0: [sda] Write Protect is off
> sd 0:0:0:0: [sda] Mode Sense: 45 00 00 08
> sd 0:0:0:0: [sda] Assuming drive cache: write through
> sda: sda1
> sd 0:0:0:0: [sda] Attached SCSI removable disk
> sd 0:0:0:0: Attached scsi generic sg0 type 0
> usb-storage: device scan complete
> irq 25: nobody cared (try booting with the "irqpoll" option)
> Call Trace:
> [cf135af0] [c0008820] show_stack+0x48/0x190 (unreliable)
> [cf135b20] [c003c414] __report_bad_irq+0x34/0xac
> [cf135b40] [c003c714] note_interrupt+0x288/0x2c8
> [cf135b70] [c003b818] __do_IRQ+0x104/0x110
> [cf135b90] [c0006900] do_IRQ+0xbc/0xc0
> [cf135ba0] [c00020c0] ret_from_except+0x0/0x18
> [cf135c60] [00000019] 0x19
> [cf135c90] [c000668c] do_softirq+0x54/0x58
> [cf135ca0] [c001df40] irq_exit+0x48/0x58
> [cf135cb0] [c00068b4] do_IRQ+0x70/0xc0
> [cf135cc0] [c00020c0] ret_from_except+0x0/0x18
> [cf135d80] [c003c2b4] setup_irq+0x1ac/0x200
> [cf135da0] [c003c3cc] request_irq+0xc4/0xd8
> [cf135dd0] [c0122328] rtl8139_open+0x38/0x210
> [cf135df0] [c0187500] dev_open+0x7c/0xcc
> [cf135e10] [c0187420] dev_change_flags+0x16c/0x1d0
> [cf135e30] [c01cbff0] devinet_ioctl+0x604/0x720
> [cf135ea0] [c01cc1f8] inet_ioctl+0x98/0xbc
> [cf135eb0] [c0179328] sock_ioctl+0x60/0x260
> [cf135ed0] [c006c360] do_ioctl+0x38/0x84
> [cf135ee0] [c006c438] vfs_ioctl+0x8c/0x40c
> [cf135f10] [c006c7f8] sys_ioctl+0x40/0x74
> [cf135f40] [c0001a84] ret_from_syscall+0x0/0x3c
> handlers:
> [<c0122bd4>] (rtl8139_interrupt+0x0/0x52c)
> Disabling IRQ #25
> eth2: link up, 100Mbps, full-duplex, lpa 0x45E1
>
>
> Who can give some advice?
>
> Thanks.
> BRs,
> Andrew.
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
Looks like wrong external interrupt settings (trigger/level) for PCI
interrupt.
^ permalink raw reply
* DTC Patch for Cygwin
From: Matt Tyrlik @ 2007-09-21 15:26 UTC (permalink / raw)
To: linuxppc-dev; +Cc: dwg
[-- Attachment #1: Type: text/plain, Size: 2353 bytes --]
Changes required to compile DTC under Cygwin
===================================================================
--- dtc-org.orig/tests/supernode_atdepth_offset.c
+++ dtc-org/tests/supernode_atdepth_offset.c
@@ -63,8 +63,11 @@ int path_prefix(const char *path, int de
return 1;
p = path;
- for (i = 0; i < depth; i++)
- p = strchrnul(p+1, '/');
+ for (i = 0; i < depth; i++) {
+ p = strchr(p+1, '/');
+ if (!p)
+ p = path + strlen(path);
+ }
return p - path;
}
Index: dtc-org/tests/testutils.c
===================================================================
--- dtc-org.orig/tests/testutils.c
+++ dtc-org/tests/testutils.c
@@ -52,10 +52,9 @@ static void sigint_handler(int signum, s
void test_init(int argc, char *argv[])
{
int err;
- struct sigaction sa_int = {
- .sa_sigaction = sigint_handler,
- };
+ struct sigaction sa_int;
+ sa_int.sa_sigaction = sigint_handler,
test_name = argv[0];
err = sigaction(SIGINT, &sa_int, NULL);
Index: dtc-org/tests/trees.S
===================================================================
--- dtc-org.orig/tests/trees.S
+++ dtc-org/tests/trees.S
@@ -17,10 +17,16 @@
.byte ((val) >> 8) & 0xff ; \
.byte (val) & 0xff
+#ifdef __CYGWIN__
+#define TREE_SYMBOL(tree) __##tree
+#else
+#define TREE_SYMBOL(tree) _##tree
+#endif
+
#define TREE_HDR(tree) \
.balign 4 ; \
- .globl _##tree ; \
-_##tree: \
+ .globl TREE_SYMBOL(tree); \
+TREE_SYMBOL(tree): \
tree: \
FDTLONG(FDT_MAGIC) ; \
FDTLONG(tree##_end - tree) ; \
Index: dtc-org/tests/tests.h
===================================================================
--- dtc-org.orig/tests/tests.h
+++ dtc-org/tests/tests.h
@@ -130,4 +130,15 @@ const void *check_getprop(void *fdt, int
void *load_blob_arg(int argc, char *argv[]);
void save_blob(const char *filename, void *blob);
+#ifndef GLIBC
+#define strndupa(my_str, my_len) \
+ ({ \
+ char *new_str=alloca((my_len) + 1); \
+ strncpy(new_str, my_str, my_len); \
+ new_str[my_len]='\0'; \
+ new_str; \
+ })
+
+#endif
+
#endif /* _TESTS_H */
Matt Tyrlik
[-- Attachment #2: Type: text/html, Size: 4295 bytes --]
^ permalink raw reply
* Re: USB on MPC885 vs. MPC850/823
From: Scott Wood @ 2007-09-21 17:22 UTC (permalink / raw)
To: Wolfgang Grandegger; +Cc: linuxppc-embedded
In-Reply-To: <46F36C01.1040401@grandegger.com>
On Fri, Sep 21, 2007 at 09:00:17AM +0200, Wolfgang Grandegger wrote:
> I heard that the MPC885 has an improved USB hardware/firmware compared
> to the one on the rather old MPC823 or MPC850. Is it similar to the USB
> on the MPC8272? It would be nice, if somebody could shed some light on
> the usability and the support of USB in Linux for the MPC885 (or similar
> MPC8xx chips).
I don't think there's any support in Linux for CPM USB.
-Scott
^ permalink raw reply
* Re: [PATCH 08/10] bootwrapper: Add a firmware-independent "raw" target.
From: Grant Likely @ 2007-09-21 17:31 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <20070905192116.GH32113@ld0162-tx32.am.freescale.net>
On 9/5/07, Scott Wood <scottwood@freescale.com> wrote:
> This target produces a flat binary rather than an ELF file,
> fixes the entry point at the beginning of the image, and takes
> a complete device tree with no fixups needed.
>
> The device tree must have labels on /#address-cells, the timebase
> frequency, and the memory size.
>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
> index 02f0fe0..2a6a4c6 100644
> --- a/arch/powerpc/boot/Makefile
> +++ b/arch/powerpc/boot/Makefile
> @@ -48,7 +48,8 @@ src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
> cpm-serial.c stdlib.c planetcore.c
> src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
> cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
> - ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c cuboot-pq2.c
> + ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c \
> + cuboot-8xx.c cuboot-pq2.c fixed-head.S raw-platform.c
> src-boot := $(src-wlib) $(src-plat) empty.c
>
> src-boot := $(addprefix $(obj)/, $(src-boot))
> @@ -146,6 +147,7 @@ image-$(CONFIG_PPC_83xx) += cuImage.83xx
> image-$(CONFIG_PPC_85xx) += cuImage.85xx
> image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
> image-$(CONFIG_BAMBOO) += treeImage.bamboo
> +image-$(CONFIG_BUILD_RAW_IMAGE) += zImage.raw
> endif
>
> # For 32-bit powermacs, build the COFF and miboot images
Are these makefile changes complete? When I attempt to compile with
this patch I get the following error:
grant@trillian:~/hacking/linux-2.6$ ppc4xx make
CHK include/linux/version.h
CHK include/linux/utsrelease.h
CALL scripts/checksyscalls.sh
CHK include/linux/compile.h
make[1]: *** No rule to make target `arch/powerpc/boot/zImage.raw',
needed by `arch/powerpc/boot/zImage'. Stop.
make: *** [zImage] Error 2
grant@trillian:~/hacking/linux-2.6$
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: [PATCH 08/10] bootwrapper: Add a firmware-independent "raw" target.
From: Scott Wood @ 2007-09-21 17:33 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40709211031t687310fdk9ca703ea8cf759e7@mail.gmail.com>
On Fri, Sep 21, 2007 at 11:31:11AM -0600, Grant Likely wrote:
> Are these makefile changes complete? When I attempt to compile with
> this patch I get the following error:
>
> grant@trillian:~/hacking/linux-2.6$ ppc4xx make
> CHK include/linux/version.h
> CHK include/linux/utsrelease.h
> CALL scripts/checksyscalls.sh
> CHK include/linux/compile.h
> make[1]: *** No rule to make target `arch/powerpc/boot/zImage.raw',
> needed by `arch/powerpc/boot/zImage'. Stop.
> make: *** [zImage] Error 2
> grant@trillian:~/hacking/linux-2.6$
Odd... It should match the zImage.% target.
-Scott
^ permalink raw reply
* Re: 44x bug: funny TLB writes?
From: Hollis Blanchard @ 2007-09-21 17:37 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20070921054218.GA13470@localhost.localdomain>
On Fri, 2007-09-21 at 15:42 +1000, David Gibson wrote:
> On Thu, Sep 20, 2007 at 10:34:12PM -0500, Hollis Blanchard wrote:
> > I seem to have come across a strange bug while doing KVM development. It
> > seems that the final tlbwe in finish_tlb (head_44x.S) is actually
> > leaking RPN bits into the "attribute" word.
> >
> > When I set a breakpoint there and press enter on the serial console, I
> > see r12=ef600703, which is the physical address of the UART on this chip
> > (440EP), plus the correct permission bits at the bottom.
> >
> > Am I crazy? I'm not really looking to step through that assembly right
> > now... Clearly (current) hardware is just ignoring these errant writes,
> > but it should be fixed.
>
> A quick glance at the code suggests this is indeed wrong. Hurrah.
> Another reason to rewrite the 44x tlb miss handling.
Actually it's slightly worse than I thought. Not only are we setting "0"
bits in the TLB word, I'm also seeing mappings like this:
pid word0 word1 word2
00000001 7fe4f210 00209000 00200349
That means WIMG=0011, which seems inappropriate for userspace mappings.
(Oh and we're also writing to the only reserved bit in word2.)
--
Hollis Blanchard
IBM Linux Technology Center
^ permalink raw reply
* Re: DTC Patch for Cygwin
From: Scott Wood @ 2007-09-21 18:46 UTC (permalink / raw)
To: Matt Tyrlik; +Cc: linuxppc-dev, dwg
In-Reply-To: <OF485FF693.8CDC7B13-ON8525735D.00541A51-8525735D.0054C8B8@us.ibm.com>
On Fri, Sep 21, 2007 at 11:26:04AM -0400, Matt Tyrlik wrote:
>
> Changes required to compile DTC under Cygwin
>
> ===================================================================
> --- dtc-org.orig/tests/supernode_atdepth_offset.c
> +++ dtc-org/tests/supernode_atdepth_offset.c
> @@ -63,8 +63,11 @@ int path_prefix(const char *path, int de
> return 1;
>
> p = path;
> - for (i = 0; i < depth; i++)
> - p = strchrnul(p+1, '/');
> + for (i = 0; i < depth; i++) {
> + p = strchr(p+1, '/');
> + if (!p)
> + p = path + strlen(path);
> + }
>
> return p - path;
> }
Maybe we should define strchrnul under #ifndef GLIBC, similar to
strndupa?
> Index: dtc-org/tests/testutils.c
> ===================================================================
> --- dtc-org.orig/tests/testutils.c
> +++ dtc-org/tests/testutils.c
> @@ -52,10 +52,9 @@ static void sigint_handler(int signum, s
> void test_init(int argc, char *argv[])
> {
> int err;
> - struct sigaction sa_int = {
> - .sa_sigaction = sigint_handler,
> - };
> + struct sigaction sa_int;
>
> + sa_int.sa_sigaction = sigint_handler,
> test_name = argv[0];
What version of GCC does cygwin use? That doesn't seem like something
that should break due to OS differences.
-Scott
^ permalink raw reply
* Re: DTC Patch for Cygwin
From: Matt Tyrlik @ 2007-09-21 19:42 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, dwg
In-Reply-To: <20070921184639.GA23906@ld0162-tx32.am.freescale.net>
[-- Attachment #1: Type: text/plain, Size: 1733 bytes --]
>Scott Wood <scottwood@freescale.com> wrote on 09/21/2007 02:46:39 PM:
> On Fri, Sep 21, 2007 at 11:26:04AM -0400, Matt Tyrlik wrote:
> >
> > Changes required to compile DTC under Cygwin
> >
> > ===================================================================
> > --- dtc-org.orig/tests/supernode_atdepth_offset.c
> > +++ dtc-org/tests/supernode_atdepth_offset.c
> > @@ -63,8 +63,11 @@ int path_prefix(const char *path, int de
> > return 1;
> >
> > p = path;
> > - for (i = 0; i < depth; i++)
> > - p = strchrnul(p+1, '/');
> > + for (i = 0; i < depth; i++) {
> > + p = strchr(p+1, '/');
> > + if (!p)
> > + p = path + strlen(path);
> > + }
> >
> > return p - path;
> > }
>
> Maybe we should define strchrnul under #ifndef GLIBC, similar to
> strndupa?
Since this is used only in one place David Gibson suggested that the
change should be done in code.
>
> > Index: dtc-org/tests/testutils.c
> > ===================================================================
> > --- dtc-org.orig/tests/testutils.c
> > +++ dtc-org/tests/testutils.c
> > @@ -52,10 +52,9 @@ static void sigint_handler(int signum, s
> > void test_init(int argc, char *argv[])
> > {
> > int err;
> > - struct sigaction sa_int = {
> > - .sa_sigaction = sigint_handler,
> > - };
> > + struct sigaction sa_int;
> >
> > + sa_int.sa_sigaction = sigint_handler,
> > test_name = argv[0];
>
> What version of GCC does cygwin use? That doesn't seem like something
> that should break due to OS differences.
>
> -Scott
Currently 3.4.4. The compiler can't handle unnamed union in an
initializer.
Matt
[-- Attachment #2: Type: text/html, Size: 2720 bytes --]
^ permalink raw reply
* Re: [PATCH v2 2/4] Implement generic time of day clocksource for powerpc machines.
From: Tony Breeds @ 2007-09-21 21:35 UTC (permalink / raw)
To: Stephen Rothwell
Cc: linuxppc-dev, Thomas Gleixner, Paul Mackerras, Realtime Kernel
In-Reply-To: <20070921145212.7e8a7b89.sfr@canb.auug.org.au>
On Fri, Sep 21, 2007 at 02:52:12PM +1000, Stephen Rothwell wrote:
> Small comments.
Thanks.
> I think this is redundant as if __USE_RTC() is true, you register
> clocksource_rtc below.
Yup you're right.
> The #ifdef is redundant since if CONFIG_ISERIES is not set,
> firmware_has_feature(FW_FEATURE_ISERIES) is constant 0.
Ahh okay. I got too fancy for my own good.
patch comming.
Yours Tony
linux.conf.au http://linux.conf.au/ || http://lca2008.linux.org.au/
Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!
^ permalink raw reply
* Re: [PATCH v3 2/4] Implement generic time of day clocksource for powerpc machines.
From: Tony Breeds @ 2007-09-21 21:35 UTC (permalink / raw)
To: Stephen Rothwell
Cc: linuxppc-dev, Thomas Gleixner, Paul Mackerras, Realtime Kernel
In-Reply-To: <20070921145212.7e8a7b89.sfr@canb.auug.org.au>
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
---
Updated to create a clocksource driver specific to the 601
Updated to address feedback from sfr
Only compile tested.
arch/powerpc/Kconfig | 6
arch/powerpc/kernel/time.c | 255 ++++++++++++-------------------------
2 files changed, 91 insertions(+), 170 deletions(-)
Index: working/arch/powerpc/Kconfig
===================================================================
--- working.orig/arch/powerpc/Kconfig
+++ working/arch/powerpc/Kconfig
@@ -24,6 +24,12 @@ config MMU
config GENERIC_CMOS_UPDATE
def_bool y
+config GENERIC_TIME
+ def_bool y
+
+config GENERIC_TIME_VSYSCALL
+ def_bool y
+
config GENERIC_HARDIRQS
bool
default y
Index: working/arch/powerpc/kernel/time.c
===================================================================
--- working.orig/arch/powerpc/kernel/time.c
+++ working/arch/powerpc/kernel/time.c
@@ -73,9 +73,38 @@
#include <asm/iseries/hv_call_xm.h>
#endif
+/* powerpc clocksource/clockevent code */
+
+#include <linux/clocksource.h>
+
+static cycle_t rtc_read(void);
+static struct clocksource clocksource_rtc = {
+ .name = "rtc",
+ .rating = 400,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .mask = CLOCKSOURCE_MASK(64),
+ .shift = 22,
+ .mult = 0, /* To be filled in */
+ .read = rtc_read,
+};
+
+static cycle_t timebase_read(void);
+static struct clocksource clocksource_timebase = {
+ .name = "timebase",
+ .rating = 400,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .mask = CLOCKSOURCE_MASK(64),
+ .shift = 22,
+ .mult = 0, /* To be filled in */
+ .read = timebase_read,
+};
+
#ifdef CONFIG_PPC_ISERIES
static unsigned long __initdata iSeries_recal_titan;
static signed long __initdata iSeries_recal_tb;
+
+/* Forward declaration is only needed for iSereis compiles */
+void __init clocksource_init(void);
#endif
#define XSEC_PER_SEC (1024*1024)
@@ -343,65 +372,6 @@ void udelay(unsigned long usecs)
}
EXPORT_SYMBOL(udelay);
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-static inline void __do_gettimeofday(struct timeval *tv)
-{
- unsigned long sec, usec;
- u64 tb_ticks, xsec;
- struct gettimeofday_vars *temp_varp;
- u64 temp_tb_to_xs, temp_stamp_xsec;
-
- /*
- * These calculations are faster (gets rid of divides)
- * if done in units of 1/2^20 rather than microseconds.
- * The conversion to microseconds at the end is done
- * without a divide (and in fact, without a multiply)
- */
- temp_varp = do_gtod.varp;
-
- /* Sampling the time base must be done after loading
- * do_gtod.varp in order to avoid racing with update_gtod.
- */
- data_barrier(temp_varp);
- tb_ticks = get_tb() - temp_varp->tb_orig_stamp;
- temp_tb_to_xs = temp_varp->tb_to_xs;
- temp_stamp_xsec = temp_varp->stamp_xsec;
- xsec = temp_stamp_xsec + mulhdu(tb_ticks, temp_tb_to_xs);
- sec = xsec / XSEC_PER_SEC;
- usec = (unsigned long)xsec & (XSEC_PER_SEC - 1);
- usec = SCALE_XSEC(usec, 1000000);
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-
-void do_gettimeofday(struct timeval *tv)
-{
- if (__USE_RTC()) {
- /* do this the old way */
- unsigned long flags, seq;
- unsigned int sec, nsec, usec;
-
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- sec = xtime.tv_sec;
- nsec = xtime.tv_nsec + tb_ticks_since(tb_last_jiffy);
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- usec = nsec / 1000;
- while (usec >= 1000000) {
- usec -= 1000000;
- ++sec;
- }
- tv->tv_sec = sec;
- tv->tv_usec = usec;
- return;
- }
- __do_gettimeofday(tv);
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
/*
* There are two copies of tb_to_xs and stamp_xsec so that no
@@ -447,56 +417,6 @@ static inline void update_gtod(u64 new_t
++(vdso_data->tb_update_count);
}
-/*
- * When the timebase - tb_orig_stamp gets too big, we do a manipulation
- * between tb_orig_stamp and stamp_xsec. The goal here is to keep the
- * difference tb - tb_orig_stamp small enough to always fit inside a
- * 32 bits number. This is a requirement of our fast 32 bits userland
- * implementation in the vdso. If we "miss" a call to this function
- * (interrupt latency, CPU locked in a spinlock, ...) and we end up
- * with a too big difference, then the vdso will fallback to calling
- * the syscall
- */
-static __inline__ void timer_recalc_offset(u64 cur_tb)
-{
- unsigned long offset;
- u64 new_stamp_xsec;
- u64 tlen, t2x;
- u64 tb, xsec_old, xsec_new;
- struct gettimeofday_vars *varp;
-
- if (__USE_RTC())
- return;
- tlen = current_tick_length();
- offset = cur_tb - do_gtod.varp->tb_orig_stamp;
- if (tlen == last_tick_len && offset < 0x80000000u)
- return;
- if (tlen != last_tick_len) {
- t2x = mulhdu(tlen << TICKLEN_SHIFT, ticklen_to_xs);
- last_tick_len = tlen;
- } else
- t2x = do_gtod.varp->tb_to_xs;
- new_stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;
- do_div(new_stamp_xsec, 1000000000);
- new_stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;
-
- ++vdso_data->tb_update_count;
- smp_mb();
-
- /*
- * Make sure time doesn't go backwards for userspace gettimeofday.
- */
- tb = get_tb();
- varp = do_gtod.varp;
- xsec_old = mulhdu(tb - varp->tb_orig_stamp, varp->tb_to_xs)
- + varp->stamp_xsec;
- xsec_new = mulhdu(tb - cur_tb, t2x) + new_stamp_xsec;
- if (xsec_new < xsec_old)
- new_stamp_xsec += xsec_old - xsec_new;
-
- update_gtod(cur_tb, new_stamp_xsec, t2x);
-}
-
#ifdef CONFIG_SMP
unsigned long profile_pc(struct pt_regs *regs)
{
@@ -568,6 +488,8 @@ static int __init iSeries_tb_recal(void)
iSeries_recal_titan = titan;
iSeries_recal_tb = tb;
+ /* Called here as now we know accurate values for the timebase */
+ clocksource_init();
return 0;
}
late_initcall(iSeries_tb_recal);
@@ -650,7 +572,6 @@ void timer_interrupt(struct pt_regs * re
if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
tb_last_jiffy = tb_next_jiffy;
do_timer(1);
- timer_recalc_offset(tb_last_jiffy);
}
write_sequnlock(&xtime_lock);
}
@@ -722,66 +643,6 @@ unsigned long long sched_clock(void)
return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift;
}
-int do_settimeofday(struct timespec *tv)
-{
- time_t wtm_sec, new_sec = tv->tv_sec;
- long wtm_nsec, new_nsec = tv->tv_nsec;
- unsigned long flags;
- u64 new_xsec;
- unsigned long tb_delta;
-
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irqsave(&xtime_lock, flags);
-
- /*
- * Updating the RTC is not the job of this code. If the time is
- * stepped under NTP, the RTC will be updated after STA_UNSYNC
- * is cleared. Tools like clock/hwclock either copy the RTC
- * to the system time, in which case there is no point in writing
- * to the RTC again, or write to the RTC but then they don't call
- * settimeofday to perform this operation.
- */
-
- /* Make userspace gettimeofday spin until we're done. */
- ++vdso_data->tb_update_count;
- smp_mb();
-
- /*
- * Subtract off the number of nanoseconds since the
- * beginning of the last tick.
- */
- tb_delta = tb_ticks_since(tb_last_jiffy);
- tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */
- new_nsec -= SCALE_XSEC(tb_delta, 1000000000);
-
- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec);
- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec);
-
- set_normalized_timespec(&xtime, new_sec, new_nsec);
- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
- ntp_clear();
-
- new_xsec = xtime.tv_nsec;
- if (new_xsec != 0) {
- new_xsec *= XSEC_PER_SEC;
- do_div(new_xsec, NSEC_PER_SEC);
- }
- new_xsec += (u64)xtime.tv_sec * XSEC_PER_SEC;
- update_gtod(tb_last_jiffy, new_xsec, do_gtod.varp->tb_to_xs);
-
- vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
- vdso_data->tz_dsttime = sys_tz.tz_dsttime;
-
- write_sequnlock_irqrestore(&xtime_lock, flags);
- clock_was_set();
- return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
static int __init get_freq(char *name, int cells, unsigned long *val)
{
struct device_node *cpu;
@@ -873,6 +734,69 @@ unsigned long read_persistent_clock(void
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
+/* clocksource code */
+static cycle_t rtc_read(void)
+{
+ return (cycle_t)get_rtc();
+}
+
+static cycle_t timebase_read(void)
+{
+ return (cycle_t)get_tb();
+}
+
+void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
+{
+ u64 t2x, stamp_xsec;
+
+ if (clock != &clocksource_timebase)
+ return;
+
+ /* Make userspace gettimeofday spin until we're done. */
+ ++vdso_data->tb_update_count;
+ smp_mb();
+
+ /* XXX this assumes clock->shift == 22 */
+ /* 4611686018 ~= 2^(20+64-22) / 1e9 */
+ t2x = (u64) clock->mult * 4611686018ULL;
+ stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;
+ do_div(stamp_xsec, 1000000000);
+ stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;
+ update_gtod(clock->cycle_last, stamp_xsec, t2x);
+}
+
+void update_vsyscall_tz(void)
+{
+ /* Make userspace gettimeofday spin until we're done. */
+ ++vdso_data->tb_update_count;
+ smp_mb();
+ vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
+ vdso_data->tz_dsttime = sys_tz.tz_dsttime;
+ smp_mb();
+ ++vdso_data->tb_update_count;
+}
+
+void __init clocksource_init(void)
+{
+ struct clocksource *clock;
+
+ if (__USE_RTC())
+ clock = &clocksource_rtc;
+ else
+ clock = &clocksource_timebase;
+
+ clock->mult = clocksource_hz2mult(tb_ticks_per_sec, clock->shift);
+
+ if (clocksource_register(clock)) {
+ printk(KERN_ERR "clocksource: %s is already registered\n",
+ clock->name);
+ return;
+ }
+
+ printk(KERN_INFO "clocksource: %s mult[%x] shift[%d] registered\n",
+ clock->name, clock->mult, clock->shift);
+}
+
/* This function is only called on the boot processor */
void __init time_init(void)
{
@@ -982,6 +906,10 @@ void __init time_init(void)
write_sequnlock_irqrestore(&xtime_lock, flags);
+ /* Register the clocksource, if we're not running on iSeries */
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ clocksource_init();
+
/* Not exact, but the timer interrupt takes care of this */
set_dec(tb_ticks_per_jiffy);
}
^ permalink raw reply
* [PATCH v2] pcmcia: Convert io_req_t to use kio_addr_t
From: Olof Johansson @ 2007-09-21 22:15 UTC (permalink / raw)
To: Andrew Morton; +Cc: linuxppc-dev, linux-pcmcia, linux-kernel, hch
In-Reply-To: <20070914034854.1658a9cf.akpm@linux-foundation.org>
Convert the io_req_t members to kio_addr_t, to allow use on machines with
more than 16 bits worth of IO ports (i.e. secondary busses on ppc64, etc).
I've also gone through the drivers, changed the few occurrances of
ioaddr_t to kio_addr_t where relevant, and changed format strings for
printk() and friends.
There are still places where a kio_addr_t is casted to an int, but at
the moment that's not causing problems. It should be cleaned up at some
point in the future though.
Signed-off-by: Olof Johansson <olof@lixom.net>
---
On Fri, Sep 14, 2007 at 03:48:54AM -0700, Andrew Morton wrote:
> On Wed, 5 Sep 2007 09:27:43 -0500 Olof Johansson <olof@lixom.net> wrote:
>
> > Convert the io_req_t members to kio_addr_t, to allow use on machines with
> > more than 16 bits worth of IO port address space (ppc64 in this case,
> > but it applies to others as well).
>
> drivers/usb/host/sl811_cs.c: In function 'sl811_cs_config':
> drivers/usb/host/sl811_cs.c:263: warning: format '%04x' expects type 'unsigned int', but argument 2 has type 'kio_addr_t'
> drivers/usb/host/sl811_cs.c:263: warning: format '%04x' expects type 'unsigned int', but argument 3 has type 'long unsigned int'
>
> That's not just a cosmetic thing - the printk can print junk and if there's
> a %s in the control string after the %x's, printk() will crash.
>
> I don't know how many instances of this are in the tree, but they'll all
> need to be found and fixed.
I think I caught them all by now.
Thanks,
-Olof
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 4177f6d..b4f6036 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -308,7 +308,7 @@ static unsigned int calc_baudv(unsigned char fidi)
return (wcrcf / wbrcf);
}
-static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s)
+static unsigned short io_read_num_rec_bytes(kio_addr_t iobase, unsigned short *s)
{
unsigned short tmp;
@@ -426,7 +426,7 @@ static struct card_fixup card_fixups[] = {
static void set_cardparameter(struct cm4000_dev *dev)
{
int i;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ kio_addr_t iobase = dev->p_dev->io.BasePort1;
u_int8_t stopbits = 0x02; /* ISO default */
DEBUGP(3, dev, "-> set_cardparameter\n");
@@ -459,7 +459,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
unsigned short num_bytes_read;
unsigned char pts_reply[4];
ssize_t rc;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ kio_addr_t iobase = dev->p_dev->io.BasePort1;
rc = 0;
@@ -610,7 +610,7 @@ exit_setprotocol:
return rc;
}
-static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev)
+static int io_detect_cm4000(kio_addr_t iobase, struct cm4000_dev *dev)
{
/* note: statemachine is assumed to be reset */
@@ -671,7 +671,7 @@ static void terminate_monitor(struct cm4000_dev *dev)
static void monitor_card(unsigned long p)
{
struct cm4000_dev *dev = (struct cm4000_dev *) p;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ kio_addr_t iobase = dev->p_dev->io.BasePort1;
unsigned short s;
struct ptsreq ptsreq;
int i, atrc;
@@ -933,7 +933,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
loff_t *ppos)
{
struct cm4000_dev *dev = filp->private_data;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ kio_addr_t iobase = dev->p_dev->io.BasePort1;
ssize_t rc;
int i, j, k;
@@ -1054,7 +1054,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ kio_addr_t iobase = dev->p_dev->io.BasePort1;
unsigned short s;
unsigned char tmp;
unsigned char infolen;
@@ -1408,7 +1408,7 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct cm4000_dev *dev = filp->private_data;
- ioaddr_t iobase = dev->p_dev->io.BasePort1;
+ kio_addr_t iobase = dev->p_dev->io.BasePort1;
struct pcmcia_device *link;
int size;
int rc;
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index b24a3e7..3ecfc33 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -586,7 +586,7 @@ static int reader_config(struct pcmcia_device *link, int devno)
dev->node.minor = devno;
dev->node.next = &dev->node;
- DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno,
+ DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4lx-0x%.4lx\n", devno,
link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1);
DEBUGP(2, dev, "<- reader_config (succ)\n");
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 2b88931..7be068f 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -665,7 +665,7 @@ static int mgslpc_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
printk("\n");
return 0;
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index a5b941c..820853a 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -211,7 +211,7 @@ static int avmcs_config(struct pcmcia_device *link)
link->io.BasePort1 = cf->io.win[0].base;
link->io.NumPorts1 = cf->io.win[0].len;
link->io.NumPorts2 = 0;
- printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
+ printk(KERN_INFO "avm_cs: testing i/o %#lx-%#lx\n",
link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
i = pcmcia_request_io(link, &link->io);
@@ -288,7 +288,7 @@ found_port:
case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
}
if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
- printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
+ printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#lx, irq %d\n",
dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
avmcs_release(link);
return -ENODEV;
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index fc6cc2c..6a75ba6 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -233,7 +233,7 @@ static int avma1cs_config(struct pcmcia_device *link)
link->io.BasePort1 = cf->io.win[0].base;
link->io.NumPorts1 = cf->io.win[0].len;
link->io.NumPorts2 = 0;
- printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n",
+ printk(KERN_INFO "avma1_cs: testing i/o %#lx-%#lx\n",
link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1 - 1);
i = pcmcia_request_io(link, &link->io);
@@ -285,7 +285,7 @@ found_port:
return -ENODEV;
}
- printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
+ printk(KERN_NOTICE "avma1_cs: checking at i/o %#lx, irq %d\n",
link->io.BasePort1, link->irq.AssignedIRQ);
icard.para[0] = link->irq.AssignedIRQ;
@@ -295,7 +295,7 @@ found_port:
i = hisax_init_pcmcia(link, &busy, &icard);
if (i < 0) {
- printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1);
+ printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#lx\n", i, link->io.BasePort1);
avma1cs_release(link);
return -ENODEV;
}
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index db7e644..6d2b338 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -296,10 +296,10 @@ static int elsa_cs_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ printk(" & 0x%04lx-0x%04lx", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
printk("\n");
@@ -310,7 +310,7 @@ static int elsa_cs_config(struct pcmcia_device *link)
i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
if (i < 0) {
- printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#x\n",
+ printk(KERN_ERR "elsa_cs: failed to initialize Elsa PCMCIA %d at i/o %#lx\n",
i, link->io.BasePort1);
elsa_cs_release(link);
} else
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 439cb53..fdead4c 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -381,10 +381,10 @@ static int sedlbauer_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ printk(" & 0x%04lx-0x%04lx", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
if (link->win)
printk(", mem 0x%06lx-0x%06lx", req.Base,
@@ -398,7 +398,7 @@ static int sedlbauer_config(struct pcmcia_device *link)
last_ret = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->stop), &icard);
if (last_ret < 0) {
- printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n",
+ printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#lx\n",
last_ret, link->io.BasePort1);
sedlbauer_release(link);
return -ENODEV;
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index ab4bd45..e492bd2 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -286,10 +286,10 @@ static int teles_cs_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ printk(" & 0x%04lx-0x%04lx", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
printk("\n");
@@ -300,7 +300,7 @@ static int teles_cs_config(struct pcmcia_device *link)
i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
if (i < 0) {
- printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
+ printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#lx\n",
i, link->io.BasePort1);
teles_cs_release(link);
return -ENODEV;
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index ea9414c..f5351c0 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -259,7 +259,7 @@ static int com20020_config(struct pcmcia_device *link)
DEBUG(0, "com20020_config(0x%p)\n", link);
- DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
+ DEBUG(1,"arcnet: baseport1 is %lXh\n", link->io.BasePort1);
i = !CS_SUCCESS;
if (!link->io.BasePort1)
{
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index f123553..2a3544f 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -356,10 +356,10 @@ static int airo_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ printk(" & 0x%04lx-0x%04lx", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
if (link->win)
printk(", mem 0x%06lx-0x%06lx", req.Base,
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 30e723f..93c6b0b 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -721,10 +721,10 @@ static int prism2_config(struct pcmcia_device *link)
if (link->conf.Attributes & CONF_ENABLE_IRQ)
printk(", irq %d", link->irq.AssignedIRQ);
if (link->io.NumPorts1)
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ printk(" & 0x%04lx-0x%04lx", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
printk("\n");
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d1e5022..80bd2f6 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+ "0x%04lx-0x%04lx\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index af70460..b87185e 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+ "0x%04lx-0x%04lx\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 802a81d..17a4cfb 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -203,7 +203,7 @@ static int parport_config(struct pcmcia_device *link)
&link->dev);
if (p == NULL) {
printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
- "0x%3x, irq %u failed\n", link->io.BasePort1,
+ "0x%3lx, irq %u failed\n", link->io.BasePort1,
link->irq.AssignedIRQ);
goto failed;
}
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 0ce39de..585c14b 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -65,8 +65,8 @@ extern int ds_pc_debug;
* Special stuff for managing IO windows, because they are scarce
*/
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
- ioaddr_t num, u_int lines)
+static int alloc_io_space(struct pcmcia_socket *s, u_int attr, kio_addr_t *base,
+ kio_addr_t num, u_int lines)
{
int i;
kio_addr_t try, align;
@@ -74,14 +74,14 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
align = (*base) ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
if (*base) {
- ds_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
+ ds_dbg(s, 0, "odd IO request: num %#lx align %#lx\n",
num, align);
align = 0;
} else
while (align && (align < num)) align <<= 1;
}
if (*base & ~(align-1)) {
- ds_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
+ ds_dbg(s, 0, "odd IO request: base %#lx align %#lx\n",
*base, align);
align = 0;
}
@@ -132,8 +132,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
} /* alloc_io_space */
-static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
- ioaddr_t num)
+static void release_io_space(struct pcmcia_socket *s, kio_addr_t base,
+ kio_addr_t num)
{
int i;
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 4b82b20..42611e6 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -160,7 +160,7 @@ static int fdomain_config(struct pcmcia_device *link)
release_region(link->io.BasePort1, link->io.NumPorts1);
/* Set configuration options for the fdomain driver */
- sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
+ sprintf(str, "%ld,%d", link->io.BasePort1, link->irq.AssignedIRQ);
fdomain_setup(str);
host = __fdomain_16x0_detect(&fdomain_driver_template);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 445cfbb..7e9a897 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1896,11 +1896,11 @@ static int nsp_cs_config(struct pcmcia_device *link)
printk(", irq %d", link->irq.AssignedIRQ);
}
if (link->io.NumPorts1) {
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
}
if (link->io.NumPorts2)
- printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ printk(" & 0x%04lx-0x%04lx", link->io.BasePort2,
link->io.BasePort2+link->io.NumPorts2-1);
if (link->win)
printk(", mem 0x%06lx-0x%06lx", req.Base,
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 5da63f5..062fba6 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -259,7 +259,7 @@ next_entry:
if (link->conf.Vpp)
printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
printk(", irq %d", link->irq.AssignedIRQ);
- printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ printk(", io 0x%04lx-0x%04lx", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
printk("\n");
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index d5838c3..657d653 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -147,11 +147,11 @@ typedef struct config_req_t {
/* For RequestIO and ReleaseIO */
typedef struct io_req_t {
- ioaddr_t BasePort1;
- ioaddr_t NumPorts1;
+ kio_addr_t BasePort1;
+ kio_addr_t NumPorts1;
u_int Attributes1;
- ioaddr_t BasePort2;
- ioaddr_t NumPorts2;
+ kio_addr_t BasePort2;
+ kio_addr_t NumPorts2;
u_int Attributes2;
u_int IOAddrLines;
} io_req_t;
^ permalink raw reply related
* Re: [PATCH v2] pcmcia: Convert io_req_t to use kio_addr_t
From: Alan Cox @ 2007-09-21 22:39 UTC (permalink / raw)
To: Olof Johansson
Cc: linuxppc-dev, Andrew Morton, linux-pcmcia, linux-kernel, hch
In-Reply-To: <20070921221516.GA7926@lixom.net>
On Fri, 21 Sep 2007 17:15:16 -0500
Olof Johansson <olof@lixom.net> wrote:
> Convert the io_req_t members to kio_addr_t, to allow use on machines with
> more than 16 bits worth of IO ports (i.e. secondary busses on ppc64, etc).
What about the formatting and field widths ?
ulong would probably be a lot saner than kio_addr_t and yet more type
obfuscation.
Otherwise looks sensible to me
^ permalink raw reply
* [PATCH 0/15] bootwrapper: kexec and external payloads
From: Milton Miller @ 2007-09-21 23:02 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
The following series of 15 patches implement
support for 64-bit powerpc zImage to be loaded by kexec-tools
the wrapper uses the same startup interface as the kernel
support for obtaining the kernel externally to the zImage link
including via searching for a path string in initramfs
This is the third round of posting for most of the patches, which
have been rebased to apply to for-2.6.24, and I ask they be considered
for inclusion therein.
I have ordered the series to apply needed functionality to get
usable code for similar enviornments before fleshing out the feature
set I am using. If desired I can reorder and rediff as requested.
(for example, adding the smp hook could go with the smp marshalling
support). The last patch is only needed for the qemu pathes below.
Following the series are an additonal 2 patches to provide experimental
platform support for running under qemu with its exiting powerpc
prep emulation. One patch provides the support necessary to build
the kernel, the second patch provides the wrapper changes and device
tree to boot, including bulding a "rom" image. Once the rom is
built, it can start a vmlinux elf when loaded into memory by qemu.
Thanks for your consideration,
milton
^ permalink raw reply
* [PATCH 1/15] boot: find initrd location from device-tree
From: Milton Miller @ 2007-09-21 23:03 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Some platforms have a boot agent that can create or modify properties in
the device-tree and load images into memory. Provide a helper to set
loader_info used by prep_initrd().
Signed-off-by: Milton Miller <miltonm@bga.com>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
---
re 12168
rediffed types.h, offset in ops.h
Index: kernel/arch/powerpc/boot/ops.h
===================================================================
--- kernel.orig/arch/powerpc/boot/ops.h 2007-09-17 22:12:47.000000000 -0500
+++ kernel/arch/powerpc/boot/ops.h 2007-09-17 22:12:51.000000000 -0500
@@ -163,6 +163,7 @@ void dt_fixup_clock(const char *path, u3
void __dt_fixup_mac_addresses(u32 startindex, ...);
#define dt_fixup_mac_addresses(...) \
__dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+void dt_find_initrd(void);
static inline void *find_node_by_linuxphandle(const u32 linuxphandle)
Index: kernel/arch/powerpc/boot/types.h
===================================================================
--- kernel.orig/arch/powerpc/boot/types.h 2007-09-17 22:12:47.000000000 -0500
+++ kernel/arch/powerpc/boot/types.h 2007-09-17 22:12:51.000000000 -0500
@@ -12,6 +12,8 @@ typedef short s16;
typedef int s32;
typedef long long s64;
+#define UINT_MAX 0xFFFFFFFF
+
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
Index: kernel/arch/powerpc/boot/devtree.c
===================================================================
--- kernel.orig/arch/powerpc/boot/devtree.c 2007-09-17 22:12:47.000000000 -0500
+++ kernel/arch/powerpc/boot/devtree.c 2007-09-17 22:12:51.000000000 -0500
@@ -1,6 +1,7 @@
/*
* devtree.c - convenience functions for device tree manipulation
* Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright 2007 Milton Miller, IBM Corporation.
* Copyright (c) 2007 Freescale Semiconductor, Inc.
*
* Authors: David Gibson <david@gibson.dropbear.id.au>
@@ -333,3 +334,68 @@ int dt_is_compatible(void *node, const c
return 0;
}
+
+/**
+ * dt_find_initrd - set loader initrd location based on existing properties
+ *
+ * finds the linux,initrd-start and linux,initrd-end properties in
+ * the /chosen node and sets the loader initrd fields accordingly.
+ *
+ * Use this if your loader sets the properties to allow other code to
+ * relocate the tree and/or cause r3 and r4 to be set on true OF
+ * platforms.
+ */
+void dt_find_initrd(void)
+{
+ int rc;
+ unsigned long long initrd_start, initrd_end;
+ void *devp;
+ static const char start_prop[] = "linux,initrd-start";
+ static const char end_prop[] = "linux,initrd-end";
+
+ devp = finddevice("/chosen");
+ if (! devp) {
+ return;
+ }
+
+ rc = getprop(devp, start_prop, &initrd_start, sizeof(initrd_start));
+ if (rc < 0)
+ return; /* not found */
+ /* The properties had to be 8 bytes until 2.6.22 */
+ if (rc == sizeof(unsigned long)) {
+ unsigned long tmp;
+ memcpy(&tmp, &initrd_start, rc);
+ initrd_start = tmp;
+ } else if (rc != sizeof(initrd_start)) { /* now they can be 4 */
+ printf("unexpected length of %s in /chosen!\n\r", start_prop);
+ return;
+ }
+
+ rc = getprop(devp, end_prop, &initrd_end, sizeof(initrd_end));
+ if (rc < 0) {
+ printf("chosen has %s but no %s!\n\r", start_prop, end_prop);
+ return;
+ }
+ if (rc == sizeof(unsigned long)) {
+ unsigned long tmp;
+ memcpy(&tmp, &initrd_end, rc);
+ initrd_end = tmp;
+ } else if (rc != sizeof(initrd_end)) {
+ printf("unexpected length of %s in /chosen!\n\r", end_prop);
+ return;
+ }
+
+ /* Check for presence, ignore if (partially) loaded above 32 bits */
+ if (initrd_start == initrd_end) {
+ printf("ignoring empty device-tree supplied initrd\n");
+ } else if (initrd_start > initrd_end) {
+ printf("ignoring device-tree supplied initrd: start 0x%llx"
+ " > end 0x%llx \n", initrd_start, initrd_end);
+ } else if (initrd_end > UINT_MAX) {
+ printf("ignoring device-tree supplied initrd:"
+ " end 0x%llx > 32 bits\n", initrd_end);
+ } else {
+ loader_info.initrd_addr = initrd_start;
+ loader_info.initrd_size = initrd_end - initrd_start;
+ }
+}
^ permalink raw reply
* [PATCH 2/15] boot: record header bytes in gunzip_start
From: Milton Miller @ 2007-09-21 23:03 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Record the number of header bytes skipped in the total bytes read field.
This is needed for the initramfs parsing code to find the end of the zip file.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Identical to 12169
Index: kernel/arch/powerpc/boot/gunzip_util.c
===================================================================
--- kernel.orig/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:33:34.000000000 -0500
+++ kernel/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:40:59.000000000 -0500
@@ -78,6 +78,7 @@ void gunzip_start(struct gunzip_state *s
fatal("inflateInit2 returned %d\n\r", r);
}
+ state->s.total_in = hdrlen;
state->s.next_in = src + hdrlen;
state->s.avail_in = srclen - hdrlen;
}
^ permalink raw reply
* [PATCH 3/15] boot: simplfy gunzip_finish
From: Milton Miller @ 2007-09-21 23:03 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Call gunzip_partial to calculate the remaining length and copy the
data to the user buffer. This makes it shorter and reduces
duplication.
Signed-off-by: Milton Miller <miltonm@bga.com>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
---
identical content to 12170, removed extra space in change log
Index: kernel/arch/powerpc/boot/gunzip_util.c
===================================================================
--- kernel.orig/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:39:07.000000000 -0500
+++ kernel/arch/powerpc/boot/gunzip_util.c 2007-07-10 03:39:07.000000000 -0500
@@ -194,13 +194,10 @@ int gunzip_finish(struct gunzip_state *s
{
int len;
+ len = gunzip_partial(state, dst, dstlen);
+
if (state->s.workspace) {
- len = gunzip_partial(state, dst, dstlen);
zlib_inflateEnd(&state->s);
- } else {
- /* uncompressed image */
- len = min(state->s.avail_in, (unsigned)dstlen);
- memcpy(dst, state->s.next_in, len);
}
return len;
^ permalink raw reply
* [PATCH 4/15] bootwrapper: smp support code
From: Milton Miller @ 2007-09-21 23:03 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Support code to move cpus around, both a spin loop and c code to
move the cpus before uncompressing and copying the kernel to 0.
The low level code is designed to be included in a crt0 or other
assembly file because it may need to be at a fixed location or there
may be other entry point requirements.
Note: this code works with kernel head_64.S. head_6xx.S needs the
0x60 entry point (it currently mentions something at address 0xC0; but
the similar code is at 0xC4); the other heads don't appear to support
SMP.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
vs 12171
get barrier from io.h instead of adding to reg.h
rediff ops.h, Makefile
Index: kernel/arch/powerpc/boot/marshal_low.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/marshal_low.S 2007-09-17 22:13:14.000000000 -0500
@@ -0,0 +1,103 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "ppc_asm.h"
+
+ .text
+ /*
+ * This code is designed to be a kexec entry point block.
+ * That is, it has both code for the master cpu that begins
+ * at offset 0 as linked into the image, and a sequence of
+ * 0x100 bytes that, when copied to address 0, forms the
+ * wait loop for slave cpus. Each slave should have its
+ * unique hardware cpu identifier in r3 before entering
+ * this code.
+ */
+ .globl master
+master: b _zimage_start_plat
+
+ .global slave_wait
+slave_wait:
+ /* r3 cpu id, r4 slaves_wait, r5 cpu bit, r6 cpu mask word offset */
+
+ /* set our bit in the slaves mask */
+98: lwarx r7,r4,r6
+ or r8,r7,r5
+ stwcx. r8,r4,r6
+ bne 98b
+
+ and. r8,r7,r5
+ bnel- err_slave
+
+99: lwz r7,gohere-slave_wait(r4)
+ cmpwi 0,r7,0
+ beq 99b
+ mtctr r7
+ mr r4,r7
+ bctr
+
+
+ .global gohere
+gohere: .long 0 /* when set the slave moves */
+
+
+err_slave:
+ stw r5,slave_error-slave_wait(4) /* no locking */
+ blr
+
+ .globl slave_error /* set when slave detects error */
+slave_error:
+ .long 0
+
+ /*
+ * The slaves may be in 32 or 64 bit mode, we don't care
+ * r3 is the slave cpu number, matching the device tree.
+ */
+ .org master+0x60
+ .globl slave
+slave: bl 1f
+1: mflr r4
+ addi r4,r4,slave_wait-1b /* code assumes r4=slave_wait */
+ li r5,1
+ rlwnm r5,r5,r3,0,31 /* bit within word */
+ rlwinm r6,r3,32-5+2,4,29 /* word in array */
+ addi r6,r6,slaves-slave_wait /* relative to r4, slave_wait */
+ b slave_wait
+
+ .org master+0x80 /* put locked bitmask data in another line */
+ .global slaves
+slaves:
+
+ .globl slaves_end;
+slaves_end = 0f
+
+#if 0
+ /* today, the 32 bit kernel starts slaves at 0xc0
+ * but this limits us to cpu to 512 vs 1024
+ */
+ .org master+0xc0
+0: b slave
+#endif
+
+
+ .org master+0x100 /* we must fit in 0x100 bytes */
+0:
+
Index: kernel/arch/powerpc/boot/marshal.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/marshal.c 2007-09-17 22:13:14.000000000 -0500
@@ -0,0 +1,276 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "reg.h"
+#include "io.h"
+
+extern unsigned int gohere[], master[], slave_wait[], slaves[], slaves_end[];
+extern unsigned int slave_error[1];
+
+static unsigned int slaves_run_here[SMP_SLAVE_SIZE / sizeof(unsigned int)];
+static unsigned int *slaves_were_here = master;
+static unsigned int *slaves_goto_here = master;
+
+/**
+ * check_slave_errors - check if the slaves have set the error flag.
+ * @slaves_here ... the location that the slaves should be spinning.
+ */
+static void check_slave_errors(unsigned int *slaves_here)
+{
+ unsigned int *error = slave_error - master + slaves_here;
+
+ if (*error) {
+ printf("WARNING: error detected by one or more slave cpus!!\n\r"
+ "WARNING: This probably means you have duplicate cpu ids\n\r");
+ /* exit() */
+ }
+}
+
+/**
+ * wait_slaves_moved - wait for the slaves to catch up
+ *
+ * Wait until all slaves that checked in the previous location have
+ * checked into the current location. Seperate so we can do other
+ * work while we wait for them to catch up.
+ */
+void wait_slaves_moved(void)
+{
+ int offset = slaves - master;
+ int len = sizeof(slaves_end[0]) * (slaves_end - slaves);
+ int printed = 0;
+ unsigned int *to = slaves_goto_here;
+ unsigned int *from = slaves_were_here;
+
+ from += offset;
+ to += offset;
+
+ if (from == to)
+ return;
+
+ while (memcmp(from, to, len)) {
+ if (!printed) {
+ printf("waiting for slave cpus to move...");
+ printed = 1;
+ HMT_LOW;
+ barrier();
+ }
+ /* check from is superset of to */
+ }
+ if (printed) {
+ HMT_MEDIUM;
+ printf("done.\n\r");
+ }
+
+ slaves_were_here = slaves_goto_here;
+}
+
+/**
+ * move_slaves_here - move slaves to a specified address.
+ * @addr: location of %SMP_SLAVE_SIZE buffer to place code and spin
+ *
+ * Tell slaves to go from their current location to a buffer @addr
+ * of %SMP_SLAVE_SIZE bytes somewhere in memory.
+ */
+void move_slaves_here(void *addr)
+{
+ unsigned int *move_slaves_here = addr;
+ unsigned int *tell_them = gohere - master + slaves_goto_here;
+ unsigned int *goto_here = slave_wait - master + move_slaves_here;
+ unsigned int *wait_here = gohere - master + move_slaves_here;
+
+ if (move_slaves_here == slaves_goto_here)
+ return; /* already there */
+
+ wait_slaves_moved(); /* one move at a time */
+
+ printf("moving slave cpus from %p to %p\n\r", slaves_goto_here,
+ move_slaves_here);
+
+ memcpy(move_slaves_here, master, SMP_SLAVE_SIZE);
+ memset(move_slaves_here + (slaves - master), 0,
+ (slaves_end - slaves) * sizeof(slaves_end[0]));
+ *wait_here = 0;
+
+ flush_cache(move_slaves_here, SMP_SLAVE_SIZE);
+
+ check_slave_errors(slaves_were_here);
+
+ *tell_them = (unsigned int)goto_here;
+ slaves_goto_here = move_slaves_here;
+}
+
+/**
+ * move_slaves_up - move slaves from somewhere low to our bss.
+ * Call before decompressing the kernel to address 0.
+ */
+void move_slaves_up(void)
+{
+ move_slaves_here(slaves_run_here);
+}
+
+/**
+ * slaves_are_low - Assert that the slaves are spinning at 0, and move them
+ * Assert that the slaves are running in a copy of the marshall code
+ * that was copied to address 0. Ask them to go up to our bss, as we
+ * know we have to move them away from 0.
+ */
+void slaves_are_low(void)
+{
+ slaves_goto_here = slaves_were_here = (void *)0;
+ move_slaves_up();
+}
+
+/**
+ * wait_slave_checkout - wait for slaves to execute checkout store.
+ * @checkout - slave checkout flag array
+ *
+ * Wait for every slave who checked in at slaves_were_here to
+ * perform the stb to @checkout before the branch to self spin loop.
+ */
+static void wait_slave_checkout(char *checkout)
+{
+ unsigned int *end = slaves_end - master + slaves_were_here;
+ unsigned int *from = slaves - master + slaves_were_here;;
+ unsigned int bit;
+ int i, ncpus = 0;
+ char *waiting = "waiting on slaves to go to kernel...";
+
+ for (i=0; from < end; from++)
+ for (bit = 1; bit; i++, bit <<= 1)
+ if (*from & bit) {
+ ncpus++;
+ while (!checkout[i]) {
+ if (waiting) {
+ printf(waiting);
+ waiting = NULL;
+ }
+ HMT_LOW;
+ barrier();
+ }
+ }
+
+ if (waiting == NULL)
+ printf("done.\n\r");
+
+ printf("moved %d slaves to the kernel.\n\r", ncpus);
+}
+
+/* The slave checkin code ... used by checkout_slaves_to_kernel below */
+extern unsigned int slave_checkout_begin[], slave_checkout_spin[];
+asm ("\
+ .globl slave_checkout_begin ;\
+ .globl slave_checkout_spin ;\
+slave_checkout_begin: ;\
+ lwz 7,0(0) ;\
+ li 8,1 ;\
+ stbx 8,7,3 ;\
+slave_checkout_spin: ;\
+ b $ ;\
+");
+
+
+/**
+ * checkout_slaves_to_kernel - send SMP slaves to the kernel
+ * @tell_them - the expected marshalling buffer for the slaves
+ *
+ * Actively move slaves spinning on @tell_them to 0x60. Since we
+ * don't know what code is there, replace it with our one code that
+ * ends with a byte store and branch to self, with the branch at 0x60.
+ * After the stores complete, we can restore the rest of the line,
+ * flush, then restore the remaining line.
+ */
+static void checkout_slaves_to_kernel(unsigned int *tell_them)
+{
+ int to, spin;
+ unsigned int *from, *low, save[SMP_SLAVE_SIZE/sizeof(unsigned int)];
+ char *checkout;
+
+ checkout = malloc(1024);
+ if (checkout == NULL)
+ fatal("can't malloc slave checkout buffer");
+ memset(checkout, 0, 1024);
+
+ low = (unsigned int *)0;
+ memcpy(save, low, SMP_SLAVE_SIZE);
+
+ to = spin = 0x60 / sizeof(int);
+
+ to++;
+ from = slave_checkout_spin;
+ while (from >= slave_checkout_begin)
+ low[--to] = *from--;
+
+ low[0] = (unsigned int)checkout;
+ flush_cache(low, SMP_SLAVE_SIZE);
+
+ *tell_them = (unsigned int)(low + to);
+
+ wait_slave_checkout(checkout);
+
+ /* at this point, all have completed the store at %0x5c and are at
+ * the branch to self at %0x60. Restore the rest of the vector,
+ * flush cache, then do the final store replacing the spin and
+ * flush again.
+ */
+ low[0] = save[0];
+ for (;to < spin; to++)
+ low[to] = save[to];
+ flush_cache(low, SMP_SLAVE_SIZE);
+ low[to] = save[to];
+ flush_cache(low, SMP_SLAVE_SIZE);
+
+}
+
+/**
+ * send_slaves_to_kernel - send SMP slaves to the kernel
+ * @vmlinux_addr: address vmlinux was decompressed to (where to get slave loop)
+ *
+ * Send slaves currently running in the marshalling system to the slave code
+ * in the next kernel which has been uncompressed at address @vmlinux_addr.
+ * Copies the first %SMP_SLAVE_SIZE bytes of the image to address %0 and
+ * then tells the slaves to go to %0x60.
+ */
+void send_slaves_to_kernel(void *vmlinux_addr)
+{
+ unsigned int *tell_them = gohere - master + slaves_goto_here;
+
+ if ((unsigned long)slaves_goto_here < SMP_SLAVE_SIZE) {
+ if ((unsigned long)vmlinux_addr < SMP_SLAVE_SIZE)
+ fatal("ERROR: slaves were not marshaled before "
+ "decompressing the kernel to 0!\n");
+ move_slaves_up();
+ send_slaves_to_kernel(vmlinux_addr);
+ return;
+ }
+
+ wait_slaves_moved();
+
+ if (vmlinux_addr) {
+ memcpy((void *)0, vmlinux_addr, SMP_SLAVE_SIZE);
+ flush_cache((void *)0, SMP_SLAVE_SIZE);
+ } else {
+ printf("kernel was decompressed to 0\n\r");
+ }
+ check_slave_errors(slaves_goto_here);
+
+ checkout_slaves_to_kernel(tell_them);
+}
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2007-09-17 22:12:41.000000000 -0500
+++ kernel/arch/powerpc/boot/Makefile 2007-09-17 22:13:14.000000000 -0500
@@ -42,6 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
+ marshal.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
Index: kernel/arch/powerpc/boot/reg.h
===================================================================
--- kernel.orig/arch/powerpc/boot/reg.h 2007-09-17 22:12:41.000000000 -0500
+++ kernel/arch/powerpc/boot/reg.h 2007-09-17 22:13:14.000000000 -0500
@@ -19,4 +19,8 @@ static inline u32 mfpvr(void)
register void *__stack_pointer asm("r1");
#define get_sp() (__stack_pointer)
+#define HMT_MEDIUM asm volatile("or 2,2,2")
+#define HMT_LOW asm volatile("or 1,1,1")
+
+
#endif /* _PPC_BOOT_REG_H */
Index: kernel/arch/powerpc/boot/ops.h
===================================================================
--- kernel.orig/arch/powerpc/boot/ops.h 2007-09-17 22:12:51.000000000 -0500
+++ kernel/arch/powerpc/boot/ops.h 2007-09-17 22:13:14.000000000 -0500
@@ -18,6 +18,7 @@
#define COMMAND_LINE_SIZE 512
#define MAX_PATH_LEN 256
#define MAX_PROP_LEN 256 /* What should this be? */
+#define SMP_SLAVE_SIZE 256 /* Size of SMP slave block, kexec/kernel */
typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5);
@@ -86,7 +87,13 @@ int mpsc_console_init(void *devp, struct
int cpm_console_init(void *devp, struct serial_console_data *scdp);
void *simple_alloc_init(char *base, unsigned long heap_size,
unsigned long granularity, unsigned long max_allocs);
-extern void flush_cache(void *, unsigned long);
+void flush_cache(void *, unsigned long);
+void move_slaves_up(void);
+void move_slaves_here(void *where);
+void send_slaves_to_kernel(void *vmlinux_addr);
+void slaves_are_low(void);
+void wait_slaves_moved(void);
+
int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
int dt_is_compatible(void *node, const char *compat);
^ permalink raw reply
* [PATCH 5/15] bootwrapper: occuppied memory ranges
From: Milton Miller @ 2007-09-21 23:04 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Add a set of library routines to manage gross memory allocations.
This code uses an array in bss to store upto 32 entrys with merging
representing a range of memory below rma_end (aka end of real mode
memory at 0).
To use this code, a platform would set rma_end (find_rma_end), mark
memory ranges occupied (add_known_ranges et al), initialize malloc in
the spaces between (ranges_init_malloc), and optionally use the supplied
vmlinux_alloc may be used.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
vs 12172
rename rmo_end to rma_end (real mode area, as used in papr)
removed section labels (now in ops.h)
rediff ops.h, Makefile
moved find_rma_end here (from kexec.c in a later patch)
find_rma_end searches by node type for "memory", checks that
the parent is the root node, then looks for a reg property
with the first address/size pair starting at 0.
Index: kernel/arch/powerpc/boot/memranges.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/memranges.c 2007-09-20 17:51:42.000000000 -0500
@@ -0,0 +1,299 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation 2007
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "flatdevtree.h"
+#include "page.h"
+#include "types.h"
+
+void *rma_end;
+
+static struct {
+ void *start, *end;
+} ranges[32];
+static int num_ranges;
+
+/**
+ * find_rma_end - find end of Real Mode Area
+ * Query the device tree to find the node of type memory that contains a
+ * reg starting with address 0, and update rma_end to point to the end
+ * of that region. On PAPR systems, only this RMA region is accessable
+ * in real mode.
+ */
+void find_rma_end(void)
+{
+ unsigned int na, ns, reg[4], *rp; char path[MAX_PATH_LEN];
+ void *devp, *root; int rc;
+
+ path[0] = '\0';
+ root = finddevice("/");
+ if (!root)
+ fatal("Ack, can't get device-tree root");
+ rc = getprop(root, "#address-cells", &na, sizeof(na));
+ if (rc != sizeof(na))
+ fatal("Ack, no #address-cells in root");
+ rc = getprop(root, "#size-cells", &ns, sizeof(ns));
+ if (rc != sizeof(ns))
+ fatal("Ack, no #size-cells in root");
+ if (!na || !ns || na < 1 || na > 2 || ns < 1 || ns > 2)
+ fatal("find_rma_end: / #addr-cells or #size-cells unsupported");
+
+ devp = NULL;
+ while ((devp = find_node_by_devtype(devp, "memory"))) {
+ if (root != get_parent(devp)) {
+ printf("Ignoring memory node %s"
+ " --- not a child of root\n\r",
+ get_path(devp, path, sizeof(path)));
+ continue;
+ }
+ rc = getprop(devp, "reg", reg, sizeof(reg));
+ if (rc < (na + ns) * sizeof(int)) {
+ printf("No valid reg property in memory node %s\n\r",
+ get_path(devp, path, sizeof(path)));
+ continue;
+ }
+ /* find the node where the first reg entry starts at 0 */
+ rp = ®[0];
+ if (*rp++)
+ continue;
+ if (na > 1 && *rp++)
+ continue;
+
+ /* if >4G, limit it */
+ if (ns > 1 && *rp++) {
+ rma_end = (void *)0xFFFFFFFF;
+ return;
+ }
+
+ /* other wise use its size */
+ rma_end = (void *)*rp;
+ return;
+ }
+ fatal("find_rma_end: didn't find memory at 0\n\r");
+}
+
+/**
+ * add_occupied_range - mark a range as occupied
+ * @start: start of range pointer
+ * @end: end of range pointer
+ *
+ * Mark the range from @start to @end as occupied.
+ * Ignore anything above rma_end.
+ */
+void add_occupied_range(void *start, void *end)
+{
+ int i, j;
+
+ if (start == end)
+ return;
+ if (start > rma_end)
+ return;
+ if (end > rma_end)
+ end = rma_end;
+ if (start > end)
+ fatal("%s: BUG: start %p > end %p\n\r", __FUNCTION__,
+ start, end);
+
+ printf("add %p %p: ", start, end);
+
+ for (i=0; i < num_ranges; i++)
+ if (start <= ranges[i].end)
+ break;
+
+ /* extend and merge any overlapping ranges */
+ if (i < num_ranges && end >= ranges[i].start) {
+ ranges[i].start = min(start, ranges[i].start);
+ for (j=i; j < num_ranges; j++)
+ if (end >= ranges[j].start)
+ end = max(end, ranges[j].end);
+ else
+ break;
+ ranges[i].end = end;
+
+ if (j == i + 1) {
+ printf("extending range %d to %p %p\n\r", i,
+ ranges[i].start, ranges[i].end);
+ } else {
+ printf("merged ranges %d to %d now %p %p\n\r", i, j,
+ ranges[i].start, ranges[i].end);
+
+ ++i;
+ memmove(&ranges[i], &ranges[j],
+ (num_ranges - j) * sizeof(ranges[0]));
+ num_ranges -= j-i;
+ }
+ } else {
+ /* insert a new range */
+ if (num_ranges >= ARRAY_SIZE(ranges) - 1)
+ fatal("Too many memory ranges to track\n");
+
+ printf("inserting range %d between %p and %p\n\r",
+ i, i ? ranges[i-1].end : 0,
+ i == num_ranges ? rma_end : ranges[i].start);
+
+ memmove(&ranges[i+1], &ranges[i],
+ (num_ranges - i) * sizeof(ranges[0]));
+ num_ranges++;
+
+ ranges[i].start = start;
+ ranges[i].end = end;
+ }
+}
+
+/**
+ * add_occupied_range_ulong - mark a range as occupied
+ * @start: start of block to occupy
+ * @end: start of block to occupy
+ *
+ * Call add_occupied_range() after casting to ulong @start and @end to
+ * void * pointers.
+ */
+void add_occupied_range_ulong(unsigned long start, unsigned long end)
+{
+ add_occupied_range((void *)start, (void *)end);
+}
+
+/**
+ * add_known_ranges - occupy some known regions
+ * @dt_blob: a flattend device tree to occupy, or NULL to skip
+ *
+ * call add_occupied_range() for the wrapper, loader supplied initrd,
+ * and, if not %NULL, the device tree blob @dt_blob and any reserved
+ * memory ranges therein.
+ */
+void add_known_ranges(struct boot_param_header *dt_blob)
+{
+ unsigned long long rstart, rlen, rend, *rsrv;
+
+ add_occupied_range(_start, _end);
+
+ add_occupied_range_ulong(loader_info.initrd_addr,
+ loader_info.initrd_addr + loader_info.initrd_size);
+
+ if (dt_blob == NULL)
+ return;
+
+ add_occupied_range(dt_blob, (void *)dt_blob + dt_blob->totalsize);
+
+ /* only support 8-byte reserve map. Only care about < 4G */
+ rsrv = (void *)dt_blob + dt_blob->off_mem_rsvmap;
+ do {
+ rstart = *rsrv++;
+ rlen = *rsrv++;
+ rend = rstart + rlen;
+
+ if (rlen && rstart < UINT_MAX) {
+ if (rend < UINT_MAX)
+ add_occupied_range_ulong(rstart, rend);
+ else
+ add_occupied_range_ulong(rstart, UINT_MAX);
+ }
+ } while (rlen);
+}
+
+/**
+ * ranges_init_malloc - initialize malloc heap in a free memory range.
+ *
+ * Call simple_alloc_init using the largest gap between occupied ranges.
+ * Does not consider before the first or after the last range.
+ */
+void ranges_init_malloc(void)
+{
+ int i;
+ unsigned long size = 0;
+ void *heap_start, *heap_end;
+
+ /*
+ * Allow the beginning for the kernel and the end for
+ * other things the platform might want to have reserved.
+ */
+
+ heap_start = NULL; /* avoid gcc warning */
+ for (i=1; i < num_ranges; i++) {
+ unsigned long newsize;
+
+ newsize = ranges[i].start - ranges[i-1].end;
+ if (newsize > size) {
+ size = newsize;
+ heap_start = ranges[i-1].end;
+ }
+ }
+
+ if (size < 4 * 1024 * 1024)
+ fatal("Can't find a sutiable gap (largest 0x%lx)", size);
+
+ printf("putting heap between %p and %p size 0x%lx\n\r", heap_start,
+ heap_start + size, size);
+ heap_end = simple_alloc_init(heap_start, size * 7 / 8,
+ PAGE_SIZE, /* max num alloc */ 4096);
+ if (heap_end > (heap_start + size))
+ fatal("heap alloc overflowed gap (%p)\n\r", heap_end);
+
+ add_occupied_range(heap_start, heap_end);
+}
+
+/**
+ * ranges_vmlinux_alloc - an optonal kernel allocator.
+ * @size: the image size of the kernel
+ *
+ * Searches for a location to put the kernel, then reserve that range
+ * and the area to which the kernel will relocate itself. First try
+ * address %0. If that is blocked by a previos call to add_occupied_range(),
+ * try malloc(). If that also fails search for free space between the
+ * occupied ranges or between the last range and rma_end.
+ */
+void *ranges_vmlinux_alloc(unsigned long size)
+{
+ void *addr;
+ int i;
+
+ /* Assume _start to _end is occupied */
+ addr = (void *)0;
+ if (addr + size < ranges[0].start)
+ goto occupy;
+
+ addr = malloc(size);
+ if (addr)
+ goto out;
+
+ for (i=1; i < num_ranges; i++) {
+ if (size < ranges[i].start - ranges[i-1].end)
+ goto occupy_range;
+ }
+ if (size < rma_end - ranges[i-1].end)
+ goto occupy_range;
+
+ fatal("Unable to find a 0x%lx byte gap for the kernel\n", size);
+
+occupy_range:
+ addr = ranges[i-1].end;
+occupy:
+ add_occupied_range(addr, addr + size);
+out:
+ /*
+ * Assume the kernel will decompress to 0, but don't implicity
+ * create a new gap below the current first range.
+ */
+ if ((unsigned long)ranges[0].end < size)
+ add_occupied_range_ulong(0, size);
+
+ return addr;
+}
Index: kernel/arch/powerpc/boot/ops.h
===================================================================
--- kernel.orig/arch/powerpc/boot/ops.h 2007-09-17 22:13:14.000000000 -0500
+++ kernel/arch/powerpc/boot/ops.h 2007-09-20 17:51:18.000000000 -0500
@@ -22,6 +22,8 @@
typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5);
+struct boot_param_header;
+
/* Platform specific operations */
struct platform_ops {
void (*fixups)(void);
@@ -99,6 +101,15 @@ int dt_xlate_addr(void *node, u32 *buf,
int dt_is_compatible(void *node, const char *compat);
void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize);
+/* memory ranges */
+extern void *rma_end;
+void add_occupied_range(void *start, void *end);
+void add_occupied_range_ulong(unsigned long start, unsigned long end);
+void add_known_ranges(struct boot_param_header *dt_blob);
+void find_rma_end(void);
+void ranges_init_malloc(void);
+void *ranges_vmlinux_alloc(unsigned long size);
+
static inline void *finddevice(const char *name)
{
return (dt_ops.finddevice) ? dt_ops.finddevice(name) : NULL;
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2007-09-17 22:13:14.000000000 -0500
+++ kernel/arch/powerpc/boot/Makefile 2007-09-20 17:51:18.000000000 -0500
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- marshal.c \
+ marshal.c memranges.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
^ permalink raw reply
* [PATCH 6/15] bootwrapper: help for 64 bit cpus
From: Milton Miller @ 2007-09-21 23:04 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Add code to check if the processor is in 64 or 32 bit mode using
only instructions from the 32 bit subset. If the processor is in
64 bit mode, switch to 32 bit mode by clearing MSR[SF].
Also add a 64 bit procedure descriptor to use as a elf64 entry
point.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
vs 12173
correct comment (equal vs not-equal)
Index: kernel/arch/powerpc/boot/crt0.S
===================================================================
--- kernel.orig/arch/powerpc/boot/crt0.S 2007-07-10 03:33:36.000000000 -0500
+++ kernel/arch/powerpc/boot/crt0.S 2007-07-10 03:39:08.000000000 -0500
@@ -17,11 +17,47 @@
_zimage_start_opd:
.long _zimage_start, 0, 0, 0
+ /* a procedure descriptor used when pretending to be elf64_powerpc */
+ .balign 8
+ .globl _zimage_start_64
+_zimage_start_64:
+ .long 0, _zimage_start /* big endian, supported reloc ppc32 */
+ .long 0, 0, 0, 0, 0, 0
+
+
.weak _zimage_start
.globl _zimage_start
_zimage_start:
.globl _zimage_start_lib
_zimage_start_lib:
+ /* Check if the processor is running in 32 bit mode, using
+ * only 32 bit instructions which should be safe on 32 and
+ * 64 bit processors.
+ *
+ * Subtract bottom 32 bits of MSR from full value recording
+ * the result. Since MSR[SF] is in the high word, we will
+ * be equal iff in 32 bit mode (either the processor is
+ * a 32 bit processor or MSR[SF] = 0).
+ */
+ mfmsr r0 /* grab whole msr */
+ rlwinm r8,r0,0,0,31 /* extract bottom word */
+ subf. r8,r8,r0 /* subtract, same? */
+ beq 0f /* yes: we are 32 bit mode */
+
+ /* We are in 64-bit mode. This program must run in 32 bit
+ * mode. Assume we are actually running somewhere in the
+ * low 32 bits of the address space, so we can just turn
+ * off MSR[SF] which is bit 0.
+ */
+ .machine push
+ .machine "ppc64"
+ rldicl r0,r0,0,1
+ sync
+ mtmsrd r0
+ isync
+ .machine pop
+0: /* We are now in 32-bit mode */
+
/* Work out the offset between the address we were linked at
and the address where we're running. */
bl 1f
^ permalink raw reply
* [PATCH 7/15] bootwrapper: Add kexec callable zImage wrapper
From: Milton Miller @ 2007-09-21 23:04 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
This code creates a 32 bit zImage wrapper for a 32 or 64 bit PowerPC
Linux kernel. This allows you to kexec a zImage with its compressed
vmlinux instead of the uncompressed vmlinux elf. The code is also
packaged as a 64 bit elf for use by kexec-tools on 64 bit kernels.
Limitations:
Note: the device-tree generated by kexec-tools is currently version 2,
not the version 16 supported by the boot code base.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
find_rmo_end moved to memranges as find_rma_end.
early_scan_flat_tree replaced with calls to its pieces in
kexec_platform_init
rediff wrapper, Makefile, ops.h
Index: kernel/arch/powerpc/boot/kexec.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/kexec.c 2007-09-21 04:52:46.000000000 -0500
@@ -0,0 +1,122 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation 2007
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "flatdevtree.h"
+#include "page.h"
+#include "types.h"
+
+extern char _start[];
+extern char _end[];
+
+BSS_STACK(16*1024);
+
+static void find_console_from_tree(void)
+{
+ int rc = -1;
+
+ if (rc) {
+ /* no console, oh well */
+ }
+}
+
+/**
+ * setup_initial_heap - setup a small heap in the bss
+ * Using a preallocated heap, setup for scanning the device tree.
+ * Intended for the initial read while the tree will remain read-only so
+ * a minimal malloc and search limit can be used. This way we don't have
+ * lots of data or bss to clear.
+ */
+static void setup_initial_heap(void)
+{
+ static char initial_heap[8*1024];
+ void *heap_end;
+
+ heap_end = simple_alloc_init(initial_heap,
+ sizeof(initial_heap) * 7 / 8,
+ sizeof(long), 64);
+
+ if (heap_end - sizeof(initial_heap) > (void *)&initial_heap[0])
+ fatal("Initial heap too big\n\r");
+}
+
+static void init_flat_tree(struct boot_param_header *dt_blob)
+{
+ int rc;
+
+ rc = ft_init(dt_blob, dt_blob->totalsize, /* max_finddevice */ 1024);
+ if (rc)
+ fatal("Unable to initialize device_tree library!\n\r");
+}
+
+static void *saved_vmlinux_addr;
+
+static void *kexec_vmlinux_alloc(unsigned long size)
+{
+ void *addr;
+
+ addr = ranges_vmlinux_alloc(size);
+
+ saved_vmlinux_addr = addr;
+ return addr;
+}
+
+static void kexec_fixups(void)
+{
+ wait_slaves_moved();
+}
+
+static unsigned long (*finalize_chain)(void);
+
+static unsigned long kexec_finalize(void)
+{
+ send_slaves_to_kernel(saved_vmlinux_addr);
+
+ return finalize_chain();
+}
+
+void kexec_platform_init(struct boot_param_header *dt_blob)
+{
+ slaves_are_low();
+ move_slaves_up();
+
+ setup_initial_heap();
+ init_flat_tree(dt_blob);
+ /*
+ * drivers can malloc and read the tree, but not realloc later
+ * or modify the tree now.
+ */
+ if (!console_ops.write)
+ find_console_from_tree();
+
+ find_rma_end();
+ dt_find_initrd();
+ add_known_ranges(dt_blob);
+ ranges_init_malloc();
+
+ /* now that we have a malloc region, start over from the flat tree */
+ init_flat_tree(dt_blob);
+
+ platform_ops.vmlinux_alloc = kexec_vmlinux_alloc;
+ platform_ops.fixups = kexec_fixups;
+ finalize_chain = dt_ops.finalize;
+ dt_ops.finalize = kexec_finalize;
+}
Index: kernel/arch/powerpc/boot/crt0_kexec.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/crt0_kexec.S 2007-09-21 04:52:46.000000000 -0500
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+ /*
+ * The kernel calls out to the first image with
+ * r3 = boot cpu, r4 = entrypoint, r5 = 0
+ *
+ * kexec-tools purgatory calls this as it would a linux kernel:
+ * r3 = boot block, r4 = entrypoint, r5 = 0
+ *
+ * The boot block boot_cpu field has been filled in.
+ *
+ * kexec-tools and its purgatory are suppposed to copy SMP_SLAVE_SIZE
+ * bytes from the from entry point, but aparently instead it copies
+ * from the image start.
+ */
+ .globl _zimage_start
+_zimage_start:
+
+#include "marshal_low.S"
+
+ .globl _zimage_start_plat
+_zimage_start_plat:
+ b _zimage_start_lib
+
+ .globl platform_init
+platform_init:
+ b kexec_platform_init
Index: kernel/arch/powerpc/boot/wrapper
===================================================================
--- kernel.orig/arch/powerpc/boot/wrapper 2007-09-21 04:51:31.000000000 -0500
+++ kernel/arch/powerpc/boot/wrapper 2007-09-21 04:52:46.000000000 -0500
@@ -133,6 +133,12 @@ coff)
platformo=$object/of.o
lds=$object/zImage.coff.lds
;;
+kexec)
+ platformo=$object/crt0_kexec.o
+ ;;
+kexec64)
+ platformo="-e _zimage_start_64 $object/crt0_kexec.o"
+ ;;
miboot|uboot)
# miboot and U-boot want just the bare bits, not an ELF binary
ext=bin
@@ -190,6 +196,9 @@ uboot)
fi
exit 0
;;
+kexec64)
+ ${CROSS}objcopy -O elf64-powerpc $ofile
+ ;;
esac
addsec() {
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2007-09-21 04:52:44.000000000 -0500
+++ kernel/arch/powerpc/boot/Makefile 2007-09-21 04:52:46.000000000 -0500
@@ -42,12 +42,12 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- marshal.c memranges.c \
+ marshal.c memranges.c kexec.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
cpm-serial.c stdlib.c
-src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
+src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c crt0_kexec.S \
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c
@@ -128,6 +128,9 @@ quiet_cmd_wrap = WRAP $@
cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
$(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux
+kexec-$(CONFIG_PPC32) += zImage.kexec
+kexec-$(CONFIG_PPC64) += zImage.kexec64
+
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
@@ -140,6 +143,7 @@ image-$(CONFIG_PPC_HOLLY) += zImage.hol
image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800
image-$(CONFIG_PPC_ISERIES) += zImage.iseries
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
+image-$(CONFIG_KEXEC) += $(kexec-y)
ifneq ($(CONFIG_DEVICE_TREE),"")
image-$(CONFIG_PPC_8xx) += cuImage.8xx
@@ -158,7 +162,7 @@ ifeq ($(CONFIG_PPC32),y)
image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
endif
-initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
+initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-) $(kexec-))
initrd-y := $(patsubst zImage%, zImage.initrd%, \
$(patsubst treeImage%, treeImage.initrd%, $(image-y)))
initrd-y := $(filter-out $(image-y), $(initrd-y))
@@ -227,7 +231,7 @@ install: $(CONFIGURE) $(addprefix $(obj)
# anything not in $(targets)
clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* treeImage.* \
- otheros.bld
+ otheros.bld $(kexec-)
# clean up files cached by wrapper
clean-kernel := vmlinux.strip vmlinux.bin
Index: kernel/arch/powerpc/boot/ops.h
===================================================================
--- kernel.orig/arch/powerpc/boot/ops.h 2007-09-21 04:52:44.000000000 -0500
+++ kernel/arch/powerpc/boot/ops.h 2007-09-21 04:52:46.000000000 -0500
@@ -95,6 +95,7 @@ void move_slaves_here(void *where);
void send_slaves_to_kernel(void *vmlinux_addr);
void slaves_are_low(void);
void wait_slaves_moved(void);
+void kexec_platform_init(struct boot_param_header *dt_blob);
int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
^ permalink raw reply
* [PATCH 8/15] bootwrapper: convert flatdevtree to version 16
From: Milton Miller @ 2007-09-21 23:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
kexec-tools still produces a version 2 device tree, while the
libraries in the wrapper only support version 16 and later.
Add a routine to convert a v2 flat device tree to a v16 one inplace
by inserting OF_DT_NOP and chomping full path. Make space for new
headers by moving and then chomping the OF_DT_NOPs.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
vs 12175
Rediffed Makefile, ops, kexec.c
Index: kernel/arch/powerpc/boot/flatdevtree_conv.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/flatdevtree_conv.c 2007-09-20 17:49:04.000000000 -0500
@@ -0,0 +1,280 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation 2007
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ */
+#include "flatdevtree.h"
+#include "stdio.h"
+#include "ops.h"
+
+#define MIN_VERSION 2
+#define OUT_VERSION 16
+#define OUT_COMPAT 16
+
+#ifdef NO_CHECK
+static int check_v123_tree(u32 *start, u32 *limit)
+{
+ return 0;
+}
+#else
+/**
+ * check_v123_tree - check integrety of a version 1, 2, or 3 tree
+ * @start: the start of the device tree struct
+ * @limit: the end of the region for the struct
+ * structural checks on device_tree
+ */
+static int check_v123_tree(u32 *start, u32 *limit)
+{
+ u32 len;
+ int depth = 0;
+ u32 *dtp = start;
+
+ while (dtp < limit)
+ switch (*dtp) {
+ case OF_DT_END:
+ if (depth)
+ return -1;
+ return ++dtp - start;
+ case OF_DT_NOP:
+ dtp++;
+ break;
+ case OF_DT_END_NODE:
+ dtp++;
+ depth--;
+ break;
+ case OF_DT_BEGIN_NODE:
+ len = strlen((char *)(++dtp));
+ /* check path is suffix to previous? */
+ dtp += 1 + (len / 4);
+ depth++;
+ break;
+ case OF_DT_PROP:
+ len = dtp[1];
+ dtp += 3;
+ if ((len >= 8) && ((long)dtp & 4))
+ dtp++;
+ dtp += (len + 3) / 4;
+ break;
+ default:
+ return -1;
+ }
+ return -1; /* no OF_DT_END */
+}
+#endif
+
+/**
+ * nop_to_v16 - add %OF_DT_NOP to hide alignment differences
+ * @dtp: pointer to the beginning of the struct area to modify
+ * insert %OF_DT_NOP into the dt_struct @dtp to make it v16 from v1, 2, or 3.
+ */
+static int nop_to_v16(u32 *dtp)
+{
+ int nops = 0;
+ char *p, *s;
+ int len;
+ u32 *next;
+
+ while (*dtp != OF_DT_END)
+ switch (*dtp) {
+ case OF_DT_BEGIN_NODE:
+ /* v2 & v3 names are full path, v16+ is relative */
+ p = (char *)(++dtp);
+ len = strlen(p);
+ next = dtp + 1 + len / 4;
+
+ for (s = p + len; *s != '/'; s--)
+ if (s == p)
+ fatal("name %s has no '/'", p);
+
+ len -= s++ - p; /* not the slash but the nul */
+ memmove(p, s, len);
+ while (len % 4)
+ p[len++] = '\0';
+ dtp += len / 4;
+ while (dtp != next) {
+ *dtp++ = OF_DT_NOP;
+ nops++;
+ }
+ break;
+ case OF_DT_PROP:
+ /* convert from align_8 to align_4 via prefixing nop */
+ len = dtp[1];
+ if ((len >= 8) && !((long)dtp & 4)) {
+ memmove(dtp+1, dtp, 12);
+ *dtp++ = OF_DT_NOP;
+ nops++;
+ }
+ dtp += 3 + (len + 3)/4;
+ break;
+ default:
+ fatal("%s: unrecognised tag %d at %p\n", __FUNCTION__,
+ *dtp, dtp);
+ case OF_DT_NOP:
+ nops ++;
+ /* fall through */
+ case OF_DT_END_NODE:
+ dtp ++;
+ break;
+ }
+ return nops;
+}
+
+#if MIN_VERSION < 3 || OUT_VERSION > 16
+/**
+ * move_nops_fwd - move nops in a v16 dt_struct to the beginning
+ * @start - device tree starting address
+ * @count - number of %OF_DT_NOP cells to move
+ */
+static void move_nops_fwd(u32 *start, int count)
+{
+ u32 *dtp = start;
+ int len;
+ while (count)
+ switch (*dtp) {
+ case OF_DT_NOP:
+ memmove(start+1,start,(dtp-start) * 4);
+ *start++ = OF_DT_NOP;
+ dtp++;
+ count--;
+ break;
+ case OF_DT_END_NODE:
+ dtp++;
+ break;
+ case OF_DT_BEGIN_NODE:
+ len = strlen((char *)(++dtp));
+ dtp += 1 + len / 4;
+ break;
+ case OF_DT_PROP:
+ len = dtp[1];
+ dtp += 3 + (len + 3) / 4;
+ break;
+ case OF_DT_END:
+ fatal("Not enough nops -- need %d more\n", count);
+ return;
+ default:
+ fatal("%s: unknown tag %d at %p", __FUNCTION__, *dtp, dtp)
+ }
+}
+#endif
+
+/**
+ * conv_flattree_inplace upgrade the version of a boot_param_header
+ * @tree: pointer to the device tree header to convert
+ *
+ * Converts a v1, 2, 3 device tree (of at least MIN_VERSION)
+ * in place to OUT_VERSION (16) format, usable by flatdevtree.c
+ */
+void conv_flattree_inplace(struct boot_param_header *tree)
+{
+ u32 *dtp;
+ u32 need = 0, nops;
+ int slen;
+
+ if (tree->magic != OF_DT_HEADER)
+ fatal("%s: no magic", __FUNCTION__);
+
+ if (tree->last_comp_version > 3)
+ return; /* don't know what to do */
+
+ if (tree->version < MIN_VERSION) {
+ printf("%s: Warning: can't handle version %d tree\n",
+ __FUNCTION__, tree->version);
+ return;
+ }
+
+ if (tree->version < 2)
+ need++; /* boot_cpu_id */
+
+ if (tree->version < 3)
+ need++; /* dt_string_size */
+
+ if (OUT_VERSION > 16)
+ need++; /* dt_struct_size */
+
+ dtp = (void *)tree + tree->off_dt_struct;
+
+ slen = check_v123_tree(dtp, (void *)tree + tree->totalsize);
+ if (slen < 0)
+ fatal("device tree check failed\n");
+
+ nops = nop_to_v16(dtp);
+
+ if (need & 1) /* keep 8 byte alignment of mem reserve */
+ need++;
+
+ if (need > nops)
+ fatal("Didn't find enough space to add new header fields\n\r"
+ "(needed %d found %d tree %p)", need, nops, tree);
+
+ /* ok now compress the dtb struct */
+ move_nops_fwd(dtp, need);
+ dtp += need;
+
+ /*
+ * move mem_rsvmap and dt_strings if they are before dt_struct
+ * onto our nops . Adjust start addresses for the 3 sections.
+ */
+ if ((tree->off_mem_rsvmap < tree->off_dt_struct) ||
+ (tree->off_dt_strings < tree->off_dt_struct)) {
+ int start, end;
+ void *ptr;
+
+ if (tree->off_mem_rsvmap < tree->off_dt_strings)
+ start = tree->off_mem_rsvmap;
+ else
+ start = tree->off_dt_strings;
+
+ end = tree->off_dt_struct;
+ ptr = (void *)tree + start;
+
+ memmove(ptr + 4 * need, ptr, end - start);
+
+ if (tree->off_mem_rsvmap < tree->off_dt_struct)
+ tree->off_mem_rsvmap += 4 * need;
+ if (tree->off_dt_strings < tree->off_dt_struct)
+ tree->off_dt_strings += 4 * need;
+ }
+ tree->off_dt_struct += 4 * need;
+
+ /* ok now we have space to extend the header. */
+ if (tree->version < 2 && MIN_VERSION < 2) {
+ tree->boot_cpuid_phys = 0; /* default, caller can fix */
+ }
+
+ /* calculate size of dt_strings_size */
+ if (tree->version < 3 && MIN_VERSION < 3) {
+ int end = tree->totalsize;
+
+ if (tree->off_dt_strings < tree->off_mem_rsvmap)
+ end = tree->off_mem_rsvmap;
+
+ if ((tree->off_dt_strings < tree->off_dt_struct) &&
+ (end > tree->off_dt_struct))
+ end = tree->off_dt_struct;
+
+ tree->dt_strings_size = end - tree->off_dt_strings;
+ }
+
+#if OUT_VERSION > 16
+ tree->dt_struct_size = 4 * slen;
+#endif
+
+ tree->version = OUT_VERSION;
+ tree->last_comp_version = OUT_COMPAT;
+
+ return;
+}
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2007-09-20 17:42:24.000000000 -0500
+++ kernel/arch/powerpc/boot/Makefile 2007-09-20 17:49:04.000000000 -0500
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- marshal.c memranges.c kexec.c \
+ flatdevtree_conv.c marshal.c memranges.c kexec.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
Index: kernel/arch/powerpc/boot/ops.h
===================================================================
--- kernel.orig/arch/powerpc/boot/ops.h 2007-09-20 17:42:24.000000000 -0500
+++ kernel/arch/powerpc/boot/ops.h 2007-09-20 17:49:04.000000000 -0500
@@ -81,7 +81,10 @@ struct loader_info {
};
extern struct loader_info loader_info;
+struct boot_param_header;
+
void start(void);
+void conv_flattree_inplace(struct boot_param_header *tree);
int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
int serial_console_init(void);
int ns16550_console_init(void *devp, struct serial_console_data *scdp);
Index: kernel/arch/powerpc/boot/kexec.c
===================================================================
--- kernel.orig/arch/powerpc/boot/kexec.c 2007-09-20 17:42:24.000000000 -0500
+++ kernel/arch/powerpc/boot/kexec.c 2007-09-20 17:49:04.000000000 -0500
@@ -99,6 +99,7 @@ void kexec_platform_init(struct boot_par
move_slaves_up();
setup_initial_heap();
+ conv_flattree_inplace(dt_blob);
init_flat_tree(dt_blob);
/*
* drivers can malloc and read the tree, but not realloc later
^ permalink raw reply
* [PATCH 9/15] bootwrapper: rtas support
From: Milton Miller @ 2007-09-21 23:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
This code provides a console write that calls put-term-char.
To avoid PIC relocation of the absolute rtas addresses, hide the
actual call to rtas in assembly and declare all variables as int.
An instantiated rtas will be protected by a reserved range in the
device tree, so no explicit call to add_occupied_range is needed
here.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
vs 12176
rtas_put_term_write now takes const char *buf
rediff ops.h, Makefile
Index: kernel/arch/powerpc/boot/rtas.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/rtas.c 2007-09-21 01:43:08.000000000 -0500
@@ -0,0 +1,146 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "flatdevtree.h"
+
+static int rtas_entry;
+static int rtas_base;
+static int rtas_size;
+
+static void find_rtas(void)
+{
+ int rc;
+ void *devp;
+ char *str;
+
+ devp = finddevice("/rtas");
+ if (! devp)
+ return;
+
+ str = "linux,rtas-entry";
+ rc = getprop(devp, str, &rtas_entry, sizeof(rtas_entry));
+ if (rc < 0)
+ return;
+ if (rc != sizeof(rtas_entry))
+ goto fail;
+
+ str = "rtas-size";
+ rc = getprop(devp, str, &rtas_size, sizeof(rtas_size));
+ if (rc < 0)
+ return;
+ if (rc != sizeof(rtas_size))
+ goto fail;
+
+ str = "linux,rtas-base";
+ rc = getprop(devp, str, &rtas_base, sizeof(rtas_base));
+ if (rc < 0) {
+ printf("rtas-size but no linux,rtas-base in /rtas. "
+ "disabling wrapper rtas interface\n\r");
+ rtas_entry = 0;
+ return;
+ }
+
+ if (rc != sizeof(rtas_base))
+ goto fail;
+
+ return;
+
+
+fail:
+ printf("Unexpected length %d of %s property in /rtas.\n\r"
+ "disabling wrapper rtas interface\n\r", rc, str);
+ rtas_entry = 0;
+ return;
+}
+
+/*
+ * PIC relocation of function pointers happens at call time.
+ * We have an absolute out-of-image address. So tell C they
+ * are just integers, and hide the call as an out-of-file
+ * function.
+ */
+__asm__ (
+ " .globl call_rtas\n"
+ " call_rtas: mtctr 5\n"
+ " bctr\n"
+ );
+
+void call_rtas(int args[], int base, int entry);
+
+
+static int put_term_char;
+
+static void rtas_put_term_write(const char *buf, int len)
+{
+ int i, args[5];
+
+ args[0] = put_term_char;
+ args[1] = 1; /* num inputs */
+ args[2] = 1; /* num outputs */
+
+ for (i=0; i < len; ) {
+ args[3] = buf[i];
+ args[4] = 0;
+
+ call_rtas(args, rtas_base, rtas_entry);
+ if (args[4] == 0) /* SUCCESS */
+ i++;
+ else if (args[4] == -1) /* HARDWARE_ERROR */
+ break;
+ /* else retry */
+ }
+}
+
+int rtas_console_init(void)
+{
+ void *devp;
+ int rc;
+
+
+ devp = finddevice("/rtas");
+ if (!devp)
+ return -1;
+
+ if (!rtas_entry)
+ find_rtas();
+ if (!rtas_entry)
+ return -1;
+
+ rc = getprop(devp, "put-term-char", &put_term_char,
+ sizeof(put_term_char));
+ if (rc == sizeof(put_term_char))
+ console_ops.write = rtas_put_term_write;
+ else
+ put_term_char = -1;
+
+ return put_term_char == -1 ? -1 : 0;
+}
+
+/* for debug, hard code */
+void use_rtas_console(int entry, int base, int tc)
+{
+ rtas_entry = entry;
+ rtas_base = base;
+ put_term_char = tc;
+ console_ops.write = rtas_put_term_write;
+}
Index: kernel/arch/powerpc/boot/ops.h
===================================================================
--- kernel.orig/arch/powerpc/boot/ops.h 2007-09-21 01:43:02.000000000 -0500
+++ kernel/arch/powerpc/boot/ops.h 2007-09-21 01:43:08.000000000 -0500
@@ -99,6 +99,8 @@ void send_slaves_to_kernel(void *vmlinux
void slaves_are_low(void);
void wait_slaves_moved(void);
void kexec_platform_init(struct boot_param_header *dt_blob);
+int rtas_console_init(void);
+void use_rtas_console(int entry, int base, int tc);
int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
Index: kernel/arch/powerpc/boot/kexec.c
===================================================================
--- kernel.orig/arch/powerpc/boot/kexec.c 2007-09-21 01:43:02.000000000 -0500
+++ kernel/arch/powerpc/boot/kexec.c 2007-09-21 01:43:08.000000000 -0500
@@ -33,6 +33,9 @@ static void find_console_from_tree(void)
{
int rc = -1;
+ rc = rtas_console_init();
+ if (!rc)
+ return;
if (rc) {
/* no console, oh well */
}
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2007-09-21 01:43:02.000000000 -0500
+++ kernel/arch/powerpc/boot/Makefile 2007-09-21 01:43:08.000000000 -0500
@@ -42,7 +42,7 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- flatdevtree_conv.c marshal.c memranges.c kexec.c \
+ flatdevtree_conv.c marshal.c memranges.c kexec.c rtas.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
^ permalink raw reply
* [PATCH 10/15] bootwrapper: add cpio file extraction library.
From: Milton Miller @ 2007-09-21 23:05 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Rob Landley, David Gibson
In-Reply-To: <boot-8-00.miltonm@bga.com>
Add a library to search through a cpio or initramfs buffer for a
specified path name. No canocalization of the path is performed.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
vs 12177
rediff Makefile
cpio.c should be reusable by a stand alone user space applicaton.
Index: kernel/arch/powerpc/boot/cpio.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/cpio.c 2007-08-22 20:51:29.000000000 -0500
@@ -0,0 +1,306 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2007 IBM Corporation.
+ *
+ * Authors: Milton Miller <miltonm@bga.com>
+ *
+ */
+
+#include "cpio.h"
+#include "string.h"
+
+struct cpio_header {
+ char ino[8];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char nlink[8];
+ char mtime[8];
+ char filesize[8];
+ char maj[8];
+ char min[8];
+ char rmaj[8];
+ char rmin[8];
+ char namesize[8];
+ char chksum[8];
+} cpio_header_buf;
+
+static int check_magic(char magic[6])
+{
+ return !memcmp(magic,"070701",6) || !memcmp(magic,"070702",6);
+}
+
+static int read_magic(struct gunzip_state *stream)
+{
+ int len;
+ char magic[6];
+
+ len = gunzip_partial(stream, magic, sizeof(magic));
+ if (len == 0)
+ return 0;
+
+ if (len == sizeof(magic) && check_magic(magic))
+ return len;
+
+
+ /* Not the right magic or short read. We might have stumbled
+ * onto a compressed archive immediately following an
+ * uncompressed one, or just some NUL bytes at the end of the
+ * archive. Inform the higher layers by the negative length.
+ */
+ return -len;
+}
+
+static int get_cpio_header(struct gunzip_state *stream)
+{
+ int len;
+
+ len = read_magic(stream);
+ if (len <= 0)
+ return len;
+
+ gunzip_exactly(stream, &cpio_header_buf, sizeof(cpio_header_buf));
+ len += sizeof(cpio_header_buf);
+
+ return len;
+}
+
+static unsigned int cpio_str_to_num(char hexascii[8])
+{
+ unsigned int num = 0;
+ char c;
+ int d;
+
+ for (d=0; d < 8; d++) {
+ c = hexascii[d];
+ num <<= 4;
+ if (c >= '0' && c <= '9') {
+ num += c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ num += c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ num += c - 'a' + 10;
+ } else {
+ cpio_error("bad cpio archive header: "
+ "invalid a hex digit");
+ }
+ }
+
+ return num;
+}
+
+static char name_buf[MAX_PATH+1];
+static const char cpio_end[] = "TRAILER!!!";
+#define CPIO_END_LEN sizeof(cpio_end)
+
+/* check_next_file
+ * Look for @path in @stream. Set @consumed to the number of bytes
+ * succesfully read and processed. return 1 on match, 0 for discarding
+ * an unmatched file, -1 on end of archive (either detected trailer or
+ * EOF on stream), or -(1 + bytes read) for a short read or bad magic
+ * number. (For the short or bad read, the consumed is not changed).
+ */
+static int check_next_file(char *path, int pathlen,
+ struct gunzip_state *stream, int *consumed)
+{
+ int len, total, match;
+
+ if (pathlen > MAX_PATH) {
+ cpio_error("path too long to search\n");
+ }
+ total = get_cpio_header(stream);
+ if (total <= 0)
+ return total - 1;
+
+ len = cpio_str_to_num(cpio_header_buf.namesize);
+
+ if (len == pathlen || len == CPIO_END_LEN) {
+ gunzip_exactly(stream, name_buf, len);
+ total += len;
+ match = !strcmp(name_buf, path);
+ if (!match && !cpio_str_to_num(cpio_header_buf.filesize))
+ match = -!strcmp(name_buf, cpio_end);
+ } else {
+ gunzip_discard(stream, len);
+ total += len;
+ name_buf[0] = '\0';
+ match = 0;
+ }
+
+ len = total % 4;
+ if (len) {
+ gunzip_discard(stream, 4 - len);
+ total += 4 - len;
+ }
+
+ if (!match) {
+ len = cpio_str_to_num(cpio_header_buf.filesize);
+ gunzip_discard(stream, len);
+ total += len;
+
+ len = total % 4;
+ if (len) {
+ gunzip_discard(stream, 4 - len);
+ total += 4 - len;
+ }
+ }
+
+ *consumed += total;
+ return match;
+}
+
+static char *this_buf;
+static int this_archive;
+
+/* find_in_cpio.
+ * find a pathname @path in a single cpio archive described by @stream.
+ * Return is the same as check_next_file.
+ */
+int find_in_cpio(char *path, struct gunzip_state *stream)
+{
+ int found;
+ int pathlen = strlen(path) + 1;
+
+ this_archive = 0;
+ do {
+ found = check_next_file(path, pathlen, stream, &this_archive);
+ } while (found == 0);
+
+ return found;
+}
+
+/* find_in_initramfs
+ * Search a initramfs buffer for a given path name. Returns 0 on
+ * not found, or 1 with @state ready to read the file.
+ *
+ * Note: this returns the first match, not the last. The kernel
+ * decompressor effectivly uses the last match. This code also
+ * doesn't worry about the directories in the path existing.
+ */
+int find_in_initramfs(char *path, char *buf, int len,
+ struct gunzip_state *stream)
+{
+ int found, total = 0;
+ int pathlen = strlen(path) + 1;
+ int *ibuf;
+
+ do {
+ /* get to word boundary, but stop if not NUL */
+ for (; total % 4 && total < len - 4; total++)
+ if (buf[total])
+ break;
+
+ if ((total % 4) == 0) {
+ /* fast forward over NUL words. */
+ for (ibuf = (int *)&buf[total];
+ total < len - sizeof(*ibuf) && !*ibuf;
+ ibuf++)
+ total += sizeof(*ibuf);
+ }
+
+ /* check remainder of a short archive -- it must all be
+ * zero as both gzip header and cpio header are bigger
+ * than this.
+ */
+ if (total >= len - 4) {
+ for (;total < len; total++) {
+ if (buf[len]) {
+ cpio_error("Junk at end of buffer");
+ }
+ }
+ break;
+ } else if (total % 4) {
+ /*
+ * If we are unalinged and not at the end of the buffer
+ * we must be following a compressed archive. Only
+ * NUL and gzip headers are allowed. We skipped NUL.
+ */
+ if (!(buf[total] == 0x1b && buf[total + 1] == 0x8b))
+ cpio_error("unalinged junk in buffer");
+ }
+
+ this_buf = buf + total;
+ this_archive = 0;
+
+ gunzip_start(stream, this_buf, len - total);
+
+ do {
+ found = check_next_file(path, pathlen, stream,
+ &this_archive);
+ } while (!found);
+
+ if (found > 0)
+ return found;
+
+ if (stream->s.workspace) {
+ int discard;
+
+ if (found < -1) {
+ cpio_error("Junk in compressed archive");
+ }
+
+ /* we either found EOF or TRAILER!!!. In the later
+ * case we need to discard to the end of the gzip
+ * contents.
+ */
+ do {
+ discard = gunzip_partial(stream, name_buf,
+ MAX_PATH);
+ this_archive += discard;
+ } while (discard);
+
+ /*
+ * Peek at how many input bytes were consumed.
+ * reset our consumed input.
+ */
+ total += stream->s.total_in + 8;
+
+ /* clean up zlib */
+ discard = gunzip_finish(stream, name_buf, 0);
+ } else {
+ if (this_archive % 4) {
+ cpio_error("Archive not multiple of 4?");
+ }
+ total += this_archive;
+
+ if (!this_archive) {
+ cpio_error("junk between archives");
+ }
+ /* don't check the < -1 of found, it might be an
+ * archive. This will be caught by the !this_archive
+ * check on the next loop.
+ */
+ }
+ } while (total < len);
+
+ return 0;
+}
+
+void get_cpio_info(void **archive_start, int *consumed)
+{
+ *archive_start = this_buf;
+ *consumed = this_archive;
+}
+
+int get_cpio_file_mode(void)
+{
+ return cpio_str_to_num(cpio_header_buf.mode);
+}
+
+int get_cpio_file_size(void)
+{
+ return cpio_str_to_num(cpio_header_buf.filesize);
+}
Index: kernel/arch/powerpc/boot/cpio.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ kernel/arch/powerpc/boot/cpio.h 2007-08-22 20:51:29.000000000 -0500
@@ -0,0 +1,12 @@
+#include "gunzip_util.h"
+
+extern int find_in_cpio(char *path, struct gunzip_state *stream);
+extern int find_in_initramfs(char *path, char *buf, int len,
+ struct gunzip_state *state);
+extern void get_cpio_info(void **archive_start, int *consumed);
+extern int get_cpio_file_size(void);
+extern int get_cpio_file_mode(void);
+
+#define MAX_PATH 256
+
+extern void cpio_error(char *msg);
Index: kernel/arch/powerpc/boot/Makefile
===================================================================
--- kernel.orig/arch/powerpc/boot/Makefile 2007-08-22 20:51:06.000000000 -0500
+++ kernel/arch/powerpc/boot/Makefile 2007-08-22 20:52:46.000000000 -0500
@@ -36,13 +36,13 @@ $(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
zlib := inffast.c inflate.c inftrees.c
zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
-zliblinuxheader := zlib.h zconf.h zutil.h
+zliblinuxheader := zlib.h zconf.h zutil.h stat.h
$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- flatdevtree_conv.c marshal.c memranges.c kexec.c rtas.c \
+ flatdevtree_conv.c marshal.c memranges.c kexec.c rtas.c cpio.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
^ 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