linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* mmap and ppc460gt
@ 2008-08-27  2:26 vb
  2008-08-27  3:24 ` Roland Dreier
  0 siblings, 1 reply; 11+ messages in thread
From: vb @ 2008-08-27  2:26 UTC (permalink / raw)
  To: linuxppc-embedded

I am trying to port an application from ppc854x to ppc440. The
application, among other things, maps register file of a PCI device
into its memory space to gain direct access to the device. mmap() is
used to accomplish the mapping.

I don't seem to be able to port this to ppc460gt: on this architecture
the PCI register space can be mapped only to 36 bit address ranges
with nonzero top nibbles. But mmap()  (at least the one I have in
2.6.25)  accepts only 32 bit values for addresses, hence there is no
way to map PCI space into user space.

Am I missing something and there is a way to map 36 bit address in 32
bit mode? Or maybe the kernel/library were not compiled properly and
mmap() is supposed to accept 64 bit addresses?

Any hints/suggestions will be highly appreciated,
TIA,
Vadim

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-27  2:26 mmap and ppc460gt vb
@ 2008-08-27  3:24 ` Roland Dreier
  2008-08-27  8:13   ` Arnd Bergmann
  0 siblings, 1 reply; 11+ messages in thread
From: Roland Dreier @ 2008-08-27  3:24 UTC (permalink / raw)
  To: vb; +Cc: linuxppc-embedded

 > I don't seem to be able to port this to ppc460gt: on this architecture
 > the PCI register space can be mapped only to 36 bit address ranges
 > with nonzero top nibbles. But mmap()  (at least the one I have in
 > 2.6.25)  accepts only 32 bit values for addresses, hence there is no
 > way to map PCI space into user space.

In the past I've been able to use mmap64() on ppc440 to get at 36-bit
addresses.  As far as I know this should still work.

Also you should be able to get at the BAR of a PCI device by using
mmap() on a resource file under /sys/devices, eg something like
/sys/devices/pci0000:00/0000:00:04.0/0000:0b:00.0/resource0
(where the bus numbers obviously depend on your system and the resource
number depends on what BAR your device has registers in)

 - R.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-27  3:24 ` Roland Dreier
@ 2008-08-27  8:13   ` Arnd Bergmann
  2008-08-27 23:13     ` vb
  0 siblings, 1 reply; 11+ messages in thread
From: Arnd Bergmann @ 2008-08-27  8:13 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: vb, Roland Dreier

On Wednesday 27 August 2008, Roland Dreier wrote:
> =A0> I don't seem to be able to port this to ppc460gt: on this architectu=
re
> =A0> the PCI register space can be mapped only to 36 bit address ranges
> =A0> with nonzero top nibbles. But mmap() =A0(at least the one I have in
> =A0> 2.6.25) =A0accepts only 32 bit values for addresses, hence there is =
no
> =A0> way to map PCI space into user space.
>=20
> In the past I've been able to use mmap64() on ppc440 to get at 36-bit
> addresses. =A0As far as I know this should still work.

Right, this is supposed to work. If it doesn't, report it as a bug.

> Also you should be able to get at the BAR of a PCI device by using
> mmap() on a resource file under /sys/devices, eg something like
> /sys/devices/pci0000:00/0000:00:04.0/0000:0b:00.0/resource0
> (where the bus numbers obviously depend on your system and the resource
> number depends on what BAR your device has registers in)

This should work as well.

The best way to do it however would be to implement a UIO device driver
for your device, see e.g. http://lwn.net/Articles/232575/.

