Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / dev / pci / probe-reg.fth
CommitLineData
920dae64
AT
1\ ========== Copyright Header Begin ==========================================
2\
3\ Hypervisor Software File: probe-reg.fth
4\
5\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6\
7\ - Do no alter or remove copyright notices
8\
9\ - Redistribution and use of this software in source and binary forms, with
10\ or without modification, are permitted provided that the following
11\ conditions are met:
12\
13\ - Redistribution of source code must retain the above copyright notice,
14\ this list of conditions and the following disclaimer.
15\
16\ - Redistribution in binary form must reproduce the above copyright notice,
17\ this list of conditions and the following disclaimer in the
18\ documentation and/or other materials provided with the distribution.
19\
20\ Neither the name of Sun Microsystems, Inc. or the names of contributors
21\ may be used to endorse or promote products derived from this software
22\ without specific prior written permission.
23\
24\ This software is provided "AS IS," without a warranty of any kind.
25\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
26\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
27\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
28\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
29\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
30\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
31\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
32\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
33\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
34\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
35\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
36\
37\ You acknowledge that this software is not designed, licensed or
38\ intended for use in the design, construction, operation or maintenance of
39\ any nuclear facility.
40\
41\ ========== Copyright Header End ============================================
42id: @(#)probe-reg.fth 1.16 06/11/01
43purpose: PCI/UPA bus mapping
44copyright: Copyright 2006 Sun Microsystems, Inc. All Rights Reserved
45copyright: Use is subject to license terms.
46
47headerless
48
49\ Tokenizer extends bit[31] all the way to bit[63].
50\ To create numbers with bit[31] set, but not extended to bit[63],
51\ we need to mask out the upper 32 bits
52: num-32 ( n -- l ) 0 lxjoin ;
53
54h# 0000.1fff invert constant pci-pagemask
55
56\ This struct has to be 64-bit aligned.
57struct
58 /n field >bar.phys.hi \ encoded phys.hi
59 /n + \ alignment padding
60 /x field >bar.size \ current allocated size
61 /x field >bar.value \ current PA
62 /n field >bar.implemented?
63 /n field >bar.assigned?
64constant /bar-struct
65
66d# 7 /bar-struct * constant /bar-data
67
68: alloc-bar-struct ( -- ptr ) /bar-data alloc-mem ;
69: free-bar-struct ( ptr -- ) /bar-data free-mem ;
70
71\ We always need at least one of these.
72alloc-bar-struct to bar-struct-addr
73
74\ this returns an effective bar# which may be used to index into bar.struct
75: get-bar# ( phys.hi -- bar# )
76 h# ff and ( cfg-offset )
77 h# 10 - 4 / ( bar# )
78 \ BARs 0-5 are normal. 6 is either at offset 30 or 38 (ROMBAR)
79 dup h# 6 > if drop 6 then ( bar# )
80;
81
82: >bar-struct ( bar# -- struct ) /bar-struct * bar-struct-addr + ;
83
84: probe-l@ ( physhi -- n ) $config-l@ $call-parent ;
85: probe-l! ( n physhi -- ) $config-l! $call-parent ;
86
87: bar64? ( physhi -- flag ) cfg>ss# h# 3 and h# 3 = ;
88: 64bit-pref? ( physhi -- flag ) cfg>ss# h# 43 and h# 43 = ;
89: 64bit-assigned? ( ptr -- flag ) >bar.value x@ xlsplit nip 0<> ;
90false value mem64-support?
91
92\
93\ This used to be clean.. now it is polluted with a BAR check!
94\ This is there because certain PLX devices violate the PCI SPEC by
95\ permitting thier IO/MEM bit to be *WRITEABLE*, so probing with -2
96\ which should be safe for all BARs screws them up..
97\ Wintel has a lot to answer for!
98\
99: probe-reg ( physhi -- size )
100 dup bar64? if ( physhi )
101 dup >r probe-l@ ( old.lo ) ( R: physhi )
102 r@ 4 + probe-l@ ( old.lo old.hi ) ( R: physhi )
103 -1 r@ 2dup probe-l! 4 + probe-l! ( old.lo old.hi ) ( R: physhi )
104 r@ probe-l@ r@ 4 + probe-l@ 2swap ( new.lo new.hi old.lo old.hi ) ( R: physhi )
105 r@ 4 + probe-l! r> probe-l! lxjoin ( new-64value )
106 else
107 dup >r probe-l@ ( old-value )
108 -1 r@ get-bar# 6 = if 1- then r@ probe-l! ( old-value )
109 r@ probe-l@ ( old-value new-value )
110 swap r> probe-l! ( new-value )
111 then
112;
113
114: probe-base-reg ( offset -- offset implemented? )
115 my-space + ( phys.hi )
116 dup get-bar# dup >r 5 > if ( phys.hi )
117 \ This is a ROMBAR ( phys.hi )
118 2 ss#>cfg or dup probe-reg ( phys.hi bits )
119 pci-pagemask and ( phys.hi size' )
120 4 -rot ( #bytes phys.hi size' )
121 else ( phys.hi )
122 dup probe-l@ ( phys.hi bar-bits )
123 dup 1 and if ( phys.hi bar-bits )
124 \ I/O register ( phys.hi )
125 drop dup probe-reg ( phys.hi bits )
126 3 invert and ( phys.hi bits )
127 dup h# 1.8000 and h# 0.8000 = if ( phys.hi bits )
128 \ Some cards don't implement the
129 \ high bits in the I/O decoder.
130 h# ffff d# 16 lshift or ( phys.hi bits' )
131 then ( phys.hi bits )
132 swap 1 ss#>cfg or swap ( phys.hi size )
133 4 -rot ( 4 phys.hi size )
134 else ( phys.hi bar-bits )
135 \ Memory ( phys.hi bar-bits )
136 \ Save Bar contents for later use after this case
137 tuck 1 >> 3 and case ( bar-bits phys.hi )
138 0 of 2 ss#>cfg or 4 endof ( bar-bits phys.hi #bytes )
139 1 of h# 82 ss#>cfg or 4 endof ( bar-bits phys.hi #bytes )
140 2 of 3 ss#>cfg or 8 endof ( bar-bits phys.hi #bytes )
141 3 of ." BAR has reserved bits set" abort endof
142 endcase ( bar-bits phys.hi #bytes )
143 -rot ( #bytes bar-bits phys.hi )
144 \ If prefetchable bar, propagate into REG.
145 \ prefetch bit is bit 3, from the pci local bus spec
146 swap h# 8 and if 40 ss#>cfg or then ( #bytes phys.hi )
147 dup probe-reg ( #bytes phys.hi bits )
148 pci-pagemask and ( #bytes phys.hi bits' )
149 then ( #bytes phys.hi bits' )
150 then ( #bytes phys.hi bits' )
151 over bar64? if
152 dup invert 1+ and ( #bytes phys.hi size )
153 else
154 dup invert 1+ and32 ( #bytes phys.hi size )
155 then
156 r> ( #bytes phys.hi size bar# )
157 >bar-struct ( #bytes phys.hi size adr )
158 over x0<> dup >r over >bar.implemented? ! ( #bytes phys.hi size adr )
159 debug-probe-bar? if ." ( " over .x ." )" then
160 tuck >bar.size x! ( #bytes phys.hi adr )
161 >bar.phys.hi ! ( #bytes phys.hi adr )
162 r> ( #bytes implemented? )
163;
164
165: make-power-of-2 ( n -- n' )
166 d# 64 0 do ( n )
167 1 i lshift ( n p2 )
168 2dup x<= if ( n p2 )
169 nip leave ( p2 )
170 else ( n p2 )
171 drop ( n )
172 then ( n )
173 loop ( p2 )
174;
175
176\ How we assign physical resource to a BAR
177\
178\ Note the defer..
179\ It is unfortunate that this routine can be called in 2 different
180\ contexts.
181\ 1. (the normal path) As a result of normal BAR probing in which case
182\ the code is executing in the child instance and we need to
183\ $call-parent to do config accesses.
184\ 2. (the abnormal path) As a result of a map-in at probe time that
185\ exceeds the allocated resource sizes of the BAR. In which case
186\ we were called by $call-parent and now need to $call-self to do
187\ config accesses.
188\
189\ By duplicating the $config-X $call-who I attempted to reduce the
190\ chances of someone accidently refering to the either uninitialised
191\ defer or the more likely incorrectly initialised defer.
192\
193defer $call-who
194: (assign-bar-resources) ( phys.hi acf -- )
195 to $call-who ( phys.hi )
196 get-bar# >bar-struct >r ( -- )
197 r@ >bar.size dup x@ ( addr size )
198 make-power-of-2 tuck swap x! ( size )
199 r@ >bar.phys.hi @ ( size phys.hi )
200 cfg>ss# h# 3 and case ( -- )
201 0 of 3drop true endof ( true )
202 1 of dup pci-io-list allocate-memrange ( pa,0 | true )
203 dup 0= if ( pa,0 | true )
204 swap num-32 swap ( pa,0 )
205 over r@ >bar.phys.hi @ ( pa,0 pa phys.hi )
206 $config-l! $call-who ( pa,0 )
207 then ( pa,0 | true )
208 endof ( pa,0 | true )
209 2 of dup pci-memlist allocate-memrange ( pa,0 | true )
210 dup 0= if ( pa,0 | true )
211 swap num-32 swap ( pa,0 )
212 over r@ >bar.phys.hi @ ( pa,0 pa phys.hi )
213 $config-l! $call-who ( pa,0 )
214 then ( pa,0 | true )
215 endof ( pa,0 | true )
216 3 of ( size )
217 r@ >bar.phys.hi @ 64bit-pref? ( size 64bit-pref? )
218 mem64-support? and if ( size )
219 \ allocate from mem64 space
220 dup pci-mem64list allocate-memrange ( pa,0 | true )
221 dup 0= if ( pa,0 | true )
222 r@ >bar.phys.hi @ >r ( pa 0 )
223 over xlsplit ( pa,0 pa.lo pa.hi )
224 r@ 4 + $config-l! $call-who ( pa,0 pa.lo )
225 r> $config-l! $call-who ( pa,0 )
226 then ( pa,0 | true )
227 else
228 \ allocate from mem32 space
229 dup pci-memlist allocate-memrange ( pa,0 | true )
230 dup 0= if ( pa,0 | true )
231 swap num-32 swap ( pa,0 )
232 r@ >bar.phys.hi @ >r ( pa 0 )
233 over r@ $config-l! $call-who ( pa,0 )
234 0 r> 4 + $config-l! $call-who ( pa,0 )
235 then ( pa,0 | true )
236 then ( pa,0 | true )
237 endof ( pa,0 | true )
238 endcase ( pa,0 | true )
239 r> swap if ( ptr )
240 \ Resource allocation problem..
241 ." Unable to assign resources for device "
242 " name" my-self ihandle>phandle get-package-property
243 if ." <unnamed>" else type then cr
244 drop abort ( -- )
245 else ( pa ptr )
246 debug-probe-bar? if ." Reg: " dup >bar.phys.hi @ .x ." = " over .x cr then
247 true over >bar.assigned? ! ( pa ptr )
248 >bar.value x! ( -- )
249 then ( -- )
250;
251
252\ Called when probing, executing in child instance
253: assign-bar-resources ( phys.hi -- )
254 ['] $call-parent (assign-bar-resources)
255;
256
257\ Called at probe time from map-in via a $call-parent
258: reassign-bar-resources ( phys.hi -- )
259 ['] $call-self (assign-bar-resources)
260;
261
262\
263\ How we release resources a BAR has been using.
264\
265: release-bar-resources ( phys.hi -- )
266 dup get-bar# >bar-struct >r ( phys.hi -- )
267 r@ >bar.assigned? @ 0= if ( phys.hi )
268 r> 2drop ( -- )
269 then ( phys.hi )
270 0 r@ >bar.assigned? ! ( phys.hi )
271 debug-probe-bar? if ." Releasing: BAR " dup .x ." = " then
272 r@ >bar.value dup x@ ( phys.hi addr pa )
273 0 rot x! ( phys.hi pa )
274 r> >bar.size x@ ( phys.hi pa len )
275 debug-probe-bar? if over .x dup .x cr then
276 rot dup >r cfg>ss# 3 and ( pa len ss' ) ( R: phy.hi )
277 case ( pa len ) ( R: phy.hi )
278 1 of pci-io-list endof ( pa len list ) ( R: phy.hi )
279 2 of pci-memlist endof ( pa len list ) ( R: phy.hi )
280 3 of
281 r@ 64bit-pref? mem64-support? and if ( pa len ) ( R: phy.hi )
282 pci-mem64list ( pa len list ) ( R: phy.hi )
283 else
284 pci-memlist ( pa len list ) ( R: phy.hi )
285 then
286 endof
287 endcase ( pa len list ) ( R: phy.hi )
288 free-memrange r> drop ( -- ) ( R: )
289;
290
291: read-bar-resources ( offset -- incr implemented )
292 debug-probe-bar? if ." read-bar-resources: " dup .x then
293 \ This is called for devices that are currently enabled.
294 \ We are much cruder here.. We set the size to the first multiple of
295 \ 2 that the current register address is at.
296 \ This is not optimal but is safe, probing an active device isn't.
297 dup get-bar# >bar-struct >r ( offset )
298 my-space + ( phys.hi )
299 dup $config-l@ $call-parent ( phys.hi size )
300 over get-bar# 5 > if ( phys.hi size )
301 h# f ( phys.hi size mask )
302 else ( phys.hi size )
303 dup 1 and if 3 else h# f then ( phys.hi size mask )
304 then ( phys.hi size mask )
305 invert over and ( phys.hi size size' )
306 0= if ( phys.hi size )
307 drop ( phys.hi )
308 my-space - ( offset )
309 dup probe-base-reg if ( phys.hi next )
310 swap assign-bar-resources true ( next true )
311 else ( phys.hi next )
312 nip false ( next 0 )
313 then ( offset implemented? )
314 r> drop ( offset implemented? )
315 else ( phys.hi size )
316 >r ( phys.hi )
317 r@ 1 and if ( phys.hi )
318 h# 81 ss#>cfg or 4 ( phsy.hi' size )
319 else ( phys.hi )
320 r@ 1 rshift 3 and 2 = ( phys.hi mem64? )
321 if 8 3 else 4 2 then ( phys.hi size type )
322 r@ 8 and if h# 40 or then swap ( phys.hi type' size )
323 >r h# 80 or ss#>cfg or r> ( phys.hi' size )
324 then ( phys.hi' size )
325 swap r> ( size phys.hi value )
326 debug-probe-bar? if over .x ." @ " dup .x then
327 over cfg>mask and ( size phys.hi value' )
328 dup dup invert 1+ and ( size phys.hi value' decode )
329 debug-probe-bar? if ." ( " dup .x ." )" cr then
330 r@ >bar.size x! ( size phys.hi value' )
331 dup r@ >bar.value x! ( size phys.hi value' )
332 0<> ( size phys.hi 0? )
333 dup r@ >bar.assigned? ! ( size phys.hi 0? )
334 dup r@ >bar.implemented? ! ( size phys.hi 0? )
335 swap ( size 0? phys.hi )
336 r> >bar.phys.hi ! ( size 0? )
337 then
338;
339
340: probe-and-assign-bar ( offset -- incr implemented? )
341 debug-probe-bar? if ." probe-and-assign-bar: " dup .x then
342 dup probe-base-reg if ( phys.hi next )
343 swap assign-bar-resources true ( next true )
344 else ( phys.hi next )
345 debug-probe-bar? if cr then ( phys.hi next )
346 nip false ( next 0 )
347 then ( offset implemented? )
348;
349
350: device-enabled? ( -- flag? ) 4 parent-w@ 7 and ;
351
352defer build-bar-resources ( offset -- )
353
354\ page 347 top para of PCI System Architecture
355\ 3rd edition (ISBN 0-201-40993-3) states:
356\ ... the configuration software will stop looking for base
357\ registers in a devices header when it detects the first
358\ unimplemented base register ...
359\
360\ However the PCI spec states:
361\ The PCI specification Revision 2.2 states in section 6.2.5.1:
362\ A type 00h predefined header has six DWORD locations allocated
363\ for Base Address registers starting at offset 10h in Configuration
364\ Space. A device may use any of the locations to implement
365\ Base Address registers. An implemented 64-bit Base Address
366\ register consumes two consecutive DWORD locations. Software looking
367\ for implemented Base Address registers must start at offset 10h
368\ and continue upwards through offset 24h.
369\
370
371: assign-addresses ( -- )
372 bar-struct-addr /bar-data erase ( -- )
373 device-enabled? if ( -- )
374 ['] read-bar-resources ( acf )
375 else ( -- )
376 ['] probe-and-assign-bar ( acf )
377 then to build-bar-resources ( -- )
378 base-register-bounds do ( -- )
379 i build-bar-resources drop ( next )
380 +loop ( )
381 card-bus? 0= if
382 expansion-rom build-bar-resources 2drop ( )
383 then
384;
385
386
3870 value make-assigned?
388
389\
390\ This routine is used to construct the "assigned-addresses" and the "reg"
391\ property. The code path was so similar it wasn't worth factoring.
392\
393: make-reg-type-property ( assigned? -- xdr,len )
394 if h# 80 else 0 then to make-assigned? ( -- )
395 0 0 encode-bytes ( xdr,len )
396 make-assigned? 0= if ( xdr,len )
397 my-space en+ 0 en+ 0 en+ ( xdr,len )
398 0 en+ 0 en+ ( xdr,len )
399 then ( xdr,len )
400 7 0 do ( xdr,len )
401 i >bar-struct ( xdr,len ptr )
402 dup >bar.implemented? @ if ( xdr,len ptr )
403 dup >bar.size x@ xlsplit swap >r >r ( xdr,len ptr )
404 dup >bar.phys.hi @ ( xdr,len ptr phys.hi )
405[ifdef] 64BIT-ASSIGNED?
406 \ If phys.hi has ss#=3, but the bar has been actually assigned
407 \ 32-bit value because either the platform did not support
408 \ mem64 space or the bar was not prefetchable, we should
409 \ indicate ss#=2 in assigned-address property.
410 make-assigned? if ( xdr,len ptr phys.hi )
411 dup cfg>ss# 3 and 3 = if ( xdr,len ptr phys.hi )
412 over 64bit-assigned? not if ( xdr,len ptr phys.hi )
413 1 ss#>cfg xor ( xdr,len ptr phys.hi' )
414 then ( xdr,len ptr phys.hi' )
415 then ( xdr,len ptr phys.hi' )
416 then ( xdr,len ptr phys.hi' )
417[then]
418 dup not-relocatable? make-assigned? or if ( xdr,len ptr phys.hi )
419 over >bar.value x@ xlsplit swap ( xdr,len ptr phys.hi phys.mid phys.lo )
420 else ( xdr,len ptr phys.hi )
421 0 0 ( xdr,len ptr phys.hi phys.mid phys.lo )
422 then >r >r ( xdr,len ptr phys.hi )
423 make-assigned? ss#>cfg or >r ( xdr,len ptr )
424 -rot r> r> r> r> r> encode5 rot ( xdr,len ptr )
425 >bar.phys.hi @ cfg>ss# ( xdr,len SS )
426 h# 3 and 3 <> if 1 else 2 then ( xdr,len incr )
427 else ( xdr,len )
428 drop 1 ( xdr,len incr )
429 then ( xdr,len incr )
430 +loop ( xdr,len )
431;
432
433: make-reg-property ( -- ) 0 make-reg-type-property " reg" property ;
434
435\
436\ We only need to decode the "reg" property if we evaluated some fcode
437\ because that is the only way the reg property could be made to differ
438\ from the h/w.
439\
440\ We pull this stunt to permit cards that lie about thier decode ability
441\ in h/w to be corrected in s/w. Certain Diamond cards are guilty of this.
442\
443: make-assigned-property ( parse? -- )
444 " reg" my-self ihandle>phandle ( parse? reg$ phandle )
445 get-package-property if drop exit then ( parse? xdr,len )
446 rot 0= if drop 0 then ( xdr,len' )
447 begin ( xdr,len )
448 dup 0> while ( xdr,len )
449 decode-int ( xdr,len phys.hi )
450 >r decode-int drop decode-int drop ( xdr,len )
451 decode-int >r decode-int r> lxjoin ( xdr,len len )
452 r> dup cfg>ss# 3 and if ( xdr,len len phys.hi )
453 dup get-bar# >bar-struct >r ( xdr,len len phys.hi )
454 r@ >bar.implemented? @ if ( xdr,len len phys.hi )
455 drop r@ >bar.size x@ over x< if ( xdr,len len reg-bigger? )
456 r@ >bar.phys.hi @ ( xdr,len len phys.hi )
457 dup release-bar-resources ( xdr,len len phys.hi )
458 swap r@ >bar.size x! ( xdr,len phys.hi )
459 assign-bar-resources ( xdr,len )
460 0 ( xdr,len 0 )
461 then ( xdr,len ? )
462 else ( xdr,len len phys.hi )
463 -1 r@ >bar.implemented? ! ( xdr,len len phys.hi )
464 r@ >bar.phys.hi ! ( xdr,len len )
465 r@ >bar.size x! ( xdr,len )
466 0 ( xdr,len 0 )
467 then ( xdr,len ? )
468 r> ( xdr,len ? ? )
469 then ( xdr,len ? ? )
470 2drop ( xdr,len )
471 repeat 2drop ( -- )
472 1 make-reg-type-property dup if
473 " assigned-addresses" property
474 else
475 2drop
476 then
477;
478
479: .dump-assigned-addr ( -- )
480 ." Assigned BARs:" cr
481 7 0 do
482 i >bar-struct >r
483 r@ >bar.implemented? @ r@ >bar.assigned? @ and if
484 r@ >bar.phys.hi @ ." Phys.hi: " .x
485 r@ >bar.size x@ ." size: " .x
486 r@ >bar.value x@ ." located: " .x cr
487 r> >bar.phys.hi @ cfg>ss# 3 = if 2 else 1 then
488 else
489 r> drop 1
490 then
491 +loop cr
492;
493
494: list>property ( xdr,len list ss -- xdr,len )
495 over if
496 swap begin ( xdr,len ss node )
497 dup while ( xdr,len ss node )
498 dup >mem.size x@ xlsplit swap >r >r ( xdr,len ss node )
499 dup >mem.adr x@ xlsplit swap >r >r ( xdr,len ss node )
500 over ss#>cfg >r ( xdr,len ss node )
501 >next-node @ 2swap r> r> r> r> r> encode5 2swap ( xdr,len ss node )
502 repeat 2drop ( xdr,len )
503 else
504 2drop ( xdr,len )
505 then
506;
507
508: make-available-property ( -- )
509 0 0 encode-bytes ( xdr,len )
510 pci-io-list @ h# 81 list>property ( xdr,len )
511 pci-memlist @ h# 82 list>property ( xdr,len )
512 pci-mem64list @ h# c3 list>property ( xdr,len )
513 ?dup if " available" property else drop then ( )
514;