Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-qemu / slof / pci-phb.fs
diff --git a/qemu/roms/SLOF/board-qemu/slof/pci-phb.fs b/qemu/roms/SLOF/board-qemu/slof/pci-phb.fs
new file mode 100644 (file)
index 0000000..a8fb7ca
--- /dev/null
@@ -0,0 +1,337 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2011 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ PAPR PCI host bridge.
+
+0 VALUE phb-debug?
+
+
+." Populating " pwd cr
+
+\ needed to find the right path in the device tree
+: decode-unit ( addr len -- phys.lo ... phys.hi )
+   2 hex-decode-unit       \ decode string
+   b lshift swap           \ shift the devicenumber to the right spot
+   8 lshift or             \ add the functionnumber
+   \ my-bus 10 lshift or   \ add the busnumber (assume always bus 0)
+   0 0 rot                 \ make phys.lo = 0 = phys.mid
+;
+
+\ needed to have the right unit address in the device tree listing
+\ phys.lo=phys.mid=0 , phys.hi=config-address
+: encode-unit ( phys.lo phys-mid phys.hi -- unit-str unit-len )
+   nip nip                     \ forget the phys.lo and phys.mid
+   dup 8 rshift 7 and swap     \ calculate function number
+   B rshift 1F and             \ calculate device number
+   over IF 2 ELSE nip 1 THEN   \ create string with dev#,fn# or dev# only?
+   hex-encode-unit
+;
+
+
+0 VALUE my-puid
+
+: setup-puid
+  s" reg" get-node get-property 0= IF
+    decode-64 to my-puid 2drop
+  THEN
+;
+
+setup-puid
+
+: config-b@  puid >r my-puid TO puid rtas-config-b@ r> TO puid ;
+: config-w@  puid >r my-puid TO puid rtas-config-w@ r> TO puid ;
+: config-l@  puid >r my-puid TO puid rtas-config-l@ r> TO puid ;
+
+\ define the config writes
+: config-b!  puid >r my-puid TO puid rtas-config-b! r> TO puid ;
+: config-w!  puid >r my-puid TO puid rtas-config-w! r> TO puid ;
+: config-l!  puid >r my-puid TO puid rtas-config-l! r> TO puid ;
+
+
+: map-in ( phys.lo phys.mid phys.hi size -- virt )
+   phb-debug? IF cr ." map-in called: " .s cr THEN
+   \ Ignore the size, phys.lo and phys.mid, get BAR from config space
+   drop nip nip                         ( phys.hi )
+   \ Sanity check whether config address is in expected range:
+   dup FF AND dup 10 28 WITHIN NOT swap 30 <> AND IF
+      cr ." phys.hi = " . cr
+      ABORT" map-in with illegal config space address"
+   THEN
+   00FFFFFF AND                         \ Need only bus-dev-fn+register bits
+   dup config-l@                        ( phys.hi' bar.lo )
+   dup 7 AND 4 = IF                     \ Is it a 64-bit BAR?
+      swap 4 + config-l@ lxjoin         \ Add upper part of 64-bit BAR
+   ELSE
+      nip
+   THEN
+   F NOT AND                            \ Clear indicator bits
+   translate-my-address
+   phb-debug? IF ." map-in done: " .s cr THEN
+;
+
+: map-out ( virt size -- )
+   phb-debug? IF ." map-out called: " .s cr THEN
+   2drop 
+;
+
+
+: dma-alloc ( size -- virt )
+   phb-debug? IF cr ." dma-alloc called: " .s cr THEN
+   fff + fff not and                  \ Align size to next 4k boundary
+   alloc-mem
+   \ alloc-mem always returns aligned memory - double check just to be sure
+   dup fff and IF
+      ." Warning: dma-alloc got unaligned memory!" cr
+   THEN
+;
+
+: dma-free ( virt size -- )
+   phb-debug? IF cr ." dma-free called: " .s cr THEN
+   fff + fff not and                  \ Align size to next 4k boundary
+   free-mem
+;
+
+
+\ Helper variables for dma-map-in and dma-map-out
+0 VALUE dma-window-liobn        \ Logical I/O bus number
+0 VALUE dma-window-base         \ Start address of window
+0 VALUE dma-window-size         \ Size of the window
+
+0 VALUE bm-handle               \ Bitmap allocator handle
+0 VALUE my-virt
+0 VALUE my-size
+0 VALUE dev-addr
+0 VALUE tmp-dev-addr
+
+\ Read helper variables (LIOBN, DMA window base and size) from the
+\ "ibm,dma-window" property. This property can be either located
+\ in the PCI device node or in the bus node, so we've got to use the
+\ "calling-child" variable here to get to the node that initiated the call.
+\ XXX We should search all the way up the tree to the PHB ...
+: (init-dma-window-vars)  ( -- )
+\   ." Foo called in " pwd cr
+\   ." calling child is " calling-child .node cr
+\   ." parent is " calling-child parent .node cr
+   s" ibm,dma-window" calling-child get-property IF
+       s" ibm,dma-window" calling-child parent get-property 
+       ABORT" no dma-window property available"
+   THEN
+   decode-int TO dma-window-liobn
+   decode-64 TO dma-window-base
+   decode-64 TO dma-window-size
+   2drop
+   bm-handle 0= IF
+       dma-window-base dma-window-size 1000 bm-allocator-init to bm-handle
+       \ Sometimes the window-base appears as zero, that does not
+       \ go well with NULL pointers. So block this address
+       dma-window-base 0= IF
+          bm-handle 1000 bm-alloc drop
+       THEN
+   THEN
+;
+
+: (clear-dma-window-vars)  ( -- )
+    0 TO dma-window-liobn
+    0 TO dma-window-base
+    0 TO dma-window-size
+;
+
+\ We assume that firmware never maps more than the whole dma-window-size
+\ so we cheat by calculating the remainder of addr/windowsize instead
+\ of taking care to maintain a list of assigned device addresses
+: dma-virt2dev  ( virt -- devaddr )
+   dma-window-size mod dma-window-base +
+;
+
+: dma-map-in  ( virt size cachable? -- devaddr )
+   phb-debug? IF cr ." dma-map-in called: " .s cr THEN
+   (init-dma-window-vars)
+   drop                               ( virt size )
+
+   to my-size
+   to my-virt
+   bm-handle my-size bm-alloc
+   to dev-addr
+   dev-addr 0 < IF
+       ." Bitmap allocation Failed " dev-addr .
+       FALSE EXIT
+   THEN
+   dev-addr to tmp-dev-addr
+
+   my-virt my-size
+   bounds dup >r                      ( v+s virt  R: virt )
+   swap fff + fff not and             \ Align end to next 4k boundary
+   swap fff not and                   ( v+s' virt'  R: virt )
+   ?DO
+       \ ." mapping " i . cr
+       dma-window-liobn                \ liobn
+       tmp-dev-addr                    \ ioba
+       i 3 OR                          \ Make a read- & writeable TCE
+       ( liobn ioba tce  R: virt )
+       hv-put-tce ABORT" H_PUT_TCE failed"
+       tmp-dev-addr 1000 + to tmp-dev-addr
+   1000 +LOOP
+   r> drop
+   my-virt FFF and dev-addr or
+   (clear-dma-window-vars)
+;
+
+: dma-map-out  ( virt devaddr size -- )
+   phb-debug? IF cr ." dma-map-out called: " .s cr THEN
+   (init-dma-window-vars)
+   to my-size
+   to dev-addr
+   to my-virt
+   dev-addr fff not and to dev-addr
+   dev-addr to tmp-dev-addr
+
+   my-virt my-size                    ( virt size )
+   bounds                             ( v+s virt )
+   swap fff + fff not and             \ Align end to next 4k boundary
+   swap fff not and                   ( v+s' virt' )
+   ?DO
+       \ ." unmapping " i . cr
+       dma-window-liobn                \ liobn
+       tmp-dev-addr                    \ ioba
+       i                               \ Lowest bits not set => invalid TCE
+       ( liobn ioba tce )
+       hv-put-tce ABORT" H_PUT_TCE failed"
+       tmp-dev-addr 1000 + to tmp-dev-addr
+   1000 +LOOP
+   bm-handle dev-addr my-size bm-free
+   (clear-dma-window-vars)
+;
+
+: dma-sync  ( virt devaddr size -- )
+   phb-debug? IF cr ." dma-sync called: " .s cr THEN
+   \ TODO: Call flush-cache or sync here?
+   3drop
+;
+
+
+: open  true ;
+: close ;
+
+\ Parse the "ranges" property of the root pci node to decode the available
+\ memory ranges. See "PCI Bus Binding to IEEE Std 1275-1994" for details.
+\ The memory ranges are then used for setting up the device bars (if necessary)
+: phb-parse-ranges ( -- )
+   \ First clear everything, in case there is something missing in the ranges
+   0  pci-next-io !
+   0  pci-max-io !
+   0  pci-next-mem !
+   0  pci-max-mem !
+   0  pci-next-mmio !
+   0  pci-max-mmio !
+   0  pci-next-mem64 !
+   0  pci-max-mem64 !
+
+   \ Now get the "ranges" property
+   s" ranges" get-node get-property 0<> ABORT" ranges property not found"
+   ( prop-addr prop-len )
+   BEGIN
+      dup
+   WHILE
+      decode-int                      \ Decode phys.hi
+      3000000 AND                     \ Filter out address space in phys.hi
+      CASE
+         1000000 OF                             \ I/O space?
+            decode-64 dup >r pci-next-io !      \ Decode PCI base address
+            decode-64 drop                      \ Forget the parent address
+            decode-64 r> + pci-max-io !         \ Decode size & calc max address
+            pci-next-io @ 0= IF
+               pci-next-io @ 10 + pci-next-io ! \ BARs must not be set to zero
+            THEN
+         ENDOF
+         2000000 OF                             \ 32-bit memory space?
+            decode-64 pci-next-mem !            \ Decode mem base address
+            decode-64 drop                      \ Forget the parent address
+            decode-64 2 / dup >r                \ Decode and calc size/2
+            pci-next-mem @ + dup pci-max-mem !  \ and calc max mem address
+            dup pci-next-mmio !                 \ which is the same as MMIO base
+            r> + pci-max-mmio !                 \ calc max MMIO address
+         ENDOF
+         3000000 OF                             \ 64-bit memory space?
+           decode-64 pci-next-mem64 !
+           decode-64 drop                      \ Forget the parent address
+           decode-64 pci-max-mem64 !
+         ENDOF
+      ENDCASE
+   REPEAT
+   ( prop-addr prop-len )
+   2drop
+
+   phb-debug? IF
+     ." pci-next-io   = " pci-next-io @ . cr
+     ." pci-max-io    = " pci-max-io  @ . cr
+     ." pci-next-mem  = " pci-next-mem @ . cr
+     ." pci-max-mem   = " pci-max-mem  @ . cr
+     ." pci-next-mmio = " pci-next-mmio @ . cr
+     ." pci-max-mmio  = " pci-max-mmio @ . cr
+     ." pci-next-mem64  = " pci-next-mem64 @ . cr
+     ." pci-max-mem64   = " pci-max-mem64  @ . cr
+   THEN
+;
+
+: phb-pci-walk-bridge ( -- )
+    phb-debug? IF ."   Calling pci-walk-bridge " pwd cr THEN
+
+    get-node child ?dup 0= IF EXIT THEN    \ get and check if we have children
+    0 to pci-device-slots                  \ reset slot array to unpoppulated
+    BEGIN
+        dup                                \ Continue as long as there are children
+    WHILE
+        dup set-node                       \ Set child node as current node
+        my-space pci-set-slot              \ set the slot bit
+        my-space pci-htype@                \ read HEADER-Type
+        7f and                             \ Mask bit 7 - multifunction device
+        CASE
+            0 OF my-space pci-device-setup ENDOF  \ | set up the device
+            1 OF my-space pci-bridge-setup ENDOF  \ | set up the bridge
+            dup OF my-space pci-htype@ pci-out ENDOF
+        ENDCASE
+        peer
+    REPEAT drop
+    get-parent set-node
+;
+
+\ Landing routing to probe the popuated device tree
+: phb-pci-probe-bus ( busnr -- )
+    drop phb-pci-walk-bridge
+;
+
+\ Stub routine, as qemu has enumerated, we already have the device
+\ properties set.
+: phb-pci-device-props ( addr -- )
+    dup pci-class-name device-name
+    dup pci-device-assigned-addresses-prop
+    drop
+;
+
+\ Scan the child nodes of the pci root node to assign bars, fixup
+\ properties etc.
+: phb-setup-children
+   puid >r                          \ Save old value of puid
+   my-puid TO puid                  \ Set current puid
+   phb-parse-ranges
+   1 TO pci-hotplug-enabled
+   s" qemu,phb-enumerated" get-node get-property 0<> IF
+       1 0 (probe-pci-host-bridge)
+   ELSE
+       2drop
+       ['] phb-pci-probe-bus TO func-pci-probe-bus
+       ['] phb-pci-device-props TO func-pci-device-props
+       phb-pci-walk-bridge          \ PHB device tree is already populated.
+   THEN
+   r> TO puid                       \ Restore previous puid
+;
+phb-setup-children