That gives you proper control over the permissions and lets you handle
interrupts and other things as well.

	Arnd <><

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-27  8:13   ` Arnd Bergmann
@ 2008-08-27 23:13     ` vb
  2008-08-28  0:11       ` Roland Dreier
  0 siblings, 1 reply; 11+ messages in thread
From: vb @ 2008-08-27 23:13 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Roland Dreier, linuxppc-embedded

On Wed, Aug 27, 2008 at 1:13 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Wednesday 27 August 2008, Roland Dreier wrote:
>>  > I don't seem to be able to port this to ppc460gt: on this architecture
>>  > the PCI register space can be mapped only to 36 bit address ranges
>>  > with nonzero top nibbles. But mmap()  (at least the one I have in
>>  > 2.6.25)  accepts only 32 bit values for addresses, hence there is no
>>  > way to map PCI space into user space.
>>
>> In the past I've been able to use mmap64() on ppc440 to get at 36-bit
>> addresses.  As far as I know this should still work.
>
> Right, this is supposed to work. If it doesn't, report it as a bug.
>
>> Also you should be able to get at the BAR of a PCI device by using
>> mmap() on a resource file under /sys/devices, eg something like
>> /sys/devices/pci0000:00/0000:00:04.0/0000:0b:00.0/resource0
>> (where the bus numbers obviously depend on your system and the resource
>> number depends on what BAR your device has registers in)
>
> This should work as well.
>
> The best way to do it however would be to implement a UIO device driver
> for your device, see e.g. http://lwn.net/Articles/232575/.
>
> That gives you proper control over the permissions and lets you handle
> interrupts and other things as well.
>
>        Arnd <><
>

Arnd, Roland, thank you for your replies, I did manage to get it
mapped using mmap64(), but as it often happens clearing one hurdle
just brings us to the next one :-)

The problem now is that that PCI register space gets mapped with
caching enabled (by looking at the TLB contents), so I still can't
control the device. I did some search and indeed UIO device driver
came up, I'll read the article. I was wondering  though if there is a
simpler way to modify cache attributes of a region. mmap() doesn't
seem to provide an interface for that, is there some other function to
call to configure 'cache inhibit' attribute for a region?

TIA,
Vadim

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-27 23:13     ` vb
@ 2008-08-28  0:11       ` Roland Dreier
  2008-08-28  0:21         ` vb
  2008-08-28  3:12         ` Roland Dreier
  0 siblings, 2 replies; 11+ messages in thread
From: Roland Dreier @ 2008-08-28  0:11 UTC (permalink / raw)
  To: vb; +Cc: Arnd Bergmann, linuxppc-embedded

 > The problem now is that that PCI register space gets mapped with
 > caching enabled (by looking at the TLB contents), so I still can't
 > control the device. I did some search and indeed UIO device driver
 > came up, I'll read the article. I was wondering  though if there is a
 > simpler way to modify cache attributes of a region. mmap() doesn't
 > seem to provide an interface for that, is there some other function to
 > call to configure 'cache inhibit' attribute for a region?

The issue would be related to phys_mem_access_prot() not doing the right
thing in this case.  In fact it looks like the arch/powerpc
page_is_ram() implementation has the same bug that I fixed a long time
ago for arch/ppc in 8b150478 ("[PATCH] ppc: make phys_mem_access_prot()
work with pfns instead of addresses").  I'll send a patch a little later
that you can try out.

 - R.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-28  0:11       ` Roland Dreier
@ 2008-08-28  0:21         ` vb
  2008-08-28  3:12         ` Roland Dreier
  1 sibling, 0 replies; 11+ messages in thread
From: vb @ 2008-08-28  0:21 UTC (permalink / raw)
  To: Roland Dreier; +Cc: Arnd Bergmann, linuxppc-embedded

On Wed, Aug 27, 2008 at 5:11 PM, Roland Dreier <rdreier@cisco.com> wrote:
>  > The problem now is that that PCI register space gets mapped with
>  > caching enabled (by looking at the TLB contents), so I still can't
>  > control the device. I did some search and indeed UIO device driver
>  > came up, I'll read the article. I was wondering  though if there is a
>  > simpler way to modify cache attributes of a region. mmap() doesn't
>  > seem to provide an interface for that, is there some other function to
>  > call to configure 'cache inhibit' attribute for a region?
>
> The issue would be related to phys_mem_access_prot() not doing the right
> thing in this case.  In fact it looks like the arch/powerpc
> page_is_ram() implementation has the same bug that I fixed a long time
> ago for arch/ppc in 8b150478 ("[PATCH] ppc: make phys_mem_access_prot()
> work with pfns instead of addresses").  I'll send a patch a little later
> that you can try out.
>

Ronald, I will appreciate the patch that very much!

TIA,
/vb


>  - R.
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-28  0:11       ` Roland Dreier
  2008-08-28  0:21         ` vb
@ 2008-08-28  3:12         ` Roland Dreier
  2008-08-28  3:47           ` vb
  2008-08-30  3:39           ` [PATCH] powerpc: Avoid integer overflow in page_is_ram() Roland Dreier
  1 sibling, 2 replies; 11+ messages in thread
From: Roland Dreier @ 2008-08-28  3:12 UTC (permalink / raw)
  To: vb; +Cc: Arnd Bergmann, linuxppc-embedded

OK, please try this and let me know if it helps:

diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 1c93c25..98d7bf9 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
 
 int page_is_ram(unsigned long pfn)
 {
-	unsigned long paddr = (pfn << PAGE_SHIFT);
-
 #ifndef CONFIG_PPC64	/* XXX for now */
-	return paddr < __pa(high_memory);
+	return pfn < max_pfn;
 #else
+	unsigned long paddr = (pfn << PAGE_SHIFT);
 	int i;
 	for (i=0; i < lmb.memory.cnt; i++) {
 		unsigned long base;

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-28  3:12         ` Roland Dreier
@ 2008-08-28  3:47           ` vb
  2008-08-28 10:36             ` Josh Boyer
  2008-08-30  3:39           ` [PATCH] powerpc: Avoid integer overflow in page_is_ram() Roland Dreier
  1 sibling, 1 reply; 11+ messages in thread
From: vb @ 2008-08-28  3:47 UTC (permalink / raw)
  To: Roland Dreier; +Cc: Arnd Bergmann, linuxppc-embedded

On Wed, Aug 27, 2008 at 8:12 PM, Roland Dreier <rdreier@cisco.com> wrote:
> OK, please try this and let me know if it helps:
>
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 1c93c25..98d7bf9 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
>
>  int page_is_ram(unsigned long pfn)
>  {
> -       unsigned long paddr = (pfn << PAGE_SHIFT);
> -
>  #ifndef CONFIG_PPC64   /* XXX for now */
> -       return paddr < __pa(high_memory);
> +       return pfn < max_pfn;
>  #else
> +       unsigned long paddr = (pfn << PAGE_SHIFT);
>        int i;
>        for (i=0; i < lmb.memory.cnt; i++) {
>                unsigned long base;
>

Ronald, thank you for the hint,  I actually tried something slightly different:

return pfn < (__pa(high_memory) >> PAGE_SHIFT);

and it worked. I guess your fix is faster, I'll try it tomorrow.

I also checked that the problem is there in the top of the tree in
Linus' git - isn't it amazing - I guess very few people use mmap()
nowadays, everybody must be using UIO device :-)

cheers,
vadim

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: mmap and ppc460gt
  2008-08-28  3:47           ` vb
@ 2008-08-28 10:36             ` Josh Boyer
  0 siblings, 0 replies; 11+ messages in thread
From: Josh Boyer @ 2008-08-28 10:36 UTC (permalink / raw)
  To: vb; +Cc: Roland Dreier, Arnd Bergmann, linuxppc-embedded

On Wed, 27 Aug 2008 20:47:24 -0700
vb <vb@vsbe.com> wrote:

> On Wed, Aug 27, 2008 at 8:12 PM, Roland Dreier <rdreier@cisco.com> wrote:
> > OK, please try this and let me know if it helps:
> >
> > diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> > index 1c93c25..98d7bf9 100644
> > --- a/arch/powerpc/mm/mem.c
> > +++ b/arch/powerpc/mm/mem.c
> > @@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
> >
> >  int page_is_ram(unsigned long pfn)
> >  {
> > -       unsigned long paddr = (pfn << PAGE_SHIFT);
> > -
> >  #ifndef CONFIG_PPC64   /* XXX for now */
> > -       return paddr < __pa(high_memory);
> > +       return pfn < max_pfn;
> >  #else
> > +       unsigned long paddr = (pfn << PAGE_SHIFT);
> >        int i;
> >        for (i=0; i < lmb.memory.cnt; i++) {
> >                unsigned long base;
> >
> 
> Ronald, thank you for the hint,  I actually tried something slightly different:
> 
> return pfn < (__pa(high_memory) >> PAGE_SHIFT);
> 
> and it worked. I guess your fix is faster, I'll try it tomorrow.
> 
> I also checked that the problem is there in the top of the tree in
> Linus' git - isn't it amazing - I guess very few people use mmap()
> nowadays, everybody must be using UIO device :-)

No, most people use device drivers in the kernel.

josh

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] powerpc: Avoid integer overflow in page_is_ram()
  2008-08-28  3:12         ` Roland Dreier
  2008-08-28  3:47           ` vb
@ 2008-08-30  3:39           ` Roland Dreier
  2008-09-01  0:27             ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 11+ messages in thread
From: Roland Dreier @ 2008-08-30  3:39 UTC (permalink / raw)
  To: paulus, benh; +Cc: vb, Arnd Bergmann, linuxppc-embedded

Commit 8b150478 ("ppc: make phys_mem_access_prot() work with pfns
instead of addresses") fixed page_is_ram() in arch/ppc to avoid overflow
for addresses above 4G on 32-bit kernels.  However arch/powerpc's
page_is_ram() is missing the same fix -- it computes a physical address
by doing pfn << PAGE_SHIFT, which overflows if pfn corresponds to a page
above 4G.

In particular this causes pages above 4G to be mapped with the wrong
caching attribute; for example many ppc440-based SoCs have PCI space
above 4G, and mmap()ing MMIO space may end up with a mapping that has
caching enabled.

Fix this by working with the pfn and avoiding the conversion to
physical address that causes the overflow.  This patch compares the
pfn to max_pfn, which is a semantic change from the old code -- that
code compared the physical address to high_memory, which corresponds
to max_low_pfn.  However, I think that was is another bug, since
highmem pages are still RAM.

Reported-by: vb <vb@vsbe.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
---
This is a fix but the bug is pretty long-standing -- I think this is
2.6.28 material.

 arch/powerpc/mm/mem.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 1c93c25..98d7bf9 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
 
 int page_is_ram(unsigned long pfn)
 {
-	unsigned long paddr = (pfn << PAGE_SHIFT);
-
 #ifndef CONFIG_PPC64	/* XXX for now */
-	return paddr < __pa(high_memory);
+	return pfn < max_pfn;
 #else
+	unsigned long paddr = (pfn << PAGE_SHIFT);
 	int i;
 	for (i=0; i < lmb.memory.cnt; i++) {
 		unsigned long base;

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] powerpc: Avoid integer overflow in page_is_ram()
  2008-08-30  3:39           ` [PATCH] powerpc: Avoid integer overflow in page_is_ram() Roland Dreier
@ 2008-09-01  0:27             ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 11+ messages in thread
From: Benjamin Herrenschmidt @ 2008-09-01  0:27 UTC (permalink / raw)
  To: Roland Dreier; +Cc: vb, paulus, Arnd Bergmann, linuxppc-embedded

On Fri, 2008-08-29 at 20:39 -0700, Roland Dreier wrote:
> Commit 8b150478 ("ppc: make phys_mem_access_prot() work with pfns
> instead of addresses") fixed page_is_ram() in arch/ppc to avoid overflow
> for addresses above 4G on 32-bit kernels.  However arch/powerpc's
> page_is_ram() is missing the same fix -- it computes a physical address
> by doing pfn << PAGE_SHIFT, which overflows if pfn corresponds to a page
> above 4G.
> 
> In particular this causes pages above 4G to be mapped with the wrong
> caching attribute; for example many ppc440-based SoCs have PCI space
> above 4G, and mmap()ing MMIO space may end up with a mapping that has
> caching enabled.
> 
> Fix this by working with the pfn and avoiding the conversion to
> physical address that causes the overflow.  This patch compares the
> pfn to max_pfn, which is a semantic change from the old code -- that
> code compared the physical address to high_memory, which corresponds
> to max_low_pfn.  However, I think that was is another bug, since
> highmem pages are still RAM.
> 
> Reported-by: vb <vb@vsbe.com>
> Signed-off-by: Roland Dreier <rolandd@cisco.com>

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

> ---
> This is a fix but the bug is pretty long-standing -- I think this is
> 2.6.28 material.
> 
>  arch/powerpc/mm/mem.c |    5 ++---
>  1 files changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
> index 1c93c25..98d7bf9 100644
> --- a/arch/powerpc/mm/mem.c
> +++ b/arch/powerpc/mm/mem.c
> @@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
>  
>  int page_is_ram(unsigned long pfn)
>  {
> -	unsigned long paddr = (pfn << PAGE_SHIFT);
> -
>  #ifndef CONFIG_PPC64	/* XXX for now */
> -	return paddr < __pa(high_memory);
> +	return pfn < max_pfn;
>  #else
> +	unsigned long paddr = (pfn << PAGE_SHIFT);
>  	int i;
>  	for (i=0; i < lmb.memory.cnt; i++) {
>  		unsigned long base;

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2008-09-01  0:38 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-27  2:26 mmap and ppc460gt vb
2008-08-27  3:24 ` Roland Dreier
2008-08-27  8:13   ` Arnd Bergmann
2008-08-27 23:13     ` vb
2008-08-28  0:11       ` Roland Dreier
2008-08-28  0:21         ` vb
2008-08-28  3:12         ` Roland Dreier
2008-08-28  3:47           ` vb
2008-08-28 10:36             ` Josh Boyer
2008-08-30  3:39           ` [PATCH] powerpc: Avoid integer overflow in page_is_ram() Roland Dreier
2008-09-01  0:27             ` Benjamin Herrenschmidt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).