* [PATCH] PCI: Fix regression in powerpc MSI-X
From: Andre Detsch @ 2009-11-04 15:03 UTC (permalink / raw)
To: linuxppc-dev, michael
Patch f598282f5145036312d90875d0ed5c14b49fd8a7 exposed a problem in
powerpc MSI-X functionality, making network interfaces such as ixgbe
and cxgb3 stop to work when MSI-X is enabled. RX interrupts were not
being generated.
The problem was caused because MSI irq was not being effectively
unmasked after device initialization.
Signed-off-by: Andre Detsch <adetsch@br.ibm.com>
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Index: linux-2.6/arch/powerpc/platforms/pseries/msi.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/pseries/msi.c 2009-11-04
06:35:39.000000000 -0700
+++ linux-2.6/arch/powerpc/platforms/pseries/msi.c 2009-11-04
07:23:27.000000000 -0700
@@ -432,8 +432,6 @@ static int rtas_setup_msi_irqs(struct pc
/* Read config space back so we can restore after reset */
read_msi_msg(virq, &msg);
entry->msg = msg;
-
- unmask_msi_irq(virq);
}
return 0;
Index: linux-2.6/arch/powerpc/platforms/pseries/xics.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/pseries/xics.c 2009-11-04
06:35:39.000000000 -0700
+++ linux-2.6/arch/powerpc/platforms/pseries/xics.c 2009-11-04
07:23:27.000000000 -0700
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/radix-tree.h>
#include <linux/cpu.h>
+#include <linux/msi.h>
#include <linux/of.h>
#include <asm/firmware.h>
@@ -219,6 +220,14 @@ static void xics_unmask_irq(unsigned int
static unsigned int xics_startup(unsigned int virq)
{
+ /*
+ * The generic MSI code returns with the interrupt disabled on the
+ * card, using the MSI mask bits. Firmware doesn't appear to unmask
+ * at that level, so we do it here by hand.
+ */
+ if (irq_to_desc(virq)->msi_desc)
+ unmask_msi_irq(virq);
+
/* unmask it */
xics_unmask_irq(virq);
return 0;
^ permalink raw reply
* RE: DMA to User-Space
From: Jonathan Haws @ 2009-11-04 17:40 UTC (permalink / raw)
To: Bo.Liu@windriver.com; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4AF0E4A0.30802@windriver.com>
> Jonathan Haws wrote:
> > All,
> >
> > I have what may be an unconventional question:
> >
> > Our application consists of data being captured by an FPGA,
> processed, and transferred to SDRAM. I simply give the FPGA an
> address of where I want it stored in SDRAM and it simply DMAs the
> data over and interrupts me when finished. I then take that data
> and store it to disk.
> >
> > I have code in user space that handles all of the writing to disk
> nicely and fast enough for my application (I am capturing data at
> about 35-40 Mbytes/sec).
> >
> > My question is this: is it possible to give a user-space pointer
> to the FPGA to DMA to? It seems like I would have problems with
> alignment, address manipulation, and a whole slew of other issues.
> >
> > What would be the best way to accomplish something like that? I
> want to handle all the disk access in user-space, but I do not want
> to have to copy 40 MB/s from kernel space to user-space either.
> >
> You can maintain a DMA buffer in kernel, then mmap to user space.
> And
> maybe you need some handshake between FPGA and the apps to balance
> input
> datas with datas to disk.
> > I can maintain an allocated, DMA-safe buffer in kernel space if
> needed. Can I simply get a user-space pointer to that buffer? What
> calls are needed to translate addresses?
> >
> Use remap_pfn_range() in your kernel DMA buffer manipulation driver
> .mmap() handler to export DMA buffer address to user space.
>=20
Can you provide an example for how to do that? I have an mmap routine to m=
ap BARs that the FPGA maintains and I can access those, however when I try =
to map the DMA buffer and access what is in it, the system crashes. Here i=
s the mmap function I have right now:
/* fpga_mmap()
*
* Description:
* The purpose of this function is to serve as a 'file_operation'
* which maps different PCI resources into the calling processes
* memory space.
*
* NOTE: The file offset are in page size; i.e.:
* offset 0 in process's mmap syscall -> BAR0
* offset 4096 in process's mmap syscall -> BAR1
* offset 8192 in process's mmap syscall -> BAR2
* offset 12288 -> Streaming DMA buffer
*
* Arguments:
* struct file *filp -- struct representing an open file
* struct vm_area_struct *vma -- struct representing memory 'segme=
nt'
*
* Returns:
* int -- indication of success or failure
*
*/
int fpga_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct pci_dev *dev;
unsigned long addressToMap;
uint8_t mapType =3D 0; /* 0 =3D IO, 1 =3D memory */
/* Get the PCI device */
dev =3D (struct pci_dev*)(filp->private_data);
/* Map in the appropriate BAR based on page offset */
if (vma->vm_pgoff =3D=3D FPGA_CONFIG_SPACE)
{
/* Map BAR1 (the CONFIG area) */
printk(KERN_ALERT "FPGA: Mapping BAR1 (CONFIG BAR).\n");
addressToMap =3D pci_resource_start(dev, FPGA_CONFIG_SPACE);
printk(KERN_ALERT "FPGA: PCI BAR1 (CONFIG BAR) Size -> %#08x.\n",
pci_resource_len(dev, FPGA_CONFIG_SPACE));
mapType =3D 0;
}
else if(vma->vm_pgoff =3D=3D FPGA_TEST_SPACE)
{
/* Map BAR2 (the TEST area) */
printk(KERN_ALERT "FPGA: Mapping BAR2 (TEST BAR).\n");
addressToMap =3D (pci_resource_start(dev, FPGA_TEST_SPACE) +
pci_resource_len(dev, FPGA_TEST_SPACE)) - FPGA_TEST_LENGTH;
printk(KERN_ALERT "FPGA: PCI BAR2 (TEST BAR) Size -> %#08x.\n",
pci_resource_len(dev, FPGA_TEST_SPACE));
mapType =3D 0;
}
else if(vma->vm_pgoff =3D=3D 3)
{
addressToMap =3D (unsigned long)&fpga_drv.strmData[0];
mapType =3D 1;
}
else
{
printk(KERN_ALERT " FPGA: Invalid BAR mapping specified.\n");
return ERROR;
}
/* Execute the mapping */
vma->vm_flags |=3D VM_IO;
vma->vm_flags |=3D VM_RESERVED;
vma->vm_page_prot =3D pgprot_noncached(vma->vm_page_prot);
printk(KERN_ALERT "FPGA: vmSize -> 0x%x.\n",
(unsigned int)(vma->vm_end - vma->vm_start));
if( mapType =3D=3D 0 )
{
if(io_remap_pfn_range(vma, vma->vm_start, addressToMap >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot) !=3D 0)
{
printk(KERN_ALERT "FPGA: Failed to map BAR PCI space to user space.\n");
return ERROR;
}
}
else
{
printk(KERN_NOTICE "FPGA: Mapping stream ptr (%#08x) to user space\n",(ui=
nt32_t)&fpga_drv.strmData[0]);
printk(KERN_NOTICE "FPGA: Setting strmData[0][0] to 0x37\n");
fpga_drv.strmData[0][0] =3D 0x37;
if(remap_pfn_range(vma, vma->vm_start, addressToMap >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot) !=3D 0)
{
printk(KERN_ALERT "FPGA: Failed to map BAR PCI space to user space.\n");
return ERROR;
}
}
return OK;
}
And here is the failure:
~ # ./main
FPGA: vmSize -> 0x4000.
FPGA: Mapping stream ptr (0xd10613bc) to user space
FPGA: Setting strmData[0][0] to 0x37
Unable to handle kernel paging request for data at address 0x00000000
Faulting instruction address: 0xd105f5e0
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT Kilauea
Modules linked in: fpgaDriver
NIP: d105f5e0 LR: d105f5d8 CTR: c003fff4
REGS: cf86dde0 TRAP: 0300 Not tainted (2.6.30.3-wolverine-dirty)
MSR: 00029030 <EE,ME,CE,IR,DR> CR: 24008022 XER: 0000005f
DEAR: 00000000, ESR: 00800000
TASK =3D cf873950[281] 'main' THREAD: cf86c000
GPR00: 00000037 cf86de90 cf873950 00000028 17d78400 c0302028 c0302068 00000=
000
GPR08: 00000000 00000000 00000003 c0300000 24008024 100e89c8 100d6590 10091=
7d8
GPR16: 100d0000 100d0000 c0320000 cfaca07c 00000001 cf8c0230 00000003 00000=
0fb
GPR24: 00000000 cf8a6840 cfaca07c 00000000 d10613bc d106128c 00000004 cfaca=
07c
NIP [d105f5e0] fpga_mmap+0x9c/0x214 [fpgaDriver]
LR [d105f5d8] fpga_mmap+0x94/0x214 [fpgaDriver]
Call Trace:
[cf86de90] [d105f5d8] fpga_mmap+0x94/0x214 [fpgaDriver] (unreliable)
[cf86deb0] [c00c1a4c] mmap_region+0x29c/0x408
[cf86df10] [c000377c] sys_mmap+0x78/0x100
[cf86df40] [c00103fc] ret_from_syscall+0x0/0x3c
Instruction dump:
386302a8 48000735 3b9d0130 3c60d106 7f84e378 386302c4 48000721 3c60d106
386302f8 48000715 813d0130 38000037 <98090000> 7fe3fb78 809f0004 80df0008
---[ end trace 4393e8cf23caef19 ]---
Where am I going wrong?
Using mmap() would work well for me.
Also, what about this:
1. I open /dev/mem and get a file descriptor
2. I use mmap to reserve some physical addresses for my buffers in user spa=
ce.
3. I give that address to the FPGA for DMA use.
4. When I get the FPGA interrupt, I invalidate the data cache and write the=
data to disk
Does that sound like it would work? Would the address I receive from mmap(=
) and pass to the FPGA be the actual physical address, or would I need to s=
end the physical address to the FPGA and use the mmap() address to access a=
nd write to disk?
Thanks for the help!
Jonathan
^ permalink raw reply
* RE: DMA to User-Space
From: Jonathan Haws @ 2009-11-04 17:50 UTC (permalink / raw)
To: Jonathan Haws, Bo.Liu@windriver.com; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <BB99A6BA28709744BF22A68E6D7EB51F03310302E2@midas.usurf.usu.edu>
> 1. I open /dev/mem and get a file descriptor
> 2. I use mmap to reserve some physical addresses for my buffers in
> user space.
> 3. I give that address to the FPGA for DMA use.
> 4. When I get the FPGA interrupt, I invalidate the data cache and
> write the data to disk
>=20
> Does that sound like it would work? Would the address I receive
> from mmap() and pass to the FPGA be the actual physical address, or
> would I need to send the physical address to the FPGA and use the
> mmap() address to access and write to disk?
One more question about this approach: does the mmap() call prevent the ker=
nel from using this memory for other purposes? Will the kernel be able to =
"move" this memory elsewhere? I guess what I am asking is if this memory i=
s locked for all other purposes?
^ permalink raw reply
* Re: Fwd: [PATCH] arch/powerpc: Improve _memcpy
From: Albrecht Dreß @ 2009-11-04 18:12 UTC (permalink / raw)
To: Chris Friesen, Grant Likely; +Cc: Dirk Eibach, linuxppc-dev list, Linux kernel
In-Reply-To: <4AF084C6.3020602@nortel.com>
[-- Attachment #1: Type: text/plain, Size: 1904 bytes --]
See <http://lists.ozlabs.org/pipermail/linuxppc-dev/2009-May/072582.html>.
Any chance to get this one into the tree? Grant?
Cheers, Albrecht.
Am 03.11.09 20:30 schrieb(en) Chris Friesen:
>
> Forwarding to the ppc mailing list.
>
> Chris
>
>
> -------- Original Message --------
> Subject: [PATCH] arch/powerpc: Improve _memcpy
> Date: Tue, 3 Nov 2009 15:20:56 +0100
> From: Dirk Eibach <eibach@gdsys.de>
> To: linux-kernel@vger.kernel.org
> CC: Dirk Eibach <eibach@gdsys.de>
>
> The implementation of _memcpy_fromio and _memcpy_toio seems to be
> suboptimal for size 4.
>
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> ---
> arch/powerpc/kernel/io.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c
> index 1882bf4..8dc7547 100644
> --- a/arch/powerpc/kernel/io.c
> +++ b/arch/powerpc/kernel/io.c
> @@ -161,7 +161,7 @@ void _memcpy_fromio(void *dest, const volatile void
> __iomem *src,
> dest++;
> n--;
> }
> - while(n > 4) {
> + while(n >= 4) {
> *((u32 *)dest) = *((volatile u32 *)vsrc);
> eieio();
> vsrc += 4;
> @@ -190,7 +190,7 @@ void _memcpy_toio(volatile void __iomem *dest, const
> void *src, unsigned long n)
> vdest++;
> n--;
> }
> - while(n > 4) {
> + while(n >= 4) {
> *((volatile u32 *)vdest) = *((volatile u32 *)src);
> src += 4;
> vdest += 4;
> --
> 1.5.6.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
>
[-- Attachment #2: Type: application/pgp-signature, Size: 190 bytes --]
^ permalink raw reply
* Please pull 'next' branch of 4xx tree
From: Josh Boyer @ 2009-11-04 18:55 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev
Hi Ben,
Please pull the next branch of the 4xx tree to get the following commits.
I have some other things in the middle of being worked that may or may not
make it in time for the next release, so I wanted to get these commits into
your tree now rather than wait.
josh
The following changes since commit 588e050887c5f00a39b056848ea58c8b496beab0:
Benjamin Herrenschmidt (1):
powerpc/8xx: Fix build breakage with sparse irq changes
are available in the git repository at:
ssh://master.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git next
Dave Mitchell (1):
powerpc/4xx: Add 16K FIFO size DTS entries on supported platforms
Stefan Roese (1):
powerpc/44x: Enable 64bit (>= 4GB) memory size in Katmai dts
arch/powerpc/boot/dts/canyonlands.dts | 2 ++
arch/powerpc/boot/dts/eiger.dts | 6 ++++++
arch/powerpc/boot/dts/glacier.dts | 6 ++++++
arch/powerpc/boot/dts/haleakala.dts | 2 ++
arch/powerpc/boot/dts/katmai.dts | 14 +++++++++++---
arch/powerpc/boot/dts/kilauea.dts | 4 ++++
arch/powerpc/boot/dts/makalu.dts | 4 ++++
arch/powerpc/boot/dts/redwood.dts | 1 +
8 files changed, 36 insertions(+), 3 deletions(-)
^ permalink raw reply
* RE: DMA to User-Space
From: john.p.price @ 2009-11-04 19:02 UTC (permalink / raw)
To: Jonathan Haws, Bo.Liu; +Cc: linuxppc-dev
In-Reply-To: <BB99A6BA28709744BF22A68E6D7EB51F03310302E2@midas.usurf.usu.edu>
Jonathan, what kind of memory is fpga_drv.strmdata? memory from the
kernel stack, something you allocated? You'll notice you were trying to
access location 0.
To use dma streaming memory you must call dma_map_single() to get the
physical address of fpga_drv.strmdata. That memory must be contiguous.
Then you may call remap_pfn_range with the page offset of the physical
address returned from the dma_map_single() call. Then when the cpu
accesses that region you must sync the region for with dma direction for
cpu or when the device needs to access it, for the device.
LDD3 seems a bit dated on this topic it says to use nopage instead of
remap_pfn_range(), in my experiments remap_pfn_range seemed ok. I would
ask others on the list for their experience on the topic.
Ultimately I went with mapping user space provided address and
implementing dma with scatter-gather.
-----Original Message-----
From: linuxppc-dev-bounces+john.p.price=3Dl-3com.com@lists.ozlabs.org
[mailto:linuxppc-dev-bounces+john.p.price=3Dl-3com.com@lists.ozlabs.org]
On Behalf Of Jonathan Haws
Sent: Wednesday, November 04, 2009 12:40 PM
To: Bo.Liu@windriver.com
Cc: linuxppc-dev@lists.ozlabs.org
Subject: RE: DMA to User-Space
> Jonathan Haws wrote:
> > All,
> >
> > I have what may be an unconventional question:
> >
> > Our application consists of data being captured by an FPGA,
> processed, and transferred to SDRAM. I simply give the FPGA an
> address of where I want it stored in SDRAM and it simply DMAs the
> data over and interrupts me when finished. I then take that data
> and store it to disk.
> >
> > I have code in user space that handles all of the writing to disk
> nicely and fast enough for my application (I am capturing data at
> about 35-40 Mbytes/sec).
> >
> > My question is this: is it possible to give a user-space pointer
> to the FPGA to DMA to? It seems like I would have problems with
> alignment, address manipulation, and a whole slew of other issues.
> >
> > What would be the best way to accomplish something like that? I
> want to handle all the disk access in user-space, but I do not want
> to have to copy 40 MB/s from kernel space to user-space either.
> >
> You can maintain a DMA buffer in kernel, then mmap to user space.
> And
> maybe you need some handshake between FPGA and the apps to balance
> input
> datas with datas to disk.
> > I can maintain an allocated, DMA-safe buffer in kernel space if
> needed. Can I simply get a user-space pointer to that buffer? What
> calls are needed to translate addresses?
> >
> Use remap_pfn_range() in your kernel DMA buffer manipulation driver
> .mmap() handler to export DMA buffer address to user space.
>=20
Can you provide an example for how to do that? I have an mmap routine
to map BARs that the FPGA maintains and I can access those, however when
I try to map the DMA buffer and access what is in it, the system
crashes. Here is the mmap function I have right now:
/* fpga_mmap()
*
* Description:
* The purpose of this function is to serve as a 'file_operation'
* which maps different PCI resources into the calling processes
* memory space.
*
* NOTE: The file offset are in page size; i.e.:
* offset 0 in process's mmap syscall -> BAR0
* offset 4096 in process's mmap syscall -> BAR1
* offset 8192 in process's mmap syscall -> BAR2
* offset 12288 -> Streaming DMA buffer
*
* Arguments:
* struct file *filp -- struct representing an open
file
* struct vm_area_struct *vma -- struct representing memory
'segment'
*
* Returns:
* int -- indication of success or failure
*
*/
int fpga_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct pci_dev *dev;
unsigned long addressToMap;
uint8_t mapType =3D 0; /* 0 =3D IO, 1 =3D memory */
/* Get the PCI device */
dev =3D (struct pci_dev*)(filp->private_data);
/* Map in the appropriate BAR based on page offset */
if (vma->vm_pgoff =3D=3D FPGA_CONFIG_SPACE)
{
/* Map BAR1 (the CONFIG area) */
printk(KERN_ALERT "FPGA: Mapping BAR1 (CONFIG BAR).\n");
addressToMap =3D pci_resource_start(dev,
FPGA_CONFIG_SPACE);
printk(KERN_ALERT "FPGA: PCI BAR1 (CONFIG BAR) Size ->
%#08x.\n",
pci_resource_len(dev, FPGA_CONFIG_SPACE));
mapType =3D 0;
}
else if(vma->vm_pgoff =3D=3D FPGA_TEST_SPACE)
{
/* Map BAR2 (the TEST area) */
printk(KERN_ALERT "FPGA: Mapping BAR2 (TEST BAR).\n");
addressToMap =3D (pci_resource_start(dev, FPGA_TEST_SPACE)
+
pci_resource_len(dev, FPGA_TEST_SPACE)) -
FPGA_TEST_LENGTH;
printk(KERN_ALERT "FPGA: PCI BAR2 (TEST BAR) Size ->
%#08x.\n",
pci_resource_len(dev, FPGA_TEST_SPACE));
mapType =3D 0;
}
else if(vma->vm_pgoff =3D=3D 3)
{
addressToMap =3D (unsigned long)&fpga_drv.strmData[0];
mapType =3D 1;
}
else
{
printk(KERN_ALERT " FPGA: Invalid BAR mapping
specified.\n");
return ERROR;
}
/* Execute the mapping */
vma->vm_flags |=3D VM_IO;
vma->vm_flags |=3D VM_RESERVED;
vma->vm_page_prot =3D pgprot_noncached(vma->vm_page_prot);
printk(KERN_ALERT "FPGA: vmSize -> 0x%x.\n",
(unsigned int)(vma->vm_end - vma->vm_start));
if( mapType =3D=3D 0 )
{
if(io_remap_pfn_range(vma, vma->vm_start, addressToMap
>> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot) !=3D 0)
{
printk(KERN_ALERT "FPGA: Failed to map BAR PCI
space to user space.\n");
return ERROR;
}
}
else
{
printk(KERN_NOTICE "FPGA: Mapping stream ptr (%#08x) to
user space\n",(uint32_t)&fpga_drv.strmData[0]);
printk(KERN_NOTICE "FPGA: Setting strmData[0][0] to
0x37\n");
fpga_drv.strmData[0][0] =3D 0x37;
if(remap_pfn_range(vma, vma->vm_start, addressToMap >>
PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot) !=3D 0)
{
printk(KERN_ALERT "FPGA: Failed to map BAR PCI
space to user space.\n");
return ERROR;
}
}
return OK;
}
And here is the failure:
~ # ./main
FPGA: vmSize -> 0x4000.
FPGA: Mapping stream ptr (0xd10613bc) to user space
FPGA: Setting strmData[0][0] to 0x37
Unable to handle kernel paging request for data at address 0x00000000
Faulting instruction address: 0xd105f5e0
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT Kilauea
Modules linked in: fpgaDriver
NIP: d105f5e0 LR: d105f5d8 CTR: c003fff4
REGS: cf86dde0 TRAP: 0300 Not tainted (2.6.30.3-wolverine-dirty)
MSR: 00029030 <EE,ME,CE,IR,DR> CR: 24008022 XER: 0000005f
DEAR: 00000000, ESR: 00800000
TASK =3D cf873950[281] 'main' THREAD: cf86c000
GPR00: 00000037 cf86de90 cf873950 00000028 17d78400 c0302028 c0302068
00000000
GPR08: 00000000 00000000 00000003 c0300000 24008024 100e89c8 100d6590
100917d8
GPR16: 100d0000 100d0000 c0320000 cfaca07c 00000001 cf8c0230 00000003
000000fb
GPR24: 00000000 cf8a6840 cfaca07c 00000000 d10613bc d106128c 00000004
cfaca07c
NIP [d105f5e0] fpga_mmap+0x9c/0x214 [fpgaDriver]
LR [d105f5d8] fpga_mmap+0x94/0x214 [fpgaDriver]
Call Trace:
[cf86de90] [d105f5d8] fpga_mmap+0x94/0x214 [fpgaDriver] (unreliable)
[cf86deb0] [c00c1a4c] mmap_region+0x29c/0x408
[cf86df10] [c000377c] sys_mmap+0x78/0x100
[cf86df40] [c00103fc] ret_from_syscall+0x0/0x3c
Instruction dump:
386302a8 48000735 3b9d0130 3c60d106 7f84e378 386302c4 48000721 3c60d106
386302f8 48000715 813d0130 38000037 <98090000> 7fe3fb78 809f0004
80df0008
---[ end trace 4393e8cf23caef19 ]---
Where am I going wrong?
Using mmap() would work well for me.
Also, what about this:
1. I open /dev/mem and get a file descriptor
2. I use mmap to reserve some physical addresses for my buffers in user
space.
3. I give that address to the FPGA for DMA use.
4. When I get the FPGA interrupt, I invalidate the data cache and write
the data to disk
Does that sound like it would work? Would the address I receive from
mmap() and pass to the FPGA be the actual physical address, or would I
need to send the physical address to the FPGA and use the mmap() address
to access and write to disk?
Thanks for the help!
Jonathan
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: Regarding FPGA based cascaded PIC
From: Benjamin Herrenschmidt @ 2009-11-04 20:51 UTC (permalink / raw)
To: Thirumalai; +Cc: linuxppc-dev
In-Reply-To: <2DA2EE8F96D44EF69D4D8A712410E546@itd210>
On Wed, 2009-11-04 at 18:09 +0530, Thirumalai wrote:
> you understood correctly. Here the problem lies.Correct me if i am wrong. So
> you are telling that irq_of_parse_and_map() will invoke the map/xlate of my
> FPGA pic. Right.
>
> But this is what not happening. Instead of calling my map/xlate functions
> the irq_of_parse_and_map() function is invoking mpic's map/xlate function.
irq_of_parse_and_map() will call the map/xlate function of the parent
PIC for the given interrupt.
In your case, the interrupts you are calling it for are defined as being
interrupts wiring the FPGA to the MPIC, hence are MPIC inputs, and thus
will be parsed/mapped by the MPIC. From the MPIC standpoint, the FPGA is
just a device.
So the code is doing what you tell it to do :-)
I don't understand what you are actually trying to acheive. If those 3
interrupts aren't outputs from the FPGA to the MPIC but input to the
FPGA then they shouldn't be there, they should be device interrupts
connected to the FPGA. Those will end up with map/xlate called in the
FPGA host.
Ben.
> Here is the piece of code that we are using.
>
> fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
> DPVPX0659_FPGA_NUM_IRQS,&fpga_pic_host_ops,
> NO_IRQ);
> if (fpga_pic_irq_host == NULL) {
> printk("FPGA PIC: Unable to allocate host\n");
> return;
> }
>
> for (i = 0; i < 3; i++) {
> fpga_irqs[i] = irq_of_parse_and_map(pic, i);
> if (fpga_irqs[i] == NO_IRQ) {
> printk("FPGA PIC: can't get irq %d.\n", i);
> continue;
> }
> printk("interrupt from device tree : %d \n",fpga_irqs[i]);
> set_irq_chained_handler(dpvpx0659_fpga_irqs[i],dpvpx0659_fpga_pic_cascade);
> }
>
>
^ permalink raw reply
* [RFC PATCH 0/5] Merge common dynamic OF device tree code
From: Nathan Fontenot @ 2009-11-04 22:07 UTC (permalink / raw)
To: devicetree-discuss, linuxppc-dev, microblaze-uclinux
This is a follow on to Grant Likely's patches, attempting to merge the common
pieces of dynamic OF device tree updating. These patches move the common
code for adding and removing nodes and properties from the device tree to
drivers/of/of_dynamic.c and wraps them under the new OF_DYNAMIC config
option. Additionally this makes the necessary updates to powerpc and
microblaze arch's for this move.
Nathan Fontenot (5)
- Move the declaration of devtree_lock and allnodes to linux/of.h
- Create drivers/of/of_dynamic.c from common code.
- powerpc and pseries updates
- microblaze updates
- powerpc/iseries updates
^ permalink raw reply
* [RFC PATCH 1/5] Move devtree_lock and allnodes declaration to of.h
From: Nathan Fontenot @ 2009-11-04 22:14 UTC (permalink / raw)
To: devicetree-discuss, linuxppc-dev, microblaze-uclinux
In-Reply-To: <4AF1FB29.50905@austin.ibm.com>
Move the declaration of devtree_lock and allnodes from powerpc/microblaze
asm/prom.h to linux/of.h
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
Index: linux-next/include/linux/of.h
===================================================================
--- linux-next.orig/include/linux/of.h 2009-11-02 13:39:46.000000000 -0600
+++ linux-next/include/linux/of.h 2009-11-02 14:17:29.000000000 -0600
@@ -19,6 +19,7 @@
#include <linux/bitops.h>
#include <linux/kref.h>
#include <linux/mod_devicetable.h>
+#include <linux/spinlock.h>
typedef u32 phandle;
typedef u32 ihandle;
@@ -63,6 +64,9 @@
#endif
};
+extern rwlock_t devtree_lock;
+extern struct device_node *allnodes;
+
static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
{
return test_bit(flag, &n->_flags);
Index: linux-next/arch/powerpc/kernel/prom.c
===================================================================
--- linux-next.orig/arch/powerpc/kernel/prom.c 2009-11-02 13:39:40.000000000 -0600
+++ linux-next/arch/powerpc/kernel/prom.c 2009-11-02 14:07:43.000000000 -0600
@@ -32,6 +32,7 @@
#include <linux/debugfs.h>
#include <linux/irq.h>
#include <linux/lmb.h>
+#include <linux/of.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -79,10 +80,6 @@
struct boot_param_header *initial_boot_params;
#endif
-extern struct device_node *allnodes; /* temporary while merging */
-
-extern rwlock_t devtree_lock; /* temporary while merging */
-
/* export that to outside world */
struct device_node *of_chosen;
Index: linux-next/arch/microblaze/include/asm/prom.h
===================================================================
--- linux-next.orig/arch/microblaze/include/asm/prom.h 2009-11-02 13:39:39.000000000 -0600
+++ linux-next/arch/microblaze/include/asm/prom.h 2009-11-02 14:10:13.000000000 -0600
@@ -23,6 +23,7 @@
#include <linux/of_fdt.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <asm/irq.h>
#include <asm/atomic.h>
@@ -37,9 +38,6 @@
#define HAVE_ARCH_DEVTREE_FIXUPS
-extern struct device_node *allnodes; /* temporary while merging */
-extern rwlock_t devtree_lock; /* temporary while merging */
-
/* For updating the device tree at runtime */
extern void of_attach_node(struct device_node *);
extern void of_detach_node(struct device_node *);
Index: linux-next/arch/sparc/kernel/prom.h
===================================================================
--- linux-next.orig/arch/sparc/kernel/prom.h 2009-11-02 13:39:40.000000000 -0600
+++ linux-next/arch/sparc/kernel/prom.h 2009-11-02 14:12:46.000000000 -0600
@@ -2,11 +2,9 @@
#define __PROM_H
#include <linux/spinlock.h>
+#include <linux/of.h>
#include <asm/prom.h>
-extern struct device_node *allnodes; /* temporary while merging */
-extern rwlock_t devtree_lock; /* temporary while merging */
-
extern void * prom_early_alloc(unsigned long size);
extern void irq_trans_init(struct device_node *dp);
^ permalink raw reply
* [RFC PATCH 2/5] Merge dynamic OF code to of_dynamic.c
From: Nathan Fontenot @ 2009-11-04 22:16 UTC (permalink / raw)
To: devicetree-discuss, linuxppc-dev, microblaze-uclinux
In-Reply-To: <4AF1FB29.50905@austin.ibm.com>
Creation of the OF dynamic device tree update code in drivers/of. This
merges the common device tree updating routines to add/remove nodes and
properties from powerpc and microblaze. All of the new code is conditional
based on a new OF_DYNAMIC config option.
There are two updates to the code. First, the routines to update properties
are re-named from prom_* to of_*. This seems correct as the routines no longer
reside in prom.c files. Second, the addition of a notifier chain for when
nodes are added removed from the device tree. This is a feature that currently
exists in powerpc.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
Index: linux-next/drivers/of/of_dynamic.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-next/drivers/of/of_dynamic.c 2009-11-04 14:45:11.000000000 -0600
@@ -0,0 +1,387 @@
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh and other computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * 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.
+ */
+
+#include <linux/of.h>
+
+BLOCKING_NOTIFIER_HEAD(of_update_chain);
+
+/**
+ * of_node_get - Increment refcount of a node
+ * @node: Node to inc refcount, NULL is supported to
+ * simplify writing of callers
+ *
+ * Returns node.
+ */
+struct device_node *of_node_get(struct device_node *node)
+{
+ if (node)
+ kref_get(&node->kref);
+ return node;
+}
+EXPORT_SYMBOL(of_node_get);
+
+static inline struct device_node *kref_to_device_node(struct kref *kref)
+{
+ return container_of(kref, struct device_node, kref);
+}
+
+/**
+ * of_node_release - release a dynamically allocated node
+ * @kref: kref element of the node to be released
+ *
+ * In of_node_put() this function is passed to kref_put()
+ * as the destructor.
+ */
+static void of_node_release(struct kref *kref)
+{
+ struct device_node *node = kref_to_device_node(kref);
+ struct property *prop = node->properties;
+
+ /* We should never be releasing nodes that haven't been detached. */
+ if (!of_node_check_flag(node, OF_DETACHED)) {
+ printk(KERN_WARNING "Bad of_node_put() on %s\n",
+ node->full_name);
+ dump_stack();
+ kref_init(&node->kref);
+ return;
+ }
+
+ if (!of_node_check_flag(node, OF_DYNAMIC))
+ return;
+
+ while (prop) {
+ struct property *next = prop->next;
+ kfree(prop->name);
+ kfree(prop->value);
+ kfree(prop);
+ prop = next;
+
+ if (!prop) {
+ prop = node->deadprops;
+ node->deadprops = NULL;
+ }
+ }
+ kfree(node->full_name);
+ kfree(node->data);
+ kfree(node);
+}
+
+/**
+ * of_node_put - Decrement refcount of a node
+ * @node: Node to dec refcount, NULL is supported to
+ * simplify writing of callers
+ *
+ */
+void of_node_put(struct device_node *node)
+{
+ if (node)
+ kref_put(&node->kref, of_node_release);
+}
+EXPORT_SYMBOL(of_node_put);
+
+static struct device_node *of_derive_parent(char *path)
+{
+ struct device_node *parent = NULL;
+ char *parent_path = "/";
+ size_t parent_path_len = strrchr(path, '/') - path + 1;
+
+ /* reject if path is "/" */
+ if (!strcmp(path, "/"))
+ return ERR_PTR(-EINVAL);
+
+ if (strrchr(path, '/') != path) {
+ parent_path = kmalloc(parent_path_len, GFP_KERNEL);
+ if (!parent_path)
+ return ERR_PTR(-ENOMEM);
+ strlcpy(parent_path, path, parent_path_len);
+ }
+
+ parent = of_find_node_by_path(parent_path);
+ if (!parent)
+ return ERR_PTR(-EINVAL);
+
+ if (strcmp(parent_path, "/"))
+ kfree(parent_path);
+ return parent;
+}
+
+static int of_attach_one_node(struct device_node *np)
+{
+ struct proc_dir_entry *ent;
+ unsigned long flags;
+ int rc;
+
+ of_node_set_flag(np, OF_DYNAMIC);
+ kref_init(&np->kref);
+
+ np->parent = of_derive_parent(np->full_name);
+ if (IS_ERR(np->parent))
+ return PTR_ERR(np->parent);
+
+ rc = of_update_notifier_call(OF_ATTACH_NODE, np);
+ if (rc == NOTIFY_BAD) {
+ printk(KERN_ERR "Failed to add device node %s\n",
+ np->full_name);
+ return -ENOMEM; /* For now, safe to assume kmalloc failure */
+ }
+
+ write_lock_irqsave(&devtree_lock, flags);
+ np->sibling = np->parent->child;
+ np->allnext = allnodes;
+ np->parent->child = np;
+
+ allnodes = np;
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+#ifdef CONFIG_PROC_DEVICETREE
+ ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde);
+ if (ent)
+ proc_device_tree_add_node(np, ent);
+#endif
+
+ of_node_put(np->parent);
+ return 0;
+}
+
+int of_attach_node(struct device_node *np)
+{
+ struct device_node *child = np->child;
+ struct device_node *sibling = np->sibling;
+ int rc;
+
+ np->child = NULL;
+ np->sibling = NULL;
+ np->parent = NULL;
+
+ rc = of_attach_one_node(np);
+ if (rc)
+ return rc;
+
+ if (child) {
+ rc = of_attach_node(child);
+ if (rc)
+ return rc;
+ }
+
+ if (sibling)
+ rc = of_attach_node(sibling);
+
+ return rc;
+}
+EXPORT_SYMBOL(of_attach_node);
+
+/*
+ * "Unplug" a node from the device tree. The caller must hold
+ * a reference to the node. The memory associated with the node
+ * is not freed until its refcount goes to zero.
+ */
+static int of_detach_one_node(struct device_node *np)
+{
+ struct device_node *parent = np->parent;
+ struct property *prop = np->properties;
+ unsigned long flags;
+
+ if (!parent)
+ return -1;
+
+#ifdef CONFIG_PROC_DEVICETREE
+ while (prop) {
+ remove_proc_entry(prop->name, np->pde);
+ prop = prop->next;
+ }
+
+ if (np->pde)
+ remove_proc_entry(np->pde->name, parent->pde);
+#endif
+
+ of_update_notifier_call(OF_DETACH_NODE, np);
+
+ write_lock_irqsave(&devtree_lock, flags);
+
+ if (allnodes == np)
+ allnodes = np->allnext;
+ else {
+ struct device_node *prev;
+ for (prev = allnodes;
+ prev->allnext != np;
+ prev = prev->allnext)
+ ;
+ prev->allnext = np->allnext;
+ }
+
+ if (parent->child == np)
+ parent->child = np->sibling;
+ else {
+ struct device_node *prevsib;
+ for (prevsib = np->parent->child;
+ prevsib->sibling != np;
+ prevsib = prevsib->sibling)
+ ;
+ prevsib->sibling = np->sibling;
+ }
+
+ of_node_set_flag(np, OF_DETACHED);
+ write_unlock_irqrestore(&devtree_lock, flags);
+ of_node_put(np);
+ return 0;
+}
+
+static int _of_detach_node(struct device_node *np)
+{
+ int rc;
+
+ if (np->child) {
+ rc = _of_detach_node(np->child);
+ if (rc)
+ return rc;
+ }
+
+ if (np->sibling) {
+ rc = _of_detach_node(np->sibling);
+ if (rc)
+ return rc;
+ }
+
+ rc = of_detach_one_node(np);
+ return rc;
+}
+
+int of_detach_node(struct device_node *np)
+{
+ int rc;
+
+ if (np->child) {
+ rc = _of_detach_node(np->child);
+ if (rc)
+ return rc;
+ }
+
+ rc = of_detach_one_node(np);
+ return rc;
+}
+EXPORT_SYMBOL(of_detach_node);
+
+/*
+ * Add a property to a node
+ */
+int of_property_attach(struct device_node *np, struct property* prop)
+{
+ struct property **next;
+ unsigned long flags;
+
+ prop->next = NULL;
+
+ write_lock_irqsave(&devtree_lock, flags);
+ next = &np->properties;
+ while (*next) {
+ if (strcmp(prop->name, (*next)->name) == 0) {
+ /* duplicate ! don't insert it */
+ write_unlock_irqrestore(&devtree_lock, flags);
+ return -1;
+ }
+ next = &(*next)->next;
+ }
+ *next = prop;
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+#ifdef CONFIG_PROC_DEVICETREE
+ /* try to add to proc as well if it was initialized */
+ if (np->pde)
+ proc_device_tree_add_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+ return 0;
+}
+EXPORT_SYMBOL(of_property_attach);
+
+/*
+ * Remove a property from a node. Note that we don't actually
+ * remove it, since we have given out who-knows-how-many pointers
+ * to the data using get-property. Instead we just move the property
+ * to the "dead properties" list, so it won't be found any more.
+ */
+int of_property_detach(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+ unsigned long flags;
+ int found = 0;
+
+ write_lock_irqsave(&devtree_lock, flags);
+ next = &np->properties;
+ while (*next) {
+ if (*next == prop) {
+ /* found the node */
+ *next = prop->next;
+ prop->next = np->deadprops;
+ np->deadprops = prop;
+ found = 1;
+ break;
+ }
+ next = &(*next)->next;
+ }
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+ if (!found)
+ return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+ /* try to remove the proc node as well */
+ if (np->pde)
+ proc_device_tree_remove_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+ return 0;
+}
+EXPORT_SYMBOL(of_property_detach);
+
+/*
+ * Update a property in a node. Note that we don't actually
+ * remove it, since we have given out who-knows-how-many pointers
+ * to the data using get-property. Instead we just move the property
+ * to the "dead properties" list, and add the new property to the
+ * property list
+ */
+int of_property_update(struct device_node *np, struct property *newprop,
+ struct property *oldprop)
+{
+ struct property **next;
+ unsigned long flags;
+ int found = 0;
+
+ write_lock_irqsave(&devtree_lock, flags);
+ next = &np->properties;
+ while (*next) {
+ if (*next == oldprop) {
+ /* found the node */
+ newprop->next = oldprop->next;
+ *next = newprop;
+ oldprop->next = np->deadprops;
+ np->deadprops = oldprop;
+ found = 1;
+ break;
+ }
+ next = &(*next)->next;
+ }
+ write_unlock_irqrestore(&devtree_lock, flags);
+
+ if (!found)
+ return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+ /* try to add to proc as well if it was initialized */
+ if (np->pde)
+ proc_device_tree_update_prop(np->pde, newprop, oldprop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+ return 0;
+}
+EXPORT_SYMBOL(of_property_update);
Index: linux-next/include/linux/of.h
===================================================================
--- linux-next.orig/include/linux/of.h 2009-11-03 11:18:08.000000000 -0600
+++ linux-next/include/linux/of.h 2009-11-03 13:42:38.000000000 -0600
@@ -20,6 +20,8 @@
#include <linux/kref.h>
#include <linux/mod_devicetable.h>
#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/notifier.h>
typedef u32 phandle;
typedef u32 ihandle;
@@ -191,4 +193,34 @@
const char *list_name, const char *cells_name, int index,
struct device_node **out_node, const void **out_args);
+#ifdef CONFIG_OF_DYNAMIC
+extern int of_attach_node(struct device_node *np);
+extern int of_detach_node(struct device_node *np);
+extern int of_property_attach(struct device_node *np, struct property *prop);
+extern int of_property_detach(struct device_node *np, struct property *prop);
+extern int of_property_update(struct device_node *np, struct property *newprop,
+ struct property *oldprop);
+
+/* Dynamic Update Notifier Chain */
+extern struct blocking_notifier_head of_update_chain;
+
+#define OF_ATTACH_NODE 1
+#define OF_DETACH_NODE 2
+
+static inline int of_update_notifier_register(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&of_update_chain, nb);
+}
+
+static inline int of_update_notifier_unregister(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&of_update_chain, nb);
+}
+
+static inline int of_update_notifier_call(unsigned int value, void *data)
+{
+ return blocking_notifier_call_chain(&of_update_chain, value, data);
+}
+#endif /* CONFIG_OF_DYNAMIC */
+
#endif /* _LINUX_OF_H */
Index: linux-next/drivers/of/Makefile
===================================================================
--- linux-next.orig/drivers/of/Makefile 2009-11-03 11:18:08.000000000 -0600
+++ linux-next/drivers/of/Makefile 2009-11-03 13:42:35.000000000 -0600
@@ -1,6 +1,7 @@
obj-y = base.o
-obj-$(CONFIG_OF_DEVICE) += device.o platform.o
-obj-$(CONFIG_OF_GPIO) += gpio.o
-obj-$(CONFIG_OF_I2C) += of_i2c.o
-obj-$(CONFIG_OF_SPI) += of_spi.o
-obj-$(CONFIG_OF_MDIO) += of_mdio.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
+obj-$(CONFIG_OF_GPIO) += gpio.o
+obj-$(CONFIG_OF_I2C) += of_i2c.o
+obj-$(CONFIG_OF_SPI) += of_spi.o
+obj-$(CONFIG_OF_MDIO) += of_mdio.o
+obj-$(CONFIG_OF_DYNAMIC) += of_dynamic.o
^ permalink raw reply
* [RFC PATCH 3/5] powerpc and pseries updates for new OF dynamic code
From: Nathan Fontenot @ 2009-11-04 22:18 UTC (permalink / raw)
To: devicetree-discuss, linuxppc-dev, microblaze-uclinux
In-Reply-To: <4AF1FB29.50905@austin.ibm.com>
Updates to powerpc generic and powerpc/pseries. This patch removes the
dynamic device tree updating code from prom.c and deletes the no longer
neccessary pSeries_reconfig.h file, all of the functionality is now in the
generic OF code.
The remaining changes deal with updating code for name changes with using
the OF code.
Signed-off-by: Nathan Fonteot <nfont@austin.ibm.com>
---
Index: linux-next/arch/powerpc/include/asm/pSeries_reconfig.h
===================================================================
--- linux-next.orig/arch/powerpc/include/asm/pSeries_reconfig.h 2009-11-04 14:42:17.000000000 -0600
+++ /dev/null 1970-01-01 00:00:00.000000000 +0000
@@ -1,29 +0,0 @@
-#ifndef _PPC64_PSERIES_RECONFIG_H
-#define _PPC64_PSERIES_RECONFIG_H
-#ifdef __KERNEL__
-
-#include <linux/notifier.h>
-
-/*
- * Use this API if your code needs to know about OF device nodes being
- * added or removed on pSeries systems.
- */
-
-#define PSERIES_RECONFIG_ADD 0x0001
-#define PSERIES_RECONFIG_REMOVE 0x0002
-#define PSERIES_DRCONF_MEM_ADD 0x0003
-#define PSERIES_DRCONF_MEM_REMOVE 0x0004
-
-#ifdef CONFIG_PPC_PSERIES
-extern int pSeries_reconfig_notifier_register(struct notifier_block *);
-extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
-#else /* !CONFIG_PPC_PSERIES */
-static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
-{
- return 0;
-}
-static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
-#endif /* CONFIG_PPC_PSERIES */
-
-#endif /* __KERNEL__ */
-#endif /* _PPC64_PSERIES_RECONFIG_H */
Index: linux-next/arch/powerpc/kernel/prom.c
===================================================================
--- linux-next.orig/arch/powerpc/kernel/prom.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/kernel/prom.c 2009-11-04 14:45:43.000000000 -0600
@@ -50,7 +50,6 @@
#include <asm/btext.h>
#include <asm/sections.h>
#include <asm/machdep.h>
-#include <asm/pSeries_reconfig.h>
#include <asm/pci-bridge.h>
#include <asm/phyp_dump.h>
#include <asm/kexec.h>
@@ -1313,138 +1312,6 @@
return NULL;
}
-/**
- * of_node_get - Increment refcount of a node
- * @node: Node to inc refcount, NULL is supported to
- * simplify writing of callers
- *
- * Returns node.
- */
-struct device_node *of_node_get(struct device_node *node)
-{
- if (node)
- kref_get(&node->kref);
- return node;
-}
-EXPORT_SYMBOL(of_node_get);
-
-static inline struct device_node * kref_to_device_node(struct kref *kref)
-{
- return container_of(kref, struct device_node, kref);
-}
-
-/**
- * of_node_release - release a dynamically allocated node
- * @kref: kref element of the node to be released
- *
- * In of_node_put() this function is passed to kref_put()
- * as the destructor.
- */
-static void of_node_release(struct kref *kref)
-{
- struct device_node *node = kref_to_device_node(kref);
- struct property *prop = node->properties;
-
- /* We should never be releasing nodes that haven't been detached. */
- if (!of_node_check_flag(node, OF_DETACHED)) {
- printk("WARNING: Bad of_node_put() on %s\n", node->full_name);
- dump_stack();
- kref_init(&node->kref);
- return;
- }
-
- if (!of_node_check_flag(node, OF_DYNAMIC))
- return;
-
- while (prop) {
- struct property *next = prop->next;
- kfree(prop->name);
- kfree(prop->value);
- kfree(prop);
- prop = next;
-
- if (!prop) {
- prop = node->deadprops;
- node->deadprops = NULL;
- }
- }
- kfree(node->full_name);
- kfree(node->data);
- kfree(node);
-}
-
-/**
- * of_node_put - Decrement refcount of a node
- * @node: Node to dec refcount, NULL is supported to
- * simplify writing of callers
- *
- */
-void of_node_put(struct device_node *node)
-{
- if (node)
- kref_put(&node->kref, of_node_release);
-}
-EXPORT_SYMBOL(of_node_put);
-
-/*
- * Plug a device node into the tree and global list.
- */
-void of_attach_node(struct device_node *np)
-{
- unsigned long flags;
-
- write_lock_irqsave(&devtree_lock, flags);
- np->sibling = np->parent->child;
- np->allnext = allnodes;
- np->parent->child = np;
- allnodes = np;
- write_unlock_irqrestore(&devtree_lock, flags);
-}
-
-/*
- * "Unplug" a node from the device tree. The caller must hold
- * a reference to the node. The memory associated with the node
- * is not freed until its refcount goes to zero.
- */
-void of_detach_node(struct device_node *np)
-{
- struct device_node *parent;
- unsigned long flags;
-
- write_lock_irqsave(&devtree_lock, flags);
-
- parent = np->parent;
- if (!parent)
- goto out_unlock;
-
- if (allnodes == np)
- allnodes = np->allnext;
- else {
- struct device_node *prev;
- for (prev = allnodes;
- prev->allnext != np;
- prev = prev->allnext)
- ;
- prev->allnext = np->allnext;
- }
-
- if (parent->child == np)
- parent->child = np->sibling;
- else {
- struct device_node *prevsib;
- for (prevsib = np->parent->child;
- prevsib->sibling != np;
- prevsib = prevsib->sibling)
- ;
- prevsib->sibling = np->sibling;
- }
-
- of_node_set_flag(np, OF_DETACHED);
-
-out_unlock:
- write_unlock_irqrestore(&devtree_lock, flags);
-}
-
#ifdef CONFIG_PPC_PSERIES
/*
* Fix up the uninitialized fields in a new device node:
@@ -1491,7 +1358,7 @@
int err;
switch (action) {
- case PSERIES_RECONFIG_ADD:
+ case OF_ATTACH_NODE:
err = of_finish_dynamic_node(node);
if (err < 0) {
printk(KERN_ERR "finish_node returned %d\n", err);
@@ -1512,125 +1379,11 @@
static int __init prom_reconfig_setup(void)
{
- return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
+ return of_update_notifier_register(&prom_reconfig_nb);
}
__initcall(prom_reconfig_setup);
#endif
-/*
- * Add a property to a node
- */
-int prom_add_property(struct device_node* np, struct property* prop)
-{
- struct property **next;
- unsigned long flags;
-
- prop->next = NULL;
- write_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (strcmp(prop->name, (*next)->name) == 0) {
- /* duplicate ! don't insert it */
- write_unlock_irqrestore(&devtree_lock, flags);
- return -1;
- }
- next = &(*next)->next;
- }
- *next = prop;
- write_unlock_irqrestore(&devtree_lock, flags);
-
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_add_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
- return 0;
-}
-
-/*
- * Remove a property from a node. Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property. Instead we just move the property
- * to the "dead properties" list, so it won't be found any more.
- */
-int prom_remove_property(struct device_node *np, struct property *prop)
-{
- struct property **next;
- unsigned long flags;
- int found = 0;
-
- write_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (*next == prop) {
- /* found the node */
- *next = prop->next;
- prop->next = np->deadprops;
- np->deadprops = prop;
- found = 1;
- break;
- }
- next = &(*next)->next;
- }
- write_unlock_irqrestore(&devtree_lock, flags);
-
- if (!found)
- return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to remove the proc node as well */
- if (np->pde)
- proc_device_tree_remove_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
- return 0;
-}
-
-/*
- * Update a property in a node. Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property. Instead we just move the property
- * to the "dead properties" list, and add the new property to the
- * property list
- */
-int prom_update_property(struct device_node *np,
- struct property *newprop,
- struct property *oldprop)
-{
- struct property **next;
- unsigned long flags;
- int found = 0;
-
- write_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (*next == oldprop) {
- /* found the node */
- newprop->next = oldprop->next;
- *next = newprop;
- oldprop->next = np->deadprops;
- np->deadprops = oldprop;
- found = 1;
- break;
- }
- next = &(*next)->next;
- }
- write_unlock_irqrestore(&devtree_lock, flags);
-
- if (!found)
- return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_update_prop(np->pde, newprop, oldprop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
- return 0;
-}
-
-
/* Find the device node for a given logical cpu number, also returns the cpu
* local thread number (index in ibm,interrupt-server#s) if relevant and
* asked for (non NULL)
Index: linux-next/arch/powerpc/platforms/pseries/hotplug-cpu.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/hotplug-cpu.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/hotplug-cpu.c 2009-11-04 14:45:43.000000000 -0600
@@ -21,13 +21,13 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/cpu.h>
+#include <linux/of.h>
#include <asm/system.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/vdso_datapage.h>
-#include <asm/pSeries_reconfig.h>
#include "xics.h"
#include "plpar_wrappers.h"
@@ -234,11 +234,11 @@
int err = NOTIFY_OK;
switch (action) {
- case PSERIES_RECONFIG_ADD:
+ case OF_ATTACH_NODE:
if (pseries_add_processor(node))
err = NOTIFY_BAD;
break;
- case PSERIES_RECONFIG_REMOVE:
+ case OF_DETACH_NODE:
pseries_remove_processor(node);
break;
default:
@@ -284,7 +284,7 @@
/* Processors can be added/removed only on LPAR */
if (firmware_has_feature(FW_FEATURE_LPAR))
- pSeries_reconfig_notifier_register(&pseries_smp_nb);
+ of_update_notifier_register(&pseries_smp_nb);
return 0;
}
Index: linux-next/arch/powerpc/platforms/pseries/hotplug-memory.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/hotplug-memory.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/hotplug-memory.c 2009-11-04 14:45:43.000000000 -0600
@@ -13,8 +13,8 @@
#include <linux/lmb.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
-#include <asm/pSeries_reconfig.h>
#include <asm/sparsemem.h>
+#include "pseries.h"
static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size)
{
@@ -118,7 +118,10 @@
return (ret < 0) ? -EINVAL : 0;
}
-static int pseries_drconf_memory(unsigned long *base, unsigned int action)
+#define PSERIES_DRCONF_MEM_ADD 1
+#define PSERIES_DRCONF_MEM_REMOVE 2
+
+static int pseries_drconf_memory(unsigned long base, unsigned int action)
{
struct device_node *np;
const unsigned long *lmb_size;
@@ -135,10 +138,10 @@
}
if (action == PSERIES_DRCONF_MEM_ADD) {
- rc = lmb_add(*base, *lmb_size);
+ rc = lmb_add(base, *lmb_size);
rc = (rc < 0) ? -EINVAL : 0;
} else if (action == PSERIES_DRCONF_MEM_REMOVE) {
- rc = pseries_remove_lmb(*base, *lmb_size);
+ rc = pseries_remove_lmb(base, *lmb_size);
} else {
rc = -EINVAL;
}
@@ -147,25 +150,30 @@
return rc;
}
+int pseries_drconf_memory_add(unsigned long base)
+{
+ return pseries_drconf_memory(base, PSERIES_DRCONF_MEM_ADD);
+}
+
+int pseries_drconf_memory_remove(unsigned long base)
+{
+ return pseries_drconf_memory(base, PSERIES_DRCONF_MEM_REMOVE);
+}
+
static int pseries_memory_notifier(struct notifier_block *nb,
unsigned long action, void *node)
{
int err = NOTIFY_OK;
switch (action) {
- case PSERIES_RECONFIG_ADD:
+ case OF_ATTACH_NODE:
if (pseries_add_memory(node))
err = NOTIFY_BAD;
break;
- case PSERIES_RECONFIG_REMOVE:
+ case OF_DETACH_NODE:
if (pseries_remove_memory(node))
err = NOTIFY_BAD;
break;
- case PSERIES_DRCONF_MEM_ADD:
- case PSERIES_DRCONF_MEM_REMOVE:
- if (pseries_drconf_memory(node, action))
- err = NOTIFY_BAD;
- break;
default:
err = NOTIFY_DONE;
break;
@@ -180,7 +188,7 @@
static int __init pseries_memory_hotplug_init(void)
{
if (firmware_has_feature(FW_FEATURE_LPAR))
- pSeries_reconfig_notifier_register(&pseries_mem_nb);
+ of_update_notifier_register(&pseries_mem_nb);
return 0;
}
Index: linux-next/arch/powerpc/platforms/pseries/iommu.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/iommu.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/iommu.c 2009-11-04 14:45:43.000000000 -0600
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/crash_dump.h>
+#include <linux/of.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -40,7 +41,6 @@
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/abs_addr.h>
-#include <asm/pSeries_reconfig.h>
#include <asm/firmware.h>
#include <asm/tce.h>
#include <asm/ppc-pci.h>
@@ -570,7 +570,7 @@
struct pci_dn *pci = PCI_DN(np);
switch (action) {
- case PSERIES_RECONFIG_REMOVE:
+ case OF_DETACH_NODE:
if (pci && pci->iommu_table &&
of_get_property(np, "ibm,dma-window", NULL))
iommu_free_table(pci->iommu_table, np->full_name);
@@ -617,7 +617,7 @@
}
- pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
+ of_update_notifier_register(&iommu_reconfig_nb);
set_pci_dma_ops(&dma_iommu_ops);
}
Index: linux-next/arch/powerpc/platforms/pseries/pseries.h
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/pseries.h 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/pseries.h 2009-11-04 14:45:43.000000000 -0600
@@ -40,4 +40,18 @@
extern void find_udbg_vterm(void);
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern int pseries_drconf_memory_add(unsigned long);
+extern int pseries_drconf_memory_remove(unsigned long);
+#else
+static inline int pseries_drconf_memory_add(unsigned long base)
+{
+ return 0;
+}
+static inline int pseries_drconf_memory_remove(unsigned long base)
+{
+ return 0;
+}
+#endif
+
#endif /* _PSERIES_PSERIES_H */
Index: linux-next/arch/powerpc/platforms/pseries/reconfig.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/reconfig.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/reconfig.c 2009-11-04 14:57:47.000000000 -0600
@@ -13,100 +13,14 @@
#include <linux/kernel.h>
#include <linux/kref.h>
-#include <linux/notifier.h>
-#include <linux/proc_fs.h>
+#include <linux/of.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/uaccess.h>
-#include <asm/pSeries_reconfig.h>
#include <asm/mmu.h>
-
-
-/*
- * Routines for "runtime" addition and removal of device tree nodes.
- */
-#ifdef CONFIG_PROC_DEVICETREE
-/*
- * Add a node to /proc/device-tree.
- */
-static void add_node_proc_entries(struct device_node *np)
-{
- struct proc_dir_entry *ent;
-
- ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde);
- if (ent)
- proc_device_tree_add_node(np, ent);
-}
-
-static void remove_node_proc_entries(struct device_node *np)
-{
- struct property *pp = np->properties;
- struct device_node *parent = np->parent;
-
- while (pp) {
- remove_proc_entry(pp->name, np->pde);
- pp = pp->next;
- }
- if (np->pde)
- remove_proc_entry(np->pde->name, parent->pde);
-}
-#else /* !CONFIG_PROC_DEVICETREE */
-static void add_node_proc_entries(struct device_node *np)
-{
- return;
-}
-
-static void remove_node_proc_entries(struct device_node *np)
-{
- return;
-}
-#endif /* CONFIG_PROC_DEVICETREE */
-
-/**
- * derive_parent - basically like dirname(1)
- * @path: the full_name of a node to be added to the tree
- *
- * Returns the node which should be the parent of the node
- * described by path. E.g., for path = "/foo/bar", returns
- * the node with full_name = "/foo".
- */
-static struct device_node *derive_parent(const char *path)
-{
- struct device_node *parent = NULL;
- char *parent_path = "/";
- size_t parent_path_len = strrchr(path, '/') - path + 1;
-
- /* reject if path is "/" */
- if (!strcmp(path, "/"))
- return ERR_PTR(-EINVAL);
-
- if (strrchr(path, '/') != path) {
- parent_path = kmalloc(parent_path_len, GFP_KERNEL);
- if (!parent_path)
- return ERR_PTR(-ENOMEM);
- strlcpy(parent_path, path, parent_path_len);
- }
- parent = of_find_node_by_path(parent_path);
- if (!parent)
- return ERR_PTR(-EINVAL);
- if (strcmp(parent_path, "/"))
- kfree(parent_path);
- return parent;
-}
-
-static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
-
-int pSeries_reconfig_notifier_register(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
-}
-
-void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
-{
- blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
-}
+#include "pseries.h"
static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
{
@@ -124,34 +38,12 @@
strcpy(np->full_name, path);
np->properties = proplist;
- of_node_set_flag(np, OF_DYNAMIC);
- kref_init(&np->kref);
-
- np->parent = derive_parent(path);
- if (IS_ERR(np->parent)) {
- err = PTR_ERR(np->parent);
- goto out_err;
- }
-
- err = blocking_notifier_call_chain(&pSeries_reconfig_chain,
- PSERIES_RECONFIG_ADD, np);
- if (err == NOTIFY_BAD) {
- printk(KERN_ERR "Failed to add device node %s\n", path);
- err = -ENOMEM; /* For now, safe to assume kmalloc failure */
- goto out_err;
- }
-
of_attach_node(np);
- add_node_proc_entries(np);
-
- of_node_put(np->parent);
-
return 0;
out_err:
if (np) {
- of_node_put(np->parent);
kfree(np->full_name);
kfree(np);
}
@@ -172,10 +64,6 @@
return -EBUSY;
}
- remove_node_proc_entries(np);
-
- blocking_notifier_call_chain(&pSeries_reconfig_chain,
- PSERIES_RECONFIG_REMOVE, np);
of_detach_node(np);
of_node_put(parent);
@@ -392,7 +280,7 @@
if (!prop)
return -ENOMEM;
- prom_add_property(np, prop);
+ of_property_attach(np, prop);
return 0;
}
@@ -416,7 +304,7 @@
prop = of_find_property(np, buf, NULL);
- return prom_remove_property(np, prop);
+ return of_property_detach(np, prop);
}
static int do_update_property(char *buf, size_t bufsize)
@@ -446,37 +334,34 @@
oldprop = of_find_property(np, name,NULL);
if (!oldprop) {
if (strlen(name))
- return prom_add_property(np, newprop);
+ return of_property_attach(np, newprop);
return -ENODEV;
}
- rc = prom_update_property(np, newprop, oldprop);
+ rc = of_property_update(np, newprop, oldprop);
if (rc)
return rc;
/* For memory under the ibm,dynamic-reconfiguration-memory node
* of the device tree, adding and removing memory is just an update
* to the ibm,dynamic-memory property instead of adding/removing a
- * memory node in the device tree. For these cases we still need to
- * involve the notifier chain.
+ * memory node in the device tree.
*/
if (!strcmp(name, "ibm,dynamic-memory")) {
- int action;
+ unsigned long *addr;
- next_prop = parse_next_property(next_prop, end, &name,
- &length, &value);
+ next_prop = parse_next_property(next_prop, end, &name, &length,
+ (unsigned char **)&addr);
if (!next_prop)
return -EINVAL;
if (!strcmp(name, "add"))
- action = PSERIES_DRCONF_MEM_ADD;
+ rc = pseries_drconf_memory_add(*addr);
else
- action = PSERIES_DRCONF_MEM_REMOVE;
+ rc = pseries_drconf_memory_remove(*addr);
- rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
- action, value);
- if (rc == NOTIFY_BAD) {
- rc = prom_update_property(np, oldprop, newprop);
+ if (rc) {
+ rc = of_property_update(np, oldprop, newprop);
return -ENOMEM;
}
}
Index: linux-next/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/setup.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/setup.c 2009-11-04 14:45:43.000000000 -0600
@@ -40,6 +40,7 @@
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
+#include <linux/of.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -63,7 +64,6 @@
#include <asm/smp.h>
#include <asm/firmware.h>
#include <asm/eeh.h>
-#include <asm/pSeries_reconfig.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -258,7 +258,7 @@
int err = NOTIFY_OK;
switch (action) {
- case PSERIES_RECONFIG_ADD:
+ case OF_ATTACH_NODE:
pci = np->parent->data;
if (pci)
update_dn_pci_info(np, pci->phb);
@@ -291,7 +291,7 @@
/* Find and initialize PCI host bridges */
init_pci_config_tokens();
find_and_init_phbs();
- pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
+ of_update_notifier_register(&pci_dn_reconfig_nb);
eeh_init();
pSeries_nvram_init();
Index: linux-next/arch/powerpc/platforms/pseries/smp.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/smp.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/platforms/pseries/smp.c 2009-11-04 14:45:43.000000000 -0600
@@ -40,7 +40,6 @@
#include <asm/firmware.h>
#include <asm/system.h>
#include <asm/rtas.h>
-#include <asm/pSeries_reconfig.h>
#include <asm/mpic.h>
#include <asm/vdso_datapage.h>
#include <asm/cputhreads.h>
Index: linux-next/arch/powerpc/include/asm/prom.h
===================================================================
--- linux-next.orig/arch/powerpc/include/asm/prom.h 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/include/asm/prom.h 2009-11-04 14:45:43.000000000 -0600
@@ -34,10 +34,6 @@
#define HAVE_ARCH_DEVTREE_FIXUPS
-/* For updating the device tree at runtime */
-extern void of_attach_node(struct device_node *);
-extern void of_detach_node(struct device_node *);
-
#ifdef CONFIG_PPC32
/*
* PCI <-> OF matching functions
Index: linux-next/arch/powerpc/kernel/machine_kexec.c
===================================================================
--- linux-next.orig/arch/powerpc/kernel/machine_kexec.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/kernel/machine_kexec.c 2009-11-04 14:45:43.000000000 -0600
@@ -173,16 +173,16 @@
* be sure what's in them, so remove them. */
prop = of_find_property(node, "linux,crashkernel-base", NULL);
if (prop)
- prom_remove_property(node, prop);
+ of_property_detach(node, prop);
prop = of_find_property(node, "linux,crashkernel-size", NULL);
if (prop)
- prom_remove_property(node, prop);
+ of_property_detach(node, prop);
if (crashk_res.start != 0) {
- prom_add_property(node, &crashk_base_prop);
+ of_property_attach(node, &crashk_base_prop);
crashk_size = crashk_res.end - crashk_res.start + 1;
- prom_add_property(node, &crashk_size_prop);
+ of_property_attach(node, &crashk_size_prop);
}
}
@@ -198,11 +198,11 @@
/* remove any stale properties so ours can be found */
prop = of_find_property(node, kernel_end_prop.name, NULL);
if (prop)
- prom_remove_property(node, prop);
+ of_property_detach(node, prop);
/* information needed by userspace when using default_machine_kexec */
kernel_end = __pa(_end);
- prom_add_property(node, &kernel_end_prop);
+ of_property_attach(node, &kernel_end_prop);
export_crashk_values(node);
Index: linux-next/arch/powerpc/kernel/machine_kexec_64.c
===================================================================
--- linux-next.orig/arch/powerpc/kernel/machine_kexec_64.c 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/kernel/machine_kexec_64.c 2009-11-04 14:45:43.000000000 -0600
@@ -15,6 +15,7 @@
#include <linux/thread_info.h>
#include <linux/init_task.h>
#include <linux/errno.h>
+#include <linux/of.h>
#include <asm/page.h>
#include <asm/current.h>
@@ -320,14 +321,14 @@
/* remove any stale propertys so ours can be found */
prop = of_find_property(node, htab_base_prop.name, NULL);
if (prop)
- prom_remove_property(node, prop);
+ of_property_detach(node, prop);
prop = of_find_property(node, htab_size_prop.name, NULL);
if (prop)
- prom_remove_property(node, prop);
+ of_property_detach(node, prop);
htab_base = __pa(htab_address);
- prom_add_property(node, &htab_base_prop);
- prom_add_property(node, &htab_size_prop);
+ of_property_attach(node, &htab_base_prop);
+ of_property_attach(node, &htab_size_prop);
of_node_put(node);
return 0;
Index: linux-next/arch/powerpc/Kconfig
===================================================================
--- linux-next.orig/arch/powerpc/Kconfig 2009-11-04 14:42:17.000000000 -0600
+++ linux-next/arch/powerpc/Kconfig 2009-11-04 14:45:43.000000000 -0600
@@ -174,6 +174,9 @@
config OF
def_bool y
+config OF_DYNAMIC
+ def_bool y
+
config PPC_UDBG_16550
bool
default n
^ permalink raw reply
* [RFC PATCH 4/5] Microblaze updates for OF dynamic code
From: Nathan Fontenot @ 2009-11-04 22:19 UTC (permalink / raw)
To: devicetree-discuss, linuxppc-dev, microblaze-uclinux
In-Reply-To: <4AF1FB29.50905@austin.ibm.com>
This patch removes the common OF dynamic device tree updating from the
microblaze prom.c file to now use the generic OF code.
NOTE: I have no means of building and testing for the microblaze architecture.
I'll sign off on this with the understanding that it has not even passed the
compile test yet.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
Index: linux-next/arch/microblaze/kernel/prom.c
===================================================================
--- linux-next.orig/arch/microblaze/kernel/prom.c 2009-11-03 13:20:25.000000000 -0600
+++ linux-next/arch/microblaze/kernel/prom.c 2009-11-03 14:01:34.000000000 -0600
@@ -30,6 +30,7 @@
#include <linux/debugfs.h>
#include <linux/irq.h>
#include <linux/lmb.h>
+#include <linux/of.h>
#include <asm/prom.h>
#include <asm/page.h>
@@ -859,252 +860,6 @@
}
EXPORT_SYMBOL(of_find_node_by_phandle);
-/**
- * of_node_get - Increment refcount of a node
- * @node: Node to inc refcount, NULL is supported to
- * simplify writing of callers
- *
- * Returns node.
- */
-struct device_node *of_node_get(struct device_node *node)
-{
- if (node)
- kref_get(&node->kref);
- return node;
-}
-EXPORT_SYMBOL(of_node_get);
-
-static inline struct device_node *kref_to_device_node(struct kref *kref)
-{
- return container_of(kref, struct device_node, kref);
-}
-
-/**
- * of_node_release - release a dynamically allocated node
- * @kref: kref element of the node to be released
- *
- * In of_node_put() this function is passed to kref_put()
- * as the destructor.
- */
-static void of_node_release(struct kref *kref)
-{
- struct device_node *node = kref_to_device_node(kref);
- struct property *prop = node->properties;
-
- /* We should never be releasing nodes that haven't been detached. */
- if (!of_node_check_flag(node, OF_DETACHED)) {
- printk(KERN_INFO "WARNING: Bad of_node_put() on %s\n",
- node->full_name);
- dump_stack();
- kref_init(&node->kref);
- return;
- }
-
- if (!of_node_check_flag(node, OF_DYNAMIC))
- return;
-
- while (prop) {
- struct property *next = prop->next;
- kfree(prop->name);
- kfree(prop->value);
- kfree(prop);
- prop = next;
-
- if (!prop) {
- prop = node->deadprops;
- node->deadprops = NULL;
- }
- }
- kfree(node->full_name);
- kfree(node->data);
- kfree(node);
-}
-
-/**
- * of_node_put - Decrement refcount of a node
- * @node: Node to dec refcount, NULL is supported to
- * simplify writing of callers
- *
- */
-void of_node_put(struct device_node *node)
-{
- if (node)
- kref_put(&node->kref, of_node_release);
-}
-EXPORT_SYMBOL(of_node_put);
-
-/*
- * Plug a device node into the tree and global list.
- */
-void of_attach_node(struct device_node *np)
-{
- unsigned long flags;
-
- write_lock_irqsave(&devtree_lock, flags);
- np->sibling = np->parent->child;
- np->allnext = allnodes;
- np->parent->child = np;
- allnodes = np;
- write_unlock_irqrestore(&devtree_lock, flags);
-}
-
-/*
- * "Unplug" a node from the device tree. The caller must hold
- * a reference to the node. The memory associated with the node
- * is not freed until its refcount goes to zero.
- */
-void of_detach_node(struct device_node *np)
-{
- struct device_node *parent;
- unsigned long flags;
-
- write_lock_irqsave(&devtree_lock, flags);
-
- parent = np->parent;
- if (!parent)
- goto out_unlock;
-
- if (allnodes == np)
- allnodes = np->allnext;
- else {
- struct device_node *prev;
- for (prev = allnodes;
- prev->allnext != np;
- prev = prev->allnext)
- ;
- prev->allnext = np->allnext;
- }
-
- if (parent->child == np)
- parent->child = np->sibling;
- else {
- struct device_node *prevsib;
- for (prevsib = np->parent->child;
- prevsib->sibling != np;
- prevsib = prevsib->sibling)
- ;
- prevsib->sibling = np->sibling;
- }
-
- of_node_set_flag(np, OF_DETACHED);
-
-out_unlock:
- write_unlock_irqrestore(&devtree_lock, flags);
-}
-
-/*
- * Add a property to a node
- */
-int prom_add_property(struct device_node *np, struct property *prop)
-{
- struct property **next;
- unsigned long flags;
-
- prop->next = NULL;
- write_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (strcmp(prop->name, (*next)->name) == 0) {
- /* duplicate ! don't insert it */
- write_unlock_irqrestore(&devtree_lock, flags);
- return -1;
- }
- next = &(*next)->next;
- }
- *next = prop;
- write_unlock_irqrestore(&devtree_lock, flags);
-
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_add_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
- return 0;
-}
-
-/*
- * Remove a property from a node. Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property. Instead we just move the property
- * to the "dead properties" list, so it won't be found any more.
- */
-int prom_remove_property(struct device_node *np, struct property *prop)
-{
- struct property **next;
- unsigned long flags;
- int found = 0;
-
- write_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (*next == prop) {
- /* found the node */
- *next = prop->next;
- prop->next = np->deadprops;
- np->deadprops = prop;
- found = 1;
- break;
- }
- next = &(*next)->next;
- }
- write_unlock_irqrestore(&devtree_lock, flags);
-
- if (!found)
- return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to remove the proc node as well */
- if (np->pde)
- proc_device_tree_remove_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
- return 0;
-}
-
-/*
- * Update a property in a node. Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property. Instead we just move the property
- * to the "dead properties" list, and add the new property to the
- * property list
- */
-int prom_update_property(struct device_node *np,
- struct property *newprop,
- struct property *oldprop)
-{
- struct property **next;
- unsigned long flags;
- int found = 0;
-
- write_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (*next == oldprop) {
- /* found the node */
- newprop->next = oldprop->next;
- *next = newprop;
- oldprop->next = np->deadprops;
- np->deadprops = oldprop;
- found = 1;
- break;
- }
- next = &(*next)->next;
- }
- write_unlock_irqrestore(&devtree_lock, flags);
-
- if (!found)
- return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_update_prop(np->pde, newprop, oldprop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
- return 0;
-}
-
#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
static struct debugfs_blob_wrapper flat_dt_blob;
Index: linux-next/arch/microblaze/include/asm/prom.h
===================================================================
--- linux-next.orig/arch/microblaze/include/asm/prom.h 2009-11-03 13:20:25.000000000 -0600
+++ linux-next/arch/microblaze/include/asm/prom.h 2009-11-03 14:01:34.000000000 -0600
@@ -38,10 +38,6 @@
#define HAVE_ARCH_DEVTREE_FIXUPS
-/* For updating the device tree at runtime */
-extern void of_attach_node(struct device_node *);
-extern void of_detach_node(struct device_node *);
-
/* Other Prototypes */
extern int early_uartlite_console(void);
Index: linux-next/arch/microblaze/Kconfig
===================================================================
--- linux-next.orig/arch/microblaze/Kconfig 2009-11-02 13:39:39.000000000 -0600
+++ linux-next/arch/microblaze/Kconfig 2009-11-03 14:02:21.000000000 -0600
@@ -112,6 +112,9 @@
config OF
def_bool y
+config OF_DYNAMIC
+ def_bool y
+
config PROC_DEVICETREE
bool "Support for device tree in /proc"
depends on PROC_FS
^ permalink raw reply
* [RFC PATCH 5/5] powerpc/iseries updates for new OF dynamic code
From: Nathan Fontenot @ 2009-11-04 22:20 UTC (permalink / raw)
To: devicetree-discuss, linuxppc-dev, microblaze-uclinux
In-Reply-To: <4AF1FB29.50905@austin.ibm.com>
Update the powerpc/iseries vio code to use the new generic OF dynamic code.
NOTE: I have no means of testing iseries kernels, this does at least pass the
compile test for me.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
Index: linux-next/arch/powerpc/platforms/iseries/vio.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/iseries/vio.c 2009-11-02 13:39:40.000000000 -0600
+++ linux-next/arch/powerpc/platforms/iseries/vio.c 2009-11-03 12:34:19.000000000 -0600
@@ -80,8 +80,7 @@
kfree(np);
}
-static struct device_node *new_node(const char *path,
- struct device_node *parent)
+static struct device_node *new_node(const char *path)
{
struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);
@@ -93,9 +92,6 @@
return NULL;
}
strcpy(np->full_name, path);
- of_node_set_flag(np, OF_DYNAMIC);
- kref_init(&np->kref);
- np->parent = of_node_get(parent);
return np;
}
@@ -122,7 +118,7 @@
if (!nprop)
return 0;
- prom_add_property(np, nprop);
+ of_property_attach(np, nprop);
return 1;
}
@@ -133,19 +129,19 @@
if (!nprop)
return 0;
- prom_add_property(np, nprop);
+ of_property_attach(np, nprop);
return 1;
}
-static struct device_node *do_device_node(struct device_node *parent,
- const char *name, u32 reg, u32 unit, const char *type,
- const char *compat, struct vio_resource *res)
+static struct device_node *do_device_node(const char *name, u32 reg,
+ u32 unit, const char *type, const char *compat,
+ struct vio_resource *res)
{
struct device_node *np;
char path[32];
snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg);
- np = new_node(path, parent);
+ np = new_node(path);
if (!np)
return NULL;
if (!add_string_property(np, "name", name) ||
@@ -168,15 +164,6 @@
np->name = of_get_property(np, "name", NULL);
np->type = of_get_property(np, "device_type", NULL);
of_attach_node(np);
-#ifdef CONFIG_PROC_DEVICETREE
- if (parent->pde) {
- struct proc_dir_entry *ent;
-
- ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde);
- if (ent)
- proc_device_tree_add_node(np, ent);
- }
-#endif
return np;
node_free:
@@ -190,16 +177,11 @@
*/
struct vio_dev *vio_create_viodasd(u32 unit)
{
- struct device_node *vio_root;
struct device_node *np;
struct vio_dev *vdev = NULL;
- vio_root = of_find_node_by_path("/vdevice");
- if (!vio_root)
- return NULL;
- np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
+ np = do_device_node("viodasd", FIRST_VIODASD + unit, unit,
"block", "IBM,iSeries-viodasd", NULL);
- of_node_put(vio_root);
if (np) {
vdev = vio_register_device_node(np);
if (!vdev)
@@ -254,7 +236,7 @@
}
}
-static void __init probe_disk(struct device_node *vio_root, u32 unit)
+static void __init probe_disk(u32 unit)
{
HvLpEvent_Rc hvrc;
struct vio_waitevent we;
@@ -305,11 +287,11 @@
return;
}
- do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
+ do_device_node("viodasd", FIRST_VIODASD + unit, unit,
"block", "IBM,iSeries-viodasd", NULL);
}
-static void __init get_viodasd_info(struct device_node *vio_root)
+static void __init get_viodasd_info(void)
{
int rc;
u32 unit;
@@ -326,7 +308,7 @@
vio_setHandler(viomajorsubtype_blockio, handle_block_event);
for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++)
- probe_disk(vio_root, unit);
+ probe_disk(unit);
vio_clearHandler(viomajorsubtype_blockio);
viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2);
@@ -372,7 +354,7 @@
}
}
-static void __init get_viocd_info(struct device_node *vio_root)
+static void __init get_viocd_info(void)
{
HvLpEvent_Rc hvrc;
u32 unit;
@@ -430,7 +412,7 @@
for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
unitinfo[unit].rsrcname[0]; unit++) {
- if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit,
+ if (!do_device_node("viocd", FIRST_VIOCD + unit, unit,
"block", "IBM,iSeries-viocd", &unitinfo[unit]))
break;
}
@@ -464,7 +446,7 @@
}
}
-static void __init get_viotape_info(struct device_node *vio_root)
+static void __init get_viotape_info(void)
{
HvLpEvent_Rc hvrc;
u32 unit;
@@ -507,7 +489,7 @@
for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
unitinfo[unit].rsrcname[0]; unit++) {
- if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit,
+ if (!do_device_node("viotape", FIRST_VIOTAPE + unit,
unit, "byte", "IBM,iSeries-viotape",
&unitinfo[unit]))
break;
@@ -522,7 +504,6 @@
static int __init iseries_vio_init(void)
{
- struct device_node *vio_root;
int ret = -ENODEV;
if (!firmware_has_feature(FW_FEATURE_ISERIES))
@@ -530,25 +511,19 @@
iommu_vio_init();
- vio_root = of_find_node_by_path("/vdevice");
- if (!vio_root)
- goto out;
-
if (viopath_hostLp == HvLpIndexInvalid) {
vio_set_hostlp();
/* If we don't have a host, bail out */
if (viopath_hostLp == HvLpIndexInvalid)
- goto put_node;
+ goto out;
}
- get_viodasd_info(vio_root);
- get_viocd_info(vio_root);
- get_viotape_info(vio_root);
+ get_viodasd_info();
+ get_viocd_info();
+ get_viotape_info();
ret = 0;
- put_node:
- of_node_put(vio_root);
out:
return ret;
}
^ permalink raw reply
* [PATCH 1/3] fsl_pq_mdio: Fix compiler/sparse warnings (part 1)
From: Anton Vorontsov @ 2009-11-04 22:52 UTC (permalink / raw)
To: David Miller; +Cc: linuxppc-dev, Sandeep Gopalpet, Andy Fleming, netdev
commit 1d2397d742b7a2b39b2f09dd9da3b9d1463f55e9 ("fsl_pq_mdio: Add
Suport for etsec2.0 devices") introduced the following warnings:
CHECK fsl_pq_mdio.c
fsl_pq_mdio.c:287:22: warning: incorrect type in initializer (different base types)
fsl_pq_mdio.c:287:22: expected unknown type 11 const *__mptr
fsl_pq_mdio.c:287:22: got unsigned long long [unsigned] [assigned] [usertype] addr
fsl_pq_mdio.c:287:19: warning: incorrect type in assignment (different base types)
fsl_pq_mdio.c:287:19: expected unsigned long long [unsigned] [usertype] ioremap_miimcfg
fsl_pq_mdio.c:287:19: got struct fsl_pq_mdio *<noident>
CC fsl_pq_mdio.o
fsl_pq_mdio.c: In function 'fsl_pq_mdio_probe':
fsl_pq_mdio.c:287: warning: initialization makes pointer from integer without a cast
fsl_pq_mdio.c:287: warning: assignment makes integer from pointer without a cast
These warnings are not easy to fix without ugly __force casts. So,
instead of introducing the casts, rework the code to substitute an
offset from an already mapped area. This makes the code a lot simpler
and less duplicated.
Plus, from now on we don't actually map reserved registers on
non-etsec2.0 devices, so we have more chances to catch programming
errors.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/fsl_pq_mdio.c | 31 ++++++++++++-------------------
1 files changed, 12 insertions(+), 19 deletions(-)
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index 4065b7c..fb8c8d9 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -262,10 +262,11 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
struct device_node *np = ofdev->node;
struct device_node *tbi;
struct fsl_pq_mdio __iomem *regs = NULL;
+ void __iomem *map;
u32 __iomem *tbipa;
struct mii_bus *new_bus;
int tbiaddr = -1;
- u64 addr = 0, size = 0, ioremap_miimcfg = 0;
+ u64 addr = 0, size = 0;
int err = 0;
new_bus = mdiobus_alloc();
@@ -279,28 +280,20 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
fsl_pq_mdio_bus_name(new_bus->id, np);
/* Set the PHY base address */
- if (of_device_is_compatible(np,"fsl,gianfar-mdio") ||
- of_device_is_compatible(np, "fsl,gianfar-tbi") ||
- of_device_is_compatible(np, "fsl,ucc-mdio") ||
- of_device_is_compatible(np,"ucc_geth_phy" )) {
- addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
- ioremap_miimcfg = container_of(addr, struct fsl_pq_mdio, miimcfg);
- regs = ioremap(ioremap_miimcfg, size +
- offsetof(struct fsl_pq_mdio, miimcfg));
- } else if (of_device_is_compatible(np,"fsl,etsec2-mdio") ||
- of_device_is_compatible(np, "fsl,etsec2-tbi")) {
- addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
- regs = ioremap(addr, size);
- } else {
- err = -EINVAL;
- goto err_free_bus;
- }
-
- if (NULL == regs) {
+ addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
+ map = ioremap(addr, size);
+ if (!map) {
err = -ENOMEM;
goto err_free_bus;
}
+ if (of_device_is_compatible(np, "fsl,gianfar-mdio") ||
+ of_device_is_compatible(np, "fsl,gianfar-tbi") ||
+ of_device_is_compatible(np, "fsl,ucc-mdio") ||
+ of_device_is_compatible(np, "ucc_geth_phy"))
+ map -= offsetof(struct fsl_pq_mdio, miimcfg);
+ regs = map;
+
new_bus->priv = (void __force *)regs;
new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 2/3] fsl_pq_mdio: Fix compiler/sparse warnings (part 2)
From: Anton Vorontsov @ 2009-11-04 22:52 UTC (permalink / raw)
To: David Miller; +Cc: linuxppc-dev, Sandeep Gopalpet, Andy Fleming, netdev
This patch fixes following warnings:
fsl_pq_mdio.c:112:38: warning: cast adds address space to expression (<asn:2>)
fsl_pq_mdio.c:124:38: warning: cast adds address space to expression (<asn:2>)
fsl_pq_mdio.c:133:38: warning: cast adds address space to expression (<asn:2>)
fsl_pq_mdio.c:414:11: warning: cast adds address space to expression (<asn:2>)
Instead of adding __force all over the place, introduce convenient
fsl_pq_mdio_get_regs() call that does the ugly casting just once.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/fsl_pq_mdio.c | 13 +++++++++----
1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index fb8c8d9..b2ca596 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -103,13 +103,18 @@ int fsl_pq_local_mdio_read(struct fsl_pq_mdio __iomem *regs,
return value;
}
+static struct fsl_pq_mdio __iomem *fsl_pq_mdio_get_regs(struct mii_bus *bus)
+{
+ return (void __iomem __force *)bus->priv;
+}
+
/*
* Write value to the PHY at mii_id at register regnum,
* on the bus, waiting until the write is done before returning.
*/
int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
{
- struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv;
+ struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus);
/* Write to the local MII regs */
return(fsl_pq_local_mdio_write(regs, mii_id, regnum, value));
@@ -121,7 +126,7 @@ int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
*/
int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
- struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv;
+ struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus);
/* Read the local MII regs */
return(fsl_pq_local_mdio_read(regs, mii_id, regnum));
@@ -130,7 +135,7 @@ int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
/* Reset the MIIM registers, and wait for the bus to free */
static int fsl_pq_mdio_reset(struct mii_bus *bus)
{
- struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv;
+ struct fsl_pq_mdio __iomem *regs = fsl_pq_mdio_get_regs(bus);
int timeout = PHY_INIT_TIMEOUT;
mutex_lock(&bus->mdio_lock);
@@ -404,7 +409,7 @@ static int fsl_pq_mdio_remove(struct of_device *ofdev)
dev_set_drvdata(device, NULL);
- iounmap((void __iomem *)bus->priv);
+ iounmap(fsl_pq_mdio_get_regs(bus));
bus->priv = NULL;
mdiobus_free(bus);
--
1.6.3.3
^ permalink raw reply related
* [PATCH 3/3] gianfar: Fix compiler and sparse warnings
From: Anton Vorontsov @ 2009-11-04 22:53 UTC (permalink / raw)
To: David Miller; +Cc: linuxppc-dev, Sandeep Gopalpet, Andy Fleming, netdev
commit fba4ed030cfae7efdb6b79a57b0c5a9d72c9de83 ("gianfar: Add Multiple
Queue Support") introduced the following warnings:
CHECK gianfar.c
gianfar.c:333:8: warning: incorrect type in assignment (different address spaces)
gianfar.c:333:8: expected unsigned int [usertype] *baddr
gianfar.c:333:8: got unsigned int [noderef] <asn:2>*<noident>
[... 67 lines skipped ...]
gianfar.c:2565:3: warning: incorrect type in argument 1 (different type sizes)
gianfar.c:2565:3: expected unsigned long const *addr
gianfar.c:2565:3: got unsigned int *<noident>
CC gianfar.o
gianfar.c: In function 'gfar_probe':
gianfar.c:985: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:985: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:993: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:993: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c: In function 'gfar_configure_coalescing':
gianfar.c:1680: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:1680: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:1688: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:1688: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c: In function 'gfar_poll':
gianfar.c:2565: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:2565: warning: passing argument 1 of 'find_next_bit' from incompatible pointer type
gianfar.c:2566: warning: passing argument 2 of 'test_bit' from incompatible pointer type
gianfar.c:2585: warning: passing argument 2 of 'set_bit' from incompatible pointer type
Following warnings left unfixed (looks like sparse doesn't like
locks in loops, so __acquires/__releases() doesn't help):
gianfar.c:441:40: warning: context imbalance in 'lock_rx_qs': wrong count at exit
gianfar.c:441:40: context '<noident>': wanted 0, got 1
gianfar.c:449:40: warning: context imbalance in 'lock_tx_qs': wrong count at exit
gianfar.c:449:40: context '<noident>': wanted 0, got 1
gianfar.c:458:3: warning: context imbalance in 'unlock_rx_qs': __context__ statement expected different context
gianfar.c:458:3: context '<noident>': wanted >= 0, got -1
gianfar.c:466:3: warning: context imbalance in 'unlock_tx_qs': __context__ statement expected different context
gianfar.c:466:3: context '<noident>': wanted >= 0, got -1
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 14 ++++++++------
drivers/net/gianfar.h | 10 +++++-----
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 086d40d..197b358 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -327,7 +327,7 @@ cleanup:
static void gfar_init_tx_rx_base(struct gfar_private *priv)
{
struct gfar __iomem *regs = priv->gfargrp[0].regs;
- u32 *baddr;
+ u32 __iomem *baddr;
int i;
baddr = ®s->tbase0;
@@ -770,7 +770,8 @@ static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
return new_bit_map;
}
-u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class)
+static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar,
+ u32 class)
{
u32 rqfpr = FPR_FILER_MASK;
u32 rqfcr = 0x0;
@@ -849,7 +850,7 @@ static int gfar_probe(struct of_device *ofdev,
int len_devname;
u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
u32 isrg = 0;
- u32 *baddr;
+ u32 __iomem *baddr;
err = gfar_of_init(ofdev, &dev);
@@ -1658,10 +1659,10 @@ void gfar_start(struct net_device *dev)
}
void gfar_configure_coalescing(struct gfar_private *priv,
- unsigned int tx_mask, unsigned int rx_mask)
+ unsigned long tx_mask, unsigned long rx_mask)
{
struct gfar __iomem *regs = priv->gfargrp[0].regs;
- u32 *baddr;
+ u32 __iomem *baddr;
int i = 0;
/* Backward compatible case ---- even if we enable
@@ -2546,7 +2547,8 @@ static int gfar_poll(struct napi_struct *napi, int budget)
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0;
- int tx_cleaned = 0, i, left_over_budget = budget, serviced_queues = 0;
+ int tx_cleaned = 0, i, left_over_budget = budget;
+ unsigned long serviced_queues = 0;
int num_queues = 0;
unsigned long flags;
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 44b63da..cbb4510 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -986,10 +986,10 @@ struct gfar_priv_grp {
struct gfar_private *priv;
struct gfar __iomem *regs;
unsigned int grp_id;
- unsigned int rx_bit_map;
- unsigned int tx_bit_map;
- unsigned int num_tx_queues;
- unsigned int num_rx_queues;
+ unsigned long rx_bit_map;
+ unsigned long tx_bit_map;
+ unsigned long num_tx_queues;
+ unsigned long num_rx_queues;
unsigned int rstat;
unsigned int tstat;
unsigned int imask;
@@ -1118,7 +1118,7 @@ extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
int enable, u32 regnum, u32 read);
extern void gfar_configure_coalescing(struct gfar_private *priv,
- unsigned int tx_mask, unsigned int rx_mask);
+ unsigned long tx_mask, unsigned long rx_mask);
void gfar_init_sysfs(struct net_device *dev);
extern const struct ethtool_ops gfar_ethtool_ops;
--
1.6.3.3
^ permalink raw reply related
* [PATCH RFC] gianfar: Make polling safe with IRQs disabled
From: Anton Vorontsov @ 2009-11-04 22:57 UTC (permalink / raw)
To: David Miller; +Cc: linuxppc-dev, netdev, Andy Fleming, Jason Wessel
When using KGDBoE, gianfar driver spits 'Interrupt problem' messages,
which appears to be a legitimate warning, i.e. we may end up calling
netif_receive_skb() or vlan_hwaccel_receive_skb() with IRQs disabled.
This patch reworks the RX path so that if netpoll is enabled (the
only case when the driver don't know from what context the polling
may be called), we check whether IRQs are disabled, and if so we
fall back to safe variants of skb receiving functions.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
I'm not sure if this is suitable for mainline since it doesn't
have KGDBoE support. Jason, if the patch is OK, would you like
to merge it into KGDB tree?
drivers/net/gianfar.c | 17 +++++++++++++----
1 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 197b358..024ca4a 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -2412,9 +2412,17 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
{
struct gfar_private *priv = netdev_priv(dev);
struct rxfcb *fcb = NULL;
-
+ int irqs_dis = 0;
int ret;
+ /*
+ * With netpoll we don't know from what context we're called (e.g
+ * KGDBoE may call us from an exception handler), otherwise we're
+ * pretty sure that IRQs are enabled.
+ */
+#ifdef CONFIG_NETPOLL
+ irqs_dis = irqs_disabled();
+#endif
/* fcb is at the beginning if exists */
fcb = (struct rxfcb *)skb->data;
@@ -2432,7 +2440,10 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
/* Send the packet up the stack */
if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN)))
- ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, fcb->vlctl);
+ ret = __vlan_hwaccel_rx(skb, priv->vlgrp, fcb->vlctl,
+ !irqs_dis);
+ else if (irqs_dis)
+ ret = netif_rx(skb);
else
ret = netif_receive_skb(skb);
@@ -2504,8 +2515,6 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
skb_put(skb, pkt_len);
dev->stats.rx_bytes += pkt_len;
- if (in_irq() || irqs_disabled())
- printk("Interrupt problem!\n");
gfar_process_frame(dev, skb, amount_pull);
} else {
--
1.6.3.3
^ permalink raw reply related
* [PATCH] powerpc/mm: Remove debug context clamping from nohash code
From: Benjamin Herrenschmidt @ 2009-11-04 23:39 UTC (permalink / raw)
To: linuxppc-dev
I inadvertently left that debug code enabled, causing the number of
contexts to be clamped to 31 which is going to slow things down on
4xx and just plain breaks 8xx
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/mm/mmu_context_nohash.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index c2f93dc..be4f34c 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -25,8 +25,8 @@
* also clear mm->cpu_vm_mask bits when processes are migrated
*/
-#define DEBUG_MAP_CONSISTENCY
-#define DEBUG_CLAMP_LAST_CONTEXT 31
+//#define DEBUG_MAP_CONSISTENCY
+//#define DEBUG_CLAMP_LAST_CONTEXT 31
//#define DEBUG_HARDER
/* We don't use DEBUG because it tends to be compiled in always nowadays
^ permalink raw reply related
* Re: [powerpc] Next tree Nov 2 : kernel BUG at mm/mmap.c:2135!
From: David Gibson @ 2009-11-05 0:16 UTC (permalink / raw)
To: Sachin Sant; +Cc: Linux/PPC Development, linux-next, Stephen Rothwell
In-Reply-To: <4AF175D4.7030507@in.ibm.com>
On Wed, Nov 04, 2009 at 06:08:44PM +0530, Sachin Sant wrote:
> Sachin Sant wrote:
> >Today's next tree failed to boot on a POWER 6 box with :
> >
> >------------[ cut here ]------------
> >kernel BUG at mm/mmap.c:2135!
> >Oops: Exception in kernel mode, sig: 5 [#2]
> >SMP NR_CPUS=1024 NUMA pSeries
> Problem exists with today's next as well.
>
> Likely cause for this problem seems to the following commit.
> If i revert this patch the machine boots fine.
>
> commit a0668cdc154e54bf0c85182e0535eea237d53146
> powerpc/mm: Cleanup management of kmem_caches for pagetables
Ugh. Ok, it's not at all obvious how my patch could cause this bug.
Can you send your .config?
> >Modules linked in: ibmvscsic scsi_transport_srp scsi_tgt scsi_mod
> >NIP: c00000000014e30c LR: c00000000014e2f8 CTR: c00000000014db88
> >REGS: c0000000db703620 TRAP: 0700 Tainted: G D
> >(2.6.32-rc5-autotest-next-20091102)
> >MSR: 8000000000029032 <EE,ME,CE,IR,DR> CR: 24022442 XER: 2000000c
> >TASK = c0000000db7f6fe0[76] 'init' THREAD: c0000000db700000 CPU: 1
> >GPR00: 0000000000000001 c0000000db7038a0 c000000000b19900
> >0000000000000000
> >GPR04: c0000000db406a40 000000000000000c c0000000fe10c370
> >c000000000bb2800
> >GPR08: 000000000000db40 0000000000000000 c0000000dfdc0e00
> >000000000000000c
> >GPR12: 0000000044022442 c000000000bb2800 00000000ffffffff
> >ffffffffffffffff
> >GPR16: 0000000008430000 00000000003c0000 c0000000db703ea0
> >c0000000db569108
> >GPR20: c0000000db568908 0000000000000000 c0000000db703d60
> >0000000000000000
> >GPR24: 0000000000000001 0000000000040100 c0000000fe503580
> >c0000000db1ac180
> >GPR28: 0000000000000000 c000000000f812d0 c000000000a84f00
> >0000000000000000
> >NIP [c00000000014e30c] .exit_mmap+0x190/0x1b8
> >LR [c00000000014e2f8] .exit_mmap+0x17c/0x1b8
> >Call Trace:
> >[c0000000db7038a0] [c00000000014e2f8] .exit_mmap+0x17c/0x1b8 (unreliable)
> >[c0000000db703950] [c0000000000916cc] .mmput+0x54/0x164
> >[c0000000db7039e0] [c0000000000968d8] .exit_mm+0x17c/0x1a0
> >[c0000000db703a90] [c000000000098cb8] .do_exit+0x248/0x784
> >[c0000000db703b70] [c0000000000992a8] .do_group_exit+0xb4/0xe8
> >[c0000000db703c00] [c0000000000aca2c] .get_signal_to_deliver+0x3ec/0x478
> >[c0000000db703cf0] [c0000000000134ac] .do_signal+0x6c/0x31c
> >[c0000000db703e30] [c000000000008b7c] do_work+0x24/0x28
> >Instruction dump:
> >7c8407b4 387d0018 4800ab11 60000000 939d0008 7fe3fb78 4bfffdbd 7c7f1b79
> >4082fff4 e81b00e8 3120ffff 7c090110 <0b000000> 382100b0 e8010010 eb61ffd8
> >---[ end trace ec052ac77a8e7cb4 ]---
> >Fixing recursive fault but reboot is needed!
> >
> >mm/mmap.c:2135 corresponds to :
> >
> >BUG_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
> >
>
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH] BUILD_BUG_ON: make it handle more cases
From: Stephen Rothwell @ 2009-11-05 0:20 UTC (permalink / raw)
To: Rusty Russell
Cc: Hollis Blanchard, linux-kernel, kvm-ppc, linux-next, Jan Beulich,
akpm, linuxppc-dev
In-Reply-To: <200910201415.34361.rusty@rustcorp.com.au>
[-- Attachment #1: Type: text/plain, Size: 1154 bytes --]
Hi Rusty,
On Tue, 20 Oct 2009 14:15:33 +1030 Rusty Russell <rusty@rustcorp.com.au> wrote:
>
> +#ifndef __OPTIMIZE__
> +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
> +#else
> +extern int __build_bug_on_failed;
> +#define BUILD_BUG_ON(condition) \
> + do { \
> + ((void)sizeof(char[1 - 2*!!(condition)])); \
> + if (condition) __build_bug_on_failed = 1; \
> + } while(0)
> +#endif
> +#define MAYBE_BUILD_BUG_ON(condition) BUILD_BUG_ON(condition)
> +
I decided to try this in linux-next, but an x86_64 allmodconfig build
gave this (gcc 4.4.0):
ERROR: "__build_bug_on_failed" [drivers/net/virtio_net.ko] undefined!
ERROR: "__build_bug_on_failed" [drivers/block/virtio_blk.ko] undefined!
I assume that this is caused by the "MAYBE_BUILD_BUG_ON(fbit >= 32)" in
virtio_has_feature() (in include/linux/virtio_config.h) which is called
all over the place. Unfortunately, virtio_has_feature() gets uninlined
in those two files ...
I have taken the patch back out again for today.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH 14/27] Add book3s_64 specific opcode emulation
From: Segher Boessenkool @ 2009-11-05 0:53 UTC (permalink / raw)
To: Alexander Graf
Cc: Kevin Wolf, Arnd Bergmann, Hollis Blanchard, Marcelo Tosatti,
kvm-ppc, linuxppc-dev, Avi Kivity, kvm, bphilips, Olof Johansson
In-Reply-To: <280C9FF6-1C52-4856-9F60-15DA0659FC31@suse.de>
>>> + case OP_31_XOP_EIOIO:
>>> + break;
>>
>> Have you always executed an eieio or sync when you get here, or
>> do you just not allow direct access to I/O devices? Other context
>> synchronising insns are not enough, they do not broadcast on the
>> bus.
>
> There is no device passthrough yet :-). It's theoretically
> possible, but nothing for it is implemented so far.
You could just always do an eieio here, it's not expensive at all
compared to the emulation trap itself.
However -- eieio is a Book II insn, it will never trap anyway!
>>> + case OP_31_XOP_DCBZ:
>>> + {
>>> + ulong rb = vcpu->arch.gpr[get_rb(inst)];
>>> + ulong ra = 0;
>>> + ulong addr;
>>> + u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
>>> +
>>> + if (get_ra(inst))
>>> + ra = vcpu->arch.gpr[get_ra(inst)];
>>> +
>>> + addr = (ra + rb) & ~31ULL;
>>> + if (!(vcpu->arch.msr & MSR_SF))
>>> + addr &= 0xffffffff;
>>> +
>>> + if (kvmppc_st(vcpu, addr, 32, zeros)) {
>>
>> DCBZ zeroes out a cache line, not 32 bytes; except on 970, where
>> there
>> are HID bits to make it work on 32 bytes only, and an extra DCBZL
>> insn
>> that always clears a full cache line (128 bytes).
>
> Yes. We only come here when we patched the dcbz opcodes to invalid
> instructions
Ah yes, I forgot. Could you rename it to OP_31_XOP_FAKE_32BIT_DCBZ
or such?
> because cache line size of target == 32.
> On 970 with MSR_HV = 0 we actually use the dcbz 32-bytes mode.
>
> Admittedly though, this could be a lot more clever.
>>> + /* guest HID5 set can change is_dcbz32 */
>>> + if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
>>> + (mfmsr() & MSR_HV))
>>> + vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
>>> + break;
>>
>> Wait, does this mean you allow other HID writes when MSR[HV] isn't
>> set? All HIDs (and many other SPRs) cannot be read or written in
>> supervisor mode.
>
> When we're running in MSR_HV=0 mode on a 970 we can use the 32 byte
> dcbz HID flag. So all we need to do is tell our entry/exit code to
> set this bit.
Which patch contains that entry/exit code?
> If we're on 970 on a hypervisor or on a non-970 though we can't use
> the HID5 bit, so we need to binary patch the opcodes.
>
> So in order to emulate real 970 behavior, we need to be able to
> emulate that HID5 bit too! That's what this chunk of code does - it
> basically sets us in dcbz32 mode when allowed on 970 guests.
But when MSR[HV]=0 and MSR[PR]=0, mtspr to a hypervisor resource
will not trap but be silently ignored. Sorry for not being more clear.
...Oh. You run your guest as MSR[PR]=1 anyway! Tricky.
Segher
^ permalink raw reply
* Re: [PATCH] PCI: Fix regression in powerpc MSI-X
From: Michael Ellerman @ 2009-11-05 1:17 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Andre Detsch, linuxppc-dev
In-Reply-To: <200911041303.19695.adetsch@br.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 457 bytes --]
On Wed, 2009-11-04 at 13:03 -0200, Andre Detsch wrote:
> Patch f598282f5145036312d90875d0ed5c14b49fd8a7 exposed a problem in
> powerpc MSI-X functionality, making network interfaces such as ixgbe
> and cxgb3 stop to work when MSI-X is enabled. RX interrupts were not
> being generated.
Which means we'd like it in 32 please Ben.
Also Andre, once Ben has merged this you should forward it to
stable@kernel.org for the 31 stable series.
cheers
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: Regarding FPGA based cascaded PIC
From: thirumalai.p @ 2009-11-05 2:46 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1257367882.13611.65.camel@pasglop>
On Thu, 05 Nov 2009 07:51:22 +1100, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Wed, 2009-11-04 at 18:09 +0530, Thirumalai wrote:
>> you understood correctly. Here the problem lies.Correct me if i am
wrong.
>> So
>> you are telling that irq_of_parse_and_map() will invoke the map/xlate of
>> my
>> FPGA pic. Right.
>>
>> But this is what not happening. Instead of calling my map/xlate
functions
>>
>> the irq_of_parse_and_map() function is invoking mpic's map/xlate
>> function.
>
> irq_of_parse_and_map() will call the map/xlate function of the parent
> PIC for the given interrupt.
>
> In your case, the interrupts you are calling it for are defined as being
> interrupts wiring the FPGA to the MPIC, hence are MPIC inputs, and thus
> will be parsed/mapped by the MPIC. From the MPIC standpoint, the FPGA is
> just a device.
>
> So the code is doing what you tell it to do :-)
>
> I don't understand what you are actually trying to acheive. If those 3
> interrupts aren't outputs from the FPGA to the MPIC but input to the
> FPGA then they shouldn't be there, they should be device interrupts
> connected to the FPGA. Those will end up with map/xlate called in the
> FPGA host.
>
I Understood the thing. Thank you very much. So you mean to say that my
map/xlate functions will get invoked only for the devices which is
connected the FPGA PIC. So for example suppose if i have an WDT connected
to my FPGA then the interrupt-parent tag should point to FPGA-PIC. So at
that time the irq_of_parse_and_map() will invoke my map/xlate functions
right.
So i need to define the nodes on my device tree for the devices which are
all going to generate interrupts for FPGA and keeping the interrupt-parent
property as fpga-pic.
So my device node for WDT is something like the following
wdt@4,2000 {
#interrupt-cells = <2>;
device_type = "watchdog";
compatible = "gef,fpga-wdt";
reg = <0x4 0x2000 0x8>;
interrupts = <0x1a 0x4>;
interrupt-parent = <&fpga_pic>;
};
Correct me if i am wrong.
> Ben.
>
>> Here is the piece of code that we are using.
>>
>> fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
>> DPVPX0659_FPGA_NUM_IRQS,&fpga_pic_host_ops,
>> NO_IRQ);
>> if (fpga_pic_irq_host == NULL) {
>> printk("FPGA PIC: Unable to allocate host\n");
>> return;
>> }
>>
>> for (i = 0; i < 3; i++) {
>> fpga_irqs[i] = irq_of_parse_and_map(pic, i);
>> if (fpga_irqs[i] == NO_IRQ) {
>> printk("FPGA PIC: can't get irq %d.\n", i);
>> continue;
>> }
>> printk("interrupt from device tree : %d
>> \n",fpga_irqs[i]);
>>
set_irq_chained_handler(dpvpx0659_fpga_irqs[i],dpvpx0659_fpga_pic_cascade);
>> }
>>
>>
Thank you
Thirumalai
**************** CAUTION - Disclaimer *****************This email may contain confidential and privileged material for the
sole use of the intended recipient(s). Any review, use, retention, distribution or disclosure by others is strictly prohibited. If you are not the intended recipient (or authorized to receive for the recipient), please contact the sender by reply email and delete all copies of this message. Also, email is susceptible to data corruption, interception, tampering, unauthorized amendment and viruses. We only send and receive emails on the basis that we are not liable for any such corruption, interception, tampering, amendment or viruses or any consequence thereof.
*********** End of Disclaimer ***********DataPatterns ITS Group**********
^ permalink raw reply
* Re: Regarding FPGA based cascaded PIC
From: Benjamin Herrenschmidt @ 2009-11-05 3:24 UTC (permalink / raw)
To: thirumalai.p; +Cc: linuxppc-dev
In-Reply-To: <99cb42d33b031818b565d67254059410@datapatterns.co.in>
On Thu, 2009-11-05 at 08:16 +0530, thirumalai.p wrote:
>
> I Understood the thing. Thank you very much. So you mean to say that
> my map/xlate functions will get invoked only for the devices which is
> connected the FPGA PIC.
Right, and I fail to see how it would make any sense the other way
around :-)
Seriously, the map and xlate functions are used to hook up interrupt to
the PIC inputs. So logically, the 3 cascade interrupts are -inputs- to
the parent controller and as such get mapped by that controller. IE. The
parent is the only one to "understand" the format of the "interrupts"
properties for those and the interrupt numbers for those are HW numbers
in the parent space. It wouldn't make -any- sense to call map/xlate of
the child. In fact, for the code in question, the child PIC is just a
device, the fact that that device is itself a PIC is irrelevant.
> So for example suppose if i have an WDT connected
> to my FPGA then the interrupt-parent tag should point to FPGA-PIC. So
> at
> that time the irq_of_parse_and_map() will invoke my map/xlate
> functions
> right.
Yes.
> So i need to define the nodes on my device tree for the devices which
> are
> all going to generate interrupts for FPGA and keeping the
> interrupt-parent
> property as fpga-pic.
Or you can just keep track of the irq_host * of the FPGA and manually
call irq_create_mapping() passing it a HW number in the FPGA irq space
if you don't want to create device nodes for those children but the
device-node approach is preferred.
> So my device node for WDT is something like the following
>
> wdt@4,2000 {
> #interrupt-cells = <2>;
> device_type = "watchdog";
> compatible = "gef,fpga-wdt";
> reg = <0x4 0x2000 0x8>;
> interrupts = <0x1a 0x4>;
> interrupt-parent = <&fpga_pic>;
> };
> Correct me if i am wrong.
It looks ok except that if I remember correctly, your FPGA PIC has a
#interrupt-cells value of '3' which means that it expects 3 numbers in
the "interrupts" property to define an interrupt (which your xlate
function is then going to translate into the appropriate HW number and
sense/polarity flags for linux).
So if you use only 2 numbers, you need to fix your #interrupt-cells
property value.
Cheers,
Ben.
> > Ben.
> >
> >> Here is the piece of code that we are using.
> >>
> >> fpga_pic_irq_host = irq_alloc_host(pic, IRQ_HOST_MAP_LINEAR,
> >> DPVPX0659_FPGA_NUM_IRQS,&fpga_pic_host_ops,
> >> NO_IRQ);
> >> if (fpga_pic_irq_host == NULL) {
> >> printk("FPGA PIC: Unable to allocate host\n");
> >> return;
> >> }
> >>
> >> for (i = 0; i < 3; i++) {
> >> fpga_irqs[i] = irq_of_parse_and_map(pic, i);
> >> if (fpga_irqs[i] == NO_IRQ) {
> >> printk("FPGA PIC: can't get irq %d.\n", i);
> >> continue;
> >> }
> >> printk("interrupt from device tree : %d
> >> \n",fpga_irqs[i]);
> >>
> set_irq_chained_handler(dpvpx0659_fpga_irqs[i],dpvpx0659_fpga_pic_cascade);
> >> }
> >>
> >>
> Thank you
> Thirumalai
^ permalink raw reply
* Re: ppc rfi in head.s result in a reset?
From: Tonyliu @ 2009-11-05 2:13 UTC (permalink / raw)
To: wilbur.chan; +Cc: linuxppc-dev
In-Reply-To: <e997b7420910161821g3d71c5fcy6fbf72f40d52c1c3@mail.gmail.com>
wilbur.chan wrote:
> ppc 6xx
>
> In platform_init function of sandpoint.c , I delete the code of
> getting command line from uboot, and set command_line to a fixed value
> , which are like this:
>
> sandpoint.c--> platform_init
> #if 0
> if (r3 && r6) {
> /* copy board info structure */
> memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
> /* copy command line */
> *(char *)(r7+KERNELBASE) = 0;
> strcpy(cmd_line, (char *)(r6+KERNELBASE));
> }
> #endif
> strcpy(cmd_line, "xxx");
>
>
Which version your kernel is ? I cant find sandpoint.c in powerpc git tree.
And I suspect it's conditional "if (r3 && r6)" to copy cmd_line, and
your change makes it unconditioned. Maybe it
will affect something.
Tony
> But I found that , when calling start_kernel in head.S (by rfi
> instruction), the borad was reset into uboot, that is :
>
> li r4,MSR_KERNEL
> FIX_SRR1(r4,r5)
> lis r3,start_kernel@h
> ori r3,r3,start_kernel@l
> mtspr SPRN_SRR0,r3
> mtspr SPRN_SRR1,r4
> SYNC
> RFI //reset,why?
>
>
> The RFI instruction here, caused the board reset to uboot. Can
> someone give me some advice on how could this happened?
>
> Thank you
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
>
--
Tony Liu | Liu Bo
-------------------------------------------------------------
WIND RIVER | China Development Center
Tel: 86-10-8477-8542 ext: 8542 | Fax: 86-10-64790367
(M): 86-136-7117-3612
Address: 15/F, Wangjing TowerB, Chaoyang District, Beijing, P.R.China
^ 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