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
10 \ * IBM Corporation - initial implementation
11 \ ****************************************************************************/
13 \ PAPR PCI host bridge.
18 ." Populating " pwd cr
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
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?
43 s" reg" get-node get-property 0= IF
44 decode-64 to my-puid 2drop
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 ;
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 ;
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"
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
76 F NOT AND \ Clear indicator bits
78 phb-debug? IF ." map-in done: " .s cr THEN
81 : map-out ( virt size -- )
82 phb-debug? IF ." map-out called: " .s cr THEN
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
91 \ alloc-mem always returns aligned memory - double check just to be sure
93 ." Warning: dma-alloc got unaligned memory!" cr
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
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
109 0 VALUE bm-handle \ Bitmap allocator handle
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"
128 decode-int TO dma-window-liobn
129 decode-64 TO dma-window-base
130 decode-64 TO dma-window-size
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
142 : (clear-dma-window-vars) ( -- )
143 0 TO dma-window-liobn
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 +
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)
162 bm-handle my-size bm-alloc
165 ." Bitmap allocation Failed " dev-addr .
168 dev-addr to tmp-dev-addr
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 )
175 \ ." mapping " i . cr
176 dma-window-liobn \ liobn
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
184 my-virt FFF and dev-addr or
185 (clear-dma-window-vars)
188 : dma-map-out ( virt devaddr size -- )
189 phb-debug? IF cr ." dma-map-out called: " .s cr THEN
190 (init-dma-window-vars)
194 dev-addr fff not and to dev-addr
195 dev-addr to tmp-dev-addr
197 my-virt my-size ( virt size )
199 swap fff + fff not and \ Align end to next 4k boundary
200 swap fff not and ( v+s' virt' )
202 \ ." unmapping " i . cr
203 dma-window-liobn \ liobn
205 i \ Lowest bits not set => invalid TCE
207 hv-put-tce ABORT" H_PUT_TCE failed"
208 tmp-dev-addr 1000 + to tmp-dev-addr
210 bm-handle dev-addr my-size bm-free
211 (clear-dma-window-vars)
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?
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
238 \ Now get the "ranges" property
239 s" ranges" get-node get-property 0<> ABORT" ranges property not found"
240 ( prop-addr prop-len )
244 decode-int \ Decode phys.hi
245 3000000 AND \ Filter out address space in phys.hi
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
252 pci-next-io @ 10 + pci-next-io ! \ BARs must not be set to zero
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
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 !
270 ( prop-addr prop-len )
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
285 : phb-pci-walk-bridge ( -- )
286 phb-debug? IF ." Calling pci-walk-bridge " pwd cr THEN
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
291 dup \ Continue as long as there are children
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
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
307 \ Landing routing to probe the popuated device tree
308 : phb-pci-probe-bus ( busnr -- )
309 drop phb-pci-walk-bridge
312 \ Stub routine, as qemu has enumerated, we already have the device
314 : phb-pci-device-props ( addr -- )
315 dup pci-class-name device-name
316 dup pci-device-assigned-addresses-prop
320 \ Scan the child nodes of the pci root node to assign bars, fixup
323 puid >r \ Save old value of puid
324 my-puid TO puid \ Set current puid
326 1 TO pci-hotplug-enabled
327 s" qemu,phb-enumerated" get-node get-property 0<> IF
328 1 0 (probe-pci-host-bridge)
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.
335 r> TO puid \ Restore previous puid