aboutsummaryrefslogtreecommitdiff
path: root/slof/fs/pci-scan.fs
diff options
context:
space:
mode:
Diffstat (limited to 'slof/fs/pci-scan.fs')
-rw-r--r--slof/fs/pci-scan.fs494
1 files changed, 494 insertions, 0 deletions
diff --git a/slof/fs/pci-scan.fs b/slof/fs/pci-scan.fs
new file mode 100644
index 0000000..e0cd813
--- /dev/null
+++ b/slof/fs/pci-scan.fs
@@ -0,0 +1,494 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2007 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
+\ ****************************************************************************/
+
+\ ----------------------------------------------------------
+\ ********** Variables to be set by host bridge **********
+\ ----------------------------------------------------------
+
+\ Values of the next free memory area
+VARIABLE pci-next-mem \ prefetchable memory mapped
+VARIABLE pci-max-mem
+VARIABLE pci-next-mmio \ non-prefetchable memory
+VARIABLE pci-max-mmio
+VARIABLE pci-next-io \ I/O space
+VARIABLE pci-max-io
+
+\ Counter of busses found
+0 VALUE pci-bus-number
+\ Counter of devices found
+0 VALUE pci-device-number
+\ bit field of devices plugged into this bridge
+0 VALUE pci-device-slots
+\ byte field holding the device-slot number vector of the current device
+\ the vector can be as deep as the max depth of bridges possible
+\ 3,4,5 means
+\ the 5th slot on the bus of the bridge in
+\ the 4th slot on the bus of the bridge in
+\ the 3rd slot on the HostBridge bus
+here 100 allot CONSTANT pci-device-vec
+0 VALUE pci-device-vec-len
+
+
+\ Fixme Glue to the pci-devices ... remove this later
+: next-pci-mem ( addr -- addr ) pci-next-mem ;
+: next-pci-mmio ( addr -- addr ) pci-next-mmio ;
+: next-pci-io ( addr -- addr ) pci-next-io ;
+
+\ ----------------------------------------------------------
+\ ****************** Helper functions ********************
+\ ----------------------------------------------------------
+
+\ convert an integer to string of len digits
+: int2str ( int len -- str len ) swap s>d rot <# 0 ?DO # LOOP #> ;
+
+\ convert addr to busnr
+: pci-addr2bus ( addr -- busnr ) 10 rshift FF and ;
+
+\ convert addr to devnr
+: pci-addr2dev ( addr -- dev ) B rshift 1F and ;
+
+\ convert addr to functionnumber
+: pci-addr2fn ( addr -- dev ) 8 rshift 7 and ;
+
+\ convert busnr devnr to addr
+: pci-bus2addr ( busnr devnr -- addr ) B lshift swap 10 lshift + ;
+
+\ print out a pci config addr
+: pci-addr-out ( addr -- ) dup pci-addr2bus 2 0.r space FFFF and 4 0.r ;
+
+\ Dump out the whole configspace
+: pci-dump ( addr -- )
+ 10 0 DO
+ dup
+ cr i 4 * +
+ dup pci-addr-out space
+ rtas-config-l@ 8 0.r
+ LOOP
+ drop cr
+;
+
+\ Dump out the pci device-slot vector
+: pci-vec ( -- )
+ cr s" device-vec(" type
+ pci-device-vec-len dup 2 0.r s" ):" type
+ 1+ 0 DO
+ pci-device-vec i + c@
+ space 2 0.r
+ LOOP
+ cr
+;
+
+\ prints out all relevant pci variables
+: var-out ( --)
+ s" mem:" type pci-next-mem @ 16 0.r cr
+ s" mmio:" type pci-next-mmio @ 16 0.r cr
+ s" io:" type pci-next-io @ 16 0.r cr
+;
+
+\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\ the following functions use l@ to fetch the data,
+\ that's because the pcie core on spider has some probs with w@ !!!
+\ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\ read Vendor ID
+: pci-vendor@ ( addr -- id ) rtas-config-l@ FFFF and ;
+\ read Device ID
+: pci-device@ ( addr -- id ) rtas-config-l@ 10 rshift ;
+\ read Status
+: pci-status@ ( addr -- status ) 4 + rtas-config-l@ 10 rshift ;
+\ read Revision ID
+: pci-revision@ ( addr -- id ) 8 + rtas-config-b@ ;
+\ read Class Code
+: pci-class@ ( addr -- class ) 8 + rtas-config-l@ 8 rshift ;
+\ read Cache Line Size
+: pci-cache@ ( addr -- size ) C + rtas-config-b@ ;
+\ read Header Type
+: pci-htype@ ( addr -- type ) E + rtas-config-b@ ;
+\ read Sub Vendor ID
+: pci-sub-vendor@ ( addr -- sub-id ) 2C + rtas-config-l@ FFFF and ;
+\ read Sub Device ID
+: pci-sub-device@ ( addr -- sub-id ) 2C + rtas-config-l@ 10 rshift FFFF and ;
+\ read Interrupt Line
+: pci-interrupt@ ( addr -- interrupt ) 3D + rtas-config-b@ ;
+\ read Minimum Grant
+: pci-min-grant@ ( addr -- min-gnt ) 3E + rtas-config-b@ ;
+\ read Maximum Latency
+: pci-max-lat@ ( addr -- max-lat ) 3F + rtas-config-b@ ;
+\ Check if Capabilities are valid
+: pci-capabilities? ( addr -- 0|1 ) pci-status@ 4 rshift 1 and ;
+\ fetch the offset of the next capability
+: pci-cap-next ( cap-addr -- next-cap-off ) rtas-config-b@ FC and ;
+\ calc the address of the next capability
+: pci-cap-next-addr ( cap-addr -- next-cap-addr ) 1+ dup pci-cap-next dup IF swap -100 and + ELSE nip THEN ;
+
+\ Dump out all capabilities
+: pci-cap-dump ( addr -- )
+ cr
+ dup pci-capabilities? IF
+ 33 + BEGIN
+ pci-cap-next-addr dup 0<>
+ WHILE
+ dup pci-addr-out s" : " type
+ dup rtas-config-b@ 2 0.r cr
+ REPEAT
+ s" end found "
+ ELSE
+ s" capabilities not enabled!"
+ THEN
+ type cr drop
+;
+
+\ search the capability-list for this id
+: pci-cap-find ( addr id -- capp-addr|0 )
+ swap dup pci-capabilities? IF
+ 33 + BEGIN
+ pci-cap-next-addr dup 0<> IF
+ dup rtas-config-b@ 2 pick =
+ ELSE
+ true
+ THEN
+ UNTIL
+ nip
+ ELSE
+ 2drop 0
+ THEN
+;
+
+\ check wether this device is a pci-express device
+: pci-express? ( addr -- 0|1 ) 10 pci-cap-find 0<> ;
+
+\ check wether this device is a pci-express device
+: pci-x? ( addr -- 0|1 ) 07 pci-cap-find 0<> ;
+
+\ check wether this device has extended config space
+: pci-config-ext? ( addr -- 0|1 ) pci-express? ;
+
+\ set and fetch the interrupt Pin
+: pci-irq-line@ ( addr -- irq-pin ) 3C + rtas-config-b@ ;
+: pci-irq-line! ( pin addr -- ) 3C + rtas-config-b! ;
+
+\ set and fetch primary bus number
+: pci-bus-prim! ( nr addr -- ) 18 + dup rtas-config-l@ FFFFFF00 and rot + swap rtas-config-l! ;
+: pci-bus-prim@ ( addr -- nr ) 18 + rtas-config-l@ FF and ;
+
+\ set and fetch secondary bus number
+: pci-bus-scnd! ( nr addr -- ) 18 + dup rtas-config-l@ FFFF00FF and rot 8 lshift + swap rtas-config-l! ;
+: pci-bus-scnd@ ( addr -- nr ) 18 + rtas-config-l@ 8 rshift FF and ;
+
+\ set and fetch subordinate bus number
+: pci-bus-subo! ( nr addr -- ) 18 + dup rtas-config-l@ FF00FFFF and rot 10 lshift + swap rtas-config-l! ;
+: pci-bus-subo@ ( addr -- nr ) 18 + rtas-config-l@ 10 rshift FF and ;
+
+\ set and fetch primary, secondary and subordinate bus number
+: pci-bus! ( subo scnd prim addr -- ) swap rot 8 lshift + rot 10 lshift + swap 18 + dup rtas-config-l@ FF000000 and rot + swap rtas-config-l! ;
+: pci-bus@ ( addr -- subo scnd prim ) 18 + rtas-config-l@ dup 10 rshift FF and swap dup 8 rshift FF and swap FF and ;
+
+\ Reset secondary Status
+: pci-reset-2nd ( addr -- ) 1C + dup rtas-config-l@ FFFF0000 or swap rtas-config-l! ;
+
+\ Disable Bus Master, Memory Space and I/O Space for this device
+: pci-device-disable ( -- ) my-space 4 + dup rtas-config-l@ 7 invert and swap rtas-config-l! ;
+
+\ Enable Bus Master
+: pci-master-enable ( -- ) my-space 4 + dup rtas-config-l@ 4 or swap rtas-config-l! ;
+
+\ Disable Bus Master
+: pci-master-disable ( -- ) my-space 4 + dup rtas-config-l@ 4 invert and swap rtas-config-l! ;
+
+\ Enable response to mem accesses of pci device
+: pci-mem-enable ( -- ) my-space 4 + dup rtas-config-w@ 2 or swap rtas-config-w! ;
+: enable-mem-access ( -- ) pci-mem-enable ;
+
+\ Enable response to I/O accesses of pci-device
+: pci-io-enable ( -- ) my-space 4 + dup rtas-config-w@ 1 or swap rtas-config-w! ;
+: enable-io-access ( -- ) pci-io-enable ;
+
+\ Enable Bus Master, I/O and mem access
+: pci-enable ( -- ) my-space 4 + dup rtas-config-w@ 7 or swap rtas-config-w! ;
+
+\ Enable #PERR and #SERR errors of pci-device
+: pci-error-enable ( -- ) my-space 4 + dup rtas-config-w@ 140 or swap rtas-config-w! ;
+
+\ prints out the ScanInformation about a device
+\ char is a sign for device type e.g. D - device ; B - bridge
+: pci-out ( addr char -- )
+ 15 spaces
+ over pci-addr-out
+ s" (" type emit s" ) : " type
+ dup pci-vendor@ 4 0.r space
+ pci-device@ 4 0.r
+ 4 spaces
+;
+
+\ Update the device-slot number vector
+\ Set the bit of the DeviceSlot in the Slot array
+: pci-set-slot ( addr -- )
+ pci-addr2dev dup \ calc slot number
+ pci-device-vec-len \ the end of the vector
+ pci-device-vec + c! \ and update the vector
+ 80000000 swap rshift \ calc bit position of the device slot
+ pci-device-slots or \ set this bit
+ TO pci-device-slots \ and write it back
+;
+
+\ Update pci-next-mmio to be 1MB aligned and set the mmio-base register
+\ and set the Limit register to the maximum available address space
+\ needed for scanning possible devices behind the bridge
+: pci-bridge-set-mmio-base ( addr -- )
+ pci-next-mmio @ 100000 #aligned \ read the current Value and align to 1MB boundary
+ dup pci-next-mmio ! \ and write it back
+ 10 rshift \ mmio-base reg is only the upper 16 bits
+ pci-max-mmio @ FFFF0000 and or \ and Insert mmio Limit (set it to max)
+ swap 20 + rtas-config-l! \ and write it into the bridge
+;
+
+\ Update pci-next-mmio to be 1MB aligned and set the mmio-limit register
+\ The Limit Value is one less then the upper boundary
+\ If the limit is less than the base the mmio is disabled
+: pci-bridge-set-mmio-limit ( addr -- )
+ pci-next-mmio @ 100000 #aligned \ fetch current value and align to 1MB
+ dup pci-next-mmio ! \ and write it back
+ 1- FFFF0000 and \ make it one less and keep upper 16 bits
+ over 20 + rtas-config-l@ 0000FFFF and \ fetch original value
+ or swap 20 + rtas-config-l! \ and write it into the Reg
+;
+
+\ Update pci-next-mem to be 1MB aligned and set the mem-base and mem-base-upper register
+\ and set the Limit register to the maximum available address space
+\ needed for scanning possible devices behind the bridge
+: pci-bridge-set-mem-base ( addr -- )
+ pci-next-mem @ 100000 #aligned \ read the current Value and align to 1MB boundary
+ dup pci-next-mem ! \ and write it back
+ over 24 + rtas-config-w@ \ check if 64bit support
+ 1 and IF \ IF 64 bit support
+ 2dup 20 rshift \ | keep upper 32 bits
+ swap 28 + rtas-config-l! \ | and write it into the Base-Upper32-bits
+ pci-max-mem @ 20 rshift \ | fetch max Limit address and keep upper 32 bits
+ 2 pick 2C + rtas-config-l! \ | and set the Limit
+ THEN \ FI
+ 10 rshift \ keep upper 16 bits
+ pci-max-mem @ FFFF0000 and or \ and Insert mmem Limit (set it to max)
+ swap 24 + rtas-config-l! \ and write it into the bridge
+;
+
+\ Update pci-next-mem to be 1MB aligned and set the mem-limit register
+\ The Limit Value is one less then the upper boundary
+\ If the limit is less than the base the mem is disabled
+: pci-bridge-set-mem-limit ( addr -- )
+ pci-next-mem @ 100000 #aligned \ read the current Value and align to 1MB boundary
+ dup pci-next-mem ! \ and write it back
+ 1- \ make limit one less than boundary
+ over 24 + rtas-config-w@ \ check if 64bit support
+ 1 and IF \ IF 64 bit support
+ 2dup 20 rshift \ | keep upper 32 bits
+ swap 2C + rtas-config-l! \ | and write it into the Limit-Upper32-bits
+ THEN \ FI
+ FFFF0000 and \ keep upper 16 bits
+ over 24 + rtas-config-l@ 0000FFFF and \ fetch original Value
+ or swap 24 + rtas-config-l! \ and write it into the bridge
+;
+
+\ Update pci-next-io to be 4KB aligned and set the io-base and io-base-upper register
+\ and set the Limit register to the maximum available address space
+\ needed for scanning possible devices behind the bridge
+: pci-bridge-set-io-base ( addr -- )
+ pci-next-io @ 1000 #aligned \ read the current Value and align to 4KB boundary
+ dup pci-next-io ! \ and write it back
+ over 1C + rtas-config-l@ \ check if 32bit support
+ 1 and IF \ IF 32 bit support
+ 2dup 10 rshift \ | keep upper 16 bits
+ pci-max-io @ FFFF0000 and or \ | insert upper 16 bits of Max-Limit
+ swap 30 + rtas-config-l! \ | and write it into the Base-Upper16-bits
+ THEN \ FI
+ 8 rshift 000000FF and \ keep upper 8 bits
+ pci-max-io @ 0000FF00 and or \ insert upper 8 bits of Max-Limit
+ over rtas-config-l@ FFFF0000 and \ fetch original Value
+ or swap 1C + rtas-config-l! \ and write it into the bridge
+;
+
+\ Update pci-next-io to be 4KB aligned and set the io-limit register
+\ The Limit Value is one less then the upper boundary
+\ If the limit is less than the base the io is disabled
+: pci-bridge-set-io-limit ( addr -- )
+ pci-next-io @ 1000 #aligned \ read the current Value and align to 4KB boundary
+ dup pci-next-io ! \ and write it back
+ 1- \ make limit one less than boundary
+ over 1D + rtas-config-b@ \ check if 32bit support
+ 1 and IF \ IF 32 bit support
+ 2dup FFFF0000 and \ | keep upper 16 bits
+ over 30 + rtas-config-l@ \ | fetch original Value
+ or swap 30 + rtas-config-l! \ | and write it into the Limit-Upper16-bits
+ THEN \ FI
+ 0000FF00 and \ keep upper 8 bits
+ over 1C + rtas-config-l@ FFFF00FF and \ fetch original Value
+ or swap 1C + rtas-config-l! \ and write it into the bridge
+;
+
+\ set up all base registers to the current variable Values
+: pci-bridge-set-bases ( addr -- )
+ dup pci-bridge-set-mmio-base
+ dup pci-bridge-set-mem-base
+ pci-bridge-set-io-base
+;
+
+\ set up all limit registers to the current variable Values
+: pci-bridge-set-limits ( addr -- )
+ dup pci-bridge-set-mmio-limit
+ dup pci-bridge-set-mem-limit
+ pci-bridge-set-io-limit
+;
+
+\ ----------------------------------------------------------
+\ ****************** PCI Scan functions ******************
+\ ----------------------------------------------------------
+
+\ define function pointer as forward declaration of pci-probe-bus
+DEFER func-pci-probe-bus
+
+\ Setup the Base and Limits in the Bridge
+\ and scan the bus(es) beyond that Bridge
+: pci-bridge-probe ( addr -- )
+ dup pci-bridge-set-bases \ SetUp all Base Registers
+ pci-bus-number 1+ TO pci-bus-number \ increase number of busses found
+ pci-device-vec-len 1+ TO pci-device-vec-len \ increase the device-slot vector depth
+ dup \ stack config-addr for pci-bus!
+ FF swap \ Subordinate Bus Number ( for now to max to open all subbusses )
+ pci-bus-number swap \ Secondary Bus Number ( the new busnumber )
+ dup pci-addr2bus swap \ Primary Bus Number ( the current bus )
+ pci-bus! \ and set them into the bridge
+ pci-enable \ enable mem/IO transactions
+ dup pci-bus-scnd@ func-pci-probe-bus \ and probe the secondary bus
+ dup pci-bus-number swap pci-bus-subo! \ set SubOrdinate Bus Number to current number of busses
+ pci-device-vec-len 1- TO pci-device-vec-len \ decrease the device-slot vector depth
+ dup pci-bridge-set-limits \ SetUp all Limit Registers
+ drop \ forget the config-addr
+;
+
+\ set up the pci-device
+: pci-device-setup ( addr -- )
+ drop \ since the config-addr is coded in my-space, drop it here
+ s" pci-device.fs" included \ and setup the device as node in the device tree
+;
+
+\ set up the pci bridge
+: pci-bridge-setup ( addr -- )
+ drop \ since the config-addr is coded in my-space, drop it here
+ s" pci-bridge.fs" included \ and setup the bridge as node in the device tree
+;
+
+\ add the new found device/bridge to the device tree and set it up
+: pci-add-device ( addr -- )
+ new-device \ create a new device-tree node
+ dup set-space \ set the config addr for this device tree entry
+ dup pci-set-slot \ set the slot bit
+ dup pci-htype@ \ read HEADER-Type
+ 1 and IF \ IF BRIDGE
+ pci-bridge-setup \ | set up the bridge
+ ELSE \ ELSE
+ pci-device-setup \ | set up the device
+ THEN \ FI
+ finish-device \ and close the device-tree node
+;
+
+\ check for multifunction and for each function
+\ (dependig from header type) call device or bridge setup
+: pci-setup-device ( addr -- )
+ dup pci-htype@ \ read HEADER-Type
+ 80 and IF 8 ELSE 1 THEN \ check for multifunction
+ 0 DO \ LOOP over all possible functions (either 8 or only 1)
+ dup
+ i 8 lshift + \ calc device-function-config-addr
+ dup pci-vendor@ \ check if valid function
+ FFFF = IF
+ drop \ non-valid so forget the address
+ ELSE
+ pci-device-number 1+ \ increase the number of devices
+ TO pci-device-number \ and store it
+ pci-add-device \ and add the device to the device tree and set it up
+ THEN
+ LOOP \ next function
+ drop \ forget the device-addr
+;
+
+\ check if a device is plugged into this bus at this device number
+: pci-probe-device ( busnr devicenr -- )
+ pci-bus2addr \ calc pci-address
+ dup pci-vendor@ \ fetch Vendor-ID
+ FFFF = IF \ check if valid
+ drop \ if not forget it
+ ELSE
+ pci-setup-device \ if valid setup the device
+ THEN
+;
+
+\ walk through all 32 possible pci devices on this bus and probe them
+: pci-probe-bus ( busnr -- )
+ 0 TO pci-device-slots \ reset slot array to unpoppulated
+ 20 0 DO
+ dup
+ i pci-probe-device
+ LOOP
+ drop
+;
+
+\ setup the function pointer used in pci-bridge-setup
+' pci-probe-bus TO func-pci-probe-bus
+
+\ ----------------------------------------------------------
+\ ****************** System functions ********************
+\ ----------------------------------------------------------
+\ Setup the whole system for pci devices
+\ start with the bus-min and try all busses
+\ until at least 1 device was found
+\ ( needed for HostBridges that don't start with Bus 0 )
+: pci-probe-all ( bus-max bus-min -- ) \ Check all busses from bus-min up to bus-max if needed
+ 0 TO pci-device-vec-len \ reset the device-slot vector
+ DO
+ i TO pci-bus-number \ set current Busnumber
+ 0 TO pci-device-number \ reset Device Number
+ pci-bus-number pci-probe-bus \ and probe this bus
+ pci-device-number 0 > IF LEAVE THEN \ if we found a device we're done
+ LOOP \ else next bus
+;
+
+\ probe the hostbridge that is specified in my-puid
+\ for the mmio mem and io addresses:
+\ base is the least available address
+\ max is the highest available address
+: probe-pci-host-bridge ( bus-max bus-min mmio-max mmio-base mem-max mem-base io-max io-base my-puid -- )
+ puid >r TO puid \ save puid and set the new
+ pci-next-io ! \ save the next io-base address
+ pci-max-io ! \ save the max io-space address
+ pci-next-mem ! \ save the next mem-base address
+ pci-max-mem ! \ save the max mem-space address
+ pci-next-mmio ! \ save the next mmio-base address
+ pci-max-mmio ! \ save the max mmio-space address
+
+ 0d emit ." Adapters on " puid 10 0.r cr \ print the puid we're looking at
+ ( bus-max bus-min ) pci-probe-all \ and walk the bus
+ pci-device-number 0= IF \ IF no devices found
+ 15 spaces \ | indent the output
+ ." None" cr \ | tell the world our result
+ THEN \ FI
+ r> TO puid \ restore puid
+;
+
+\ provide the device-alias definition words
+#include <pci-aliases.fs>
+
+\ provide all words for the interrupts settings
+#include <pci-interrupts.fs>
+
+\ provide all words for the pci capabilities init
+#include <pci-capabilities.fs>
+
+\ provide all words needed to generate the properties and/or assign BAR values
+#include "pci-properties.fs"