APC8750にNetBSD/evbarmを移植するための記録 9/7 その1
2014/01/13(月) 21:11 NetBSD はてブ情報 はてブに登録 はてブ数

ずいぶん時間が過ぎ去った。割り込みコントローラの続き。

割り込みコントローラのアドレスをダンプしてみる
WMT # md.l d8140000
d8140000: 0000003f 0000003f 0000003f 00000000    ?...?...?.......
d8140010: 00000000 00000000 00000000 00000000    ................
d8140020: 00000000 00000000 00000000 00000000    ................
d8140030: 00000000 00000000 00000000 00000000    ................
d8140040: 00000000 00000000 00000000 00000000    ................
d8140050: 00000000 00000000 00000000 00000000    ................
d8140060: 00000000 00000000 00000000 00000000    ................
d8140070: 00000000 00000000 00000000 00000000    ................
d8140080: 00000000 00000000 00000000 00000000    ................
d8140090: 00000000 00000000 00000000 00000000    ................
d81400a0: 00000000 00000000 00000000 00000000    ................
d81400b0: 00000000 00000000 00000000 00000000    ................
d81400c0: 00000000 00000000 00000000 00000000    ................
d81400d0: 00000000 00000000 00000000 00000000    ................
d81400e0: 00000000 00000000 00000000 00000000    ................
d81400f0: 00000000 00000000 00000000 00000000    ................
最初の三つが気になる。
u-bootも見たほうがいいか?
うーん、探せない...

まぁ、触ってみるか。
        /* debug */
        for (i = 0; i < 10; i++) {
                aprint_normal("icu-debug: ");
                debug = bus_space_read_4(sc->sc_iot, sc->sc_ioh, i);
                aprint_normal("%08x  %08x\n", (int)WM8750_IC0_BASE + i * 4, debug);
        }
とかattachルーチンにいれてみた。

bus_space_read_4の引き数の最後は割り込みコントローラの先頭アドレス(0xd8140000)からの相対位置でよい。最初は絶対アドレスで書いていたら
wmicu0 at obio0 addr 0xd8140000-0xd814ffff
icu-debug:
uvm_fault(0xc027dfb4, d6280000, 1) -> e
Fatal kernel mode data abort: 'Translation Fault (S)'
trapframe: 0xc0296d80
FSR=00000005, FAR=d6280000, spsr=200001d3
r0 =00000000, r1 =fe140000, r2 =d8140000, r3 =c000e840
r4 =c1a2a668, r5 =d8140000, r6 =d8140028, r7 =c01b16dc
r8 =c018c0a8, r9 =c0180744, r10=00000000, r11=c0296dec
r12=c0296da8, ssp=c0296dd0, slr=c01659dc, pc =c000e844

Stopped in pid 0.1 (system) at  netbsd:generic_bs_r_4+0x4:      ldr     r0, [r1, r2]
0xc0296dec: netbsd:wm8750_icu_attach+0xc
0xc0296e18: netbsd:config_attach_loc+0x190
0xc0296e30: netbsd:config_found+0x2c
0xc0296e58: netbsd:obio_attach_critical+0x40
0xc0296e70: netbsd:obio_attach+0x38
0xc0296e9c: netbsd:config_attach_loc+0x190
0xc0296eb0: netbsd:config_attach+0x24
0xc0296eec: netbsd:mainbussearch+0x8c
0xc0296f30: netbsd:config_search_loc+0x134
0xc0296f44: netbsd:config_search_ia+0x1c
0xc0296f70: netbsd:config_attach_loc+0x190
0xc0296f84: netbsd:config_attach+0x24
0xc0296f9c: netbsd:cpu_configure+0x30
0xc0296fec: netbsd:main+0x1fc
0xc0296ffc: netbsd:kernel_text+0x50
db>
などと言って落ちた。

もちろん、先のコードでも
icu-debug: d8140000  0000003f
icu-debug: data_abort_handler: data_aborts fsr=0x1 far=0xfe140001
Fatal kernel mode data abort: 'Alignment Fault 1'
trapframe: 0xc0296d78
FSR=00000001, FAR=fe140001, spsr=200001d3
r0 =00000000, r1 =fe140000, r2 =00000001, r3 =c000e840
r4 =c1a2a668, r5 =00000001, r6 =d8140004, r7 =00000000
r8 =c018c0a8, r9 =c0180744, r10=00000000, r11=c0296dec
r12=c0296da4, ssp=c0296dcc, slr=c01659e0, pc =c000e844

Stopped in pid 0.1 (system) at  netbsd:generic_bs_r_4+0x4:      ldr     r0, [r1, r2]
0xc0296dec: netbsd:wm8750_icu_attach+0xc
0xc0296e18: netbsd:config_attach_loc+0x190
0xc0296e30: netbsd:config_found+0x2c
0xc0296e58: netbsd:obio_attach_critical+0x40
0xc0296e70: netbsd:obio_attach+0x38
0xc0296e9c: netbsd:config_attach_loc+0x190
0xc0296eb0: netbsd:config_attach+0x24
0xc0296eec: netbsd:mainbussearch+0x8c
0xc0296f30: netbsd:config_search_loc+0x134
0xc0296f44: netbsd:config_search_ia+0x1c
0xc0296f70: netbsd:config_attach_loc+0x190
0xc0296f84: netbsd:config_attach+0x24
0xc0296f9c: netbsd:cpu_configure+0x30
0xc0296fec: netbsd:main+0x1fc
0xc0296ffc: netbsd:kernel_text+0x50
db>
と言って落ちる。一刻みのアドレスでアクセスできるわけないのでアラインメントがおかしいといって。おちる。
comprobe1 0
</wm8750_uart_match rv=0>
wmicu0 at obio0 addr 0xd8140000-0xd814ffff
icu-debug: d8140000  0000003f
icu-debug: d8140004  0000003f
icu-debug: d8140008  0000003f
icu-debug: d814000c  00000000
icu-debug: d8140010  00000000
icu-debug: d8140014  00000000

中略

icu-debug: d81400f8  00000000
icu-debug: d81400fc  00000000
<wm8750_uart_match>
com0 at obio0 addr 0xd8200000-0xd820ffff intr 32  : ns16650, no ERS, working fifo
com0: console
establish_irq
debug: unblock
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer
establish_irq
debug: unblock
rn_init: radix functions require max_keylen be set
boot device: <unknown>
root device:
debugいれてみた。icuのモジュールが呼ばれている。

ということで、読むのができたら書けるはず。

unblock, blockで読み書きをしてみたが、値が書けるところと書けないところがある。irq=32だとかけて、irq=0だと書けない。
そもそもirq=0って使っていないはず。

establish_irqでis->is_irqで表示させたらirq=3である。なんだこれ。

とにかく、何で書けないのか。

頭にきて、attachで0xd8140000から0xFFFFFFFFを128個ほど書いて直後に読んで書き込めているかどうか表示させてみた。

すると、0xd8140040からは0x7F7F7F7Fが16個(8ビットで64個)と書けている。

そういえば、Linuxでは
#define    ICDC0_ADDR      (__IC_BASE + 0x40)      /* dest_ctl_addr[0]  */
と書いてあったのを忘れていた。0xd8140040から8ビット刻みで64個なので辻褄もあっている。ご丁寧に0で初期化されている。

つぎは、irq=3がirq=0になっているところ。

これは、block, unblockに渡されてくるirqbase, irq_maskの二つの合わせ技で考えなければならなかった。

これはsys/arch/arm/pic/pic.c#660を読むとわかる。
    660     (*pic->pic_ops->pic_establish_irq)(pic, is);
    661
    662     (*pic->pic_ops->pic_unblock_irqs)(pic, is->is_irq & ~0x1f,
    663         __BIT(is->is_irq & 0x1f));
establish_irqにはすなおにisが渡されているが、unblockには0x1fでビットがクリアされたものがirqbaseに渡されている。
0から31を表現する下位5ビット分(0x1f)を数字として、32ビットのビット位置で表現されている。

たとえば、irq=3であれば、0x1fでビットをクリアすると0x0なのでirqbaseはゼロ。下位5ビット分は3なので3ビット目が立っている0x8となる。3ビット目といっても0ビット目があるので1<<4になる。1を4ビットシフトさせて0x8である。

ということで、IRQ番号を求めるには、irqbase + (irq_maskの何ビット目が立っているか)を計算する必要がある。

geminiのようにIRQのmaskをビットでやるようなタイプだとこちらのほうが便利ということですね。

さて、IRQは3だということがわかったのですが、このIRQは使われていない(unusedで定義されている)はずなので、やっぱり何かが変です。

また、このestablishを読んでいるのはおそらくタイマードライバです。タイマードライバはirq=48でconfigに書いてあるのですが。

謎だ。

と思ったら、intrが3になる件、当たり前だった。
clock_ih = wm8750_intr_establish(WM8750_INT_TIMER3, IPL_CLOCK,
などとRPIのそのまま(RPIからWM8750に単純置換したまま)になっていたからだ。ばかすぎる。

ところでIPL_CLOCKのIPLとはなにか、Interreput Priority Levelとのこと。

sys/arch/evbarm/include/intr.h#44によると次のとおり。
     43 /* Interrupt priority "levels". */
     44 #define    IPL_NONE    0        /* nothing */
     45 #define    IPL_SOFTCLOCK    1        /* clock */
     46 #define    IPL_SOFTBIO    2        /* block I/O */
     47 #define    IPL_SOFTNET    3        /* software network interrupt */
     48 #define    IPL_SOFTSERIAL    4        /* software serial interrupt */
     49 #define    IPL_VM        5        /* memory allocation */
     50 #define    IPL_SCHED    6        /* clock interrupt */
     51 #define    IPL_HIGH    7        /* everything */
     52
     53 #define    NIPL        8
こういうレベルに基づいて割り込みを格付けしているのですね。

wm8750tmr_softcにint sc_intrというメンバを加え、attach時にobioから
        sc->sc_intr = obio->obio_intr;
てな感じでsoftcに保存。establish時にsc->sc_intrを使うようにすると、
com0 at obio0 addr 0xd8200000-0xd820ffff intr 32  : ns16650, no ERS, working fifo
com0: console
icu: establish_irq: is->is_irq=0x20
icu: unblock: irqbase=0x00000020, irqmask=0x00000001, 0x00000000 -> 0x00000008
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, 0x00000008 -> 0x00000008
rn_init: radix functions require max_keylen be set
boot device: <unknown>
root device:
てな具合。irqmaskも0x10000なので、右から数えて17番目、0から始めて16を表現しているから、0x20+0x10=0x30であってますね。
IRQ = iobase + log(irqmask, 2) という数式で表せばいいかな。

ここまでのログを張っておこう。
WMT # go 8000
## Starting application at 0x00008000 ...
00008328
NetBSD
00000000 00000000 0049096b 00000412
00000000 00000412 00000004 00000412
c0000000 00000000 0049096b 0000041e
00003000 0000041e 00000004 0000041e
fe000000 d8000000 010fffff 00000412
00003f80 d8000412 00000010 00000412
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000



NetBSD/evbarm (APC) booting ...
initarm: Configuring system ...
arm32_bootmem_init: memstart=0, memsize=0x20000000, kernelstart=0x8000
arm32_bootmem_init: kernelend=0x291000
arm32_bootmem_init: adding 130415 free pages: [0x291000..0x1fffffff] (VA 0xc0291000)
arm32_bootmem_init: adding 8 free pages: [0..0x7fff] (VA 0xc0000000)
arm32_kernel_vm_init: 1 L2 pages are needed to map 0x2bc000 kernel bytes
arm32_kernel_vm_init: allocating page tables for vectoradd_pages: adding pv 0xc027fbe8 (pa 0x291000, va 0xc0291000, 1 pages) at tail
 kerneladd_pages: appending pv 0xc027fe70 (0x292000..0x292fff) to 0x291000..0x291fff
 vmadd_pages: appending pv 0xc027fe84 (0x293000..0x293fff) to 0x291000..0x292fff
add_pages: appending pv 0xc028892c (0x294000..0x297fff) to 0x291000..0x293fff
add_pages: appending pv 0xc027fe98 (0x298000..0x298fff) to 0x291000..0x297fff
add_pages: appending pv 0xc027feac (0x299000..0x299fff) to 0x291000..0x298fff
add_pages: appending pv 0xc027fec0 (0x29a000..0x29afff) to 0x291000..0x299fff
add_pages: appending pv 0xc027fed4 (0x29b000..0x29bfff) to 0x291000..0x29afff
add_pages: appending pv 0xc027fee8 (0x29c000..0x29cfff) to 0x291000..0x29bfff
add_pages: appending pv 0xc027fefc (0x29d000..0x29dfff) to 0x291000..0x29cfff
add_pages: appending pv 0xc027ff10 (0x29e000..0x29efff) to 0x291000..0x29dfff
add_pages: appending pv 0xc028016c (0x29f000..0x29ffff) to 0x291000..0x29efff
add_pages: appending pv 0xc0280180 (0x2a0000..0x2a0fff) to 0x291000..0x29ffff
add_pages: appending pv 0xc0280194 (0x2a1000..0x2a1fff) to 0x291000..0x2a0fff
add_pages: appending pv 0xc02801a8 (0x2a2000..0x2a2fff) to 0x291000..0x2a1fff
add_pages: appending pv 0xc02801bc (0x2a3000..0x2a4fff) to 0x291000..0x2a2fff
add_pages: appending pv 0xc0280158 (0x2a5000..0x2a6fff) to 0x291000..0x2a4fff
add_pages: appending pv 0xc027fc64 (0x2a7000..0x2aafff) to 0x291000..0x2a6fff
Creating L1 page table at 0x00294000
arm32_kernel_vm_init: adding L2 pt (VA 0xc0291000, PA 0x291000) for VA 0xffff0000
 (vectors)arm32_kernel_vm_init: adding L2 pt (VA 0xc0292000, PA 0x292000) for VA 0xc0000000 (kernel)
arm32_kernel_vm_init: adding L2 pt (VA 0xc0293000, PA 0x293000) for VA 0xc1000000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc0298000, PA 0x298000) for VA 0xc1400000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc0299000, PA 0x299000) for VA 0xc1800000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc029a000, PA 0x29a000) for VA 0xc1c00000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc029b000, PA 0x29b000) for VA 0xc2000000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc029c000, PA 0x29c000) for VA 0xc2400000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc029d000, PA 0x29d000) for VA 0xc2800000 (vm)
arm32_kernel_vm_init: adding L2 pt (VA 0xc029e000, PA 0x29e000) for VA 0xc2c00000 (vm)
Mapping kernel
arm32_kernel_vm_init: adding chunk for kernel text 0x8000..0x1affff (VA 0xc0008000)
add_pages: adding pv 0xc027fbd4 (pa 0x8000, va 0xc0008000, 424 pages) before pa 0x291000
arm32_kernel_vm_init: adding chunk for kernel data/bss 0x1b0000..0x290fff (VA 0xc01b0000)
add_pages: appending pv 0xc027fc3c (0x1b0000..0x290fff) to 0x8000..0x1affff
add_pages: merging pv 0xc027fbe8 (0x291000..0x2aafff) to 0x8000..0x290fff
Listing Chunks
arm32_kernel_vm_init: pv 0xc027fbd4: chunk VA 0xc0008000..0xc02aafff (PA 0x8000, prot 3, cache 1)

Mapping Chunks
arm32_kernel_vm_init: mapping last chunk VA 0xc0008000..0xc02aafff (PA 0x8000, prot 3, cache 1)
pmap_map_chunk: pa=0x8000 va=0xc0008000 size=0x2a3000 resid=0x2a3000 prot=0x3 cache=1
PPPPPPPPLLLLLLLLLLLLLLLSLLLLLLLLLLPPPPPPPPPPP
devmap: d8000000 -> d8ffffff @ fe000000
pmap_map_chunk: pa=0xd8000000 va=0xfe000000 size=0x1000000 resid=0x1000000 prot=0x3 cache=0
SSSSSSSSSSSSSSSS
                             Physical              Virtual        Num
                       Starting    Ending    Starting    Ending   Pages
               SDRAM: 0x00000000 0x1fffffff 0xc0000000 0xdfffffff 131072
        text section: 0x00008000 0x001affff 0xc0008000 0xc01affff 424
        data section: 0x001c0000 0x0027f4c0 0xc01c0000 0xc027f4c0 192
         bss section: 0x0027f4c0 0x0029096c 0xc027f4c0 0xc029096c 18
   L1 page directory: 0x00294000 0x00297fff 0xc0294000 0xc0297fff 4
   ABT stack (CPU 0): 0x0029f000 0x0029ffff 0xc029f000 0xc029ffff 1
   FIQ stack (CPU 0): 0x002a0000 0x002a0fff 0xc02a0000 0xc02a0fff 1
   IRQ stack (CPU 0): 0x002a1000 0x002a1fff 0xc02a1000 0xc02a1fff 1
   UND stack (CPU 0): 0x002a2000 0x002a2fff 0xc02a2000 0xc02a2fff 1
  IDLE stack (CPU 0): 0x002a3000 0x002a4fff 0xc02a3000 0xc02a4fff 2
           SVC stack: 0x002a5000 0x002a6fff 0xc02a5000 0xc02a6fff 2
      Message Buffer: 0x002a7000 0x002aafff 0xc02a7000 0xc02aafff 4
   Exception Vectors: 0x002ab000 0x002abfff 0xffff0000 0xffff0fff 1
         Free Memory: 0x002ac000 0x1fffffff                       130388
         Free Memory: 0x00000000 0x00007fff                       8
