public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* Some Large Address Space Ponders on A9
@ 2014-07-01 15:59 Jon Loeliger
  2014-07-01 16:26 ` Catalin Marinas
  2014-07-01 16:43 ` Arnd Bergmann
  0 siblings, 2 replies; 6+ messages in thread
From: Jon Loeliger @ 2014-07-01 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

Folks,

I have a classic Cortex A9 based SoC in which I will need to
do some device driver development that will be capable of
addressing a physical address space larger than 32-bits.
I understand that the A9 doesn't support LPAE and that
pretending that it does and config'ing LPAE "on" will just
break six-ways-to-hell.

But I need to be able to specify some 64-bit addresses in
the Device Tree, and allow my device driver to manipulate
64-bit resource_size_t ranges.

Here's the problem.  Over in include/linux/types.h we find:

    #ifdef CONFIG_PHYS_ADDR_T_64BIT
    typedef u64 phys_addr_t;
    #else
    typedef u32 phys_addr_t;
    #endif

    typedef phys_addr_t resource_size_t;

So that means on my A9 system, phys_addr_t and resource_size_t
are either both 32-bit or both 64-bit.  I can't get just resource_size_t
to be 64-bit without some surgery here.

I've tried the obvious experiment of just config'ing up a
selection defining CONFIG_PHYS_ADDR_T_64BIT and seeing
if things work.  They don't; details below.

So, a few questions...

Should using a 64-bit phys_addr_t on an A9 "just work"?  Or is
this a new scenario never considered before?  Maybe a bug
due to this odd configuration that might need to be fixed?
Maybe some assumption of alignment, packed-ness
or sizes in some structure relating to context switching?

I think the device-tree handling code is able to grok and process
64-bit addresses.  Does it make sense to allow the phys_addr_t and
the resource_size_t to take on different sizes?  That is, to break the
above definition of resource_size_t from types.h and allow its size
to be determined independently of phys_addr_t?

Is there some easier (obvious even?) way to allow some DT devices to
use 64-bit resources and I've just missed it?

Thanks,
jdl


Failure mode details:

During boot, cpu_v7_switch_mm() gets handed an r1 with 0 in it
and dereferences it.  Here, in proc-v7-2level.S:

/*
 *    cpu_v7_switch_mm(pgd_phys, tsk)
 *
 *    Set the translation table base pointer to be pgd_phys
 *
 *    - pgd_phys - physical address of new TTB
 *
 *    It is assumed that:
 *    - we are not using split page tables
 */
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
    mov    r2, #0
    mmid    r1, r1                @ get mm->context.id
    ALT_SMP(orr    r0, r0, #TTB_FLAGS_SMP)
    ALT_UP(orr    r0, r0, #TTB_FLAGS_UP)
#ifdef CONFIG_ARM_ERRATA_430973
    mcr    p15, 0, r2, c7, c5, 6        @ flush BTAC/BTB
#endif
#ifdef CONFIG_PID_IN_CONTEXTIDR
    mrc    p15, 0, r2, c13, c0, 1        @ read current context ID
    lsr    r2, r2, #8            @ extract the PID
    bfi    r1, r2, #8, #24            @ insert into new context ID
#endif
#ifdef CONFIG_ARM_ERRATA_754322
    dsb
#endif
    mcr    p15, 0, r1, c13, c0, 1        @ set context ID
    isb
    mcr    p15, 0, r0, c2, c0, 0        @ set TTB 0
    isb
#endif
    mov    pc, lr
ENDPROC(cpu_v7_switch_mm)



[    2.724891] devtmpfs: mounted
[    2.728262] Freeing unused kernel memory: 152K (c03df000 - c0405000)
[    2.736104] Unable to handle kernel NULL pointer dereference at
virtual address 00000178
[    2.744293] pgd = ede00000
[    2.747010] [00000178] *pgd=00000000
[    2.750637] Internal error: Oops: 5 [#1] SMP ARM
[    2.755259] Modules linked in:
[    2.758338] CPU: 0 PID: 1 Comm: swapper/0 Not tainted
3.14.0-00019-g5f79c4b-dirty #380
[    2.766264] task: ee84c000 ti: ee858000 task.ti: ee858000
[    2.771679] PC is at cpu_v7_switch_mm+0x4/0x24
[    2.776139] LR is at flush_old_exec+0x3f0/0x514
[    2.780682] pc : [<c0018f64>]    lr : [<c00a8d5c>]    psr: 20000113
[    2.780682] sp : ee859ea8  ip : ede00000  fp : c0429698
[    2.792167] r10: ee84c314  r9 : eea4c800  r8 : eddf4000
[    2.797399] r7 : eeb78400  r6 : 00000000  r5 : ee84c000  r4 : c0415840
[    2.803932] r3 : 00000001  r2 : 00000000  r1 : 00000000  r0 : 2de00000
[    2.810466] Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM
Segment kernel
[    2.817782] Control: 10c5387d  Table: 0000404a  DAC: 00000015
[    2.823534] Process swapper/0 (pid: 1, stack limit = 0xee858240)
[    2.829547] Stack: (0xee859ea8 to 0xee85a000)
[    2.833917] 9ea0:                   05000002 ee8b96b4 ee8b9680
eeb78400 00000001 00000002
[    2.842109] 9ec0: ee004100 c00e1950 eeb78400 00000080 00000001
ee858000 00000000 eeb78400
[    2.850301] 9ee0: 00000001 beffffd3 ee004f00 eeff0075 eeb78400
c00a7d3c 00000017 ee859f0c
[    2.858491] 9f00: 00000000 0000000b befff000 ee859ec8 beffffc8
c0400fc8 0000000b 00000000
[    2.866683] 9f20: ef003000 eeb78400 c04177a4 c00e1698 00000001
c0417168 eddf4044 eddf4000
[    2.874874] 9f40: c0429698 c00a7e9c eeb78400 ee858000 ee81c000
00000000 00000001 c00a9498
[    2.883065] 9f60: c0410258 c04102e0 00000000 ee84c1fc 00000000
c04291c0 c0364a08 00000000
[    2.891255] 9f80: 00000000 00000000 00000000 00000000 00000000
c00086d4 00000000 c04291c0
[    2.899444] 9fa0: c02cb744 c02cb7bc 00000000 c000d918 00000000
00000000 00000000 00000000
[    2.907633] 9fc0: 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000
[    2.915822] 9fe0: 00000000 00000000 00000000 00000000 00000013
00000000 ffffffff ffffffff
[    2.924029] [<c0018f64>] (cpu_v7_switch_mm) from [<ee858000>] (0xee858000)
[    2.930920] Code: 00000000 00000000 00000000 e3a02000 (e5911178)
[    2.937053] ---[ end trace 41f2c02886b01a23 ]---

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

* Some Large Address Space Ponders on A9
  2014-07-01 15:59 Some Large Address Space Ponders on A9 Jon Loeliger
@ 2014-07-01 16:26 ` Catalin Marinas
  2014-07-01 17:41   ` Jon Loeliger
  2014-07-01 16:43 ` Arnd Bergmann
  1 sibling, 1 reply; 6+ messages in thread
From: Catalin Marinas @ 2014-07-01 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 01, 2014 at 10:59:45AM -0500, Jon Loeliger wrote:
> I have a classic Cortex A9 based SoC in which I will need to
> do some device driver development that will be capable of
> addressing a physical address space larger than 32-bits.
> I understand that the A9 doesn't support LPAE and that
> pretending that it does and config'ing LPAE "on" will just
> break six-ways-to-hell.
> 
> But I need to be able to specify some 64-bit addresses in
> the Device Tree, and allow my device driver to manipulate
> 64-bit resource_size_t ranges.
> 
> Here's the problem.  Over in include/linux/types.h we find:
> 
>     #ifdef CONFIG_PHYS_ADDR_T_64BIT
>     typedef u64 phys_addr_t;
>     #else
>     typedef u32 phys_addr_t;
>     #endif
> 
>     typedef phys_addr_t resource_size_t;

I won't comment on how you define this in DT but for the kernel things
will likely break when you increase phys_addr_t to 64-bit on non-LPAE
builds.

First (only) question - how do you intend to map such physical address?
The only way I'm aware of on A9 is using supersections and the ARM Linux
port provides __arm_ioremap_pfn(). However, the supersections code is
only enabled if !SMP.

-- 
Catalin

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

* Some Large Address Space Ponders on A9
  2014-07-01 15:59 Some Large Address Space Ponders on A9 Jon Loeliger
  2014-07-01 16:26 ` Catalin Marinas
@ 2014-07-01 16:43 ` Arnd Bergmann
  2014-07-01 17:51   ` Jon Loeliger
  2014-07-01 19:12   ` Jon Loeliger
  1 sibling, 2 replies; 6+ messages in thread
From: Arnd Bergmann @ 2014-07-01 16:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 01 July 2014 10:59:45 Jon Loeliger wrote:
> Folks,
> 
> I have a classic Cortex A9 based SoC in which I will need to
> do some device driver development that will be capable of
> addressing a physical address space larger than 32-bits.
> I understand that the A9 doesn't support LPAE and that
> pretending that it does and config'ing LPAE "on" will just
> break six-ways-to-hell.
> 
> But I need to be able to specify some 64-bit addresses in
> the Device Tree, and allow my device driver to manipulate
> 64-bit resource_size_t ranges.
> 
> Here's the problem.  Over in include/linux/types.h we find:
> 
>     #ifdef CONFIG_PHYS_ADDR_T_64BIT
>     typedef u64 phys_addr_t;
>     #else
>     typedef u32 phys_addr_t;
>     #endif
> 
>     typedef phys_addr_t resource_size_t;
> 
> So that means on my A9 system, phys_addr_t and resource_size_t
> are either both 32-bit or both 64-bit.  I can't get just resource_size_t
> to be 64-bit without some surgery here.

Hmm, we sometimes confuse phys_addr_t and dma_addr_t, because for
all practical purposes they tend to be the same. However, I think
what you need here is dma_addr_t, which is defined independently.

You will probably run into bugs if you have dma_addr_t >
phys_addr_t, but you could try fixing those.

> I've tried the obvious experiment of just config'ing up a
> selection defining CONFIG_PHYS_ADDR_T_64BIT and seeing
> if things work.  They don't; details below.
> 
> So, a few questions...
> 
> Should using a 64-bit phys_addr_t on an A9 "just work"?  Or is
> this a new scenario never considered before?  Maybe a bug
> due to this odd configuration that might need to be fixed?
> Maybe some assumption of alignment, packed-ness
> or sizes in some structure relating to context switching?

It should mostly just work, since a lot of the same code gets
used by A7 and A15 when LPAE is enabled.

> I think the device-tree handling code is able to grok and process
> 64-bit addresses.  Does it make sense to allow the phys_addr_t and
> the resource_size_t to take on different sizes?  That is, to break the
> above definition of resource_size_t from types.h and allow its size
> to be determined independently of phys_addr_t?

resource_size_t and phys_addr_t should really be the same all the
time.

> Is there some easier (obvious even?) way to allow some DT devices to
> use 64-bit resources and I've just missed it?

You can try 64-bit dma_addr_t with 32-bit resource_size_t/phys_addr_t,
but it's more likely to work if you make them all 64-bit.

	Arnd

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

* Some Large Address Space Ponders on A9
  2014-07-01 16:26 ` Catalin Marinas
@ 2014-07-01 17:41   ` Jon Loeliger
  0 siblings, 0 replies; 6+ messages in thread
From: Jon Loeliger @ 2014-07-01 17:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 1, 2014 at 11:26 AM, Catalin Marinas
<catalin.marinas@arm.com> wrote:

>> Here's the problem.  Over in include/linux/types.h we find:
>>
>>     #ifdef CONFIG_PHYS_ADDR_T_64BIT
>>     typedef u64 phys_addr_t;
>>     #else
>>     typedef u32 phys_addr_t;
>>     #endif
>>
>>     typedef phys_addr_t resource_size_t;
>
> I won't comment on how you define this in DT but for the kernel things
> will likely break when you increase phys_addr_t to 64-bit on non-LPAE
> builds.
>
> First (only) question - how do you intend to map such physical address?
> The only way I'm aware of on A9 is using supersections and the ARM Linux
> port provides __arm_ioremap_pfn(). However, the supersections code is
> only enabled if !SMP.
>
> --
> Catalin

So, I don't really need to map in that as physical address space
that will be actually accessed.  I need to be able to parse the
large values out of the DT (2-cell values) into resource_size_t
variables and then manipulate the address space they represent.
Later, my IP block can handle the larger addresses, not as physical
memory, but as addresses.  I guess you could think of it as a
windowing or address translation mechanism that isn't coming
from the A9's 32-bit AXI bus.

Does that help explain the weird?  Or just confuse it? :-)

jdl

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

* Some Large Address Space Ponders on A9
  2014-07-01 16:43 ` Arnd Bergmann
@ 2014-07-01 17:51   ` Jon Loeliger
  2014-07-01 19:12   ` Jon Loeliger
  1 sibling, 0 replies; 6+ messages in thread
From: Jon Loeliger @ 2014-07-01 17:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arnd,

On Tue, Jul 1, 2014 at 11:43 AM, Arnd Bergmann <arnd@arndb.de> wrote:

> Hmm, we sometimes confuse phys_addr_t and dma_addr_t, because for
> all practical purposes they tend to be the same. However, I think
> what you need here is dma_addr_t, which is defined independently.
>
> You will probably run into bugs if you have dma_addr_t >
> phys_addr_t, but you could try fixing those.

Changing even dma_addr_t won't solve the issues that I see.
I need to be able to specify device tree devices that have 64-bit
resources.  All the subsequent math on those resources just falls
out and is written already in terms of resource_size_t data.

>> Should using a 64-bit phys_addr_t on an A9 "just work"?  Or is
>> this a new scenario never considered before?  Maybe a bug
>> due to this odd configuration that might need to be fixed?
>> Maybe some assumption of alignment, packed-ness
>> or sizes in some structure relating to context switching?
>
> It should mostly just work, since a lot of the same code gets
> used by A7 and A15 when LPAE is enabled.

Well, see, that's where I kind of thought we might be.  It seems
like the boot was working reasonably well.  But that maybe there
was some niggling "oh, duh!" bug that needed to be tracked down
in the context switch code or so...  And I just don't even begin to
understand enough of that black magic to start guessing yet. :-)

>> I think the device-tree handling code is able to grok and process
>> 64-bit addresses.  Does it make sense to allow the phys_addr_t and
>> the resource_size_t to take on different sizes?  That is, to break the
>> above definition of resource_size_t from types.h and allow its size
>> to be determined independently of phys_addr_t?
>
> resource_size_t and phys_addr_t should really be the same all the
> time.

Why?  What is the driving force or underlying assumption there?

>> Is there some easier (obvious even?) way to allow some DT devices to
>> use 64-bit resources and I've just missed it?
>
> You can try 64-bit dma_addr_t with 32-bit resource_size_t/phys_addr_t,
> but it's more likely to work if you make them all 64-bit.

Hmm.  So ponder enabling LPAE *except* for changes that it would
induce on page tables, MMU, addressing, illegal instructions, etc.
Just the address size changes, alignment, structure layout, etc.

World of hurt, right?

>         Arnd

Thanks,
jdl

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

* Some Large Address Space Ponders on A9
  2014-07-01 16:43 ` Arnd Bergmann
  2014-07-01 17:51   ` Jon Loeliger
@ 2014-07-01 19:12   ` Jon Loeliger
  1 sibling, 0 replies; 6+ messages in thread
From: Jon Loeliger @ 2014-07-01 19:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 1, 2014 at 11:43 AM, Arnd Bergmann <arnd@arndb.de> wrote:

>> I think the device-tree handling code is able to grok and process
>> 64-bit addresses.  Does it make sense to allow the phys_addr_t and
>> the resource_size_t to take on different sizes?  That is, to break the
>> above definition of resource_size_t from types.h and allow its size
>> to be determined independently of phys_addr_t?
>
> resource_size_t and phys_addr_t should really be the same all the
> time.
>
>         Arnd

So, as an experiment I did this:

diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 1f8fed9..0dfb76f 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -631,6 +631,9 @@ config ARCH_PHYS_ADDR_T_64BIT
 config ARCH_DMA_ADDR_T_64BIT
        bool

+config RESOURCE_SIZE_T_64BIT
+       bool
+
 config ARM_THUMB
        bool "Support Thumb user binaries" if !CPU_THUMBONLY
        depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || \
diff --git a/include/linux/types.h b/include/linux/types.h
index 4d118ba..331d59a 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -164,7 +164,11 @@ typedef u64 phys_addr_t;
 typedef u32 phys_addr_t;
 #endif

+#ifdef CONFIG_RESOURCE_SIZE_T_64BIT
+typedef u64 resource_size_t;
+#else
 typedef phys_addr_t resource_size_t;
+#endif

And then this:

+       select RESOURCE_SIZE_T_64BIT

Verified a few things:

$ gdb -q ./vmlinux
Reading symbols from vmlinux...done.
(gdb) p sizeof(resource_size_t)
$1 = 8
(gdb) p sizeof(phys_addr_t)
$2 = 4
(gdb) p sizeof(dma_addr_t)
$3 = 4

And it all booted just fine.

jdl

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

end of thread, other threads:[~2014-07-01 19:12 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-01 15:59 Some Large Address Space Ponders on A9 Jon Loeliger
2014-07-01 16:26 ` Catalin Marinas
2014-07-01 17:41   ` Jon Loeliger
2014-07-01 16:43 ` Arnd Bergmann
2014-07-01 17:51   ` Jon Loeliger
2014-07-01 19:12   ` Jon Loeliger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox