]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/alphapc/pci.c
pci: add intel qm67 pch
[plan9front.git] / sys / src / 9 / 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 }