switching to new L1 page table @0x294000...TTBR0=0x294000 OK
done.
nfreeblocks = 2, free_pages = 130396 (0x1fd5c)
bootstrap done.
vectors 0xffff0000
init subsystems: stacks vectors undefined page pmap_physload pmap [ Kernel symbol table missing! ]
done.
Loaded initial symtab at 0xc01c4364, strtab at 0xc01e34d4, # entries 7944
pmap_postinit: Allocated 35 static L1 descriptor tables
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 6.99.23 (APC) #55: Mon Sep  9 22:46:37 UTC 2013
        root@builder.localdomain:/usr/obj/sys/arch/evbarm/compile/APC
total memory = 512 MB
avail memory = 499 MB
mainbus0 (root)
cpu0 at mainbus0 core 0: ARM1176JZ-S r0p7 (ARM11J V6ZK core)
cpu0: DC enabled IC enabled WB enabled LABT
cpu0: 16KB/32B 4-way L1 Instruction cache
cpu0: 16KB/32B 4-way write-back-locking-C L1 Data cache
vfp0 at cpu0: VFP11
obio0 at mainbus0
<wm8750_uart_match>
comprobe1 0
</wm8750_uart_match rv=0>
wmicu0 at obio0 addr 0xd8140000-0xd814ffff
icu-debug: d8140040: 00000000
icu-debug: d8140044: 00000000
icu-debug: d8140048: 00000000
icu-debug: d814004c: 00000000
icu-debug: d8140050: 00000000
icu-debug: d8140054: 00000000
icu-debug: d8140058: 00000000
icu-debug: d814005c: 00000000
icu-debug: d8140060: 00000000
icu-debug: d8140064: 00000000
icu-debug: d8140068: 00000000
icu-debug: d814006c: 00000000
icu-debug: d8140070: 00000000
icu-debug: d8140074: 00000000
icu-debug: d8140078: 00000000
icu-debug: d814007c: 00000000
<wm8750_uart_match>
com0 at obio0 addr 0xd8200000-0xd820ffff intr 32  : ns16650, no ERS, working fifo
com0: console
icu: establish_irq: is->is_irq=0x20
icu: unblock: irqbase=0x00000020, irqmask=0x00000001, 0x00000000 -> 0x00000008
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer
icu: establish_irq: is->is_irq=0x30
icu: unblock: irqbase=0x00000020, irqmask=0x00010000, 0x00000008 -> 0x00000008
rn_init: radix functions require max_keylen be set
boot device: <unknown>
root device:

APC8750にNetBSD/evbarmを移植するための記録 8/26
2014/01/13(月) 20:39 NetBSD はてブ情報 はてブに登録 はてブ数

今日はgitを入れてリモートからリポジトリを使えるようにする。

が、pkgsrcからscmgitを入れているだけで終わってしまった。

APC8750にNetBSD/evbarmを移植するための記録 8/25
2014/01/13(月) 18:12 NetBSD はてブ情報 はてブに登録 はてブ数

割り込みコントローラをちゃんとしないといけないらしいが、まるで分らない。

ARMのドキュメントをあたると、Cortexなどは標準の割り込みコントローラが内蔵されているようにみえるが、ARM11は英語しかないのでわからん。が、Chapter 12. Vectored Interrupt Controller Portとかいうのがある。こいつはPL192とかいうやつらしいのでその仕様書を読めと書いてある。

Linuxのソースをあたっても、PL192とかいうのはWM8750では使ってなさそうな気がする。

そういえば、http://www.spinics.net/lists/arm-kernel/msg240125.htmlとかいうページを見つけた。vt8500-intcとか読めるので、VT8500というCPU(おそらく昔のVIAのARMで、それがWonderMediaに子会社化されたとかそういうの?)とcompatibleといっておる。VT8500のirc.cとWM8750のirc.cを比較すると、似ているといえば似ているけれど、だいぶ違うような。

http://lxr.free-electrons.com/source/drivers/irqchip/irq-vt8500.c

https://github.com/apc-io/apc-8750/blob/master/kernel/arch/arm/mach-wmt/irq.c

そもそもソースツリーの構造が違うのを比較しても意味ないかもしれんな。

