366 lines
17 KiB
Forth
366 lines
17 KiB
Forth
\ *****************************************************************************
|
|
\ * Copyright (c) 2004, 2008 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
|
|
VARIABLE pci-next-mem64 \ prefetchable 64-bit memory mapped
|
|
VARIABLE pci-max-mem64
|
|
|
|
\ 0 to default to natural alignment
|
|
0 VALUE pci-mem-bar-min-align
|
|
|
|
\ 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
|
|
\ enable/disable creation of hotplug-specific properties
|
|
0 VALUE pci-hotplug-enabled
|
|
|
|
#include "pci-helper.fs"
|
|
|
|
\ 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
|
|
: pci-var-out ( -- )
|
|
." pci-next-io = " pci-next-io @ 10 0.r cr
|
|
." pci-max-io = " pci-max-io @ 10 0.r cr
|
|
." pci-next-mem = " pci-next-mem @ 10 0.r cr
|
|
." pci-max-mem = " pci-max-mem @ 10 0.r cr
|
|
." pci-next-mmio = " pci-next-mmio @ 10 0.r cr
|
|
." pci-max-mmio = " pci-max-mmio @ 10 0.r cr
|
|
." pci-next-mem64 = " pci-next-mem64 @ 10 0.r cr
|
|
." pci-max-mem64 = " pci-max-mem64 @ 10 0.r cr
|
|
;
|
|
|
|
|
|
\ 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 @ 1- 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 + \ add space for hot-plugging
|
|
100000 #aligned \ align to 1MB boundary
|
|
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 (or mem64) to be aligned and set the mem-base and
|
|
\ mem-base-upper register. Also set the Limit register to the maximum available
|
|
\ address space needed for scanning possible devices behind the bridge
|
|
: pci-bridge-set-mem-base ( addr -- )
|
|
dup 24 + rtas-config-w@ 1 and \ does bridge support 64-bit?
|
|
pci-next-mem64 @ 0<> and IF \ and do we have 64-bit memory?
|
|
\ Align variable to 4GB boundary
|
|
pci-next-mem64 @ 100000000 #aligned
|
|
dup pci-next-mem64 x!
|
|
\ Set base and limit registers:
|
|
20 rshift over 28 + rtas-config-l! \ set prefetch base upper 32 bits
|
|
pci-next-mem64 @ 10 rshift FFF0 and
|
|
pci-max-mem64 @ 1- FFF00000 and or
|
|
over 24 + rtas-config-l! \ set prefetch limit & base lower
|
|
pci-max-mem64 @ 1- 20 rshift
|
|
swap 2C + rtas-config-l! \ and set the limit upper 32 bits
|
|
ELSE
|
|
\ Align variable to 1MB boundary
|
|
pci-next-mem @ 100000 #aligned
|
|
dup pci-next-mem !
|
|
\ Set base and limit register:
|
|
10 rshift FFF0 and
|
|
pci-max-mem @ 1- FFF00000 and or
|
|
swap 24 + rtas-config-l!
|
|
THEN
|
|
;
|
|
|
|
\ Update pci-next-mem (or -mem64) to be aligned (with some additional space
|
|
\ for hot-plugging later) and set the mem-limit register. The Limit Value is
|
|
\ one less then the upper boundary.
|
|
: pci-bridge-set-mem-limit ( addr -- )
|
|
dup 24 + rtas-config-w@ 1 and \ does bridge support 64-bit?
|
|
pci-next-mem64 @ 0<> and IF \ and do we have 64-bit memory?
|
|
\ Update current variable (add space for hot-plugging and align it)
|
|
pci-next-mem64 @ 80000000 +
|
|
100000000 #aligned
|
|
dup pci-next-mem64 x!
|
|
\ Update the limit registers:
|
|
1- 20 rshift
|
|
over 2C + rtas-config-l! \ set the limit upper 32 bits
|
|
pci-next-mem64 @ 1- 10 rshift
|
|
swap 26 + rtas-config-w! \ set limit lower bits
|
|
ELSE
|
|
\ Update current variable (add space for hot-plugging and align it)
|
|
pci-next-mem @ 100000 +
|
|
100000 #aligned
|
|
dup pci-next-mem !
|
|
1- 10 rshift
|
|
swap 26 + rtas-config-w!
|
|
THEN
|
|
;
|
|
|
|
\ 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 @ 1- 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 @ 800 + \ add space for hot-plugging
|
|
1000 #aligned \ 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
|
|
DEFER func-pci-bridge-range-props
|
|
|
|
\ 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
|
|
dup func-pci-bridge-range-props \ Setup temporary "range
|
|
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
|
|
;
|
|
DEFER func-pci-bridge-probe
|
|
' pci-bridge-probe TO func-pci-bridge-probe
|
|
|
|
\ 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
|
|
7f and \ Mask bit 7 - multifunction device
|
|
CASE
|
|
0 OF pci-device-setup ENDOF \ | set up the device
|
|
1 OF pci-bridge-setup ENDOF \ | set up the bridge
|
|
dup OF dup pci-htype@ pci-out ENDOF
|
|
ENDCASE
|
|
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-pci-host-bridge) ( bus-max bus-min -- )
|
|
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
|
|
;
|
|
|
|
\ 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
|
|
(probe-pci-host-bridge)
|
|
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"
|
|
|
|
\ setup the function pointer for bridge ranges
|
|
' pci-bridge-range-props TO func-pci-bridge-range-props
|