FreeBSD/Linux Kernel Cross Reference
sys/alphapc/pci.c
1 /*
2 * PCI support code.
3 * To do:
4 * initialise bridge mappings if the PCI BIOS didn't.
5 */
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "../port/error.h"
13
14 enum {
15 MaxFNO = 7,
16 MaxUBN = 255,
17 };
18
19 enum
20 { /* command register */
21 IOen = (1<<0),
22 MEMen = (1<<1),
23 MASen = (1<<2),
24 MemWrInv = (1<<4),
25 PErrEn = (1<<6),
26 SErrEn = (1<<8),
27 };
28
29 static Lock pcicfglock;
30 static Lock pcicfginitlock;
31 static int pcicfgmode = -1;
32 static int pcimaxdno;
33 static Pcidev* pciroot;
34 static Pcidev* pcilist;
35 static Pcidev* pcitail;
36
37 static int pcicfgrw32(int, int, int, int);
38
39 uchar *vgabios;
40
41 static int
42 pciscan(int bno, Pcidev** list)
43 {
44 ulong v;
45 Pcidev *p, *head, *tail;
46 int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
47
48 maxubn = bno;
49 head = nil;
50 tail = nil;
51 for(dno = 0; dno <= pcimaxdno; dno++){
52 maxfno = 0;
53 for(fno = 0; fno <= maxfno; fno++){
54 /*
55 * For this possible device, form the
56 * bus+device+function triplet needed to address it
57 * and try to read the vendor and device ID.
58 * If successful, allocate a device struct and
59 * start to fill it in with some useful information
60 * from the device's configuration space.
61 */
62 tbdf = MKBUS(BusPCI, bno, dno, fno);
63 l = pcicfgrw32(tbdf, PciVID, 0, 1);
64 if(l == 0xFFFFFFFF || l == 0)
65 continue;
66 /* optional safety checks:
67 if(l == pcicfgrw32(tbdf, PciPCR, 0, 1))
68 continue;
69 if(l != pcicfgrw32(tbdf, PciVID, 0, 1))
70 continue;
71 if(l == pcicfgrw32(tbdf, PciPCR, 0, 1))
72 continue;
73 */
74 p = malloc(sizeof(*p));
75 p->tbdf = tbdf;
76 p->vid = l;
77 p->did = l>>16;
78
79 if(pcilist != nil)
80 pcitail->list = p;
81 else
82 pcilist = p;
83 pcitail = p;
84
85 p->rid = pcicfgr8(p, PciRID);
86 p->ccrp = pcicfgr8(p, PciCCRp);
87 p->ccru = pcicfgr8(p, PciCCRu);
88 p->ccrb = pcicfgr8(p, PciCCRb);
89 p->pcr = pcicfgr32(p, PciPCR);
90
91 p->intl = pcicfgr8(p, PciINTL);
92
93 /*
94 * If the device is a multi-function device adjust the
95 * loop count so all possible functions are checked.
96 */
97 hdt = pcicfgr8(p, PciHDT);
98 if(hdt & 0x80)
99 maxfno = MaxFNO;
100
101 /*
102 * If appropriate, read the base address registers
103 * and work out the sizes.
104 */
105 switch(p->ccrb){
106
107 case 0x03: /* display controller */
108 if(vgabios == nil) {
109 v = pcicfgr32(p, PciROM);
110 pcicfgw32(p, PciROM, v|1); /* enable decode */
111 vgabios = kmapv(((uvlong)0x88<<32LL)|(v&~0xffff), 0x10000);
112 // print("VGA BIOS %lux -> %lux\n", v, vgabios);
113 }
114 /* fall through */
115 case 0x01: /* mass storage controller */
116 case 0x02: /* network controller */
117 case 0x04: /* multimedia device */
118 case 0x07: /* simple communication controllers */
119 case 0x08: /* base system peripherals */
120 case 0x09: /* input devices */
121 case 0x0A: /* docking stations */
122 case 0x0B: /* processors */
123 case 0x0C: /* serial bus controllers */
124 if((hdt & 0x7F) != 0)
125 break;
126 rno = PciBAR0 - 4;
127 for(i = 0; i < nelem(p->mem); i++){
128 rno += 4;
129 p->mem[i].bar = pcicfgr32(p, rno);
130 pcicfgw32(p, rno, -1);
131 v = pcicfgr32(p, rno);
132 pcicfgw32(p, rno, p->mem[i].bar);
133 p->mem[i].size = -(v & ~0xF);
134 }
135 break;
136
137 case 0x00:
138 case 0x05: /* memory controller */
139 case 0x06: /* bridge device */
140 default:
141 break;
142 }
143
144 if(head != nil)
145 tail->link = p;
146 else
147 head = p;
148 tail = p;
149 }
150 }
151
152 *list = head;
153 for(p = head; p != nil; p = p->link){
154 /*
155 * Find PCI-PCI bridges and recursively descend the tree.
156 */
157 if(p->ccrb != 0x06 || p->ccru != 0x04)
158 continue;
159
160 /*
161 * If the secondary or subordinate bus number is not initialised
162 * try to do what the PCI BIOS should have done and fill in the
163 * numbers as the tree is descended. On the way down the subordinate
164 * bus number is set to the maximum as it's not known how many
165 * buses are behind this one; the final value is set on the way
166 * back up.
167 */
168 sbn = pcicfgr8(p, PciSBN);
169 ubn = pcicfgr8(p, PciUBN);
170 if(sbn == 0 || ubn == 0){
171 sbn = maxubn+1;
172 /*
173 * Make sure memory, I/O and master enables are off,
174 * set the primary, secondary and subordinate bus numbers
175 * and clear the secondary status before attempting to
176 * scan the secondary bus.
177 *
178 * Initialisation of the bridge should be done here.
179 */
180 pcicfgw32(p, PciPCR, 0xFFFF0000);
181 l = (MaxUBN<<16)|(sbn<<8)|bno;
182 pcicfgw32(p, PciPBN, l);
183 pcicfgw16(p, PciSPSR, 0xFFFF);
184 maxubn = pciscan(sbn, &p->bridge);
185 l = (maxubn<<16)|(sbn<<8)|bno;
186 pcicfgw32(p, PciPBN, l);
187 }
188 else{
189 maxubn = ubn;
190 pciscan(sbn, &p->bridge);
191 }
192 }
193
194 return maxubn;
195 }
196
197 static void
198 pcicfginit(void)
199 {
200 char *p;
201
202 lock(&pcicfginitlock);
203 if(pcicfgmode == -1){
204 pcicfgmode = 0;
205 pcimaxdno = 15; /* was 20; what is correct value??? */
206 if(p = getconf("*pcimaxdno"))
207 pcimaxdno = strtoul(p, 0, 0);
208 pciscan(0, &pciroot);
209 }
210 unlock(&pcicfginitlock);
211 }
212
213 static int
214 pcicfgrw8(int tbdf, int rno, int data, int read)
215 {
216 int x;
217 uchar *p;
218
219 if(pcicfgmode == -1)
220 pcicfginit();
221 x = -1;
222 if(BUSDNO(tbdf) > pcimaxdno)
223 return x;
224
225 p = (uchar*)arch->pcicfg(tbdf, rno);
226 if(read)
227 x = *p;
228 else
229 *p = data;
230
231 return x;
232 }
233
234 int
235 pcicfgr8(Pcidev* pcidev, int rno)
236 {
237 return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
238 }
239
240 void
241 pcicfgw8(Pcidev* pcidev, int rno, int data)
242 {
243 pcicfgrw8(pcidev->tbdf, rno, data, 0);
244 }
245
246 static int
247 pcicfgrw16(int tbdf, int rno, int data, int read)
248 {
249 int x;
250 ushort *p;
251
252 if(pcicfgmode == -1)
253 pcicfginit();
254 x = -1;
255 if(BUSDNO(tbdf) > pcimaxdno)
256 return x;
257
258 p = (ushort*)arch->pcicfg(tbdf, rno);
259 if(read)
260 x = *p;
261 else
262 *p = data;
263
264 return x;
265 }
266
267 int
268 pcicfgr16(Pcidev* pcidev, int rno)
269 {
270 return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
271 }
272
273 void
274 pcicfgw16(Pcidev* pcidev, int rno, int data)
275 {
276 pcicfgrw16(pcidev->tbdf, rno, data, 0);
277 }
278
279 static int
280 pcicfgrw32(int tbdf, int rno, int data, int read)
281 {
282 int x;
283 ulong *p;
284
285 if(pcicfgmode == -1)
286 pcicfginit();
287 x = -1;
288 if(BUSDNO(tbdf) > pcimaxdno)
289 return x;
290
291 p = (ulong*)arch->pcicfg(tbdf, rno);
292 if(read)
293 x = *p;
294 else
295 *p = data;
296
297 return x;
298 }
299
300 int
301 pcicfgr32(Pcidev* pcidev, int rno)
302 {
303 return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
304 }
305
306 void
307 pcicfgw32(Pcidev* pcidev, int rno, int data)
308 {
309 pcicfgrw32(pcidev->tbdf, rno, data, 0);
310 }
311
312 Pcidev*
313 pcimatch(Pcidev* prev, int vid, int did)
314 {
315 if(pcicfgmode == -1)
316 pcicfginit();
317
318 if(prev == nil)
319 prev = pcilist;
320 else
321 prev = prev->list;
322
323 while(prev != nil) {
324 if((vid == 0 || prev->vid == vid)
325 && (did == 0 || prev->did == did))
326 break;
327 prev = prev->list;
328 }
329 return prev;
330 }
331
332 Pcidev*
333 pcimatchtbdf(int tbdf)
334 {
335 Pcidev *pcidev;
336
337 if(pcicfgmode == -1)
338 pcicfginit();
339
340 for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
341 if(pcidev->tbdf == tbdf)
342 break;
343 }
344 return pcidev;
345 }
346
347 void
348 pcihinv(Pcidev* p)
349 {
350 int i;
351 Pcidev *t;
352
353 if(pcicfgmode == -1)
354 pcicfginit();
355 if(p == nil) {
356 p = pciroot;
357 print("bus dev type vid did intl memory\n");
358 }
359 for(t = p; t != nil; t = t->link) {
360 print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %2d ",
361 BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
362 t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
363
364 for(i = 0; i < nelem(p->mem); i++) {
365 if(t->mem[i].size == 0)
366 continue;
367 print("%d:%.8lux %d ", i,
368 t->mem[i].bar, t->mem[i].size);
369 }
370 print("\n");
371 }
372 while(p != nil) {
373 if(p->bridge != nil)
374 pcihinv(p->bridge);
375 p = p->link;
376 }
377 }
378
379 void
380 pcireset(void)
381 {
382 Pcidev *p;
383 int pcr;
384
385 if(pcicfgmode == -1)
386 pcicfginit();
387
388 for(p = pcilist; p != nil; p = p->list){
389 pcr = pcicfgr16(p, PciPSR);
390 pcicfgw16(p, PciPSR, pcr & ~0x04);
391 }
392 }
393
394 void
395 pcisetbme(Pcidev* p)
396 {
397 int pcr;
398
399 pcr = pcicfgr16(p, PciPCR);
400 pcr |= MASen;
401 pcicfgw16(p, PciPCR, pcr);
402 }
403
404 void
405 pciclrbme(Pcidev* p)
406 {
407 int pcr;
408
409 pcr = pcicfgr16(p, PciPCR);
410 pcr &= ~MASen;
411 pcicfgw16(p, PciPCR, pcr);
412 }
Cache object: 72acd86d4a4d6359ba26a3876cf05f7d
|