* linux kernel BUG REPORT "/usr/src/linux-2.6.11.7/drivers/ide/ppc/pmac.c"
From: stewart midgley @ 2007-06-11 4:23 UTC (permalink / raw)
To: linuxppc-dev
(1) One line summary: Occasional problem with hard disk access, that
kills an iBookG4, but is fixed by rebooting
(2) Full description: Occasional error with the following kernel message
> EXT3-fs error device hda17 in start_transaction : Journal has aborted
The /var partition is mounted on /dev/hda17
The machine will not respond, acknowledging key board commands but cant
execute code (e.g., /sbin/sync or /sbin/shutdown -r now), with
complaints that I forgot to write down. Problem fixed by rebooting, but
all unsaved data is lost. We speculated about hard disk failure and
consulted the web. A link suggested looking at
/usr/src/linux-2.6.11.7/drivers/ide/ppc/pmac.c, and I find the following
clues in /var/log/messages (at the time of the last failure).
> Jun 7 04:02:11 l-cl27-g41-a logrotate: ALERT exited abnormally with [1]
> Jun 8 04:02:11 l-cl27-g41-a logrotate: ALERT exited abnormally with [1]
> Jun 8 15:49:39 l-cl27-g41-a kernel: ide-pmac lost interrupt, dma
status: 8480
> Jun 8 15:49:39 l-cl27-g41-a kernel: hda: lost interrupt
> Jun 8 15:49:39 l-cl27-g41-a kernel: hda: dma_intr: status=0xd0 { Busy }
> Jun 8 15:49:39 l-cl27-g41-a kernel:
> Jun 8 15:49:39 l-cl27-g41-a kernel: ide: failed opcode was: unknown
> Jun 8 15:49:39 l-cl27-g41-a kernel: hda: DMA disabled
> Jun 8 15:49:55 l-cl27-g41-a kernel: ide0: reset: success
> Jun 8 17:24:48 localhost syslogd 1.4.1: restart.
> Jun 8 17:24:48 localhost syslog: syslogd startup succeeded
(3) Key words: drivers, ide, ppc pmac.c
(4) cat /proc/version
Linux version 2.6.11.7 (root@w-cl27-g41-aa.spme.monash.edu.au) (gcc
version 3.3.3 (Yellow Dog Linux 3.3.3-16.ydl.4)) #1 Wed Apr 27 10:16:03
EST 2005
rnel version
(5) Not an Oops problem
(6) Problem creation script: N/A, an infrequent problem
(7) Environment information
(7.1) Software is Yellow Dog linux 4.0
script ver_linux finds
Linux l-cl27-g41-a.physics.monash.edu.au 2.6.11.7 #1 Wed Apr 27
10:16:03 EST 2005 ppc ppc ppc GNU/Linux
Gnu C 3.3.3
Gnu make 3.80
binutils 2.15.90
util-linux 2.12pre
mount 2.12pre
module-init-tools 2.4.26
e2fsprogs 1.35
reiserfsprogs line
reiser4progs line
pcmcia-cs 3.2.7
quota-tools 3.10.
PPP 2.4.2
isdn4k-utils 3.3
nfs-utils 1.0.6
Linux C Library 2.3.3
Dynamic linker (ldd) 2.3.3
Procps 3.2.0
Net-tools 1.60
Kbd 1.12
Sh-utils 5.2.1
./ver_linux: line 90: udevinfo: command not found
Modules Loaded ipx p8022 psnap llc sg ohci1394 ieee1394 sd_mod
scsi_mod vfat fat
(7.2) cat /proc/cpuinfo
processor : 0
cpu : 7447A, altivec supported
clock : 1066MHz
revision : 1.1 (pvr 8003 0101)
bogomips : 1060.86
machine : PowerBook6,5
motherboard : PowerBook6,5 MacRISC3 Power Macintosh
detected as : 287 (iBook G4)
pmac flags : 0000001b
L2 cache : 512K unified
memory : 768MB
pmac-generation : NewWorld
(7.3) cat /proc/modules
ipx 28188 0 - Live 0xf21ee000
p8022 1792 1 ipx, Live 0xf21df000
psnap 3460 1 ipx, Live 0xf1032000
llc 6460 2 p8022,psnap, Live 0xf21e1000
sg 34916 0 - Live 0xf20f6000
ohci1394 35716 0 - Live 0xf1075000
ieee1394 106984 1 ohci1394, Live 0xf21c1000
sd_mod 15120 0 - Live 0xf1028000
scsi_mod 137404 2 sg,sd_mod, Live 0xf2401000
vfat 12736 0 - Live 0xf102d000
fat 41468 1 vfat, Live 0xf1061000
(7.4) cat /proc/modules
ipx 28188 0 - Live 0xf21ee000
p8022 1792 1 ipx, Live 0xf21df000
psnap 3460 1 ipx, Live 0xf1032000
llc 6460 2 p8022,psnap, Live 0xf21e1000
sg 34916 0 - Live 0xf20f6000
ohci1394 35716 0 - Live 0xf1075000
ieee1394 106984 1 ohci1394, Live 0xf21c1000
sd_mod 15120 0 - Live 0xf1028000
scsi_mod 137404 2 sg,sd_mod, Live 0xf2401000
vfat 12736 0 - Live 0xf102d000
fat 41468 1 vfat, Live 0xf1061000
[root@l-cl27-g41-a scripts]# cat /proc/ioports
00000000-007fffff : /pci@f2000000
00802000-01001fff : /pci@f0000000
00802400-008024ff : 0000:00:10.0
00802400-008024ff : radeonfb
ff7fe000-ffffdfff : /pci@f4000000
cat /proc/iomem
80000000-8fffffff : /pci@f2000000
80000000-8007ffff : 0001:10:17.0
80000000-8007ffff : 0.80000000:mac-io
80000050-8000007f : 0.00000050:gpio
80008000-800080ff : 0.00010000:i2s
80008000-800080ff : i2s-a (tx dma)
80008100-800081ff : 0.00010000:i2s
80008100-800081ff : i2s-a (rx dma)
80008200-800082ff : 0.00010000:i2s
80008300-800083ff : 0.00010000:i2s
80008800-800088ff : 0.00020000:ata-3
80008800-800088ff : ide-pmac (dma)
80010000-80010fff : 0.00010000:i2s
80010000-80010fff : i2s-a
80013000-80013000 : 0.00013000:ch-b
80013010-80013010 : 0.00013000:ch-b
80013020-80013020 : 0.00013020:ch-a
80013030-80013030 : 0.00013020:ch-a
80013040-80013040 : 0.00013000:ch-b
80013050-80013050 : 0.00013020:ch-a
80015000-80015fff : 0.00015000:timer
80016000-80017fff : 0.00016000:via-pmu
80016000-80017fff : via-pmu
80018000-80018fff : 0.00018000:i2c
80020000-80020fff : 0.00020000:ata-3
80020000-80020fff : ide-pmac (ports)
80040000-8007ffff : interrupt-controller
80040000-8007ffff : 0.00040000:interrup
80080000-800800ff : 0001:10:1b.2
80080000-800800ff : ehci_hcd
80081000-80081fff : 0001:10:1b.1
80081000-80081fff : ohci_hcd
80082000-80082fff : 0001:10:1b.0
80082000-80082fff : ohci_hcd
80083000-80083fff : 0001:10:1a.0
80083000-80083fff : ohci_hcd
90000000-9fffffff : /pci@f0000000
90000000-9000ffff : 0000:00:10.0
90000000-9000ffff : radeonfb
98000000-9fffffff : 0000:00:10.0
98000000-9fffffff : radeonfb
f1000000-f1ffffff : /pci@f0000000
f1000000-f101ffff : 0000:00:10.0
f3000000-f3ffffff : /pci@f2000000
f5000000-f5ffffff : /pci@f4000000
f5000000-f5000fff : 0002:20:0e.0
f5000000-f50007ff : ohci1394
f5004000-f5007fff : 0002:20:0d.0
f5004000-f5007fff : Kauai ATA
f5200000-f53fffff : 0002:20:0f.0
f5200000-f53fffff : sungem
f8000000-f8ffffff : uni-n
(7.5) /sbin/lspci -vvv
00:0b.0 Host bridge: Apple Computer Inc. UniNorth 2 AGP
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort+ >SERR- <PERR-
Latency: 16, Cache Line Size 08
Capabilities: [80] AGP version 1.0
Status: RQ=8 Iso- ArqSz=0 Cal=0 SBA+ ITACoh- GART64-
HTrans- 64bit- FW+ AGP3- Rate=x1,x2,x4
Command: RQ=1 ArqSz=0 Cal=0 SBA+ AGP+ GART64- 64bit- FW-
Rate=x1
00:10.0 VGA compatible controller: ATI Technologies Inc Radeon RV280
[Radeon Mobility 9200 M9+] (rev 01) (prog-if 00 [VGA])
Subsystem: ATI Technologies Inc Radeon RV280 [Radeon Mobility
9200 M9+]
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 255 (2000ns min), Cache Line Size 08
Interrupt: pin A routed to IRQ 48
Region 0: Memory at 0000000098000000 (32-bit, prefetchable)
[size=00000000f1000000]
Region 1: I/O ports at 802400 [size=256]
Region 2: Memory at 0000000090000000 (32-bit, non-prefetchable)
[size=64K]
Expansion ROM at 0000000000020000 [disabled]
Capabilities: [58] AGP version 2.0
Status: RQ=80 Iso- ArqSz=0 Cal=0 SBA+ ITACoh- GART64-
HTrans- 64bit- FW+ AGP3- Rate=x1,x2,x4
Command: RQ=8 ArqSz=0 Cal=0 SBA+ AGP+ GART64- 64bit- FW-
Rate=x1
Capabilities: [50] Power Management version 2
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
0001:10:0b.0 Host bridge: Apple Computer Inc. UniNorth 2 PCI
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort+ >SERR- <PERR-
Latency: 16, Cache Line Size 08
0001:10:17.0 Class ff00: Apple Computer Inc. KeyLargo/Intrepid Mac I/O
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 16, Cache Line Size 08
Region 0: Memory at 0000000080000000 (32-bit, non-prefetchable)
0001:10:18.0 USB Controller: Apple Computer Inc. KeyLargo/Intrepid USB
(prog-if 10 [OHCI])
Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin A routed to IRQ 0
0001:10:19.0 USB Controller: Apple Computer Inc. KeyLargo/Intrepid USB
(prog-if 10 [OHCI])
Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Interrupt: pin A routed to IRQ 0
0001:10:1a.0 USB Controller: Apple Computer Inc. KeyLargo/Intrepid USB
(prog-if 10 [OHCI])
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 16 (750ns min, 21500ns max), Cache Line Size 08
Interrupt: pin A routed to IRQ 29
Region 0: Memory at 0000000080083000 (32-bit, non-prefetchable)
0001:10:1b.0 USB Controller: NEC Corporation USB (rev 43) (prog-if 10
[OHCI])
Subsystem: NEC Corporation USB
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 16 (250ns min, 10500ns max), Cache Line Size 08
Interrupt: pin A routed to IRQ 63
Region 0: Memory at 0000000080082000 (32-bit, non-prefetchable)
Capabilities: [40] Power Management version 2
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
0001:10:1b.1 USB Controller: NEC Corporation USB (rev 43) (prog-if 10
[OHCI])
Subsystem: NEC Corporation USB
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 16 (250ns min, 10500ns max), Cache Line Size 08
Interrupt: pin B routed to IRQ 63
Region 0: Memory at 0000000080081000 (32-bit, non-prefetchable)
Capabilities: [40] Power Management version 2
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
0001:10:1b.2 USB Controller: NEC Corporation USB 2.0 (rev 04) (prog-if
20 [EHCI])
Subsystem: NEC Corporation USB 2.0
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 16 (4000ns min, 8500ns max), Cache Line Size 08
Interrupt: pin C routed to IRQ 63
Region 0: Memory at 0000000080080000 (32-bit, non-prefetchable)
Capabilities: [40] Power Management version 2
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 PME-Enable- DSel=0 DScale=0 PME-
0002:20:0b.0 Host bridge: Apple Computer Inc. UniNorth 2 Internal PCI
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort+ >SERR- <PERR-
Latency: 16, Cache Line Size 08
0002:20:0d.0 Class ff00: Apple Computer Inc. UniNorth/Intrepid ATA/100
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR+
Latency: 32, Cache Line Size 08
Interrupt: pin ? routed to IRQ 39
Region 0: Memory at 00000000f5004000 (32-bit, non-prefetchable)
0002:20:0e.0 FireWire (IEEE 1394): Apple Computer Inc. UniNorth 2
FireWire (rev 81) (prog-if 10 [OHCI])
Subsystem: Apple Computer Inc.: Unknown device 5811
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR-
Latency: 64 (3000ns min, 6000ns max), Cache Line Size 08
Interrupt: pin A routed to IRQ 40
Region 0: Memory at 00000000f5000000 (32-bit, non-prefetchable)
Capabilities: [44] Power Management version 2
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0+,D1+,D2+,D3hot+,D3cold-)
Status: D0 PME-Enable- DSel=0 DScale=0 PME+
0002:20:0f.0 Ethernet controller: Apple Computer Inc. UniNorth 2 GMAC
(Sun GEM) (rev 80)
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop-
ParErr- Stepping- SERR- FastB2B-
Status: Cap- 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=slow >TAbort-
<TAbort- <MAbort- >SERR- <PERR+
Latency: 16 (16000ns min, 16000ns max), Cache Line Size 08
Interrupt: pin A routed to IRQ 41
Region 0: Memory at 00000000f5200000 (32-bit, non-prefetchable)
[size=00000000f5100000]
Expansion ROM at 0000000000100000 [disabled]
(7.6) cat /proc/scsi/scsi
Attached devices:
(7.7) Other relevant information:
Hi Paul, Benjamin and helpers,
I found your names in the code and among list of maintainers.
Perhaps you already fixed this and I need to upgrade my 2 year old kernel?
regards
Stewart
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dr Stewart Midgley
Instrumentation Group,
Monash Centre for Synchrotron Science,
Monash University, Clayton, VIC 3800
Room 111, Building 26
ph: +61 3 9905 9350 fax: +61 3 9905 3637
email: stewart.midgley@sync.monash.ed.au
http://www.sync.monash.edu.au/instgroup/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
^ permalink raw reply
* opb_ethernet driver
From: xu chen @ 2007-06-11 2:47 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 636 bytes --]
Hello.
I'm porting an opb_ethernet driver to my ml403 board now, using the 2.6.17 kernel. I know the ethernet support 3 mode: No DMA, simple DMA, scatter gather DMA, when I use the No DMA mode, we can write the skb into the FIFO, but can't ping other PCs in the network. When I use the simple DMA mode, at the time of ping, in the driver, we should initialize the DMA channel, but when transfering the skb, the DMA returns a "DMA bus time out" signal.
Now I'm worry about it. Who had encountered the problem before? I think I need some help.
---------------------------------
抢注雅虎免费邮箱3.5G容量,20M附件!
[-- Attachment #2: Type: text/html, Size: 822 bytes --]
^ permalink raw reply
* opb_ethernet driver
From: xu chen @ 2007-06-11 2:37 UTC (permalink / raw)
To: linuxppc-dev
[-- Attachment #1: Type: text/plain, Size: 624 bytes --]
Hello.
I'm porting an opb_ethernet driver to my ml403 board now, using the 2.6.17 kernel. I know the ethernet support 3 mode: No DMA, simple DMA, scatter gather DMA, when I use the No DMA mode, we can write the skb into the FIFO, but can't ping other PCs in the network. When I use the simple DMA mode, at the time of ping, in the driver, we should initialize the DMA channel, but when transfering the skb, the DMA returns a "DMA bus time out" signal.
Now I'm worry about it. Who had encountered the problem before? I think I need some help.
---------------------------------
雅虎免费邮箱-3.5G容量,20M附件
[-- Attachment #2: Type: text/html, Size: 715 bytes --]
^ permalink raw reply
* Re: [PATCH] Fix interrupt distribution in ppc970
From: Milton Miller @ 2007-06-11 1:58 UTC (permalink / raw)
To: mohan; +Cc: ppcdev, Paul Mackerras, kexec
In-Reply-To: <20070606113134.GC4916@in.ibm.com>
On Jun 6, 2007, at 6:31 AM, Mohan Kumar M wrote:
> I updated the patch with correct tab spacing and removed unnecessary
> "else".
> In some of the PPC970 based systems, interrupt would be distributed to
> offline cpus also even when booted with "maxcpus=1". So check whether
> cpu online map and cpu present map are equal or not. If they are equal
> default_distrib_server is used as interrupt server otherwise boot cpu
> (default_server) used as interrupt server.
>
> In addition to this, if an interrupt is assigned to a specific cpu (ie
> smp affinity) and if that cpu is not online, the earlier code used to
> return the default_distrib_server as interrupt server. This patch
> introduces an additional paramter to the get_irq function ie
> strict_check, based on this parameter, if the cpu is not online either
> default_distrib_server or -1 is returned.
The code is structured cleanly. However, when testing this patch, I
found (1) you printed the mask as a cpulist instead of a cpumask.
Since the user writes a cpumask to /proc/irq/xx/smp_affinity, it would
make more sense to print a mask in the error message.
However, this is all mute because (2) the common in /kenrel/irq/proc.c
checks that a cpu in the mask is online and returns -EINVAL to the user
without calling the ->set_affinity hook (we have no select_smp_affinity
hook arch code). Unless there is another path to call ->set_affinity,
we can only trigger the case of no online cpu by racing between setting
the affinity and taking a cpu offline.
Does anyone know of another path to set the affinity? If not I would
remove this extra logic and change the behavior from ignore to set to
default server.
milton
> #ifdef CONFIG_SMP
> -static int get_irq_server(unsigned int virq)
> +static int get_irq_server(unsigned int virq, unsigned int
> strict_check)
> {
> - unsigned int server;
> + int server;
> /* For the moment only implement delivery to all cpus or one cpu */
> cpumask_t cpumask = irq_desc[virq].affinity;
> cpumask_t tmp = CPU_MASK_NONE;
> @@ -166,22 +166,25 @@ static int get_irq_server(unsigned int v
> if (!distribute_irqs)
> return default_server;
>
> - if (cpus_equal(cpumask, CPU_MASK_ALL)) {
> - server = default_distrib_server;
> - } else {
> + if (!cpus_equal(cpumask, CPU_MASK_ALL)) {
> cpus_and(tmp, cpu_online_map, cpumask);
>
> - if (cpus_empty(tmp))
> - server = default_distrib_server;
> - else
> - server = get_hard_smp_processor_id(first_cpu(tmp));
> + server = first_cpu(tmp);
> +
> + if (server < NR_CPUS)
> + return get_hard_smp_processor_id(server);
> +
> + if (strict_check)
> + return -1;
> }
>
> - return server;
> + if (cpus_equal(cpu_online_map, cpu_present_map))
> + return default_distrib_server;
>
> + return default_server;
> }
>
...
> + /*
> + * For the moment only implement delivery to all cpus or one cpu.
> + * Get current irq_server for the given irq
> + */
> + irq_server = get_irq_server(irq, 1);
> + if (irq_server == -1) {
> + char cpulist[128];
> + cpulist_scnprintf(cpulist, sizeof(cpulist), cpumask);
> + printk(KERN_WARNING "xics_set_affinity: No online cpus in "
> + "the mask %s for irq %d\n", cpulist, virq);
> + return;
> }
^ permalink raw reply
* Re: zImage.miboot and vmlinux.lds
From: Stephen Rothwell @ 2007-06-11 0:25 UTC (permalink / raw)
To: Christian Kujau; +Cc: linuxppc-dev
In-Reply-To: <alpine.DEB.0.99.0706092327300.8312@foobar-g4>
[-- Attachment #1: Type: text/plain, Size: 697 bytes --]
On Sat, 9 Jun 2007 23:39:20 +0200 (CEST) Christian Kujau <lists@nerdbynature.de> wrote:
>
> On Sat, 9 Jun 2007, Segher Boessenkool wrote:
> > vmlinux.lds should be cleaned from the main (non-arch)
> > Makefile; I could swear I've sent a patch for that some
> > time ago.
>
> Well, Stephen Rothwell did (too?) and you replied to his post:
> http://article.gmane.org/gmane.linux.ports.ppc.devel/5881
That patch actually removed vmlinux.lds for the repository as it had
become a generated file i.e. the patch did not add rules to the Makefile
to remove the file for mrproper.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [PATCH] Don't register udbg_console without udbg_putc
From: Milton Miller @ 2007-06-10 4:32 UTC (permalink / raw)
To: dale, mgreer, paulus, paulus; +Cc: linuxppc-dev, olof
Previously, registering this early console would just result
in dropping early buffered printk output until a udbg_putc
was registered.
However, commit 69331af79cf29e26d1231152a172a1a10c2df511
clears the CON_PRINTBUFFER flag on the main console when a
CON_BOOT (early) console has been registered, resulting in
the buffered messages never being displayed to the user.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
Mark and Dale can you test this please?
The call in the common code is made after ->early_init and
before ->setup_arch on both 32 and 64 bit. If a platform
were to set udbg_putc from the setup_arch hook previosly it
would display output from the point of setting that hook.
After this patch it will not get any output until the main
console registers unless it calls register_early_udbg_console.
I didn't see any platforms that do this in my 5 minute check.
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 87703df..993eedc 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -151,12 +151,18 @@ static struct console udbg_console = {
static int early_console_initialized;
-/* called by setup_system */
+/*
+ * Called by setup_system after ppc_md->probe and ppc_md->early_init.
+ * Call it again after setting udbg_putc in ppc_md->setup_arch.
+ */
void register_early_udbg_console(void)
{
if (early_console_initialized)
return;
+ if (!udbg_putc)
+ return;
+
if (strstr(boot_command_line, "udbg-immortal")) {
printk(KERN_INFO "early console immortal !\n");
udbg_console.flags &= ~CON_BOOT;
^ permalink raw reply related
* [PATCH] dtc: parse NOP in dtb input
From: Milton Miller @ 2007-06-10 4:21 UTC (permalink / raw)
To: jdl; +Cc: linuxppc-dev, david
Version 16 and later of the flat device tree format allow NOPs
to be placed in the tree. When processing dtb input, dtc must
recognise them.
Previously it would produce the error message
FATAL ERROR: Invalid opcode word 00000004 in device tree blob
Signed-off-by: Milton Miller <miltonm@bga.com>
---
I was trying to look at the output of convert_flattree_inplace
when I found this. ftdump.c was able to process the input,
producing // [NOP] comments when encountered.
--- dtc/flattree.c.orig 2007-06-07 15:23:53.000000000 -0500
+++ dtc/flattree.c 2007-06-07 15:32:01.000000000 -0500
@@ -27,6 +27,7 @@
#define FTF_BOOTCPUID 0x8
#define FTF_STRTABSIZE 0x10
#define FTF_STRUCTSIZE 0x20
+#define FTF_NOPS 0x40
static struct version_info {
int version;
@@ -41,9 +42,9 @@ static struct version_info {
{3, 1, BPH_V3_SIZE,
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
{16, 16, BPH_V3_SIZE,
- FTF_BOOTCPUID|FTF_STRTABSIZE},
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
{17, 16, BPH_V17_SIZE,
- FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE},
+ FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
};
struct emitter {
@@ -774,6 +775,13 @@ static struct node *unflatten_tree(struc
die("Premature OF_DT_END in device tree blob\n");
break;
+ case OF_DT_NOP:
+ if (flags & FTF_NOPS)
+ break;
+
+ die("OF_DT_NOP in device tree blob\n");
+ break;
+
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
@@ -895,6 +903,8 @@ struct boot_info *dt_from_blob(FILE *f)
if (version < 16) {
flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
+ } else {
+ flags |= FTF_NOPS;
}
inbuf_init(&memresvbuf,
^ permalink raw reply
* Re: [patch 08/18] PS3: Kexec support
From: Geoff Levand @ 2007-06-10 0:13 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <1181184846.31677.277.camel@localhost.localdomain>
Benjamin Herrenschmidt wrote:
> On Thu, 2007-06-07 at 12:31 +1000, Michael Ellerman wrote:
>> > >> + pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__,
>> pd->cpu, virq);
>> > >> +
>> > >> + local_irq_save(flags);
>> > >> + asm volatile(
>> > >> + "1: ldarx %0,0,%3\n"
>> > >> + "andc %0,%0,%2\n"
>> > >> + "stdcx. %0,0,%3\n"
>> > >> + "bne- 1b"
>> > >> + : "=&r" (old), "+m" (*p)
>> > >> + : "r" (bit), "r" (p)
>> > >> + : "cc" );
>> > >> +
>> > >> + lv1_did_update_interrupt_mask(pd->node, pd->cpu);
>> > >> + local_irq_restore(flags);
>> > >
>> > > How is this different from set_bit() ? (asm-powerpc/bitops.h)
>> > >
>> > > ps. now that I see you're just moving this code around someone's
>> > > probably already asked that question.
>
> Actually the above is clear_bit :-)
>
> That would thus be something around the lines of:
>
> clear_bit(&pd->bmp.mask, 63 - virq);
>
> Geoff, feel free to replace it with the clear_bit if you think it's
> nicer that way :-) (and double check I didn't smoke crack when doing
> the above conversion).
>
> The other one in unmask would be set_bit() of course.
Almost right. Needed clear_bit(63 - virq, &pd->bmp.mask).
I added it in.
-Geoff
^ permalink raw reply
* Re: [patch 08/18] PS3: Kexec support (and a tutoral on the kexec flow for 64 bit powerpc)
From: Geoff Levand @ 2007-06-09 22:47 UTC (permalink / raw)
To: Milton Miller; +Cc: ppcdev
In-Reply-To: <aedf9b62aefb7f14cb71ba5bba9c5e38@bga.com>
Hi Milton.
Milton Miller wrote:
> On Wed Jun 6 13:00:15 EST 2007, Geoff Levand wrote:
>
>> Fixup the core platform parts needed for kexec to work on the PS3.
>> - Setup ps3_hpte_clear correctly.
>> - Mask interrupts on irq removal.
>> - Release all hypervisor resources.
>> static void ps3_hpte_clear(void)
>> {
>> - /* Make sure to clean up the frame buffer device first */
>> - ps3fb_cleanup();
>
> I'm glad to see this go. Which patch added the call to the driver?
I don't know the exact history, but I am pretty sure that is a left
over from before the framebuffer driver used the dma support now
provided by the ps3_system_bus. The old fb code managed its own
IOPTE's, and I think this call cleaned those. But as Geert was
re-writing the fb driver ps3fb_cleanup became a place to put general
fb shutdown code. At the time we were working to just get it to boot
and run, and had no concern what happened at shutdown let alone
kexec. It wasn't like someone consciously made a single change to
do driver shutdown here, it just was a result of the churn.
>> + int result;
>>
>> - lv1_unmap_htab(htab_addr);
>> + DBG(" -> %s:%d\n", __func__, __LINE__);
>> +
>> + result = lv1_unmap_htab(htab_addr);
>> + BUG_ON(result);
>> +
>> + ps3_mm_shutdown();
>> +
>> + ps3_mm_vas_destroy();
>>
> I tried to look at these to check that nothing dynamically allocated
> was being touched. I didn't find anything if the memory had been
> hot-unplugged, but it also looked like they skipped the last one.
By 'last one' I guess you mean the rm region (map.rm). That is
the 'real mode' boot mem region. It is allocated by the hypervisor
for the life of the lpar. It's not hot-pluggable.
>> @@ -209,31 +209,28 @@ static int __init ps3_probe(void)
>> #if defined(CONFIG_KEXEC)
>> static void ps3_kexec_cpu_down(int crash_shutdown, int secondary)
>> {
>> - DBG(" -> %s:%d\n", __func__, __LINE__);
>> + int result;
>> + u64 ppe_id;
>> + u64 thread_id = secondary ? 1 : 0;
>
> This is wrong. This is not what secondary means. To get the
> thread_id you must use smp_processor_id for logical or
> hard_smp_processor_id() for the hardware thread id.
>
>> + DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, secondary);
>> + ps3_smp_cleanup_cpu(thread_id);
>> +
>> + lv1_get_logical_ppe_id(&ppe_id);
>> + result = lv1_configure_irq_state_bitmap(ppe_id, secondary ? 0
>> : 1, 0);
>> + /* seems to fail on second call */
>> + DBG("%s:%d: lv1_configure_irq_state_bitmap (%d) %s\n",
>
> As the second argument is thread id, again this is wrong.
OK, I setup a new routine ps3_shutdown_IRQ() to mirror ps3_init_IRQ().
ps3_shutdown_IRQ() uses the hard processor id.
> Once linux is running, all processors are identical. That is the S in
...
> location as it must when started from open firmware.
Thanks for the explanation. I wish I had that before starting this
work, but it still explained a few points I still wasn't clear on.
I think we should put it somewhere formal like the kernel source
Documentntation directory. What do you think?
-Geoff
^ permalink raw reply
* Re: [PATCH 2.6.22-rc4] ehea: Fixed possible kernel panic on VLAN packet recv
From: Jeff Garzik @ 2007-06-09 22:26 UTC (permalink / raw)
To: Thomas Klein
Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
Christoph Raisch, Stefan Roscher, linux-ppc, Marcus Eder
In-Reply-To: <200706062053.16986.osstklei@de.ibm.com>
Thomas Klein wrote:
> This patch fixes a possible kernel panic due to not checking the vlan group
> when processing received VLAN packets and a malfunction in VLAN/hypervisor
> registration.
>
>
> Signed-off-by: Thomas Klein <tklein@de.ibm.com>
applied
^ permalink raw reply
* Re: zImage.miboot and vmlinux.lds
From: Christian Kujau @ 2007-06-09 21:39 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <981f558c34d946fcb2683a9731f8d5ad@kernel.crashing.org>
On Sat, 9 Jun 2007, Segher Boessenkool wrote:
> vmlinux.lds should be cleaned from the main (non-arch)
> Makefile; I could swear I've sent a patch for that some
> time ago.
Well, Stephen Rothwell did (too?) and you replied to his post:
http://article.gmane.org/gmane.linux.ports.ppc.devel/5881
http://article.gmane.org/gmane.linux.ports.ppc.devel/5897
> Maybe it should be added to $(image-) unconditionally?
> Or get rid of the ifeq, preferably.
What about just adding it to clean-files, since $(image-) does not seem
to catch it?
--- linux-2.6.22-rc3.orig/arch/powerpc/boot/Makefile 2007-05-26 04:55:14.000000000 +0200
+++ linux-2.6.22-rc3/arch/powerpc/boot/Makefile 2007-06-09 23:38:07.000000000 +0200
@@ -81,7 +81,7 @@ $(obj)/zImage.lds $(obj)/zImage.coff.lds
@cp $< $@
clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
- empty.c zImage.coff.lds zImage.lds
+ empty.c zImage.coff.lds zImage.lds zImage.miboot
quiet_cmd_bootcc = BOOTCC $@
cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
--
make bzImage, not war
^ permalink raw reply
* Re: zImage.miboot and vmlinux.lds
From: Segher Boessenkool @ 2007-06-09 21:03 UTC (permalink / raw)
To: Christian Kujau; +Cc: linuxppc-dev
In-Reply-To: <alpine.DEB.0.99.0706092110060.8312@foobar-g4>
> Hm, the files are still there. Is there any reason for "mrproper" not
> to
> remove these files? Otherwise, would the following be appropriate?
>
> --- linux-2.6-dev/arch/powerpc/Makefile.orig 2007-05-28
> 21:24:39.000000000 +0200
> +++ linux-2.6-dev/arch/powerpc/Makefile 2007-05-28 21:23:25.000000000
> +0200
> @@ -174,6 +174,7 @@ archclean:
>
> archmrproper:
> $(Q)rm -rf arch/$(ARCH)/include
> + $(Q)rm -f arch/$(ARCH)/boot/zImage.miboot
> arch/$(ARCH)/kernel/vmlinux.lds
vmlinux.lds should be cleaned from the main (non-arch)
Makefile; I could swear I've sent a patch for that some
time ago.
zImage.miboot should be added to $(clean-files) in
arch/powerpc/boot/Makefile; the $(image-) in there
should catch it except for the ifeq in
ifeq ($(CONFIG_PPC32),y)
image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
endif
Maybe it should be added to $(image-) unconditionally?
Or get rid of the ifeq, preferably.
Segher
^ permalink raw reply
* Re: zImage.miboot and vmlinux.lds
From: Christian Kujau @ 2007-06-09 19:14 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <Pine.LNX.4.64.0705282025250.6275@sheep.housecafe.de>
On Mon, 28 May 2007, Christian Kujau wrote:
> when doing a "make mrproper" or even "make distclean" on a current 2.6-git
> tree, I see 2 files being left over:
>
> arch/powerpc/boot/zImage.miboot
> arch/powerpc/kernel/vmlinux.lds
Hm, the files are still there. Is there any reason for "mrproper" not to
remove these files? Otherwise, would the following be appropriate?
--- linux-2.6-dev/arch/powerpc/Makefile.orig 2007-05-28 21:24:39.000000000 +0200
+++ linux-2.6-dev/arch/powerpc/Makefile 2007-05-28 21:23:25.000000000 +0200
@@ -174,6 +174,7 @@ archclean:
archmrproper:
$(Q)rm -rf arch/$(ARCH)/include
+ $(Q)rm -f arch/$(ARCH)/boot/zImage.miboot arch/$(ARCH)/kernel/vmlinux.lds
archprepare: checkbin
Thanks,
Christian.
--
make bzImage, not war
^ permalink raw reply
* Re: [spi-devel-general] [PATCH] Simple driver for Xilinx SPI controler.
From: Andrei Konovalov @ 2007-06-09 16:58 UTC (permalink / raw)
To: David Brownell; +Cc: spi-devel-general, linuxppc-embedded
In-Reply-To: <200706062209.09731.david-b@pacbell.net>
[-- Attachment #1: Type: text/plain, Size: 19781 bytes --]
Hi David,
In the bottom there is the interdiff against the previous version of the patch.
The new patch is attached to this message.
Thanks,
Andrei
David Brownell wrote:
> On Wednesday 06 June 2007, Andrei Konovalov wrote:
>> Would be nice to get this driver into mainline.
>> Reviews and comments are welcome.
>
> I'll ignore the Kconfig flamage ... ;)
I've left untouched XILINX_VIRTEX in
+config SPI_XILINX
+ tristate "Xilinx SPI controller"
+ depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
as in the current kernel there is no other symbol to "depend on".
If / when someone comes with a separate patch to add XILINX_DRIVERS
or whatever suitable this "depends on" line can be revisited.
>> --- /dev/null
>> +++ b/drivers/spi/xilinx_spi.c
>> @@ -0,0 +1,447 @@
>> +/*
>> + * xilinx_spi.c
>> + *
>> + * Xilinx SPI controler driver (master mode only)
>> + *
>> + * Author: MontaVista Software, Inc.
>> + * source@mvista.com
>> + *
>> + * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
>> + * terms of the GNU General Public License version 2. This program is licensed
>> + * "as is" without any warranty of any kind, whether express or implied.
>> + */
>> +
>> +
>> +/* Simple macros to get the code more readable */
>> +#define xspi_in16(addr) in_be16((u16 __iomem *)(addr))
>> +#define xspi_in32(addr) in_be32((u32 __iomem *)(addr))
>> +#define xspi_out16(addr, value) out_be16((u16 __iomem *)(addr), (value))
>> +#define xspi_out32(addr, value) out_be32((u32 __iomem *)(addr), (value))
>
> I'm rather used to seeing I/O addressses passed around as "void __iomem *"
> so those sorts of cast are not needed... :)
The macros has been removed, using "void __iomem *" now.
>> +
>> +static void xspi_abort_transfer(u8 __iomem *regs_base)
>> +{
>
> You should not need an abort primitive. This is called only
> in the remove-controller path. By the time it's called,
> every child spi_device on this bus segment should have been
> removed ... which means any spi_driver attached to that
> device has already returned from its remove() method, which
> in turn means that there will be no spi_message objects in
> flight from any of those drivers.
xspi_abort_transfer() removed
>> +static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
>> +{
>> + struct xilinx_spi *xspi;
>> + u8 __iomem *regs_base;
>> +
>> + xspi = spi_master_get_devdata(spi->master);
>> + regs_base = xspi->regs;
>> +
>> + if (is_on == BITBANG_CS_INACTIVE) {
>> + /* Deselect the slave on the SPI bus */
>> + xspi_out32(regs_base + XSPI_SSR_OFFSET, 0xffff);
>
> I take it you can't support SPI_CS_HIGH??
Yes.
>> +/* spi_bitbang requires custom setup_transfer() to be defined if there is a
>> + * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
>> + * supports just 8 bits per word, and SPI clock can't be changed in software.
>> + * Check for 8 bits per word; speed_hz checking could be added if the SPI
>> + * clock information is available. Chip select delay calculations could be
>> + * added here as soon as bitbang_work() can be made aware of the delay value.
>> + */
>> +static int xilinx_spi_setup_transfer(struct spi_device *spi,
>> + struct spi_transfer *t)
>> +{
>> + u8 bits_per_word;
>> +
>> + bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
>> + if (bits_per_word != 8)
>> + return -EINVAL;
>
> Speed checking *SHOULD* be added; the clock info can be platform data.
Speed checking has be added.
The current problem is that EDK (the tool to create the FPGA "image"
thus configuring what devices are in it) doesn't put the SPI clock
information into any *.c or *.h file it generates. I've tried to
address that in the "enable SPI driver for ML300" patch, but this
doesn't affect the driver patch.
> (Although in practice it's best to have the transfer method do
> the error checking, so that messages that will fail do so before
> they are allowed to enter the I/O queue.)
>
> ISTR you may need to delegate to the default method here too, but
> it's been a while since I poked at that level and the issue might
> not apply to this particular driver config.
As far as I can tell, for the drivers relying on spi_bitbabg
the setup_transfer() method is the right place for the speed
checking.
>> +
>> + return 0;
>> +}
>> +
>> +
>> +static int xilinx_spi_setup(struct spi_device *spi)
>> +{
>> + struct spi_bitbang *bitbang;
>> + struct xilinx_spi *xspi;
>> + int retval;
>> +
>> + xspi = spi_master_get_devdata(spi->master);
>> + bitbang = &xspi->bitbang;
>
> You need to verify ALL the input parameters. In particular,
> mask spi->mode against all the values this driver recognizes
> and supports. If you don't support SPI_LSB_FIRST it's a bug
> if setup() succeeds after setting that. Same thing with all
> other bits defined today (SPI_3WIRE, SPI_CS_HIGH) and in the
> future...
Done
>> + ...
>> +
>> +static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
>> +{
>> + struct xilinx_spi *xspi;
>> + u8 __iomem *regs_base;
>> + u32 ipif_isr;
>> +
>> + xspi = (struct xilinx_spi *) dev_id;
>> + regs_base = xspi->regs;
>> +
>> + /* Get the IPIF inetrrupts, and clear them immediately */
>
> Spell checkers will tell you this is "interrupts" ... ;)
Fixed
>> + ipif_isr = xspi_in32(regs_base + XIPIF_V123B_IISR_OFFSET);
>> + xspi_out32(regs_base + XIPIF_V123B_IISR_OFFSET, ipif_isr);
>> +
>> + if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
>> + u16 cr;
>> + u8 sr;
>> +
>> + /* A transmit has just completed. Process received data and
>> + * check for more data to transmit. Always inhibit the
>> + * transmitter while the Isr refills the transmit register/FIFO,
>> + * or make sure it is stopped if we're done.
>> + */
>> + cr = xspi_in16(regs_base + XSPI_CR_OFFSET);
>> + xspi_out16(regs_base + XSPI_CR_OFFSET,
>> + cr | XSPI_CR_TRANS_INHIBIT);
>> +
>> + /* Read out all the data from the Rx FIFO */
>> + sr = in_8(regs_base + XSPI_SR_OFFSET);
>> + while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
>> + u8 data;
>> +
>> + data = in_8(regs_base + XSPI_RXD_OFFSET);
>> + if (xspi->rx_ptr) {
>> + *xspi->rx_ptr++ = data;
>> + }
>> + sr = in_8(regs_base + XSPI_SR_OFFSET);
>> + }
>> +
>> + /* See if there is more data to send */
>> + if (xspi->remaining_bytes > 0) {
>> + /* sr content is valid here; no need for io_8() */
>> + while ((sr & XSPI_SR_TX_FULL_MASK) == 0
>> + && xspi->remaining_bytes > 0) {
>> + if (xspi->tx_ptr) {
>> + out_8(regs_base + XSPI_TXD_OFFSET,
>> + *xspi->tx_ptr++);
>> + } else {
>> + out_8(regs_base + XSPI_TXD_OFFSET, 0);
>> + }
>
> This duplicates the loop in txrx_bufs(); that's bad style.
> Have one routine holding the shared code.
Moved into separate function.
>> +static int __init xilinx_spi_probe(struct platform_device *dev)
>> +{
>> + int ret = 0;
>> + struct spi_master *master;
>> + struct xilinx_spi *xspi;
>> + struct xspi_platform_data *pdata;
>> + struct resource *r;
>> +
>> + /* Get resources(memory, IRQ) associated with the device */
>> + master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi));
>> +
>> + if (master == NULL) {
>> + return -ENOMEM;
>> + }
>> +
>> + platform_set_drvdata(dev, master);
>> + pdata = dev->dev.platform_data;
>> +
>> + if (pdata == NULL) {
>> + ret = -ENODEV;
>> + goto put_master;
>> + }
>> +
>> + r = platform_get_resource(dev, IORESOURCE_MEM, 0);
>> + if (r == NULL) {
>> + ret = -ENODEV;
>> + goto put_master;
>> + }
>> +
>> + xspi = spi_master_get_devdata(master);
>> + xspi->bitbang.master = spi_master_get(master);
>> + xspi->bitbang.chipselect = xilinx_spi_chipselect;
>> + xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
>> + xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
>> + xspi->bitbang.master->setup = xilinx_spi_setup;
>> + init_completion(&xspi->done);
>> +
>> + xspi->regs = ioremap(r->start, r->end - r->start + 1);
>
> Strictly speaking a request_region() should precede the ioremap,
> but a lot of folk don't bother. However, lacking that I'd put
> the request_irq() earlier, since that will be the only resource
> providing any guard against another driver sharing the hardware.
request_region() added
Here is the interdiff against the previous version of the patch:
diff -u b/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
--- b/arch/ppc/syslib/virtex_devices.h
+++ b/arch/ppc/syslib/virtex_devices.h
@@ -49,6 +49,7 @@
struct xspi_platform_data {
s16 bus_num;
u16 num_chipselect;
+ u32 speed_hz;
};
#endif /* __ASM_VIRTEX_DEVICES_H__ */
diff -u b/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
--- b/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -71,12 +71,6 @@
#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
-/* Simple macros to get the code more readable */
-#define xspi_in16(addr) in_be16((u16 __iomem *)(addr))
-#define xspi_in32(addr) in_be32((u32 __iomem *)(addr))
-#define xspi_out16(addr, value) out_be16((u16 __iomem *)(addr), (value))
-#define xspi_out32(addr, value) out_be32((u32 __iomem *)(addr), (value))
-
struct xilinx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
@@ -87,62 +81,48 @@
u32 irq;
+ u32 speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
+
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */
};
-static void xspi_abort_transfer(u8 __iomem *regs_base)
-{
- /* Deselect the slave on the SPI bus */
- xspi_out32(regs_base + XSPI_SSR_OFFSET, 0xffff);
-
- /* Terminate transmit in progress (if any) and Reset the FIFOs */
- xspi_out16(regs_base + XSPI_CR_OFFSET,
- xspi_in16(regs_base + XSPI_CR_OFFSET)
- | XSPI_CR_TRANS_INHIBIT | XSPI_CR_TXFIFO_RESET
- | XSPI_CR_RXFIFO_RESET);
-}
-
-static void xspi_init_hw(u8 __iomem *regs_base)
+static void xspi_init_hw(void __iomem *regs_base)
{
/* Reset the SPI device */
- xspi_out32(regs_base + XIPIF_V123B_RESETR_OFFSET,
- XIPIF_V123B_RESET_MASK);
+ out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
+ XIPIF_V123B_RESET_MASK);
/* Disable all the interrupts just in case */
- xspi_out32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
+ out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
/* Enable the global IPIF interrupt */
- xspi_out32(regs_base + XIPIF_V123B_DGIER_OFFSET,
- XIPIF_V123B_GINTR_ENABLE);
+ out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
+ XIPIF_V123B_GINTR_ENABLE);
/* Deselect the slave on the SPI bus */
- xspi_out32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+ out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
/* Disable the transmitter, enable Manual Slave Select Assertion,
* put SPI controller into master mode, and enable it */
- xspi_out16(regs_base + XSPI_CR_OFFSET,
- XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
- | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
+ out_be16(regs_base + XSPI_CR_OFFSET,
+ XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
+ | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
}
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
{
- struct xilinx_spi *xspi;
- u8 __iomem *regs_base;
-
- xspi = spi_master_get_devdata(spi->master);
- regs_base = xspi->regs;
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
if (is_on == BITBANG_CS_INACTIVE) {
/* Deselect the slave on the SPI bus */
- xspi_out32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+ out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
} else if (is_on == BITBANG_CS_ACTIVE) {
/* Set the SPI clock phase and polarity */
- u16 cr = xspi_in16(regs_base + XSPI_CR_OFFSET)
+ u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
& ~XSPI_CR_MODE_MASK;
if (spi->mode & SPI_CPHA)
cr |= XSPI_CR_CPHA;
if (spi->mode & SPI_CPOL)
cr |= XSPI_CR_CPOL;
- xspi_out16(regs_base + XSPI_CR_OFFSET, cr);
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
@@ -150,30 +130,43 @@
*/
/* Activate the chip select */
- xspi_out32(regs_base + XSPI_SSR_OFFSET,
- ~(0x0001 << spi->chip_select));
+ out_be32(xspi->regs + XSPI_SSR_OFFSET,
+ ~(0x0001 << spi->chip_select));
}
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
* custom txrx_bufs(). We have nothing to setup here as the SPI IP block
* supports just 8 bits per word, and SPI clock can't be changed in software.
- * Check for 8 bits per word; speed_hz checking could be added if the SPI
- * clock information is available. Chip select delay calculations could be
+ * Check for 8 bits per word. Chip select delay calculations could be
* added here as soon as bitbang_work() can be made aware of the delay value.
*/
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
u8 bits_per_word;
+ u32 hz;
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
- if (bits_per_word != 8)
+ hz = (t) ? t->speed_hz : spi->max_speed_hz;
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
+ __FUNCTION__, bits_per_word);
return -EINVAL;
+ }
+
+ if (hz && xspi->speed_hz > hz) {
+ dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
+ __FUNCTION__, hz);
+ return -EINVAL;
+ }
return 0;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
static int xilinx_spi_setup(struct spi_device *spi)
{
@@ -186,63 +179,70 @@
if (!spi->bits_per_word)
spi->bits_per_word = 8;
+
+ if (spi->mode & ~MODEBITS) {
+ dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
+ __FUNCTION__, spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
retval = xilinx_spi_setup_transfer(spi, NULL);
if (retval < 0)
return retval;
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
- __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
- spi->bits_per_word, 0);
+ __FUNCTION__, spi->mode & MODEBITS, spi->bits_per_word, 0);
return 0;
}
+static inline void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
+{
+ u8 sr;
+
+ /* Fill the Tx FIFO with as many bytes as possible */
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
+ if (xspi->tx_ptr) {
+ out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
+ } else {
+ out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
+ }
+ xspi->remaining_bytes--;
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ }
+}
+
static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct xilinx_spi *xspi;
- u8 __iomem *regs_base;
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u32 ipif_ier;
u16 cr;
- u8 sr;
/* We get here with transmitter inhibited */
- xspi = spi_master_get_devdata(spi->master);
- regs_base = xspi->regs;
-
xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf;
xspi->remaining_bytes = t->len;
INIT_COMPLETION(xspi->done);
- /* Fill the Tx FIFO with as many bytes as possible */
- sr = in_8(regs_base + XSPI_SR_OFFSET);
- while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
- if (xspi->tx_ptr) {
- out_8(regs_base + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
- } else {
- out_8(regs_base + XSPI_TXD_OFFSET, 0);
- }
- xspi->remaining_bytes--;
- sr = in_8(regs_base + XSPI_SR_OFFSET);
- }
+ xilinx_spi_fill_tx_fifo(xspi);
/* Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
*/
- ipif_ier = xspi_in32(regs_base + XIPIF_V123B_IIER_OFFSET);
- xspi_out32(regs_base + XIPIF_V123B_IIER_OFFSET,
- ipif_ier | XSPI_INTR_TX_EMPTY);
+ ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
+ out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
+ ipif_ier | XSPI_INTR_TX_EMPTY);
/* Start the transfer by not inhibiting the transmitter any longer */
- cr = xspi_in16(regs_base + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
- xspi_out16(regs_base + XSPI_CR_OFFSET, cr);
+ cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
wait_for_completion(&xspi->done);
/* Disable the transmit empty interrupt */
- xspi_out32(regs_base + XIPIF_V123B_IIER_OFFSET, ipif_ier);
+ out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
return t->len - xspi->remaining_bytes;
}
@@ -255,16 +255,12 @@
*/
static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
{
- struct xilinx_spi *xspi;
- u8 __iomem *regs_base;
+ struct xilinx_spi *xspi = dev_id;
u32 ipif_isr;
- xspi = (struct xilinx_spi *) dev_id;
- regs_base = xspi->regs;
-
- /* Get the IPIF inetrrupts, and clear them immediately */
- ipif_isr = xspi_in32(regs_base + XIPIF_V123B_IISR_OFFSET);
- xspi_out32(regs_base + XIPIF_V123B_IISR_OFFSET, ipif_isr);
+ /* Get the IPIF interrupts, and clear them immediately */
+ ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
u16 cr;
@@ -275,40 +271,29 @@
* transmitter while the Isr refills the transmit register/FIFO,
* or make sure it is stopped if we're done.
*/
- cr = xspi_in16(regs_base + XSPI_CR_OFFSET);
- xspi_out16(regs_base + XSPI_CR_OFFSET,
- cr | XSPI_CR_TRANS_INHIBIT);
+ cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
+ out_be16(xspi->regs + XSPI_CR_OFFSET,
+ cr | XSPI_CR_TRANS_INHIBIT);
/* Read out all the data from the Rx FIFO */
- sr = in_8(regs_base + XSPI_SR_OFFSET);
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
u8 data;
- data = in_8(regs_base + XSPI_RXD_OFFSET);
+ data = in_8(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*xspi->rx_ptr++ = data;
}
- sr = in_8(regs_base + XSPI_SR_OFFSET);
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
}
/* See if there is more data to send */
if (xspi->remaining_bytes > 0) {
- /* sr content is valid here; no need for io_8() */
- while ((sr & XSPI_SR_TX_FULL_MASK) == 0
- && xspi->remaining_bytes > 0) {
- if (xspi->tx_ptr) {
- out_8(regs_base + XSPI_TXD_OFFSET,
- *xspi->tx_ptr++);
- } else {
- out_8(regs_base + XSPI_TXD_OFFSET, 0);
- }
- xspi->remaining_bytes--;
- sr = in_8(regs_base + XSPI_SR_OFFSET);
- }
+ xilinx_spi_fill_tx_fifo(xspi);
/* Start the transfer by not inhibiting the
* transmitter any longer
*/
- xspi_out16(regs_base + XSPI_CR_OFFSET, cr);
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
} else {
/* No more data to send.
* Indicate the transfer is completed.
@@ -359,6 +344,12 @@
xspi->bitbang.master->setup = xilinx_spi_setup;
init_completion(&xspi->done);
+ if (!request_mem_region(r->start,
+ r->end - r->start + 1, XILINX_SPI_NAME)) {
+ ret = -ENXIO;
+ goto put_master;
+ }
+
xspi->regs = ioremap(r->start, r->end - r->start + 1);
if (xspi->regs == NULL) {
ret = -ENOMEM;
@@ -373,6 +364,7 @@
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;
+ xspi->speed_hz = pdata->speed_hz;
/* SPI controller initializations */
xspi_init_hw(xspi->regs);
@@ -411,7 +403,6 @@
xspi = spi_master_get_devdata(master);
spi_bitbang_stop(&xspi->bitbang);
- xspi_abort_transfer(xspi->regs);
free_irq(xspi->irq, xspi);
iounmap(xspi->regs);
platform_set_drvdata(dev, 0);
[-- Attachment #2: xilinx-spi-driver.ko.patch --]
[-- Type: text/x-patch, Size: 15373 bytes --]
Simple driver for Xilinx SPI controler.
From: Andrei Konovalov <ank@localhost.localdomain>
Only master mode is supported. No support for multiple masters.
Slave mode is not supported either.
Not using level 1 drivers from EDK.
Signed-off-by: Yuri Frolov <yfrolov@ru.mvista.com>
Signed-off-by: Andrei Konovalov <akonovalov@ru.mvista.com>
---
---
arch/ppc/syslib/virtex_devices.h | 7 +
drivers/spi/Kconfig | 9 +
drivers/spi/Makefile | 1
drivers/spi/xilinx_spi.c | 438 ++++++++++++++++++++++++++++++++++++++
4 files changed, 455 insertions(+), 0 deletions(-)
diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
index b49dc61..420a634 100644
--- a/arch/ppc/syslib/virtex_devices.h
+++ b/arch/ppc/syslib/virtex_devices.h
@@ -31,4 +31,11 @@ struct xtemac_platform_data {
*/
int virtex_device_fixup(struct platform_device *dev);
+/* SPI Controller IP */
+struct xspi_platform_data {
+ s16 bus_num;
+ u16 num_chipselect;
+ u32 speed_hz;
+};
+
#endif /* __ASM_VIRTEX_DEVICES_H__ */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5e3f748..851d651 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -156,6 +156,15 @@ config SPI_S3C24XX_GPIO
GPIO lines to provide the SPI bus. This can be used where
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
+
+config SPI_XILINX
+ tristate "Xilinx SPI controller"
+ depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This enables using the SPI controller IP from Xilinx EDK in master
+ mode. See the DS464, "OPB Serial Peripheral Interface (SPI) (v1.00e)"
+ Product Specification document for the hardware details.
#
# Add new SPI master controllers in alphabetical order above this line
#
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5788d86..a2412bd 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
+obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
new file mode 100644
index 0000000..a0e96d7
--- /dev/null
+++ b/drivers/spi/xilinx_spi.c
@@ -0,0 +1,438 @@
+/*
+ * xilinx_spi.c
+ *
+ * Xilinx SPI controler driver (master mode only)
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is licensed
+ * "as is" without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/io.h>
+#include <syslib/virtex_devices.h>
+
+#define XILINX_SPI_NAME "xspi"
+
+/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
+ * Product Specification", DS464
+ */
+#define XSPI_CR_OFFSET 0x62 /* 16-bit Control Register */
+
+#define XSPI_CR_ENABLE 0x02
+#define XSPI_CR_MASTER_MODE 0x04
+#define XSPI_CR_CPOL 0x08
+#define XSPI_CR_CPHA 0x10
+#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL)
+#define XSPI_CR_TXFIFO_RESET 0x20
+#define XSPI_CR_RXFIFO_RESET 0x40
+#define XSPI_CR_MANUAL_SSELECT 0x80
+#define XSPI_CR_TRANS_INHIBIT 0x100
+
+#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */
+
+#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
+#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
+#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */
+#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
+#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
+
+#define XSPI_TXD_OFFSET 0x6b /* 8-bit Data Transmit Register */
+#define XSPI_RXD_OFFSET 0x6f /* 8-bit Data Receive Register */
+
+#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
+
+/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
+ * IPIF registers are 32 bit
+ */
+#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */
+#define XIPIF_V123B_GINTR_ENABLE 0x80000000
+
+#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */
+#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */
+
+#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */
+#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while
+ * disabled */
+#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */
+#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
+#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
+#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */
+
+#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
+#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
+
+struct xilinx_spi {
+ /* bitbang has to be first */
+ struct spi_bitbang bitbang;
+ struct completion done;
+
+ u32 regs_phys; /* phys. address of the control registers */
+ void __iomem *regs; /* virt. address of the control registers */
+
+ u32 irq;
+
+ u32 speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
+
+ u8 *rx_ptr; /* pointer in the Tx buffer */
+ const u8 *tx_ptr; /* pointer in the Rx buffer */
+ int remaining_bytes; /* the number of bytes left to transfer */
+};
+
+static void xspi_init_hw(void __iomem *regs_base)
+{
+ /* Reset the SPI device */
+ out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
+ XIPIF_V123B_RESET_MASK);
+ /* Disable all the interrupts just in case */
+ out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
+ /* Enable the global IPIF interrupt */
+ out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
+ XIPIF_V123B_GINTR_ENABLE);
+ /* Deselect the slave on the SPI bus */
+ out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+ /* Disable the transmitter, enable Manual Slave Select Assertion,
+ * put SPI controller into master mode, and enable it */
+ out_be16(regs_base + XSPI_CR_OFFSET,
+ XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
+ | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
+}
+
+static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
+{
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+
+ if (is_on == BITBANG_CS_INACTIVE) {
+ /* Deselect the slave on the SPI bus */
+ out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
+ } else if (is_on == BITBANG_CS_ACTIVE) {
+ /* Set the SPI clock phase and polarity */
+ u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
+ & ~XSPI_CR_MODE_MASK;
+ if (spi->mode & SPI_CPHA)
+ cr |= XSPI_CR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ cr |= XSPI_CR_CPOL;
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+
+ /* We do not check spi->max_speed_hz here as the SPI clock
+ * frequency is not software programmable (the IP block design
+ * parameter)
+ */
+
+ /* Activate the chip select */
+ out_be32(xspi->regs + XSPI_SSR_OFFSET,
+ ~(0x0001 << spi->chip_select));
+ }
+}
+
+/* spi_bitbang requires custom setup_transfer() to be defined if there is a
+ * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
+ * supports just 8 bits per word, and SPI clock can't be changed in software.
+ * Check for 8 bits per word. Chip select delay calculations could be
+ * added here as soon as bitbang_work() can be made aware of the delay value.
+ */
+static int xilinx_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ u8 bits_per_word;
+ u32 hz;
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+
+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
+ hz = (t) ? t->speed_hz : spi->max_speed_hz;
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
+ __FUNCTION__, bits_per_word);
+ return -EINVAL;
+ }
+
+ if (hz && xspi->speed_hz > hz) {
+ dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
+ __FUNCTION__, hz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
+
+static int xilinx_spi_setup(struct spi_device *spi)
+{
+ struct spi_bitbang *bitbang;
+ struct xilinx_spi *xspi;
+ int retval;
+
+ xspi = spi_master_get_devdata(spi->master);
+ bitbang = &xspi->bitbang;
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if (spi->mode & ~MODEBITS) {
+ dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
+ __FUNCTION__, spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ retval = xilinx_spi_setup_transfer(spi, NULL);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
+ __FUNCTION__, spi->mode & MODEBITS, spi->bits_per_word, 0);
+
+ return 0;
+}
+
+static inline void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
+{
+ u8 sr;
+
+ /* Fill the Tx FIFO with as many bytes as possible */
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
+ if (xspi->tx_ptr) {
+ out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
+ } else {
+ out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
+ }
+ xspi->remaining_bytes--;
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ }
+}
+
+static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ u32 ipif_ier;
+ u16 cr;
+
+ /* We get here with transmitter inhibited */
+
+ xspi->tx_ptr = t->tx_buf;
+ xspi->rx_ptr = t->rx_buf;
+ xspi->remaining_bytes = t->len;
+ INIT_COMPLETION(xspi->done);
+
+ xilinx_spi_fill_tx_fifo(xspi);
+
+ /* Enable the transmit empty interrupt, which we use to determine
+ * progress on the transmission.
+ */
+ ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
+ out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
+ ipif_ier | XSPI_INTR_TX_EMPTY);
+
+ /* Start the transfer by not inhibiting the transmitter any longer */
+ cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+
+ wait_for_completion(&xspi->done);
+
+ /* Disable the transmit empty interrupt */
+ out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
+
+ return t->len - xspi->remaining_bytes;
+}
+
+
+/* This driver supports single master mode only. Hence Tx FIFO Empty
+ * is the only interrupt we care about.
+ * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
+ * Fault are not to happen.
+ */
+static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
+{
+ struct xilinx_spi *xspi = dev_id;
+ u32 ipif_isr;
+
+ /* Get the IPIF interrupts, and clear them immediately */
+ ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
+
+ if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
+ u16 cr;
+ u8 sr;
+
+ /* A transmit has just completed. Process received data and
+ * check for more data to transmit. Always inhibit the
+ * transmitter while the Isr refills the transmit register/FIFO,
+ * or make sure it is stopped if we're done.
+ */
+ cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
+ out_be16(xspi->regs + XSPI_CR_OFFSET,
+ cr | XSPI_CR_TRANS_INHIBIT);
+
+ /* Read out all the data from the Rx FIFO */
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
+ u8 data;
+
+ data = in_8(xspi->regs + XSPI_RXD_OFFSET);
+ if (xspi->rx_ptr) {
+ *xspi->rx_ptr++ = data;
+ }
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ }
+
+ /* See if there is more data to send */
+ if (xspi->remaining_bytes > 0) {
+ xilinx_spi_fill_tx_fifo(xspi);
+ /* Start the transfer by not inhibiting the
+ * transmitter any longer
+ */
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+ } else {
+ /* No more data to send.
+ * Indicate the transfer is completed.
+ */
+ complete(&xspi->done);
+ }
+ } else {
+ /* spurious interrupt */
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init xilinx_spi_probe(struct platform_device *dev)
+{
+ int ret = 0;
+ struct spi_master *master;
+ struct xilinx_spi *xspi;
+ struct xspi_platform_data *pdata;
+ struct resource *r;
+
+ /* Get resources(memory, IRQ) associated with the device */
+ master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi));
+
+ if (master == NULL) {
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(dev, master);
+ pdata = dev->dev.platform_data;
+
+ if (pdata == NULL) {
+ ret = -ENODEV;
+ goto put_master;
+ }
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENODEV;
+ goto put_master;
+ }
+
+ xspi = spi_master_get_devdata(master);
+ xspi->bitbang.master = spi_master_get(master);
+ xspi->bitbang.chipselect = xilinx_spi_chipselect;
+ xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
+ xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
+ xspi->bitbang.master->setup = xilinx_spi_setup;
+ init_completion(&xspi->done);
+
+ if (!request_mem_region(r->start,
+ r->end - r->start + 1, XILINX_SPI_NAME)) {
+ ret = -ENXIO;
+ goto put_master;
+ }
+
+ xspi->regs = ioremap(r->start, r->end - r->start + 1);
+ if (xspi->regs == NULL) {
+ ret = -ENOMEM;
+ goto put_master;
+ }
+
+ xspi->irq = platform_get_irq(dev, 0);
+ if (xspi->irq < 0) {
+ ret = -ENXIO;
+ goto unmap_io;
+ }
+
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->num_chipselect;
+ xspi->speed_hz = pdata->speed_hz;
+
+ /* SPI controller initializations */
+ xspi_init_hw(xspi->regs);
+
+ /* Register for SPI Interrupt */
+ ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+ if (ret != 0)
+ goto unmap_io;
+
+ ret = spi_bitbang_start(&xspi->bitbang);
+ if (ret != 0) {
+ printk(KERN_ALERT "spi_btbang_start FAILED\n");
+ goto free_irq;
+ }
+
+ printk(KERN_INFO "%s: at 0x%08X mapped to 0x%08X, irq=%d\n",
+ dev->dev.bus_id, r->start, (u32)xspi->regs, xspi->irq);
+
+ return ret;
+
+free_irq:
+ free_irq(xspi->irq, xspi);
+unmap_io:
+ iounmap(xspi->regs);
+put_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int __devexit xilinx_spi_remove(struct platform_device *dev)
+{
+ struct xilinx_spi *xspi;
+ struct spi_master *master;
+
+ master = platform_get_drvdata(dev);
+ xspi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&xspi->bitbang);
+ free_irq(xspi->irq, xspi);
+ iounmap(xspi->regs);
+ platform_set_drvdata(dev, 0);
+ spi_master_put(xspi->bitbang.master);
+
+ return 0;
+}
+
+static struct platform_driver xilinx_spi_driver = {
+ .probe = xilinx_spi_probe,
+ .remove = __devexit_p(xilinx_spi_remove),
+ .driver = {
+ .name = XILINX_SPI_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init xilinx_spi_init(void)
+{
+ return platform_driver_register(&xilinx_spi_driver);
+}
+
+static void __exit xilinx_spi_exit(void)
+{
+ platform_driver_unregister(&xilinx_spi_driver);
+}
+
+module_init(xilinx_spi_init);
+module_exit(xilinx_spi_exit);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("Xilinx SPI driver");
+MODULE_LICENSE("GPL");
^ permalink raw reply related
* [PATCH] PHY fixed driver: rework release path and update phy_id notation
From: Vitaly Bordug @ 2007-06-09 16:21 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linuxppc-dev, linux-kernel, netdev
device_bind_driver() error code returning has been fixed.
release() function has been written, so that to free resources
in correct way; the release path is now clean.
Before the rework, it used to cause
Device 'fixed@100:1' does not have a release() function, it is broken
and must be fixed.
BUG: at drivers/base/core.c:104 device_release()
Call Trace:
[<ffffffff802ec380>] kobject_cleanup+0x53/0x7e
[<ffffffff802ec3ab>] kobject_release+0x0/0x9
[<ffffffff802ecf3f>] kref_put+0x74/0x81
[<ffffffff8035493b>] fixed_mdio_register_device+0x230/0x265
[<ffffffff80564d31>] fixed_init+0x1f/0x35
[<ffffffff802071a4>] init+0x147/0x2fb
[<ffffffff80223b6e>] schedule_tail+0x36/0x92
[<ffffffff8020a678>] child_rip+0xa/0x12
[<ffffffff80311714>] acpi_ds_init_one_object+0x0/0x83
[<ffffffff8020705d>] init+0x0/0x2fb
[<ffffffff8020a66e>] child_rip+0x0/0x12
Also changed the notation of the fixed phy definition on
mdio bus to the form of <speed>+<duplex> to make it able to be used by
gianfar and ucc_geth that define phy_id strictly as "%d:%d"
Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
---
drivers/net/phy/Kconfig | 4 ++
drivers/net/phy/fixed.c | 93 +++++++++++++++++++++++++++--------------------
2 files changed, 57 insertions(+), 40 deletions(-)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 09b6f25..a938c48 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -71,4 +71,8 @@ config FIXED_MII_100_FDX
bool "Emulation for 100M Fdx fixed PHY behavior"
depends on FIXED_PHY
+config FIXED_MII_1000_FDX
+ bool "Emulation for 1000M Fdx fixed PHY behavior"
+ depends on FIXED_PHY
+
endif # PHYLIB
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 68c99b4..34b9111 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -187,12 +187,29 @@ static struct phy_driver fixed_mdio_driver = {
.driver = { .owner = THIS_MODULE,},
};
+static void fixed_mdio_release (struct device * dev)
+{
+ struct phy_device *phydev = container_of(dev, struct phy_device, dev);
+ struct mii_bus *bus = phydev->bus;
+ struct fixed_info *fixed = bus->priv;
+
+ kfree(phydev);
+ kfree(bus->dev);
+ kfree(bus);
+ kfree(fixed->regs);
+ kfree(fixed);
+}
+
/*-----------------------------------------------------------------------------
* This func is used to create all the necessary stuff, bind
* the fixed phy driver and register all it on the mdio_bus_type.
- * speed is either 10 or 100, duplex is boolean.
+ * speed is either 10 or 100 or 1000, duplex is boolean.
* number is used to create multiple fixed PHYs, so that several devices can
* utilize them simultaneously.
+ *
+ * The device on mdio bus will look like <bus_id>:<phy_id>,
+ * bus_id = number
+ * phy_id = speed+duplex.
*-----------------------------------------------------------------------------*/
static int fixed_mdio_register_device(int number, int speed, int duplex)
{
@@ -221,6 +238,12 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
}
fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL);
+ if (NULL == fixed->regs) {
+ kfree(dev);
+ kfree(new_bus);
+ kfree(fixed);
+ return -ENOMEM;
+ }
fixed->regs_num = MII_REGS_NUM;
fixed->phy_status.speed = speed;
fixed->phy_status.duplex = duplex;
@@ -249,57 +272,43 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
fixed->phydev = phydev;
if(NULL == phydev) {
- err = -ENOMEM;
- goto device_create_fail;
+ kfree(dev);
+ kfree(new_bus);
+ kfree(fixed->regs);
+ kfree(fixed);
+ return -ENOMEM;
}
phydev->irq = PHY_IGNORE_INTERRUPT;
phydev->dev.bus = &mdio_bus_type;
- if(number)
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- "fixed_%d@%d:%d", number, speed, duplex);
- else
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- "fixed@%d:%d", speed, duplex);
+ snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
+ "%d:%d", number, speed + duplex);
+
phydev->bus = new_bus;
+ phydev->dev.driver = &fixed_mdio_driver.driver;
+ phydev->dev.release = fixed_mdio_release;
+
+ err = phydev->dev.driver->probe(&phydev->dev);
+ if(err < 0) {
+ printk(KERN_ERR "Phy %s: problems with fixed driver\n",
+ phydev->dev.bus_id);
+ kfree(phydev);
+ kfree(dev);
+ kfree(new_bus);
+ kfree(fixed->regs);
+ kfree(fixed);
+ return err;
+ }
+
err = device_register(&phydev->dev);
if(err) {
printk(KERN_ERR "Phy %s failed to register\n",
phydev->dev.bus_id);
- goto bus_register_fail;
- }
-
- /*
- the mdio bus has phy_id match... In order not to do it
- artificially, we are binding the driver here by hand;
- it will be the same for all the fixed phys anyway.
- */
- phydev->dev.driver = &fixed_mdio_driver.driver;
-
- err = phydev->dev.driver->probe(&phydev->dev);
- if(err < 0) {
- printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
- goto probe_fail;
}
- err = device_bind_driver(&phydev->dev);
- if (err)
- goto probe_fail;
-
return 0;
-
-probe_fail:
- device_unregister(&phydev->dev);
-bus_register_fail:
- kfree(phydev);
-device_create_fail:
- kfree(dev);
- kfree(new_bus);
- kfree(fixed);
-
- return err;
}
@@ -322,11 +331,11 @@ static int __init fixed_init(void)
driver to them.
Then the external software can lookup the phy bus by searching
- fixed@speed:duplex, e.g. fixed@100:1, to be connected to the
+ 0:speed+duplex, e.g. 0:101, to be connected to the
virtual 100M Fdx phy.
In case several virtual PHYs required, the bus_id will be in form
- fixed_<num>@<speed>:<duplex>, which make it able even to define
+ <num>:<duplex>+<speed>, which make it able even to define
driver-specific link control callback, if for instance PHY is completely
SW-driven.
@@ -338,6 +347,10 @@ static int __init fixed_init(void)
#endif
#endif
+#ifdef CONFIG_FIXED_MII_1000_FDX
+ fixed_mdio_register_device(0, 1000, 1);
+#endif
+
#ifdef CONFIG_FIXED_MII_100_FDX
fixed_mdio_register_device(0, 100, 1);
#endif
^ permalink raw reply related
* Re: [PATCH 1/6] 82xx: Add the support of Wind River SBC PowerQUICCII 82xx
From: Vitaly Bordug @ 2007-06-09 15:08 UTC (permalink / raw)
To: Mark Zhan; +Cc: linuxppc-dev@ozlabs.org, paulus@samba.org
In-Reply-To: <1181292534.11341.9.camel@mark>
On Fri, 08 Jun 2007 16:48:53 +0800
Mark Zhan <rongkai.zhan@windriver.com> wrote:
> Current MII bitbang bus driver hard-codes the phy mask of mii_bus to
> ~0x09, which is actually specific for the FSL boards. This patch will
> make the bitbang driver to generate MII bus phy_mask dynamically.
>
Please send this to netdev, CC me.
Of course since subject goes into SCM, it should be individual
and reflect briefly the nature of the specific change.
> Signed-off-by: Mark Zhan <rongkai.zhan@windriver.com>
> ---
--
Sincerely,
Vitaly
^ permalink raw reply
* Re: [PATCH 3/6] 82xx: Add the support of Wind River SBC PowerQUICCII 82xx
From: Vitaly Bordug @ 2007-06-09 15:25 UTC (permalink / raw)
To: Mark Zhan; +Cc: linuxppc-dev@ozlabs.org, paulus@samba.org
In-Reply-To: <1181292878.11341.15.camel@mark>
On Fri, 08 Jun 2007 16:54:38 +0800
Mark Zhan <rongkai.zhan@windriver.com> wrote:
> snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
> - (u32)res.start, fs_enet_data.phy_addr);
> + fs_enet_dev->id, fs_enet_data.phy_addr);
> +
> fs_enet_data.bus_id = (char*)&bus_id[(*id)];
Have to admit this is not correct. The issue is in fs_enet code (which should take mdio bus id, not device id), and I'll cover it.
--
Sincerely,
Vitaly
^ permalink raw reply
* a question for linux framebuffer driver
From: silicom @ 2007-06-09 12:21 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 359 bytes --]
Hello,
Now I'm porting framebuffer driver for ml403 in linux 2.6.17.1, but I find after registering the driver using driver_register function in xilinxfb_int, the xilinxfb_drv_probe function has not been called, so framebuffer not registered yet, no devices founded(but I have connected the monitor). I want to know when will xilinxfb_drv_probe be called?
[-- Attachment #2: Type: text/html, Size: 720 bytes --]
^ permalink raw reply
* Re: [patch 08/18] PS3: Kexec support (and a tutoral on the kexec flow for 64 bit powerpc)
From: Milton Miller @ 2007-06-09 8:17 UTC (permalink / raw)
To: Geoff Levand; +Cc: ppcdev
In-Reply-To: <4666233F.1080103@am.sony.com>
On Wed Jun 6 13:00:15 EST 2007, Geoff Levand wrote:
> Fixup the core platform parts needed for kexec to work on the PS3.
> - Setup ps3_hpte_clear correctly.
> - Mask interrupts on irq removal.
> - Release all hypervisor resources.
>
> Signed-off-by: Geoff Levand <geoffrey.levand at am.sony.com>
> ---
> arch/powerpc/platforms/ps3/htab.c | 14 +-
> arch/powerpc/platforms/ps3/interrupt.c | 199
> ++++++++++++++++++++-------------
> arch/powerpc/platforms/ps3/setup.c | 29 ++--
> 3 files changed, 147 insertions(+), 95 deletions(-)
>
> --- a/arch/powerpc/platforms/ps3/htab.c
> +++ b/arch/powerpc/platforms/ps3/htab.c
> @@ -234,10 +234,18 @@ static void ps3_hpte_invalidate(unsigned
>
> static void ps3_hpte_clear(void)
> {
> - /* Make sure to clean up the frame buffer device first */
> - ps3fb_cleanup();
I'm glad to see this go. Which patch added the call to the driver?
> + int result;
>
> - lv1_unmap_htab(htab_addr);
> + DBG(" -> %s:%d\n", __func__, __LINE__);
> +
> + result = lv1_unmap_htab(htab_addr);
> + BUG_ON(result);
> +
> + ps3_mm_shutdown();
> +
> + ps3_mm_vas_destroy();
>
I tried to look at these to check that nothing dynamically allocated
was being touched. I didn't find anything if the memory had been
hot-unplugged, but it also looked like they skipped the last one.
> +
> + DBG(" <- %s:%d\n", __func__, __LINE__);
> }
>
> void __init ps3_hpte_init(unsigned long htab_size)
>
[skipped interrupt.c changes]
> --- a/arch/powerpc/platforms/ps3/setup.c
> +++ b/arch/powerpc/platforms/ps3/setup.c
> @@ -209,31 +209,28 @@ static int __init ps3_probe(void)
> #if defined(CONFIG_KEXEC)
> static void ps3_kexec_cpu_down(int crash_shutdown, int secondary)
> {
> - DBG(" -> %s:%d\n", __func__, __LINE__);
> + int result;
> + u64 ppe_id;
> + u64 thread_id = secondary ? 1 : 0;
This is wrong. This is not what secondary means. To get the
thread_id you must use smp_processor_id for logical or
hard_smp_processor_id() for the hardware thread id.
> +
> + DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, secondary);
> + ps3_smp_cleanup_cpu(thread_id);
> +
> + lv1_get_logical_ppe_id(&ppe_id);
> + result = lv1_configure_irq_state_bitmap(ppe_id, secondary ? 0
> : 1, 0);
As the second argument is thread id, again this is wrong.
>
> - if (secondary) {
> - int cpu;
> - for_each_online_cpu(cpu)
> - if (cpu)
> - ps3_smp_cleanup_cpu(cpu);
> - } else
> - ps3_smp_cleanup_cpu(0);
> + /* seems to fail on second call */
> + DBG("%s:%d: lv1_configure_irq_state_bitmap (%d) %s\n",
> __func__,
> + __LINE__, secondary, ps3_result(result));
>
> DBG(" <- %s:%d\n", __func__, __LINE__);
> }
Once linux is running, all processors are identical. That is the S in
SMP. However, during kernel boot, we need one cpu to be running and
the others to wait until the path is prepared. Since kexec effectively
leads to a boot, one cpu becomes known as the boot cpu and the rest
become secondary cpus.
There are two paths to enter the kexec code: the panic code, and the
shutdown/reboot syscall. For normal kexec, whatever cpu thread is
running the user process when it makes the reboot system call will be
the master. For crash kexec, its whichever thread called panic.
The secondary flag to cpu_down exists because the secondary cpus will
call it in ipi context but will not return to the irq layer to eoi the
ipi. The call to cpu_down is made from kexec_smp_down initiated via
the smp_call_function ipi context but instead of returning,
kexec_smp_down calls kexec_smp_wait which will mark the paca, switch to
real mode and spin with the hardware thread in r3 until the master
tells them its done copying the kernel, when it will jump to address
0x60.
The code in default_machine_kexec calls kexec_prepare_cpus which uses
smp_call_function to ipi the other cpus and have them call
kexec_cpu_down. After the secondaries have marked their paca, cpu_down
will be called on the master with the secondary arg 0. During this
call all other cpus are spinning. After this call, the cpu will switch
to a statically allocated stack and copy the new image pages into
place, destroying any dynamically allocated and per-cpu data. It then
calls switches to real mode and calls the htab_clear hook to tear down
the page tables, leaving a clean state for the new kernel. When
finished it copies 256 bytes from the entry point to address 0 and
tells any slaves to branch to 0x60. It then branches to the entry
point (not address 0) with r3 containing its hardware cpu id, r4
containing the entry address, and r5 containing 0.
When using kexec-tools, the entry point in v2wrap.S stores the master
cpu id, calls the generic C code to checksum the image, then stores the
master cpu id as the boot cpu in the device tree header, loads r3 with
the device tree, and enters the new kernel. (This adjusts for the
difference between leaving the kernel, where cpu id is in r3, and
entering the kernel, which expects a pointer to the device tree. The
kexec_load syscall just supplies memory contents and the entry point;
the design is that any registers needed by the new code are to be set
by a trampoline added to the list of image segments by user space. The
master cpu is not known until kexec is initiated and therefore is
passed in the r3 (the very existence of the device-tree structure is
only known to user space, not passed to the system call); the
specification of r4 and r5 for the master thread is for convenience)
Since there is no handoff to say the slave noticed that the master was
done copying the image, I have submitted a kernel patch to release the
slaves to the new kernel's wait code entry point at 0x60 before calling
the htab_clear routine, giving them the time that the htab_clear
function executes in addition to the time for the code in purgatory.
The patch \to copy the payload kernel's spin loop instead of creating
another loop and sync gate is in kexec-testing.
Note that the order describe above is for the 64 bit PowerPC port; most
architectures switch to real mode, flash invalidate the mmu and copy
the new kernel in real mode using an relocatable assembly routine
running at a location chosen by the kernel (a page that is neither an
image source or destination page). The LPAR real mode limitations
deem this impractical; instead we reserve the kernel text, data, and
bss space, the mmu hash table (in non-lpar mode), and any tce tables.
If the execed image was a kernel, it will copy itself to its linked
location as it must when started from open firmware.
>
> static void ps3_machine_kexec(struct kimage *image)
> {
> - unsigned long ppe_id;
> -
> DBG(" -> %s:%d\n", __func__, __LINE__);
>
> - lv1_get_logical_ppe_id(&ppe_id);
> - lv1_configure_irq_state_bitmap(ppe_id, 0, 0);
> - ps3_mm_shutdown();
> - ps3_mm_vas_destroy();
> -
> - default_machine_kexec(image);
> + default_machine_kexec(image); // needs ipi, never returns.
>
> DBG(" <- %s:%d\n", __func__, __LINE__);
> }
>
Others noted this now passthough function can be eliminated.
milton
^ permalink raw reply
* [patch] PS3: Fix USB return value
From: Geoff Levand @ 2007-06-08 23:22 UTC (permalink / raw)
To: gregkh; +Cc: owen, Paul Mackerras, linux-usb-devel, linuxppc-dev
In-Reply-To: <46662443.9020905@am.sony.com>
Fix a minor error on the return value of ps3_ehci_driver_register()
and ps3_ohci_driver_register() when running on non-PS3 systems.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
Hi Greg,
Testers found a problem with my latest PS3 USB patch. Please
add it in.
-Geoff
drivers/usb/host/ehci-ps3.c | 2 +-
drivers/usb/host/ohci-ps3.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -227,7 +227,7 @@ static int ps3_ehci_driver_register(stru
{
return firmware_has_feature(FW_FEATURE_PS3_LV1)
? ps3_system_bus_driver_register(drv)
- : -ENODEV;
+ : 0;
}
static void ps3_ehci_driver_unregister(struct ps3_system_bus_driver *drv)
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -230,7 +230,7 @@ static int ps3_ohci_driver_register(stru
{
return firmware_has_feature(FW_FEATURE_PS3_LV1)
? ps3_system_bus_driver_register(drv)
- : -ENODEV;
+ : 0;
}
static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv)
^ permalink raw reply
* Re: [PATCH 1/3] [PATCH i386] during VM oom condition, kill all threads in process group
From: Eric W. Biederman @ 2007-06-08 22:48 UTC (permalink / raw)
To: will_schmidt
Cc: linuxppc-dev, Andrew Morton, Oleg Nesterov, linux-kernel,
Anton Blanchard
In-Reply-To: <1181337147.21409.42.camel@farscape.rchland.ibm.com>
Will Schmidt <will_schmidt@vnet.ibm.com> writes:
> On Fri, 2007-06-08 at 12:32 -0700, Andrew Morton wrote:
>> On Fri, 08 Jun 2007 14:19:18 -0500
>> Will Schmidt <will_schmidt@vnet.ibm.com> wrote:
>>
>> > > > > zap_other_threads() requires tasklist_lock.
>> >
>
>> In fact, it's probably the case that rcu_read_lock() is now sufficient
>> locking coverage for zap_other_threads() (cc's people).
>>
>> It had better be, because do_group_exit() forgot to take tasklist_lock. It
>> is perhaps relying upon spin_lock()'s hidden rcu_read_lock() properties
>> without so much as a code comment, which would be somewhat nasty of it.
>
>> You could perhaps just call do_group_exit() from within the fault
>> handler,
>> btw.
>
> Yup, so looks like I can actually replace the existing do_exit() call
> with do_group_exit(). I'll sit on this for a bit to give other folks a
> chance to comment on which lock call is sufficient, read_lock() or
> rcu_read_lock(), etc; and do_group_exit()'s issue with taking
> tasklist_lock.
No. The rcu_read_lock is not sufficient.
Yes. sighand->siglock is enough, and we explicitly take it in
do_group_exit before calling zap_other_threads.
Unless I have completely miss-understood this thread.
Eric
^ permalink raw reply
* Re: [PATCH 1/3] [PATCH i386] during VM oom condition, kill all threads in process group
From: Will Schmidt @ 2007-06-08 21:12 UTC (permalink / raw)
To: Andrew Morton
Cc: linuxppc-dev, linux-kernel, Eric W. Biederman, Anton Blanchard,
Oleg Nesterov
In-Reply-To: <20070608123230.520655f5.akpm@linux-foundation.org>
On Fri, 2007-06-08 at 12:32 -0700, Andrew Morton wrote:
> On Fri, 08 Jun 2007 14:19:18 -0500
> Will Schmidt <will_schmidt@vnet.ibm.com> wrote:
>
> > > > > zap_other_threads() requires tasklist_lock.
> >
> In fact, it's probably the case that rcu_read_lock() is now sufficient
> locking coverage for zap_other_threads() (cc's people).
>
> It had better be, because do_group_exit() forgot to take tasklist_lock. It
> is perhaps relying upon spin_lock()'s hidden rcu_read_lock() properties
> without so much as a code comment, which would be somewhat nasty of it.
> You could perhaps just call do_group_exit() from within the fault
> handler,
> btw.
Yup, so looks like I can actually replace the existing do_exit() call
with do_group_exit(). I'll sit on this for a bit to give other folks a
chance to comment on which lock call is sufficient, read_lock() or
rcu_read_lock(), etc; and do_group_exit()'s issue with taking
tasklist_lock.
Thanks,
-Will
^ permalink raw reply
* Re: [RFC/PATCH 4/4] Add support for MSI on Axon-based Cell systems
From: Segher Boessenkool @ 2007-06-08 20:16 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200706082206.55380.arnd@arndb.de>
> If you do
>
> for_each_compatible_node(node, NULL, "foo") {
> do_something(node);
> }
>
> then the reference count is held just as long as the do_something()
> function is run,
Yeah. so (like we discussed on irc) the of_node_get() in
the code under discussion should really be done inside the
axon_msi_setup_one() function.
> and if you do
>
> for_each_compatible_node(node, NULL, "foo")
> if (conditional_func(node))
> break;
>
> then the node variable will have the reference count.
Yes. This is bad form though, "for_each" means for
_each_, open coding the loop would be clearer IMHO.
Segher
^ permalink raw reply
* Re: [RFC/PATCH 4/4] Add support for MSI on Axon-based Cell systems
From: Arnd Bergmann @ 2007-06-08 20:06 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: linuxppc-dev
In-Reply-To: <34656f27cfbc4a091e08526b42969ec1@kernel.crashing.org>
On Friday 08 June 2007, Segher Boessenkool wrote:
> > That wasn't my question though?
>=20
> Oh wait. =A0You're saying for_each_compatible_node() does
> a put() on all nodes it traverses, but no get()? =A0Ouch!
No, just read the code, it does exactly the right thing.
If you do
for_each_compatible_node(node, NULL, "foo") {
do_something(node);
}
then the reference count is held just as long as the do_something()
function is run, and if you do
for_each_compatible_node(node, NULL, "foo")
if (conditional_func(node))
break;
then the node variable will have the reference count.
Arnd <><
^ permalink raw reply
* Re: [RFC/PATCH 4/4] Add support for MSI on Axon-based Cell systems
From: Segher Boessenkool @ 2007-06-08 20:06 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200706082201.26308.arnd@arndb.de>
>> That wasn't my question though?
>
> Sorry, I misread this. The of_node_get is done because we keep
> a reference to the device node in the axon_msic struct. There is
> no module_exit function in the driver that could clean up the
> axon_msic, so we must never have an of_node_put as far as I
> understand.
>>>>>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if =
(axon_msi_setup_one(of_node_get(node)) =3D=3D 0)
>>>>>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 found++;
What if axon_msi_setup_one() returns an error? Sounds
to me like the get() should be inside that function no
matter what?
If the reference counting isn't obvious, it is obviously
wrong ;-)
Segher
^ 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