summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/slof/fs/pci-scan.fs
blob: b8b9fe61f5b2436eb4c3d8d24aa4e998c15f1cd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
\ *****************************************************************************
\ * 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

\ 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


\ 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 ;


#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 ( -- )
        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
;


\ 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 100000 + pci-next-mmio !            \ and write back with 1MB for bridge
        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 #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 100000 + pci-next-mem !             \ and write back with 1MB for bridge
        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 @ 1- 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 1000 + pci-next-io !                \ and write back with 4K for bridge
        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 @ 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
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
;

\ 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