Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-qemu / slof / pci-phb.fs
1 \ *****************************************************************************
2 \ * Copyright (c) 2004, 2011 IBM Corporation
3 \ * All rights reserved.
4 \ * This program and the accompanying materials
5 \ * are made available under the terms of the BSD License
6 \ * which accompanies this distribution, and is available at
7 \ * http://www.opensource.org/licenses/bsd-license.php
8 \ *
9 \ * Contributors:
10 \ *     IBM Corporation - initial implementation
11 \ ****************************************************************************/
12
13 \ PAPR PCI host bridge.
14
15 0 VALUE phb-debug?
16
17
18 ." Populating " pwd cr
19
20 \ needed to find the right path in the device tree
21 : decode-unit ( addr len -- phys.lo ... phys.hi )
22    2 hex-decode-unit       \ decode string
23    b lshift swap           \ shift the devicenumber to the right spot
24    8 lshift or             \ add the functionnumber
25    \ my-bus 10 lshift or   \ add the busnumber (assume always bus 0)
26    0 0 rot                 \ make phys.lo = 0 = phys.mid
27 ;
28
29 \ needed to have the right unit address in the device tree listing
30 \ phys.lo=phys.mid=0 , phys.hi=config-address
31 : encode-unit ( phys.lo phys-mid phys.hi -- unit-str unit-len )
32    nip nip                     \ forget the phys.lo and phys.mid
33    dup 8 rshift 7 and swap     \ calculate function number
34    B rshift 1F and             \ calculate device number
35    over IF 2 ELSE nip 1 THEN   \ create string with dev#,fn# or dev# only?
36    hex-encode-unit
37 ;
38
39
40 0 VALUE my-puid
41
42 : setup-puid
43   s" reg" get-node get-property 0= IF
44     decode-64 to my-puid 2drop
45   THEN
46 ;
47
48 setup-puid
49
50 : config-b@  puid >r my-puid TO puid rtas-config-b@ r> TO puid ;
51 : config-w@  puid >r my-puid TO puid rtas-config-w@ r> TO puid ;
52 : config-l@  puid >r my-puid TO puid rtas-config-l@ r> TO puid ;
53
54 \ define the config writes
55 : config-b!  puid >r my-puid TO puid rtas-config-b! r> TO puid ;
56 : config-w!  puid >r my-puid TO puid rtas-config-w! r> TO puid ;
57 : config-l!  puid >r my-puid TO puid rtas-config-l! r> TO puid ;
58
59
60 : map-in ( phys.lo phys.mid phys.hi size -- virt )
61    phb-debug? IF cr ." map-in called: " .s cr THEN
62    \ Ignore the size, phys.lo and phys.mid, get BAR from config space
63    drop nip nip                         ( phys.hi )
64    \ Sanity check whether config address is in expected range:
65    dup FF AND dup 10 28 WITHIN NOT swap 30 <> AND IF
66       cr ." phys.hi = " . cr
67       ABORT" map-in with illegal config space address"
68    THEN
69    00FFFFFF AND                         \ Need only bus-dev-fn+register bits
70    dup config-l@                        ( phys.hi' bar.lo )
71    dup 7 AND 4 = IF                     \ Is it a 64-bit BAR?
72       swap 4 + config-l@ lxjoin         \ Add upper part of 64-bit BAR
73    ELSE
74       nip
75    THEN
76    F NOT AND                            \ Clear indicator bits
77    translate-my-address
78    phb-debug? IF ." map-in done: " .s cr THEN
79 ;
80
81 : map-out ( virt size -- )
82    phb-debug? IF ." map-out called: " .s cr THEN
83    2drop 
84 ;
85
86
87 : dma-alloc ( size -- virt )
88    phb-debug? IF cr ." dma-alloc called: " .s cr THEN
89    fff + fff not and                  \ Align size to next 4k boundary
90    alloc-mem
91    \ alloc-mem always returns aligned memory - double check just to be sure
92    dup fff and IF
93       ." Warning: dma-alloc got unaligned memory!" cr
94    THEN
95 ;
96
97 : dma-free ( virt size -- )
98    phb-debug? IF cr ." dma-free called: " .s cr THEN
99    fff + fff not and                  \ Align size to next 4k boundary
100    free-mem
101 ;
102
103
104 \ Helper variables for dma-map-in and dma-map-out
105 0 VALUE dma-window-liobn        \ Logical I/O bus number
106 0 VALUE dma-window-base         \ Start address of window
107 0 VALUE dma-window-size         \ Size of the window
108
109 0 VALUE bm-handle               \ Bitmap allocator handle
110 0 VALUE my-virt
111 0 VALUE my-size
112 0 VALUE dev-addr
113 0 VALUE tmp-dev-addr
114
115 \ Read helper variables (LIOBN, DMA window base and size) from the
116 \ "ibm,dma-window" property. This property can be either located
117 \ in the PCI device node or in the bus node, so we've got to use the
118 \ "calling-child" variable here to get to the node that initiated the call.
119 \ XXX We should search all the way up the tree to the PHB ...
120 : (init-dma-window-vars)  ( -- )
121 \   ." Foo called in " pwd cr
122 \   ." calling child is " calling-child .node cr
123 \   ." parent is " calling-child parent .node cr
124    s" ibm,dma-window" calling-child get-property IF
125        s" ibm,dma-window" calling-child parent get-property 
126        ABORT" no dma-window property available"
127    THEN
128    decode-int TO dma-window-liobn
129    decode-64 TO dma-window-base
130    decode-64 TO dma-window-size
131    2drop
132    bm-handle 0= IF
133        dma-window-base dma-window-size 1000 bm-allocator-init to bm-handle
134        \ Sometimes the window-base appears as zero, that does not
135        \ go well with NULL pointers. So block this address
136        dma-window-base 0= IF
137           bm-handle 1000 bm-alloc drop
138        THEN
139    THEN
140 ;
141
142 : (clear-dma-window-vars)  ( -- )
143     0 TO dma-window-liobn
144     0 TO dma-window-base
145     0 TO dma-window-size
146 ;
147
148 \ We assume that firmware never maps more than the whole dma-window-size
149 \ so we cheat by calculating the remainder of addr/windowsize instead
150 \ of taking care to maintain a list of assigned device addresses
151 : dma-virt2dev  ( virt -- devaddr )
152    dma-window-size mod dma-window-base +
153 ;
154
155 : dma-map-in  ( virt size cachable? -- devaddr )
156    phb-debug? IF cr ." dma-map-in called: " .s cr THEN
157    (init-dma-window-vars)
158    drop                               ( virt size )
159
160    to my-size
161    to my-virt
162    bm-handle my-size bm-alloc
163    to dev-addr
164    dev-addr 0 < IF
165        ." Bitmap allocation Failed " dev-addr .
166        FALSE EXIT
167    THEN
168    dev-addr to tmp-dev-addr
169
170    my-virt my-size
171    bounds dup >r                      ( v+s virt  R: virt )
172    swap fff + fff not and             \ Align end to next 4k boundary
173    swap fff not and                   ( v+s' virt'  R: virt )
174    ?DO
175        \ ." mapping " i . cr
176        dma-window-liobn                \ liobn
177        tmp-dev-addr                    \ ioba
178        i 3 OR                          \ Make a read- & writeable TCE
179        ( liobn ioba tce  R: virt )
180        hv-put-tce ABORT" H_PUT_TCE failed"
181        tmp-dev-addr 1000 + to tmp-dev-addr
182    1000 +LOOP
183    r> drop
184    my-virt FFF and dev-addr or
185    (clear-dma-window-vars)
186 ;
187
188 : dma-map-out  ( virt devaddr size -- )
189    phb-debug? IF cr ." dma-map-out called: " .s cr THEN
190    (init-dma-window-vars)
191    to my-size
192    to dev-addr
193    to my-virt
194    dev-addr fff not and to dev-addr
195    dev-addr to tmp-dev-addr
196
197    my-virt my-size                    ( virt size )
198    bounds                             ( v+s virt )
199    swap fff + fff not and             \ Align end to next 4k boundary
200    swap fff not and                   ( v+s' virt' )
201    ?DO
202        \ ." unmapping " i . cr
203        dma-window-liobn                \ liobn
204        tmp-dev-addr                    \ ioba
205        i                               \ Lowest bits not set => invalid TCE
206        ( liobn ioba tce )
207        hv-put-tce ABORT" H_PUT_TCE failed"
208        tmp-dev-addr 1000 + to tmp-dev-addr
209    1000 +LOOP
210    bm-handle dev-addr my-size bm-free
211    (clear-dma-window-vars)
212 ;
213
214 : dma-sync  ( virt devaddr size -- )
215    phb-debug? IF cr ." dma-sync called: " .s cr THEN
216    \ TODO: Call flush-cache or sync here?
217    3drop
218 ;
219
220
221 : open  true ;
222 : close ;
223
224 \ Parse the "ranges" property of the root pci node to decode the available
225 \ memory ranges. See "PCI Bus Binding to IEEE Std 1275-1994" for details.
226 \ The memory ranges are then used for setting up the device bars (if necessary)
227 : phb-parse-ranges ( -- )
228    \ First clear everything, in case there is something missing in the ranges
229    0  pci-next-io !
230    0  pci-max-io !
231    0  pci-next-mem !
232    0  pci-max-mem !
233    0  pci-next-mmio !
234    0  pci-max-mmio !
235    0  pci-next-mem64 !
236    0  pci-max-mem64 !
237
238    \ Now get the "ranges" property
239    s" ranges" get-node get-property 0<> ABORT" ranges property not found"
240    ( prop-addr prop-len )
241    BEGIN
242       dup
243    WHILE
244       decode-int                      \ Decode phys.hi
245       3000000 AND                     \ Filter out address space in phys.hi
246       CASE
247          1000000 OF                             \ I/O space?
248             decode-64 dup >r pci-next-io !      \ Decode PCI base address
249             decode-64 drop                      \ Forget the parent address
250             decode-64 r> + pci-max-io !         \ Decode size & calc max address
251             pci-next-io @ 0= IF
252                pci-next-io @ 10 + pci-next-io ! \ BARs must not be set to zero
253             THEN
254          ENDOF
255          2000000 OF                             \ 32-bit memory space?
256             decode-64 pci-next-mem !            \ Decode mem base address
257             decode-64 drop                      \ Forget the parent address
258             decode-64 2 / dup >r                \ Decode and calc size/2
259             pci-next-mem @ + dup pci-max-mem !  \ and calc max mem address
260             dup pci-next-mmio !                 \ which is the same as MMIO base
261             r> + pci-max-mmio !                 \ calc max MMIO address
262          ENDOF
263          3000000 OF                             \ 64-bit memory space?
264             decode-64 pci-next-mem64 !
265             decode-64 drop                      \ Forget the parent address
266             decode-64 pci-max-mem64 !
267          ENDOF
268       ENDCASE
269    REPEAT
270    ( prop-addr prop-len )
271    2drop
272
273    phb-debug? IF
274      ." pci-next-io   = " pci-next-io @ . cr
275      ." pci-max-io    = " pci-max-io  @ . cr
276      ." pci-next-mem  = " pci-next-mem @ . cr
277      ." pci-max-mem   = " pci-max-mem  @ . cr
278      ." pci-next-mmio = " pci-next-mmio @ . cr
279      ." pci-max-mmio  = " pci-max-mmio @ . cr
280      ." pci-next-mem64  = " pci-next-mem64 @ . cr
281      ." pci-max-mem64   = " pci-max-mem64  @ . cr
282    THEN
283 ;
284
285 : phb-pci-walk-bridge ( -- )
286     phb-debug? IF ."   Calling pci-walk-bridge " pwd cr THEN
287
288     get-node child ?dup 0= IF EXIT THEN    \ get and check if we have children
289     0 to pci-device-slots                  \ reset slot array to unpoppulated
290     BEGIN
291         dup                                \ Continue as long as there are children
292     WHILE
293         dup set-node                       \ Set child node as current node
294         my-space pci-set-slot              \ set the slot bit
295         my-space pci-htype@                \ read HEADER-Type
296         7f and                             \ Mask bit 7 - multifunction device
297         CASE
298             0 OF my-space pci-device-setup ENDOF  \ | set up the device
299             1 OF my-space pci-bridge-setup ENDOF  \ | set up the bridge
300             dup OF my-space pci-htype@ pci-out ENDOF
301         ENDCASE
302         peer
303     REPEAT drop
304     get-parent set-node
305 ;
306
307 \ Landing routing to probe the popuated device tree
308 : phb-pci-probe-bus ( busnr -- )
309     drop phb-pci-walk-bridge
310 ;
311
312 \ Stub routine, as qemu has enumerated, we already have the device
313 \ properties set.
314 : phb-pci-device-props ( addr -- )
315     dup pci-class-name device-name
316     dup pci-device-assigned-addresses-prop
317     drop
318 ;
319
320 \ Scan the child nodes of the pci root node to assign bars, fixup
321 \ properties etc.
322 : phb-setup-children
323    puid >r                          \ Save old value of puid
324    my-puid TO puid                  \ Set current puid
325    phb-parse-ranges
326    1 TO pci-hotplug-enabled
327    s" qemu,phb-enumerated" get-node get-property 0<> IF
328        1 0 (probe-pci-host-bridge)
329    ELSE
330        2drop
331        ['] phb-pci-probe-bus TO func-pci-probe-bus
332        ['] phb-pci-device-props TO func-pci-device-props
333        phb-pci-walk-bridge          \ PHB device tree is already populated.
334    THEN
335    r> TO puid                       \ Restore previous puid
336 ;
337 phb-setup-children