\ ***************************************************************************** \ * 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 \ ****************************************************************************/ \ this is a C-to-Forth translation from the translate \ address code in the client \ with extensions to handle different sizes of #size-cells \ this tries to figure out if it is a PCI device what kind of \ translation is wanted \ if prop_type is 0, "reg" property is used, otherwise "assigned-addresses" : pci-address-type ( node address prop_type -- type ) -rot 2 pick ( prop_type node address prop_type ) 0= IF swap s" reg" rot get-property ( prop_type address data dlen false ) ELSE swap s" assigned-addresses" rot get-property ( prop_type address data dlen false ) THEN IF 2drop -1 EXIT THEN 4 / 5 / \ advance (phys-addr(3) size(2)) steps 0 DO \ BARs and Expansion ROM must be in assigned-addresses... \ so if prop_type is 0 ("reg") and a config space offset is set \ we skip this entry... dup l@ FF AND 0<> ( prop_type address data cfgspace_offset? ) 3 pick 0= ( prop_type address data cfgspace_offset? reg_prop? ) AND NOT IF 2dup 4 + ( prop_type address data address data' ) 2dup @ 2 pick 8 + @ + <= -rot @ >= and IF l@ 03000000 and 18 rshift nip ( prop_type type ) swap drop ( type ) UNLOOP EXIT THEN THEN \ advance in 4 byte steps and (phys-addr(3) size(2)) steps 4 5 * + LOOP 3drop -1 ; : (range-read-cells) ( range-addr #cells -- range-value ) \ if number of cells != 1; do 64bit read; else a 32bit read 1 = IF l@ ELSE @ THEN ; \ this functions tries to find a mapping for the given address \ it assumes that if we have #address-cells == 3 that we are trying \ to do a PCI translation \ nac - #address-cells \ nsc - #size-cells \ pnac - parent #address-cells : (map-one-range) ( type range pnac nsc nac address -- address true | address false ) \ only check for the type if nac == 3 (PCI) over 3 = 5 pick l@ 3000000 and 18 rshift 7 pick <> and IF >r 2drop 3drop r> false EXIT THEN \ get size 4 pick 4 pick 3 pick + 4 * + \ get nsc 3 pick \ read size ( type range pnac nsc nac address range nsc ) (range-read-cells) ( type range pnac nsc nac address size ) \ skip type if PCI 5 pick 3 pick 3 = IF 4 + THEN \ get nac 3 pick ( type range pnac nsc nac address size range nac ) \ read child-mapping (range-read-cells) ( type range pnac nsc nac address size child-mapping ) dup >r dup 3 pick > >r + over <= r> or IF \ address is not inside the mapping range >r 2drop 3drop r> r> drop false EXIT THEN dup r> - ( type range pnac nsc nac address offset ) \ add the offset on the parent mapping 5 pick 5 pick 3 = IF \ skip type if PCI 4 + THEN 3 pick 4 * + ( type range pnac nsc nac address offset parent-mapping-address ) \ get pnac 5 pick \ read parent mapping (range-read-cells) ( type range pnac nsc nac address offset parent-mapping ) + >r 3drop 3drop r> true ; \ this word translates the given address starting from the node specified \ in node; the word will return to the node it was started from : translate-address ( node address -- address ) \ check for address type in "assigned-addresses" 2dup 1 pci-address-type ( node address type ) dup -1 = IF \ not found in "assigned-addresses", check in "reg" drop 2dup 0 pci-address-type ( node address type ) THEN rot parent BEGIN \ check if it is the root node dup parent 0= IF 2drop EXIT THEN ( address type parent ) s" #address-cells" 2 pick get-property 2drop l@ >r \ nac s" #size-cells" 2 pick get-property 2drop l@ >r \ nsc s" #address-cells" 2 pick parent get-property 2drop l@ >r \ pnac -rot ( node address type ) s" ranges" 4 pick get-property IF 3drop ABORT" no ranges property; not translatable" THEN r> r> r> 3 roll ( node address type ranges pnac nsc nac length ) 4 / >r 3dup + + >r 5 roll r> r> swap / 0 ?DO ( node type ranges pnac nsc nac address ) 6dup (map-one-range) IF nip leave THEN nip \ advance ranges 4 roll ( node type pnac nsc nac address ranges ) 4 pick 4 pick 4 pick + + 4 * + 4 -roll LOOP >r 2drop 2drop r> ( node type address ) swap rot parent ( address type node ) dup 0= UNTIL ; \ this words translates the given address starting from the current node : translate-my-address ( address -- address' ) get-node swap translate-address ;