NetBSDの割り込み処理を読んでも、よくわからん。もしかしたら、LinuxとNetBSDの両方にある評価ボードの割り込み処理を比較して、Linuxでこう書くところをNetBSDでこう書けばよい、とわかれば、それをWM8750のirq.cからNetBSDに変換することができるかもしれん。

例によってLinux側のgeminiを見てみるか。ソースはapc-8750/kernel/arch/arm/mach-gemini/irq.cだな。

まずは、レジスタは4刻みで定義されている。
#define IRQ_SOURCE(base_addr) (base_addr + 0x00)
#define IRQ_MASK(base_addr) (base_addr + 0x04)
#define IRQ_CLEAR(base_addr) (base_addr + 0x08)
#define IRQ_TMODE(base_addr) (base_addr + 0x0C)
#define IRQ_TLEVEL(base_addr) (base_addr + 0x10)
#define IRQ_STATUS(base_addr) (base_addr + 0x14)
#define FIQ_SOURCE(base_addr) (base_addr + 0x20)
#define FIQ_MASK(base_addr) (base_addr + 0x24)
#define FIQ_CLEAR(base_addr) (base_addr + 0x28)
#define FIQ_TMODE(base_addr) (base_addr + 0x2C)
#define FIQ_LEVEL(base_addr) (base_addr + 0x30)
#define FIQ_STATUS(base_addr) (base_addr + 0x34)
geminiとwmtで関数を比較する。
  • gemini_ack_irq
  • gemini_mask_irq
  • gemini_unmask_irq
  • gemini_init_irq
  • wmt_ack_irq
  • wmt_mask_irq
  • wmt_unmask_irq
  • wmt_init_irq
  • wmt_irq_suspend
  • wmt_irq_resume
  • wmt_irq_init_devicefs
最初の四つは似たような関数名だ。suspend, resumeはPMのifdefで囲われているので、パワーマネジメント関係が必要になってきたら頑張ればよいとして、関数の有無レベルでの差分はwmt_irq_init_devicefsですかね。

関数の直後にdevice_initcall(wmt_irq_init_devicefs);という文があるのは初期化の際に呼ばれるもののよう。

関数の中身はデバイスクラスを登録する関数を読んでいるようだ。こいつもその直前の構造体を読むとsuspend,resumeはこの関数名ですよと言っているので、まぁ、最初は気にしなくてよいことにしよう。

ack_irqは先ほどのマクロIRQ_CLEARに1<< irqをraw_write1しているだけ。
mask_irqはIRQ_MASKを読んで~(1<<irq)のANDをとって再びIRQ_MASKに書いているだけ。

unmask_irqは|=(1<<irq)しているだけ。maskってintだから32bitとして、32個しか割り込みないのかな?

init_irqが初期化処理みたい。なんか、forループでNR_IRQSの数だけ回している。

geminiのヘッダを見ると
#define NORMAL_IRQ_NUM 32

#define GPIO_IRQ_BASE NORMAL_IRQ_NUM
#define GPIO_IRQ_NUM (3 * 32)
#define NR_IRQS (NORMAL_IRQ_NUM + GPIO_IRQ_NUM)
つうことは、割り込みの数は32じゃなくて32 + 32 * 3 で128あるってことか。
GPIOだけマクロが
#define IRQ_GPIO(x)    (22 + (x))
ってなっているのがポイント?  GPIOだけ特別扱いされているっぽい、って思っていればいいか。

ループの中では、set_irq_chip, set_irq_handler, set_irq_flagsを割り込みそれぞれに対して呼び出している模様。
handle_edge_irqの時だけはmode, levelのビットを立てている。

ループの後、すべての割り込みを禁止して、割り込みモードとして先のmode, levelをraw_writelで書き込んでいる。

geminiは割り込み32個をビットにして管理しているってことかな?

NetBSDのgemini_icu.cをみると、確かに割り込み32個あるようだ。sources[32]がそれだろう。

関数として、block, unblockというのがLinuxのmask, unmaskっぽいな。
Linuxのack_irqに相当するものはなさそう。

NetBSDの場合、find_pending_irqs, irq_handler,establish_irqがある。

find_pending_irqs, irq_handlerそれぞれ、最後はpic_から始まる関数を呼んでいる。attachでもadd_picなどとしている。こいつが共通的な何かをしてくれるものなのだろうか。

しかし、irq_handlerは何をしているのだろう、というか、pending処理以外、何もしていないような。ハンドリングしてくれるのかと思ったが...

establish_irqは、IRQの確立、つまり初期化処理なのだろう。UARTのattachで似たような関数を呼んでいた。つまり、何らかのデバイスドライバがこいつを呼ぶということであろうか。

Linuxは最初にループでIRQの初期化を回す。NetBSDはデバイスドライバが初期化されるごとに個々のIRQの初期化処理が走るということなのかもしれない。

WMTのLinuxコードを見ると、割り込みコントローラICDC0は次のようになっている。
#define    ICDC0_ADDR      (__IC_BASE + 0x40)      /* dest_ctl_addr[0]  */
__IC_BASEは
#ifdef __IC_BASE
#error  "__IC_BASE has already been defined in another file."
#endif
#ifdef INTERRUPT_CTRL_BASE_ADDR        /* From wmt_mmap.h  */
#define __IC_BASE       INTERRUPT0_CTRL_BASE_ADDR
#else
#define __IC_BASE       0xFE140000      /* 64K */
#endif
てなぐあい。割り込みコントローラのVAであろう。

ちなみにmmap.cでは
#define INTERRUPT0_CTRL_BASE_ADDR               (0xD8140000 + WMT_MMAP_OFFSET)  /* 64K  */
なのだ。いずれにせよVAのアドレスになっている。bus_space_mapはPAばかりだったけど...

それはともかく、irq.cではICDC0_VAL(irq) = val;という値の代入しかやっていない。

初期化(wmt_init_irq)では0を入れており、mask, unmaskではICDC_ENABLEを立てたり・クリアしたりしている。

ICDC_ENABLEは
#define    ICDC_ENABLE     BIT3                  /* Interrupt enable bit.*/
なのでBIT3を立てている・クリアしているだけである。

ICDC0_VAL(irq)を追っかけてみる。まずは、元の定義は
#define ICDC0_VAL(x)     (REG8_VAL(ICDC0_ADDR + ICDC_OFFSET_WMT(x)))
となり、マクロが絡み合っているので読み解こう。

まず、ICDC_OFFSET_WMT(irq)は次のように定義されている。
#define ICDC_OFFSET_WMT(x)  ((x) & ICDC_NUMMASK_WMT)
NUMMASKなどと言っているが、
#define ICDC_NUMMASK_WMT    0x7F           /* mask to avoid overflow */
ということでほぼxと思えばよい。つまり、ICDC0_VALマクロは
#define ICDC0_VAL(x)     (REG8_VAL(ICDC0_ADDR + x))
である。で、残ったREG8_VALは最終的にこうなる。hardware.hに定義がある。
# define __REG8P(x)     (((__regbase8 *)((x)&~4095))->offset[((x)&4095)>>0])
typedef struct {
    volatile u8 offset[4096];       /* 4K * 1 = SZ_4K */

} __regbase8;
つまり、ICDC0_ADDRを先頭に、割り込み番号ごとに8ビット割り当てられて64個ならんでいると。で、ENABLEのやつにはその8ビットの3ビット目に1が立っていると。

初期化ルーチンを読んでみる。

まず、ICDC0_ADDRを先頭とした8ビット単位で64個のテーブルを作り、0で初期化しているというわけか。

次に、おのおののIRQで使うルーチンをset_irq_chipで指定。すべて、
static struct irq_chip wmt_normal_chip = {
    .name   = "normal",
    .ack    = wmt_ack_irq,
    .mask   = wmt_mask_irq,
    .unmask = wmt_unmask_irq,
};
なので、自ファイル(irq.c)にある関数を呼び出すと。

次に、set_irq_handlerでデフォルトのハンドラhandle_level_irq(kernel/irq/chip.c)をセット。set_irq_flagにデフォルトのフラグをセットしている。
デフォルトのフラグは
#define IRQF_VALID    (1 << 0)
なので0x01ということか。

つうことで、結局、gemini, wmtともにirq.cにはMDの部分だけが書かれていたということですね。

geminiは32ビットのうち、IRQビット目を立てる、という方式だし、WMTは8ビットつまり1バイトを64個ならべて、IRQ個目の1バイトの3ビット目を立てたり、クリアしたり、という部分だけでした。

そこをNetBSDで実装してあげればいいんですね、たぶん。

APC8750にNetBSD/evbarmを移植するための記録 8/24
2014/01/13(月) 16:44 NetBSD はてブ情報 はてブに登録 はてブ数

8/24からは書き溜めたメモから順次投下していく。敬体から常体に書きぶりも変わってマス。

二台目は普通に動いてうれしい。

u-bootに毎回同じコマンドを入れるのが面倒くさい。ということで対策。

tftpbootはデフォルトファイル名をC0A80002.imgが設定されているので、netbsd.binにシンボリックリンクを張れば少しだけサボれる。

結局、ほかのドライバと比較するときわかりにくいのでobioをgeminiのobioっぽく書き換え。oba -> obioに変更するなど。ドライバ全体に波及。

シリアルドライバ、matchが1を返すという実装から、geminiのような初期化を加える。
さらに、attachはsc->sc_typeをCOM_TYPE_16650_NOERSに変更。当たり前だが、起動時のメッセージが変わった。で、attachの前後にデバッグ文を入れてみたら、uartのattachはなぜか二回呼ばれている。

ねんがんのシリアル「入力」はできない。

良く考えたら、割り込みコントローラって、コンパイルを通るようにしただけなので、動いているわけがない。

シリアルの入力は、割り込みによって入力処理に飛ばされるはずだから、割り込みコントローラの実装をやらないとダメって気が。当たり前か。consinitで表示ができるのも、わりと謎だが...
WMT # set serverip 192.168.0.10
WMT # tftpboot 8000
EEP-less strapping = TRUE
*** Warning: no boot file name; using 'C0A80002.img'
TFTP from server 192.168.0.10; our IP address is 192.168.0.2
Filename 'C0A80002.img'.
Load address: 0x8000
Loading: #################################################################
         #################################################################
         ######################################T ###########################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         ######################################
done
Bytes transferred = 2520256 (2674c0 hex)
WMT # go 8000
## Starting application at 0x00008000 ...
00008328
NetBSD
00000000 00000000 0048096b 00000412
00000000 00000412 00000004 00000412
c0000000 00000000 0048096b 0000041e
00003000 0000041e 00000004 0000041e
fe000000 d8000000 010fffff 00000412
00003f80 d8000412 00000010 00000412
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000



NetBSD/evbarm (APC) booting ...
[ Kernel symbol table missing! ]
Loaded initial symtab at 0xc01b4364, strtab at 0xc01d3494, # entries 7940
pmap_postinit: Allocated 35 static L1 descriptor tables
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 6.99.23 (APC) #28: Sat Aug 24 13:53:26 UTC 2013
        root@builder.localdomain:/usr/obj/sys/arch/evbarm/compile/APC
total memory = 512 MB
avail memory = 499 MB
mainbus0 (root)
cpu0 at mainbus0 core 0: ARM1176JZ-S r0p7 (ARM11J V6ZK core)
cpu0: DC enabled IC enabled WB enabled LABT
cpu0: 16KB/32B 4-way L1 Instruction cache
cpu0: 16KB/32B 4-way write-back-locking-C L1 Data cache
vfp0 at cpu0: VFP11
obio0 at mainbus0
<wm8750_uart_match>
comprobe1 0
</wm8750_uart_match rv=0>
wmicu0 at obio0 addr 0xd8140000-0xd814ffff
<wm8750_uart_match>
com0 at obio0 addr 0xd8200000-0xd820ffff intr 32  : ns16650, no ERS, working fifo
com0: console
wmtmr0 at obio0 addr 0xd8100000-0xd810ffff intr 48 : VC System Timer
rn_init: radix functions require max_keylen be set
boot device: <unknown>
root device:
<wm8750_uart_match>はデバッグ文である。むかしむかしJavaでこういう書き方したのでやってみたが、イマイチカッコ悪いな。

で、comprobe1でへくっとる。
根本的におかしいんじゃないのかなと思ってしまう。

geminiとか、consinitでbus_space_mapしてるんだよな。
やったほうがいいのかな。comcnattachだけでええんやろか?
よく考えたら、ここでもCOM_TYPE_NORMALってやってるけど、変えたほうがいいのか?

調べてみたら、COM_TYPE_NORMALじゃないやつって、COM_TYPE_PXA2x0を除けばgeminiのCOM_TYPE_16550_NOERSぐらいか。むしろgeminiが異端に見えるので真似しないほうがよいのかも...

やっぱり、シリアルコンソールの出力はマグレで表示されていると思ったほうがよさそうな気がしてきた。

APC8750にNetBSD/evbarmを移植するための記録 8/23
2014/01/12(日) 25:49 NetBSD はてブ情報 はてブに登録 はてブ数

二台目のAPCが手元に届きました。実は8/22に到着していたのですが、不在にて持ち帰りだったのです。

8/19に注文で8/22に到着とは、思いのほか早く手に入りました。